feat:품목 검색 API에 수입검사 양식 연결 필드 추가

- has_inspection_template 필드 추가 (수입검사 양식 연결 여부)
- getItemsWithInspectionTemplate() 헬퍼 메서드 추가
- name 필드에 코드 합치기 제거 (중복 표시 해결)
- exclude_process_id 파라미터 추가 (공정별 품목 선택 시 중복 방지)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-05 21:58:00 +09:00
parent 70aab06364
commit 9f2b1cf44a

View File

@@ -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)));
}
/**
* 품목 통계 조회
*