feat:중간검사 API 다중단계/resolve/upsert 지원 (Phase 5.1.3)
- getInspectionTemplate: 전체 검사 단계 templates[] 반환 (기존 첫번째만→다중) - resolveInspectionDocument 신규: step_id 기반 기존 문서 조회 또는 템플릿 반환 - createInspectionDocument 개선: step_id 파라미터, 기존 DRAFT/REJECTED 문서 update 지원 - GET inspection-resolve 라우트 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -230,7 +230,17 @@ public function inspectionTemplate(int $id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 검사 완료 시 검사 문서(Document) 생성
|
||||
* 검사 문서 resolve (기존 문서 조회 또는 생성 정보 반환)
|
||||
*/
|
||||
public function resolveInspectionDocument(Request $request, int $id)
|
||||
{
|
||||
return ApiResponse::handle(function () use ($request, $id) {
|
||||
return $this->service->resolveInspectionDocument($id, $request->all());
|
||||
}, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 검사 완료 시 검사 문서(Document) 생성/수정
|
||||
*/
|
||||
public function createInspectionDocument(Request $request, int $id)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Documents\Document;
|
||||
use App\Models\Documents\DocumentTemplate;
|
||||
use App\Models\Orders\Order;
|
||||
use App\Models\Production\WorkOrder;
|
||||
@@ -1630,6 +1631,7 @@ public function getInspectionData(int $workOrderId, array $params = []): array
|
||||
* 작업지시의 검사용 문서 템플릿 조회
|
||||
*
|
||||
* work_order → process → steps(needs_inspection=true) → documentTemplate 로드
|
||||
* 모든 검사 단계의 템플릿을 반환 (다중 검사 단계 지원)
|
||||
*/
|
||||
public function getInspectionTemplate(int $workOrderId): array
|
||||
{
|
||||
@@ -1662,38 +1664,112 @@ public function getInspectionTemplate(int $workOrderId): array
|
||||
return [
|
||||
'work_order_id' => $workOrderId,
|
||||
'has_template' => false,
|
||||
'templates' => [],
|
||||
'template' => null,
|
||||
'work_order_info' => $this->buildWorkOrderInfo($workOrder),
|
||||
];
|
||||
}
|
||||
|
||||
// 첫 번째 검사 단계의 템플릿 사용 (향후 다중 검사 단계 지원 가능)
|
||||
$inspectionStep = $inspectionSteps->first();
|
||||
$template = $inspectionStep->documentTemplate;
|
||||
|
||||
if (! $template) {
|
||||
return [
|
||||
'work_order_id' => $workOrderId,
|
||||
'has_template' => false,
|
||||
'template' => null,
|
||||
'work_order_info' => $this->buildWorkOrderInfo($workOrder),
|
||||
];
|
||||
}
|
||||
|
||||
// DocumentService의 formatTemplateForReact와 동일한 포맷
|
||||
$documentService = app(DocumentService::class);
|
||||
$formattedTemplate = $documentService->formatTemplateForReact($template);
|
||||
$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),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'work_order_id' => $workOrderId,
|
||||
'has_template' => true,
|
||||
'has_template' => ! empty($templates),
|
||||
'templates' => $templates,
|
||||
// 하위호환: 첫 번째 템플릿
|
||||
'template' => ! empty($templates) ? $templates[0]['template'] : null,
|
||||
'work_order_info' => $this->buildWorkOrderInfo($workOrder),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 작업지시 검사 문서 resolve (기존 문서 조회 또는 생성 정보 반환)
|
||||
*
|
||||
* step_id 기반으로 해당 검사 단계의 템플릿과 기존 문서를 조회.
|
||||
* 기존 DRAFT/REJECTED 문서가 있으면 반환, 없으면 template만 반환.
|
||||
*/
|
||||
public function resolveInspectionDocument(int $workOrderId, array $params = []): array
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
|
||||
$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([
|
||||
'approvalLines',
|
||||
'basicFields',
|
||||
'sections.items',
|
||||
'columns',
|
||||
'sectionFields',
|
||||
]),
|
||||
'salesOrder:id,order_no,client_name,site_name',
|
||||
'items:id,work_order_id,item_name,specification,quantity,unit,sort_order',
|
||||
])
|
||||
->find($workOrderId);
|
||||
|
||||
if (! $workOrder) {
|
||||
throw new NotFoundHttpException(__('error.not_found'));
|
||||
}
|
||||
|
||||
// step_id가 지정되면 해당 단계 사용, 아니면 첫 번째 검사 단계
|
||||
$inspectionSteps = $workOrder->process?->steps ?? collect();
|
||||
$stepId = $params['step_id'] ?? null;
|
||||
|
||||
$inspectionStep = $stepId
|
||||
? $inspectionSteps->firstWhere('id', (int) $stepId)
|
||||
: $inspectionSteps->first();
|
||||
|
||||
if (! $inspectionStep || ! $inspectionStep->document_template_id) {
|
||||
throw new BadRequestHttpException(__('error.work_order.no_inspection_template'));
|
||||
}
|
||||
|
||||
$documentService = app(DocumentService::class);
|
||||
$formattedTemplate = $documentService->formatTemplateForReact($inspectionStep->documentTemplate);
|
||||
|
||||
// 기존 문서 조회 (work_order + template, 수정 가능한 상태)
|
||||
$existingDocument = Document::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('template_id', $inspectionStep->document_template_id)
|
||||
->where('linkable_type', 'work_order')
|
||||
->where('linkable_id', $workOrderId)
|
||||
->whereIn('status', [Document::STATUS_DRAFT, Document::STATUS_REJECTED])
|
||||
->with(['data', 'attachments.file', 'approvals.user:id,name'])
|
||||
->latest()
|
||||
->first();
|
||||
|
||||
return [
|
||||
'work_order_id' => $workOrderId,
|
||||
'step_id' => $inspectionStep->id,
|
||||
'step_name' => $inspectionStep->step_name,
|
||||
'template' => $formattedTemplate,
|
||||
'existing_document' => $existingDocument,
|
||||
'work_order_info' => $this->buildWorkOrderInfo($workOrder),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 검사 완료 시 Document + DocumentData 생성
|
||||
*
|
||||
* step_id 지정 시 해당 단계의 템플릿 사용, 미지정 시 첫 번째 검사 단계 사용.
|
||||
* 기존 DRAFT/REJECTED 문서가 있으면 update, 없으면 create.
|
||||
*/
|
||||
public function createInspectionDocument(int $workOrderId, array $inspectionData): array
|
||||
{
|
||||
@@ -1713,31 +1789,57 @@ public function createInspectionDocument(int $workOrderId, array $inspectionData
|
||||
throw new NotFoundHttpException(__('error.not_found'));
|
||||
}
|
||||
|
||||
$inspectionStep = $workOrder->process?->steps?->first();
|
||||
// step_id가 지정되면 해당 단계 사용, 아니면 첫 번째
|
||||
$inspectionSteps = $workOrder->process?->steps ?? collect();
|
||||
$stepId = $inspectionData['step_id'] ?? null;
|
||||
|
||||
$inspectionStep = $stepId
|
||||
? $inspectionSteps->firstWhere('id', (int) $stepId)
|
||||
: $inspectionSteps->first();
|
||||
|
||||
if (! $inspectionStep || ! $inspectionStep->document_template_id) {
|
||||
throw new BadRequestHttpException(__('error.work_order.no_inspection_template'));
|
||||
}
|
||||
|
||||
$documentService = app(DocumentService::class);
|
||||
|
||||
// DocumentService::create() 재사용
|
||||
$documentData = [
|
||||
'template_id' => $inspectionStep->document_template_id,
|
||||
'title' => $inspectionData['title'] ?? "중간검사성적서 - {$workOrder->work_order_no}",
|
||||
'linkable_type' => 'work_order',
|
||||
'linkable_id' => $workOrderId,
|
||||
'data' => $inspectionData['data'] ?? [],
|
||||
'approvers' => $inspectionData['approvers'] ?? [],
|
||||
];
|
||||
// 기존 DRAFT/REJECTED 문서가 있으면 update
|
||||
$existingDocument = Document::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('template_id', $inspectionStep->document_template_id)
|
||||
->where('linkable_type', 'work_order')
|
||||
->where('linkable_id', $workOrderId)
|
||||
->whereIn('status', [Document::STATUS_DRAFT, Document::STATUS_REJECTED])
|
||||
->latest()
|
||||
->first();
|
||||
|
||||
$document = $documentService->create($documentData);
|
||||
if ($existingDocument) {
|
||||
$document = $documentService->update($existingDocument->id, [
|
||||
'title' => $inspectionData['title'] ?? $existingDocument->title,
|
||||
'data' => $inspectionData['data'] ?? [],
|
||||
]);
|
||||
|
||||
$action = 'inspection_document_updated';
|
||||
} else {
|
||||
$documentData = [
|
||||
'template_id' => $inspectionStep->document_template_id,
|
||||
'title' => $inspectionData['title'] ?? "중간검사성적서 - {$workOrder->work_order_no}",
|
||||
'linkable_type' => 'work_order',
|
||||
'linkable_id' => $workOrderId,
|
||||
'data' => $inspectionData['data'] ?? [],
|
||||
'approvers' => $inspectionData['approvers'] ?? [],
|
||||
];
|
||||
|
||||
$document = $documentService->create($documentData);
|
||||
$action = 'inspection_document_created';
|
||||
}
|
||||
|
||||
// 감사 로그
|
||||
$this->auditLogger->log(
|
||||
$tenantId,
|
||||
self::AUDIT_TARGET,
|
||||
$workOrderId,
|
||||
'inspection_document_created',
|
||||
$action,
|
||||
null,
|
||||
['document_id' => $document->id, 'document_no' => $document->document_no]
|
||||
);
|
||||
@@ -1746,6 +1848,7 @@ public function createInspectionDocument(int $workOrderId, array $inspectionData
|
||||
'document_id' => $document->id,
|
||||
'document_no' => $document->document_no,
|
||||
'status' => $document->status,
|
||||
'is_new' => $action === 'inspection_document_created',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,8 @@
|
||||
Route::get('/{id}/inspection-data', [WorkOrderController::class, 'inspectionData'])->whereNumber('id')->name('v1.work-orders.inspection-data'); // 검사 데이터 조회
|
||||
Route::get('/{id}/inspection-report', [WorkOrderController::class, 'inspectionReport'])->whereNumber('id')->name('v1.work-orders.inspection-report'); // 검사 성적서 조회
|
||||
Route::get('/{id}/inspection-template', [WorkOrderController::class, 'inspectionTemplate'])->whereNumber('id')->name('v1.work-orders.inspection-template'); // 검사 문서 템플릿 조회
|
||||
Route::post('/{id}/inspection-document', [WorkOrderController::class, 'createInspectionDocument'])->whereNumber('id')->name('v1.work-orders.inspection-document'); // 검사 문서 생성
|
||||
Route::get('/{id}/inspection-resolve', [WorkOrderController::class, 'resolveInspectionDocument'])->whereNumber('id')->name('v1.work-orders.inspection-resolve'); // 검사 문서 resolve (기존 문서/템플릿)
|
||||
Route::post('/{id}/inspection-document', [WorkOrderController::class, 'createInspectionDocument'])->whereNumber('id')->name('v1.work-orders.inspection-document'); // 검사 문서 생성/수정
|
||||
});
|
||||
|
||||
// Work Result API (작업실적 관리)
|
||||
|
||||
Reference in New Issue
Block a user