error('neblogistic.partition and neblogistic.form_id must be configured.'); return 1; } $records = DB::table('neblogistic') ->where('status', 'Rejected') ->whereNull('rejected_at') ->where(function ($q) { $q->whereNull('rejected_reason')->orWhere('rejected_reason', ''); }) ->whereNotNull('submission_id') ->where('submission_id', '!=', '') ->orderBy('id') ->limit($batch) ->get(); if ($records->isEmpty()) { $this->info('No inconsistent neblogistic rows to process.'); return 0; } $processed = 0; $failed = 0; foreach ($records as $row) { try { $params = [ 'partition' => $partition, 'form_id' => $formId, 'id' => $row->submission_id, ]; $response = LambdaRequest::getrequest( 'form', 'formentity/getsubmissiondetails', $params, '', $timeout > 0 ? $timeout : null ); if (!is_object($response) || ($response->status ?? '') !== 'success') { Log::warning('Neblogistic sync: form API did not return success', [ 'neblogistic_id' => $row->id, 'submission_id' => $row->submission_id, 'response' => $response, ]); $failed++; continue; } $submission = $response->data->submission ?? null; if (!is_object($submission)) { Log::warning('Neblogistic sync: missing submission in response', [ 'neblogistic_id' => $row->id, 'submission_id' => $row->submission_id, ]); $failed++; continue; } $workflowStatus = strtolower((string) ($submission->workflow_status ?? '')); $updates = $this->buildUpdatesFromWorkflow($submission, $workflowStatus); if ($updates === null) { Log::info('Neblogistic sync: unsupported or empty workflow_status, skipping', [ 'neblogistic_id' => $row->id, 'submission_id' => $row->submission_id, 'workflow_status' => $workflowStatus, ]); continue; } $oldData = json_decode(json_encode($row), true); print_r($updates); DB::table('neblogistic')->where('id', $row->id)->update($updates); NeblogisticAuditService::logUpdate( $row->id, $oldData, $updates, null, null ); $processed++; $this->line(sprintf('Updated neblogistic id=%s submission_id=%s workflow=%s', $row->id, $row->submission_id, $workflowStatus)); } catch (\Throwable $e) { $failed++; Log::error('Neblogistic sync: exception', [ 'neblogistic_id' => $row->id ?? null, 'submission_id' => $row->submission_id ?? null, 'message' => $e->getMessage(), ]); } } $this->info(sprintf('Done. Updated: %d, failed/skipped: %d.', $processed, $failed)); return 0; } /** * @param object $submission * @return array|null */ private function buildUpdatesFromWorkflow($submission, string $workflowStatus): ?array { if ($workflowStatus === '') { return null; } $now = now()->format('Y-m-d H:i:s'); $actionDate = $this->parseSubmissionDate($submission); switch ($workflowStatus) { case 'rejected': return [ 'status' => 'Rejected', 'rejected_at' => $actionDate ? $actionDate->format('Y-m-d H:i:s') : $now, 'rejected_reason' => $this->latestRejectReason($submission) ?? 'Synced from form workflow', 'updated_at' => $now, ]; case 'approved': return [ 'status' => 'L1 Approved', 'l1_approved_at' => $actionDate ? $actionDate->format('Y-m-d H:i:s') : $now, 'rejected_at' => null, 'rejected_reason' => null, 'updated_at' => $now, ]; case 'unapproved': return [ 'status' => 'Requested', 'l1_approved_at' => null, 'rejected_at' => null, 'rejected_reason' => null, 'updated_at' => $now, ]; default: return null; } } /** * @param object $submission */ private function parseSubmissionDate($submission): ?Carbon { $raw = $submission->workflow_action_date ?? null; if ($raw === null || $raw === '') { return null; } try { return Carbon::parse($raw); } catch (\Exception $e) { return null; } } /** * approval_history is ordered with newest first (unshift on approve/reject). * * @param object $submission */ private function latestRejectReason($submission): ?string { $history = $submission->approval_history ?? null; if (!is_array($history)) { return null; } foreach ($history as $entry) { $entry = is_object($entry) ? get_object_vars($entry) : (array) $entry; $action = strtolower((string) ($entry['action'] ?? '')); if ($action !== 'reject') { continue; } $reason = trim((string) ($entry['reason'] ?? '')); return $reason !== '' ? $reason : null; } return null; } }