Commit 9895319f authored by Mahmoud Aglan's avatar Mahmoud Aglan

Fix low stock, inventory movements, product sales, POS reports + payment search filter

1. Low stock: use min_stock_level (not reorder_point), eager-load inventoryLevels
2. Inventory movements: reference is a morphTo — show class_basename#id instead of raw object
3. Product sales: pos_transaction_items has item_type/item_id (not product_id)
4. POS transactions: relationship is processedBy (not user), field is receipt_number
5. Collect payment wizard: only search participants with outstanding invoices
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 50db0586
...@@ -490,21 +490,21 @@ public function trainerWorkload(string $from, string $to, ?int $branchId = null) ...@@ -490,21 +490,21 @@ public function trainerWorkload(string $from, string $to, ?int $branchId = null)
public function lowStockReport(?int $branchId = null): Collection public function lowStockReport(?int $branchId = null): Collection
{ {
return Product::with(['category']) return Product::with(['category', 'inventoryLevels'])
->where('track_inventory', true) ->where('track_inventory', true)
->where('is_active', true) ->where('is_active', true)
->get() ->get()
->map(function ($product) { ->map(function ($product) {
$level = $product->inventoryLevels()->first(); $level = $product->inventoryLevels->first();
$onHand = $level?->quantity_on_hand ?? 0; $onHand = $level?->quantity_on_hand ?? 0;
$reorder = $product->reorder_point ?? 0; $minStock = $product->min_stock_level ?? 0;
return [ return [
'product' => $product->name_ar ?? $product->name ?? '', 'product' => $product->name_ar ?? $product->name ?? '',
'sku' => $product->sku ?? '', 'sku' => $product->sku ?? '',
'category' => $product->category?->name_ar ?? '', 'category' => $product->category?->name_ar ?? '',
'on_hand' => $onHand, 'on_hand' => $onHand,
'reorder_point' => $reorder, 'reorder_point' => $minStock,
'status' => $onHand <= 0 ? 'نفد' : ($onHand <= $reorder ? 'منخفض' : 'متوفر'), 'status' => $onHand <= 0 ? 'نفد' : ($onHand <= $minStock ? 'منخفض' : 'متوفر'),
]; ];
}) })
->filter(fn ($p) => $p['on_hand'] <= $p['reorder_point']) ->filter(fn ($p) => $p['on_hand'] <= $p['reorder_point'])
...@@ -529,7 +529,7 @@ public function inventoryMovementReport(string $from, string $to, ?int $branchId ...@@ -529,7 +529,7 @@ public function inventoryMovementReport(string $from, string $to, ?int $branchId
'quantity' => $m->quantity, 'quantity' => $m->quantity,
'before' => $m->quantity_before ?? 0, 'before' => $m->quantity_before ?? 0,
'after' => $m->quantity_after ?? 0, 'after' => $m->quantity_after ?? 0,
'reference' => $m->reference ?? '', 'reference' => $m->reference_type ? class_basename($m->reference_type) . '#' . $m->reference_id : '—',
]); ]);
} }
...@@ -537,10 +537,10 @@ public function productSalesReport(string $from, string $to, ?int $branchId = nu ...@@ -537,10 +537,10 @@ public function productSalesReport(string $from, string $to, ?int $branchId = nu
{ {
return DB::table('pos_transaction_items') return DB::table('pos_transaction_items')
->join('pos_transactions', 'pos_transactions.id', '=', 'pos_transaction_items.pos_transaction_id') ->join('pos_transactions', 'pos_transactions.id', '=', 'pos_transaction_items.pos_transaction_id')
->join('products', 'products.id', '=', 'pos_transaction_items.product_id') ->join('products', 'products.id', '=', 'pos_transaction_items.item_id')
->where('pos_transaction_items.item_type', 'product')
->whereBetween('pos_transactions.processed_at', [$from, $to . ' 23:59:59']) ->whereBetween('pos_transactions.processed_at', [$from, $to . ' 23:59:59'])
->when($branchId, fn ($q) => $q->where('pos_transactions.branch_id', $branchId)) ->when($branchId, fn ($q) => $q->where('pos_transactions.branch_id', $branchId))
->whereNotNull('pos_transaction_items.product_id')
->select( ->select(
'products.name_ar as product', 'products.name_ar as product',
'products.sku', 'products.sku',
...@@ -556,7 +556,7 @@ public function productSalesReport(string $from, string $to, ?int $branchId = nu ...@@ -556,7 +556,7 @@ public function productSalesReport(string $from, string $to, ?int $branchId = nu
public function posTransactionReport(string $from, string $to, ?int $branchId = null): Collection public function posTransactionReport(string $from, string $to, ?int $branchId = null): Collection
{ {
return POSTransaction::with(['user', 'branch']) return POSTransaction::with(['processedBy', 'branch'])
->whereBetween('processed_at', [$from, $to . ' 23:59:59']) ->whereBetween('processed_at', [$from, $to . ' 23:59:59'])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId)) ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->orderByDesc('processed_at') ->orderByDesc('processed_at')
...@@ -564,12 +564,12 @@ public function posTransactionReport(string $from, string $to, ?int $branchId = ...@@ -564,12 +564,12 @@ public function posTransactionReport(string $from, string $to, ?int $branchId =
->get() ->get()
->map(fn ($t) => [ ->map(fn ($t) => [
'date' => $t->processed_at?->format('Y-m-d H:i'), 'date' => $t->processed_at?->format('Y-m-d H:i'),
'number' => $t->transaction_number ?? '', 'number' => $t->receipt_number ?? '',
'total' => $t->total_amount, 'total' => $t->total_amount,
'discount' => $t->discount_amount ?? 0, 'discount' => $t->discount_amount ?? 0,
'items_count' => $t->items_count ?? 0, 'items_count' => $t->items()->count(),
'payment_method' => $t->payment_method?->value ?? $t->payment_method ?? '', 'payment_method' => $t->payment_method ?? '',
'cashier' => $t->user?->name ?? '', 'cashier' => $t->processedBy?->name ?? '',
'branch' => $t->branch?->name_ar ?? '', 'branch' => $t->branch?->name_ar ?? '',
]); ]);
} }
......
...@@ -195,6 +195,7 @@ public function render() ...@@ -195,6 +195,7 @@ public function render()
$searchResults = Participant::query() $searchResults = Participant::query()
->with('person') ->with('person')
->where('branch_id', $this->branchId) ->where('branch_id', $this->branchId)
->whereHas('invoices', fn ($iq) => $iq->whereIn('status', ['sent', 'partially_paid', 'overdue']))
->where(function ($q) { ->where(function ($q) {
$search = $this->search; $search = $this->search;
$q->where('participant_number', 'ilike', "%{$search}%") $q->where('participant_number', 'ilike', "%{$search}%")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment