Files
alrahma_sunday_school_api/app/Services/PurchaseOrders/PurchaseOrderReceiveService.php
T
2026-06-11 11:06:32 -04:00

106 lines
3.6 KiB
PHP

<?php
namespace App\Services\PurchaseOrders;
use App\Models\PurchaseOrder;
use App\Models\PurchaseOrderItem;
use App\Models\Supply;
use App\Models\SupplyTransaction;
use App\Services\Inventory\InventoryMovementService;
use Illuminate\Support\Facades\DB;
use RuntimeException;
class PurchaseOrderReceiveService
{
public function __construct(
private InventoryMovementService $inventoryMovementService
) {
}
public function receive(int $poId, array $received, string $issuedBy): array
{
$po = PurchaseOrder::query()->find($poId);
if (!$po || in_array($po->status, [PurchaseOrder::STATUS_CANCELED, PurchaseOrder::STATUS_RECEIVED], true)) {
throw new RuntimeException('PO not receivable.');
}
if (empty($received)) {
throw new RuntimeException('No items to receive.');
}
return DB::transaction(function () use ($po, $received, $issuedBy) {
$completed = true;
foreach ($received as $item) {
$itemId = (int) ($item['id'] ?? 0);
$qty = (int) ($item['quantity'] ?? 0);
if ($itemId <= 0 || $qty <= 0) {
continue;
}
$poItem = PurchaseOrderItem::query()
->where('purchase_order_id', $po->id)
->where('id', $itemId)
->first();
if (!$poItem) {
$completed = false;
continue;
}
$remaining = (int) $poItem->quantity - (int) $poItem->received_qty;
$toReceive = min($remaining, $qty);
if ($toReceive <= 0) {
continue;
}
$poItem->received_qty = (int) $poItem->received_qty + $toReceive;
$poItem->save();
// Update supply qty_on_hand (legacy support)
$supply = Supply::query()->find($poItem->supply_id);
if ($supply) {
$supply->qty_on_hand = (int) $supply->qty_on_hand + $toReceive;
$supply->save();
SupplyTransaction::query()->create([
'supply_id' => $supply->id,
'type' => 'in',
'quantity' => $toReceive,
'ref' => 'PO ' . ($po->po_number ?? $po->id),
'issued_to' => 'Inventory',
'issued_by' => $issuedBy,
'notes' => 'Received against PO',
]);
}
// Create inventory movement if the PO item is linked to an inventory item
$inventoryItemId = $poItem->inventory_item_id;
if ($inventoryItemId) {
$performedBy = is_numeric($issuedBy) ? (int) $issuedBy : null;
$this->inventoryMovementService->recordMovement(
itemId: (int) $inventoryItemId,
qtyChange: $toReceive,
type: 'in',
reason: 'Purchase order received',
note: 'PO ' . ($po->po_number ?? $po->id),
performedBy: $performedBy
);
}
if ($poItem->received_qty < $poItem->quantity) {
$completed = false;
}
}
$po->status = $completed ? PurchaseOrder::STATUS_RECEIVED : PurchaseOrder::STATUS_ORDERED;
$po->save();
return [
'status' => $po->status,
'completed' => $completed,
];
});
}
}