@extends('layouts.app') @section('title', 'Product Report - ' . $product->name) @section('content')

{{ $product->name }}

SKU: {{ $product->sku }} @if($product->category) · {{ $product->category->name }} @endif @if($product->brand) · {{ $product->brand->name }} @endif @if($product->supplier) · Supplier: {{ $product->supplier->name }} @endif

Current Stock

{{ number_format($product->current_stock ?? 0) }}

Selling at {{ formatCurrency($product->selling_price) }}
Sold

{{ number_format($salesTotals->qty) }}

{{ $salesTotals->count }} sale(s) · {{ formatCurrency($salesTotals->amount) }}
Purchased

{{ rtrim(rtrim(number_format($purchaseTotals->qty, 2), '0'), '.') }}

{{ $purchaseTotals->count }} purchase(s) · {{ formatCurrency($purchaseTotals->amount) }}
Expiry Date

{{ $product->expiry_date ? \Carbon\Carbon::parse($product->expiry_date)->format('M d, Y') : '—' }}

Alert at {{ number_format($product->alert_quantity ?? 0) }}
Batches in stock
Batch recall lookup
@if($batches->isEmpty())

No stock.

@else
@foreach($batches as $i => $batch) @php $days = $batch->expiry_date ? today()->diffInDays($batch->expiry_date, false) : null; @endphp @endforeach
Batch NoExpiryIn stockReceivedSold from it
{{ $batch->label() }} @if($i === $batches->search(fn ($b) => !$b->isExpired()))sold next@endif @if($batch->expiry_date) {{ $batch->expiry_date->format('d M Y') }} @if($batch->isExpired())Expired @elseif($days <= \App\Models\Product::EXPIRING_SOON_DAYS){{ (int) $days }} days left@endif @else None @endif {{ rtrim(rtrim(number_format($batch->quantity, 2), '0'), '.') }} {{ rtrim(rtrim(number_format($batch->received_quantity, 2), '0'), '.') }}
{{ $batch->received_at?->format('d M Y') }}
{{ rtrim(rtrim(number_format($soldFromBatch[$batch->id] ?? 0, 2), '0'), '.') }} @if($batch->batch_no)Trace@endif
@if($batches->contains->isExpired())

Expired batches cannot be sold. Remove them with a Stock Out adjustment (reason: Expired).

@endif @endif
@if(request('from') || request('to')) Clear @endif
@forelse($sales->getCollection()->groupBy(fn ($i) => \Carbon\Carbon::parse($i->sold_at)->toDateString()) as $day => $items) @foreach($items as $item) @php($seller = $item->sale?->user ?? $item->sale?->register?->user) @endforeach @empty @endforelse
Time Invoice Customer Payment Qty Price Subtotal Sold By
{{ \Carbon\Carbon::parse($day)->format('l, M d, Y') }} {{ number_format($salesPerDay[$day]->qty ?? 0) }} {{ formatCurrency($salesPerDay[$day]->amount ?? 0) }} day total
{{ \Carbon\Carbon::parse($item->sold_at)->format('H:i') }} @if($item->sale) {{ $item->sale->invoice_no }} @endif {{ $item->sale->customer_name ?? 'Walk-In Customer' }} {{ str_replace('_', ' ', $item->sale->payment_method ?? '—') }} {{ number_format($item->quantity) }} {{ formatCurrency($item->price) }} {{ formatCurrency($item->subtotal) }} {{ $seller->name ?? 'Unknown' }} @if($item->sale?->is_edited)
Edited by {{ $item->sale->editor->name ?? 'Unknown' }} {{ $item->sale->edited_at ? 'on ' . $item->sale->edited_at->format('M d, H:i') : '' }} @endif
No sales found for this product
{{ $sales->links() }}
@forelse($purchases->getCollection()->groupBy(fn ($r) => $r->at->toDateString()) as $day => $rows) @foreach($rows as $row) @endforeach @empty @endforelse
Reference Supplier Status Qty Unit Cost Line Total Expiry Recorded By
{{ \Carbon\Carbon::parse($day)->format('l, M d, Y') }} {{ rtrim(rtrim(number_format($purchasesPerDay[$day]->qty ?? 0, 2), '0'), '.') }} {{ formatCurrency($purchasesPerDay[$day]->amount ?? 0) }} day total
@if($row->purchase) {{ $row->reference }} @else {{ $row->kind === 'adjustment' ? 'Stock in' : 'First stock' }} @if($row->reference)
{{ $row->reference }}@endif @endif
{{ $row->supplier ?? '—' }} {{ $row->status ?? '—' }} {{ rtrim(rtrim(number_format($row->quantity, 2), '0'), '.') }} {{ formatCurrency($row->unit_cost) }} {{ formatCurrency($row->line_total) }} {{ $row->expiry ? \Carbon\Carbon::parse($row->expiry)->format('M d, Y') : '—' }} {{ $row->by ?? 'Unknown' }}
No purchases found for this product
{{ $purchases->links() }}
@forelse($adjustments as $adjustment) @empty @endforelse
Date & Time Type Qty Change Previous → New Price Change Reason By
{{ $adjustment->created_at->format('M d, Y H:i') }} {{ $adjustment->adjustment_type_text }} {{ $adjustment->quantity_change }} {{ number_format($adjustment->previous_quantity) }} → {{ number_format($adjustment->new_quantity) }} @if($adjustment->previous_price != $adjustment->new_price) {{ formatCurrency($adjustment->previous_price) }} → {{ formatCurrency($adjustment->new_price) }} @else No change @endif {{ $adjustment->reason }} {{ $adjustment->user->name ?? 'Unknown' }}
No stock adjustments found for this product
{{ $adjustments->links() }}
@forelse($movements as $movement) @empty @endforelse
Date & Time Type Qty Change Stock After Reference Customer / Supplier By
{{ $movement->created_at->format('M d, Y H:i') }} {{ $movement->type }} {{ $movement->quantity_change >= 0 ? '+' : '' }}{{ number_format($movement->quantity_change) }} {{ number_format($movement->new_quantity) }} {{ $movement->reference_no ?? '—' }} {{ $movement->customer_supplier ?? '—' }} @if($movement->user) {{ $movement->user->name }} @else Not recorded @endif
No stock movements found for this product
{{ $movements->links() }}
@php($qty = fn ($n) => rtrim(rtrim(number_format((float) $n, 2), '0'), '.'))

Stock at the start (opening) and end (closing) of each day. {{ request('from') || request('to') ? 'Days in the selected period' : 'The last 30 days' }}, newest first; use From / To above for other days.

@forelse($dailyStock as $day => $row) @php($quiet = !$row['received'] && !$row['sold'] && !$row['adjusted']) @empty @endforelse
Date Opening Stock Received Sold Adjusted Closing Stock
{{ \Carbon\Carbon::parse($day)->format('D, M d, Y') }}{{ \Carbon\Carbon::parse($day)->isToday() ? ' (today)' : '' }} {{ $qty($row['opening']) }} {{ $row['received'] ? '+' . $qty($row['received']) : '—' }} {{ $row['sold'] ? '−' . $qty($row['sold']) : '—' }} {{ $row['adjusted'] ? ($row['adjusted'] > 0 ? '+' : '−') . $qty(abs($row['adjusted'])) : '—' }} {{ $qty($row['closing']) }}
No days in the selected period
@forelse($activities as $activity) @empty @endforelse
Date & Time Action Description By IP Address
{{ $activity->created_at->format('M d, Y H:i') }} {{ $activity->action }} {{ $activity->description }} {{ $activity->user->name ?? 'Unknown' }} {{ $activity->ip_address }}
No activity recorded for this product
{{ $activities->links() }}
@endsection @section('scripts') @endsection