Rapport-Laravel/app/Console/Commands/NeblogisticSyncWorkflowStat...

212 lines
7.1 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Http\Requests\LambdaRequest;
use App\Services\NeblogisticAuditService;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class NeblogisticSyncWorkflowStatus extends Command
{
protected $signature = 'neblogistic:sync-workflow-status';
protected $description = 'Reconcile neblogistic rows stuck as Rejected without rejection metadata using form submission workflow_status';
public function handle(): int
{
$partition = config('neblogistic.partition', 'rapport-team3');
$formId = config('neblogistic.form_id', '1750914801-153443b9-94d0-4dcb-b3f3-4fa11588a0a9');
$batch = (int) config('neblogistic.batch_limit', 500);
$timeout = (int) config('neblogistic.http_timeout', 120);
if (empty($partition) || empty($formId)) {
$this->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<string, mixed>|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;
}
}