feat: 작업지시 목록에 assigned_to_me 필터 추가

- 작업자 화면에서 나에게 배정된 작업만 조회하도록 지원
- 주 담당자(assignee_id) 또는 공동 담당자(assignees) 모두 포함
- 프론트엔드 WorkerScreen의 assigned_to_me=1 파라미터 처리

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-01-14 19:15:25 +09:00
parent 524f1cf0fc
commit 92d39d7294

View File

@@ -32,6 +32,7 @@ public function index(array $params)
$status = $params['status'] ?? null; $status = $params['status'] ?? null;
$processId = $params['process_id'] ?? null; $processId = $params['process_id'] ?? null;
$assigneeId = $params['assignee_id'] ?? null; $assigneeId = $params['assignee_id'] ?? null;
$assignedToMe = isset($params['assigned_to_me']) && $params['assigned_to_me'];
$teamId = $params['team_id'] ?? null; $teamId = $params['team_id'] ?? null;
$scheduledFrom = $params['scheduled_from'] ?? null; $scheduledFrom = $params['scheduled_from'] ?? null;
$scheduledTo = $params['scheduled_to'] ?? null; $scheduledTo = $params['scheduled_to'] ?? null;
@@ -63,6 +64,15 @@ public function index(array $params)
$query->where('assignee_id', $assigneeId); $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) { if ($teamId !== null) {
$query->where('team_id', $teamId); $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(); $tenantId = $this->tenantId();
$userId = $this->apiUserId(); $userId = $this->apiUserId();
@@ -357,36 +371,106 @@ public function updateStatus(int $id, string $status)
); );
} }
$oldStatus = $workOrder->status; return DB::transaction(function () use ($workOrder, $status, $resultData, $tenantId, $userId) {
$workOrder->status = $status; $oldStatus = $workOrder->status;
$workOrder->updated_by = $userId; $workOrder->status = $status;
$workOrder->updated_by = $userId;
// 상태에 따른 타임스탬프 업데이트 // 상태에 따른 타임스탬프 업데이트
switch ($status) { switch ($status) {
case WorkOrder::STATUS_IN_PROGRESS: case WorkOrder::STATUS_IN_PROGRESS:
$workOrder->started_at = $workOrder->started_at ?? now(); $workOrder->started_at = $workOrder->started_at ?? now();
break; break;
case WorkOrder::STATUS_COMPLETED: case WorkOrder::STATUS_COMPLETED:
$workOrder->completed_at = now(); $workOrder->completed_at = now();
break; // 모든 품목에 결과 데이터 저장
case WorkOrder::STATUS_SHIPPED: $this->saveItemResults($workOrder, $resultData, $userId);
$workOrder->shipped_at = now(); break;
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(); return sprintf('%s-%s-%02d', $prefix, $date, $seq);
// 상태 변경 감사 로그
$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']);
} }
/** /**