fix(abdm): evaluate cooling from clinical event date and prevent reset on taskboard view

This commit is contained in:
DevSoftTech Server 2026-10-01 08:03:44 +05:30
parent 376cb7eeb1
commit 734b9a2bc4
7 changed files with 437 additions and 46 deletions

View File

@ -157,10 +157,7 @@ class AbdmTaskBoard extends BaseController
}
$taskType = (string) ($task['task_type'] ?? '');
$lastModified = ! empty($task['updated_at'])
? (string) $task['updated_at']
: (! empty($task['created_at']) ? (string) $task['created_at'] : null);
$lastModified = AbdmTaskBoardSyncService::resolveTaskClinicalTimestamp($task, $this->db);
$cooling = AbdmTaskBoardSyncService::calculateCooling($taskType, $lastModified);
$task['cooling_active'] = ! empty($cooling['is_cooling_active']);
@ -428,7 +425,10 @@ class AbdmTaskBoard extends BaseController
return;
}
$select = 'r.id, r.patient_id, r.patient_name, r.lab_type, r.charge_id, r.status, ' . implode(', ', $abhaSelectParts);
$labFields = $this->db->getFieldNames('lab_request') ?? [];
$dateFields = array_intersect(['reported_time', 'collected_time', 'Request_Date'], $labFields);
$dateSelect = ! empty($dateFields) ? (', r.' . implode(', r.', $dateFields)) : '';
$select = 'r.id, r.patient_id, r.patient_name, r.lab_type, r.charge_id, r.status' . $dateSelect . ', ' . implode(', ', $abhaSelectParts);
$rows = $this->db->table('lab_request r')
->select($select)
@ -466,6 +466,10 @@ class AbdmTaskBoard extends BaseController
continue;
}
$clinTs = ! empty($row['reported_time'])
? $row['reported_time']
: (! empty($row['collected_time']) ? $row['collected_time'] : ($row['Request_Date'] ?? ''));
$this->taskService->createOrRefreshTask(
$taskType,
'diagnosis',
@ -476,9 +480,10 @@ class AbdmTaskBoard extends BaseController
$abha,
'submit',
[
'lab_type' => $labType,
'invoice_id' => (int) ($row['charge_id'] ?? 0),
'trigger' => 'task_board.backfill',
'lab_type' => $labType,
'invoice_id' => (int) ($row['charge_id'] ?? 0),
'clinical_timestamp' => (string) $clinTs,
'trigger' => 'task_board.backfill',
]
);
}
@ -1217,6 +1222,18 @@ class AbdmTaskBoard extends BaseController
continue;
}
$exists = $this->db->table('abdm_work_tasks')
->select('id')
->where('task_type', 'health_document_publish')
->where('entity_type', 'doctor_document')
->where('entity_id', (string) $docId)
->whereIn('status', ['pending', 'in_progress', 'completed'])
->get(1)
->getRowArray();
if (! empty($exists)) {
continue;
}
$patientName = trim((string) ($row['p_fname'] ?? ''));
$this->taskService->createOrRefreshTask(
'health_document_publish',
@ -1228,8 +1245,9 @@ class AbdmTaskBoard extends BaseController
$abhaId,
'submit',
[
'patient_doc_id' => $docId,
'trigger' => 'patient_doc.compiled',
'patient_doc_id' => $docId,
'clinical_timestamp' => (string) (! empty($row['created_at']) ? $row['created_at'] : ($row['date_issue'] ?? '')),
'trigger' => 'patient_doc.compiled',
]
);
}
@ -1253,6 +1271,18 @@ class AbdmTaskBoard extends BaseController
continue;
}
$exists = $this->db->table('abdm_work_tasks')
->select('id')
->where('task_type', 'health_document_publish')
->where('entity_type', 'patient_document')
->where('entity_id', (string) $fileId)
->whereIn('status', ['pending', 'in_progress', 'completed'])
->get(1)
->getRowArray();
if (! empty($exists)) {
continue;
}
$patientName = trim((string) ($fRow['p_fname'] ?? ''));
$this->taskService->createOrRefreshTask(
'health_document_publish',
@ -1264,8 +1294,9 @@ class AbdmTaskBoard extends BaseController
$abhaId,
'submit',
[
'file_upload_id' => $fileId,
'trigger' => 'file_upload_data.created',
'file_upload_id' => $fileId,
'clinical_timestamp' => (string) ($fRow['insert_date'] ?? ''),
'trigger' => 'file_upload_data.created',
]
);
}
@ -1317,6 +1348,18 @@ class AbdmTaskBoard extends BaseController
continue;
}
$exists = $this->db->table('abdm_work_tasks')
->select('id')
->where('task_type', 'wellness_record_publish')
->where('entity_type', 'opd_vitals')
->where('entity_id', (string) $rxId)
->whereIn('status', ['pending', 'in_progress', 'completed'])
->get(1)
->getRowArray();
if (! empty($exists)) {
continue;
}
$patientName = trim((string) ($row['p_fname'] ?? ''));
$this->taskService->createOrRefreshTask(
'wellness_record_publish',
@ -1329,8 +1372,9 @@ class AbdmTaskBoard extends BaseController
'submit',
[
'opd_prescription_id' => $rxId,
'opd_session_id' => $opdId,
'trigger' => 'vitals.backfilled',
'opd_session_id' => $opdId,
'clinical_timestamp' => (string) ($row['date_opd_visit'] ?? ''),
'trigger' => 'vitals.backfilled',
]
);
}

View File

@ -2540,9 +2540,9 @@ class DoctorDocument extends BaseController
$visitDate = (string) ($source['visit_date'] ?? date('Y-m-d'));
$doctorName = (string) ($source['doctor_name'] ?? '');
if ($patientId > 0 && preg_match('/^\d{14}$/', $abhaDigits) === 1 && class_exists('\App\Libraries\Abdm\Task\AbdmTaskService')) {
if ($patientId > 0 && preg_match('/^\d{14}$/', $abhaDigits) === 1 && class_exists('\App\Libraries\AbdmWorkTaskService')) {
try {
$taskService = new \App\Libraries\Abdm\Task\AbdmTaskService();
$taskService = new \App\Libraries\AbdmWorkTaskService();
$taskService->createOrRefreshTask(
'health_document_publish',
'patient_doc',
@ -2554,6 +2554,7 @@ class DoctorDocument extends BaseController
'submit',
[
'patient_doc_id' => $patientDocId,
'clinical_timestamp' => (string) ($source['visit_date'] ?? date('Y-m-d H:i:s')),
'trigger' => 'patient_doc.compiled',
]
);

View File

@ -6043,9 +6043,9 @@ class Patient extends BaseController
$adapter = new \App\Libraries\Abdm\Fhir\Support\GatewayPayloadAdapter();
$gatewayPayload = $adapter->toGatewayPayload($generatorOutput, $source, $hfrId);
if ($pid > 0 && preg_match('/^\d{14}$/', $abhaDigits) === 1 && class_exists('\App\Libraries\Abdm\Task\AbdmTaskService')) {
if ($pid > 0 && preg_match('/^\d{14}$/', $abhaDigits) === 1 && class_exists('\App\Libraries\AbdmWorkTaskService')) {
try {
$taskService = new \App\Libraries\Abdm\Task\AbdmTaskService();
$taskService = new \App\Libraries\AbdmWorkTaskService();
$taskService->createOrRefreshTask(
'health_document_publish',
'file_upload_data',
@ -6057,6 +6057,7 @@ class Patient extends BaseController
'submit',
[
'file_upload_id' => $fileUploadId,
'clinical_timestamp' => date('Y-m-d H:i:s'),
'trigger' => 'file_upload_data.created',
]
);
@ -6167,9 +6168,9 @@ class Patient extends BaseController
$patientName = (string) ($source['patient']['name'] ?? 'Patient');
$abhaDigits = (string) ($source['patient']['abha_id'] ?? '');
if ($patientId > 0 && preg_match('/^\d{14}$/', $abhaDigits) === 1 && class_exists('\App\Libraries\Abdm\Task\AbdmTaskService')) {
if ($patientId > 0 && preg_match('/^\d{14}$/', $abhaDigits) === 1 && class_exists('\App\Libraries\AbdmWorkTaskService')) {
try {
$taskService = new \App\Libraries\Abdm\Task\AbdmTaskService();
$taskService = new \App\Libraries\AbdmWorkTaskService();
$taskService->createOrRefreshTask(
'wellness_record_publish',
'opd_prescription',
@ -6181,6 +6182,7 @@ class Patient extends BaseController
'submit',
[
'opd_session_id' => $opdSessionId,
'clinical_timestamp' => (string) ($source['visit_date'] ?? date('Y-m-d H:i:s')),
'trigger' => 'vitals.saved',
]
);

View File

@ -557,6 +557,9 @@ class AbdmTaskBoardSyncService
return $summary;
}
// Auto-discover any newly completed clinical records with ABHA
$this->backfillMissingWorkTasks(30, 100);
$supportedTaskTypes = [
'opd_prescription_publish',
'lab_report_publish',
@ -567,11 +570,12 @@ class AbdmTaskBoardSyncService
'ipd_discharge_publish',
];
// Fetch candidate batch wider than $limit to bypass cooling or retrying items without queue starvation
$tasks = $this->db->table('abdm_work_tasks')
->whereIn('task_type', $supportedTaskTypes)
->whereIn('status', ['pending', 'in_progress'])
->orderBy('id', 'ASC')
->limit(max(1, $limit))
->limit(max(60, $limit * 3))
->get()
->getResultArray();
@ -579,6 +583,8 @@ class AbdmTaskBoardSyncService
return $summary;
}
$processedCount = 0;
foreach ($tasks as $task) {
$taskId = (int) $task['id'];
$taskType = (string) $task['task_type'];
@ -586,8 +592,8 @@ class AbdmTaskBoardSyncService
$patientId = (int) ($task['patient_id'] ?? 0);
$abhaId = trim((string) ($task['abha_id'] ?? ''));
// Check cooling period from the latest modification/refresh timestamp
$lastModified = ! empty($task['updated_at']) ? $task['updated_at'] : ($task['created_at'] ?? date('Y-m-d H:i:s'));
// Check cooling period from the actual clinical event/modification timestamp
$lastModified = self::resolveTaskClinicalTimestamp($task, $this->db);
$cooling = self::calculateCooling($taskType, $lastModified);
if ($cooling['is_cooling_active']) {
@ -614,6 +620,10 @@ class AbdmTaskBoardSyncService
'patient' => $task['patient_name'] ?? '',
'status' => 'dry_run_eligible',
];
$processedCount++;
if ($processedCount >= $limit) {
break;
}
continue;
}
@ -636,11 +646,29 @@ class AbdmTaskBoardSyncService
];
} else {
$summary['failed']++;
$this->taskService->markTaskStatus(
$taskId,
'pending', // remain pending for retry on next cron tick
'Cron retry pending: ' . ($result['error'] ?? 'Sync failed')
);
$payload = ! empty($task['payload_json']) ? json_decode((string) $task['payload_json'], true) : [];
$retryCount = (int) ($payload['retry_count'] ?? 0) + 1;
$payload['retry_count'] = $retryCount;
$payload['last_error'] = (string) ($result['error'] ?? 'Sync failed');
$payload['last_failed_at'] = Time::now('Asia/Kolkata')->toDateTimeString();
$errJson = (string) json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$this->db->table('abdm_work_tasks')->where('id', $taskId)->update(['payload_json' => $errJson]);
if ($retryCount >= 5) {
$this->taskService->markTaskStatus(
$taskId,
'failed',
'Max cron retries (5) exceeded: ' . ($result['error'] ?? 'Sync failed')
);
} else {
$this->taskService->markTaskStatus(
$taskId,
'pending', // remain pending for retry on next cron tick
'Cron retry #' . $retryCount . ' pending: ' . ($result['error'] ?? 'Sync failed')
);
}
$summary['details'][] = [
'task_id' => $taskId,
'task_type' => $taskType,
@ -649,6 +677,11 @@ class AbdmTaskBoardSyncService
'error' => $result['error'] ?? 'Sync failed',
];
}
$processedCount++;
if ($processedCount >= $limit) {
break;
}
}
return $summary;
@ -724,7 +757,8 @@ class AbdmTaskBoardSyncService
$abhaNumber = trim((string) $patientRow['abha_id']);
}
$visitDate = date('Y-m-d');
$clinTs = self::resolveTaskClinicalTimestamp($task, $this->db);
$visitDate = ! empty($clinTs) && strtotime($clinTs) > 0 ? date('Y-m-d', strtotime($clinTs)) : date('Y-m-d');
$prefix = match ($taskType) {
'radiology_report_publish' => 'RAD-',
'lab_report_publish' => 'LAB-',
@ -942,5 +976,286 @@ class AbdmTaskBoardSyncService
{
return self::calculateCooling($taskType, $lastModified);
}
/**
* Resolves the actual clinical / event timestamp for a task to accurately measure cooling.
* Checks task payload meta, underlying clinical record tables, and falls back to created_at.
*
* @param array<string, mixed> $task
*/
public static function resolveTaskClinicalTimestamp(array $task, ?BaseConnection $db = null): string
{
$payload = ! empty($task['payload_json']) ? json_decode((string) $task['payload_json'], true) : [];
$meta = is_array($payload) ? ($payload['meta'] ?? []) : [];
// 1. Direct meta timestamps
foreach (['clinical_timestamp', 'event_date', 'reported_time', 'collected_time', 'given_date', 'date_opd_visit', 'discharge_date'] as $key) {
if (! empty($meta[$key]) && strtotime((string) $meta[$key]) > 0) {
return (string) $meta[$key];
}
}
$taskType = (string) ($task['task_type'] ?? '');
$entityType = (string) ($task['entity_type'] ?? '');
$entityId = (int) ($task['entity_id'] ?? 0);
if ($entityId > 0) {
try {
$dbConn = $db ?? db_connect();
// 2. Health Documents: file_upload_data or patient_doc
if (in_array($entityType, ['patient_document', 'file_upload_data'], true) || $taskType === 'health_document_publish') {
if ($dbConn->tableExists('file_upload_data')) {
$fRow = $dbConn->table('file_upload_data')->select('insert_date')->where('id', $entityId)->get(1)->getRowArray();
if (! empty($fRow['insert_date']) && strtotime((string) $fRow['insert_date']) > 0) {
return (string) $fRow['insert_date'];
}
}
if ($dbConn->tableExists('patient_doc')) {
$pRow = $dbConn->table('patient_doc')->select('created_at, date_issue')->where('id', $entityId)->get(1)->getRowArray();
$date = ! empty($pRow['created_at']) ? $pRow['created_at'] : ($pRow['date_issue'] ?? null);
if (! empty($date) && strtotime((string) $date) > 0) {
return (string) $date;
}
}
}
// 3. Lab / Radiology: lab_request
if ($entityType === 'lab_request' || in_array($taskType, ['lab_report_publish', 'radiology_report_publish'], true)) {
if ($dbConn->tableExists('lab_request')) {
$fields = $dbConn->getFieldNames('lab_request');
$selectCols = array_intersect(['reported_time', 'collected_time', 'Request_Date'], $fields);
if (! empty($selectCols)) {
$lRow = $dbConn->table('lab_request')->select(implode(', ', $selectCols))->where('id', $entityId)->get(1)->getRowArray();
foreach (['reported_time', 'collected_time', 'Request_Date'] as $col) {
if (! empty($lRow[$col]) && strtotime((string) $lRow[$col]) > 0) {
return (string) $lRow[$col];
}
}
}
}
}
// 4. Immunization: immunization_records
if ($entityType === 'immunization' || $taskType === 'immunization_record_publish') {
if ($dbConn->tableExists('immunization_records')) {
$iRow = $dbConn->table('immunization_records')->select('given_date, created_at')->where('id', $entityId)->get(1)->getRowArray();
$date = ! empty($iRow['given_date']) ? $iRow['given_date'] : ($iRow['created_at'] ?? null);
if (! empty($date) && strtotime((string) $date) > 0) {
return (string) $date;
}
}
}
// 5. Wellness: opd_prescription
if ($entityType === 'opd_prescription' || $entityType === 'opd_vitals' || $taskType === 'wellness_record_publish') {
if ($dbConn->tableExists('opd_prescription')) {
$fields = $dbConn->getFieldNames('opd_prescription');
$dateCol = in_array('date_opd_visit', $fields, true) ? 'date_opd_visit' : 'id';
$rxRow = $dbConn->table('opd_prescription')->select($dateCol)->where('id', $entityId)->get(1)->getRowArray();
if (! empty($rxRow['date_opd_visit']) && strtotime((string) $rxRow['date_opd_visit']) > 0) {
return (string) $rxRow['date_opd_visit'];
}
}
}
// 6. IPD Discharge: ipd_discharge
if ($entityType === 'ipd_discharge' || $taskType === 'ipd_discharge_publish') {
if ($dbConn->tableExists('ipd_discharge')) {
$dRow = $dbConn->table('ipd_discharge')->select('discharge_date, created_at')->where('id', $entityId)->get(1)->getRowArray();
$date = ! empty($dRow['discharge_date']) ? $dRow['discharge_date'] : ($dRow['created_at'] ?? null);
if (! empty($date) && strtotime((string) $date) > 0) {
return (string) $date;
}
}
}
} catch (\Throwable) {
// Silently fallback
}
}
// Fallback to task's created_at, or updated_at
return ! empty($task['created_at'])
? (string) $task['created_at']
: (! empty($task['updated_at']) ? (string) $task['updated_at'] : date('Y-m-d H:i:s'));
}
/**
* Backfill missing work tasks for finalized clinical records with ABHA.
* Ensures cron discovers and queues tasks even if staff haven't opened the web Task Board.
*/
public function backfillMissingWorkTasks(int $days = 30, int $limit = 100): void
{
if (! $this->db->tableExists('abdm_work_tasks') || ! $this->db->tableExists('patient_master')) {
return;
}
$patientFields = $this->db->getFieldNames('patient_master') ?? [];
$abhaCol = $this->resolveFirstExistingColumn($patientFields, ['abha_id', 'abha_no', 'abha_address', 'abha']);
if ($abhaCol === null) {
return;
}
$sinceDate = date('Y-m-d H:i:s', strtotime("-{$days} days"));
// 1. Health Documents: file_upload_data
if ($this->db->tableExists('file_upload_data')) {
$fileRows = $this->db->table('file_upload_data f')
->select('f.id, f.pid, f.insert_date, p.p_fname, p.' . $abhaCol . ' as abha_id', false)
->join('patient_master p', 'p.id = f.pid', 'inner')
->where('p.' . $abhaCol . ' !=', '')
->where('f.insert_date >=', $sinceDate)
->orderBy('f.id', 'DESC')
->limit($limit)
->get()
->getResultArray();
foreach ($fileRows as $fRow) {
$fileId = (int) ($fRow['id'] ?? 0);
$patientId = (int) ($fRow['pid'] ?? 0);
$abhaId = trim((string) ($fRow['abha_id'] ?? ''));
if ($fileId <= 0 || $patientId <= 0 || preg_match('/^\d{14}$/', $abhaId) !== 1) {
continue;
}
$exists = $this->db->table('abdm_work_tasks')
->select('id')
->where('task_type', 'health_document_publish')
->where('entity_type', 'patient_document')
->where('entity_id', (string) $fileId)
->get(1)
->getRowArray();
if (! empty($exists)) {
continue;
}
$this->taskService->createOrRefreshTask(
'health_document_publish',
'file_upload_data',
'patient_document',
(string) $fileId,
$patientId,
trim((string) ($fRow['p_fname'] ?? '')),
$abhaId,
'submit',
[
'file_upload_id' => $fileId,
'clinical_timestamp' => (string) ($fRow['insert_date'] ?? ''),
'trigger' => 'cron.backfill',
]
);
}
}
// 2. Health Documents: patient_doc
if ($this->db->tableExists('patient_doc')) {
$docRows = $this->db->table('patient_doc pd')
->select('pd.id, pd.p_id, pd.date_issue, pd.created_at, p.p_fname, p.' . $abhaCol . ' as abha_id', false)
->join('patient_master p', 'p.id = pd.p_id', 'inner')
->where('p.' . $abhaCol . ' !=', '')
->where('pd.created_at >=', $sinceDate)
->orderBy('pd.id', 'DESC')
->limit($limit)
->get()
->getResultArray();
foreach ($docRows as $dRow) {
$docId = (int) ($dRow['id'] ?? 0);
$patientId = (int) ($dRow['p_id'] ?? 0);
$abhaId = trim((string) ($dRow['abha_id'] ?? ''));
if ($docId <= 0 || $patientId <= 0 || preg_match('/^\d{14}$/', $abhaId) !== 1) {
continue;
}
$exists = $this->db->table('abdm_work_tasks')
->select('id')
->where('task_type', 'health_document_publish')
->where('entity_type', 'doctor_document')
->where('entity_id', (string) $docId)
->get(1)
->getRowArray();
if (! empty($exists)) {
continue;
}
$this->taskService->createOrRefreshTask(
'health_document_publish',
'patient_doc',
'doctor_document',
(string) $docId,
$patientId,
trim((string) ($dRow['p_fname'] ?? '')),
$abhaId,
'submit',
[
'patient_doc_id' => $docId,
'clinical_timestamp' => (string) (! empty($dRow['created_at']) ? $dRow['created_at'] : ($dRow['date_issue'] ?? '')),
'trigger' => 'cron.backfill',
]
);
}
}
// 3. Lab & Radiology: lab_request
if ($this->db->tableExists('lab_request')) {
$labFields = $this->db->getFieldNames('lab_request') ?? [];
$dateFields = array_intersect(['reported_time', 'collected_time', 'Request_Date'], $labFields);
$dateSelect = ! empty($dateFields) ? (', r.' . implode(', r.', $dateFields)) : '';
$labRows = $this->db->table('lab_request r')
->select('r.id, r.patient_id, r.patient_name, r.lab_type, r.charge_id, r.status' . $dateSelect . ', p.' . $abhaCol . ' as abha_id', false)
->join('patient_master p', 'p.id = r.patient_id', 'inner')
->where('r.status >=', 2)
->where('p.' . $abhaCol . ' !=', '')
->orderBy('r.id', 'DESC')
->limit($limit)
->get()
->getResultArray();
foreach ($labRows as $lRow) {
$labReqId = (int) ($lRow['id'] ?? 0);
$patientId = (int) ($lRow['patient_id'] ?? 0);
$abhaId = trim((string) ($lRow['abha_id'] ?? ''));
if ($labReqId <= 0 || $patientId <= 0 || preg_match('/^\d{14}$/', $abhaId) !== 1) {
continue;
}
$labType = (int) ($lRow['lab_type'] ?? 0);
$taskType = in_array($labType, [1, 2, 3, 4, 6], true) ? 'radiology_report_publish' : 'lab_report_publish';
$exists = $this->db->table('abdm_work_tasks')
->select('id')
->where('task_type', $taskType)
->where('entity_type', 'lab_request')
->where('entity_id', (string) $labReqId)
->get(1)
->getRowArray();
if (! empty($exists)) {
continue;
}
$clinTs = ! empty($lRow['reported_time'])
? $lRow['reported_time']
: (! empty($lRow['collected_time']) ? $lRow['collected_time'] : ($lRow['Request_Date'] ?? ''));
$this->taskService->createOrRefreshTask(
$taskType,
'diagnosis',
'lab_request',
(string) $labReqId,
$patientId,
trim((string) ($lRow['patient_name'] ?? '')),
$abhaId,
'submit',
[
'lab_type' => $labType,
'invoice_id' => (int) ($lRow['charge_id'] ?? 0),
'clinical_timestamp' => (string) $clinTs,
'trigger' => 'cron.backfill',
]
);
}
}
}
}

View File

@ -59,28 +59,54 @@ class AbdmWorkTaskService
->get(1)
->getRowArray();
$row = [
'source_module' => $sourceModule,
'patient_id' => $patientId > 0 ? $patientId : null,
'patient_name' => $patientName !== '' ? $patientName : null,
'abha_id' => $abhaId !== '' ? $abhaId : null,
'action_mode' => $actionMode !== '' ? $actionMode : null,
'payload_json' => (string) json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
'updated_at' => $now,
];
$encodedPayload = (string) json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if (! empty($existing)) {
$this->db->table('abdm_work_tasks')->where('id', (int) $existing['id'])->update($row);
$existingPayload = (string) ($existing['payload_json'] ?? '');
$existingAbha = trim((string) ($existing['abha_id'] ?? ''));
$existingPatientId = (int) ($existing['patient_id'] ?? 0);
// Only update if meaningful data changed (avoids cooling period reset on idempotent refresh)
$needsUpdate = ($existingAbha !== $abhaId)
|| ($existingPatientId !== $patientId)
|| ($existingPayload !== $encodedPayload);
if ($needsUpdate) {
$updateRow = [
'source_module' => $sourceModule,
'patient_id' => $patientId > 0 ? $patientId : null,
'patient_name' => $patientName !== '' ? $patientName : null,
'abha_id' => $abhaId !== '' ? $abhaId : null,
'action_mode' => $actionMode !== '' ? $actionMode : null,
'payload_json' => $encodedPayload,
'updated_at' => $now,
];
$this->db->table('abdm_work_tasks')->where('id', (int) $existing['id'])->update($updateRow);
}
return (int) $existing['id'];
}
$row['task_code'] = $this->generateTaskCode();
$row['task_type'] = $taskType;
$row['entity_type'] = $entityType;
$row['entity_id'] = $entityId;
$row['status'] = 'pending';
$row['priority'] = 'normal';
$row['created_at'] = $now;
$createdAt = ! empty($meta['clinical_timestamp']) && strtotime((string) $meta['clinical_timestamp']) > 0
? date('Y-m-d H:i:s', strtotime((string) $meta['clinical_timestamp']))
: $now;
$row = [
'task_code' => $this->generateTaskCode(),
'task_type' => $taskType,
'source_module' => $sourceModule,
'entity_type' => $entityType,
'entity_id' => $entityId,
'patient_id' => $patientId > 0 ? $patientId : null,
'patient_name' => $patientName !== '' ? $patientName : null,
'abha_id' => $abhaId !== '' ? $abhaId : null,
'action_mode' => $actionMode !== '' ? $actionMode : null,
'payload_json' => $encodedPayload,
'status' => 'pending',
'priority' => 'normal',
'created_at' => $createdAt,
'updated_at' => $now,
];
$this->db->table('abdm_work_tasks')->insert($row);
$insertId = (int) $this->db->insertID();

View File

@ -34,6 +34,7 @@ crontab -l 2>/dev/null | awk -v start="$BLOCK_START" -v end="$BLOCK_END" '
cat >> "$TMP_CRON" <<EOF
$BLOCK_START
* * * * * cd $PROJECT_DIR && $PHP_BIN spark abdm:push-sync --limit=20 --worker=cron-abdm-m2 >> $LOG_DIR/abdm_push_sync.log 2>&1
* * * * * cd $PROJECT_DIR && $PHP_BIN spark abdm:taskboard-sync --limit=20 >> $LOG_DIR/abdm_taskboard_sync.log 2>&1
* * * * * cd $PROJECT_DIR && $PHP_BIN spark abdm:sms-notify --limit=20 >> $LOG_DIR/abdm_sms_notify.log 2>&1
* * * * * cd $PROJECT_DIR && $PHP_BIN spark bridge:sync --limit 10 >> $LOG_DIR/bridge_sync.log 2>&1
* * * * * cd $PROJECT_DIR && $PHP_BIN spark snomed:process-coding >> $LOG_DIR/snomed_process.log 2>&1

View File

@ -104,6 +104,8 @@ cmd_install() {
$BLOCK_START
# ABDM M2 Care Context Push Sync (Every 1 minute)
* * * * * cd $project_dir && $php_bin spark abdm:push-sync --limit=20 --worker=cron-abdm-m2 >> $log_dir/abdm_push_sync.log 2>&1
# ABDM Work Task Board Auto-Link Sync (Every 1 minute)
* * * * * cd $project_dir && $php_bin spark abdm:taskboard-sync --limit=20 >> $log_dir/abdm_taskboard_sync.log 2>&1
# ABDM Deep-Link SMS Notification Sync (Every 1 minute)
* * * * * cd $project_dir && $php_bin spark abdm:sms-notify --limit=20 >> $log_dir/abdm_sms_notify.log 2>&1
# ABDM Bridge Records Sync (Every 1 minute)