@php $workspace = $appraisalWorkspace ?? []; $workflow = $appraisalWorkflow ?? []; $appraisal = $workspace['appraisal'] ?? null; $canEdit = (bool) ($workspace['canEdit'] ?? false); $editLockReason = filled($workspace['editLockReason'] ?? null) ? (string) $workspace['editLockReason'] : null; $canComplete = (bool) ($workspace['canComplete'] ?? false); $officerComplete = (bool) ($appraisal?->isOfficerWorkComplete() ?? false); // Signature + Complete must be available while editable. Readiness may require // the officer signature, so gating the pad on canComplete creates a deadlock. $canSignAndFinish = $canEdit && ! $officerComplete; $readOnlyBrowse = ! $canEdit; $collateralSummary = $workspace['collateralSummary'] ?? []; $tableItems = $workspace['collateralTableItems'] ?? []; $completionErrors = (array) ($workspace['completionErrors'] ?? []); $investigation = $workspace['field_investigation'] ?? []; $repeatBorrowerHistory = $workspace['repeat_borrower_history'] ?? []; $pastCollateralCatalog = $workspace['past_collateral_catalog'] ?? ['applicant' => [], 'guarantor' => [], 'is_repeat_borrower' => false]; $workspaceGuidance = $workspace['workspace_guidance'] ?? []; $verificationPhotos = $investigation['verification_photos'] ?? []; $businessGpsReady = (bool) ($investigation['business_gps_ready'] ?? false); $fieldPhotoCount = (int) ($investigation['verification_photo_count'] ?? count($verificationPhotos)); $hasInitialCollateral = collect($tableItems)->contains(function ($row) { return filled($row['item'] ?? null) || filled($row['description'] ?? null) || filled($row['identification'] ?? null) || filled($row['value'] ?? null); }); $policyPayload = $workspace['policy'] ?? []; $guarantorSignatureRequired = (bool) data_get($policyPayload, 'appraisal.guarantor_signature_required', false); $officerSignatureRequired = (bool) data_get($policyPayload, 'appraisal.officer_signature_required', true); $requirementDefs = []; if ($guarantorSignatureRequired) { $requirementDefs['guarantor_signature'] = 'Guarantor signature'; } if ($officerSignatureRequired) { $requirementDefs['officer_signature'] = 'Loan officer signature'; } $requirementItems = []; foreach ($requirementDefs as $errorKey => $label) { $anchor = match ($errorKey) { 'guarantor_signature' => 'appraisal-guarantors', 'officer_signature' => 'appraisal-officer-signature', default => 'appraisal-collateral', }; $requirementItems[] = [ 'key' => $errorKey, 'label' => $label, 'status' => array_key_exists($errorKey, $completionErrors) ? 'incomplete' : 'complete', 'anchor' => $anchor, ]; } $incompleteRequirements = collect($requirementItems)->where('status', 'incomplete')->values(); $firstIncompleteAnchor = $incompleteRequirements->first()['anchor'] ?? ''; $fieldInvestigationDone = filled($investigation['findings'] ?? null) || ! empty($investigation['visits']); $fieldVisitRequired = (bool) data_get($policyPayload, 'appraisal.visit_required', false) || (bool) data_get($policyPayload, 'appraisal.field_investigation_required', false); if (! $fieldInvestigationDone && ! $fieldVisitRequired) { $fieldInvestigationDone = filled($investigation['visit_date'] ?? null); } $repeatBorrowerReviewRequired = $repeatBorrowerHistory !== []; $repeatBorrowerReviewDone = ! $repeatBorrowerReviewRequired || collect($repeatBorrowerHistory)->every(fn (array $row): bool => (bool) ($row['review_submitted'] ?? false)); // Appraisal workspace is Security → Field visit → Sign-off. Open on the first workflow // step that still needs input — not on sign-off just because the officer signature is missing. $collateralRequired = (bool) data_get($policyPayload, 'collateral.required', false); $initialStep = match (true) { $readOnlyBrowse && $officerComplete => 1, $officerComplete => 3, $collateralRequired && ! $hasInitialCollateral => 1, ! $fieldInvestigationDone => 2, default => 3, }; $initialSecurityTab = ($readOnlyBrowse && $officerComplete) || ! in_array($firstIncompleteAnchor, ['appraisal-guarantors', 'appraisal-guarantor-signature'], true) ? 'collateral' : 'guarantors'; // Always present the register table when editable so resume-from-register is not an empty state. $showCollateralEditor = $canEdit || $hasInitialCollateral; $visitingOfficer = old('visiting_officer', $investigation['visiting_officer'] ?? ''); $canPickVisitingOfficer = (bool) ($investigation['can_pick_visiting_officer'] ?? false); $visitingOfficerOptions = $investigation['visiting_officer_options'] ?? []; $coAppraiserEmployeeId = (int) old('co_appraiser_employee_id', $investigation['co_appraiser_employee_id'] ?? 0); $coAppraiserOptions = $investigation['co_appraiser_options'] ?? []; $originationSummary = $workspace['origination_summary'] ?? []; $clientSum = $originationSummary['client'] ?? []; $gpsRaw = (string) ($clientSum['gps'] ?? '—'); $gpsReady = $gpsRaw !== '' && $gpsRaw !== '—' && ! str_contains(strtolower($gpsRaw), 'not captured'); $kycLabel = (string) ($clientSum['kyc'] ?? '—'); $officerSignatures = app(\App\Services\LoanBook\Appraisal\LoanBookAppraisalOfficerSignatureService::class); $hasOfficerSignature = $officerSignatures->hasSignature($appraisal); @endphp
@if ($errors->any()) @endif @if ($readOnlyBrowse && $editLockReason)

Appraisal is view-only

{{ $editLockReason }}

Use Next and Back below to browse what the loan officer submitted. It reopens for editing only if this file is rejected back to appraisal.

@endif {{-- Appraisal workspace progress (officer work, not loan lifecycle) --}}

{{ $workspaceGuidance['appraisal_desk'] ?? 'Appraisal' }}

{{ $workspaceGuidance['loan_stage'] ?? str($application->stage)->headline() }} {{ (int) ($workspaceGuidance['progress_percent'] ?? 0) }}%
@if (($workspaceGuidance['pending'] ?? []) !== [] && $canEdit)
@elseif ($canEdit) @endif {{-- Machine-only requirement keys for Complete-appraisal checks (no visible copy). --}} {{-- ═══════════════ STEP 1: Collateral Requirements ═══════════════ --}}

Fulfill collateral requirements

Complete applicant collateral first, followed by guarantor collateral.

{{-- Collateral --}}
@csrf

Applicant's collateral register

@if ($canEdit && ($pastCollateralCatalog['applicant'] ?? []) !== [])
@endif @if ($canEdit) @endif
@if ($canEdit) @endif
@if ($canEdit) @endif
Item Description Identification Value (KES)Actions
Total accepted security
Loan amount
Coverage

Continue to .

{{-- Guarantors --}}
@php $appraisalGuarantors = $application->guarantors ?? collect(); @endphp @if ($canEdit) @include('loan.book.applications.partials.guarantor-repeatable-fields', [ 'application' => $application, 'appraisal' => $appraisal, 'existingGuarantors' => $appraisalGuarantors, 'unifiedAppraisal' => true, 'pastGuarantorCollateral' => $pastCollateralCatalog['guarantor'] ?? [], ]) @else @include('loan.book.applications.partials.appraisal-guarantors-readonly', [ 'application' => $application, 'workspace' => $workspace, ]) @endif
{{-- ═══════════════ STEP 2: Field Verification ═══════════════ --}}

Field verification

Visit details, GPS, photos, and officer findings in one workspace.

Visit GPS {{ $businessGpsReady ? 'Captured' : 'Optional — not set' }}
Visit photos {{ $fieldPhotoCount > 0 ? $fieldPhotoCount.'/4 attached' : 'None yet' }}
Borrower GPS {{ $gpsReady ? 'Captured' : 'Missing on client profile' }}
Borrower ID photos {{ $kycLabel }}

Visit photos and visit GPS are captured on this page. Guarantor passport/ID photos are on Stage 2 (Guarantor collateral). Borrower ID photos and borrower GPS live on the Evidence tab.

@if ($canEdit)
@csrf

Visit photos (optional, max 4)

Shop, borrower, stock, signage, etc.

@foreach ($verificationPhotos as $photo) @endforeach
@foreach ($verificationPhotos as $index => $photo)

Photo {{ $index + 1 }}

@endforeach @for ($slot = $fieldPhotoCount; $slot < 4; $slot++) @endfor
@else @include('loan.book.applications.partials.appraisal-field-investigation-readonly', [ 'investigation' => $investigation, ]) @endif @if (! empty($investigation['visits']))
    @foreach ($investigation['visits'] as $visit)
  • #{{ $visit['id'] }} {{ $visit['title'] ?? '' }} · {{ $visit['status'] ?? '' }} · {{ $visit['completed_at'] ?? 'open' }}
  • @endforeach
@endif
{{-- ═══════════════ STEP 3: Officer Sign-off ═══════════════ --}}

Officer sign-off

{{ $readOnlyBrowse ? 'Review what the loan officer signed off.' : 'Review readiness, sign, and complete the appraisal.' }}

@if ($repeatBorrowerHistory !== []) @include('loan.book.applications.partials.repeat-borrower-history-review', [ 'repeatBorrowerHistory' => $repeatBorrowerHistory, 'repeatBorrowerGraduation' => $workspace['repeat_borrower_graduation'] ?? null, 'saveRepeatReviewUrl' => route('loan.book.applications.appraisal.repeat_borrower_review', $application), 'canSignAndFinish' => $canSignAndFinish, ]) @endif

Completion checklist

  • @if ($repeatBorrowerHistory !== [])
  • @endif
  • Loan officer signature
@if ($canSignAndFinish)
@csrf @include('loan.book.applications.partials.officer-appraisal-signature', [ 'appraisal' => $appraisal, 'canEdit' => true, 'saveFormId' => 'appraisal-officer-signature-form', ]) @else @include('loan.book.applications.partials.officer-appraisal-signature', [ 'appraisal' => $appraisal, 'canEdit' => false, ]) @endif
@if (($workflow['verifications'] ?? collect())->isNotEmpty())
    @foreach ($workflow['verifications'] as $verification)
  • {{ $verification->workflow_stage_label ?: $verification->workflow_stage_key }} · {{ $verification->actor?->name }} · {{ optional($verification->verified_at)->format('d-M-Y H:i') }} @if ($verification->comments)

    {{ $verification->comments }}

    @endif
  • @endforeach
@endif
@if ($canSignAndFinish)