diff --git a/app/Models/Production/WorkOrderItem.php b/app/Models/Production/WorkOrderItem.php index c11930f..1b3e4b7 100644 --- a/app/Models/Production/WorkOrderItem.php +++ b/app/Models/Production/WorkOrderItem.php @@ -19,6 +19,7 @@ class WorkOrderItem extends Model protected $fillable = [ 'tenant_id', 'work_order_id', + 'source_order_item_id', // 원본 수주 품목 추적용 'item_id', 'item_name', 'specification', diff --git a/app/Services/WorkOrderService.php b/app/Services/WorkOrderService.php index 04d89cd..c45158c 100644 --- a/app/Services/WorkOrderService.php +++ b/app/Services/WorkOrderService.php @@ -40,7 +40,14 @@ public function index(array $params) $query = WorkOrder::query() ->where('tenant_id', $tenantId) - ->with(['assignee:id,name', 'assignees.user:id,name', 'team:id,name', 'salesOrder:id,order_no', 'process:id,process_name,process_code']); + ->with([ + 'assignee:id,name', + 'assignees.user:id,name', + 'team:id,name', + 'salesOrder:id,order_no,client_id,client_name', + 'salesOrder.client:id,name', + 'process:id,process_name,process_code', + ]); // 검색어 if ($q !== '') { @@ -133,7 +140,7 @@ public function show(int $id) 'assignee:id,name', 'assignees.user:id,name', 'team:id,name', - 'salesOrder:id,order_no,site_name', + 'salesOrder:id,order_no,site_name,client_id', 'salesOrder.client:id,name', 'process:id,process_name,process_code,work_steps', 'items', @@ -171,6 +178,7 @@ public function store(array $data) $items = $data['items'] ?? []; $bendingDetail = $data['bending_detail'] ?? null; + $salesOrderId = $data['sales_order_id'] ?? null; unset($data['items'], $data['bending_detail']); $workOrder = WorkOrder::create($data); @@ -178,11 +186,30 @@ public function store(array $data) // process 관계 로드 (isBending 체크용) $workOrder->load('process:id,process_name,process_code'); - // 품목 저장 - foreach ($items as $index => $item) { - $item['tenant_id'] = $tenantId; - $item['sort_order'] = $index; - $workOrder->items()->create($item); + // 품목 저장: 직접 전달된 품목이 없고 수주 ID가 있으면 수주에서 복사 + if (empty($items) && $salesOrderId) { + $salesOrder = \App\Models\Orders\Order::with('items')->find($salesOrderId); + if ($salesOrder && $salesOrder->items->isNotEmpty()) { + foreach ($salesOrder->items as $index => $orderItem) { + $workOrder->items()->create([ + 'tenant_id' => $tenantId, + 'source_order_item_id' => $orderItem->id, // 원본 수주 품목 추적용 + 'item_id' => $orderItem->item_id, + 'item_name' => $orderItem->item_name, + 'specification' => $orderItem->specification, + 'quantity' => $orderItem->quantity, + 'unit' => $orderItem->unit, + 'sort_order' => $index, + ]); + } + } + } else { + // 직접 전달된 품목 저장 + foreach ($items as $index => $item) { + $item['tenant_id'] = $tenantId; + $item['sort_order'] = $index; + $workOrder->items()->create($item); + } } // 벤딩 상세 저장 (벤딩 공정인 경우) @@ -227,7 +254,8 @@ public function update(int $id, array $data) $items = $data['items'] ?? null; $bendingDetail = $data['bending_detail'] ?? null; - unset($data['items'], $data['bending_detail'], $data['work_order_no']); // 번호 변경 불가 + $assigneeIds = $data['assignee_ids'] ?? null; + unset($data['items'], $data['bending_detail'], $data['assignee_ids'], $data['work_order_no']); // 번호 변경 불가 // 품목 수정 시 기존 품목 기록 $oldItems = null; @@ -235,8 +263,46 @@ public function update(int $id, array $data) $oldItems = $workOrder->items()->get()->toArray(); } + // 담당자 수정 시 기존 담당자 기록 + $oldAssignees = null; + if ($assigneeIds !== null) { + $oldAssignees = $workOrder->assignees()->pluck('user_id')->toArray(); + } + $workOrder->update($data); + // 담당자 처리 (assignee_ids 배열) + if ($assigneeIds !== null) { + $assigneeIds = array_unique(array_filter($assigneeIds)); + + // 기존 담당자 삭제 후 새로 추가 + $workOrder->assignees()->delete(); + + foreach ($assigneeIds as $index => $assigneeId) { + WorkOrderAssignee::create([ + 'tenant_id' => $workOrder->tenant_id, + 'work_order_id' => $workOrder->id, + 'user_id' => $assigneeId, + 'is_primary' => $index === 0, // 첫 번째가 주 담당자 + ]); + } + + // 주 담당자는 work_orders 테이블에도 설정 (하위 호환) + $primaryAssigneeId = $assigneeIds[0] ?? null; + $workOrder->assignee_id = $primaryAssigneeId; + $workOrder->save(); + + // 담당자 수정 감사 로그 + $this->auditLogger->log( + $workOrder->tenant_id, + self::AUDIT_TARGET, + $workOrder->id, + 'assignees_updated', + ['assignee_ids' => $oldAssignees], + ['assignee_ids' => $assigneeIds] + ); + } + // 품목 부분 수정 (ID 기반 upsert/delete) if ($items !== null) { $existingIds = $workOrder->items()->pluck('id')->toArray(); diff --git a/database/migrations/2026_01_16_100001_add_source_order_item_id_to_work_order_items_table.php b/database/migrations/2026_01_16_100001_add_source_order_item_id_to_work_order_items_table.php new file mode 100644 index 0000000..89deb48 --- /dev/null +++ b/database/migrations/2026_01_16_100001_add_source_order_item_id_to_work_order_items_table.php @@ -0,0 +1,29 @@ +unsignedBigInteger('source_order_item_id')->nullable()->after('work_order_id') + ->comment('원본 수주 품목 ID (추적용)'); + $table->index('source_order_item_id', 'idx_work_order_items_source'); + }); + } + + public function down(): void + { + Schema::table('work_order_items', function (Blueprint $table) { + $table->dropIndex('idx_work_order_items_source'); + $table->dropColumn('source_order_item_id'); + }); + } +}; \ No newline at end of file