@php use App\Enums\Order\OrderItemStatusEnum; use App\Enums\Order\OrderStatusEnum; use App\Support\Currency\CurrencyDisplay; use Carbon\Carbon; use Illuminate\Support\Str; @endphp @php $isOrderTerminal = in_array( $order['status'] ?? null, [ OrderStatusEnum::DELIVERED(), OrderStatusEnum::CANCELLED(), OrderStatusEnum::FAILED(), OrderStatusEnum::REJECTED_BY_SELLER(), ], true, ); @endphp @php $isScheduledOrder = !empty($isScheduledOrder) || str_contains(request()->route()?->getName() ?? '', 'scheduled_orders') || request()->boolean('is_scheduled'); $activeMenuPage = $isScheduledOrder ? $menuAdmin['scheduled_orders']['active'] ?? '' : $menuAdmin['orders']['active'] ?? ''; $ordersListTitle = $isScheduledOrder ? __('labels.scheduled_orders') : __('labels.orders'); $ordersListRoute = $isScheduledOrder ? route('admin.scheduled_orders.index') : route('admin.orders.index'); $invoiceRoute = $isScheduledOrder ? route('admin.scheduled_orders.invoice', ['id' => $order['uuid']]) : route('admin.orders.invoice', ['id' => $order['uuid']]); $orderCurrencyCode = strtoupper((string) ($order['currency_code'] ?? $order['base_currency_code'] ?? ($systemSettings['currency'] ?? ''))); $money = fn ($amount) => CurrencyDisplay::format($amount, $orderCurrencyCode, $systemSettings['currencySymbol'] ?? null); @endphp @extends('layouts.admin.app', ['page' => $activeMenuPage]) @section('title', __('labels.order_details')) @section('header_data') @php $page_title = __('labels.order_details'); $page_pretitle = __('labels.admin') . ' ' . $ordersListTitle; @endphp @endsection @php $breadcrumbs = [ ['title' => __('labels.home'), 'url' => route('admin.dashboard')], ['title' => $ordersListTitle, 'url' => $ordersListRoute], ['title' => __('labels.order_details'), 'url' => ''], ]; @endphp @section('admin-content')
@if (!empty($order['is_flagged']) && ($order['delivery_type'] ?? '') !== 'pickup') @php // Build a store_id → store_name lookup from the order's items so // multi-vendor flags can call out the laggard store(s) by name // instead of by id. $storeNamesById = collect($order['items'] ?? []) ->map(fn($it) => $it['store'] ?? null) ->filter() ->keyBy('id') ->map(fn($s) => $s['name'] ?? null) ->all(); $resolveStoreNames = function (array $ids) use ($storeNamesById): string { $names = collect($ids)->map(fn($id) => $storeNamesById[$id] ?? null)->filter()->values(); if ($names->isEmpty()) { return __('labels.one_or_more_stores'); } if ($names->count() === 1) { return $names->first(); } return $names->slice(0, -1)->join(', ') . ' ' . __('labels.and') . ' ' . $names->last(); }; $reasonsPayload = (array) ($order['escalation_reasons'] ?? []); $reasonLines = []; foreach ($reasonsPayload as $code => $payload) { $sinceIso = is_array($payload) ? $payload['since'] ?? ($payload['flagged_at'] ?? null) : null; $sinceCarbon = $sinceIso ? Carbon::parse($sinceIso) : null; $for = $sinceCarbon?->diffForHumans(null, true); // "17 minutes" $storeIds = is_array($payload) && !empty($payload['store_ids']) ? (array) $payload['store_ids'] : []; $reasonLines[] = match ($code) { 'seller_unresponsive' => $for ? (!empty($storeIds) ? __('labels.flag_reason_seller_unresponsive_named_for', [ 'stores' => $resolveStoreNames($storeIds), 'for' => $for, ]) : __('labels.flag_reason_seller_unresponsive_for', ['for' => $for])) : __('labels.seller_unresponsive'), 'no_rider_available' => $for ? __('labels.flag_reason_no_rider_available_for', ['for' => $for]) : __('labels.no_rider_available'), 'return_unconfirmed' => $for ? __('labels.flag_reason_return_unconfirmed_for', ['for' => $for]) : __('labels.return_unconfirmed'), default => __('labels.' . $code) !== 'labels.' . $code ? __('labels.' . $code) : Str::title(str_replace('_', ' ', $code)), }; } @endphp
@endif {{-- END PAGE HEADER --}}
@php $paymentStatusValue = strtolower((string) ($order['payment_status'] ?? '')); $paymentBadgeClass = match (true) { in_array($paymentStatusValue, ['paid', 'completed', 'success'], true) => 'bg-green-lt', in_array($paymentStatusValue, ['failed', 'declined'], true) => 'bg-red-lt', in_array($paymentStatusValue, ['refunded', 'partially_refunded'], true) => 'bg-blue-lt', default => 'bg-yellow-lt', }; $statusStripClass = match (true) { in_array($order['status'] ?? '', ['cancelled', 'rejected_by_seller', 'failed'], true) => 'bg-red', in_array($order['status'] ?? '', ['delivered'], true) => 'bg-success', in_array($order['status'] ?? '', ['out_for_delivery', 'collected', 'assigned'], true) => 'bg-blue', default => 'bg-primary', }; @endphp

{{ __('labels.order_summary') }}

{{ __('labels.order_number') }}
#{{ $order['id'] }}
{{ __('labels.order_date') }}
{{ $order['created_at'] }}
{{ __('labels.payment_method') }}
{{ $order['payment_method'] }}
{{ __('labels.payment_status') }}
{{ $order['payment_status'] }}
{{ __('labels.final_total') }}
{{ $money($order['final_total']) }}
{{ __('labels.uuid') }}
{{ $order['uuid'] }}
{{-- Customer card — avatar-led layout, mobile is a tel: link, email is a mailto: link. Same visual rhythm as the Delivery card so the right column reads cleanly top-to-bottom. --}}

{{ __('labels.customer_information') }}

{{ $order['billing_name'] ?? '—' }}
@if (!empty($order['email'])) {{ $order['email'] }} @endif @if (!empty($order['billing_phone'])) {{ $order['billing_phone'] }} @endif
{{-- Shipping address — map-pin lead icon, recipient name called out separately when it differs from the billing name. --}} @if (($order['delivery_type'] ?? '') !== 'pickup')

{{ __('labels.shipping_address') }}

@if (!empty($order['shipping_name']) && $order['shipping_name'] !== ($order['billing_name'] ?? null))
{{ $order['shipping_name'] }}
@endif
{{ $order['shipping_address_1'] }}@if ($order['shipping_address_2']) , {{ $order['shipping_address_2'] }} @endif
@if ($order['shipping_landmark']) {{ $order['shipping_landmark'] }}
@endif {{ $order['shipping_city'] }} , {{ $order['shipping_state'] }} {{ $order['shipping_zip'] }}
{{ $order['shipping_country'] }}
@if (!empty($order['shipping_phone'])) {{ $order['shipping_phone'] }} @endif
@endif @if (!empty($order['order_note']) && ($order['delivery_type'] ?? '') !== 'pickup')

{{ __('labels.order_note') }}

{{ $order['order_note'] }}

@endif
{{-- Delivery card — assigned rider, zone, ETA. Empty state when unassigned. The card-header reserves space on the right for an inline "Reassign rider" admin button to land in the next phase without re-shuffling layout. --}} @if (($order['delivery_type'] ?? '') === 'pickup')

{{ __('labels.pickup_information') ?? 'Pickup Information' }}

{{ __('labels.delivery_type') ?? 'Delivery Type' }}
{{ __('labels.delivery_type_pickup') ?? 'Pickup' }}
{{ __('labels.ready_for_pickup') ?? 'Ready For Pickup' }}
{{ $order['ready_for_pickup_at'] ?? '—' }}
{{ __('labels.picked_up_at') ?? 'Picked Up At' }}
{{ $order['picked_up_at'] ?? '—' }}
@else

{{ __('labels.delivery_information') }}

@php $canReassignRider = ($editPermission ?? false) && in_array( $order['status'] ?? null, [OrderStatusEnum::READY_FOR_PICKUP(), OrderStatusEnum::ASSIGNED()], true, ); @endphp
@if ($canReassignRider) @endif
@if (!empty($order['delivery_boy']) && !empty($order['delivery_boy']['id']))
{{ $order['delivery_boy']['full_name'] ?? __('labels.delivery_boy') }} @if (!empty($order['delivery_boy']['is_blocked'])) {{ __('labels.blocked') }} @endif
@if (!empty($order['delivery_boy']['email'])) {{ $order['delivery_boy']['email'] }} @endif @if (!empty($order['delivery_boy']['mobile'])) {{ $order['delivery_boy']['mobile'] }} @endif
@else
{{ __('labels.no_rider_assigned') }}
{{ __('labels.no_rider_assigned_hint') }}
@endif
{{ __('labels.delivery_zone') }}
{{ $order['delivery_zone']['name'] ?? '—' }}
{{ __('labels.estimated_delivery_time') }}
{{ $order['estimated_delivery_time'] ?? '—' }}
@if (!empty($order['scheduled_date']))
{{ __('labels.scheduled_date') ?? 'Scheduled Date' }}
{{ \Carbon\Carbon::parse($order['scheduled_date'])->format('M d, Y') }}
@if (!empty($order['scheduled_time_slot_label']))
{{ __('labels.scheduled_time') ?? 'Scheduled Time' }}
{{ $order['scheduled_time_slot_label'] }}
@endif @endif @if (!empty($order['delivery_route']))
{{ __('labels.total_distance') }}
{{ number_format((float) ($order['delivery_route']['total_distance'] ?? 0), 2) }} {{ __('labels.km') }}
{{ __('labels.stops') }}
{{ (int) ($order['delivery_route']['stops_count'] ?? 0) }}
@endif
{{-- Rider earnings breakdown — pulled from the active DeliveryBoyAssignment row when present, otherwise a live calculation off the zone + route + tips. Total is what the rider currently stands to earn for this trip, and it's what the Force Cancel pay-rider toggle controls. --}} @if (!empty($order['delivery_assignment'])) @php $da = $order['delivery_assignment']; @endphp
{{ __('labels.rider_earnings') }}
@if (!empty($da['payment_status'])) {{ Str::ucfirst(Str::replace('_', ' ', $da['payment_status'])) }} @elseif(empty($da['has_persisted_row'])) {{ __('labels.rider_earnings_projected') }} @endif
{{ __('labels.base_fee') }}
{{ $money($da['base_fee']) }}
{{ __('labels.per_store_pickup_fee') }}
{{ $money($da['per_store_pickup_fee']) }}
{{ __('labels.distance_based_fee') }}
{{ $money($da['distance_based_fee']) }}
{{ __('labels.per_order_incentive') }}
{{ $money($da['per_order_incentive']) }}
@if ((float) ($da['tip_amount'] ?? 0) > 0)
{{ __('labels.rider_tips') }}
{{ $money($da['tip_amount']) }}
@endif
{{ __('labels.total_earnings') }}
{{ $money($da['total_earnings']) }}
@if (!empty($da['assigned_at']))
{{ __('labels.assigned_at') }}: {{ $da['assigned_at'] }} @if (!empty($da['paid_at'])) · {{ __('labels.paid_at') }}: {{ $da['paid_at'] }} @endif
@endif {{-- Settle Earnings panel — visible only when this assignment is CANCELLED_BY_ADMIN with payment_status=PENDING. Admin chooses Approve (pay total_earnings) or Reject (zero out). Both require a remark which lands in the order_audit_logs. --}} @if (!empty($da['awaiting_settle']) && ($editPermission ?? false))
@endif @endif
@endif {{-- Live tracking map — shown only when rider is assigned and delivery is active --}} @php $trackableStatuses = [ OrderStatusEnum::ASSIGNED(), OrderStatusEnum::COLLECTED(), OrderStatusEnum::OUT_FOR_DELIVERY(), ]; $showTrackingMap = !empty($order['delivery_boy_id']) && in_array($order['status'] ?? null, $trackableStatuses, true); @endphp @if ($showTrackingMap)

{{ __('labels.live_tracking') }}

{{ __('labels.live') }}
@endif
@php $itemsForStores = $order['items'] ?? []; $storeBuckets = []; foreach ($itemsForStores as $itm) { $sid = $itm['store']['id'] ?? null; if (!$sid) { continue; } if (!isset($storeBuckets[$sid])) { $storeBuckets[$sid] = [ 'store' => $itm['store'], 'item_count' => 0, 'subtotal' => 0.0, ]; } $storeBuckets[$sid]['item_count']++; $storeBuckets[$sid]['subtotal'] += (float) ($itm['sub_total'] ?? 0); } @endphp @if (!empty($storeBuckets))

{{ __('labels.stores_and_sellers') }} {{ count($storeBuckets) }}

@foreach ($storeBuckets as $bucket) @php $st = $bucket['store']; @endphp
{{ $st['name'] ?? '—' }}
@if (!empty($st['contact_number'])) {{ $st['contact_number'] }} @endif @if (!empty($st['contact_email'])) {{ $st['contact_email'] }} @endif @if (!empty($st['city']) || !empty($st['state'])) {{ trim(($st['city'] ?? '') . ', ' . ($st['state'] ?? ''), ', ') }} @endif
@if (!empty($st['seller']))
{{ __('labels.seller') }}: {{ $st['seller']['name'] ?? '—' }} @if (!empty($st['seller']['mobile'])) · {{ $st['seller']['mobile'] }} @endif @if (!empty($st['seller']['email'])) · {{ $st['seller']['email'] }} @endif
@endif
{{ $bucket['item_count'] }} {{ $bucket['item_count'] === 1 ? __('labels.item') : __('labels.items') }}
{{ $money($bucket['subtotal']) }}
@endforeach
@endif @php $hasActionCol = ($editPermission ?? false) && !$isOrderTerminal && ($order['delivery_type'] ?? '') !== 'pickup'; $bulkEnabled = $hasActionCol; @endphp

{{ __('labels.order_items') }}

@if ($bulkEnabled)
@endif
@if ($bulkEnabled) @endif @if ($hasActionCol) @endif @foreach ($order['items'] as $item) @php $itemId = $item['orderItem']['id'] ?? null; $hasTransitions = !empty($itemTransitions[$itemId] ?? []); @endphp @if ($bulkEnabled) @endif @if ($hasActionCol) @endif @endforeach @php // Base small/large colspans; +1 each when the bulk-select column // is present (checkbox shares its visibility with the actions col). $colspanSmall = ($hasActionCol ? 6 : 5) + ($bulkEnabled ? 1 : 0); $colspanLarge = ($hasActionCol ? 7 : 6) + ($bulkEnabled ? 1 : 0); @endphp @php $riderTipAmount = (float) ($order['rider_tip_amount'] ?? 0); $grandTotal = $order['subtotal'] + $order['delivery_charge'] + ($order['handling_charges'] ?? 0) + ($order['per_store_drop_off_fee'] ?? 0); if ($riderTipAmount > 0) { $grandTotal += $riderTipAmount; } @endphp @if ($riderTipAmount > 0) @endif @if ($order['wallet_balance'] > 0) @endif @if ($order['promo_discount'] > 0) @endif
{{ __('labels.order_item_id') }} {{ __('labels.store_name') }} {{ __('labels.product') }} {{ __('labels.variant') }} {{ __('labels.price') }} {{ __('labels.status') }} {{ __('labels.quantity') }} {{ __('labels.subtotal') }}{{ __('labels.actions') }}
#{{ $item['orderItem']['id'] ?? 'N/A' }} {{ $item['store']['name'] ?? 'N/A' }} {{ $item['product']['title'] ?? 'N/A' }} @if (!empty($item['attachments']))
Attachments
    @foreach ($item['attachments'] as $attachment)
  • view
  • @endforeach
@endif @if (!empty($item['addons']))
{{ __('labels.addons') }}
    @foreach ($item['addons'] as $addon)
  • @if (!empty($addon['group']['title'])) {{ $addon['group']['title'] }} — @endif {{ $addon['item']['title'] ?? '—' }} · {{ $money($addon['price']) }}
  • @endforeach
@endif
{{ $item['variant']['title'] ?? 'N/A' }} {{ $money($item['price'] + $item['tax_amount']) }} @php $itemReason = $item['orderItem']['cancellation_reason'] ?? $item['orderItem']['delivery_fail_reason'] ?? ($itemStatusReasons[$itemId] ?? null); @endphp {{ $item['orderItem']['status_formatted'] }} @if(!empty($itemReason))
{{ __('labels.reason') }}: {{ $itemReason }}
@endif
{{ $item['quantity'] }} {{ $money($item['sub_total']) }} @if (!empty($item['addons_total']) && (float) $item['addons_total'] > 0)
{{ __('labels.addons_total') }} : {{ $money($item['addons_total']) }}
@endif
@php $itemId = $item['orderItem']['id'] ?? null; $transitions = $itemTransitions[$itemId] ?? []; @endphp @if (($order['delivery_type'] ?? '') === 'pickup' && !empty($transitions))
@foreach ($transitions as $transition) @endforeach
@elseif(!empty($transitions)) @else — @endif
{{ __('labels.total') }}: {{ collect($order['items'])->sum('quantity') }} {{ $money($order['subtotal']) }}
{{ __('labels.shipping_handling') }} : {{ $money($order['delivery_charge']) }}
{{ __('labels.handling_charges') }}: {{ $money($order['handling_charges'] ?? 0) }}
{{ __('labels.per_store_drop_off_fee') }}: {{ $money($order['per_store_drop_off_fee'] ?? 0) }}
{{ __('labels.rider_tips') }}: {{ $money($riderTipAmount) }}
{{ __('labels.grand_total') }}: {{ $money($grandTotal) }}
{{ __('labels.wallet_used') }}: - {{ $money($order['wallet_balance']) }}
{{ __('labels.promo_discount') }} @if (!empty($order['promo_line']) && ($order['promo_line']['cashback_flag'] ?? false)) ({{ __('labels.cashback') }}) @endif ({{ $order['promo_code'] }}): - {{ $money($order['promo_discount']) }}
{{ __('labels.total_payable') }}: {{ $money($order['total_payable']) }}
@if (isset($auditLogs))

{{ __('labels.activity_and_notes') }} {{ $auditLogs->count() }}

@if ($editPermission ?? false) @endif
@if ($auditLogs->isEmpty())
{{ __('labels.audit_log_empty') }}
@else
@foreach ($auditLogs as $log) @include('admin.orders.partials.audit-log-row', [ 'log' => $log, ]) @endforeach
@endif
@endif
@if ($editPermission ?? false) @include('admin.orders.partials.add-note-modal') @include('admin.orders.partials.force-cancel-modal') @include('admin.orders.partials.reassign-rider-modal') @include('admin.orders.partials.admin-action-modals') @if (!$isOrderTerminal) @include('admin.orders.partials.bulk-update-status-modal') @endif @include('admin.orders.partials.settle-rider-earnings-modal') @endif @endsection @push('scripts') @if ($editPermission ?? false) @php // Items the admin can pick to cancel — drop already-terminal ones // so the dropdown stays clean. $cancellableItemsForJs = collect($order['items'] ?? []) ->filter( fn($item) => !in_array( $item['orderItem']['status'] ?? '', ['cancelled', 'rejected', 'failed', 'refunded'], true, ), ) ->map( fn($item) => [ 'id' => $item['orderItem']['id'] ?? null, 'title' => $item['product']['title'] ?? '', 'status' => $item['orderItem']['status'] ?? '', 'store' => $item['store']['name'] ?? null, ], ) ->filter(fn($i) => !empty($i['id'])) ->values() ->all(); @endphp @endif @if ($showTrackingMap ?? false) @endif @endpush