@php use App\Support\LoanBook\LoanValidationMessagePresenter; use Illuminate\Support\MessageBag; $workflowRoute = $workflowRoute ?? []; $approvalRailSteps = $approvalRailSteps ?? []; $approvalUiStages = $approvalUiStages ?? $approvalRailSteps; $workflowConfigured = $workflowConfigured ?? false; $canSubmitForApproval = $canSubmitForApproval ?? false; $canActOnWorkflow = $canActOnWorkflow ?? false; $canRejectWorkflow = $canRejectWorkflow ?? false; $canReopenRejected = $canReopenRejected ?? false; $canActOnFirstStep = $canActOnFirstStep ?? false; $workflowActionLabels = $workflowActionLabels ?? ['approve' => 'Approve', 'reject' => 'Reject & send back']; $workflowName = (string) ($workflowRoute['workflow_name'] ?? ''); $workflowKey = (string) ($workflowRoute['workflow_key'] ?? 'loan_application'); $borrowerBlocked = (string) (($borrowerDecision['borrower_category'] ?? '') ?: '') === 'blocked'; $appraisalIncomplete = ($appraisalReadiness['required'] ?? false) && ! ($appraisalReadiness['ready'] ?? false); $approveBlockedByAppraisal = $appraisalIncomplete; $canApproveUi = $canActOnWorkflow && ! $approveBlockedByAppraisal; $canOverrideBorrowerPolicy = $canOverrideBorrowerPolicy ?? false; $approvalActionErrorBag = new MessageBag(); foreach (['approval', 'comments', 'stage', 'decision_comment', 'approved_principal', 'approved_term_value', 'conditions_text', 'exception_reason', 'graduation_reason', 'decline_reason', 'reject_target'] as $approvalErrorKey) { foreach ($errors->get($approvalErrorKey) as $message) { $approvalActionErrorBag->add($approvalErrorKey, $message); } } $approvalValidationLines = LoanValidationMessagePresenter::lines($approvalActionErrorBag); $hasApprovalValidationErrors = count($approvalValidationLines) > 0; $approvalActionFromQuery = request()->query('approval_action'); $resolvedApprovalActionTab = in_array($approvalActionFromQuery, ['approve', 'reject', 'reopen_rejected'], true) ? $approvalActionFromQuery : null; $defaultApprovalActionTab = $resolvedApprovalActionTab ?? ($canApproveUi ? 'approve' : ($canRejectWorkflow ? 'reject' : 'approve')); // Land approvers on the attention checklist + final decision. $initialApprovalWorkStep = 3; $attentionAllApproved = (bool) data_get($approvalWorkspace, 'attention.all_approved', true); $attentionRequiredCount = (int) data_get($approvalWorkspace, 'attention.required_count', 0); $guarantorOtpDutyPending = (bool) data_get($approvalWorkspace, 'guarantor_otp.duty_required', false) && ! (bool) data_get($approvalWorkspace, 'guarantor_otp.all_verified', true); $finalApproveBlocked = $approveBlockedByAppraisal || ! empty($approvalWorkspace['frozen']) || ($attentionRequiredCount > 0 && ! $attentionAllApproved) || $guarantorOtpDutyPending; $approveBlockReasonKey = null; $approveBlockReason = null; $approveBlockReasonHint = null; if ($finalApproveBlocked) { if ($approveBlockedByAppraisal ?? false) { $approveBlockReasonKey = 'appraisal'; $approveBlockReason = 'Complete appraisal before you can advance this file.'; $approveBlockReasonHint = 'Finish the appraisal workspace, then return here to approve.'; } elseif (($attentionRequiredCount ?? 0) > 0 && ! $attentionAllApproved) { $approveBlockReasonKey = 'attention'; $approveBlockReason = 'Approve every review attention item above before proceeding.'; $approveBlockReasonHint = 'Check each row in Review attentions, then try again.'; } elseif ($guarantorOtpDutyPending) { $guarantorOtpRows = (array) data_get($approvalWorkspace, 'guarantor_otp.guarantors', []); $guarantorOtpPendingCount = collect($guarantorOtpRows)->filter( fn (array $row): bool => ! (bool) ($row['verified'] ?? false), )->count(); $approveBlockReasonKey = 'guarantor_otp'; $approveBlockReason = $guarantorOtpPendingCount === 1 ? 'Verify the guarantor by OTP before you can approve and advance.' : "Verify all {$guarantorOtpPendingCount} guarantors by OTP before you can approve and advance."; $approveBlockReasonHint = 'Use Send OTP on each guarantor row, enter the SMS code, then tap Verify.'; } elseif (! empty($approvalWorkspace['frozen'])) { $approveBlockReasonKey = 'frozen'; $approveBlockReason = 'This decision workspace is frozen and cannot be advanced.'; $approveBlockReasonHint = 'Contact an administrator if you believe this is an error.'; } else { $approveBlockReasonKey = 'generic'; $approveBlockReason = 'This approval action is currently blocked.'; $approveBlockReasonHint = 'Review the checklist above for outstanding requirements.'; } } $approveButtonLabel = (string) ($workflowActionLabels['approve'] ?? 'Approve'); if (str_contains($approveButtonLabel, 'Approve & advance to ')) { $approveButtonLabel = 'Approve and send to '.substr($approveButtonLabel, strlen('Approve & advance to ')); } elseif (str_contains($approveButtonLabel, 'Approve & move to booking')) { $approveButtonLabel = 'Approve and complete'; } $currentStageLabel = (string) ($workflowActionLabels['current'] ?? ''); if ($currentStageLabel === '' && $approvalUiStages !== []) { $currentStageRow = collect($approvalUiStages)->firstWhere('state', 'current'); if (is_array($currentStageRow)) { $currentStageLabel = (string) ($currentStageRow['label'] ?? ''); } elseif (collect($approvalUiStages)->every(static fn (array $step): bool => ($step['state'] ?? '') === 'done')) { $currentStageLabel = 'Credit approved'; } } $approvalCreditComplete = in_array((string) $application->stage, [ \App\Models\LoanBookApplication::STAGE_APPROVED, \App\Models\LoanBookApplication::STAGE_DISBURSED, ], true) || (string) ($application->workflow_status ?? '') === \App\Models\LoanBookApplication::WORKFLOW_STATUS_APPROVED || in_array((string) (($approvalRequest ?? null)?->current_status ?? ''), [ \App\Models\ApprovalRequest::STATUS_APPROVED, \App\Models\ApprovalRequest::STATUS_OVERRIDDEN, ], true); if ($approvalCreditComplete) { $currentStageLabel = 'Credit approved'; } $simplifiedApproveForm = app(\App\Services\Approval\LoanApplicationApprovalService::class) ->isLightweightApproveStep($application); @endphp
@if ($approvalEngineEnabled ?? false)
@include('loan.book.applications.partials.approval-desk-banner') @if (($appraisalReadiness['ready'] ?? false) && ! ($approveBlockedByAppraisal ?? false))
@endif @if (! $workflowConfigured)

Approval workflow not configured

Configure a loan application workflow in Workflow Center.

Open Workflow Center →
@else @include('loan.book.applications.partials.approval-attention-checklist') @if (($awaitingMakerCorrection ?? false) && ! ($canSubmitForApproval ?? false))

Correction required before resubmit

@if (filled($loanOfficerCorrectionNotes ?? null))

Approver note: {{ $loanOfficerCorrectionNotes }}

@endif

Use Edit application to change the requested amount or product, open Appraisal to revise field work, then complete appraisal again before you submit for approval.

Edit application
@endif {{-- Gates stay visible when relevant --}} @if ($approveBlockedByAppraisal)

Appraisal required

@endif @if ($canSubmitForApproval)

{{ ($awaitingLoanOfficerResubmit ?? false) ? 'Ready to resubmit' : 'Ready for approval' }}

@if ($awaitingLoanOfficerResubmit ?? false) Submit the corrected file back into the workflow. Later desks will review each attention item when the file reaches them. @else Submit the file into the workflow. Approvers on later desks will check each review attention — you do not approve those items yourself. @endif

@csrf
@endif @if ($canReopenRejected) @php $reopenTargets = $approvalWorkspace['reject_targets'] ?? \App\Support\Approval\ApprovalRejectTargetOptions::correctionWorkspaces(); $reopenTargetDefault = old('reject_target', $reopenTargets[0]['value'] ?? 'appraisal'); @endphp

Previously rejected — send back to a stage

Same as a normal rejection: choose the stage and leave correction notes so the file can continue.

@csrf @error('reject_target')

{{ $message }}

@enderror

Mandatory guideline for what must be fixed (min 10 characters).

@error('comments')

{{ $message }}

@enderror @error('approval')

{{ $message }}

@enderror
@endif @if ($canActOnWorkflow || $canRejectWorkflow || $approveBlockedByAppraisal) @include('loan.book.applications.partials.approval-proceed-form') @endif @if (! ($canActOnWorkflow || $canRejectWorkflow || $approveBlockedByAppraisal || $canSubmitForApproval)) @if ($workflowConfigured && ($approvalRequest ?? null) && $approvalRequest->isOpen() && ($approvalWaitingViewer ?? null)) @php $waitingViewerVariant = (string) (($approvalWaitingViewer['variant'] ?? 'waiting') === 'attention' ? 'amber' : 'slate'); @endphp
$waitingViewerVariant === 'amber', 'border-slate-200 bg-slate-50 text-slate-800' => $waitingViewerVariant !== 'amber', ])>

{{ $approvalWaitingViewer['title'] ?? 'Waiting for approval' }}

@if (! empty($approvalWaitingViewer['message']))

{{ $approvalWaitingViewer['message'] }}

@endif
@elseif ( ! ($canSubmitForApproval ?? false) && ! $approvalRequest && in_array((string) $application->stage, [\App\Models\LoanBookApplication::STAGE_SUBMITTED, \App\Models\LoanBookApplication::STAGE_CREDIT_REVIEW], true) )

You do not have permission to act on this approval workflow.

@endif @endif @if ($approvalRequest)
Request status
{{ str($approvalRequest->current_status)->headline() }}
Submitted by
{{ $approvalRequest->requester?->name ?? '—' }}
Submitted at
{{ $approvalRequest->submitted_at?->format('Y-m-d H:i') ?? '—' }}
@if ($approvalRequest->actions->isNotEmpty())
    @foreach ($approvalRequest->actions as $action)
  • {{ str($action->action_type)->headline() }} {{ $action->created_at?->format('Y-m-d H:i') }}

    {{ $action->actor?->name ?? 'System' }}@if ($action->step_key) · {{ str($action->step_key)->headline() }}@endif

    @if ($action->comments)

    {{ $action->comments }}

    @endif
  • @endforeach
@else

No decisions recorded yet.

@endif @if ($approvalRequest->overrides->isNotEmpty())

Override recorded

@foreach ($approvalRequest->overrides as $override)

{{ $override->actor?->name }}: {{ $override->reason }}

@endforeach
@endif
@endif @endif
@else

Credit decision

@if ($approvalRailSteps !== [])
@include('loan.book.applications.partials.application-360-approval-tracker', [ 'approvalUiStages' => $approvalUiStages, ])
@endif
Stage
{{ $stageLabel ?? str($application->stage)->headline() }}
Required level
{{ $workflowRoute['approval_level_required'] ?? 'Standard' }}
@if ($borrowerBlocked) @php $blockReasons = \App\Support\LoanBook\BorrowerBlockingReasonFormatter::describeMany( (array) ($borrowerDecision['blocking_reasons'] ?? []), (array) ($borrowerCapacity ?? []), $application->loanClient, ); @endphp

Borrower blocked

@if ($blockReasons !== [])
    @foreach ($blockReasons as $reasonLabel)
  • {{ $reasonLabel }}
  • @endforeach
@endif @if ($application->loanClient)

Open client profile

@endif
@endif @if ($hasApprovalValidationErrors) @endif @if (in_array((string) $application->stage, [\App\Models\LoanBookApplication::STAGE_SUBMITTED, \App\Models\LoanBookApplication::STAGE_CREDIT_REVIEW], true))
@csrf @method('PATCH')
Edit loan details
@else
Edit loan details Applications register
@endif
@endif