@extends('layouts.master') @section('title') {{ $requisition->reference_no }} @endsection @section('content') @component('components.breadcrumb') @slot('li_1') Requisitions @endslot @slot('title') {{ $requisition->reference_no }} @endslot @endcomponent @if(session('success')) @endif @if($errors->any()) @endif @if($hint = $requisition->action_hint) @php $overdue = app(\App\Services\SlaService::class)->overdue($requisition); @endphp @endif {{-- Emergency + restricted-item flags --}} @if($requisition->isEmergency() || $requisition->hasRestrictedItems())
@if($requisition->isEmergency()) Emergency / Urgent — fast-track @endif @if($requisition->hasRestrictedItems()) Restricted items — extra authorisation: {{ implode(', ', $requisition->restrictedItemNames()) }} @endif
@endif {{-- Required approvals — derived from the value-based Approval Matrix --}} @php $matrix = app(\App\Services\ApprovalMatrixService::class)->progress($requisition); @endphp @if(!empty($matrix['steps']))
Required approvals: @foreach($matrix['steps'] as $i => $step) @php $c = ['done' => 'success', 'current' => 'warning', 'pending' => 'secondary'][$step['state']]; @endphp @if($step['state']==='done')@elseif($step['state']==='current')@endif {{ $step['label'] }} @if(!$loop->last)@endif @endforeach @if($matrix['tier'])Tier: {{ $matrix['tier']->label }} ({{ $matrix['tier']->band_label }}) @elsedefault gates — no matching threshold tier@endif
@endif @php $hasAuth = $requisition->approvals->where('decision','approved')->whereIn('level',['area','pal'])->isNotEmpty(); @endphp @if($hasAuth)
View Approval Document
@endif
{{ $requisition->title }}
{{ $requisition->status_label }}
Reference{{ $requisition->reference_no }}
Station{{ $requisition->station?->name }}
End User{{ $requisition->endUser ? $requisition->endUser->name.' ('.$requisition->endUser->type_label.')' : '—' }}
Area{{ $requisition->area?->name }}
Priority{{ $requisition->priority }}
Needed By{{ optional($requisition->needed_by_date)->format('d M Y') ?? '—' }}
Raised By{{ $requisition->creator?->name }}
Procurement Method{{ $requisition->procurementMethod ? $requisition->procurementMethod->name.($requisition->procurementMethod->short_name ? ' ('.$requisition->procurementMethod->short_name.')' : '') : '—' }}
@if($requisition->formationStation)
Formation (Station){{ $requisition->formationStation->path }}
@endif
@if($requisition->description)

Description{{ $requisition->description }}

@endif @if($requisition->justification)

Justification{{ $requisition->justification }}

@endif @if($requisition->procurement_justification)

Method Justification{{ $requisition->procurement_justification }}

@endif
Line Items
@foreach($requisition->items as $line) @endforeach
Item / Description Qty Unit Unit Cost Line Total
{{ $line->item?->name ?? $line->description ?? '—' }} @if($line->item && $line->description){{ $line->description }}@endif {{ rtrim(rtrim(number_format($line->quantity,2),'0'),'.') }} {{ $line->uom?->abbreviation }} {{ $line->estimated_unit_cost !== null ? number_format($line->estimated_unit_cost,2) : '—' }} {{ number_format($line->estimated_line_total ?? 0,2) }}
Estimated Total {{ number_format($requisition->estimated_total,2) }}
@if($requisition->quotes->isNotEmpty() || $canPalProcess)
Quotes
@if($canPalProcess) @endif
@forelse($requisition->quotes->sortByDesc('is_selected') as $quote)
{{ $quote->supplier->name }} @if($quote->is_selected)Selected@endif
{{ $quote->quote_reference ? $quote->quote_reference.' · ' : '' }}{{ $quote->quote_date->format('d M Y') }} @if($quote->valid_until) · valid to {{ $quote->valid_until->format('d M Y') }}@endif @if($quote->notes){{ $quote->notes }}@endif @if($quote->attachment_path) Original quote document @endif
{{ $quote->currency }} {{ number_format($quote->total, 2) }}
sub {{ number_format($quote->subtotal,2) }} + tax {{ number_format($quote->tax_total,2) }}
@if($canPalProcess)
@unless($quote->is_selected)
@csrf
@endunless
@csrf @method('DELETE')
@endif
@empty

No quotes recorded yet.

@endforelse
@endif {{-- Automated quote analysis (quality + costing) --}} @php $analysis = $requisition->quoteAnalysis; @endphp @if($analysis || ($canPalProcess && $requisition->quotes->count() >= 1))
Quote Analysis
@php $ac = ['complete'=>'success','processing'=>'info','failed'=>'danger','pending'=>'warning'][$analysis->status ?? ''] ?? 'secondary'; @endphp @if($analysis){{ $analysis->status }}@endif @if($canPalProcess)
@csrf
@endif
@if(!$analysis || in_array($analysis->status, ['pending','processing']))

Analysis {{ $analysis->status ?? 'not run' }} — it runs automatically in the background once 2+ quotes exist (process the queue with php artisan queue:work), or click Run analysis for an instant result.

@elseif($analysis->status === 'complete')

{{ $analysis->summary }}

@foreach(($analysis->data['quotes'] ?? []) as $row) @endforeach
#SupplierTotalRatingCostQualityValue
{{ $row['rank'] }} {{ $row['supplier'] }} @if($row['quote_id'] == $analysis->recommended_quote_id)Recommended@endif @foreach($row['flags'] as $flag){{ $flag }}@endforeach {{ $row['currency'] }} {{ number_format($row['total'],2) }} {{ $row['rating'] !== null ? $row['rating'].'/5' : '—' }} {{ number_format($row['cost_score']*100) }}% {{ number_format($row['quality_score']*100) }}% {{ number_format($row['value_score']*100) }}% @if($canPalProcess && $row['quote_id'] != ($requisition->quotes->firstWhere('is_selected',true)?->id))
@csrf
@endif
{{ $analysis->data['method'] ?? '' }} · generated {{ optional($analysis->generated_at)->diffForHumans() }} @else

{{ $analysis->summary }}

@endif
@endif @foreach($requisition->purchaseOrders->where('status', '!=', \App\Models\PurchaseOrder::STATUS_CANCELLED)->sortByDesc('id') as $po)
Purchase Order {{ $po->po_number }}
{{ $po->status_label }} @php $poLink = \Illuminate\Support\Facades\URL::signedRoute('po.public', $po); $poMsg = 'Purchase Order '.$po->po_number.' from the Jamaica Constabulary Force (PAL Centre). View your Purchase Order and confirm receipt here: '.$poLink; $waDigits = preg_replace('/\D/', '', (string) $po->supplier?->phone); if (strlen($waDigits) === 10) $waDigits = '1'.$waDigits; // JA 10-digit -> 11 $waUrl = 'https://wa.me/'.$waDigits.'?text='.rawurlencode($poMsg); $mailUrl = 'mailto:'.($po->supplier?->email ?? '').'?subject='.rawurlencode('Purchase Order '.$po->po_number.' — JCF').'&body='.rawurlencode($poMsg); @endphp View / Download PO Delivery Sheet WhatsApp Email
Supplier{{ $po->supplier->name }}
Issued{{ $po->issue_date->format('d M Y') }} by {{ $po->issuedBy?->name }}
Expected Delivery{{ optional($po->expected_delivery_date)->format('d M Y') ?? '—' }}
@if($po->sent_to_supplier_at)
Sent to Supplier{{ $po->sent_to_supplier_at->format('d M Y, g:i a') }}
@endif
@php $f = fn($n) => rtrim(rtrim(number_format((float)$n,2),'0'),'.'); // Quantities delivered but not yet confirmed (awaiting inspection) — "in transit". $pendingByItem = []; foreach ($requisition->deliveries as $del) { if ($del->confirmed_at || $del->inspection_status === 'rejected') continue; foreach ($del->items as $di) { $pendingByItem[$di->purchase_order_item_id] = ($pendingByItem[$di->purchase_order_item_id] ?? 0) + (float) $di->quantity_delivered; } } $poOutstanding = $po->items->sum(fn($i) => max(0, (float)$i->quantity - (float)$i->quantity_received)); $poPending = array_sum(array_intersect_key($pendingByItem, $po->items->keyBy('id')->all())); @endphp
@foreach($po->items as $pi) @php $out = max(0, (float)$pi->quantity - (float)$pi->quantity_received); $pending = (float) ($pendingByItem[$pi->id] ?? 0); @endphp @endforeach
ItemQtyReceivedPendingOutstandingUnitLine Total
{{ $pi->description }} {{ $f($pi->quantity) }} {{ $f($pi->quantity_received) }} @if($pending > 0.0001){{ $f($pending) }}@else 0@endif @if($out > 0.0001){{ $f($out) }}@else0@endif {{ number_format($pi->unit_price,2) }} {{ number_format($pi->line_total,2) }}
Total ({{ $po->currency }}){{ number_format($po->total,2) }}
@if($poOutstanding > 0.0001)
{{ $f($poOutstanding) }} item(s) still outstanding on this PO. @if($poPending > 0.0001){{ $f($poPending) }} is in a delivery awaiting confirmation — it only counts as received once that delivery is inspected and confirmed. @elseif($canDeliver)Use Record Delivery below to deliver the balance. @else This order will reopen for delivery once the current delivery is confirmed.@endif
@endif @if($po->terms)

Terms{{ $po->terms }}

@endif
@if($po->attachment_path) Attached PO document @endif @if(in_array(auth()->user()->role, [\App\Models\User::ROLE_PROCUREMENT, \App\Models\User::ROLE_PAL, \App\Models\User::ROLE_ADMIN], true))
@csrf
@endif
@endforeach @php $activeDeliveries = $requisition->deliveries->filter(fn($d) => optional($d->purchaseOrder)->status !== \App\Models\PurchaseOrder::STATUS_CANCELLED); @endphp @if($activeDeliveries->isNotEmpty())
Deliveries
@foreach($activeDeliveries->sortByDesc('id') as $delivery) @php $insClass = match($delivery->inspection_status) { 'accepted' => 'success', 'rejected' => 'danger', 'partial' => 'warning', default => 'secondary', }; @endphp
{{ $delivery->delivery_number }} @if($delivery->confirmed_at)Confirmed@endif
Delivered {{ $delivery->delivered_at->format('d M Y, g:i a') }}
{{ $delivery->inspection_status }}
@php $fmt = fn($n) => rtrim(rtrim(number_format((float)$n, 2), '0'), '.'); @endphp
@foreach($delivery->items as $di) @php $ordered = (float) ($di->purchaseOrderItem?->quantity ?? 0); $delivd = (float) $di->quantity_delivered; $variance = $delivd - $ordered; // negative = short, positive = over @endphp @endforeach
ItemOrderedDeliveredVariance
{{ $di->purchaseOrderItem?->description ?? 'Item' }} {{ $fmt($ordered) }} {{ $fmt($delivd) }} @if(abs($variance) < 0.0001) 0 @else {{ $variance > 0 ? '+' : '' }}{{ $fmt($variance) }} {{ $variance < 0 ? 'short' : 'over' }} @endif
@foreach($delivery->issues as $issue)
{{ str_replace('_',' ',$issue->issue_type) }}: {{ $issue->description }} @if($issue->status === 'resolved')
Resolved: {{ $issue->resolution }}
@endif
@endforeach @if($delivery->inspection_notes && $delivery->inspection_status === 'accepted') Inspection note: {{ $delivery->inspection_notes }} @endif
@if(\App\Support\DeliveryGate::canInspect(auth()->user(), $delivery)) @endif @if(\App\Support\DeliveryGate::canResolve(auth()->user(), $delivery)) @endif @if(\App\Support\DeliveryGate::canConfirm(auth()->user(), $delivery))
@csrf
@endif
@endforeach
@endif @php $invoice = $requisition->invoices->sortByDesc('id')->first(); @endphp @if($invoice)
Invoice {{ $invoice->invoice_number }}
@php $ic = match($invoice->status){'paid'=>'success','disputed'=>'danger','with_finance'=>'info','pal_verified'=>'primary',default=>'secondary'}; @endphp {{ str_replace('_',' ',$invoice->status) }}
Supplier Ref{{ $invoice->supplier_invoice_no ?? '—' }}
Invoice Date{{ $invoice->invoice_date->format('d M Y') }}
Due{{ optional($invoice->due_date)->format('d M Y') ?? '—' }}
@if($invoice->verification_status === 'discrepancy' && $invoice->discrepancy_notes)
Discrepancy: {{ $invoice->discrepancy_notes }}
@endif
@foreach($invoice->items as $ii) @endforeach
ItemQtyLine Total
{{ $ii->description }}{{ rtrim(rtrim(number_format($ii->quantity,2),'0'),'.') }}{{ number_format($ii->line_total,2) }}
Subtotal{{ number_format($invoice->subtotal,2) }}
Tax{{ number_format($invoice->tax_total,2) }}
Total ({{ $invoice->currency }}){{ number_format($invoice->total,2) }}
@if($invoice->attachment_path) Supplier invoice document @endif Payment Certification Sheet
{{-- Certification chain: PAL sighted original → Procurement approved for payment → Finance pays --}}
Original sighted (PAL) @if($invoice->original_sighted_at) {{ $invoice->original_sighted_by_name }} {{ $invoice->original_sighted_at->format('d M Y, g:i a') }} @elsePending PAL certification@endif
Approved for payment (Procurement) @if($invoice->payment_approved_at) {{ $invoice->payment_approved_by_name }} {{ $invoice->payment_approved_at->format('d M Y, g:i a') }} @elsePending Procurement approval@endif
@endif @php $payment = $requisition->payments->sortByDesc('id')->first(); @endphp @if($payment)
Payment {{ $payment->payment_reference }}
@php $pc = match($payment->status){'received'=>'success','confirmed'=>'primary','failed'=>'danger',default=>'secondary'}; @endphp {{ $payment->status }}
Amount{{ $payment->currency }} {{ number_format($payment->amount,2) }}
Method{{ ucwords(str_replace('_',' ',$payment->method)) }}
Date{{ $payment->payment_date->format('d M Y') }}
@if($payment->transaction_ref)
Txn Ref{{ $payment->transaction_ref }}
@endif @if($payment->confirmed_at)
Confirmed{{ $payment->confirmed_at->format('d M Y') }}
@endif @if($payment->receipt_confirmed_at)
Receipt Confirmed{{ $payment->receipt_confirmed_at->format('d M Y') }}
@endif
@endif @php $rating = $requisition->ratings->sortByDesc('id')->first(); @endphp @if($rating)
Supplier Rating
{{ number_format($rating->overall_rating, 2) }} / 5
@foreach(['quality_rating'=>'Quality','timeliness_rating'=>'Timeliness','price_rating'=>'Price','communication_rating'=>'Communication'] as $field => $label)
{{ $label }} @for($i=1;$i<=5;$i++)@endfor
@endforeach
@if($rating->comments)

Comments{{ $rating->comments }}

@endif Rated by {{ $rating->ratedBy?->name }} · {{ $rating->created_at->format('d M Y') }}
@endif {{-- Supplier satisfaction survey (opened when invoice is received) --}} @php $survey = $requisition->survey; $canSurvey = in_array(auth()->user()->role, [\App\Models\User::ROLE_PAL, \App\Models\User::ROLE_PROCUREMENT, \App\Models\User::ROLE_ADMIN], true); @endphp @if($survey && $canSurvey)
Supplier Survey
{{ $survey->status }}
@if($survey->isCompleted())
{{ $survey->sentiment === 'up' ? '👍' : '👎' }} @for($i=1;$i<=5;$i++){{ $i <= $survey->rating ? '★' : '☆' }}@endfor
@if($survey->comment)

“{{ $survey->comment }}”

@endif Recorded {{ optional($survey->submitted_at)->format('d M Y') }} ({{ $survey->source }}) @else @php $surveyLink = \Illuminate\Support\Facades\URL::signedRoute('survey.respond', $survey); @endphp

Awaiting the supplier's response. Share this link, or record their feedback on their behalf.

Open
@csrf
@endif
@endif @include('requisitions._documents')
@if($canEdit || $canReview || $canPalReceive || $canPalProcess || $canProcReview || $canPalResolve || $canPalSendPo || $canAcknowledge || $canDeliver || $canSubmitInvoice || $canReceiveInvoice || $canVerifyInvoice || $canForwardInvoice || $canProcessPayment || $canConfirmPayment || $canConfirmReceipt || $canRate || $canClose || $canReturn)
Actions
@if($canReview) @endif @if($canEmergencyFastTrack) @endif @if($canEdit) {{ $requisition->status === \App\Models\Requisition::STATUS_RETURNED_TO_STATION ? 'Correct & Resubmit' : 'Edit' }} @endif @if($canPalReceive)
@csrf
@endif @if($canPalProcess) @endif @if($requisition->status === \App\Models\Requisition::STATUS_PAL_PROCESSING) @unless($requisition->quotes->firstWhere('is_selected', true)) Select a quote to enable submission. @endunless @endif @if($canPalResolve) @endif @if($canProcReview) @endif @if($canPalSendPo)
@csrf
@endif @if($canAcknowledge)
@csrf
@endif @if($canDeliver) @endif @if($canSubmitInvoice) @endif @if($canReceiveInvoice)
@csrf
@endif @if($canVerifyInvoice) @endif @if($canForwardInvoice) @endif @if($canProcessPayment) @endif @if($canConfirmPayment)
@csrf
@endif @if($canConfirmReceipt)
@csrf
@endif @if($canRate) @endif @if($canClose)
@csrf
@endif @if($canReturn) @endif
@endif
SLA Timeline
@if($sla['any_breached'])SLA breached@elseOn track@endif
@foreach($sla['stages'] as $row) @php $sc = ['breached'=>'danger','on_time'=>'success','in_progress'=>'info','pending'=>'secondary'][$row['status']] ?? 'secondary'; @endphp
{{ $row['label'] }} Target {{ $row['target_days'] }}d @if($row['elapsed_days'] !== null)· {{ $row['elapsed_days'] }}d elapsed @endif
{{ str_replace('_',' ',$row['status']) }}
@endforeach
Workflow Timeline
@forelse($requisition->workflowLogs->sortByDesc('created_at') as $log)
{{ $log->step_number }}
{{ $log->action }}
Stage {{ $log->stage }} · {{ ucwords(str_replace('_',' ',$log->actor_role)) }} @if($log->to_status)→ {{ ucwords(str_replace('_',' ',$log->to_status)) }}@endif {{ $log->user?->name }} · {{ $log->created_at->format('d M Y, g:i a') }}
@empty

No activity recorded.

@endforelse
@if($requisition->status === \App\Models\Requisition::STATUS_PAL_PROCESSING) @endif @if($canPalProcess) @endif @if($canProcReview) @endif @if($canPalResolve) @endif @if($canReturn) @endif @if($canDeliver) @php $deliverPo = $requisition->purchaseOrders->where('status','!=',\App\Models\PurchaseOrder::STATUS_CANCELLED)->sortByDesc('id')->first(); @endphp @endif @foreach($requisition->deliveries->filter(fn($d) => optional($d->purchaseOrder)->status !== \App\Models\PurchaseOrder::STATUS_CANCELLED) as $delivery) @if(\App\Support\DeliveryGate::canInspect(auth()->user(), $delivery)) @endif @if(\App\Support\DeliveryGate::canResolve(auth()->user(), $delivery)) @endif @endforeach @if($canSubmitInvoice) @php $poForInv = $requisition->purchaseOrders->where('status','!=',\App\Models\PurchaseOrder::STATUS_CANCELLED)->sortByDesc('id')->first(); @endphp @endif @if($canVerifyInvoice) @php $inv = $requisition->invoices->sortByDesc('id')->first(); $poForVerify = $requisition->purchaseOrders->where('status','!=',\App\Models\PurchaseOrder::STATUS_CANCELLED)->sortByDesc('id')->first(); $deliveryConfirmed = $requisition->deliveries->firstWhere('confirmed_at', '!=', null) !== null; $totalsMatch = $inv && $poForVerify && (string)$inv->total === (string)$poForVerify->total; @endphp @endif @if($canForwardInvoice) @php $invForFwd = $requisition->invoices->sortByDesc('id')->first(); @endphp @endif @if($canProcessPayment) @php $invForPay = $requisition->invoices->sortByDesc('id')->first(); @endphp @endif @if($canRate) @endif @if($canReview) @endif @if($canEmergencyFastTrack) @endif @endsection @section('script') @endsection