fix: [QMS] 인정품목 표시 수정 + 제품검사 성적서 필터 개선
- getFgProductName(): BOM 순회 대신 Order.item_id 직접 참조로 변경
- 제품검사 성적서 필터: document_id만 → document_id || inspection_status=completed
- getLocationDetail(): FQC 문서 데이터 포함 (template + data)
- formatFqcTemplate(): DB item → item_name 매핑 추가
- formatDocumentItem('product'): 개소별 층/기호 코드 표시
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -23,8 +23,7 @@ class QmsLotAuditService extends Service
|
||||
public function index(array $params): array
|
||||
{
|
||||
$query = QualityDocument::with([
|
||||
'documentOrders.order.nodes' => fn ($q) => $q->whereNull('parent_id'),
|
||||
'documentOrders.order.nodes.items.item',
|
||||
'documentOrders.order.item',
|
||||
'locations',
|
||||
'performanceReport',
|
||||
])
|
||||
@@ -89,7 +88,7 @@ public function routeDocuments(int $qualityDocumentOrderId): array
|
||||
{
|
||||
$docOrder = QualityDocumentOrder::with([
|
||||
'order.workOrders.process',
|
||||
'locations',
|
||||
'locations.orderItem',
|
||||
'qualityDocument',
|
||||
])->findOrFail($qualityDocumentOrderId);
|
||||
|
||||
@@ -119,17 +118,20 @@ public function routeDocuments(int $qualityDocumentOrderId): array
|
||||
// 2. 수주서
|
||||
$documents[] = $this->formatDocument('order', '수주서', collect([$order]));
|
||||
|
||||
// 3. 작업일지 (subType: process.process_name 기반)
|
||||
$documents[] = $this->formatDocumentWithSubType('log', '작업일지', $workOrders);
|
||||
// 3. 작업일지 (공정별 1개씩 — 같은 공정의 WO는 그룹핑)
|
||||
$workOrdersByProcess = $workOrders->groupBy('process_id')->map(fn ($group) => $group->first());
|
||||
$documents[] = $this->formatDocumentWithSubType('log', '작업일지', $workOrdersByProcess);
|
||||
|
||||
// 4. 중간검사 성적서 (PQC)
|
||||
// 4. 중간검사 성적서 (PQC — 공정별 1개씩)
|
||||
$pqcInspections = Inspection::where('inspection_type', 'PQC')
|
||||
->whereIn('work_order_id', $workOrders->pluck('id'))
|
||||
->where('status', 'completed')
|
||||
->with('workOrder.process')
|
||||
->get();
|
||||
|
||||
$documents[] = $this->formatDocumentWithSubType('report', '중간검사 성적서', $pqcInspections, 'workOrder');
|
||||
// 공정별 그룹핑 (같은 공정의 PQC는 최신 1개만)
|
||||
$pqcByProcess = $pqcInspections->groupBy(fn ($insp) => $insp->workOrder?->process_id)
|
||||
->map(fn ($group) => $group->sortByDesc('inspection_date')->first());
|
||||
$documents[] = $this->formatDocumentWithSubType('report', '중간검사 성적서', $pqcByProcess, 'workOrder');
|
||||
|
||||
// 5. 납품확인서
|
||||
$shipments = $order->shipments()->get();
|
||||
@@ -138,9 +140,11 @@ public function routeDocuments(int $qualityDocumentOrderId): array
|
||||
// 6. 출고증
|
||||
$documents[] = $this->formatDocument('shipping', '출고증', $shipments);
|
||||
|
||||
// 7. 제품검사 성적서
|
||||
$locationsWithDoc = $docOrder->locations->filter(fn ($loc) => $loc->document_id);
|
||||
$documents[] = $this->formatDocument('product', '제품검사 성적서', $locationsWithDoc);
|
||||
// 7. 제품검사 성적서 (FQC 문서 또는 inspection_data 완료건)
|
||||
$locationsWithInspection = $docOrder->locations->filter(
|
||||
fn ($loc) => $loc->document_id || $loc->inspection_status === 'completed'
|
||||
);
|
||||
$documents[] = $this->formatDocument('product', '제품검사 성적서', $locationsWithInspection);
|
||||
|
||||
// 8. 품질관리서
|
||||
$documents[] = $this->formatDocument('quality', '품질관리서', collect([$qualityDoc]));
|
||||
@@ -220,30 +224,14 @@ private function transformReportToFrontend(QualityDocument $doc): array
|
||||
}
|
||||
|
||||
/**
|
||||
* BOM 최상위(FG) 제품명 추출
|
||||
* Order → root OrderNode(parent_id=null) → 대표 OrderItem → Item(FG).name
|
||||
* 수주 대표 제품명 추출
|
||||
* Order.item_id → Item.name
|
||||
*/
|
||||
private function getFgProductName(QualityDocument $doc): string
|
||||
{
|
||||
$firstDocOrder = $doc->documentOrders->first();
|
||||
if (! $firstDocOrder) {
|
||||
return '';
|
||||
}
|
||||
$order = $doc->documentOrders->first()?->order;
|
||||
|
||||
$order = $firstDocOrder->order;
|
||||
if (! $order) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// eager loaded with whereNull('parent_id') filter
|
||||
$rootNode = $order->nodes->first();
|
||||
if (! $rootNode) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$representativeItem = $rootNode->items->first();
|
||||
|
||||
return $representativeItem?->item?->name ?? '';
|
||||
return $order?->item?->name ?? '';
|
||||
}
|
||||
|
||||
private function transformRouteToFrontend(QualityDocumentOrder $docOrder, QualityDocument $qualityDoc): array
|
||||
@@ -313,11 +301,12 @@ private function formatDocumentWithSubType(string $type, string $title, $collect
|
||||
'items' => $collection->values()->map(function ($item) use ($type, $workOrderRelation) {
|
||||
$formatted = $this->formatDocumentItem($type, $item);
|
||||
|
||||
// subType: process.process_name 기반
|
||||
// subType: process.process_name 기반 + work_order_id 전달
|
||||
$workOrder = $workOrderRelation ? $item->{$workOrderRelation} : $item;
|
||||
if ($workOrder instanceof WorkOrder) {
|
||||
$processName = $workOrder->process?->process_name;
|
||||
$formatted['sub_type'] = $this->mapProcessToSubType($processName);
|
||||
$formatted['work_order_id'] = $workOrder->id;
|
||||
}
|
||||
|
||||
return $formatted;
|
||||
@@ -354,7 +343,7 @@ private function formatDocumentItem(string $type, $item): array
|
||||
],
|
||||
'product' => [
|
||||
'id' => (string) $item->id,
|
||||
'title' => '제품검사 성적서',
|
||||
'title' => trim(($item->orderItem?->floor_code ?? '').' '.($item->orderItem?->symbol_code ?? '')) ?: '제품검사 성적서',
|
||||
'date' => $item->updated_at?->toDateString() ?? '',
|
||||
'code' => '',
|
||||
],
|
||||
@@ -479,9 +468,16 @@ private function getShipmentDetail(int $id): array
|
||||
|
||||
private function getLocationDetail(int $id): array
|
||||
{
|
||||
$location = QualityDocumentLocation::with(['orderItem', 'document'])->findOrFail($id);
|
||||
$location = QualityDocumentLocation::with([
|
||||
'orderItem',
|
||||
'document.template.sections.items',
|
||||
'document.template.columns',
|
||||
'document.template.approvalLines',
|
||||
'document.template.basicFields',
|
||||
'document.data',
|
||||
])->findOrFail($id);
|
||||
|
||||
return [
|
||||
$result = [
|
||||
'type' => 'product',
|
||||
'data' => [
|
||||
'id' => $location->id,
|
||||
@@ -494,6 +490,86 @@ private function getLocationDetail(int $id): array
|
||||
'document_id' => $location->document_id,
|
||||
],
|
||||
];
|
||||
|
||||
// FQC 문서가 있으면 template + data 포함
|
||||
if ($location->document) {
|
||||
$doc = $location->document;
|
||||
$result['data']['fqc_document'] = [
|
||||
'id' => $doc->id,
|
||||
'template_id' => $doc->template_id,
|
||||
'document_no' => $doc->document_no,
|
||||
'title' => $doc->title,
|
||||
'status' => $doc->status,
|
||||
'created_at' => $doc->created_at?->toIso8601String(),
|
||||
'template' => $this->formatFqcTemplate($doc->template),
|
||||
'data' => $doc->data->map(fn ($d) => [
|
||||
'section_id' => $d->section_id,
|
||||
'column_id' => $d->column_id,
|
||||
'row_index' => $d->row_index,
|
||||
'field_key' => $d->field_key,
|
||||
'field_value' => $d->field_value,
|
||||
])->all(),
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function formatFqcTemplate($template): ?array
|
||||
{
|
||||
if (! $template) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $template->id,
|
||||
'name' => $template->name,
|
||||
'category' => $template->category,
|
||||
'title' => $template->title,
|
||||
'approval_lines' => $template->approvalLines->map(fn ($a) => [
|
||||
'id' => $a->id,
|
||||
'name' => $a->name,
|
||||
'department' => $a->department,
|
||||
'sort_order' => $a->sort_order,
|
||||
])->all(),
|
||||
'basic_fields' => $template->basicFields->map(fn ($f) => [
|
||||
'id' => $f->id,
|
||||
'label' => $f->label,
|
||||
'field_key' => $f->field_key,
|
||||
'field_type' => $f->field_type,
|
||||
'default_value' => $f->default_value,
|
||||
'is_required' => $f->is_required,
|
||||
'sort_order' => $f->sort_order,
|
||||
])->all(),
|
||||
'sections' => $template->sections->map(fn ($s) => [
|
||||
'id' => $s->id,
|
||||
'name' => $s->name,
|
||||
'title' => $s->title,
|
||||
'description' => $s->description,
|
||||
'image_path' => $s->image_path,
|
||||
'sort_order' => $s->sort_order,
|
||||
'items' => $s->items->map(fn ($i) => [
|
||||
'id' => $i->id,
|
||||
'section_id' => $i->section_id,
|
||||
'item_name' => $i->item ?? '',
|
||||
'standard' => $i->standard,
|
||||
'tolerance' => $i->tolerance,
|
||||
'measurement_type' => $i->measurement_type,
|
||||
'frequency' => $i->frequency,
|
||||
'sort_order' => $i->sort_order,
|
||||
'category' => $i->category,
|
||||
'method' => $i->method,
|
||||
])->all(),
|
||||
])->all(),
|
||||
'columns' => $template->columns->map(fn ($c) => [
|
||||
'id' => $c->id,
|
||||
'label' => $c->label,
|
||||
'column_type' => $c->column_type,
|
||||
'width' => $c->width,
|
||||
'group_name' => $c->group_name,
|
||||
'sort_order' => $c->sort_order,
|
||||
])->all(),
|
||||
];
|
||||
}
|
||||
|
||||
private function getQualityDocDetail(int $id): array
|
||||
|
||||
Reference in New Issue
Block a user