@extends('layouts.app') @section('title', 'Inventory, Purchasing & Issuance') @push('styles') @endpush @php $fmt = fn ($n) => rtrim(rtrim(number_format((float) $n, 2), '0'), '.'); $levelMeta = ['ok' => ['In stock', 'pill-available'], 'low' => ['Low — reorder', 'pill-maintenance'], 'out' => ['Out of stock', 'pill-overdue']]; $reopen = old('_form'); // Reopened after a validation error as a correction (purchase-correct / issue-correct)? $correctingPurchase = $reopen === 'purchase-correct'; $correctingIssue = $reopen === 'issue-correct'; @endphp @section('content')
@foreach ([ ['Stock value at cost', '₦' . number_format($stats['value'], 2), 'bi-safe', '#eef2ff', '#4f46e5', null], ['Stock items', $stats['items'], 'bi-box-seam', '#f1f5f9', '#475569', null], ['Low or out of stock', $stats['low'], 'bi-exclamation-triangle', $stats['low'] ? '#fef3c7' : '#dcfce7', $stats['low'] ? '#b45309' : '#15803d', null], ['Unpaid to suppliers', '₦' . number_format($stats['unpaid'], 2), 'bi-receipt', '#fee2e2', '#b91c1c', $stats['unpaidCount'] . ' ' . Str::plural('purchase', $stats['unpaidCount']) . ' on credit'], ] as [$label, $value, $icon, $bg, $fg, $hint])
{{ $value }} {{ $label }} @if ($hint){{ $hint }}@endif
@endforeach
{{-- ================= Stock levels ================= --}}
@php $filtering = $filters['q'] !== '' || $filters['category'] || $filters['level']; @endphp {{-- Server-side: the filters reach every page of stock, not just the one on screen. --}}
@if ($showBranch)@endif @forelse ($stock as $item) @php [$levelLabel, $levelClass] = $levelMeta[$item->stockLevel()]; @endphp @if ($showBranch)@endif @empty @endforelse @if ($items->isNotEmpty()) {{-- The whole store's value, not just this page. --}} @endif
Item CategoryBranchOn hand Level Unit cost Value Actions
{{ $item->item_name }}
@if ($item->posItems->isNotEmpty()) @endif
{{ $item->category->category_name ?? '—' }}{{ $item->branch->branch_name ?? '—' }}{{ $fmt($item->quantity_in_stock) }} {{ $item->unitLabel() }} {{ $levelLabel }}
Reorder at {{ $fmt($item->reorder_level) }}
₦{{ number_format((float) $item->unit_cost, 2) }} ₦{{ number_format($item->stockValue(), 2) }} @if ($can['create']) @endif @if ($can['edit']) @endif @if ($can['delete'])
@csrf @method('DELETE')
@endif
@if ($filtering)
No stock matches these filters.
@elseif ($stock->total())
No items on this page.
@else
No stock items yet{{ $can['create'] ? ' — use "Register Item" to add your first one.' : '.' }}
@endif
Total stock value (all items)₦{{ number_format($stats['value'], 2) }}
@include('partials.list-pager', ['page' => $stock, 'noun' => 'item'])
{{-- ================= Purchases ================= --}}
@forelse ($purchases as $p) @empty @endforelse
Date Item Quantity × cost Supplier Amount Payment Actions
{{ $p->txn_date?->format('M d, Y') }}
#{{ $p->expenditure_id }}@if ($p->posted_entry_id) · JE #{{ $p->posted_entry_id }}@endif
{{ $p->item->item_name ?? '—' }}
@if ($p->created_by)
by {{ $p->created_by }}
@endif
{{ $fmt($p->quantity) }} {{ $p->item?->unitLabel() }} × ₦{{ number_format((float) $p->unit_cost, 2) }} {{ $p->payee_name ?: '—' }} ₦{{ number_format((float) $p->amount, 2) }} @if ($p->payment_status === 'paid') Paid · {{ $p->payment_method ?: 'Cash' }} @elseif ($p->settled_entry_id) Settled later @else Unpaid · on credit @endif @if ($can['edit'] && !$p->settled_entry_id) @php $fix = ['action' => route('hotel.inventory.purchases.correct', $p), 'id' => $p->expenditure_id, 'date' => $p->txn_date?->toDateString(), 'dateLabel' => $p->txn_date?->format('M d, Y'), 'item' => $p->item_id, 'qty' => (float) $p->quantity, 'cost' => (float) $p->unit_cost, 'vendor' => $p->payee_name, 'status' => $p->payment_status === 'paid' ? 'paid' : 'unpaid', 'method' => $p->payment_method]; @endphp @endif @if ($can['edit']) @endif @if ($can['delete'])
@csrf @method('DELETE')
@endif
{{ $purchases->total() ? 'No purchases on this page.' : 'No purchases recorded yet.' }}
@include('partials.list-pager', ['page' => $purchases, 'noun' => 'purchase'])
Only the supplier and date can be edited. A wrong quantity, cost or payment is corrected by deleting the purchase (which reverses its stock and ledger entry) and recording it again. Purchases on credit are paid off under Expenditure → Accounts Payable.
{{-- ================= Issues ================= --}}
@forelse ($issues as $iss) @php $fromPos = $iss->isFromPosSale(); @endphp @empty @endforelse
Date Item Quantity Issued to Cost Source Actions
{{ $iss->issue_date?->format('M d, Y') }}
#{{ $iss->issue_id }}@if ($iss->posted_entry_id) · JE #{{ $iss->posted_entry_id }}@endif
{{ $iss->item->item_name ?? '—' }} {{ $fmt($iss->quantity) }} {{ $iss->item?->unitLabel() }} {{ $iss->outlet_name }} ₦{{ number_format((float) $iss->total_cost, 2) }} @if ($fromPos) POS sale @else Manual issue @endif @if ($iss->notes)
{{ $iss->notes }}
@endif
@unless ($fromPos) @if ($can['edit'] && ($iss->posted_entry_id || (float) $iss->total_cost == 0)) @php $fix = ['action' => route('hotel.inventory.issues.correct', $iss), 'id' => $iss->issue_id, 'date' => $iss->issue_date?->toDateString(), 'dateLabel' => $iss->issue_date?->format('M d, Y'), 'item' => $iss->item_id, 'outlet' => $iss->outlet_id, 'qty' => (float) $iss->quantity, 'notes' => $iss->notes]; @endphp @endif @if ($can['edit']) @endif @if ($can['delete'])
@csrf @method('DELETE')
@endif @endunless
{{ $issues->total() ? 'No issues on this page.' : 'No stock has been issued yet.' }}
@include('partials.list-pager', ['page' => $issues, 'noun' => 'issue'])
POS-sale lines are created automatically when a stock-linked item is sold and can only change by reversing that sale.
{{-- ================= Setup ================= --}}

Stock categories

Also used to file cost of sales under the right department (food, beverage…) when stock is issued or sold.

@if ($can['create'])
@csrf
@if ($branches->isNotEmpty())
@endif
@endif
    @forelse ($categories as $c)
  • {{ $c->category_name }} · {{ $c->items_count }} {{ Str::plural('item', $c->items_count) }}@if ($showBranch) · {{ $c->branch->branch_name ?? 'All branches' }}@endif @if ($c->description)
    {{ $c->description }}
    @endif
    @if ($can['delete'])
    @csrf @method('DELETE')
    @endif
  • @empty
  • No categories yet.
  • @endforelse

Units of measure

How each item is counted — kilograms, bottles, pieces…

@if ($can['create'])
@csrf
@endif
    @forelse ($units as $u)
  • {{ $u->unit_name }} {{ $u->unit_symbol }} · {{ $u->items_count }} {{ Str::plural('item', $u->items_count) }} @if ($can['delete'])
    @csrf @method('DELETE')
    @endif
  • @empty
  • No units yet.
  • @endforelse
{{-- ================= Modals ================= --}} {{-- Register / edit item --}} {{-- Record purchase --}} {{-- Issue stock --}} {{-- Stock count correction --}} {{-- Edit purchase (supplier/date only) --}} {{-- Edit issue (outlet/date/notes) --}} @endsection @push('scripts') @endpush