From 92d39d7294f10586b95fa7796b0448083ad41eda Mon Sep 17 00:00:00 2001 From: kent Date: Wed, 14 Jan 2026 19:15:25 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9E=91=EC=97=85=EC=A7=80=EC=8B=9C=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=EC=97=90=20assigned=5Fto=5Fme=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 작업자 화면에서 나에게 배정된 작업만 조회하도록 지원 - 주 담당자(assignee_id) 또는 공동 담당자(assignees) 모두 포함 - 프론트엔드 WorkerScreen의 assigned_to_me=1 파라미터 처리 Co-Authored-By: Claude --- app/Services/WorkOrderService.php | 140 ++++++++++++++++++++++++------ 1 file changed, 112 insertions(+), 28 deletions(-) diff --git a/app/Services/WorkOrderService.php b/app/Services/WorkOrderService.php index 461ce52..4fee2fe 100644 --- a/app/Services/WorkOrderService.php +++ b/app/Services/WorkOrderService.php @@ -32,6 +32,7 @@ public function index(array $params) $status = $params['status'] ?? null; $processId = $params['process_id'] ?? null; $assigneeId = $params['assignee_id'] ?? null; + $assignedToMe = isset($params['assigned_to_me']) && $params['assigned_to_me']; $teamId = $params['team_id'] ?? null; $scheduledFrom = $params['scheduled_from'] ?? null; $scheduledTo = $params['scheduled_to'] ?? null; @@ -63,6 +64,15 @@ public function index(array $params) $query->where('assignee_id', $assigneeId); } + // 나에게 배정된 작업만 필터 (주 담당자 또는 공동 담당자) + if ($assignedToMe) { + $userId = $this->apiUserId(); + $query->where(function ($q) use ($userId) { + $q->where('assignee_id', $userId) + ->orWhereHas('assignees', fn ($aq) => $aq->where('user_id', $userId)); + }); + } + // 팀 필터 if ($teamId !== null) { $query->where('team_id', $teamId); @@ -329,8 +339,12 @@ public function destroy(int $id) /** * 상태 변경 + * + * @param int $id 작업지시 ID + * @param string $status 변경할 상태 + * @param array|null $resultData 완료 시 결과 데이터 (선택) */ - public function updateStatus(int $id, string $status) + public function updateStatus(int $id, string $status, ?array $resultData = null) { $tenantId = $this->tenantId(); $userId = $this->apiUserId(); @@ -357,36 +371,106 @@ public function updateStatus(int $id, string $status) ); } - $oldStatus = $workOrder->status; - $workOrder->status = $status; - $workOrder->updated_by = $userId; + return DB::transaction(function () use ($workOrder, $status, $resultData, $tenantId, $userId) { + $oldStatus = $workOrder->status; + $workOrder->status = $status; + $workOrder->updated_by = $userId; - // 상태에 따른 타임스탬프 업데이트 - switch ($status) { - case WorkOrder::STATUS_IN_PROGRESS: - $workOrder->started_at = $workOrder->started_at ?? now(); - break; - case WorkOrder::STATUS_COMPLETED: - $workOrder->completed_at = now(); - break; - case WorkOrder::STATUS_SHIPPED: - $workOrder->shipped_at = now(); - break; + // 상태에 따른 타임스탬프 업데이트 + switch ($status) { + case WorkOrder::STATUS_IN_PROGRESS: + $workOrder->started_at = $workOrder->started_at ?? now(); + break; + case WorkOrder::STATUS_COMPLETED: + $workOrder->completed_at = now(); + // 모든 품목에 결과 데이터 저장 + $this->saveItemResults($workOrder, $resultData, $userId); + break; + case WorkOrder::STATUS_SHIPPED: + $workOrder->shipped_at = now(); + break; + } + + $workOrder->save(); + + // 상태 변경 감사 로그 + $this->auditLogger->log( + $tenantId, + self::AUDIT_TARGET, + $workOrder->id, + 'status_changed', + ['status' => $oldStatus], + ['status' => $status] + ); + + return $workOrder->load(['assignee:id,name', 'assignees.user:id,name', 'team:id,name', 'process:id,process_name,process_code']); + }); + } + + /** + * 작업지시 품목에 결과 데이터 저장 + */ + private function saveItemResults(WorkOrder $workOrder, ?array $resultData, int $userId): void + { + $items = $workOrder->items; + $lotNo = $this->generateLotNo($workOrder); + + foreach ($items as $item) { + $itemResult = [ + 'completed_at' => now()->toDateTimeString(), + 'good_qty' => $item->quantity, // 기본값: 지시수량 전체가 양품 + 'defect_qty' => 0, + 'defect_rate' => 0, + 'lot_no' => $lotNo, + 'is_inspected' => false, + 'is_packaged' => false, + 'worker_id' => $userId, + 'memo' => null, + ]; + + // 개별 품목 결과 데이터가 있으면 병합 + if ($resultData && isset($resultData['items'][$item->id])) { + $itemResult = array_merge($itemResult, $resultData['items'][$item->id]); + // 불량률 재계산 + $totalQty = ($itemResult['good_qty'] ?? 0) + ($itemResult['defect_qty'] ?? 0); + $itemResult['defect_rate'] = $totalQty > 0 + ? round(($itemResult['defect_qty'] / $totalQty) * 100, 2) + : 0; + } + + // 품목 상태도 완료로 변경 + $item->status = WorkOrderItem::STATUS_COMPLETED; + $options = $item->options ?? []; + $options['result'] = $itemResult; + $item->options = $options; + $item->save(); + } + } + + /** + * LOT 번호 생성 + */ + private function generateLotNo(WorkOrder $workOrder): string + { + $date = now()->format('ymd'); + $prefix = 'KD-SA'; + + // 오늘 날짜의 마지막 LOT 번호 조회 + $lastLotNo = WorkOrderItem::where('tenant_id', $workOrder->tenant_id) + ->whereNotNull('options->result->lot_no') + ->where('options->result->lot_no', 'like', "{$prefix}-{$date}-%") + ->orderByDesc('id') + ->value('options->result->lot_no'); + + if ($lastLotNo) { + // 마지막 번호에서 시퀀스 추출 후 증가 + $parts = explode('-', $lastLotNo); + $seq = (int) end($parts) + 1; + } else { + $seq = 1; } - $workOrder->save(); - - // 상태 변경 감사 로그 - $this->auditLogger->log( - $tenantId, - self::AUDIT_TARGET, - $workOrder->id, - 'status_changed', - ['status' => $oldStatus], - ['status' => $status] - ); - - return $workOrder->load(['assignee:id,name', 'assignees.user:id,name', 'team:id,name', 'process:id,process_name,process_code']); + return sprintf('%s-%s-%02d', $prefix, $date, $seq); } /**