From 8bac207274866e394372c7a0de29b532757411a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Fri, 16 Jan 2026 15:30:50 +0900 Subject: [PATCH] =?UTF-8?q?fix(WEB):=20=EC=9E=91=EC=97=85=EC=A7=80?= =?UTF-8?q?=EC=8B=9C=20=ED=92=88=EB=AA=A9=20=EC=88=98=EC=A3=BC=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99=20=EB=B0=8F=20=EB=B0=9C=EC=A3=BC=EC=B2=98=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 작업지시 생성 시 수주 품목 자동 복사 기능 추가 - 품목 추적용 source_order_item_id 컬럼 추가 - 발주처 표시를 위해 salesOrder 로딩에 client_id 추가 - 담당자 수정 시 assignee_ids 배열 처리 추가 Co-Authored-By: Claude --- app/Models/Production/WorkOrderItem.php | 1 + app/Services/WorkOrderService.php | 82 +++++++++++++++++-- ...rder_item_id_to_work_order_items_table.php | 29 +++++++ 3 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 database/migrations/2026_01_16_100001_add_source_order_item_id_to_work_order_items_table.php 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