summaryrefslogtreecommitdiff
path: root/lib/avl/service.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/avl/service.ts')
-rw-r--r--lib/avl/service.ts167
1 files changed, 144 insertions, 23 deletions
diff --git a/lib/avl/service.ts b/lib/avl/service.ts
index 1f781486..5d7c2418 100644
--- a/lib/avl/service.ts
+++ b/lib/avl/service.ts
@@ -941,9 +941,71 @@ export async function deleteAvlVendorInfo(id: number): Promise<boolean> {
}
/**
+ * 프로젝트 AVL 벤더 정보 건수 조회
+ */
+export async function getProjectAvlVendorInfoCount(
+ projectCode: string,
+ htDivision?: string
+): Promise<number> {
+ try {
+ const conditions = [
+ eq(avlVendorInfo.projectCode, projectCode),
+ eq(avlVendorInfo.isTemplate, false)
+ ];
+
+ // H/T 구분이 있으면 조건에 추가
+ if (htDivision) {
+ conditions.push(eq(avlVendorInfo.htDivision, htDivision));
+ }
+
+ const result = await db
+ .select({ count: count() })
+ .from(avlVendorInfo)
+ .where(and(...conditions));
+
+ return result[0]?.count || 0;
+ } catch (error) {
+ console.error("Error in getProjectAvlVendorInfoCount:", error);
+ return 0;
+ }
+}
+
+/**
+ * 표준 AVL 벤더 정보 건수 조회
+ */
+export async function getStandardAvlVendorInfoCount(
+ standardAvlInfo: {
+ constructionSector: string;
+ shipType: string;
+ avlKind: string;
+ htDivision: string;
+ }
+): Promise<number> {
+ try {
+ const result = await db
+ .select({ count: count() })
+ .from(avlVendorInfo)
+ .where(
+ and(
+ eq(avlVendorInfo.isTemplate, true),
+ eq(avlVendorInfo.constructionSector, standardAvlInfo.constructionSector),
+ eq(avlVendorInfo.shipType, standardAvlInfo.shipType),
+ eq(avlVendorInfo.avlKind, standardAvlInfo.avlKind),
+ eq(avlVendorInfo.htDivision, standardAvlInfo.htDivision)
+ )
+ );
+
+ return result[0]?.count || 0;
+ } catch (error) {
+ console.error("Error in getStandardAvlVendorInfoCount:", error);
+ return 0;
+ }
+}
+
+/**
* 프로젝트 AVL 최종 확정
* 1. 주어진 프로젝트 정보로 avlList에 레코드를 생성한다.
- * 2. 현재 avlVendorInfo 레코드들의 avlListId를 새로 생성된 AVL 리스트 ID로 업데이트한다.
+ * 2. 해당 프로젝트 코드의 모든 avlVendorInfo 레코드들의 avlListId를 새로 생성된 AVL 리스트 ID로 업데이트한다.
*/
export async function finalizeProjectAvl(
projectCode: string,
@@ -953,23 +1015,48 @@ export async function finalizeProjectAvl(
shipType: string;
htDivision: string;
},
- avlVendorInfoIds: number[],
currentUser?: string
): Promise<{ success: boolean; avlListId?: number; message: string }> {
try {
debugLog('프로젝트 AVL 최종 확정 시작', {
projectCode,
projectInfo,
- avlVendorInfoIds: avlVendorInfoIds.length,
currentUser
});
- // 1. 기존 AVL 리스트의 최고 revision 확인
+ // 1. DB에서 해당 프로젝트 코드와 H/T 구분의 모든 avlVendorInfo 레코드 ID 조회
+ const allVendorInfoRecords = await db
+ .select({ id: avlVendorInfo.id })
+ .from(avlVendorInfo)
+ .where(
+ and(
+ eq(avlVendorInfo.projectCode, projectCode),
+ eq(avlVendorInfo.htDivision, projectInfo.htDivision),
+ eq(avlVendorInfo.isTemplate, false)
+ )
+ );
+
+ const avlVendorInfoIds = allVendorInfoRecords.map(record => record.id);
+
+ if (avlVendorInfoIds.length === 0) {
+ return {
+ success: false,
+ message: "해당 프로젝트의 AVL 벤더 정보가 없습니다."
+ };
+ }
+
+ debugLog('프로젝트 AVL 벤더 정보 조회 완료', {
+ projectCode,
+ totalVendorInfoCount: avlVendorInfoIds.length
+ });
+
+ // 2. 기존 AVL 리스트의 최고 revision 확인 (프로젝트 코드 + H/T 구분별로)
const existingAvlLists = await db
.select({ rev: avlList.rev })
.from(avlList)
.where(and(
eq(avlList.projectCode, projectCode),
+ eq(avlList.htDivision, projectInfo.htDivision),
eq(avlList.isTemplate, false)
))
.orderBy(desc(avlList.rev))
@@ -983,7 +1070,7 @@ export async function finalizeProjectAvl(
nextRevision
});
- // 2. AVL 리스트 생성을 위한 데이터 준비
+ // 3. AVL 리스트 생성을 위한 데이터 준비
const createAvlListData: CreateAvlListInput = {
isTemplate: false, // 프로젝트 AVL이므로 false
constructionSector: projectInfo.constructionSector,
@@ -998,7 +1085,7 @@ export async function finalizeProjectAvl(
debugLog('AVL 리스트 생성 데이터', { createAvlListData });
- // 2. AVL Vendor Info 스냅샷 생성 (AVL 리스트 생성 전에 현재 상태 저장)
+ // 4. AVL Vendor Info 스냅샷 생성 (AVL 리스트 생성 전에 현재 상태 저장)
debugLog('AVL Vendor Info 스냅샷 생성 시작', {
vendorInfoIdsCount: avlVendorInfoIds.length,
vendorInfoIds: avlVendorInfoIds
@@ -1017,7 +1104,7 @@ export async function finalizeProjectAvl(
snapshotLength: createAvlListData.vendorInfoSnapshot?.length
});
- // 3. AVL 리스트 생성
+ // 5. AVL 리스트 생성
const newAvlList = await createAvlList(createAvlListData);
if (!newAvlList) {
@@ -1026,7 +1113,7 @@ export async function finalizeProjectAvl(
debugSuccess('AVL 리스트 생성 완료', { avlListId: newAvlList.id });
- // 3. avlVendorInfo 레코드들의 avlListId 업데이트
+ // 6. avlVendorInfo 레코드들의 avlListId 업데이트
if (avlVendorInfoIds.length > 0) {
debugLog('AVL Vendor Info 업데이트 시작', {
count: avlVendorInfoIds.length,
@@ -1071,7 +1158,7 @@ export async function finalizeProjectAvl(
}
}
- // 4. 캐시 무효화
+ // 7. 캐시 무효화
revalidateTag('avl-list');
revalidateTag('avl-vendor-info');
@@ -1123,6 +1210,11 @@ export const getProjectAvlVendorInfo = async (input: GetProjectAvlSchema) => {
whereConditions.push(ilike(avlVendorInfo.projectCode, `%${input.projectCode}%`));
}
+ // 필수 필터: H/T 구분 (avlVendorInfo에서 직접 필터링)
+ if (input.htDivision) {
+ whereConditions.push(eq(avlVendorInfo.htDivision, input.htDivision));
+ }
+
// 검색어 기반 필터링
if (input.search) {
const searchTerm = `%${input.search}%`;
@@ -1513,11 +1605,12 @@ export const getStandardAvlVendorInfo = async (input: GetStandardAvlSchema) => {
export const copyToProjectAvl = async (
selectedIds: number[],
targetProjectCode: string,
+ targetHtDivision: string,
targetAvlListId: number,
userName: string
): Promise<ActionResult> => {
try {
- debugLog('선종별표준AVL → 프로젝트AVL 복사 시작', { selectedIds, targetProjectCode, targetAvlListId });
+ debugLog('선종별표준AVL → 프로젝트AVL 복사 시작', { selectedIds, targetProjectCode, targetHtDivision, targetAvlListId });
if (!selectedIds.length) {
return { success: false, message: "복사할 항목을 선택해주세요." };
@@ -1544,12 +1637,12 @@ export const copyToProjectAvl = async (
id: undefined, // 새 ID 생성
isTemplate: false, // 프로젝트 AVL로 변경
projectCode: targetProjectCode, // 대상 프로젝트 코드
+ htDivision: targetHtDivision, // 프로젝트 AVL에서 선택한 H/T 구분 적용
avlListId: targetAvlListId, // 대상 AVL 리스트 ID
// 표준 AVL 필드들은 null로 설정 (프로젝트 AVL에서는 사용하지 않음)
constructionSector: null,
shipType: null,
avlKind: null,
- htDivision: null,
createdAt: undefined,
updatedAt: undefined,
}));
@@ -1887,11 +1980,12 @@ export const copyToVendorPool = async (
export const copyFromVendorPoolToProjectAvl = async (
selectedIds: number[],
targetProjectCode: string,
+ targetHtDivision: string,
targetAvlListId: number,
userName: string
): Promise<ActionResult> => {
try {
- debugLog('벤더풀 → 프로젝트AVL 복사 시작', { selectedIds, targetProjectCode, targetAvlListId });
+ debugLog('벤더풀 → 프로젝트AVL 복사 시작', { selectedIds, targetProjectCode, targetHtDivision, targetAvlListId });
if (!selectedIds.length) {
return { success: false, message: "복사할 항목을 선택해주세요." };
@@ -1913,6 +2007,7 @@ export const copyFromVendorPoolToProjectAvl = async (
const recordsToInsert: NewAvlVendorInfo[] = selectedRecords.map(record => ({
// 프로젝트 AVL용 필드들
projectCode: targetProjectCode,
+ htDivision: targetHtDivision, // 프로젝트 AVL에서 선택한 H/T 구분 적용
avlListId: targetAvlListId,
isTemplate: false,
@@ -1921,9 +2016,8 @@ export const copyFromVendorPoolToProjectAvl = async (
vendorName: record.vendorName,
vendorCode: record.vendorCode,
- // 기본 정보 (벤더풀의 데이터 활용)
- constructionSector: record.constructionSector,
- htDivision: record.htDivision,
+ // 기본 정보 (프로젝트 AVL에서는 constructionSector 사용 안함)
+ constructionSector: null,
// 자재그룹 정보
materialGroupCode: record.materialGroupCode,
@@ -2332,6 +2426,7 @@ export const copyFromStandardAvlToVendorPool = async (
/**
* 표준 AVL 최종 확정
* 표준 AVL을 최종 확정하여 AVL 리스트에 등록합니다.
+ * DB에서 해당 조건에 맞는 모든 avlVendorInfo 레코드를 조회하여 확정합니다.
*/
export async function finalizeStandardAvl(
standardAvlInfo: {
@@ -2340,17 +2435,43 @@ export async function finalizeStandardAvl(
avlKind: string;
htDivision: string;
},
- avlVendorInfoIds: number[],
currentUser?: string
): Promise<{ success: boolean; avlListId?: number; message: string }> {
try {
debugLog('표준 AVL 최종 확정 시작', {
standardAvlInfo,
- avlVendorInfoIds: avlVendorInfoIds.length,
currentUser
});
- // 1. 기존 표준 AVL 리스트의 최고 revision 확인
+ // 1. DB에서 해당 조건의 모든 avlVendorInfo 레코드 ID 조회
+ const allVendorInfoRecords = await db
+ .select({ id: avlVendorInfo.id })
+ .from(avlVendorInfo)
+ .where(
+ and(
+ eq(avlVendorInfo.isTemplate, true),
+ eq(avlVendorInfo.constructionSector, standardAvlInfo.constructionSector),
+ eq(avlVendorInfo.shipType, standardAvlInfo.shipType),
+ eq(avlVendorInfo.avlKind, standardAvlInfo.avlKind),
+ eq(avlVendorInfo.htDivision, standardAvlInfo.htDivision)
+ )
+ );
+
+ const avlVendorInfoIds = allVendorInfoRecords.map(record => record.id);
+
+ if (avlVendorInfoIds.length === 0) {
+ return {
+ success: false,
+ message: "해당 조건의 표준 AVL 벤더 정보가 없습니다."
+ };
+ }
+
+ debugLog('표준 AVL 벤더 정보 조회 완료', {
+ standardAvlInfo,
+ totalVendorInfoCount: avlVendorInfoIds.length
+ });
+
+ // 2. 기존 표준 AVL 리스트의 최고 revision 확인
const existingAvlLists = await db
.select({ rev: avlList.rev })
.from(avlList)
@@ -2372,7 +2493,7 @@ export async function finalizeStandardAvl(
nextRevision
});
- // 2. AVL 리스트 생성을 위한 데이터 준비
+ // 3. AVL 리스트 생성을 위한 데이터 준비
const createAvlListData: CreateAvlListInput = {
isTemplate: true, // 표준 AVL이므로 true
constructionSector: standardAvlInfo.constructionSector,
@@ -2387,7 +2508,7 @@ export async function finalizeStandardAvl(
debugLog('표준 AVL 리스트 생성 데이터', { createAvlListData });
- // 2-1. AVL Vendor Info 스냅샷 생성 (AVL 리스트 생성 전에 현재 상태 저장)
+ // 4. AVL Vendor Info 스냅샷 생성 (AVL 리스트 생성 전에 현재 상태 저장)
debugLog('표준 AVL Vendor Info 스냅샷 생성 시작', {
vendorInfoIdsCount: avlVendorInfoIds.length,
vendorInfoIds: avlVendorInfoIds
@@ -2406,7 +2527,7 @@ export async function finalizeStandardAvl(
snapshotLength: createAvlListData.vendorInfoSnapshot?.length
});
- // 3. AVL 리스트 생성
+ // 5. AVL 리스트 생성
const newAvlList = await createAvlList(createAvlListData);
if (!newAvlList) {
@@ -2415,7 +2536,7 @@ export async function finalizeStandardAvl(
debugSuccess('표준 AVL 리스트 생성 완료', { avlListId: newAvlList.id });
- // 4. avlVendorInfo 레코드들의 avlListId 업데이트
+ // 6. avlVendorInfo 레코드들의 avlListId 업데이트
if (avlVendorInfoIds.length > 0) {
debugLog('표준 AVL Vendor Info 업데이트 시작', {
count: avlVendorInfoIds.length,
@@ -2459,7 +2580,7 @@ export async function finalizeStandardAvl(
}
}
- // 5. 캐시 무효화
+ // 7. 캐시 무효화
revalidateTag('avl-list');
revalidateTag('avl-vendor-info');