feat: 작업일지/중간검사 설정을 ProcessStep → Process 레벨로 이동
- Process 모델에 document_template_id, needs_work_log, work_log_template_id 추가 - ProcessStep에서 해당 필드 제거 - WorkOrderService의 검사 관련 3개 메서드(getInspectionTemplate, resolveInspectionDocument, createInspectionDocument) 공정 레벨 참조로 변경 - ProcessService eager loading에 documentTemplate, workLogTemplateRelation 추가 - FormRequest 검증 규칙 이동 (ProcessStep → Process) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -55,7 +55,7 @@ public function index(array $params)
|
||||
'salesOrder.client:id,name',
|
||||
'process:id,process_name,process_code,department',
|
||||
'items:id,work_order_id,item_id,item_name,specification,quantity,unit,status,options,sort_order,source_order_item_id',
|
||||
'items.sourceOrderItem:id,order_node_id',
|
||||
'items.sourceOrderItem:id,order_node_id,floor_code,symbol_code',
|
||||
'items.sourceOrderItem.node:id,name,code',
|
||||
]);
|
||||
|
||||
@@ -210,7 +210,7 @@ public function show(int $id)
|
||||
'salesOrder.writer:id,name',
|
||||
'process:id,process_name,process_code,work_steps,department',
|
||||
'process.steps' => fn ($q) => $q->where('is_active', true)->orderBy('sort_order'),
|
||||
'items.sourceOrderItem:id,order_node_id',
|
||||
'items.sourceOrderItem:id,order_node_id,floor_code,symbol_code',
|
||||
'items.sourceOrderItem.node:id,name,code',
|
||||
'bendingDetail',
|
||||
'issues' => fn ($q) => $q->orderByDesc('created_at'),
|
||||
@@ -257,9 +257,22 @@ public function store(array $data)
|
||||
|
||||
// 품목 저장: 직접 전달된 품목이 없고 수주 ID가 있으면 수주에서 복사
|
||||
if (empty($items) && $salesOrderId) {
|
||||
$salesOrder = \App\Models\Orders\Order::with('items')->find($salesOrderId);
|
||||
$salesOrder = \App\Models\Orders\Order::with('items.node')->find($salesOrderId);
|
||||
if ($salesOrder && $salesOrder->items->isNotEmpty()) {
|
||||
foreach ($salesOrder->items as $index => $orderItem) {
|
||||
// 수주 품목 + 노드에서 options 조합
|
||||
$nodeOptions = $orderItem->node?->options ?? [];
|
||||
$options = array_filter([
|
||||
'floor' => $orderItem->floor_code,
|
||||
'code' => $orderItem->symbol_code,
|
||||
'width' => $nodeOptions['width'] ?? $nodeOptions['open_width'] ?? null,
|
||||
'height' => $nodeOptions['height'] ?? $nodeOptions['open_height'] ?? null,
|
||||
'cutting_info' => $nodeOptions['cutting_info'] ?? null,
|
||||
'slat_info' => $nodeOptions['slat_info'] ?? null,
|
||||
'bending_info' => $nodeOptions['bending_info'] ?? null,
|
||||
'wip_info' => $nodeOptions['wip_info'] ?? null,
|
||||
], fn ($v) => $v !== null);
|
||||
|
||||
$workOrder->items()->create([
|
||||
'tenant_id' => $tenantId,
|
||||
'source_order_item_id' => $orderItem->id, // 원본 수주 품목 추적용
|
||||
@@ -269,6 +282,7 @@ public function store(array $data)
|
||||
'quantity' => $orderItem->quantity,
|
||||
'unit' => $orderItem->unit,
|
||||
'sort_order' => $index,
|
||||
'options' => ! empty($options) ? $options : null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1639,11 +1653,7 @@ public function getInspectionTemplate(int $workOrderId): array
|
||||
|
||||
$workOrder = WorkOrder::where('tenant_id', $tenantId)
|
||||
->with([
|
||||
'process.steps' => fn ($q) => $q->where('is_active', true)
|
||||
->where('needs_inspection', true)
|
||||
->whereNotNull('document_template_id')
|
||||
->orderBy('sort_order'),
|
||||
'process.steps.documentTemplate' => fn ($q) => $q->with([
|
||||
'process.documentTemplate' => fn ($q) => $q->with([
|
||||
'approvalLines',
|
||||
'basicFields',
|
||||
'sections.items',
|
||||
@@ -1659,8 +1669,10 @@ public function getInspectionTemplate(int $workOrderId): array
|
||||
throw new NotFoundHttpException(__('error.not_found'));
|
||||
}
|
||||
|
||||
$inspectionSteps = $workOrder->process?->steps ?? collect();
|
||||
if ($inspectionSteps->isEmpty()) {
|
||||
$process = $workOrder->process;
|
||||
$docTemplate = $process?->documentTemplate;
|
||||
|
||||
if (! $docTemplate) {
|
||||
return [
|
||||
'work_order_id' => $workOrderId,
|
||||
'has_template' => false,
|
||||
@@ -1671,28 +1683,17 @@ public function getInspectionTemplate(int $workOrderId): array
|
||||
}
|
||||
|
||||
$documentService = app(DocumentService::class);
|
||||
$templates = [];
|
||||
|
||||
foreach ($inspectionSteps as $step) {
|
||||
if (! $step->documentTemplate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$templates[] = [
|
||||
'step_id' => $step->id,
|
||||
'step_name' => $step->step_name,
|
||||
'step_code' => $step->step_code,
|
||||
'sort_order' => $step->sort_order,
|
||||
'template' => $documentService->formatTemplateForReact($step->documentTemplate),
|
||||
];
|
||||
}
|
||||
$formattedTemplate = $documentService->formatTemplateForReact($docTemplate);
|
||||
|
||||
return [
|
||||
'work_order_id' => $workOrderId,
|
||||
'has_template' => ! empty($templates),
|
||||
'templates' => $templates,
|
||||
// 하위호환: 첫 번째 템플릿
|
||||
'template' => ! empty($templates) ? $templates[0]['template'] : null,
|
||||
'has_template' => true,
|
||||
'templates' => [[
|
||||
'template_id' => $docTemplate->id,
|
||||
'template_name' => $docTemplate->name,
|
||||
'template' => $formattedTemplate,
|
||||
]],
|
||||
'template' => $formattedTemplate,
|
||||
'work_order_info' => $this->buildWorkOrderInfo($workOrder),
|
||||
];
|
||||
}
|
||||
@@ -1709,11 +1710,7 @@ public function resolveInspectionDocument(int $workOrderId, array $params = []):
|
||||
|
||||
$workOrder = WorkOrder::where('tenant_id', $tenantId)
|
||||
->with([
|
||||
'process.steps' => fn ($q) => $q->where('is_active', true)
|
||||
->where('needs_inspection', true)
|
||||
->whereNotNull('document_template_id')
|
||||
->orderBy('sort_order'),
|
||||
'process.steps.documentTemplate' => fn ($q) => $q->with([
|
||||
'process.documentTemplate' => fn ($q) => $q->with([
|
||||
'approvalLines',
|
||||
'basicFields',
|
||||
'sections.items',
|
||||
@@ -1729,25 +1726,21 @@ public function resolveInspectionDocument(int $workOrderId, array $params = []):
|
||||
throw new NotFoundHttpException(__('error.not_found'));
|
||||
}
|
||||
|
||||
// step_id가 지정되면 해당 단계 사용, 아니면 첫 번째 검사 단계
|
||||
$inspectionSteps = $workOrder->process?->steps ?? collect();
|
||||
$stepId = $params['step_id'] ?? null;
|
||||
$process = $workOrder->process;
|
||||
$templateId = $process?->document_template_id;
|
||||
$docTemplate = $process?->documentTemplate;
|
||||
|
||||
$inspectionStep = $stepId
|
||||
? $inspectionSteps->firstWhere('id', (int) $stepId)
|
||||
: $inspectionSteps->first();
|
||||
|
||||
if (! $inspectionStep || ! $inspectionStep->document_template_id) {
|
||||
if (! $templateId || ! $docTemplate) {
|
||||
throw new BadRequestHttpException(__('error.work_order.no_inspection_template'));
|
||||
}
|
||||
|
||||
$documentService = app(DocumentService::class);
|
||||
$formattedTemplate = $documentService->formatTemplateForReact($inspectionStep->documentTemplate);
|
||||
$formattedTemplate = $documentService->formatTemplateForReact($docTemplate);
|
||||
|
||||
// 기존 문서 조회 (work_order + template, 수정 가능한 상태)
|
||||
$existingDocument = Document::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('template_id', $inspectionStep->document_template_id)
|
||||
->where('template_id', $templateId)
|
||||
->where('linkable_type', 'work_order')
|
||||
->where('linkable_id', $workOrderId)
|
||||
->whereIn('status', [Document::STATUS_DRAFT, Document::STATUS_REJECTED])
|
||||
@@ -1757,8 +1750,7 @@ public function resolveInspectionDocument(int $workOrderId, array $params = []):
|
||||
|
||||
return [
|
||||
'work_order_id' => $workOrderId,
|
||||
'step_id' => $inspectionStep->id,
|
||||
'step_name' => $inspectionStep->step_name,
|
||||
'template_id' => $templateId,
|
||||
'template' => $formattedTemplate,
|
||||
'existing_document' => $existingDocument,
|
||||
'work_order_info' => $this->buildWorkOrderInfo($workOrder),
|
||||
@@ -1768,7 +1760,7 @@ public function resolveInspectionDocument(int $workOrderId, array $params = []):
|
||||
/**
|
||||
* 검사 완료 시 Document + DocumentData 생성
|
||||
*
|
||||
* step_id 지정 시 해당 단계의 템플릿 사용, 미지정 시 첫 번째 검사 단계 사용.
|
||||
* 공정(Process) 레벨의 document_template_id를 사용.
|
||||
* 기존 DRAFT/REJECTED 문서가 있으면 update, 없으면 create.
|
||||
*/
|
||||
public function createInspectionDocument(int $workOrderId, array $inspectionData): array
|
||||
@@ -1777,27 +1769,18 @@ public function createInspectionDocument(int $workOrderId, array $inspectionData
|
||||
$userId = $this->apiUserId();
|
||||
|
||||
$workOrder = WorkOrder::where('tenant_id', $tenantId)
|
||||
->with([
|
||||
'process.steps' => fn ($q) => $q->where('is_active', true)
|
||||
->where('needs_inspection', true)
|
||||
->whereNotNull('document_template_id')
|
||||
->orderBy('sort_order'),
|
||||
])
|
||||
->with(['process'])
|
||||
->find($workOrderId);
|
||||
|
||||
if (! $workOrder) {
|
||||
throw new NotFoundHttpException(__('error.not_found'));
|
||||
}
|
||||
|
||||
// step_id가 지정되면 해당 단계 사용, 아니면 첫 번째
|
||||
$inspectionSteps = $workOrder->process?->steps ?? collect();
|
||||
$stepId = $inspectionData['step_id'] ?? null;
|
||||
// 공정 레벨의 중간검사 양식 사용
|
||||
$process = $workOrder->process;
|
||||
$templateId = $process?->document_template_id;
|
||||
|
||||
$inspectionStep = $stepId
|
||||
? $inspectionSteps->firstWhere('id', (int) $stepId)
|
||||
: $inspectionSteps->first();
|
||||
|
||||
if (! $inspectionStep || ! $inspectionStep->document_template_id) {
|
||||
if (! $templateId) {
|
||||
throw new BadRequestHttpException(__('error.work_order.no_inspection_template'));
|
||||
}
|
||||
|
||||
@@ -1806,7 +1789,7 @@ public function createInspectionDocument(int $workOrderId, array $inspectionData
|
||||
// 기존 DRAFT/REJECTED 문서가 있으면 update
|
||||
$existingDocument = Document::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('template_id', $inspectionStep->document_template_id)
|
||||
->where('template_id', $templateId)
|
||||
->where('linkable_type', 'work_order')
|
||||
->where('linkable_id', $workOrderId)
|
||||
->whereIn('status', [Document::STATUS_DRAFT, Document::STATUS_REJECTED])
|
||||
@@ -1822,7 +1805,7 @@ public function createInspectionDocument(int $workOrderId, array $inspectionData
|
||||
$action = 'inspection_document_updated';
|
||||
} else {
|
||||
$documentData = [
|
||||
'template_id' => $inspectionStep->document_template_id,
|
||||
'template_id' => $templateId,
|
||||
'title' => $inspectionData['title'] ?? "중간검사성적서 - {$workOrder->work_order_no}",
|
||||
'linkable_type' => 'work_order',
|
||||
'linkable_id' => $workOrderId,
|
||||
|
||||
Reference in New Issue
Block a user