@extends('layouts.dashboard') @section('content') @php /** * Vendor → Cash drawer → session report: the Z-report once closed, and the X-report (a * mid-shift reading) while the session is still open. * * The X-report obeys the same blind rule as the cash-up screen. An operator who could * print expected cash from here would never have to face the blind count, so while the * session is open and uncounted the cash summary, the cash tender line and the movement * amounts are withheld. Everything the report exists to give that is NOT cash in that * drawer — card and wallet takings, tips, who served, service mode, menu section — is * shown in full throughout. * * @var array $shift @var array|null $totals @var float|null $expected @var bool $reveal * @var array $tenders @var array $counts @var array $movements * @var array $byServer @var array $byMode @var array $byCategory */ $closed = ($shift['status'] ?? '') === 'closed'; $reveal = $reveal ?? $closed; $typeLabels = ['sale' => t_raw('vendor.shifts.type_sale'), 'refund' => t_raw('vendor.shifts.type_refund'), 'payin' => t_raw('vendor.shifts.type_payin'), 'payout' => t_raw('vendor.shifts.type_payout'), 'drop' => t_raw('vendor.shifts.type_drop')]; $typePills = ['sale' => 'qm-pill-green', 'refund' => 'qm-pill-red', 'payin' => 'qm-pill-blue', 'payout' => 'qm-pill-amber', 'drop' => 'qm-pill-grey']; // Covers both key spaces: ledger tenders (cash/card/...) and, for sessions // predating the ledger, orders.payment_method (cod/offline/...). $cashLbl = t_raw('status.payment_method.cash'); $cardLbl = t_raw('status.payment_method.card'); $methodLabels = ['cash' => $cashLbl, 'cod' => $cashLbl, 'card' => $cardLbl, 'offline' => $cardLbl, 'stripe' => 'Stripe', 'paypal' => 'PayPal', 'other' => t_raw('status.payment_method.other')]; // Which tender keys ARE the cash in the drawer, and therefore have to wait for the count. $cashKeys = ['cash', 'cod']; $modeLabels = ['delivery' => t_raw('common.delivery'), 'pickup' => t_raw('common.pickup'), 'dine_in' => t_raw('common.dine_in')]; $counts += ['total_c' => 0, 'cancelled_c' => 0, 'discounted_c' => 0, 'discount_s' => 0, 'refunded_c' => 0, 'tip_s' => 0, 'tipped_c' => 0]; $variance = $closed && $shift['variance'] !== null ? (float) $shift['variance'] : null; $byServer = $byServer ?? []; $byMode = $byMode ?? []; $byCategory = $byCategory ?? []; @endphp

{!! $closed ? t('vendor.shifts.report_sub_closed') : t('vendor.shifts.report_sub_open') !!}

{{ t_raw('vendor.shifts.back_to_drawer_link') }}

{!! $closed ? t('vendor.shifts.report_heading') : t('vendor.shifts.xreport_page_title') !!} — #{{ (int) $shift['id'] }}

{!! t_raw('vendor.shifts.opened_template', [':date' => fmt_datetime($shift['opened_at'])]) !!}{!! !empty($shift['opened_by']) ? ' ' . t('vendor.shifts.by_name_suffix', [':name' => (string) $shift['opened_by']]) : '' !!} @if ($closed && $shift['closed_at']) · {!! t_raw('vendor.shifts.closed_template', [':date' => fmt_datetime($shift['closed_at'])]) !!}{!! !empty($shift['closed_by']) ? ' ' . t('vendor.shifts.by_name_suffix', [':name' => (string) $shift['closed_by']]) : '' !!}@endif

{{ t_raw('vendor.shifts.section_cash_summary') }}

@if (!$reveal)

{{ t_raw('vendor.shifts.xreport_blind_notice') }}

@else
{{ t_raw('vendor.shifts.stat_opening_float') }}{{ money($shift['opening_float']) }} {{ t_raw('vendor.shifts.stat_cash_sales') }}{{ money($totals['sale']) }} {{ t_raw('vendor.shifts.stat_payins') }}{{ money($totals['payin']) }} {{ t_raw('vendor.shifts.stat_payouts') }}{{ money($totals['payout']) }} {{ t_raw('vendor.shifts.stat_safe_drops') }}{{ money($totals['drop']) }} {{ t_raw('vendor.shifts.stat_cash_refunds') }}{{ money($totals['refund']) }} {!! $closed ? t('vendor.shifts.col_expected') : t('vendor.shifts.stat_expected_now') !!}{{ money($expected) }} @if ($closed) {{ t_raw('vendor.shifts.col_counted') }}{!! $shift['counted_cash'] !== null ? money($shift['counted_cash']) : dash() !!} {{ t_raw('vendor.shifts.col_variance') }}@php if ($variance === null) { echo dash(); } elseif ($variance == 0.0) { echo '' . t('vendor.shifts.balanced_pill') . ''; } elseif ($variance > 0) { echo '' . money($variance) . ' ' . t('vendor.shifts.variance_over_suffix') . ''; } else { echo '' . money(abs($variance)) . ' ' . t('vendor.shifts.variance_short_suffix') . ''; } @endphp @if (!empty($shift['variance_reason'])) {{ t_raw('vendor.shifts.variance_reason_label') }}{{ (string) $shift['variance_reason'] }} @endif @endif
@endif

{{ t_raw('vendor.shifts.section_orders_open') }}

@if ($tenders) @foreach ($tenders as $t) @php $isCash = in_array((string) $t['payment_method'], $cashKeys, true); @endphp @php /* Card and wallet takings are already banked and can never be counted in the till, so they are shown throughout. The cash line is the till, so it waits for the count like everything else. */ @endphp @endforeach @else @partial('table-empty', ['colspan' => 3, 'icon' => 'fa-receipt', 'msg' => t_raw('vendor.shifts.empty_no_paid_orders')]) @endif
{{ t_raw('vendor.shifts.tenders_caption') }}
{{ t_raw('vendor.shifts.col_tender') }}{{ t_raw('vendor.shifts.col_paid_orders') }}{{ t_raw('vendor.shifts.col_takings') }}
@php $m = (string) $t['payment_method']; $ico = payment_method_icon($m); echo $ico !== '' ? $ico : e($methodLabels[$m] ?? ucfirst($m)); @endphp {{ (int) $t['c'] }}@if ($isCash && !$reveal){{ t_raw('vendor.shifts.hidden_until_counted') }}@else{{ money($t['s']) }}@endif
{{ t_raw('vendor.shifts.stat_orders_placed') }}{{ number_format((int) $counts['total_c']) }} {{ t_raw('common.cancelled') }}{{ number_format((int) $counts['cancelled_c']) }} {{ t_raw('common.refunded') }}{{ number_format((int) $counts['refunded_c']) }} {{ t_raw('vendor.shifts.stat_discounted_orders') }}{{ number_format((int) $counts['discounted_c']) }} {{ t_raw('vendor.shifts.stat_discounts_given') }}{{ money($counts['discount_s']) }} @php /* Tips are staff money, not takings — they belong on this report because this is where they are shared out, and nowhere else showed them per session. */ @endphp {{ t_raw('vendor.shifts.stat_tips') }}{{ money($counts['tip_s']) }} {{ t_raw('vendor.shifts.stat_tipped_orders') }}{{ number_format((int) $counts['tipped_c']) }}
@php /* Who worked it. An order belongs to whoever moved it through its statuses and money to whoever settled it — the same attribution the staff reports use, so the two can never tell different stories about the same shift. */ @endphp

{{ t_raw('vendor.shifts.section_by_server') }}

@if ($byServer) @foreach ($byServer as $s) @endforeach @else @partial('table-empty', ['colspan' => 4, 'icon' => 'fa-user-friends', 'msg' => t_raw('vendor.shifts.empty_by_server')]) @endif
{{ t_raw('vendor.shifts.by_server_caption') }}
{{ t_raw('vendor.staff.col_member') }}{{ t_raw('common.orders') }}{{ t_raw('vendor.shifts.col_settled') }}{{ t_raw('vendor.shifts.stat_tips') }}
{!! brandmark_html($s['avatar'] ?? null, (string) $s['name'], 'md', 'qm-brandmark--round') !!}
{{ (string) $s['name'] }}
{{ number_format((int) $s['orders_c']) }} {{ money($s['settled']) }} {{ money($s['tips']) }}

{{ t_raw('vendor.shifts.section_by_mode') }}

@if ($byMode) @foreach ($byMode as $m) @endforeach @else @partial('table-empty', ['colspan' => 4, 'icon' => 'fa-random', 'msg' => t_raw('vendor.shifts.empty_no_paid_orders')]) @endif
{{ t_raw('vendor.shifts.by_mode_caption') }}
{{ t_raw('vendor.shifts.col_service_mode') }}{{ t_raw('common.orders') }}{{ t_raw('vendor.analytics.kpi_covers') }}{{ t_raw('vendor.shifts.col_takings') }}
{{ $modeLabels[(string) $m['service_mode']] ?? (string) $m['service_mode'] }} {{ number_format((int) $m['orders_c']) }} {!! (int) $m['covers'] > 0 ? number_format((int) $m['covers']) : dash() !!} {{ money($m['revenue']) }}

{{ t_raw('vendor.shifts.section_by_category') }}

@if ($byCategory) @foreach ($byCategory as $c) @endforeach @else @partial('table-empty', ['colspan' => 3, 'icon' => 'fa-utensils', 'msg' => t_raw('vendor.shifts.empty_no_paid_orders')]) @endif
{{ t_raw('vendor.shifts.by_category_caption') }}
{{ t_raw('vendor.menu.category_label') }}{{ t_raw('vendor.shifts.col_units') }}{{ t_raw('vendor.shifts.col_takings') }}
{!! (string) $c['category'] !== '' ? e((string) $c['category']) : t('vendor.menu.uncategorised_option') !!} {{ number_format((int) $c['units']) }} {{ money($c['revenue']) }}

{{ t_raw('vendor.shifts.section_movements') }}

@if (!$reveal)

{{ t_raw('vendor.shifts.xreport_movements_blind') }}

@else
@if ($movements) @foreach ($movements as $m) @endforeach @else @partial('table-empty', ['colspan' => 6, 'icon' => 'fa-exchange-alt', 'msg' => t_raw('vendor.shifts.empty_no_movements')]) @endif
{{ t_raw('vendor.shifts.movements_full_caption') }}
{{ t_raw('common.when') }}{{ t_raw('common.type') }}{{ t_raw('common.amount') }}{{ t_raw('vendor.shifts.col_order') }}{{ t_raw('vendor.shifts.col_by') }}{{ t_raw('common.note') }}
{!! fmt_clock($m['created_at']) !!} {{ $typeLabels[$m['type']] ?? ucfirst((string) $m['type']) }} {{ in_array($m['type'], ['refund', 'payout', 'drop'], true) ? '−' : '+' }}{{ money($m['amount']) }} {!! or_dash($m['order_number'] ?? null) !!} {!! or_dash($m['user_name'] ?? null) !!} {!! or_dash($m['note'] ?? null) !!}
@endif
@endsection