From 286201560523883250d058a0868ad17fd6e9f123 Mon Sep 17 00:00:00 2001 From: hskwon Date: Mon, 15 Dec 2025 19:27:36 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20Items=20show()=20API=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20-=20files=20=EB=A1=9C=EB=94=A9=20=EB=B0=8F=20item?= =?UTF-8?q?=5Ftype=20=EC=84=A0=ED=83=9D=EC=A0=81=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Item 모델 files() 관계를 document_id/document_type 기반으로 변경 - show() 메서드에 files 로딩 및 field_key별 그룹화 추가 - item_type 파라미터 선택적 처리 (ID만으로 조회 가능) - showWithPrice() 메서드 반환 타입 변경에 맞게 수정 --- .../Controllers/Api/V1/ItemsController.php | 7 +-- app/Models/Items/Item.php | 10 ++-- app/Services/ItemService.php | 50 ++++++++++++++++--- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/app/Http/Controllers/Api/V1/ItemsController.php b/app/Http/Controllers/Api/V1/ItemsController.php index 0944471..aea6c78 100644 --- a/app/Http/Controllers/Api/V1/ItemsController.php +++ b/app/Http/Controllers/Api/V1/ItemsController.php @@ -40,13 +40,14 @@ public function index(Request $request) * * GET /api/v1/items/{id}?item_type=FG&include_price=true&client_id=1&price_date=2025-01-10 * - * @param string item_type 품목 유형 (필수 - 동적 테이블 라우팅) + * @param string|null item_type 품목 유형 (선택적 - 없으면 ID만으로 조회) */ public function show(Request $request, int $id) { return ApiResponse::handle(function () use ($request, $id) { - // item_type 필수 (동적 테이블 라우팅에 사용) - $itemType = strtoupper($request->input('item_type', '')); + // item_type 선택적 (없으면 ID만으로 items 테이블에서 조회) + $itemType = $request->input('item_type'); + $itemType = $itemType ? strtoupper($itemType) : null; $includePrice = filter_var($request->input('include_price', false), FILTER_VALIDATE_BOOLEAN); if ($includePrice) { diff --git a/app/Models/Items/Item.php b/app/Models/Items/Item.php index 8a25c58..9ffe1ce 100644 --- a/app/Models/Items/Item.php +++ b/app/Models/Items/Item.php @@ -104,11 +104,15 @@ public function bomChildren() } /** - * 파일 (폴리모픽) + * 파일 (document_id/document_type 기반) + * + * ItemsFileController가 document_id=item_id, document_type='1'(group_id)로 저장 + * morphMany(fileable) 대신 hasMany + where 조건 사용 */ public function files() { - return $this->morphMany(File::class, 'fileable'); + return $this->hasMany(File::class, 'document_id') + ->where('document_type', '1'); // ITEM_GROUP_ID } /** @@ -200,4 +204,4 @@ public function loadBomChildren(): self return $this; } -} \ No newline at end of file +} diff --git a/app/Services/ItemService.php b/app/Services/ItemService.php index 73ab8cc..c0e5410 100644 --- a/app/Services/ItemService.php +++ b/app/Services/ItemService.php @@ -5,6 +5,7 @@ use App\Models\Commons\Category; use App\Models\ItemMaster\ItemField; use App\Models\ItemMaster\ItemPage; +use App\Models\Items\Item; use App\Models\Items\ItemDetail; use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Model; @@ -433,17 +434,30 @@ public function store(array $data): Model * 단건 조회 (동적 테이블 라우팅) * * @param int $id 품목 ID - * @param string $itemType 품목 유형 (필수) + * @param string|null $itemType 품목 유형 (선택적 - 없으면 ID로만 조회) + * @return array 품목 데이터 (files 그룹화 포함) */ - public function show(int $id, string $itemType): Model + public function show(int $id, ?string $itemType = null): array { + // item_type이 없으면 items 테이블에서 직접 조회 + if (! $itemType) { + $item = Item::with(['category:id,name', 'details', 'files']) + ->find($id); + + if (! $item) { + throw new BadRequestHttpException(__('error.not_found')); + } + + return $this->formatItemResponse($item); + } + // 동적 테이블 라우팅 $modelInfo = $this->getModelInfoByItemType($itemType); $query = $this->newQuery($itemType); // items 테이블인 경우 관계 로드 if ($modelInfo['source_table'] === 'items') { - $query->with(['category:id,name', 'details']); + $query->with(['category:id,name', 'details', 'files']); } $item = $query->find($id); @@ -452,7 +466,25 @@ public function show(int $id, string $itemType): Model throw new BadRequestHttpException(__('error.not_found')); } - return $item; + return $this->formatItemResponse($item); + } + + /** + * 품목 응답 포맷 (files 그룹화 포함) + */ + private function formatItemResponse(Model $item): array + { + $arr = $item->toArray(); + + // 날짜 포맷 + $arr['created_at'] = $item->created_at + ? $item->created_at->format('Y-m-d') + : null; + + // files를 field_key별로 그룹화 + $arr['files'] = $this->groupFilesByFieldKey($arr['files'] ?? []); + + return $arr; } /** @@ -706,15 +738,17 @@ public function batchDestroy(array $ids, string $itemType): int * @param int|null $clientId 거래처 ID * @param string|null $priceDate 가격 기준일 */ - public function showWithPrice(int $id, string $itemType, ?int $clientId = null, ?string $priceDate = null): array + public function showWithPrice(int $id, ?string $itemType = null, ?int $clientId = null, ?string $priceDate = null): array { - $item = $this->show($id, $itemType); - $data = $item->toArray(); + // show()가 이제 array를 반환 + $data = $this->show($id, $itemType); // PricingService로 가격 조회 try { $pricingService = app(\App\Services\Pricing\PricingService::class); - $itemTypeCode = in_array(strtoupper($itemType), ['FG', 'PT']) ? 'PRODUCT' : 'MATERIAL'; + // item_type에서 가격 유형 결정 (데이터에서 추출) + $actualItemType = $data['item_type'] ?? $itemType ?? 'FG'; + $itemTypeCode = in_array(strtoupper($actualItemType), ['FG', 'PT']) ? 'PRODUCT' : 'MATERIAL'; $data['prices'] = [ 'sale' => $pricingService->getPriceByType($itemTypeCode, $id, 'SALE', $clientId, $priceDate),