fix: 절곡 자재투입 dynamic_bom 수량 보정 및 개소당 수량 산출
- getMaterialsForItem(): dynamic_bom 우선 체크 추가 (정적 BOM만 확인하던 문제) - dynamic_bom.qty를 woItem.quantity로 나눠 개소당 수량 산출 (작업일지 bendingInfo와 일치) - getMaterials(): 동일하게 개소당 수량으로 변환 - 응답에 lot_prefix, part_type, category 필드 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1229,16 +1229,18 @@ public function getMaterials(int $workOrderId): array
|
||||
|
||||
// 합산 키: (item_id, work_order_item_id) 쌍
|
||||
$key = $childItemId.'_'.$woItem->id;
|
||||
// dynamic_bom.qty는 아이템 수량이 곱해져 있으므로 나눠서 개소당 수량 산출
|
||||
$bomQty = (float) ($bomEntry['qty'] ?? 1);
|
||||
$requiredQty = $bomQty * ($woItem->quantity ?? 1);
|
||||
$woItemQty = max(1, (float) ($woItem->quantity ?? 1));
|
||||
$perNodeQty = $bomQty / $woItemQty;
|
||||
|
||||
if (isset($uniqueMaterials[$key])) {
|
||||
$uniqueMaterials[$key]['required_qty'] += $requiredQty;
|
||||
$uniqueMaterials[$key]['required_qty'] += $perNodeQty;
|
||||
} else {
|
||||
$uniqueMaterials[$key] = [
|
||||
'item' => $dynamicItems[$childItemId],
|
||||
'bom_qty' => $bomQty,
|
||||
'required_qty' => $requiredQty,
|
||||
'bom_qty' => $perNodeQty,
|
||||
'required_qty' => $perNodeQty,
|
||||
'work_order_item_id' => $woItem->id,
|
||||
'lot_prefix' => $bomEntry['lot_prefix'] ?? null,
|
||||
'part_type' => $bomEntry['part_type'] ?? null,
|
||||
@@ -2847,7 +2849,45 @@ public function getMaterialsForItem(int $workOrderId, int $itemId): array
|
||||
// 해당 개소의 BOM 기반 자재 추출
|
||||
$materialItems = [];
|
||||
|
||||
if ($woItem->item_id) {
|
||||
// ① dynamic_bom 우선 체크 (절곡 등 동적 BOM 사용 공정)
|
||||
$options = is_string($woItem->options) ? json_decode($woItem->options, true) : ($woItem->options ?? []);
|
||||
$dynamicBom = $options['dynamic_bom'] ?? null;
|
||||
|
||||
if ($dynamicBom && is_array($dynamicBom)) {
|
||||
// dynamic_bom child_item_id 배치 조회 (N+1 방지)
|
||||
$childItemIds = array_filter(array_column($dynamicBom, 'child_item_id'));
|
||||
$childItems = [];
|
||||
if (! empty($childItemIds)) {
|
||||
$childItems = \App\Models\Items\Item::where('tenant_id', $tenantId)
|
||||
->whereIn('id', array_unique($childItemIds))
|
||||
->get()
|
||||
->keyBy('id');
|
||||
}
|
||||
|
||||
foreach ($dynamicBom as $bomEntry) {
|
||||
$childItemId = $bomEntry['child_item_id'] ?? null;
|
||||
if (! $childItemId || ! isset($childItems[$childItemId])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// dynamic_bom.qty는 아이템 수량이 곱해져 있으므로 나눠서 개소당 수량 산출
|
||||
// (작업일지 bendingInfo와 동일한 수량)
|
||||
$bomQty = (float) ($bomEntry['qty'] ?? 1);
|
||||
$woItemQty = max(1, (float) ($woItem->quantity ?? 1));
|
||||
$perNodeQty = $bomQty / $woItemQty;
|
||||
$materialItems[] = [
|
||||
'item' => $childItems[$childItemId],
|
||||
'bom_qty' => $perNodeQty,
|
||||
'required_qty' => $perNodeQty,
|
||||
'lot_prefix' => $bomEntry['lot_prefix'] ?? null,
|
||||
'part_type' => $bomEntry['part_type'] ?? null,
|
||||
'category' => $bomEntry['category'] ?? null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// ② dynamic_bom이 없으면 정적 BOM fallback
|
||||
if (empty($materialItems) && $woItem->item_id) {
|
||||
$item = \App\Models\Items\Item::where('tenant_id', $tenantId)
|
||||
->find($woItem->item_id);
|
||||
|
||||
@@ -2936,6 +2976,9 @@ public function getMaterialsForItem(int $workOrderId, int $itemId): array
|
||||
'receipt_date' => $lot->receipt_date,
|
||||
'supplier' => $lot->supplier,
|
||||
'fifo_rank' => $rank++,
|
||||
'lot_prefix' => $matInfo['lot_prefix'] ?? null,
|
||||
'part_type' => $matInfo['part_type'] ?? null,
|
||||
'category' => $matInfo['category'] ?? null,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -2959,6 +3002,9 @@ public function getMaterialsForItem(int $workOrderId, int $itemId): array
|
||||
'receipt_date' => null,
|
||||
'supplier' => null,
|
||||
'fifo_rank' => $rank++,
|
||||
'lot_prefix' => $matInfo['lot_prefix'] ?? null,
|
||||
'part_type' => $matInfo['part_type'] ?? null,
|
||||
'category' => $matInfo['category'] ?? null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user