feat: [품질검사] 수주 선택 필터링 + 개소 상세 + 검사 상태 개선
- availableOrders: client_id/item_id 필터 파라미터 지원 - availableOrders: 응답에 client_id, client_name, item_id, item_name, locations(개소 상세) 추가 - show: 개소별 데이터에 거래처/모델 정보 포함 - DocumentService: fqcStatus rootNodes 기반으로 변경 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# 논리적 데이터베이스 관계 문서
|
||||
|
||||
> **자동 생성**: 2026-03-06 15:12:45
|
||||
> **자동 생성**: 2026-03-06 21:25:05
|
||||
> **소스**: Eloquent 모델 관계 분석
|
||||
|
||||
## 📊 모델별 관계 현황
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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'] ?? '',
|
||||
|
||||
Reference in New Issue
Block a user