feat: [품질관리] order_ids 영속성 + location 데이터 저장
- StoreRequest/UpdateRequest에 order_ids 검증 추가 - UpdateRequest에 locations 검증 추가 (시공규격, 변경사유, 검사데이터) - QualityDocumentLocation에 inspection_data(JSON) fillable/cast 추가 - QualityDocumentService store()에 syncOrders 연동 - QualityDocumentService update()에 syncOrders + updateLocations 연동 - inspection_data 컬럼 추가 migration 신규 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
use App\Models\Orders\Order;
|
||||
use App\Models\Orders\OrderItem;
|
||||
use App\Models\Orders\OrderNode;
|
||||
use App\Models\Qualitys\PerformanceReport;
|
||||
use App\Models\Qualitys\QualityDocument;
|
||||
use App\Models\Qualitys\QualityDocumentLocation;
|
||||
@@ -178,6 +179,10 @@ public function store(array $data)
|
||||
$userId = $this->apiUserId();
|
||||
|
||||
return DB::transaction(function () use ($data, $tenantId, $userId) {
|
||||
// order_ids는 별도 처리 후 $data에서 제거
|
||||
$orderIds = $data['order_ids'] ?? null;
|
||||
unset($data['order_ids']);
|
||||
|
||||
$data['tenant_id'] = $tenantId;
|
||||
$data['quality_doc_number'] = QualityDocument::generateDocNumber($tenantId);
|
||||
$data['status'] = QualityDocument::STATUS_RECEIVED;
|
||||
@@ -185,6 +190,11 @@ public function store(array $data)
|
||||
|
||||
$doc = QualityDocument::create($data);
|
||||
|
||||
// 수주 연결
|
||||
if (! empty($orderIds)) {
|
||||
$this->syncOrders($doc, $orderIds, $tenantId);
|
||||
}
|
||||
|
||||
$this->auditLogger->log(
|
||||
$tenantId,
|
||||
self::AUDIT_TARGET,
|
||||
@@ -194,7 +204,7 @@ public function store(array $data)
|
||||
$doc->toArray()
|
||||
);
|
||||
|
||||
return $this->transformToFrontend($doc->load(['client', 'inspector:id,name', 'creator:id,name']));
|
||||
return $this->transformToFrontend($doc->load(['client', 'inspector:id,name', 'creator:id,name', 'documentOrders.order', 'locations.orderItem.node']));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -213,7 +223,12 @@ public function update(int $id, array $data)
|
||||
|
||||
$beforeData = $doc->toArray();
|
||||
|
||||
return DB::transaction(function () use ($doc, $data, $userId, $beforeData) {
|
||||
return DB::transaction(function () use ($doc, $data, $userId, $beforeData, $tenantId) {
|
||||
// order_ids, locations는 별도 처리 후 $data에서 제거
|
||||
$orderIds = $data['order_ids'] ?? null;
|
||||
$locations = $data['locations'] ?? null;
|
||||
unset($data['order_ids'], $data['locations']);
|
||||
|
||||
$data['updated_by'] = $userId;
|
||||
|
||||
// options는 기존 값과 병합
|
||||
@@ -224,6 +239,16 @@ public function update(int $id, array $data)
|
||||
|
||||
$doc->update($data);
|
||||
|
||||
// 수주 동기화 (order_ids가 전달된 경우만)
|
||||
if ($orderIds !== null) {
|
||||
$this->syncOrders($doc, $orderIds, $tenantId);
|
||||
}
|
||||
|
||||
// 개소별 데이터 업데이트 (시공규격, 변경사유, 검사데이터)
|
||||
if (! empty($locations)) {
|
||||
$this->updateLocations($doc->id, $locations);
|
||||
}
|
||||
|
||||
$this->auditLogger->log(
|
||||
$doc->tenant_id,
|
||||
self::AUDIT_TARGET,
|
||||
@@ -233,7 +258,7 @@ public function update(int $id, array $data)
|
||||
$doc->fresh()->toArray()
|
||||
);
|
||||
|
||||
return $this->transformToFrontend($doc->load(['client', 'inspector:id,name', 'creator:id,name', 'documentOrders.order', 'locations']));
|
||||
return $this->transformToFrontend($doc->load(['client', 'inspector:id,name', 'creator:id,name', 'documentOrders.order', 'locations.orderItem.node']));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -372,6 +397,101 @@ public function availableOrders(array $params): array
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 개소별 데이터 업데이트
|
||||
*/
|
||||
private function updateLocations(int $docId, array $locations): void
|
||||
{
|
||||
foreach ($locations as $locData) {
|
||||
$locId = $locData['id'] ?? null;
|
||||
if (! $locId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$location = QualityDocumentLocation::where('quality_document_id', $docId)->find($locId);
|
||||
if (! $location) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$updateData = [];
|
||||
if (array_key_exists('post_width', $locData)) {
|
||||
$updateData['post_width'] = $locData['post_width'];
|
||||
}
|
||||
if (array_key_exists('post_height', $locData)) {
|
||||
$updateData['post_height'] = $locData['post_height'];
|
||||
}
|
||||
if (array_key_exists('change_reason', $locData)) {
|
||||
$updateData['change_reason'] = $locData['change_reason'];
|
||||
}
|
||||
if (array_key_exists('inspection_data', $locData)) {
|
||||
$updateData['inspection_data'] = $locData['inspection_data'];
|
||||
}
|
||||
|
||||
if (! empty($updateData)) {
|
||||
$location->update($updateData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 수주 동기화 (update 시 사용)
|
||||
*/
|
||||
private function syncOrders(QualityDocument $doc, array $orderIds, int $tenantId): void
|
||||
{
|
||||
$existingOrderIds = QualityDocumentOrder::where('quality_document_id', $doc->id)
|
||||
->pluck('order_id')
|
||||
->toArray();
|
||||
|
||||
$toAttach = array_diff($orderIds, $existingOrderIds);
|
||||
$toDetach = array_diff($existingOrderIds, $orderIds);
|
||||
|
||||
// 새로 연결
|
||||
foreach ($toAttach as $orderId) {
|
||||
$order = Order::where('tenant_id', $tenantId)->find($orderId);
|
||||
if (! $order) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$docOrder = QualityDocumentOrder::firstOrCreate([
|
||||
'quality_document_id' => $doc->id,
|
||||
'order_id' => $orderId,
|
||||
]);
|
||||
|
||||
// 개소(root OrderNode) 기준으로 location 생성
|
||||
$rootNodes = OrderNode::where('order_id', $orderId)
|
||||
->whereNull('parent_id')
|
||||
->orderBy('sort_order')
|
||||
->get();
|
||||
|
||||
foreach ($rootNodes as $node) {
|
||||
// 각 개소의 대표 OrderItem (해당 노드 하위 첫 번째 품목)
|
||||
$representativeItem = OrderItem::where('order_node_id', $node->id)
|
||||
->orderBy('sort_order')
|
||||
->first();
|
||||
|
||||
if ($representativeItem) {
|
||||
QualityDocumentLocation::firstOrCreate([
|
||||
'quality_document_id' => $doc->id,
|
||||
'quality_document_order_id' => $docOrder->id,
|
||||
'order_item_id' => $representativeItem->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 연결 해제
|
||||
foreach ($toDetach as $orderId) {
|
||||
$docOrder = QualityDocumentOrder::where('quality_document_id', $doc->id)
|
||||
->where('order_id', $orderId)
|
||||
->first();
|
||||
|
||||
if ($docOrder) {
|
||||
QualityDocumentLocation::where('quality_document_order_id', $docOrder->id)->delete();
|
||||
$docOrder->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 수주 연결
|
||||
*/
|
||||
@@ -397,14 +517,24 @@ public function attachOrders(int $docId, array $orderIds)
|
||||
'order_id' => $orderId,
|
||||
]);
|
||||
|
||||
// 수주 연결 시 개소(order_items)를 locations에 자동 생성
|
||||
$orderItems = OrderItem::where('order_id', $orderId)->get();
|
||||
foreach ($orderItems as $item) {
|
||||
QualityDocumentLocation::firstOrCreate([
|
||||
'quality_document_id' => $doc->id,
|
||||
'quality_document_order_id' => $docOrder->id,
|
||||
'order_item_id' => $item->id,
|
||||
]);
|
||||
// 수주 연결 시 개소(root OrderNode)를 locations에 자동 생성
|
||||
$rootNodes = OrderNode::where('order_id', $orderId)
|
||||
->whereNull('parent_id')
|
||||
->orderBy('sort_order')
|
||||
->get();
|
||||
|
||||
foreach ($rootNodes as $node) {
|
||||
$representativeItem = OrderItem::where('order_node_id', $node->id)
|
||||
->orderBy('sort_order')
|
||||
->first();
|
||||
|
||||
if ($representativeItem) {
|
||||
QualityDocumentLocation::firstOrCreate([
|
||||
'quality_document_id' => $doc->id,
|
||||
'quality_document_order_id' => $docOrder->id,
|
||||
'order_item_id' => $representativeItem->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,7 +665,7 @@ private function transformToFrontend(QualityDocument $doc, bool $detail = false)
|
||||
'site_address_detail' => $options['site_address']['detail'] ?? '',
|
||||
];
|
||||
|
||||
// 개소 목록
|
||||
// 개소 목록 (각 location은 1개 root OrderNode = 1개 개소)
|
||||
$result['order_items'] = $doc->locations->map(function ($loc) {
|
||||
$orderItem = $loc->orderItem;
|
||||
$node = $orderItem?->node;
|
||||
@@ -544,9 +674,10 @@ private function transformToFrontend(QualityDocument $doc, bool $detail = false)
|
||||
|
||||
return [
|
||||
'id' => (string) $loc->id,
|
||||
'order_id' => $order?->id,
|
||||
'order_number' => $order?->order_no ?? '',
|
||||
'site_name' => $order?->site_name ?? '',
|
||||
'delivery_date' => $order?->delivery_date ?? '',
|
||||
'delivery_date' => $order?->delivery_date ? $order->delivery_date->format('Y-m-d') : '',
|
||||
'floor' => $orderItem?->floor_code ?? '',
|
||||
'symbol' => $orderItem?->symbol_code ?? '',
|
||||
'order_width' => $nodeOptions['width'] ?? 0,
|
||||
@@ -554,6 +685,7 @@ private function transformToFrontend(QualityDocument $doc, bool $detail = false)
|
||||
'construction_width' => $loc->post_width ?? 0,
|
||||
'construction_height' => $loc->post_height ?? 0,
|
||||
'change_reason' => $loc->change_reason ?? '',
|
||||
'inspection_data' => $loc->inspection_data,
|
||||
];
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user