Add patient list age fields
- Include Age and BirthdateConversion in patient list responses - Keep Sex label transformation unchanged - Preserve existing patient audit/update behavior
This commit is contained in:
parent
8fdaf0ade7
commit
4f87be295b
@ -13,9 +13,9 @@ use App\Services\AuditService;
|
|||||||
class PatientModel extends BaseModel {
|
class PatientModel extends BaseModel {
|
||||||
protected $table = 'patient';
|
protected $table = 'patient';
|
||||||
protected $primaryKey = 'InternalPID';
|
protected $primaryKey = 'InternalPID';
|
||||||
protected $allowedFields = ['PatientID', 'AlternatePID', 'Prefix', 'NameFirst', 'NameMiddle', 'NameMaiden', 'NameLast', 'Suffix', 'NameAlias', 'Sex', 'Birthdate', 'PlaceOfBirth', 'Street_1', 'Street_2', 'Street_3',
|
protected $allowedFields = ['PatientID', 'AlternatePID', 'Prefix', 'NameFirst', 'NameMiddle', 'NameMaiden', 'NameLast', 'Suffix', 'NameAlias', 'Sex', 'Birthdate', 'PlaceOfBirth', 'Street_1', 'Street_2', 'Street_3',
|
||||||
'City', 'Province', 'ZIP', 'EmailAddress1', 'EmailAddress2', 'Phone', 'MobilePhone', 'Custodian', 'AccountNumber', 'Country', 'Race', 'MaritalStatus', 'Religion', 'Ethnic', 'Citizenship',
|
'City', 'Province', 'ZIP', 'EmailAddress1', 'EmailAddress2', 'Phone', 'MobilePhone', 'Custodian', 'AccountNumber', 'Country', 'Race', 'MaritalStatus', 'Religion', 'Ethnic', 'Citizenship',
|
||||||
'isDead', 'TimeOfDeath', 'LinkTo', 'CreateDate', 'DelDate' ];
|
'isDead', 'TimeOfDeath', 'LinkTo', 'CreateDate', 'DelDate' ];
|
||||||
|
|
||||||
protected $useTimestamps = true;
|
protected $useTimestamps = true;
|
||||||
protected $createdField = 'CreateDate';
|
protected $createdField = 'CreateDate';
|
||||||
@ -48,6 +48,16 @@ class PatientModel extends BaseModel {
|
|||||||
$rows = ValueSet::transformLabels($rows, [
|
$rows = ValueSet::transformLabels($rows, [
|
||||||
'Sex' => 'sex',
|
'Sex' => 'sex',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
foreach ($rows as &$row) {
|
||||||
|
$birthdate = $row['Birthdate'] ?? null;
|
||||||
|
$row['Age'] = empty($birthdate)
|
||||||
|
? ''
|
||||||
|
: $this->calculateAgeFromBirthdate($birthdate, null);
|
||||||
|
$row['BirthdateConversion'] = $this->formatedDateForDisplay($birthdate);
|
||||||
|
}
|
||||||
|
unset($row);
|
||||||
|
|
||||||
return $rows;
|
return $rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,14 +92,14 @@ class PatientModel extends BaseModel {
|
|||||||
unset($patient['Identifier']);
|
unset($patient['Identifier']);
|
||||||
unset($patient['Comment']);
|
unset($patient['Comment']);
|
||||||
|
|
||||||
$patient = ValueSet::transformLabels([$patient], [
|
$patient = ValueSet::transformLabels([$patient], [
|
||||||
'Sex' => 'sex',
|
'Sex' => 'sex',
|
||||||
'Country' => 'country',
|
'Country' => 'country',
|
||||||
'Race' => 'race',
|
'Race' => 'race',
|
||||||
'Religion' => 'religion',
|
'Religion' => 'religion',
|
||||||
'Ethnic' => 'ethnic',
|
'Ethnic' => 'ethnic',
|
||||||
'MaritalStatus' => 'marital_status',
|
'MaritalStatus' => 'marital_status',
|
||||||
])[0];
|
])[0];
|
||||||
|
|
||||||
$patient['PatIdt'] = null;
|
$patient['PatIdt'] = null;
|
||||||
$patient['PatAtt'] = [];
|
$patient['PatAtt'] = [];
|
||||||
@ -151,24 +161,24 @@ class PatientModel extends BaseModel {
|
|||||||
$newInternalPID = $this->getInsertID();
|
$newInternalPID = $this->getInsertID();
|
||||||
$this->checkDbError($db, 'Insert patient');
|
$this->checkDbError($db, 'Insert patient');
|
||||||
|
|
||||||
$auditDiff = $this->buildAuditDiff([], $input);
|
$auditDiff = $this->buildAuditDiff([], $input);
|
||||||
AuditService::logData(
|
AuditService::logData(
|
||||||
'PATIENT_REGISTERED',
|
'PATIENT_REGISTERED',
|
||||||
'CREATE',
|
'CREATE',
|
||||||
'patient',
|
'patient',
|
||||||
(string) $newInternalPID,
|
(string) $newInternalPID,
|
||||||
'patient',
|
'patient',
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
'Patient registration',
|
'Patient registration',
|
||||||
[
|
[
|
||||||
'diff' => $auditDiff,
|
'diff' => $auditDiff,
|
||||||
'patient_id' => $input['PatientID'] ?? null,
|
'patient_id' => $input['PatientID'] ?? null,
|
||||||
'validation_profile' => 'patient.create',
|
'validation_profile' => 'patient.create',
|
||||||
],
|
],
|
||||||
['entity_version' => 1]
|
['entity_version' => 1]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!empty($patIdt)) {
|
if (!empty($patIdt)) {
|
||||||
$modelPatIdt->createPatIdt($patIdt, $newInternalPID);
|
$modelPatIdt->createPatIdt($patIdt, $newInternalPID);
|
||||||
@ -195,7 +205,7 @@ class PatientModel extends BaseModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatePatient($input) {
|
public function updatePatient($input) {
|
||||||
$db = \Config\Database::connect();
|
$db = \Config\Database::connect();
|
||||||
$modelPatIdt = new PatIdtModel();
|
$modelPatIdt = new PatIdtModel();
|
||||||
$modelPatCom = new PatComModel();
|
$modelPatCom = new PatComModel();
|
||||||
@ -219,30 +229,30 @@ class PatientModel extends BaseModel {
|
|||||||
$db->transBegin();
|
$db->transBegin();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$InternalPID = $input['InternalPID'];
|
$InternalPID = $input['InternalPID'];
|
||||||
$previousData = $this->find($InternalPID) ?? [];
|
$previousData = $this->find($InternalPID) ?? [];
|
||||||
$this->where('InternalPID',$InternalPID)->set($input)->update();
|
$this->where('InternalPID',$InternalPID)->set($input)->update();
|
||||||
$this->checkDbError($db, 'Update patient');
|
$this->checkDbError($db, 'Update patient');
|
||||||
|
|
||||||
$changedFields = array_keys(array_diff_assoc((array) $previousData, (array) $input));
|
$changedFields = array_keys(array_diff_assoc((array) $previousData, (array) $input));
|
||||||
$auditDiff = $this->buildAuditDiff((array) $previousData, $input);
|
$auditDiff = $this->buildAuditDiff((array) $previousData, $input);
|
||||||
AuditService::logData(
|
AuditService::logData(
|
||||||
'PATIENT_DEMOGRAPHICS_UPDATED',
|
'PATIENT_DEMOGRAPHICS_UPDATED',
|
||||||
'UPDATE',
|
'UPDATE',
|
||||||
'patient',
|
'patient',
|
||||||
(string) $InternalPID,
|
(string) $InternalPID,
|
||||||
'patient',
|
'patient',
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
'Patient data updated',
|
'Patient data updated',
|
||||||
[
|
[
|
||||||
'diff' => $auditDiff,
|
'diff' => $auditDiff,
|
||||||
'changed_fields' => $changedFields,
|
'changed_fields' => $changedFields,
|
||||||
'validation_profile' => 'patient.update',
|
'validation_profile' => 'patient.update',
|
||||||
],
|
],
|
||||||
['entity_version' => 1]
|
['entity_version' => 1]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!empty($input['PatIdt'])) {
|
if (!empty($input['PatIdt'])) {
|
||||||
$modelPatIdt->updatePatIdt($input['PatIdt'], $InternalPID);
|
$modelPatIdt->updatePatIdt($input['PatIdt'], $InternalPID);
|
||||||
@ -348,170 +358,170 @@ class PatientModel extends BaseModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function formatedDateForDisplay($dateString) {
|
private function formatedDateForDisplay($dateString) {
|
||||||
$date = \DateTime::createFromFormat('Y-m-d H:i', $dateString);
|
$date = \DateTime::createFromFormat('Y-m-d H:i', $dateString);
|
||||||
|
|
||||||
if (!$date) {
|
if (!$date) {
|
||||||
$timestamp = strtotime($dateString);
|
$timestamp = strtotime($dateString);
|
||||||
if ($timestamp) {
|
if ($timestamp) {
|
||||||
return date('j M Y', $timestamp);
|
return date('j M Y', $timestamp);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $date->format('j M Y');
|
return $date->format('j M Y');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatePatientPartial(int $InternalPID, array $input): ?int {
|
public function updatePatientPartial(int $InternalPID, array $input): ?int {
|
||||||
$db = \Config\Database::connect();
|
$db = \Config\Database::connect();
|
||||||
$modelPatIdt = new PatIdtModel();
|
$modelPatIdt = new PatIdtModel();
|
||||||
$modelPatCom = new PatComModel();
|
$modelPatCom = new PatComModel();
|
||||||
$modelPatAtt = new PatAttModel();
|
$modelPatAtt = new PatAttModel();
|
||||||
|
|
||||||
$patient = $this->find($InternalPID);
|
$patient = $this->find($InternalPID);
|
||||||
if (!$patient) {
|
if (!$patient) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$hasPatIdt = array_key_exists('PatIdt', $input);
|
$hasPatIdt = array_key_exists('PatIdt', $input);
|
||||||
$hasPatCom = array_key_exists('PatCom', $input);
|
$hasPatCom = array_key_exists('PatCom', $input);
|
||||||
$hasPatAtt = array_key_exists('PatAtt', $input);
|
$hasPatAtt = array_key_exists('PatAtt', $input);
|
||||||
|
|
||||||
$patIdt = $hasPatIdt ? $input['PatIdt'] : null;
|
$patIdt = $hasPatIdt ? $input['PatIdt'] : null;
|
||||||
$patCom = $hasPatCom ? $input['PatCom'] : null;
|
$patCom = $hasPatCom ? $input['PatCom'] : null;
|
||||||
$patAtt = $hasPatAtt ? $input['PatAtt'] : null;
|
$patAtt = $hasPatAtt ? $input['PatAtt'] : null;
|
||||||
|
|
||||||
unset($input['PatIdt'], $input['PatCom'], $input['PatAtt']);
|
unset($input['PatIdt'], $input['PatCom'], $input['PatAtt']);
|
||||||
|
|
||||||
if (array_key_exists('Custodian', $input)) {
|
if (array_key_exists('Custodian', $input)) {
|
||||||
if (is_array($input['Custodian'])) {
|
if (is_array($input['Custodian'])) {
|
||||||
$input['Custodian'] = $input['Custodian']['InternalPID'] ?? null;
|
$input['Custodian'] = $input['Custodian']['InternalPID'] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($input['Custodian'] !== null && $input['Custodian'] !== '') {
|
if ($input['Custodian'] !== null && $input['Custodian'] !== '') {
|
||||||
$input['Custodian'] = (int) $input['Custodian'];
|
$input['Custodian'] = (int) $input['Custodian'];
|
||||||
} else {
|
} else {
|
||||||
$input['Custodian'] = null;
|
$input['Custodian'] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array_key_exists('LinkTo', $input)) {
|
if (array_key_exists('LinkTo', $input)) {
|
||||||
if (is_array($input['LinkTo'])) {
|
if (is_array($input['LinkTo'])) {
|
||||||
$internalPids = array_column($input['LinkTo'], 'InternalPID');
|
$internalPids = array_column($input['LinkTo'], 'InternalPID');
|
||||||
$internalPids = array_filter($internalPids, static fn($pid) => $pid !== null && $pid !== '');
|
$internalPids = array_filter($internalPids, static fn($pid) => $pid !== null && $pid !== '');
|
||||||
$input['LinkTo'] = empty($internalPids) ? null : implode(',', $internalPids);
|
$input['LinkTo'] = empty($internalPids) ? null : implode(',', $internalPids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$allowedMap = array_flip($this->allowedFields);
|
$allowedMap = array_flip($this->allowedFields);
|
||||||
$patientUpdate = array_intersect_key($input, $allowedMap);
|
$patientUpdate = array_intersect_key($input, $allowedMap);
|
||||||
unset($patientUpdate['CreateDate'], $patientUpdate['DelDate']);
|
unset($patientUpdate['CreateDate'], $patientUpdate['DelDate']);
|
||||||
|
|
||||||
$db->transBegin();
|
$db->transBegin();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$previousData = $this->find($InternalPID) ?? [];
|
$previousData = $this->find($InternalPID) ?? [];
|
||||||
|
|
||||||
if ($patientUpdate !== []) {
|
if ($patientUpdate !== []) {
|
||||||
$this->where('InternalPID', $InternalPID)->set($patientUpdate)->update();
|
$this->where('InternalPID', $InternalPID)->set($patientUpdate)->update();
|
||||||
$this->checkDbError($db, 'Update patient');
|
$this->checkDbError($db, 'Update patient');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($hasPatIdt) {
|
if ($hasPatIdt) {
|
||||||
if ($patIdt === null || $patIdt === []) {
|
if ($patIdt === null || $patIdt === []) {
|
||||||
$modelPatIdt->deletePatIdt((string) $InternalPID);
|
$modelPatIdt->deletePatIdt((string) $InternalPID);
|
||||||
$this->checkDbError($db, 'Delete patidt');
|
$this->checkDbError($db, 'Delete patidt');
|
||||||
} else {
|
} else {
|
||||||
$modelPatIdt->updatePatIdt($patIdt, (string) $InternalPID);
|
$modelPatIdt->updatePatIdt($patIdt, (string) $InternalPID);
|
||||||
$this->checkDbError($db, 'Update patidt');
|
$this->checkDbError($db, 'Update patidt');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($hasPatCom) {
|
if ($hasPatCom) {
|
||||||
if ($patCom === null) {
|
if ($patCom === null) {
|
||||||
$modelPatCom->deletePatCom((string) $InternalPID);
|
$modelPatCom->deletePatCom((string) $InternalPID);
|
||||||
$this->checkDbError($db, 'Delete patcom');
|
$this->checkDbError($db, 'Delete patcom');
|
||||||
} else {
|
} else {
|
||||||
$modelPatCom->updatePatCom((string) $patCom, (string) $InternalPID);
|
$modelPatCom->updatePatCom((string) $patCom, (string) $InternalPID);
|
||||||
$this->checkDbError($db, 'Update PatCom');
|
$this->checkDbError($db, 'Update PatCom');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($hasPatAtt) {
|
if ($hasPatAtt) {
|
||||||
if ($patAtt === null) {
|
if ($patAtt === null) {
|
||||||
$modelPatAtt->deletePatAtt((string) $InternalPID);
|
$modelPatAtt->deletePatAtt((string) $InternalPID);
|
||||||
$this->checkDbError($db, 'Delete patatt');
|
$this->checkDbError($db, 'Delete patatt');
|
||||||
} else {
|
} else {
|
||||||
$modelPatAtt->updatePatAtt((array) $patAtt, (string) $InternalPID);
|
$modelPatAtt->updatePatAtt((array) $patAtt, (string) $InternalPID);
|
||||||
$this->checkDbError($db, 'Update/Delete patatt');
|
$this->checkDbError($db, 'Update/Delete patatt');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$afterData = array_merge((array) $previousData, $patientUpdate);
|
$afterData = array_merge((array) $previousData, $patientUpdate);
|
||||||
$auditDiff = $this->buildAuditDiff((array) $previousData, $afterData);
|
$auditDiff = $this->buildAuditDiff((array) $previousData, $afterData);
|
||||||
$changedFields = array_column($auditDiff, 'field');
|
$changedFields = array_column($auditDiff, 'field');
|
||||||
|
|
||||||
if ($hasPatIdt) {
|
if ($hasPatIdt) {
|
||||||
$changedFields[] = 'PatIdt';
|
$changedFields[] = 'PatIdt';
|
||||||
}
|
}
|
||||||
if ($hasPatCom) {
|
if ($hasPatCom) {
|
||||||
$changedFields[] = 'PatCom';
|
$changedFields[] = 'PatCom';
|
||||||
}
|
}
|
||||||
if ($hasPatAtt) {
|
if ($hasPatAtt) {
|
||||||
$changedFields[] = 'PatAtt';
|
$changedFields[] = 'PatAtt';
|
||||||
}
|
}
|
||||||
|
|
||||||
AuditService::logData(
|
AuditService::logData(
|
||||||
'PATIENT_DEMOGRAPHICS_UPDATED',
|
'PATIENT_DEMOGRAPHICS_UPDATED',
|
||||||
'UPDATE',
|
'UPDATE',
|
||||||
'patient',
|
'patient',
|
||||||
(string) $InternalPID,
|
(string) $InternalPID,
|
||||||
'patient',
|
'patient',
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
'Patient data updated',
|
'Patient data updated',
|
||||||
[
|
[
|
||||||
'diff' => $auditDiff,
|
'diff' => $auditDiff,
|
||||||
'changed_fields' => array_values(array_unique($changedFields)),
|
'changed_fields' => array_values(array_unique($changedFields)),
|
||||||
'validation_profile' => 'patient.patch',
|
'validation_profile' => 'patient.patch',
|
||||||
],
|
],
|
||||||
['entity_version' => 1]
|
['entity_version' => 1]
|
||||||
);
|
);
|
||||||
|
|
||||||
$db->transCommit();
|
$db->transCommit();
|
||||||
|
|
||||||
return $InternalPID;
|
return $InternalPID;
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$db->transRollback();
|
$db->transRollback();
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildAuditDiff(array $before, array $after): array {
|
private function buildAuditDiff(array $before, array $after): array {
|
||||||
$diff = [];
|
$diff = [];
|
||||||
$fields = array_unique(array_merge(array_keys($before), array_keys($after)));
|
$fields = array_unique(array_merge(array_keys($before), array_keys($after)));
|
||||||
foreach ($fields as $field) {
|
foreach ($fields as $field) {
|
||||||
$prev = $before[$field] ?? null;
|
$prev = $before[$field] ?? null;
|
||||||
$next = $after[$field] ?? null;
|
$next = $after[$field] ?? null;
|
||||||
if ($prev === $next) {
|
if ($prev === $next) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$diff[] = [
|
$diff[] = [
|
||||||
'field' => $field,
|
'field' => $field,
|
||||||
'previous' => $prev,
|
'previous' => $prev,
|
||||||
'new' => $next,
|
'new' => $next,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return $diff;
|
return $diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function checkDbError($db, string $context) {
|
private function checkDbError($db, string $context) {
|
||||||
$error = $db->error();
|
$error = $db->error();
|
||||||
if (!empty($error['code'])) {
|
if (!empty($error['code'])) {
|
||||||
throw new \Exception(
|
throw new \Exception(
|
||||||
"{$context} failed: {$error['code']} - {$error['message']}"
|
"{$context} failed: {$error['code']} - {$error['message']}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -529,23 +539,23 @@ class PatientModel extends BaseModel {
|
|||||||
$this->delete($InternalPID);
|
$this->delete($InternalPID);
|
||||||
$this->checkDbError($db, 'Delete patient');
|
$this->checkDbError($db, 'Delete patient');
|
||||||
|
|
||||||
$auditDiff = $this->buildAuditDiff((array) $previousData, []);
|
$auditDiff = $this->buildAuditDiff((array) $previousData, []);
|
||||||
AuditService::logData(
|
AuditService::logData(
|
||||||
'PATIENT_DELETED',
|
'PATIENT_DELETED',
|
||||||
'DELETE',
|
'DELETE',
|
||||||
'patient',
|
'patient',
|
||||||
(string) $InternalPID,
|
(string) $InternalPID,
|
||||||
'patient',
|
'patient',
|
||||||
null,
|
null,
|
||||||
$previousData,
|
$previousData,
|
||||||
null,
|
null,
|
||||||
'Patient deleted',
|
'Patient deleted',
|
||||||
[
|
[
|
||||||
'diff' => $auditDiff,
|
'diff' => $auditDiff,
|
||||||
'patient_id' => $previousData['PatientID'] ?? null,
|
'patient_id' => $previousData['PatientID'] ?? null,
|
||||||
],
|
],
|
||||||
['entity_version' => 1]
|
['entity_version' => 1]
|
||||||
);
|
);
|
||||||
|
|
||||||
$db->transCommit();
|
$db->transCommit();
|
||||||
return $InternalPID;
|
return $InternalPID;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user