getProductIdByCode($code); return $this->service->index($productId, $request->all()); }, __('message.bom.fetch')); } /** * GET /api/v1/items/{code}/bom/tree * BOM 트리 구조 조회 (계층적) */ public function tree(string $code, Request $request) { return ApiResponse::handle(function () use ($code, $request) { $productId = $this->getProductIdByCode($code); return $this->service->tree($request, $productId); }, __('message.bom.fetch')); } /** * POST /api/v1/items/{code}/bom * BOM 라인 추가 (bulk upsert) */ public function store(string $code, Request $request) { return ApiResponse::handle(function () use ($code, $request) { $productId = $this->getProductIdByCode($code); return $this->service->bulkUpsert($productId, $request->input('items', [])); }, __('message.bom.created')); } /** * PUT /api/v1/items/{code}/bom/{lineId} * BOM 라인 수정 */ public function update(string $code, int $lineId, Request $request) { return ApiResponse::handle(function () use ($code, $lineId, $request) { $productId = $this->getProductIdByCode($code); return $this->service->update($productId, $lineId, $request->all()); }, __('message.bom.updated')); } /** * DELETE /api/v1/items/{code}/bom/{lineId} * BOM 라인 삭제 */ public function destroy(string $code, int $lineId) { return ApiResponse::handle(function () use ($code, $lineId) { $productId = $this->getProductIdByCode($code); $this->service->destroy($productId, $lineId); return 'success'; }, __('message.bom.deleted')); } /** * GET /api/v1/items/{code}/bom/summary * BOM 요약 정보 */ public function summary(string $code) { return ApiResponse::handle(function () use ($code) { $productId = $this->getProductIdByCode($code); return $this->service->summary($productId); }, __('message.bom.fetch')); } /** * GET /api/v1/items/{code}/bom/validate * BOM 유효성 검사 */ public function validate(string $code) { return ApiResponse::handle(function () use ($code) { $productId = $this->getProductIdByCode($code); return $this->service->validateBom($productId); }, __('message.bom.fetch')); } /** * POST /api/v1/items/{code}/bom/replace * BOM 전체 교체 */ public function replace(string $code, Request $request) { return ApiResponse::handle(function () use ($code, $request) { $productId = $this->getProductIdByCode($code); return $this->service->replaceBom($productId, $request->all()); }, __('message.bom.created')); } /** * POST /api/v1/items/{code}/bom/reorder * BOM 정렬 변경 */ public function reorder(string $code, Request $request) { return ApiResponse::handle(function () use ($code, $request) { $productId = $this->getProductIdByCode($code); $this->service->reorder($productId, $request->input('items', [])); return 'success'; }, __('message.bom.reordered')); } /** * GET /api/v1/items/{code}/bom/categories * 해당 품목의 BOM에서 사용 중인 카테고리 목록 */ public function listCategories(string $code) { return ApiResponse::handle(function () use ($code) { $productId = $this->getProductIdByCode($code); return $this->service->listCategoriesForProduct($productId); }, __('message.bom.fetch')); } // ==================== Helper Methods ==================== /** * itemCode로 product ID 조회 * * @throws NotFoundHttpException */ private function getProductIdByCode(string $code): int { $tenantId = app('tenant_id'); $product = Product::query() ->where('tenant_id', $tenantId) ->where('code', $code) ->first(['id']); if (! $product) { throw new NotFoundHttpException(__('error.not_found')); } return $product->id; } }