From 7967082f8bb0cca7f9ffce7c362027a612052c22 Mon Sep 17 00:00:00 2001 From: hskwon Date: Thu, 4 Dec 2025 13:45:41 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20BOM=20API=20ref=5Fid=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=20=EB=B0=8F=20=EC=9D=91=EB=8B=B5=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - child_product_id, material_id를 ref_id 단일 컬럼으로 통합 - splitRef() 메서드 제거 - bulkUpsert() 응답에 created_ids, updated_ids 추가 --- app/Services/ProductBomService.php | 59 ++++++++++++------------------ 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/app/Services/ProductBomService.php b/app/Services/ProductBomService.php index 954f88f..3560ede 100644 --- a/app/Services/ProductBomService.php +++ b/app/Services/ProductBomService.php @@ -36,9 +36,9 @@ public function index(int $parentProductId, array $params) ->orderBy('sort_order') ->get(); - // 리졸브(제품/자재) - $productIds = $items->where('ref_type', 'PRODUCT')->pluck('child_product_id')->filter()->unique()->values(); - $materialIds = $items->where('ref_type', 'MATERIAL')->pluck('material_id')->filter()->unique()->values(); + // 리졸브(제품/자재) - ref_id 기준 + $productIds = $items->where('ref_type', 'PRODUCT')->pluck('ref_id')->filter()->unique()->values(); + $materialIds = $items->where('ref_type', 'MATERIAL')->pluck('ref_id')->filter()->unique()->values(); $products = $productIds->isNotEmpty() ? Product::query()->where('tenant_id', $tenantId)->whereIn('id', $productIds)->get(['id', 'code', 'name', 'product_type', 'category_id'])->keyBy('id') @@ -52,26 +52,25 @@ public function index(int $parentProductId, array $params) $base = [ 'id' => (int) $row->id, 'ref_type' => $row->ref_type, + 'ref_id' => (int) $row->ref_id, 'quantity' => $row->quantity, 'sort_order' => (int) $row->sort_order, 'is_default' => (int) $row->is_default, ]; if ($row->ref_type === 'PRODUCT') { - $p = $products->get($row->child_product_id); + $p = $products->get($row->ref_id); return $base + [ - 'ref_id' => (int) $row->child_product_id, 'code' => $p?->code, 'name' => $p?->name, 'product_type' => $p?->product_type, 'category_id' => $p?->category_id, ]; } else { // MATERIAL - $m = $materials->get($row->material_id); + $m = $materials->get($row->ref_id); return $base + [ - 'ref_id' => (int) $row->material_id, 'code' => $m?->code, 'name' => $m?->name, 'unit' => $m?->unit, @@ -98,8 +97,10 @@ public function bulkUpsert(int $parentProductId, array $items): array $created = 0; $updated = 0; + $createdIds = []; + $updatedIds = []; - DB::transaction(function () use ($tenantId, $userId, $parentProductId, $items, &$created, &$updated) { + DB::transaction(function () use ($tenantId, $userId, $parentProductId, $items, &$created, &$updated, &$createdIds, &$updatedIds) { foreach ($items as $it) { $payload = $this->validateItem($it); @@ -115,40 +116,40 @@ public function bulkUpsert(int $parentProductId, array $items): array throw new BadRequestHttpException(__('error.not_found')); } - // ref 변경 허용 시: 충돌 검사 - [$childProductId, $materialId] = $this->splitRef($payload); - $pc->update([ 'ref_type' => $payload['ref_type'], - 'child_product_id' => $childProductId, - 'material_id' => $materialId, + 'ref_id' => (int) $payload['ref_id'], 'quantity' => $payload['quantity'], 'sort_order' => $payload['sort_order'] ?? $pc->sort_order, 'is_default' => $payload['is_default'] ?? $pc->is_default, 'updated_by' => $userId, ]); $updated++; + $updatedIds[] = $pc->id; } else { // 신규 - [$childProductId, $materialId] = $this->splitRef($payload); - - ProductComponent::create([ + $pc = ProductComponent::create([ 'tenant_id' => $tenantId, 'parent_product_id' => $parentProductId, 'ref_type' => $payload['ref_type'], - 'child_product_id' => $childProductId, - 'material_id' => $materialId, + 'ref_id' => (int) $payload['ref_id'], 'quantity' => $payload['quantity'], 'sort_order' => $payload['sort_order'] ?? 0, 'is_default' => $payload['is_default'] ?? 0, 'created_by' => $userId, ]); $created++; + $createdIds[] = $pc->id; } } }); - return compact('created', 'updated'); + return [ + 'created' => $created, + 'updated' => $updated, + 'created_ids' => $createdIds, + 'updated_ids' => $updatedIds, + ]; } // 단건 수정 @@ -180,14 +181,12 @@ public function update(int $parentProductId, int $itemId, array $data) $refType = $payload['ref_type'] ?? $pc->ref_type; $refId = isset($payload['ref_id']) ? (int) $payload['ref_id'] - : ($pc->ref_type === 'PRODUCT' ? (int) $pc->child_product_id : (int) $pc->material_id); + : (int) $pc->ref_id; $this->assertReference($tenantId, $parentProductId, $refType, $refId); - [$childProductId, $materialId] = $this->splitRef(['ref_type' => $refType, 'ref_id' => $refId]); $pc->ref_type = $refType; - $pc->child_product_id = $childProductId; - $pc->material_id = $materialId; + $pc->ref_id = $refId; } if (isset($payload['quantity'])) { @@ -290,14 +289,14 @@ public function validateBom(int $parentProductId): array if ($row->quantity <= 0) { $errors[] = ['id' => $row->id, 'error' => 'INVALID_QUANTITY']; } - $key = $row->ref_type.':'.($row->ref_type === 'PRODUCT' ? $row->child_product_id : $row->material_id); + $key = $row->ref_type.':'.$row->ref_id; if (isset($seen[$key])) { $errors[] = ['id' => $row->id, 'error' => 'DUPLICATE_ITEM']; } else { $seen[$key] = true; } // 자기참조 - if ($row->ref_type === 'PRODUCT' && (int) $row->child_product_id === (int) $parentProductId) { + if ($row->ref_type === 'PRODUCT' && (int) $row->ref_id === (int) $parentProductId) { $errors[] = ['id' => $row->id, 'error' => 'SELF_REFERENCE']; } } @@ -324,16 +323,6 @@ private function validateItem(array $it): array return $v->validate(); } - private function splitRef(array $payload): array - { - // returns [child_product_id, material_id] - if ($payload['ref_type'] === 'PRODUCT') { - return [(int) $payload['ref_id'], null]; - } - - return [null, (int) $payload['ref_id']]; - } - private function assertProduct(int $tenantId, int $productId): void { $exists = Product::query()->where('tenant_id', $tenantId)->where('id', $productId)->exists();