From 38c240277176828220bf014a25e54d870e6ad288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Thu, 5 Mar 2026 19:26:52 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20[=EC=83=9D=EC=82=B0=EC=A7=80=EC=8B=9C]?= =?UTF-8?q?=20=EA=B3=B5=EC=A0=95=20=EC=A7=84=ED=96=89=20=ED=98=84=ED=99=A9?= =?UTF-8?q?=20WO=20=ED=95=84=ED=84=B0=EB=A7=81=20+=20BOM=20=ED=8C=8C?= =?UTF-8?q?=EC=8B=B1=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 공정 진행 현황: process_id=null인 구매품/서비스 WO 제외 (withCount, 목록/상세 모두) - extractBomProcessGroups: bom_result.items[] 구조에 맞게 파싱 수정 - process_name → process_group 키 사용 - 품목 필드 매핑 수정 (item_id, specification, unit, quantity, unit_price, total_price, node_name) Co-Authored-By: Claude Opus 4.6 --- app/Services/ProductionOrderService.php | 76 ++++++++++++++++--------- 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/app/Services/ProductionOrderService.php b/app/Services/ProductionOrderService.php index 65d6fc7c..349a6b3e 100644 --- a/app/Services/ProductionOrderService.php +++ b/app/Services/ProductionOrderService.php @@ -29,7 +29,10 @@ public function index(array $params): LengthAwarePaginator ->where('tenant_id', $tenantId) ->whereIn('status_code', self::PRODUCTION_STATUSES) ->with(['client', 'workOrders.process', 'workOrders.assignees.user']) - ->withCount(['workOrders', 'nodes']); + ->withCount([ + 'workOrders' => fn ($q) => $q->whereNotNull('process_id'), + 'nodes', + ]); // 검색어 필터 if (! empty($params['search'])) { @@ -79,12 +82,13 @@ public function index(array $params): LengthAwarePaginator // 개소수 (order_nodes 수) $order->node_count = $order->nodes_count ?? 0; - $workOrders = $order->workOrders; + // 생산 공정이 있는 WO만 (구매품/서비스 제외) + $productionWOs = $order->workOrders->filter(fn ($wo) => ! empty($wo->process_id)); $order->work_order_progress = [ - 'total' => $workOrders->count(), - 'completed' => $workOrders->where('status', 'completed')->count() - + $workOrders->where('status', 'shipped')->count(), - 'in_progress' => $workOrders->where('status', 'in_progress')->count(), + 'total' => $productionWOs->count(), + 'completed' => $productionWOs->where('status', 'completed')->count() + + $productionWOs->where('status', 'shipped')->count(), + 'in_progress' => $productionWOs->where('status', 'in_progress')->count(), ]; // 프론트 탭용 production_status 매핑 @@ -154,16 +158,19 @@ public function show(int $orderId): array : null; $order->production_status = $this->mapProductionStatus($order->status_code); - // WorkOrder 진행 현황 + // 생산 공정이 있는 WorkOrder만 필터 (process_id가 null인 구매품/서비스 제외) + $productionWorkOrders = $order->workOrders->filter(fn ($wo) => ! empty($wo->process_id)); + + // WorkOrder 진행 현황 (생산 공정 기준) $workOrderProgress = [ - 'total' => $order->workOrders->count(), - 'completed' => $order->workOrders->where('status', 'completed')->count() - + $order->workOrders->where('status', 'shipped')->count(), - 'in_progress' => $order->workOrders->where('status', 'in_progress')->count(), + 'total' => $productionWorkOrders->count(), + 'completed' => $productionWorkOrders->where('status', 'completed')->count() + + $productionWorkOrders->where('status', 'shipped')->count(), + 'in_progress' => $productionWorkOrders->where('status', 'in_progress')->count(), ]; - // WorkOrder 목록 가공 - $workOrders = $order->workOrders->map(function ($wo) { + // WorkOrder 목록 가공 (생산 공정만) + $workOrders = $productionWorkOrders->values()->map(function ($wo) { return [ 'id' => $wo->id, 'work_order_no' => $wo->work_order_no, @@ -202,6 +209,9 @@ private function mapProductionStatus(string $statusCode): string /** * order_nodes에서 BOM 공정 분류 추출 + * + * bom_result 구조: { items: [...], success, subtotals, ... } + * 각 item: { item_id, item_code, item_name, process_group, specification, quantity, unit, ... } */ private function extractBomProcessGroups($nodes): array { @@ -209,30 +219,42 @@ private function extractBomProcessGroups($nodes): array foreach ($nodes as $node) { $bomResult = $node->options['bom_result'] ?? null; - if (! $bomResult) { + if (! $bomResult || ! is_array($bomResult)) { continue; } - // bom_result 구조에 따라 공정별 그룹화 - foreach ($bomResult as $item) { - $processName = $item['process_name'] ?? '기타'; + // bom_result.items 배열에서 추출 + $items = $bomResult['items'] ?? []; + if (! is_array($items)) { + continue; + } - if (! isset($groups[$processName])) { - $groups[$processName] = [ - 'process_name' => $processName, - 'size_spec' => $item['size_spec'] ?? null, + $nodeName = $node->name ?? ''; + + foreach ($items as $item) { + if (! is_array($item)) { + continue; + } + + $processGroup = $item['process_group'] ?? $item['category_group'] ?? '기타'; + + if (! isset($groups[$processGroup])) { + $groups[$processGroup] = [ + 'process_name' => $processGroup, 'items' => [], ]; } - $groups[$processName]['items'][] = [ - 'id' => $item['id'] ?? null, + $groups[$processGroup]['items'][] = [ + 'id' => $item['item_id'] ?? null, 'item_code' => $item['item_code'] ?? '', 'item_name' => $item['item_name'] ?? '', - 'spec' => $item['spec'] ?? '', - 'lot_no' => $item['lot_no'] ?? '', - 'required_qty' => $item['required_qty'] ?? 0, - 'qty' => $item['qty'] ?? 0, + 'spec' => $item['specification'] ?? '', + 'unit' => $item['unit'] ?? '', + 'quantity' => $item['quantity'] ?? 0, + 'unit_price' => $item['unit_price'] ?? 0, + 'total_price' => $item['total_price'] ?? 0, + 'node_name' => $nodeName, ]; } }