diff options
Diffstat (limited to 'lib/vendor-regular-registrations/repository.ts')
| -rw-r--r-- | lib/vendor-regular-registrations/repository.ts | 157 |
1 files changed, 142 insertions, 15 deletions
diff --git a/lib/vendor-regular-registrations/repository.ts b/lib/vendor-regular-registrations/repository.ts index d4c979a5..38bf4aaf 100644 --- a/lib/vendor-regular-registrations/repository.ts +++ b/lib/vendor-regular-registrations/repository.ts @@ -5,8 +5,11 @@ import { vendorAttachments,
vendorInvestigationAttachments,
basicContract,
+ basicContractTemplates,
vendorPQSubmissions,
vendorInvestigations,
+ vendorBusinessContacts,
+ vendorAdditionalInfo,
} from "@/db/schema";
import { eq, desc, and, sql, inArray } from "drizzle-orm";
import type { VendorRegularRegistration } from "@/config/vendorRegularRegistrationsColumnsConfig";
@@ -27,11 +30,16 @@ export async function getVendorRegularRegistrations( assignedDepartment: vendorRegularRegistrations.assignedDepartment,
assignedUser: vendorRegularRegistrations.assignedUser,
remarks: vendorRegularRegistrations.remarks,
+ // 새로 추가된 필드들
+ safetyQualificationContent: vendorRegularRegistrations.safetyQualificationContent,
+ gtcSkipped: vendorRegularRegistrations.gtcSkipped,
// 벤더 기본 정보
businessNumber: vendors.taxId,
companyName: vendors.vendorName,
establishmentDate: vendors.createdAt,
representative: vendors.representativeName,
+ // 국가 정보 추가
+ country: vendors.country,
})
.from(vendorRegularRegistrations)
.innerJoin(vendors, eq(vendorRegularRegistrations.vendorId, vendors.id))
@@ -59,23 +67,81 @@ export async function getVendorRegularRegistrations( .innerJoin(vendorInvestigations, eq(vendorInvestigationAttachments.investigationId, vendorInvestigations.id))
.where(inArray(vendorInvestigations.vendorId, vendorIds)) : [];
+ // 기본 계약 정보 조회 (템플릿별로 가장 최신 것만)
+ const basicContractsList = vendorIds.length > 0 ? await db
+ .select({
+ vendorId: basicContract.vendorId,
+ templateId: basicContract.templateId,
+ status: basicContract.status,
+ templateName: basicContractTemplates.templateName,
+ createdAt: basicContract.createdAt,
+ })
+ .from(basicContract)
+ .leftJoin(basicContractTemplates, eq(basicContract.templateId, basicContractTemplates.id))
+ .where(inArray(basicContract.vendorId, vendorIds))
+ .orderBy(desc(basicContract.createdAt)) : [];
+
+ // 추가정보 입력 상태 조회 (업무담당자 정보)
+ const businessContactsList = vendorIds.length > 0 ? await db
+ .select({
+ vendorId: vendorBusinessContacts.vendorId,
+ contactType: vendorBusinessContacts.contactType,
+ })
+ .from(vendorBusinessContacts)
+ .where(inArray(vendorBusinessContacts.vendorId, vendorIds)) : [];
+
+ // 추가정보 테이블 조회
+ const additionalInfoList = vendorIds.length > 0 ? await db
+ .select({
+ vendorId: vendorAdditionalInfo.vendorId,
+ })
+ .from(vendorAdditionalInfo)
+ .where(inArray(vendorAdditionalInfo.vendorId, vendorIds)) : [];
+
// 각 등록 레코드별로 데이터를 매핑하여 결과 반환
return registrations.map((registration) => {
// 벤더별 첨부파일 필터링
const vendorFiles = vendorAttachmentsList.filter(att => att.vendorId === registration.vendorId);
const investigationFiles = investigationAttachmentsList.filter(att => att.vendorId === registration.vendorId);
+ const allVendorContracts = basicContractsList.filter(contract => contract.vendorId === registration.vendorId);
+ const vendorContacts = businessContactsList.filter(contact => contact.vendorId === registration.vendorId);
+ const vendorAdditionalInfoData = additionalInfoList.filter(info => info.vendorId === registration.vendorId);
+
+ // 기술자료 동의서, 비밀유지계약서 제외 필터링
+ const filteredContracts = allVendorContracts.filter(contract => {
+ const templateName = contract.templateName?.toLowerCase() || '';
+ return !templateName.includes('기술자료') && !templateName.includes('비밀유지');
+ });
+
+ // 템플릿명 기준으로 가장 최신 계약만 유지 (중복 제거)
+ const vendorContracts = filteredContracts.reduce((acc, contract) => {
+ const existing = acc.find(c => c.templateName === contract.templateName);
+ if (!existing || (contract.createdAt && existing.createdAt && contract.createdAt > existing.createdAt)) {
+ // 기존에 같은 템플릿명이 없거나, 더 최신인 경우 추가/교체
+ return acc.filter(c => c.templateName !== contract.templateName).concat(contract);
+ }
+ return acc;
+ }, [] as typeof filteredContracts);
// 디버깅을 위한 로그
- console.log(`📋 벤더 ID ${registration.vendorId} (${registration.companyName}) 첨부파일 현황:`, {
+ console.log(`📋 벤더 ID ${registration.vendorId} (${registration.companyName}) 현황:`, {
vendorFiles: vendorFiles.map(f => ({ type: f.attachmentType, fileName: f.fileName })),
- investigationFiles: investigationFiles.map(f => ({ type: f.attachmentType, fileName: f.fileName }))
+ investigationFiles: investigationFiles.map(f => ({ type: f.attachmentType, fileName: f.fileName })),
+ allContracts: allVendorContracts.length,
+ uniqueContracts: vendorContracts.map(c => ({
+ templateName: c.templateName,
+ status: c.status,
+ createdAt: c.createdAt?.toISOString()
+ })),
+ contactTypes: vendorContacts.map(c => c.contactType)
});
- // 문서 제출 현황 - 실제 첨부파일 존재 여부 확인 (DB 타입명과 정확히 매칭)
+ // 문서 제출 현황 - 국가별 요구사항 적용
+ const isForeign = registration.country !== 'KR';
const documentSubmissionsStatus = {
businessRegistration: vendorFiles.some(f => f.attachmentType === "BUSINESS_REGISTRATION"),
creditEvaluation: vendorFiles.some(f => f.attachmentType === "CREDIT_REPORT"),
- bankCopy: vendorFiles.some(f => f.attachmentType === "BANK_ACCOUNT_COPY"),
+ bankCopy: isForeign ? vendorFiles.some(f => f.attachmentType === "BANK_ACCOUNT_COPY") : true, // 내자는 통장사본 불필요
auditResult: investigationFiles.length > 0, // 실사 첨부파일이 하나라도 있으면 true
};
@@ -88,33 +154,88 @@ export async function getVendorRegularRegistrations( };
// 문서 제출 현황 로그
- console.log(`📊 벤더 ID ${registration.vendorId} 문서 제출 현황:`, documentSubmissionsStatus);
+ console.log(`📊 벤더 ID ${registration.vendorId} 문서 제출 현황:`, {
+ documentSubmissionsStatus,
+ isForeign,
+ vendorFiles: vendorFiles.map(f => ({
+ type: f.attachmentType,
+ fileName: f.fileName
+ })),
+ investigationFilesCount: investigationFiles.length,
+ country: registration.country
+ });
- // 계약 동의 현황 (기본값 - 추후 실제 계약 테이블과 연동)
+ // 계약 동의 현황 - 실제 기본 계약 데이터 기반으로 단순화
const contractAgreementsStatus = {
- cp: "not_submitted",
- gtc: "not_submitted",
- standardSubcontract: "not_submitted",
- safetyHealth: "not_submitted",
- ethics: "not_submitted",
- domesticCredit: "not_submitted",
- safetyQualification: "not_submitted",
+ cp: vendorContracts.some(c => c.status === "COMPLETED") ? "completed" : "not_submitted",
+ gtc: registration.gtcSkipped ? "completed" : (vendorContracts.some(c => c.templateName?.includes("GTC") && c.status === "COMPLETED") ? "completed" : "not_submitted"),
+ standardSubcontract: vendorContracts.some(c => c.templateName?.includes("표준하도급") && c.status === "COMPLETED") ? "completed" : "not_submitted",
+ safetyHealth: vendorContracts.some(c => c.templateName?.includes("안전보건") && c.status === "COMPLETED") ? "completed" : "not_submitted",
+ ethics: vendorContracts.some(c => c.templateName?.includes("윤리") && c.status === "COMPLETED") ? "completed" : "not_submitted",
+ domesticCredit: vendorContracts.some(c => c.templateName?.includes("내국신용장") && c.status === "COMPLETED") ? "completed" : "not_submitted",
};
+ // 추가정보 입력 완료 여부 - 5개 필수 업무담당자 타입 + 추가정보 테이블 모두 입력되었는지 확인
+ const requiredContactTypes = ["sales", "design", "delivery", "quality", "tax_invoice"];
+ const contactsCompleted = requiredContactTypes.every(type =>
+ vendorContacts.some(contact => contact.contactType === type)
+ );
+ const additionalInfoTableCompleted = vendorAdditionalInfoData.length > 0;
+ const additionalInfoCompleted = contactsCompleted && additionalInfoTableCompleted;
+
+ // 추가정보 디버깅 로그
+ console.log(`🔍 벤더 ID ${registration.vendorId} 추가정보 상세:`, {
+ requiredContactTypes,
+ vendorContactTypes: vendorContacts.map(c => c.contactType),
+ contactsCompleted,
+ additionalInfoTableCompleted,
+ additionalInfoData: vendorAdditionalInfoData,
+ finalAdditionalInfoCompleted: additionalInfoCompleted
+ });
+
+ // 모든 조건 충족 여부 확인
+ const allDocumentsSubmitted = Object.values(documentSubmissionsStatus).every(status => status === true);
+ const allContractsCompleted = vendorContracts.length > 0 && vendorContracts.every(c => c.status === "COMPLETED");
+ const safetyQualificationCompleted = !!registration.safetyQualificationContent;
+
+ // 모든 조건이 충족되면 status를 "approval_ready"(조건충족)로 자동 변경
+ const shouldUpdateStatus = allDocumentsSubmitted && allContractsCompleted && safetyQualificationCompleted && additionalInfoCompleted;
+
+ // 현재 상태가 조건충족이 아닌데 모든 조건이 충족되면 상태 업데이트
+ if (shouldUpdateStatus && registration.status !== "approval_ready") {
+ // 비동기 업데이트 (백그라운드에서 실행)
+ updateVendorRegularRegistration(registration.id, {
+ status: "approval_ready"
+ }).catch(error => {
+ console.error(`상태 자동 업데이트 실패 (벤더 ID: ${registration.vendorId}):`, error);
+ });
+ }
+
return {
id: registration.id,
vendorId: registration.vendorId,
- status: registration.status || "audit_pass",
+ status: shouldUpdateStatus ? "approval_ready" : (registration.status || "audit_pass"),
potentialCode: registration.potentialCode,
businessNumber: registration.businessNumber || "",
companyName: registration.companyName || "",
majorItems: registration.majorItems,
establishmentDate: registration.establishmentDate?.toISOString() || null,
representative: registration.representative,
+ country: registration.country,
documentSubmissions: documentSubmissionsStatus,
documentFiles: documentFiles, // 파일 정보 추가
contractAgreements: contractAgreementsStatus,
- additionalInfo: true, // TODO: 추가정보 로직 구현 필요
+ // 새로 추가된 필드들
+ safetyQualificationContent: registration.safetyQualificationContent,
+ gtcSkipped: registration.gtcSkipped || false,
+ additionalInfo: additionalInfoCompleted,
+ // 기본계약 정보
+ basicContracts: vendorContracts.map(contract => ({
+ templateId: contract.templateId,
+ templateName: contract.templateName,
+ status: contract.status,
+ createdAt: contract.createdAt,
+ })),
registrationRequestDate: registration.registrationRequestDate || null,
assignedDepartment: registration.assignedDepartment,
assignedUser: registration.assignedUser,
@@ -137,6 +258,8 @@ export async function createVendorRegularRegistration(data: { assignedUser?: string;
assignedUserCode?: string;
remarks?: string;
+ safetyQualificationContent?: string;
+ gtcSkipped?: boolean;
}) {
try {
const [registration] = await db
@@ -151,6 +274,8 @@ export async function createVendorRegularRegistration(data: { assignedUser: data.assignedUser,
assignedUserCode: data.assignedUserCode,
remarks: data.remarks,
+ safetyQualificationContent: data.safetyQualificationContent,
+ gtcSkipped: data.gtcSkipped || false,
})
.returning();
@@ -173,6 +298,8 @@ export async function updateVendorRegularRegistration( assignedUser: string;
assignedUserCode: string;
remarks: string;
+ safetyQualificationContent: string;
+ gtcSkipped: boolean;
}>
) {
try {
|
