diff --git a/app/Services/ItemService.php b/app/Services/ItemService.php index 9ab0168..1467dcf 100644 --- a/app/Services/ItemService.php +++ b/app/Services/ItemService.php @@ -7,6 +7,7 @@ use App\Models\ItemMaster\ItemPage; use App\Models\Items\Item; use App\Models\Items\ItemDetail; +use App\Models\ProcessItem; use App\Models\Products\CommonCode; use App\Models\Scopes\TenantScope; use Illuminate\Contracts\Pagination\LengthAwarePaginator; @@ -347,6 +348,7 @@ protected function fetchCategoryTree(?int $parentId = null) * 목록/검색 (동적 테이블 라우팅) * * @param array $params 검색 파라미터 (item_type/group_id 없으면 group_id=1 기본값) + * - exclude_process_id: 해당 공정 외 다른 공정에 이미 배정된 품목 제외 */ public function index(array $params): LengthAwarePaginator { @@ -358,6 +360,7 @@ public function index(array $params): LengthAwarePaginator $groupId = $params['group_id'] ?? null; $active = $params['active'] ?? null; $hasBom = $params['has_bom'] ?? null; + $excludeProcessId = $params['exclude_process_id'] ?? null; // item_type 또는 group_id 없으면 group_id = 1 기본값 적용 if (! $itemType && ! $groupId) { @@ -427,6 +430,21 @@ public function index(array $params): LengthAwarePaginator } } + // 다른 공정에 배정된 품목 제외 (공정별 품목 선택 시 중복 방지) + // exclude_process_id가 주어지면: 해당 공정에 이미 있는 품목은 허용, 다른 공정 품목은 제외 + if ($excludeProcessId !== null && $excludeProcessId !== '') { + $excludeProcessId = (int) $excludeProcessId; + // 다른 공정에 배정된 품목 ID 목록 조회 + $assignedToOtherProcesses = ProcessItem::where('process_id', '!=', $excludeProcessId) + ->where('is_active', true) + ->pluck('item_id') + ->toArray(); + + if (! empty($assignedToOtherProcesses)) { + $query->whereNotIn('id', $assignedToOtherProcesses); + } + } + // common_codes에서 item_type 한글명 조회 (서브쿼리로 컬럼 충돌 방지) $tableName = $query->getModel()->getTable(); $query->addSelect([ @@ -440,9 +458,13 @@ public function index(array $params): LengthAwarePaginator $paginator = $query->orderBy("{$tableName}.id", 'desc')->paginate($size); + // 수입검사 양식에 연결된 품목 ID 조회 (incoming_inspection 카테고리) + $itemIds = $paginator->pluck('id')->toArray(); + $itemsWithInspection = $this->getItemsWithInspectionTemplate($itemIds); + // 날짜 형식 변환, files 그룹화, options 펼침, code → item_code $paginator->setCollection( - $paginator->getCollection()->transform(function ($item) { + $paginator->getCollection()->transform(function ($item) use ($itemsWithInspection) { $arr = $item->toArray(); $arr['created_at'] = $item->created_at ? $item->created_at->format('Y-m-d') @@ -463,8 +485,8 @@ public function index(array $params): LengthAwarePaginator // has_bom 계산 필드 추가 (BOM이 있는 품목 필터링에 사용) $arr['has_bom'] = ! empty($arr['bom']) && is_array($arr['bom']) && count($arr['bom']) > 0; - // name 필드를 "코드 이름" 형식으로 변경 (일시적) - $arr['name'] = trim(($arr['item_code'] ?? '').' '.($arr['name'] ?? '')); + // has_inspection_template 필드 추가 (수입검사 양식 연결 여부) + $arr['has_inspection_template'] = in_array($arr['id'], $itemsWithInspection); return $arr; }) @@ -993,6 +1015,39 @@ private function groupFilesByFieldKey(array $files): array return $grouped; } + /** + * 수입검사 양식에 연결된 품목 ID 목록 조회 + * + * @param array $itemIds 조회할 품목 ID 배열 + * @return array 수입검사 양식에 연결된 품목 ID 배열 + */ + private function getItemsWithInspectionTemplate(array $itemIds): array + { + if (empty($itemIds)) { + return []; + } + + $tenantId = $this->tenantId(); + + // document_templates에서 category='incoming_inspection'이고 + // linked_item_ids JSON 배열에 품목 ID가 포함된 템플릿 조회 + $templates = \DB::table('document_templates') + ->where('tenant_id', $tenantId) + ->where('category', 'incoming_inspection') + ->where('is_active', true) + ->whereNotNull('linked_item_ids') + ->get(['linked_item_ids']); + + $linkedItemIds = []; + foreach ($templates as $template) { + $ids = json_decode($template->linked_item_ids, true) ?? []; + $linkedItemIds = array_merge($linkedItemIds, $ids); + } + + // 요청된 품목 ID와 연결된 품목 ID의 교집합 + return array_values(array_intersect($itemIds, array_unique($linkedItemIds))); + } + /** * 품목 통계 조회 *