feat(WEB): 절곡 자재투입 LOT 매핑 파이프라인 구현

- PrefixResolver: 제품코드×마감재질→LOT prefix 결정 + BD-XX-NN 코드 생성
- DynamicBomEntry DTO: dynamic_bom JSON 항목 타입 안전 관리
- BendingInfoBuilder 확장: build() 리턴 변경 + buildDynamicBomForItem() 추가
- OrderService: 작업지시 생성 시 per-item dynamic_bom 자동 저장
- WorkOrderService.getMaterials(): dynamic_bom 우선 체크 + N+1 배치 최적화
- WorkOrderService.registerMaterialInput(): work_order_item_id 분기 라우팅 통일
- 단위 테스트 58개 + 통합 테스트 6개 (64 tests / 293 assertions)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-22 02:13:08 +09:00
parent 9c88138de8
commit 5a3d6c2243
8 changed files with 1625 additions and 33 deletions

View File

@@ -1336,9 +1336,9 @@ public function createProductionOrder(int $orderId, array $data)
->values()
->all();
$bendingInfo = app(BendingInfoBuilder::class)->build($order, $processId, $nodeIds ?: null);
if ($bendingInfo) {
$workOrderOptions = ['bending_info' => $bendingInfo];
$buildResult = app(BendingInfoBuilder::class)->build($order, $processId, $nodeIds ?: null);
if ($buildResult) {
$workOrderOptions = ['bending_info' => $buildResult['bending_info']];
}
}
@@ -1405,17 +1405,33 @@ public function createProductionOrder(int $orderId, array $data)
$slatInfo['joint_bar'] = (2 + (int) floor(((float) $woWidth - 500) / 1000)) * $qty;
}
$woHeight = $nodeOptions['height'] ?? $nodeOptions['open_height'] ?? null;
$woItemOptions = array_filter([
'floor' => $orderItem->floor_code,
'code' => $orderItem->symbol_code,
'width' => $woWidth,
'height' => $nodeOptions['height'] ?? $nodeOptions['open_height'] ?? null,
'height' => $woHeight,
'cutting_info' => $nodeOptions['cutting_info'] ?? null,
'slat_info' => $slatInfo,
'bending_info' => $nodeOptions['bending_info'] ?? null,
'wip_info' => $nodeOptions['wip_info'] ?? null,
], fn ($v) => $v !== null);
// 절곡 공정: 개소별 dynamic_bom 생성
if (! empty($buildResult['context']) && $woWidth && $woHeight) {
$dynamicBom = app(BendingInfoBuilder::class)->buildDynamicBomForItem(
$buildResult['context'],
(int) $woWidth,
(int) $woHeight,
(int) ($orderItem->quantity ?? 1),
$tenantId,
);
if (! empty($dynamicBom)) {
$woItemOptions['dynamic_bom'] = $dynamicBom;
}
}
DB::table('work_order_items')->insert([
'tenant_id' => $tenantId,
'work_order_id' => $workOrder->id,