diff --git a/app/Services/OrderService.php b/app/Services/OrderService.php index ab63e6f..c3df77a 100644 --- a/app/Services/OrderService.php +++ b/app/Services/OrderService.php @@ -1325,9 +1325,13 @@ public function createProductionOrder(int $orderId, array $data) // 작업지시번호 생성 $workOrderNo = $this->generateWorkOrderNo($tenantId); - // 절곡 공정이면 bending_info 자동 생성 + // 공정 옵션 초기화 (보조 공정 플래그 포함) $workOrderOptions = null; if ($processId) { + $process = \App\Models\Process::find($processId); + if ($process && ! empty($process->options['is_auxiliary'])) { + $workOrderOptions = ['is_auxiliary' => true]; + } // 이 작업지시에 포함되는 노드 ID만 추출 $nodeIds = collect($items) ->pluck('order_node_id') @@ -1338,7 +1342,7 @@ public function createProductionOrder(int $orderId, array $data) $buildResult = app(BendingInfoBuilder::class)->build($order, $processId, $nodeIds ?: null); if ($buildResult) { - $workOrderOptions = ['bending_info' => $buildResult['bending_info']]; + $workOrderOptions = array_merge($workOrderOptions ?? [], ['bending_info' => $buildResult['bending_info']]); } } diff --git a/app/Services/ProductionOrderService.php b/app/Services/ProductionOrderService.php index 349a6b3..a4889de 100644 --- a/app/Services/ProductionOrderService.php +++ b/app/Services/ProductionOrderService.php @@ -82,8 +82,8 @@ public function index(array $params): LengthAwarePaginator // 개소수 (order_nodes 수) $order->node_count = $order->nodes_count ?? 0; - // 생산 공정이 있는 WO만 (구매품/서비스 제외) - $productionWOs = $order->workOrders->filter(fn ($wo) => ! empty($wo->process_id)); + // 주요 생산 공정 WO만 (구매품 + 보조 공정 제외) + $productionWOs = $this->filterMainProductionWOs($order->workOrders); $order->work_order_progress = [ 'total' => $productionWOs->count(), 'completed' => $productionWOs->where('status', 'completed')->count() @@ -158,8 +158,8 @@ public function show(int $orderId): array : null; $order->production_status = $this->mapProductionStatus($order->status_code); - // 생산 공정이 있는 WorkOrder만 필터 (process_id가 null인 구매품/서비스 제외) - $productionWorkOrders = $order->workOrders->filter(fn ($wo) => ! empty($wo->process_id)); + // 주요 생산 공정 WO만 필터 (구매품 + 보조 공정 제외) + $productionWorkOrders = $this->filterMainProductionWOs($order->workOrders); // WorkOrder 진행 현황 (생산 공정 기준) $workOrderProgress = [ @@ -261,4 +261,23 @@ private function extractBomProcessGroups($nodes): array return array_values($groups); } + + /** + * 주요 생산 공정 WO만 필터 (구매품/서비스 + 보조 공정 제외) + * + * 제외 대상: + * - process_id가 null인 WO (구매품/서비스) + * - options.is_auxiliary가 true인 WO (재고생산 등 보조 공정) + */ + private function filterMainProductionWOs($workOrders): \Illuminate\Support\Collection + { + return $workOrders->filter(function ($wo) { + if (empty($wo->process_id)) { + return false; + } + $options = is_array($wo->options) ? $wo->options : (json_decode($wo->options, true) ?? []); + + return empty($options['is_auxiliary']); + }); + } } diff --git a/app/Services/WorkOrderService.php b/app/Services/WorkOrderService.php index 806c57a..d18aa7d 100644 --- a/app/Services/WorkOrderService.php +++ b/app/Services/WorkOrderService.php @@ -259,6 +259,17 @@ public function store(array $data) $salesOrderId = $data['sales_order_id'] ?? null; unset($data['items'], $data['bending_detail']); + // 공정의 is_auxiliary 플래그를 WO options에 복사 + if (! empty($data['process_id'])) { + $process = \App\Models\Process::find($data['process_id']); + if ($process && ! empty($process->options['is_auxiliary'])) { + $opts = $data['options'] ?? []; + $opts = is_array($opts) ? $opts : (json_decode($opts, true) ?? []); + $opts['is_auxiliary'] = true; + $data['options'] = $opts; + } + } + $workOrder = WorkOrder::create($data); // process 관계 로드 (isBending 체크용) @@ -815,6 +826,11 @@ private function syncOrderStatus(WorkOrder $workOrder, int $tenantId): void return; } + // 보조 공정(재고생산 등)은 수주 상태에 영향 주지 않음 + if ($this->isAuxiliaryWorkOrder($workOrder)) { + return; + } + $order = Order::where('tenant_id', $tenantId)->find($workOrder->sales_order_id); if (! $order) { return; @@ -858,6 +874,9 @@ private function syncOrderStatus(WorkOrder $workOrder, int $tenantId): void */ private function autoStartWorkOrderOnMaterialInput(WorkOrder $workOrder, int $tenantId): void { + // 보조 공정(재고생산 등)은 WO 자체는 진행중으로 전환하되, 수주 상태는 변경하지 않음 + $isAuxiliary = $this->isAuxiliaryWorkOrder($workOrder); + // 아직 진행 전인 상태에서만 자동 전환 (자재투입 = 실질적 작업 시작) if (! in_array($workOrder->status, [ WorkOrder::STATUS_UNASSIGNED, @@ -882,8 +901,10 @@ private function autoStartWorkOrderOnMaterialInput(WorkOrder $workOrder, int $te ['status' => WorkOrder::STATUS_IN_PROGRESS] ); - // 연결된 수주(Order) 상태 동기화 (IN_PROGRESS → IN_PRODUCTION) - $this->syncOrderStatus($workOrder, $tenantId); + // 보조 공정이 아닌 경우만 수주 상태 동기화 + if (! $isAuxiliary) { + $this->syncOrderStatus($workOrder, $tenantId); + } } /** @@ -926,6 +947,16 @@ private function saveItemResults(WorkOrder $workOrder, ?array $resultData, int $ } } + /** + * 보조 공정(재고생산 등) 여부 판단 + */ + private function isAuxiliaryWorkOrder(WorkOrder $workOrder): bool + { + $options = is_array($workOrder->options) ? $workOrder->options : (json_decode($workOrder->options, true) ?? []); + + return ! empty($options['is_auxiliary']); + } + /** * LOT 번호 생성 */