chore: checkpoint before discharge history panel refactor
This commit is contained in:
parent
8fc60e893e
commit
96c030b72d
|
|
@ -83,20 +83,35 @@ class Abha extends BaseController
|
|||
$payload = $result['data'] ?? $result;
|
||||
$newTxnId = $payload['txnId'] ?? $payload['txn_id'] ?? $txnId;
|
||||
|
||||
// aadhaar/verify-otp returns ABHAProfile when ABHA is created/found
|
||||
$profile = $payload['ABHAProfile'] ?? [];
|
||||
if (empty($profile) && ! empty($payload['accounts'][0])) {
|
||||
$profile = $payload['accounts'][0]; // legacy fallback
|
||||
}
|
||||
$profile = $this->pickGatewayAbhaProfile($payload);
|
||||
|
||||
$abhaNum = (string) ($profile['ABHANumber'] ?? $payload['ABHANumber'] ?? '');
|
||||
$name = (string) ($profile['name'] ?? $profile['fullName'] ?? '');
|
||||
$photo = (string) ($profile['profilePhoto'] ?? '');
|
||||
$mobile = (string) ($profile['mobile'] ?? $payload['mobile'] ?? $payload['mobileNumber'] ?? '');
|
||||
$profileGender = (string) ($profile['gender'] ?? '');
|
||||
$profileDob = (string) ($profile['dob'] ?? '');
|
||||
$abhaNum = (string) ($profile['ABHANumber'] ?? $profile['abha_id'] ?? $payload['ABHANumber'] ?? $payload['abha_id'] ?? '');
|
||||
$abhaAddress = (string) ($profile['preferredAbhaAddress'] ?? $profile['abha_address'] ?? $payload['preferredAbhaAddress'] ?? $payload['abha_address'] ?? '');
|
||||
$name = (string) ($profile['name'] ?? $profile['fullName'] ?? $profile['full_name'] ?? $payload['name'] ?? $payload['full_name'] ?? '');
|
||||
$photo = (string) ($profile['profilePhoto'] ?? $profile['profile_photo'] ?? $payload['profilePhoto'] ?? $payload['profile_photo'] ?? '');
|
||||
$mobile = (string) ($profile['mobile'] ?? $payload['mobile'] ?? $payload['mobileNumber'] ?? '');
|
||||
$profileGender = (string) ($profile['gender'] ?? $payload['gender'] ?? '');
|
||||
$profileDob = (string) ($profile['dob'] ?? $profile['date_of_birth'] ?? $payload['dob'] ?? $payload['date_of_birth'] ?? '');
|
||||
$verifiedStatus = (string) ($profile['verifiedStatus'] ?? $payload['verifiedStatus'] ?? '');
|
||||
$verificationType = (string) ($profile['verificationType'] ?? $payload['verificationType'] ?? '');
|
||||
$kycVerified = $profile['kycVerified'] ?? $payload['kycVerified'] ?? null;
|
||||
$mobileVerified = $profile['mobileVerified'] ?? $payload['mobileVerified'] ?? null;
|
||||
|
||||
$patientInfo = $this->autoCreateOrFindPatient($abhaNum, $name, $mobile, $profileGender, $profileDob);
|
||||
$patientInfo = $this->autoCreateOrFindPatient(
|
||||
$abhaNum,
|
||||
$name,
|
||||
$mobile,
|
||||
$profileGender,
|
||||
$profileDob,
|
||||
[
|
||||
'abha_address' => $abhaAddress,
|
||||
'profile_photo' => $photo,
|
||||
'verified_status' => $verifiedStatus,
|
||||
'verification_type' => $verificationType,
|
||||
'kyc_verified' => $kycVerified,
|
||||
'mobile_verified' => $mobileVerified,
|
||||
]
|
||||
);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'ok' => 1,
|
||||
|
|
@ -180,20 +195,35 @@ class Abha extends BaseController
|
|||
|
||||
$payload = $result['data'] ?? $result;
|
||||
|
||||
// mobile/verify-otp returns data.profile (new format) or data.ABHAProfile / accounts[0] (legacy)
|
||||
$profile = $payload['profile'] ?? $payload['ABHAProfile'] ?? [];
|
||||
if (empty($profile) && ! empty($payload['accounts'][0])) {
|
||||
$profile = $payload['accounts'][0];
|
||||
}
|
||||
$profile = $this->pickGatewayAbhaProfile($payload);
|
||||
|
||||
$abhaNum = (string) ($profile['ABHANumber'] ?? $payload['ABHANumber'] ?? '');
|
||||
$name = (string) ($profile['name'] ?? $profile['fullName'] ?? $payload['name'] ?? '');
|
||||
$photo = (string) ($profile['profilePhoto'] ?? $payload['profilePhoto'] ?? '');
|
||||
$gender = (string) ($profile['gender'] ?? $payload['gender'] ?? '');
|
||||
$dob = (string) ($profile['dob'] ?? $payload['dob'] ?? '');
|
||||
$mobile = (string) ($profile['mobile'] ?? $payload['mobile'] ?? '');
|
||||
$abhaNum = (string) ($profile['ABHANumber'] ?? $profile['abha_id'] ?? $payload['ABHANumber'] ?? $payload['abha_id'] ?? '');
|
||||
$abhaAddress = (string) ($profile['preferredAbhaAddress'] ?? $profile['abha_address'] ?? $payload['preferredAbhaAddress'] ?? $payload['abha_address'] ?? '');
|
||||
$name = (string) ($profile['name'] ?? $profile['fullName'] ?? $profile['full_name'] ?? $payload['name'] ?? $payload['full_name'] ?? '');
|
||||
$photo = (string) ($profile['profilePhoto'] ?? $profile['profile_photo'] ?? $payload['profilePhoto'] ?? $payload['profile_photo'] ?? '');
|
||||
$gender = (string) ($profile['gender'] ?? $payload['gender'] ?? '');
|
||||
$dob = (string) ($profile['dob'] ?? $profile['date_of_birth'] ?? $payload['dob'] ?? $payload['date_of_birth'] ?? '');
|
||||
$mobile = (string) ($profile['mobile'] ?? $payload['mobile'] ?? $payload['mobileNumber'] ?? '');
|
||||
$verifiedStatus = (string) ($profile['verifiedStatus'] ?? $payload['verifiedStatus'] ?? '');
|
||||
$verificationType = (string) ($profile['verificationType'] ?? $payload['verificationType'] ?? '');
|
||||
$kycVerified = $profile['kycVerified'] ?? $payload['kycVerified'] ?? null;
|
||||
$mobileVerified = $profile['mobileVerified'] ?? $payload['mobileVerified'] ?? null;
|
||||
|
||||
$patientInfo = $this->autoCreateOrFindPatient($abhaNum, $name, $mobile, $gender, $dob);
|
||||
$patientInfo = $this->autoCreateOrFindPatient(
|
||||
$abhaNum,
|
||||
$name,
|
||||
$mobile,
|
||||
$gender,
|
||||
$dob,
|
||||
[
|
||||
'abha_address' => $abhaAddress,
|
||||
'profile_photo' => $photo,
|
||||
'verified_status' => $verifiedStatus,
|
||||
'verification_type' => $verificationType,
|
||||
'kyc_verified' => $kycVerified,
|
||||
'mobile_verified' => $mobileVerified,
|
||||
]
|
||||
);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'ok' => 1,
|
||||
|
|
@ -287,7 +317,8 @@ class Abha extends BaseController
|
|||
string $name,
|
||||
string $mobile,
|
||||
string $gender,
|
||||
string $dob
|
||||
string $dob,
|
||||
array $abhaMeta = []
|
||||
): array {
|
||||
$db = \Config\Database::connect();
|
||||
$fields = $db->getFieldNames('patient_master') ?? [];
|
||||
|
|
@ -301,7 +332,8 @@ class Abha extends BaseController
|
|||
$abhaField = 'abha_address';
|
||||
}
|
||||
|
||||
$abhaNumClean = preg_replace('/\D/', '', $abhaNum); // strip dashes → 14 digits
|
||||
$abhaNumClean = preg_replace('/\D/', '', $abhaNum); // strip dashes -> 14 digits
|
||||
$abhaAddress = trim((string) ($abhaMeta['abha_address'] ?? ''));
|
||||
|
||||
// 1. Search by ABHA number
|
||||
$existing = null;
|
||||
|
|
@ -329,21 +361,58 @@ class Abha extends BaseController
|
|||
->where('id', $patientId)
|
||||
->update([$abhaField => $abhaNumClean]);
|
||||
}
|
||||
|
||||
$this->syncAbhaMetaToPatient($patientId, $abhaMeta, $abhaNumClean, $abhaAddress, $fields);
|
||||
return ['patient_id' => $patientId, 'p_code' => $pCode, 'is_new' => false];
|
||||
}
|
||||
|
||||
// 2b. Safe repair path for orphan placeholder rows created during prior failed mapping.
|
||||
// Reuse only when there is exactly one unambiguous candidate with no clinical linkage.
|
||||
$placeholder = $this->findRepairablePlaceholderPatient($db, $fields);
|
||||
if ($placeholder !== null) {
|
||||
$patientId = (int) ($placeholder['id'] ?? 0);
|
||||
if ($patientId > 0) {
|
||||
$repairData = [
|
||||
'p_fname' => strtoupper($name !== '' ? $name : 'ABHA PATIENT'),
|
||||
'mphone1' => $mobile,
|
||||
'gender' => $this->toPatientGenderValue($gender),
|
||||
'estimate_dob' => 1,
|
||||
];
|
||||
|
||||
$dobDb = $this->normalizeDobToDb($dob);
|
||||
if ($dobDb !== '') {
|
||||
$repairData['dob'] = $dobDb;
|
||||
$repairData['estimate_dob'] = 0;
|
||||
}
|
||||
|
||||
if ($abhaField && $abhaNumClean !== '') {
|
||||
$repairData[$abhaField] = $abhaNumClean;
|
||||
}
|
||||
if ($abhaAddress !== '' && in_array('abha_address', $fields, true)) {
|
||||
$repairData['abha_address'] = $abhaAddress;
|
||||
}
|
||||
|
||||
$this->applyAbhaMetaColumns($repairData, $abhaMeta, $fields);
|
||||
if (($abhaNumClean !== '' || $abhaAddress !== '') && in_array('abdm_linked_at', $fields, true)) {
|
||||
$repairData['abdm_linked_at'] = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
$db->table('patient_master')->where('id', $patientId)->update($repairData);
|
||||
|
||||
$row = $db->table('patient_master')->select('p_code')->where('id', $patientId)->get()->getRowArray();
|
||||
$pCode = (string) ($row['p_code'] ?? '');
|
||||
|
||||
$this->syncAbhaMetaToPatient($patientId, $abhaMeta, $abhaNumClean, $abhaAddress, $fields);
|
||||
|
||||
return ['patient_id' => $patientId, 'p_code' => $pCode, 'is_new' => false];
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Create new patient row from ABHA profile data
|
||||
$genderDb = 1; // default Male
|
||||
$genderAbs = strtoupper($gender);
|
||||
if ($genderAbs === 'F' || $genderAbs === '2') { $genderDb = 2; }
|
||||
$genderDb = $this->toPatientGenderValue($gender);
|
||||
|
||||
// Convert DOB to MySQL YYYY-MM-DD
|
||||
$dobDb = '';
|
||||
if (preg_match('/^(\d{2})-(\d{2})-(\d{4})$/', $dob, $m)) {
|
||||
$dobDb = $m[3] . '-' . $m[2] . '-' . $m[1]; // DD-MM-YYYY → YYYY-MM-DD
|
||||
} elseif (preg_match('/^\d{4}-\d{2}-\d{2}$/', $dob)) {
|
||||
$dobDb = $dob;
|
||||
}
|
||||
$dobDb = $this->normalizeDobToDb($dob);
|
||||
|
||||
$insertData = [
|
||||
'p_fname' => strtoupper($name !== '' ? $name : 'ABHA PATIENT'),
|
||||
|
|
@ -361,6 +430,14 @@ class Abha extends BaseController
|
|||
if ($abhaField && $abhaNumClean !== '') {
|
||||
$insertData[$abhaField] = $abhaNumClean;
|
||||
}
|
||||
if ($abhaAddress !== '' && in_array('abha_address', $fields, true)) {
|
||||
$insertData['abha_address'] = $abhaAddress;
|
||||
}
|
||||
|
||||
$this->applyAbhaMetaColumns($insertData, $abhaMeta, $fields);
|
||||
if (($abhaNumClean !== '' || $abhaAddress !== '') && in_array('abdm_linked_at', $fields, true)) {
|
||||
$insertData['abdm_linked_at'] = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
$patientModel = new \App\Models\PatientModel();
|
||||
$patientId = $patientModel->insertPatient($insertData);
|
||||
|
|
@ -370,9 +447,198 @@ class Abha extends BaseController
|
|||
$pCode = (string) ($row['p_code'] ?? '');
|
||||
}
|
||||
|
||||
if ($patientId > 0) {
|
||||
$this->syncAbhaMetaToPatient($patientId, $abhaMeta, $abhaNumClean, $abhaAddress, $fields);
|
||||
}
|
||||
|
||||
return ['patient_id' => $patientId, 'p_code' => $pCode, 'is_new' => true];
|
||||
}
|
||||
|
||||
private function syncAbhaMetaToPatient(int $patientId, array $abhaMeta, string $abhaNumClean, string $abhaAddress, array $fields): void
|
||||
{
|
||||
if ($patientId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
$updates = [];
|
||||
if ($abhaAddress !== '' && in_array('abha_address', $fields, true)) {
|
||||
$updates['abha_address'] = $abhaAddress;
|
||||
}
|
||||
|
||||
$this->applyAbhaMetaColumns($updates, $abhaMeta, $fields);
|
||||
|
||||
if (($abhaNumClean !== '' || $abhaAddress !== '') && in_array('abdm_linked_at', $fields, true)) {
|
||||
$updates['abdm_linked_at'] = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
if ($updates !== []) {
|
||||
$db->table('patient_master')->where('id', $patientId)->update($updates);
|
||||
}
|
||||
}
|
||||
|
||||
private function applyAbhaMetaColumns(array &$target, array $abhaMeta, array $fields): void
|
||||
{
|
||||
$verifiedStatus = trim((string) ($abhaMeta['verified_status'] ?? ''));
|
||||
if ($verifiedStatus !== '' && in_array('abha_verified_status', $fields, true)) {
|
||||
$target['abha_verified_status'] = strtoupper($verifiedStatus);
|
||||
}
|
||||
|
||||
$verificationType = trim((string) ($abhaMeta['verification_type'] ?? ''));
|
||||
if ($verificationType !== '' && in_array('abha_verification_type', $fields, true)) {
|
||||
$target['abha_verification_type'] = strtoupper($verificationType);
|
||||
}
|
||||
|
||||
if (array_key_exists('kyc_verified', $abhaMeta) && in_array('abha_kyc_verified', $fields, true)) {
|
||||
$target['abha_kyc_verified'] = $this->toDbBool($abhaMeta['kyc_verified']);
|
||||
}
|
||||
|
||||
if (array_key_exists('mobile_verified', $abhaMeta) && in_array('abha_mobile_verified', $fields, true)) {
|
||||
$target['abha_mobile_verified'] = $this->toDbBool($abhaMeta['mobile_verified']);
|
||||
}
|
||||
|
||||
$profilePhoto = trim((string) ($abhaMeta['profile_photo'] ?? ''));
|
||||
if ($profilePhoto !== '' && in_array('abha_profile_photo_base64', $fields, true)) {
|
||||
$target['abha_profile_photo_base64'] = $profilePhoto;
|
||||
}
|
||||
}
|
||||
|
||||
private function toDbBool($value): int
|
||||
{
|
||||
if (is_bool($value)) {
|
||||
return $value ? 1 : 0;
|
||||
}
|
||||
|
||||
$v = strtolower(trim((string) $value));
|
||||
if ($v === '1' || $v === 'true' || $v === 'yes' || $v === 'y') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function toPatientGenderValue(string $gender): int
|
||||
{
|
||||
$genderAbs = strtoupper(trim($gender));
|
||||
if ($genderAbs === 'F' || $genderAbs === '2' || $genderAbs === 'FEMALE') {
|
||||
return 2;
|
||||
}
|
||||
if ($genderAbs === 'O' || $genderAbs === '3' || $genderAbs === 'OTHER') {
|
||||
return 3;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private function normalizeDobToDb(string $dob): string
|
||||
{
|
||||
$dob = trim($dob);
|
||||
if ($dob === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (preg_match('/^(\d{2})-(\d{2})-(\d{4})$/', $dob, $m)) {
|
||||
return $m[3] . '-' . $m[2] . '-' . $m[1];
|
||||
}
|
||||
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $dob)) {
|
||||
return $dob;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Find one safe placeholder candidate to repair.
|
||||
* Conditions:
|
||||
* - name is ABHA PATIENT
|
||||
* - ABHA id and address are empty
|
||||
* - no OPD/invoice linkage
|
||||
* - inserted recently (last 24h)
|
||||
* - exactly one candidate (to avoid accidental overwrite)
|
||||
*
|
||||
* @param array<int, string> $fields
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
private function findRepairablePlaceholderPatient($db, array $fields): ?array
|
||||
{
|
||||
if (! $db->tableExists('patient_master')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$abhaField = null;
|
||||
foreach (['abha_id', 'abha_no', 'abha'] as $f) {
|
||||
if (in_array($f, $fields, true)) {
|
||||
$abhaField = $f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$builder = $db->table('patient_master p')
|
||||
->select('p.id,p.p_code,p.insert_date')
|
||||
->where('UPPER(TRIM(COALESCE(p.p_fname, "")))', 'ABHA PATIENT')
|
||||
->where('(p.mphone1 IS NULL OR TRIM(p.mphone1) = "")', null, false)
|
||||
->where('p.insert_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)', null, false);
|
||||
|
||||
if ($abhaField !== null) {
|
||||
$builder->where('(p.' . $abhaField . ' IS NULL OR TRIM(p.' . $abhaField . ') = "")', null, false);
|
||||
}
|
||||
if (in_array('abha_address', $fields, true)) {
|
||||
$builder->where('(p.abha_address IS NULL OR TRIM(p.abha_address) = "")', null, false);
|
||||
}
|
||||
|
||||
if ($db->tableExists('opd_master')) {
|
||||
$builder->where('NOT EXISTS (SELECT 1 FROM opd_master o WHERE o.p_id = p.id)', null, false);
|
||||
}
|
||||
if ($db->tableExists('invoice_master')) {
|
||||
$builder->where('NOT EXISTS (SELECT 1 FROM invoice_master i WHERE i.attach_type = 0 AND i.attach_id = p.id)', null, false);
|
||||
}
|
||||
|
||||
$rows = $builder->orderBy('p.id', 'DESC')->limit(2)->get()->getResultArray();
|
||||
if (count($rows) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $rows[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $payload
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function pickGatewayAbhaProfile(array $payload): array
|
||||
{
|
||||
$candidates = [
|
||||
$payload['gateway_patient'] ?? null,
|
||||
$payload['ABHAProfile'] ?? null,
|
||||
$payload['accounts'][0] ?? null,
|
||||
$payload['profile'] ?? null,
|
||||
$payload,
|
||||
];
|
||||
|
||||
foreach ($candidates as $candidate) {
|
||||
if (is_array($candidate) && $this->looksLikeGatewayAbhaProfile($candidate)) {
|
||||
return $candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $profile
|
||||
*/
|
||||
private function looksLikeGatewayAbhaProfile(array $profile): bool
|
||||
{
|
||||
foreach (['ABHANumber', 'abha_id', 'preferredAbhaAddress', 'abha_address', 'name', 'fullName', 'full_name', 'gender', 'dob', 'date_of_birth', 'profilePhoto', 'profile_photo'] as $key) {
|
||||
if (array_key_exists($key, $profile) && trim((string) $profile[$key]) !== '') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Validate ABHA number or address
|
||||
// POST abha/register/validate
|
||||
|
|
|
|||
|
|
@ -529,6 +529,7 @@ class Ipd_discharge extends BaseController
|
|||
// Main clinical discharge summary: use explicit DB field first (instruction_remark).
|
||||
// Fallback to section extraction for older cached content.
|
||||
$instructionRow = $ipdId > 0 ? $this->firstRowByIpd('ipd_discharge_instructions', $ipdId) : [];
|
||||
$instructionMeta = $this->parseInstructionMetaPayload((string) ($instructionRow['comp_report'] ?? ''));
|
||||
$clinicalSummaryRaw = $this->normalizeRichText((string) ($instructionRow['comp_remark'] ?? ''));
|
||||
$clinicalSummary = $clinicalSummaryRaw !== ''
|
||||
? '<div class="discharge-summary-content">' . $this->renderRichText($clinicalSummaryRaw) . '</div>'
|
||||
|
|
@ -599,6 +600,28 @@ class Ipd_discharge extends BaseController
|
|||
$otherAdvice = $section(['Other Advice:']);
|
||||
$followUpInstructions = $section(['Discharge Summary:']);
|
||||
|
||||
// Heading-only fragments are treated as empty and should fallback to DB-backed meta values.
|
||||
$otherAdviceHeadingOnly = trim(strip_tags((string) $otherAdvice));
|
||||
if (preg_match('/^Other\s+Advice\s*:?$/i', $otherAdviceHeadingOnly) === 1) {
|
||||
$otherAdvice = '';
|
||||
}
|
||||
|
||||
if ($otherAdvice === '') {
|
||||
$otherAdviceRaw = trim((string) ($instructionMeta['other_text'] ?? ''));
|
||||
if ($otherAdviceRaw === ''
|
||||
&& $this->tableHasColumns('ipd_discharge_drug_food_interaction', ['ipd_id'])
|
||||
&& $this->db->fieldExists('food_text', 'ipd_discharge_drug_food_interaction')) {
|
||||
$legacyFoodRow = $this->firstRowByIpd('ipd_discharge_drug_food_interaction', $ipdId);
|
||||
$otherAdviceRaw = trim((string) ($legacyFoodRow['food_text'] ?? ''));
|
||||
}
|
||||
|
||||
if ($otherAdviceRaw !== '') {
|
||||
$otherAdvice = '<div class="discharge-field"><strong>Other Advice:</strong> '
|
||||
. $this->renderStoredHtmlFragment($otherAdviceRaw)
|
||||
. '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore heading-only extraction (no real follow-up narrative text).
|
||||
$followUpHeadingOnly = trim(strip_tags((string) $followUpInstructions));
|
||||
if (preg_match('/^Discharge\s+Summary\s*:?$/i', $followUpHeadingOnly) === 1) {
|
||||
|
|
|
|||
|
|
@ -117,11 +117,13 @@ class Patient extends BaseController
|
|||
];
|
||||
$this->applyPatientAbhaFieldValues($data, $abhaId, $abhaAddress);
|
||||
|
||||
if ($chk_age === 'on') {
|
||||
$data['age'] = $age_year;
|
||||
$data['age_in_month'] = $age_month;
|
||||
} else {
|
||||
$data['dob'] = $this->parseDate($this->request->getPost('datepicker_dob'));
|
||||
if (!$isAbhaVerifiedLocked) {
|
||||
if ($chk_age === 'on') {
|
||||
$data['age'] = $age_year;
|
||||
$data['age_in_month'] = $age_month;
|
||||
} else {
|
||||
$data['dob'] = $this->parseDate($this->request->getPost('datepicker_dob'));
|
||||
}
|
||||
}
|
||||
|
||||
$patientModel = new PatientModel();
|
||||
|
|
@ -610,10 +612,14 @@ class Patient extends BaseController
|
|||
|
||||
$profile_file_path = '/assets/images/no_image.svg';
|
||||
$profile_picture_path = '';
|
||||
$abha_profile_photo_base64 = '';
|
||||
|
||||
if ($this->db->fieldExists('profile_picture', 'patient_master')) {
|
||||
$profile_picture_path = (string) ($data['data'][0]->profile_picture ?? '');
|
||||
}
|
||||
if ($this->db->fieldExists('abha_profile_photo_base64', 'patient_master')) {
|
||||
$abha_profile_photo_base64 = trim((string) ($data['data'][0]->abha_profile_photo_base64 ?? ''));
|
||||
}
|
||||
|
||||
$sql = "SELECT * from blood_group order by id";
|
||||
$query = $this->db->query($sql);
|
||||
|
|
@ -643,6 +649,10 @@ class Patient extends BaseController
|
|||
} else {
|
||||
$profile_file_path = $profile_picture_path;
|
||||
}
|
||||
} elseif ($abha_profile_photo_base64 !== '') {
|
||||
$profile_file_path = str_starts_with($abha_profile_photo_base64, 'data:image')
|
||||
? $abha_profile_photo_base64
|
||||
: 'data:image/jpeg;base64,' . $abha_profile_photo_base64;
|
||||
}
|
||||
|
||||
$data['profile_file_path'] = $profile_file_path;
|
||||
|
|
@ -663,11 +673,17 @@ class Patient extends BaseController
|
|||
}
|
||||
|
||||
$chk_age = $this->request->getPost('chk_age');
|
||||
$pid = (int) $this->request->getPost('p_id');
|
||||
$abhaIdInput = trim((string) $this->request->getPost('input_abha_id'));
|
||||
$abhaAddressInput = trim((string) $this->request->getPost('input_abha_address'));
|
||||
[$abhaId, $abhaAddress, $abhaError] = $this->normalizeAbhaInputs($abhaIdInput, $abhaAddressInput);
|
||||
$age_month = (string) $this->request->getPost('input_age_month');
|
||||
$age_year = (string) $this->request->getPost('input_age_year');
|
||||
$patientModel = new PatientModel();
|
||||
$existingPatient = $pid > 0 ? $patientModel->find($pid) : null;
|
||||
$isAbhaVerifiedLocked = is_array($existingPatient)
|
||||
&& trim((string) ($existingPatient['abha_id'] ?? $existingPatient['abha_no'] ?? $existingPatient['abha'] ?? $existingPatient['abha_address'] ?? '')) !== ''
|
||||
&& strtoupper(trim((string) ($existingPatient['abha_verified_status'] ?? ''))) === 'VERIFIED';
|
||||
|
||||
$rules = [
|
||||
'input_name' => 'required|min_length[1]|max_length[30]',
|
||||
|
|
@ -717,6 +733,23 @@ class Patient extends BaseController
|
|||
'estimate_dob' => $estimate_dob,
|
||||
'blood_group' => $this->request->getPost('input_blood_group'),
|
||||
];
|
||||
|
||||
if ($isAbhaVerifiedLocked) {
|
||||
$data['p_fname'] = (string) ($existingPatient['p_fname'] ?? $data['p_fname']);
|
||||
$data['gender'] = (string) ($existingPatient['gender'] ?? $data['gender']);
|
||||
$data['dob'] = $existingPatient['dob'] ?? ($data['dob'] ?? null);
|
||||
if (array_key_exists('age', $existingPatient)) {
|
||||
$data['age'] = $existingPatient['age'];
|
||||
}
|
||||
if (array_key_exists('age_in_month', $existingPatient)) {
|
||||
$data['age_in_month'] = $existingPatient['age_in_month'];
|
||||
}
|
||||
if (array_key_exists('estimate_dob', $existingPatient)) {
|
||||
$data['estimate_dob'] = $existingPatient['estimate_dob'];
|
||||
}
|
||||
$abhaId = trim((string) ($existingPatient['abha_id'] ?? $existingPatient['abha_no'] ?? $existingPatient['abha'] ?? $existingPatient['abha_address'] ?? $abhaId));
|
||||
}
|
||||
|
||||
$this->applyPatientAbhaFieldValues($data, $abhaId, $abhaAddress);
|
||||
|
||||
if ($chk_age === 'on') {
|
||||
|
|
@ -726,8 +759,6 @@ class Patient extends BaseController
|
|||
$data['dob'] = $this->parseDate($this->request->getPost('datepicker_dob'));
|
||||
}
|
||||
|
||||
$pid = (int) $this->request->getPost('p_id');
|
||||
$patientModel = new PatientModel();
|
||||
$patientModel->updatePatient($data, $pid);
|
||||
$this->saveNamesToNameList([
|
||||
(string) $this->request->getPost('input_name'),
|
||||
|
|
@ -1356,14 +1387,14 @@ class Patient extends BaseController
|
|||
}
|
||||
|
||||
$profile = $this->pickGatewayAbhaProfile($payload);
|
||||
$abhaNumberRaw = trim((string) ($profile['ABHANumber'] ?? $payload['ABHANumber'] ?? ''));
|
||||
$abhaNumberRaw = trim((string) ($profile['ABHANumber'] ?? $profile['abha_id'] ?? $payload['ABHANumber'] ?? $payload['abha_id'] ?? ''));
|
||||
$abhaDigits = preg_replace('/\D/', '', $abhaNumberRaw);
|
||||
$abhaAddress = trim((string) ($profile['preferredAbhaAddress'] ?? $payload['abha_address'] ?? ''));
|
||||
$gatewayName = trim((string) ($profile['name'] ?? $payload['name'] ?? ''));
|
||||
$abhaAddress = trim((string) ($profile['preferredAbhaAddress'] ?? $profile['abha_address'] ?? $payload['abha_address'] ?? $payload['preferredAbhaAddress'] ?? ''));
|
||||
$gatewayName = trim((string) ($profile['name'] ?? $profile['fullName'] ?? $profile['full_name'] ?? $payload['name'] ?? $payload['full_name'] ?? ''));
|
||||
$gatewayMobile = trim((string) ($profile['mobile'] ?? $payload['mobile'] ?? $payload['mobileNumber'] ?? ''));
|
||||
$gatewayDob = trim((string) ($profile['dob'] ?? $payload['dob'] ?? ''));
|
||||
$gatewayDob = trim((string) ($profile['dob'] ?? $profile['date_of_birth'] ?? $payload['dob'] ?? $payload['date_of_birth'] ?? ''));
|
||||
$gatewayGender = trim((string) ($profile['gender'] ?? $payload['gender'] ?? ''));
|
||||
$gatewayPhoto = trim((string) ($profile['profilePhoto'] ?? $payload['profilePhoto'] ?? ''));
|
||||
$gatewayPhoto = trim((string) ($profile['profilePhoto'] ?? $profile['profile_photo'] ?? $payload['profilePhoto'] ?? $payload['profile_photo'] ?? ''));
|
||||
|
||||
$patient = $this->findPatientForAbhaProfile($requestedPid, $abhaDigits, $gatewayMobile);
|
||||
$patientId = (int) ($patient['id'] ?? 0);
|
||||
|
|
@ -1467,22 +1498,37 @@ class Patient extends BaseController
|
|||
*/
|
||||
private function pickGatewayAbhaProfile(array $payload): array
|
||||
{
|
||||
if (isset($payload['gateway_patient']) && is_array($payload['gateway_patient'])) {
|
||||
return $payload['gateway_patient'];
|
||||
}
|
||||
if (isset($payload['ABHAProfile']) && is_array($payload['ABHAProfile'])) {
|
||||
return $payload['ABHAProfile'];
|
||||
}
|
||||
if (isset($payload['profile']) && is_array($payload['profile'])) {
|
||||
return $payload['profile'];
|
||||
}
|
||||
if (isset($payload['accounts'][0]) && is_array($payload['accounts'][0])) {
|
||||
return $payload['accounts'][0];
|
||||
$candidates = [
|
||||
$payload['gateway_patient'] ?? null,
|
||||
$payload['ABHAProfile'] ?? null,
|
||||
$payload['accounts'][0] ?? null,
|
||||
$payload['profile'] ?? null,
|
||||
$payload,
|
||||
];
|
||||
|
||||
foreach ($candidates as $candidate) {
|
||||
if (is_array($candidate) && $this->looksLikeGatewayAbhaProfile($candidate)) {
|
||||
return $candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $profile
|
||||
*/
|
||||
private function looksLikeGatewayAbhaProfile(array $profile): bool
|
||||
{
|
||||
foreach (['ABHANumber', 'abha_id', 'preferredAbhaAddress', 'abha_address', 'name', 'fullName', 'full_name', 'gender', 'dob', 'date_of_birth', 'profilePhoto', 'profile_photo'] as $key) {
|
||||
if (array_key_exists($key, $profile) && trim((string) $profile[$key]) !== '') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ class AbdmGatewaySettings extends BaseController
|
|||
|
||||
$token = $this->readSettingValue('EATRIA_BRIDGE_TOKEN');
|
||||
$hfrId = $this->readSettingValue('ABDM_HFR_ID');
|
||||
if ($hfrId === '') {
|
||||
$hfrId = $this->readSettingValue('H_HFR_ID');
|
||||
}
|
||||
$hmsName = $this->readSettingValue('ABDM_HMS_NAME');
|
||||
$gwUrl = $this->readSettingValue('EATRIA_BRIDGE_URL') ?: 'https://abdm-bridge.e-atria.in/api';
|
||||
$bridgeHospitalId = $this->readSettingValue('ABDM_BRIDGE_HOSPITAL_ID');
|
||||
|
|
@ -129,6 +132,9 @@ class AbdmGatewaySettings extends BaseController
|
|||
}
|
||||
if ($hfrId === '') {
|
||||
$hfrId = $this->readSettingValue('ABDM_HFR_ID');
|
||||
if ($hfrId === '') {
|
||||
$hfrId = $this->readSettingValue('H_HFR_ID');
|
||||
}
|
||||
}
|
||||
|
||||
$gwUrl = rtrim($gwUrl, '/');
|
||||
|
|
@ -210,7 +216,7 @@ class AbdmGatewaySettings extends BaseController
|
|||
]);
|
||||
}
|
||||
|
||||
$statusUrl = $gwUrl . '/v3/gateway/status';
|
||||
$statusUrl = $gwUrl . '/v3/gateway/status' . ($hfrId !== '' ? '?hfr_id=' . urlencode($hfrId) : '');
|
||||
$ch2 = curl_init();
|
||||
curl_setopt_array($ch2, [
|
||||
CURLOPT_URL => $statusUrl,
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ HTML;
|
|||
if ($this->db->tableExists('hospital_setting')) {
|
||||
$hsRows = $this->db->table('hospital_setting')
|
||||
->select('s_name, s_value')
|
||||
->whereIn('s_name', ['EATRIA_BRIDGE_URL', 'EATRIA_BRIDGE_TOKEN', 'ABDM_HFR_ID'])
|
||||
->whereIn('s_name', ['EATRIA_BRIDGE_URL', 'EATRIA_BRIDGE_TOKEN', 'ABDM_HFR_ID', 'H_HFR_ID'])
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
|
|
@ -192,6 +192,9 @@ HTML;
|
|||
if ($sName === 'ABDM_HFR_ID') {
|
||||
$hfrId = $sValue;
|
||||
}
|
||||
if ($sName === 'H_HFR_ID' && $hfrId === '') {
|
||||
$hfrId = $sValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddAbhaProfileMetaToPatientMaster extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! $this->tableExists('patient_master')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = $this->getColumns('patient_master');
|
||||
$add = [];
|
||||
|
||||
if (! in_array('abha_profile_photo_base64', $fields, true)) {
|
||||
$add['abha_profile_photo_base64'] = [
|
||||
'type' => 'LONGTEXT',
|
||||
'null' => true,
|
||||
];
|
||||
}
|
||||
|
||||
if (! in_array('abha_verified_status', $fields, true)) {
|
||||
$add['abha_verified_status'] = [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 30,
|
||||
'null' => true,
|
||||
];
|
||||
}
|
||||
|
||||
if (! in_array('abha_verification_type', $fields, true)) {
|
||||
$add['abha_verification_type'] = [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 30,
|
||||
'null' => true,
|
||||
];
|
||||
}
|
||||
|
||||
if (! in_array('abha_kyc_verified', $fields, true)) {
|
||||
$add['abha_kyc_verified'] = [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'null' => true,
|
||||
'default' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
if (! in_array('abha_mobile_verified', $fields, true)) {
|
||||
$add['abha_mobile_verified'] = [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'null' => true,
|
||||
'default' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
if ($add !== []) {
|
||||
$this->forge->addColumn('patient_master', $add);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (! $this->tableExists('patient_master')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = $this->getColumns('patient_master');
|
||||
foreach ([
|
||||
'abha_profile_photo_base64',
|
||||
'abha_verified_status',
|
||||
'abha_verification_type',
|
||||
'abha_kyc_verified',
|
||||
'abha_mobile_verified',
|
||||
] as $column) {
|
||||
if (in_array($column, $fields, true)) {
|
||||
$this->forge->dropColumn('patient_master', $column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getColumns(string $table): array
|
||||
{
|
||||
if (! preg_match('/^[a-zA-Z0-9_]+$/', $table)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = $this->db->query('SHOW COLUMNS FROM `' . $table . '`')->getResultArray();
|
||||
|
||||
return array_map(static fn (array $row): string => (string) ($row['Field'] ?? ''), $result);
|
||||
}
|
||||
|
||||
private function tableExists(string $table): bool
|
||||
{
|
||||
if (! preg_match('/^[a-zA-Z0-9_]+$/', $table)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$row = $this->db->query("SHOW TABLES LIKE '" . $table . "'")->getRowArray();
|
||||
|
||||
return ! empty($row);
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface
|
|||
if ($db->tableExists('hospital_setting')) {
|
||||
$rows = $db->table('hospital_setting')
|
||||
->select('s_name, s_value')
|
||||
->whereIn('s_name', ['EATRIA_BRIDGE_TOKEN', 'ABDM_BRIDGE_TOKEN', 'EATRIA_BRIDGE_URL', 'ABDM_HFR_ID'])
|
||||
->whereIn('s_name', ['EATRIA_BRIDGE_TOKEN', 'ABDM_BRIDGE_TOKEN', 'EATRIA_BRIDGE_URL', 'ABDM_HFR_ID', 'H_HFR_ID'])
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
|
|
@ -58,8 +58,12 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface
|
|||
if (! empty($dbSettings['EATRIA_BRIDGE_URL'])) {
|
||||
$this->baseUrl = rtrim(trim($dbSettings['EATRIA_BRIDGE_URL']), '/');
|
||||
}
|
||||
if (! empty($dbSettings['ABDM_HFR_ID'])) {
|
||||
$this->hfrId = trim($dbSettings['ABDM_HFR_ID']);
|
||||
$dbHfrId = trim((string) ($dbSettings['ABDM_HFR_ID'] ?? ''));
|
||||
if ($dbHfrId === '') {
|
||||
$dbHfrId = trim((string) ($dbSettings['H_HFR_ID'] ?? ''));
|
||||
}
|
||||
if ($dbHfrId !== '') {
|
||||
$this->hfrId = $dbHfrId;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
|
|
@ -87,6 +91,22 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface
|
|||
return trim($token, " \t\n\r\0\x0B\"'");
|
||||
}
|
||||
|
||||
private function normalizeBridgeGender($value): string
|
||||
{
|
||||
$v = strtoupper(trim((string) $value));
|
||||
if ($v === '1' || $v === 'M' || $v === 'MALE') {
|
||||
return 'M';
|
||||
}
|
||||
if ($v === '2' || $v === 'F' || $v === 'FEMALE') {
|
||||
return 'F';
|
||||
}
|
||||
if ($v === '3' || $v === 'O' || $v === 'OTHER' || $v === 'OTHERS') {
|
||||
return 'O';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Internal HTTP helper
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
@ -111,6 +131,10 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface
|
|||
*/
|
||||
private function get(string $path, array $query = []): array
|
||||
{
|
||||
// e-Atria bridge expects hfr_id alongside Bearer auth for GET endpoints too.
|
||||
if ($this->hfrId !== '' && empty($query['hfr_id'])) {
|
||||
$query['hfr_id'] = $this->hfrId;
|
||||
}
|
||||
return $this->httpCall('GET', $path, [], $query);
|
||||
}
|
||||
|
||||
|
|
@ -476,9 +500,19 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface
|
|||
}
|
||||
|
||||
foreach (['abha_id', 'doctor_name', 'department', 'notes', 'gender', 'year_of_birth'] as $optional) {
|
||||
if (! empty($data[$optional])) {
|
||||
$body[$optional] = (string) $data[$optional];
|
||||
if (empty($data[$optional])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($optional === 'gender') {
|
||||
$gender = $this->normalizeBridgeGender($data[$optional]);
|
||||
if ($gender !== '') {
|
||||
$body['gender'] = $gender;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$body[$optional] = (string) $data[$optional];
|
||||
}
|
||||
|
||||
return $this->post('/v3/records/push', $body);
|
||||
|
|
@ -582,6 +616,15 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface
|
|||
|
||||
public function opdTokenCreate(array $payload): array
|
||||
{
|
||||
if (array_key_exists('gender', $payload)) {
|
||||
$gender = $this->normalizeBridgeGender($payload['gender']);
|
||||
if ($gender !== '') {
|
||||
$payload['gender'] = $gender;
|
||||
} else {
|
||||
unset($payload['gender']);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->post('/v3/opd/token', $payload);
|
||||
}
|
||||
|
||||
|
|
@ -619,6 +662,15 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface
|
|||
|
||||
public function hipLinkToken(array $payload): array
|
||||
{
|
||||
if (array_key_exists('gender', $payload)) {
|
||||
$gender = $this->normalizeBridgeGender($payload['gender']);
|
||||
if ($gender !== '') {
|
||||
$payload['gender'] = $gender;
|
||||
} else {
|
||||
unset($payload['gender']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->hfrId !== '' && empty($payload['hfr_id'])) {
|
||||
$payload['hfr_id'] = $this->hfrId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -684,9 +684,9 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="mt-3 d-flex gap-2 flex-wrap">
|
||||
<a id="abhareg_result_profile_btn" href="#" class="btn btn-success btn-sm d-none">
|
||||
<button type="button" id="abhareg_result_profile_btn" class="btn btn-success btn-sm d-none" data-url="">
|
||||
<i class="bi bi-person-lines-fill me-1"></i>View Patient Profile
|
||||
</a>
|
||||
</button>
|
||||
<a id="abhareg_result_card_btn" href="#" target="_blank" class="btn btn-outline-primary btn-sm d-none">
|
||||
<i class="bi bi-card-image me-1"></i>Print ABHA Card
|
||||
</a>
|
||||
|
|
@ -1099,7 +1099,7 @@
|
|||
$('#abhareg_result_photo_ph').removeClass('d-none');
|
||||
}
|
||||
if (patId > 0) {
|
||||
$('#abhareg_result_profile_btn').attr('href', '<?= base_url('billing/patient/person_record') ?>/' + patId).removeClass('d-none');
|
||||
$('#abhareg_result_profile_btn').attr('data-url', '<?= base_url('billing/patient/person_record') ?>/' + patId).removeClass('d-none');
|
||||
}
|
||||
if (abhaRaw.length === 14) {
|
||||
$('#abhareg_result_card_btn').attr('href', '<?= base_url('abha/card/') ?>' + abhaRaw).removeClass('d-none');
|
||||
|
|
@ -1281,6 +1281,14 @@
|
|||
$('#abhareg_mob_otp_input').on('keypress', function(e) {
|
||||
if (e.which === 13) { $('#abhareg_mob_verify_btn').trigger('click'); }
|
||||
});
|
||||
|
||||
$('#abhareg_result_profile_btn').on('click', function() {
|
||||
var url = ($(this).attr('data-url') || '').toString().trim();
|
||||
if (url === '') {
|
||||
return;
|
||||
}
|
||||
load_form(url, 'Patient Profile');
|
||||
});
|
||||
})();
|
||||
/* ===== END ABHA REGISTRATION WIZARD ===== */
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,17 @@
|
|||
<?php
|
||||
$user = auth()->user();
|
||||
$patientAbhaId = (string) ($data[0]->abha_id ?? $data[0]->abha_no ?? $data[0]->abha ?? $data[0]->abha_address ?? '');
|
||||
$abhaAddress = trim((string) ($data[0]->abha_address ?? ''));
|
||||
$abhaVerifiedStatus = trim((string) ($data[0]->abha_verified_status ?? ''));
|
||||
$abhaVerificationType = trim((string) ($data[0]->abha_verification_type ?? ''));
|
||||
$abhaKycVerified = (int) ($data[0]->abha_kyc_verified ?? 0) === 1;
|
||||
$abhaMobileVerified = (int) ($data[0]->abha_mobile_verified ?? 0) === 1;
|
||||
$abhaLinkedAt = trim((string) ($data[0]->abdm_linked_at ?? ''));
|
||||
$abhaPhotoAvailable = trim((string) ($data[0]->abha_profile_photo_base64 ?? '')) !== '';
|
||||
$abhaVerifiedLocked = $patientAbhaId !== '' && strtoupper($abhaVerifiedStatus) === 'VERIFIED';
|
||||
$canEditNameAnytime = is_object($user) && method_exists($user, 'can') ? $user->can('billing.patient.edit-name-anytime') : false;
|
||||
$isAdmin = is_object($user) && method_exists($user, 'inGroup') ? $user->inGroup('admin') : false;
|
||||
$abhaLockNotice = $abhaVerifiedLocked ? 'ABHA verified: name, gender, ABHA ID, and date of birth are locked.' : '';
|
||||
|
||||
// Allow edit if within 24 hours OR user has edit-name-anytime permission OR is admin
|
||||
if ($data[0]->p_edit == 1 || $canEditNameAnytime || $isAdmin) {
|
||||
|
|
@ -60,7 +69,7 @@
|
|||
<div class="form-group">
|
||||
<label>Full Name</label>
|
||||
<input class="form-control input-sm" name="input_name" placeholder="Full Name"
|
||||
value="<?=$data[0]->p_fname ?>" type="text" autocomplete="off" <?=$readonlyName?>>
|
||||
value="<?=$data[0]->p_fname ?>" type="text" autocomplete="off" <?=($readonlyName !== '' || $abhaVerifiedLocked) ? 'readonly' : ''?>>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
|
|
@ -69,14 +78,17 @@
|
|||
<div class="radio">
|
||||
<label>
|
||||
<input name="optionsRadios_gender" id="options_gender1" value="1"
|
||||
<?=radio_checked("1",$data[0]->gender)?> type="radio">
|
||||
<?=radio_checked("1",$data[0]->gender)?> type="radio" <?= $abhaVerifiedLocked ? 'disabled' : '' ?>>
|
||||
Male
|
||||
</label>
|
||||
<label>
|
||||
<input name="optionsRadios_gender" id="options_gender2" value="2"
|
||||
<?=radio_checked("2",$data[0]->gender)?> type="radio">
|
||||
<?=radio_checked("2",$data[0]->gender)?> type="radio" <?= $abhaVerifiedLocked ? 'disabled' : '' ?>>
|
||||
Female
|
||||
</label>
|
||||
<?php if ($abhaVerifiedLocked) : ?>
|
||||
<input type="hidden" name="optionsRadios_gender" value="<?= esc((string) ($data[0]->gender ?? '')) ?>">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -93,7 +105,7 @@
|
|||
<label>ABHA ID</label>
|
||||
<input class="form-control input-sm" name="input_abha_id" id="input_abha_id"
|
||||
value="<?= esc($patientAbhaId) ?>" placeholder="14-digit ABHA ID" type="text"
|
||||
autocomplete="off" maxlength="14">
|
||||
autocomplete="off" maxlength="14" <?= $abhaVerifiedLocked ? 'readonly' : '' ?>>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
|
|
@ -104,6 +116,26 @@
|
|||
data-inputmask='"mask": "9999999999"' data-mask>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert-light border mt-2 mb-1">
|
||||
<div class="row">
|
||||
<div class="col-md-3"><strong>ABHA Address:</strong> <?= $abhaAddress !== '' ? esc($abhaAddress) : '-' ?></div>
|
||||
<div class="col-md-3"><strong>Status:</strong> <?= $abhaVerifiedStatus !== '' ? esc($abhaVerifiedStatus) : 'UNAVAILABLE' ?></div>
|
||||
<div class="col-md-3"><strong>Type:</strong> <?= $abhaVerificationType !== '' ? esc($abhaVerificationType) : '-' ?></div>
|
||||
<div class="col-md-3"><strong>Linked At:</strong> <?= $abhaLinkedAt !== '' ? esc($abhaLinkedAt) : '-' ?></div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 6px;">
|
||||
<div class="col-md-3"><strong>KYC Verified:</strong> <?= $abhaKycVerified ? 'YES' : 'NO' ?></div>
|
||||
<div class="col-md-3"><strong>Mobile Verified:</strong> <?= $abhaMobileVerified ? 'YES' : 'NO' ?></div>
|
||||
<div class="col-md-6"><strong>ABHA Photo:</strong> <?= $abhaPhotoAvailable ? 'AVAILABLE (BASE64 STORED)' : 'NOT AVAILABLE' ?></div>
|
||||
</div>
|
||||
<?php if ($abhaLockNotice !== '') : ?>
|
||||
<div class="row" style="margin-top: 6px;">
|
||||
<div class="col-md-12"><span class="badge bg-success-subtle text-success border border-success-subtle"><?= esc($abhaLockNotice) ?></span></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row well well-sm">
|
||||
<?php
|
||||
|
|
@ -127,8 +159,11 @@
|
|||
?>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<label><input id="chk_age" name="chk_age" type="checkbox" <?=$checkbox_checked?>>
|
||||
<label><input id="chk_age" name="chk_age" type="checkbox" <?=$checkbox_checked?> <?= $abhaVerifiedLocked ? 'disabled' : '' ?>>
|
||||
Estimate Age</label>
|
||||
<?php if ($abhaVerifiedLocked && $checkbox_checked === 'checked') : ?>
|
||||
<input type="hidden" name="chk_age" value="on">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div id="age_input_1" <?=$age_input_1?>>
|
||||
|
|
@ -140,14 +175,14 @@
|
|||
<td>Year :</td>
|
||||
<td><input class="form-control number input-sm" name="input_age_year"
|
||||
id="input_age_year" placeholder="Year" type="text"
|
||||
autocomplete="off" style=" width:100px;" value="<?=$data[0]->age?>">
|
||||
autocomplete="off" style=" width:100px;" value="<?=$data[0]->age?>" <?= $abhaVerifiedLocked ? 'readonly' : '' ?>>
|
||||
</td>
|
||||
<td style=" width:50px;"></td>
|
||||
<td>Month : </td>
|
||||
<td><input class="form-control number input-sm" name="input_age_month"
|
||||
id="input_age_month" placeholder="Month" type="text"
|
||||
autocomplete="off" style=" width:100px;"
|
||||
value="<?=$data[0]->age_in_month?>"></td>
|
||||
value="<?=$data[0]->age_in_month?>" <?= $abhaVerifiedLocked ? 'readonly' : '' ?>></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
|
@ -157,7 +192,7 @@
|
|||
<div class="col-md-4">
|
||||
<label> Date of Birth</label>
|
||||
<input class="form-control input-sm" name="datepicker_dob"
|
||||
id="datepicker_dob" type="date" value="<?=$DateofBirth ?>" />
|
||||
id="datepicker_dob" type="date" value="<?=$DateofBirth ?>" <?= $abhaVerifiedLocked ? 'readonly' : '' ?> />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,14 @@
|
|||
<?= csrf_field() ?>
|
||||
<?php
|
||||
$patientAbhaId = (string) ($data[0]->abha_id ?? $data[0]->abha_no ?? $data[0]->abha ?? $data[0]->abha_address ?? '');
|
||||
$abhaAddress = trim((string) ($data[0]->abha_address ?? ''));
|
||||
$abhaVerifiedStatus = trim((string) ($data[0]->abha_verified_status ?? ''));
|
||||
$abhaVerificationType = trim((string) ($data[0]->abha_verification_type ?? ''));
|
||||
$abhaKycVerified = (int) ($data[0]->abha_kyc_verified ?? 0) === 1;
|
||||
$abhaMobileVerified = (int) ($data[0]->abha_mobile_verified ?? 0) === 1;
|
||||
$abhaLinkedAt = trim((string) ($data[0]->abdm_linked_at ?? ''));
|
||||
$abhaPhotoAvailable = trim((string) ($data[0]->abha_profile_photo_base64 ?? '')) !== '';
|
||||
$isAbhaLinkedAndVerified = $patientAbhaId !== '' && strtoupper($abhaVerifiedStatus) === 'VERIFIED';
|
||||
?>
|
||||
<?php
|
||||
$user = auth()->user();
|
||||
|
|
@ -77,11 +85,13 @@
|
|||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#profile-insurance" type="button" role="tab">Insurance</button>
|
||||
</li>
|
||||
<?php if (!$isAbhaLinkedAndVerified) : ?>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#profile-abha" type="button" role="tab">
|
||||
<i class="bi bi-person-check me-1"></i>ABHA Create/Verify
|
||||
</button>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if(count($opd_List)>0) { ?>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#profile-opd" type="button" role="tab">OPD</button>
|
||||
|
|
@ -107,7 +117,13 @@
|
|||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Relation</div>
|
||||
<div class="col-lg-9 col-md-8"><?=$data[0]->p_relative?> <?=ucwords($data[0]->p_rname)?></div>
|
||||
<div class="col-lg-9 col-md-8">
|
||||
<?php if (trim((string) ($data[0]->p_relative ?? '')) !== '' || trim((string) ($data[0]->p_rname ?? '')) !== '') : ?>
|
||||
<?=$data[0]->p_relative?> <?=ucwords($data[0]->p_rname)?>
|
||||
<?php else : ?>
|
||||
<span class="badge bg-warning-subtle text-warning border border-warning-subtle">Relation not filled</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Aadhar No.</div>
|
||||
|
|
@ -123,6 +139,7 @@
|
|||
<span class="text-muted small">Not linked</span>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
<?php if (!$isAbhaLinkedAndVerified) : ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary py-0" style="font-size:12px"
|
||||
onclick="openAbhaOtpModal(
|
||||
<?= (int)$data[0]->id ?>,
|
||||
|
|
@ -131,6 +148,7 @@
|
|||
)">
|
||||
<i class="bi bi-person-check me-1"></i><?= $patientAbhaId !== '' ? 'Re-link ABHA' : 'Link ABHA via OTP' ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if ($patientAbhaId !== '') :
|
||||
$abhaCardNum = preg_replace('/\D/', '', $patientAbhaId);
|
||||
?>
|
||||
|
|
@ -144,6 +162,47 @@
|
|||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">ABHA Address</div>
|
||||
<div class="col-lg-9 col-md-8">
|
||||
<?php if ($abhaAddress !== '') : ?>
|
||||
<span class="badge bg-primary-subtle text-primary border border-primary-subtle"><?= esc($abhaAddress) ?></span>
|
||||
<?php else : ?>
|
||||
<span class="text-muted small">Not available</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">ABHA Verification</div>
|
||||
<div class="col-lg-9 col-md-8 d-flex align-items-center gap-2 flex-wrap">
|
||||
<?php if ($abhaVerifiedStatus !== '') : ?>
|
||||
<span class="badge bg-success-subtle text-success border border-success-subtle"><?= esc($abhaVerifiedStatus) ?></span>
|
||||
<?php else : ?>
|
||||
<span class="badge bg-secondary-subtle text-secondary border border-secondary-subtle">UNAVAILABLE</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($abhaVerificationType !== '') : ?>
|
||||
<span class="badge bg-info-subtle text-info border border-info-subtle"><?= esc($abhaVerificationType) ?></span>
|
||||
<?php endif; ?>
|
||||
|
||||
<span class="badge <?= $abhaKycVerified ? 'bg-success-subtle text-success border border-success-subtle' : 'bg-warning-subtle text-warning border border-warning-subtle' ?>">KYC <?= $abhaKycVerified ? 'YES' : 'NO' ?></span>
|
||||
<span class="badge <?= $abhaMobileVerified ? 'bg-success-subtle text-success border border-success-subtle' : 'bg-warning-subtle text-warning border border-warning-subtle' ?>">MOBILE <?= $abhaMobileVerified ? 'YES' : 'NO' ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">ABHA Linked At</div>
|
||||
<div class="col-lg-9 col-md-8">
|
||||
<?= $abhaLinkedAt !== '' ? esc($abhaLinkedAt) : '<span class="text-muted small">Not linked via OTP</span>' ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">ABHA Photo</div>
|
||||
<div class="col-lg-9 col-md-8">
|
||||
<span class="badge <?= $abhaPhotoAvailable ? 'bg-success-subtle text-success border border-success-subtle' : 'bg-secondary-subtle text-secondary border border-secondary-subtle' ?>">
|
||||
<?= $abhaPhotoAvailable ? 'AVAILABLE (BASE64 STORED)' : 'NOT AVAILABLE' ?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php $hpPatientSyncId = trim((string) ($data[0]->healthplix_sync_id ?? '')); ?>
|
||||
<?php if ($hpPatientSyncId !== '') : ?>
|
||||
<div class="row">
|
||||
|
|
@ -155,7 +214,13 @@
|
|||
<?php endif; ?>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Phone</div>
|
||||
<div class="col-lg-9 col-md-8"><?=$data[0]->mphone1?></div>
|
||||
<div class="col-lg-9 col-md-8">
|
||||
<?php if (trim((string) ($data[0]->mphone1 ?? '')) !== '') : ?>
|
||||
<?=$data[0]->mphone1?>
|
||||
<?php else : ?>
|
||||
<span class="badge bg-warning-subtle text-warning border border-warning-subtle">Phone not filled</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 label">Email</div>
|
||||
|
|
@ -179,6 +244,7 @@
|
|||
<button type="button" id="btn_update_aadhar" class="btn btn-info">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (!$isAbhaLinkedAndVerified) : ?>
|
||||
<div class="col-lg-6">
|
||||
<label class="form-label">ABHA ID</label>
|
||||
<div class="input-group input-group-sm">
|
||||
|
|
@ -193,6 +259,7 @@
|
|||
</div>
|
||||
<div class="form-text">Type to set manually, or use <i class="bi bi-person-check"></i> for OTP flow.</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="col-lg-6">
|
||||
<button type="button" class="btn btn-warning btn-sm mt-4" onclick="load_form('<?= base_url('billing/patient/show_cards') ?>/<?=$data[0]->id?>/1');">Insurance Update</button>
|
||||
</div>
|
||||
|
|
@ -312,9 +379,11 @@
|
|||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php if (!$isAbhaLinkedAndVerified) : ?>
|
||||
<div class="tab-pane fade pt-3" id="profile-abha" role="tabpanel">
|
||||
<?= view('partials/abha_create_panel', ['data' => $data, 'patientAbhaId' => $patientAbhaId]) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user