@extends('layouts.app') @section('title', 'Close register - ' . setting('system_name')) @section('content') @php // Blind close: cashiers count the drawer without seeing what the system expects $isAdmin = auth()->user()->hasRole('admin') || auth()->user()->hasRole('super_admin'); // One switch in Loss Prevention settings: when on, everyone must count the drawer and non-admins can't see the expected cash $countRequired = \App\Models\IntegrityEvent::cashCountRequired(); $blind = $countRequired && !$isAdmin; $money = fn ($v, $prefix = 'MWK ') => $blind ? '••••••' : $prefix . number_format($v, 2); // The shop's payment methods (Settings → Payment methods), cheque totals are kept under "cheques" $methods = collect(\App\Helpers\PaymentMethods::definitions()) ->map(fn ($m) => ['key' => $m['key'] === 'cheque' ? 'cheques' : $m['key'], 'label' => $m['label'], 'icon' => $m['icon'], 'color' => $m['color']]) ->values()->all(); $methods[] = ['key' => 'cash_and_card', 'label' => 'Other', 'icon' => 'bi-intersect', 'color' => '#334155']; // Anything else paid in this shift (e.g. a method since deleted) still gets a line foreach (array_keys($counts) as $countKey) { $key = substr($countKey, 6); if ($key !== 'total_sales' && !in_array($key, array_column($methods, 'key'), true)) { $methods[] = ['key' => $key, 'label' => ucwords(str_replace('_', ' ', $key)), 'icon' => 'bi-wallet', 'color' => '#7c3aed']; } } $used = collect($methods)->filter(fn ($m) => ($counts['count_' . $m['key']] ?? 0) > 0)->values(); $methodTotal = max(1, $used->sum(fn ($m) => $totals['total_' . $m['key']] ?? 0)); $expectedCash = ($totals['total_cash'] ?? 0) + $register->opening_cash; $minutesOpen = (int) $register->opened_at->diffInMinutes(now()); @endphp
{{-- Header --}}

Close register

{{ auth()->user()->name }} · opened {{ $register->opened_at->format('d M Y, H:i') }} · open {{ intdiv($minutesOpen, 60) }}h {{ str_pad($minutesOpen % 60, 2, '0', STR_PAD_LEFT) }}m
Back to POS
{{-- Headline figures --}}
Opening float
MWK {{ number_format($register->opening_cash, 2) }}
Sales
{{ $money($totals['total_sales']) }}
{{ $counts['count_total_sales'] ?? 0 }} {{ ($counts['count_total_sales'] ?? 0) == 1 ? 'sale' : 'sales' }}
Cash sales
{{ $money($totals['total_cash'] ?? 0) }}
Expected in drawer
{{ $money($expectedCash) }}
{{ $blind ? 'Hidden: count the drawer yourself' : 'Opening float + cash sales' }}
{{-- Sales by payment method --}}
Sales by payment method
@forelse($used as $m) @php($amount = $totals['total_' . $m['key']] ?? 0)
{{ $m['label'] }} {{ $counts['count_' . $m['key']] }} {{ $counts['count_' . $m['key']] == 1 ? 'payment' : 'payments' }} {{ $money($amount) }}
@unless($blind) @endunless
@empty
No sales in this session.
@endforelse
{{-- Count & close --}}
Count & close

@if($countRequired) Count all notes and coins in the drawer, including the opening float. Do not copy a figure from the screen. @else Check the drawer against the expected amount, then close the register. @endif

@csrf @method('PATCH')
MWK @error('counted_cash')
{{ $message }}
@enderror
@unless($blind) {{-- Admins see the difference as they type --}}
Difference
@endunless
The Z-report is emailed when the register is closed.
@if(brand_image_exists($settings['logo'] ?? null)) @endif

{{ $settings['system_name'] ?? 'REGISTER SUMMARY' }}

Z-REPORT
Cashier: {{ auth()->user()->name ?? 'Unknown' }}
Register ID: #{{ $register->id }}
Time Opened:
{{ $register->opened_at->format('d M Y, H:i') }}
Time Closed:
{{ now()->format('d M Y, H:i') }}
OPENING CASH: MWK {{ number_format($register->opening_cash, 2) }}
PAYMENT METHODS USED
@foreach($methods as $method) @if(($counts['count_'.$method['key']] ?? 0) > 0) @endif @endforeach @if(($counts['count_total_sales'] ?? 0) == 0) @endif
Method Count Total
{{ $method['label'] }} {{ $counts['count_'.$method['key']] }} {{ $money($totals['total_'.$method['key']], '') }}
No sales recorded
TOTAL SALES: {{ $money($totals['total_sales']) }}
TOTAL IN DRAWER: {{ $money(($totals['total_cash'] ?? 0) + $register->opening_cash) }}
(Opening Cash + Cash Sales)

*** END OF REPORT ***

{{-- Sales made offline on this device must be uploaded before the shift is closed --}} @endsection