feat: [생산관리] 중간검사 데이터 저장/조회 API 구현
- POST /work-orders/{id}/items/{itemId}/inspection: 품목별 검사 데이터 저장
- GET /work-orders/{id}/inspection-data: 전체 품목 검사 데이터 조회
- GET /work-orders/{id}/inspection-report: 검사 성적서용 데이터 조회
- WorkOrderItem 모델에 getInspectionData/setInspectionData 헬퍼 추가
- StoreItemInspectionRequest FormRequest 생성
- work_order_items.options['inspection_data']에 검사 결과 저장
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1519,4 +1519,151 @@ public function getMaterialInputHistory(int $workOrderId): array
|
||||
];
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// 중간검사 관련
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* 품목별 중간검사 데이터 저장
|
||||
*/
|
||||
public function storeItemInspection(int $workOrderId, int $itemId, array $data): array
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
$userId = $this->apiUserId();
|
||||
|
||||
$workOrder = WorkOrder::where('tenant_id', $tenantId)->find($workOrderId);
|
||||
if (! $workOrder) {
|
||||
throw new NotFoundHttpException(__('error.not_found'));
|
||||
}
|
||||
|
||||
$item = $workOrder->items()->find($itemId);
|
||||
if (! $item) {
|
||||
throw new NotFoundHttpException(__('error.not_found'));
|
||||
}
|
||||
|
||||
$beforeData = $item->getInspectionData();
|
||||
|
||||
$inspectionData = $data['inspection_data'];
|
||||
$inspectionData['process_type'] = $data['process_type'];
|
||||
$inspectionData['inspected_at'] = now()->toDateTimeString();
|
||||
$inspectionData['inspected_by'] = $userId;
|
||||
|
||||
$item->setInspectionData($inspectionData);
|
||||
$item->save();
|
||||
|
||||
// 감사 로그
|
||||
$this->auditLogger->log(
|
||||
$tenantId,
|
||||
self::AUDIT_TARGET,
|
||||
$workOrderId,
|
||||
'item_inspection_saved',
|
||||
['item_id' => $itemId, 'inspection_data' => $beforeData],
|
||||
['item_id' => $itemId, 'inspection_data' => $inspectionData]
|
||||
);
|
||||
|
||||
return [
|
||||
'item_id' => $item->id,
|
||||
'inspection_data' => $item->getInspectionData(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 작업지시의 전체 품목 검사 데이터 조회
|
||||
*/
|
||||
public function getInspectionData(int $workOrderId, array $params = []): array
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
|
||||
$workOrder = WorkOrder::where('tenant_id', $tenantId)->find($workOrderId);
|
||||
if (! $workOrder) {
|
||||
throw new NotFoundHttpException(__('error.not_found'));
|
||||
}
|
||||
|
||||
$query = $workOrder->items()->ordered();
|
||||
|
||||
// 공정 유형 필터
|
||||
if (! empty($params['process_type'])) {
|
||||
$query->where('options->inspection_data->process_type', $params['process_type']);
|
||||
}
|
||||
|
||||
$items = $query->get();
|
||||
|
||||
$inspectionMap = [];
|
||||
foreach ($items as $item) {
|
||||
$inspectionData = $item->getInspectionData();
|
||||
if ($inspectionData) {
|
||||
$inspectionMap[$item->id] = [
|
||||
'item_id' => $item->id,
|
||||
'item_name' => $item->item_name,
|
||||
'specification' => $item->specification,
|
||||
'quantity' => $item->quantity,
|
||||
'sort_order' => $item->sort_order,
|
||||
'options' => $item->options,
|
||||
'inspection_data' => $inspectionData,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'work_order_id' => $workOrderId,
|
||||
'items' => array_values($inspectionMap),
|
||||
'total' => count($inspectionMap),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 작업지시 검사 성적서용 데이터 조회 (전체 품목 + 검사 데이터 + 주문 정보)
|
||||
*/
|
||||
public function getInspectionReport(int $workOrderId): array
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
|
||||
$workOrder = WorkOrder::where('tenant_id', $tenantId)
|
||||
->with(['order', 'items' => function ($q) {
|
||||
$q->ordered();
|
||||
}])
|
||||
->find($workOrderId);
|
||||
|
||||
if (! $workOrder) {
|
||||
throw new NotFoundHttpException(__('error.not_found'));
|
||||
}
|
||||
|
||||
$items = $workOrder->items->map(function ($item) {
|
||||
return [
|
||||
'id' => $item->id,
|
||||
'item_name' => $item->item_name,
|
||||
'specification' => $item->specification,
|
||||
'quantity' => $item->quantity,
|
||||
'sort_order' => $item->sort_order,
|
||||
'status' => $item->status,
|
||||
'options' => $item->options,
|
||||
'inspection_data' => $item->getInspectionData(),
|
||||
];
|
||||
});
|
||||
|
||||
return [
|
||||
'work_order' => [
|
||||
'id' => $workOrder->id,
|
||||
'order_no' => $workOrder->order_no,
|
||||
'status' => $workOrder->status,
|
||||
'planned_date' => $workOrder->planned_date,
|
||||
'due_date' => $workOrder->due_date,
|
||||
],
|
||||
'order' => $workOrder->order ? [
|
||||
'id' => $workOrder->order->id,
|
||||
'order_no' => $workOrder->order->order_no,
|
||||
'client_name' => $workOrder->order->client_name ?? null,
|
||||
'site_name' => $workOrder->order->site_name ?? null,
|
||||
'order_date' => $workOrder->order->order_date ?? null,
|
||||
] : null,
|
||||
'items' => $items,
|
||||
'summary' => [
|
||||
'total_items' => $items->count(),
|
||||
'inspected_items' => $items->filter(fn ($i) => $i['inspection_data'] !== null)->count(),
|
||||
'passed_items' => $items->filter(fn ($i) => ($i['inspection_data']['judgment'] ?? null) === 'pass')->count(),
|
||||
'failed_items' => $items->filter(fn ($i) => ($i['inspection_data']['judgment'] ?? null) === 'fail')->count(),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user