diff --git a/LOGICAL_RELATIONSHIPS.md b/LOGICAL_RELATIONSHIPS.md index a8ccbb8..6fc90b6 100644 --- a/LOGICAL_RELATIONSHIPS.md +++ b/LOGICAL_RELATIONSHIPS.md @@ -1,6 +1,6 @@ # 논리적 데이터베이스 관계 문서 -> **자동 생성**: 2026-03-06 15:12:45 +> **자동 생성**: 2026-03-06 21:25:05 > **소스**: Eloquent 모델 관계 분석 ## 📊 모델별 관계 현황 diff --git a/app/Services/DocumentService.php b/app/Services/DocumentService.php index 82783b6..ed25399 100644 --- a/app/Services/DocumentService.php +++ b/app/Services/DocumentService.php @@ -663,20 +663,32 @@ public function fqcStatus(int $orderId, int $templateId): array $tenantId = $this->tenantId(); $order = \App\Models\Orders\Order::where('tenant_id', $tenantId) - ->with('items') + ->with(['rootNodes.items' => fn ($q) => $q->orderBy('sort_order')]) ->findOrFail($orderId); - // 해당 수주의 FQC 문서 조회 + // 개소별 대표 OrderItem ID 수집 + $representativeItemIds = $order->rootNodes + ->map(fn ($node) => $node->items->first()?->id) + ->filter() + ->values(); + + // 해당 대표 품목의 FQC 문서 조회 $documents = Document::where('tenant_id', $tenantId) ->where('template_id', $templateId) ->where('linkable_type', \App\Models\Orders\OrderItem::class) - ->whereIn('linkable_id', $order->items->pluck('id')) + ->whereIn('linkable_id', $representativeItemIds) ->with('data') ->get() ->keyBy('linkable_id'); - $items = $order->items->map(function ($orderItem) use ($documents) { - $doc = $documents->get($orderItem->id); + // 개소(root node)별 진행현황 + $items = $order->rootNodes->map(function ($node) use ($documents) { + $representativeItem = $node->items->first(); + if (! $representativeItem) { + return null; + } + + $doc = $documents->get($representativeItem->id); // 종합판정 값 추출 $judgement = null; @@ -686,17 +698,17 @@ public function fqcStatus(int $orderId, int $templateId): array } return [ - 'order_item_id' => $orderItem->id, - 'floor_code' => $orderItem->floor_code, - 'symbol_code' => $orderItem->symbol_code, - 'specification' => $orderItem->specification, - 'item_name' => $orderItem->item_name, + 'order_item_id' => $representativeItem->id, + 'floor_code' => $representativeItem->floor_code, + 'symbol_code' => $representativeItem->symbol_code, + 'specification' => $representativeItem->specification, + 'item_name' => $representativeItem->item_name, 'document_id' => $doc?->id, 'document_no' => $doc?->document_no, 'status' => $doc?->status ?? 'NONE', 'judgement' => $judgement, ]; - }); + })->filter()->values(); // 통계 $total = $items->count(); @@ -889,6 +901,7 @@ public function upsert(array $data): Document if (isset($data['rendered_html'])) { $updatePayload['rendered_html'] = $data['rendered_html']; } + return $this->update($existingDocument->id, $updatePayload); } @@ -904,6 +917,7 @@ public function upsert(array $data): Document if (isset($data['rendered_html'])) { $createPayload['rendered_html'] = $data['rendered_html']; } + return $this->create($createPayload); }); } diff --git a/app/Services/QualityDocumentService.php b/app/Services/QualityDocumentService.php index 74a3829..e3142cd 100644 --- a/app/Services/QualityDocumentService.php +++ b/app/Services/QualityDocumentService.php @@ -2,6 +2,9 @@ namespace App\Services; +use App\Models\Documents\Document; +use App\Models\Documents\DocumentData; +use App\Models\Documents\DocumentTemplate; use App\Models\Orders\Order; use App\Models\Orders\OrderItem; use App\Models\Orders\OrderNode; @@ -9,9 +12,6 @@ use App\Models\Qualitys\QualityDocument; use App\Models\Qualitys\QualityDocumentLocation; use App\Models\Qualitys\QualityDocumentOrder; -use App\Models\Documents\Document; -use App\Models\Documents\DocumentData; -use App\Models\Documents\DocumentTemplate; use App\Services\Audit\AuditLogger; use Illuminate\Support\Facades\DB; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; @@ -377,6 +377,8 @@ public function availableOrders(array $params): array { $tenantId = $this->tenantId(); $q = trim((string) ($params['q'] ?? '')); + $clientId = $params['client_id'] ?? null; + $itemId = $params['item_id'] ?? null; // 이미 연결된 수주 ID 목록 $linkedOrderIds = QualityDocumentOrder::whereHas('qualityDocument', function ($query) use ($tenantId) { @@ -385,6 +387,12 @@ public function availableOrders(array $params): array $query = Order::where('tenant_id', $tenantId) ->whereNotIn('id', $linkedOrderIds) + ->with(['item:id,name', 'nodes' => function ($q) { + $q->whereNull('parent_id')->orderBy('sort_order') + ->with(['items' => function ($q2) { + $q2->orderBy('sort_order')->limit(1); + }]); + }]) ->withCount(['nodes as location_count' => function ($q) { $q->whereNull('parent_id'); }]); @@ -396,6 +404,16 @@ public function availableOrders(array $params): array }); } + // 같은 거래처(발주처) 필터 + if ($clientId) { + $query->where('client_id', $clientId); + } + + // 같은 모델(품목) 필터 + if ($itemId) { + $query->where('item_id', $itemId); + } + return $query->orderByDesc('id') ->limit(50) ->get() @@ -403,9 +421,24 @@ public function availableOrders(array $params): array 'id' => $order->id, 'order_number' => $order->order_no, 'site_name' => $order->site_name ?? '', + 'client_id' => $order->client_id, 'client_name' => $order->client_name ?? '', + 'item_id' => $order->item_id, + 'item_name' => $order->item?->name ?? '', 'delivery_date' => $order->delivery_date?->format('Y-m-d') ?? '', 'location_count' => $order->location_count, + 'locations' => $order->nodes->where('parent_id', null)->map(function ($node) { + $item = $node->items->first(); + $options = $node->options ?? []; + + return [ + 'node_id' => $node->id, + 'floor' => $item?->floor_code ?? $node->code ?? '', + 'symbol' => $item?->symbol_code ?? '', + 'order_width' => $options['width'] ?? 0, + 'order_height' => $options['height'] ?? 0, + ]; + })->values()->toArray(), ]) ->toArray(); } @@ -701,6 +734,10 @@ private function transformToFrontend(QualityDocument $doc, bool $detail = false) 'order_id' => $order?->id, 'order_number' => $order?->order_no ?? '', 'site_name' => $order?->site_name ?? '', + 'client_id' => $order?->client_id, + 'client_name' => $order?->client_name ?? '', + 'item_id' => $order?->item_id, + 'item_name' => $order?->item?->name ?? '', 'delivery_date' => $order?->delivery_date ? $order->delivery_date->format('Y-m-d') : '', 'floor' => $orderItem?->floor_code ?? '', 'symbol' => $orderItem?->symbol_code ?? '', @@ -710,6 +747,7 @@ private function transformToFrontend(QualityDocument $doc, bool $detail = false) 'construction_height' => $loc->post_height ?? 0, 'change_reason' => $loc->change_reason ?? '', 'inspection_data' => $loc->inspection_data, + 'document_id' => $loc->document_id, ]; })->toArray(); } @@ -729,10 +767,6 @@ public function inspectLocation(int $docId, int $locId, array $data) throw new NotFoundHttpException(__('error.not_found')); } - if ($doc->isCompleted()) { - throw new BadRequestHttpException(__('error.quality.cannot_modify_completed')); - } - $location = QualityDocumentLocation::where('quality_document_id', $docId)->find($locId); if (! $location) { throw new NotFoundHttpException(__('error.not_found')); @@ -753,6 +787,9 @@ public function inspectLocation(int $docId, int $locId, array $data) if (isset($data['inspection_status'])) { $updateData['inspection_status'] = $data['inspection_status']; } + if (array_key_exists('inspection_data', $data)) { + $updateData['inspection_data'] = $data['inspection_data']; + } if (! empty($updateData)) { $location->update($updateData); @@ -931,7 +968,7 @@ private function syncRequestDocument(QualityDocument $doc): void 'tenant_id' => $tenantId, 'template_id' => self::REQUEST_TEMPLATE_ID, 'document_no' => $documentNo, - 'title' => '제품검사 요청서 - ' . ($doc->site_name ?? $doc->quality_doc_number), + 'title' => '제품검사 요청서 - '.($doc->site_name ?? $doc->quality_doc_number), 'status' => Document::STATUS_DRAFT, 'linkable_type' => QualityDocument::class, 'linkable_id' => $doc->id, @@ -1029,6 +1066,7 @@ private function syncRequestDocument(QualityDocument $doc): void DocumentData::insert(array_map(function ($d) { $d['created_at'] = now(); $d['updated_at'] = now(); + return $d; }, $eavData)); } @@ -1052,7 +1090,7 @@ private function buildBasicFieldMapping(QualityDocument $doc, array $options): a 'manager_contact' => $manager['phone'] ?? '', 'site_name' => $doc->site_name ?? '', 'delivery_date' => $order?->delivery_date?->format('Y-m-d') ?? '', - 'site_address' => trim(($siteAddress['address'] ?? '') . ' ' . ($siteAddress['detail'] ?? '')), + 'site_address' => trim(($siteAddress['address'] ?? '').' '.($siteAddress['detail'] ?? '')), 'total_locations' => (string) ($doc->locations?->count() ?? 0), 'receipt_date' => $doc->received_date?->format('Y-m-d') ?? '', 'inspection_request_date' => $inspection['request_date'] ?? '',