實作 InventoryService 的批量入庫 (processIncomingInventory) 與庫存調整 (adjustInventory) 邏輯
All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 55s

This commit is contained in:
2026-03-02 10:47:43 +08:00
parent 5f8b2a1c2d
commit 649af40919
5 changed files with 330 additions and 226 deletions

View File

@@ -674,4 +674,168 @@ class InventoryService implements InventoryServiceInterface
->groupBy('inventories.product_id', 'products.external_pos_id', 'products.code', 'products.name')
->get();
}
public function processIncomingInventory(Warehouse $warehouse, array $items, array $meta): void
{
DB::transaction(function () use ($warehouse, $items, $meta) {
foreach ($items as $item) {
$inventory = null;
if ($item['batchMode'] === 'existing') {
// 模式 A選擇現有批號 (包含已刪除的也要能找回來累加)
$inventory = Inventory::withTrashed()->findOrFail($item['inventoryId']);
if ($inventory->trashed()) {
$inventory->restore();
}
// 更新成本 (若有傳入)
if (isset($item['unit_cost'])) {
$inventory->unit_cost = $item['unit_cost'];
}
} elseif ($item['batchMode'] === 'none') {
// 模式 C不使用批號 (自動累加至 NO-BATCH)
$inventory = $warehouse->inventories()->withTrashed()->firstOrNew(
[
'product_id' => $item['productId'],
'batch_number' => 'NO-BATCH'
],
[
'quantity' => 0,
'unit_cost' => $item['unit_cost'] ?? 0,
'total_value' => 0,
'arrival_date' => $meta['inboundDate'],
'origin_country' => 'TW',
]
);
if ($inventory->trashed()) {
$inventory->restore();
}
} else {
// 模式 B建立新批號
$originCountry = $item['originCountry'] ?? 'TW';
$product = Product::find($item['productId']);
$batchNumber = Inventory::generateBatchNumber(
$product->code ?? 'UNK',
$originCountry,
$meta['inboundDate']
);
// 檢查是否存在
$inventory = $warehouse->inventories()->withTrashed()->firstOrNew(
[
'product_id' => $item['productId'],
'batch_number' => $batchNumber
],
[
'quantity' => 0,
'unit_cost' => $item['unit_cost'] ?? 0,
'total_value' => 0,
'location' => $item['location'] ?? null,
'arrival_date' => $meta['inboundDate'],
'expiry_date' => $item['expiryDate'] ?? null,
'origin_country' => $originCountry,
]
);
if ($inventory->trashed()) {
$inventory->restore();
}
}
$currentQty = $inventory->quantity;
$newQty = $currentQty + $item['quantity'];
$inventory->quantity = $newQty;
// 更新總價值
$inventory->total_value = $inventory->quantity * $inventory->unit_cost;
$inventory->saveQuietly();
// 寫入異動紀錄
$inventory->transactions()->create([
'type' => '手動入庫',
'quantity' => $item['quantity'],
'unit_cost' => $inventory->unit_cost,
'balance_before' => $currentQty,
'balance_after' => $newQty,
'reason' => $meta['reason'] . (!empty($meta['notes']) ? ' - ' . $meta['notes'] : ''),
'actual_time' => $meta['inboundDate'],
'user_id' => auth()->id(),
]);
}
});
}
public function adjustInventory(Inventory $inventory, array $data): void
{
DB::transaction(function () use ($inventory, $data) {
$currentQty = (float) $inventory->quantity;
$newQty = (float) $data['quantity'];
$isAdjustment = isset($data['operation']);
$changeQty = 0;
if ($isAdjustment) {
switch ($data['operation']) {
case 'add':
$changeQty = (float) $data['quantity'];
$newQty = $currentQty + $changeQty;
break;
case 'subtract':
$changeQty = -(float) $data['quantity'];
$newQty = $currentQty + $changeQty;
break;
case 'set':
$changeQty = $newQty - $currentQty;
break;
}
} else {
$changeQty = $newQty - $currentQty;
}
if (isset($data['unit_cost'])) {
$inventory->unit_cost = $data['unit_cost'];
}
$inventory->quantity = $newQty;
$inventory->total_value = $inventory->quantity * $inventory->unit_cost;
$inventory->saveQuietly();
$type = $data['type'] ?? ($isAdjustment ? 'manual_adjustment' : 'adjustment');
$typeMapping = [
'manual_adjustment' => '手動調整庫存',
'adjustment' => '盤點調整',
'purchase_in' => '採購進貨',
'sales_out' => '銷售出庫',
'return_in' => '退貨入庫',
'return_out' => '退貨出庫',
'transfer_in' => '撥補入庫',
'transfer_out' => '撥補出庫',
];
$chineseType = $typeMapping[$type] ?? $type;
if (!$isAdjustment && !isset($data['type'])) {
$chineseType = '手動編輯';
}
$reason = $data['reason'] ?? ($isAdjustment ? '手動庫存調整' : '編輯頁面更新');
if (!empty($data['notes'])) {
$reason .= ' - ' . $data['notes'];
}
if (abs($changeQty) > 0.0001) {
$inventory->transactions()->create([
'type' => $chineseType,
'quantity' => $changeQty,
'unit_cost' => $inventory->unit_cost,
'balance_before' => $currentQty,
'balance_after' => $newQty,
'reason' => $reason,
'actual_time' => now(),
'user_id' => auth()->id(),
]);
}
});
}
}