diff --git a/app/Services/QmsLotAuditService.php b/app/Services/QmsLotAuditService.php index 511ebf95..8e07a4a2 100644 --- a/app/Services/QmsLotAuditService.php +++ b/app/Services/QmsLotAuditService.php @@ -27,15 +27,13 @@ public function index(array $params): array 'documentOrders.locations', 'performanceReport', ]) - ->where('status', QualityDocument::STATUS_COMPLETED); + ->where('status', QualityDocument::STATUS_COMPLETED) + ->whereHas('performanceReport', fn ($pr) => $pr->where('confirmation_status', '!=', 'unconfirmed')); // 연도 필터 if (! empty($params['year'])) { $year = (int) $params['year']; - $query->where(function ($q) use ($year) { - $q->whereHas('performanceReport', fn ($pr) => $pr->where('year', $year)) - ->orWhereDoesntHave('performanceReport'); - }); + $query->whereHas('performanceReport', fn ($pr) => $pr->where('year', $year)); } // 분기 필터 @@ -246,8 +244,17 @@ private function transformReportToFrontend(QualityDocument $doc): array private function getFgProductName(QualityDocument $doc): string { $order = $doc->documentOrders->first()?->order; + if (! $order) { + return ''; + } - return $order?->item?->name ?? ''; + // 1차: Order.item 릴레이션 + if ($order->item?->name) { + return $order->item->name; + } + + // 2차: Order.items (order_items 테이블)의 첫 번째 품목명 + return $order->items->first()?->item_name ?? ''; } private function transformRouteToFrontend(QualityDocumentOrder $docOrder, QualityDocument $qualityDoc): array @@ -400,7 +407,7 @@ private function mapProcessToSubType(?string $processName): ?string str_contains($name, 'bending') || str_contains($name, '절곡') => 'bending', str_contains($name, 'slat') || str_contains($name, '슬랫') => 'slat', str_contains($name, 'jointbar') || str_contains($name, '조인트바') || str_contains($name, 'joint') => 'jointbar', - default => null, + default => mb_strtolower(trim($processName)), }; } @@ -489,7 +496,7 @@ private function getOrderDetail(int $id): array $motorRight = []; foreach ($motorItems->groupBy('item_name') as $name => $group) { $item = $group->first(); - $totalQty = $group->sum('quantity'); + $totalQty = (int) $group->sum('quantity'); $row = [ 'item' => $item['item_name'], 'type' => $item['specification'] ?? '-', @@ -506,7 +513,8 @@ private function getOrderDetail(int $id): array // 절곡물 (category: steel) $steelItems = $allBomItems->filter(fn ($i) => ($i['item_category'] ?? '') === 'steel'); - $bendingParts = $this->groupBendingParts($steelItems); + $shutterCount = $rootNodes->count(); + $bendingParts = $this->groupBendingParts($steelItems, $shutterCount); // 부자재 (category: parts) $partItems = $allBomItems->filter(fn ($i) => ($i['item_category'] ?? '') === 'parts'); @@ -516,7 +524,7 @@ private function getOrderDetail(int $id): array $subsidiaryParts[] = [ 'name' => $item['item_name'], 'spec' => $item['specification'] ?? '-', - 'qty' => $group->sum('quantity'), + 'qty' => (int) $group->sum('quantity'), ]; } @@ -558,8 +566,12 @@ private function getOrderDetail(int $id): array /** * 절곡물 BOM items를 그룹별로 분류 + * 문서 표시용: 길이 기반 BOM 수량 → 개수(EA) 기반으로 변환 + * - 가이드레일: 2 × 셔터수량 (좌/우) + * - 케이스: 셔터수량 + * - 마구리(측면부): 2 × 셔터수량 (좌/우) */ - private function groupBendingParts($steelItems): array + private function groupBendingParts($steelItems, int $shutterCount = 0): array { $groups = [ '가이드레일' => [], @@ -572,17 +584,30 @@ private function groupBendingParts($steelItems): array foreach ($steelItems->groupBy('item_name') as $name => $group) { $item = $group->first(); $totalQty = $group->sum('quantity'); + + // 개수(EA) 기반 수량 결정 + $isMaguri = str_contains($name, '마구리') || str_contains($name, '측면'); + $isGuideRail = str_contains($name, '가이드레일'); + $isCase = str_contains($name, '케이스') && ! $isMaguri; + + if ($shutterCount > 0 && ($isGuideRail || $isCase || $isMaguri)) { + // 가이드레일, 마구리: 2 × 셔터수량 / 케이스: 셔터수량 + $qty = ($isGuideRail || $isMaguri) ? 2 * $shutterCount : $shutterCount; + } else { + $qty = $totalQty; + } + $row = [ 'name' => $item['item_name'], 'spec' => $item['specification'] ?? '-', - 'qty' => $totalQty, + 'qty' => (int) $qty, ]; if (str_contains($name, '연기차단재')) { $groups['연기차단재'][] = $row; - } elseif (str_contains($name, '가이드레일')) { + } elseif ($isGuideRail) { $groups['가이드레일'][] = $row; - } elseif (str_contains($name, '케이스') || str_contains($name, '마구리')) { + } elseif ($isCase || $isMaguri) { $groups['케이스'][] = $row; } elseif (str_contains($name, '하장바') || str_contains($name, 'L-BAR') || str_contains($name, '보강평철')) { $groups['하단마감'][] = $row; diff --git a/app/Services/QualityDocumentService.php b/app/Services/QualityDocumentService.php index e67a9ff1..3f76382d 100644 --- a/app/Services/QualityDocumentService.php +++ b/app/Services/QualityDocumentService.php @@ -192,6 +192,7 @@ public function store(array $data) $data['tenant_id'] = $tenantId; $data['quality_doc_number'] = QualityDocument::generateDocNumber($tenantId); $data['status'] = QualityDocument::STATUS_RECEIVED; + $data['received_date'] = $data['received_date'] ?? now()->toDateString(); $data['created_by'] = $userId; $doc = QualityDocument::create($data);