feat: API調整訂單與販賣機訂單同步強制使用warehouse_code,更新API對接文件,及優化生產與配方模組UI顯示
All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 55s
All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 55s
This commit is contained in:
@@ -93,14 +93,16 @@ class SyncOrderAction
|
||||
'source_label' => $data['source_label'] ?? null,
|
||||
]);
|
||||
|
||||
// 2. 查找或建立倉庫
|
||||
$warehouseId = $data['warehouse_id'] ?? null;
|
||||
|
||||
if (empty($warehouseId)) {
|
||||
$warehouseName = $data['warehouse'] ?? '銷售倉庫';
|
||||
$warehouse = $this->inventoryService->findOrCreateWarehouseByName($warehouseName);
|
||||
$warehouseId = $warehouse->id;
|
||||
// 2. 查找倉庫
|
||||
$warehouseCode = $data['warehouse_code'];
|
||||
$warehouses = $this->inventoryService->getWarehousesByCodes([$warehouseCode]);
|
||||
|
||||
if ($warehouses->isEmpty()) {
|
||||
throw ValidationException::withMessages([
|
||||
'warehouse_code' => ["Warehouse with code {$warehouseCode} not found."]
|
||||
]);
|
||||
}
|
||||
$warehouseId = $warehouses->first()->id;
|
||||
|
||||
$totalAmount = 0;
|
||||
|
||||
|
||||
@@ -90,14 +90,16 @@ class SyncVendingOrderAction
|
||||
'source_label' => $data['machine_id'] ?? null,
|
||||
]);
|
||||
|
||||
// 2. 查找或建立倉庫
|
||||
$warehouseId = $data['warehouse_id'] ?? null;
|
||||
|
||||
if (empty($warehouseId)) {
|
||||
$warehouseName = $data['warehouse'] ?? '販賣機倉庫';
|
||||
$warehouse = $this->inventoryService->findOrCreateWarehouseByName($warehouseName);
|
||||
$warehouseId = $warehouse->id;
|
||||
// 2. 查找倉庫
|
||||
$warehouseCode = $data['warehouse_code'];
|
||||
$warehouses = $this->inventoryService->getWarehousesByCodes([$warehouseCode]);
|
||||
|
||||
if ($warehouses->isEmpty()) {
|
||||
throw ValidationException::withMessages([
|
||||
'warehouse_code' => ["Warehouse with code {$warehouseCode} not found."]
|
||||
]);
|
||||
}
|
||||
$warehouseId = $warehouses->first()->id;
|
||||
|
||||
$totalAmount = 0;
|
||||
|
||||
|
||||
@@ -23,8 +23,7 @@ class SyncOrderRequest extends FormRequest
|
||||
{
|
||||
return [
|
||||
'external_order_id' => 'required|string',
|
||||
'warehouse' => 'nullable|string',
|
||||
'warehouse_id' => 'nullable|integer',
|
||||
'warehouse_code' => 'required|string',
|
||||
'payment_method' => 'nullable|string|in:cash,credit_card,line_pay,ecpay,transfer,other',
|
||||
'sold_at' => 'nullable|date',
|
||||
'items' => 'required|array|min:1',
|
||||
|
||||
@@ -24,8 +24,7 @@ class SyncVendingOrderRequest extends FormRequest
|
||||
return [
|
||||
'external_order_id' => 'required|string',
|
||||
'machine_id' => 'nullable|string',
|
||||
'warehouse' => 'nullable|string',
|
||||
'warehouse_id' => 'nullable|integer',
|
||||
'warehouse_code' => 'required|string',
|
||||
'payment_method' => 'nullable|string|in:cash,electronic,line_pay,other',
|
||||
'sold_at' => 'nullable|date',
|
||||
'items' => 'required|array|min:1',
|
||||
|
||||
@@ -67,21 +67,46 @@ class ProductionOrderController extends Controller
|
||||
if (!in_array((int)$perPage, [10, 20, 50, 100])) {
|
||||
$perPage = $defaultPerPage;
|
||||
}
|
||||
$productionOrders = $query->paginate($perPage)->withQueryString();
|
||||
$productionOrders = $query->with('items')->paginate($perPage)->withQueryString();
|
||||
|
||||
// --- 手動資料水和 (Manual Hydration) ---
|
||||
$productIds = $productionOrders->pluck('product_id')->unique()->filter()->toArray();
|
||||
$warehouseIds = $productionOrders->pluck('warehouse_id')->unique()->filter()->toArray();
|
||||
$userIds = $productionOrders->pluck('user_id')->unique()->filter()->toArray();
|
||||
$productIds = collect();
|
||||
$warehouseIds = collect();
|
||||
$userIds = collect();
|
||||
$inventoryIds = collect();
|
||||
|
||||
$products = $this->inventoryService->getProductsByIds($productIds)->keyBy('id');
|
||||
$warehouses = $this->inventoryService->getAllWarehouses()->whereIn('id', $warehouseIds)->keyBy('id');
|
||||
$users = $this->coreService->getUsersByIds($userIds)->keyBy('id');
|
||||
foreach ($productionOrders as $order) {
|
||||
$productIds->push($order->product_id);
|
||||
$warehouseIds->push($order->warehouse_id);
|
||||
$userIds->push($order->user_id);
|
||||
if ($order->items) {
|
||||
$inventoryIds = $inventoryIds->merge($order->items->pluck('inventory_id'));
|
||||
}
|
||||
}
|
||||
|
||||
$productionOrders->getCollection()->transform(function ($order) use ($products, $warehouses, $users) {
|
||||
$products = $this->inventoryService->getProductsByIds($productIds->unique()->filter()->toArray())->keyBy('id');
|
||||
$warehouses = $this->inventoryService->getAllWarehouses()->whereIn('id', $warehouseIds->unique()->filter()->toArray())->keyBy('id');
|
||||
$users = $this->coreService->getUsersByIds($userIds->unique()->filter()->toArray())->keyBy('id');
|
||||
$inventories = $this->inventoryService->getInventoriesByIds($inventoryIds->unique()->filter()->toArray())->keyBy('id');
|
||||
|
||||
$productionOrders->getCollection()->transform(function ($order) use ($products, $warehouses, $users, $inventories) {
|
||||
$order->product = $products->get($order->product_id);
|
||||
$order->warehouse = $warehouses->get($order->warehouse_id);
|
||||
$order->user = $users->get($order->user_id);
|
||||
|
||||
$totalCost = 0;
|
||||
if ($order->items) {
|
||||
foreach ($order->items as $item) {
|
||||
$inventory = $inventories->get($item->inventory_id);
|
||||
if ($inventory) {
|
||||
$totalCost += $item->quantity_used * ($inventory->unit_cost ?? 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
$order->estimated_total_cost = $totalCost;
|
||||
$order->estimated_unit_cost = $order->output_quantity > 0 ? $totalCost / $order->output_quantity : 0;
|
||||
unset($order->items);
|
||||
|
||||
return $order;
|
||||
});
|
||||
|
||||
@@ -231,7 +256,9 @@ class ProductionOrderController extends Controller
|
||||
'unit_name' => $inv->product->baseUnit->name ?? '',
|
||||
'base_unit_id' => $inv->product->base_unit_id ?? null,
|
||||
'large_unit_id' => $inv->product->large_unit_id ?? null,
|
||||
'purchase_unit_id' => $inv->product->purchase_unit_id ?? null,
|
||||
'conversion_rate' => $inv->product->conversion_rate ?? 1,
|
||||
'unit_cost' => (float) $inv->unit_cost,
|
||||
];
|
||||
});
|
||||
|
||||
@@ -258,7 +285,10 @@ class ProductionOrderController extends Controller
|
||||
'expiry_date' => $inv->expiry_date ? $inv->expiry_date->format('Y-m-d') : null,
|
||||
'unit_name' => $inv->product->baseUnit->name ?? '',
|
||||
'base_unit_id' => $inv->product->base_unit_id ?? null,
|
||||
'large_unit_id' => $inv->product->large_unit_id ?? null,
|
||||
'purchase_unit_id' => $inv->product->purchase_unit_id ?? null,
|
||||
'conversion_rate' => $inv->product->conversion_rate ?? 1,
|
||||
'unit_cost' => (float) $inv->unit_cost,
|
||||
];
|
||||
});
|
||||
|
||||
|
||||
@@ -46,14 +46,51 @@ class RecipeController extends Controller
|
||||
$perPage = $defaultPerPage;
|
||||
}
|
||||
|
||||
$recipes = $query->paginate($perPage)->withQueryString();
|
||||
$recipes = $query->with('items')->paginate($perPage)->withQueryString();
|
||||
|
||||
// Manual Hydration
|
||||
$productIds = $recipes->pluck('product_id')->unique()->filter()->toArray();
|
||||
$products = $this->inventoryService->getProductsByIds($productIds)->keyBy('id');
|
||||
$productIds = collect();
|
||||
$itemProductIds = collect();
|
||||
|
||||
foreach ($recipes as $recipe) {
|
||||
$productIds->push($recipe->product_id);
|
||||
if ($recipe->items) {
|
||||
$itemProductIds = $itemProductIds->merge($recipe->items->pluck('product_id'));
|
||||
}
|
||||
}
|
||||
|
||||
$allProductIds = array_unique(array_merge(
|
||||
$productIds->unique()->filter()->toArray(),
|
||||
$itemProductIds->unique()->filter()->toArray()
|
||||
));
|
||||
|
||||
$products = $this->inventoryService->getProductsByIds($allProductIds)->keyBy('id');
|
||||
|
||||
$recipes->getCollection()->transform(function ($recipe) use ($products) {
|
||||
$recipe->product = $products->get($recipe->product_id);
|
||||
|
||||
$totalCost = 0;
|
||||
if ($recipe->items) {
|
||||
foreach ($recipe->items as $item) {
|
||||
$itemProduct = $products->get($item->product_id);
|
||||
if ($itemProduct) {
|
||||
$baseCost = $itemProduct->cost_price ?? 0;
|
||||
$conversionRate = 1;
|
||||
|
||||
if ($item->unit_id == $itemProduct->large_unit_id && !is_null($itemProduct->conversion_rate)) {
|
||||
$conversionRate = $itemProduct->conversion_rate;
|
||||
} elseif ($item->unit_id == $itemProduct->purchase_unit_id && !is_null($itemProduct->conversion_rate_purchase)) {
|
||||
$conversionRate = $itemProduct->conversion_rate_purchase;
|
||||
}
|
||||
|
||||
$totalCost += ($item->quantity * $baseCost * $conversionRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
$recipe->estimated_total_cost = $totalCost;
|
||||
$recipe->estimated_unit_cost = $recipe->yield_quantity > 0 ? $totalCost / $recipe->yield_quantity : 0;
|
||||
unset($recipe->items);
|
||||
|
||||
return $recipe;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user