summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/soap/mdg/send/vendor-master/action.ts122
-rw-r--r--lib/vendors/service.ts121
2 files changed, 228 insertions, 15 deletions
diff --git a/lib/soap/mdg/send/vendor-master/action.ts b/lib/soap/mdg/send/vendor-master/action.ts
index e96b93fc..ae0c2c89 100644
--- a/lib/soap/mdg/send/vendor-master/action.ts
+++ b/lib/soap/mdg/send/vendor-master/action.ts
@@ -267,34 +267,34 @@ async function fetchVendorData(vendorCode: string) {
// SOAP 데이터 생성 (WSDL 구조에 맞춤)
function buildSoapData(vendorData: NonNullable<Awaited<ReturnType<typeof fetchVendorData>>>) {
- const { vendorHeader, addresses, adEmails, adFaxes, adPostals, adTels, adUrls, bpTaxnums, bpVengens } = vendorData;
+ const { vendorHeader, addresses, adFaxes, adPostals, adTels, bpTaxnums, bpVengens } = vendorData;
// 값 추출 매핑 ------------------------------------
const mapping: Record<string, string | undefined> = {
// Header
BP_HEADER: vendorHeader?.VNDRCD,
ZZSRMCD: 'EVCP',
- TITLE: vendorHeader?.TITLE ?? '',
- BU_SORT1: adPostals[0]?.VNDRNM_ABRV_1,
- NAME_ORG1: adPostals[0]?.VNDRNM_1,
- KTOKK: bpVengens[0]?.ACNT_GRP,
+ TITLE: '', // vendorHeader에 TITLE 필드가 없음
+ BU_SORT1: adPostals[0]?.VNDRNM_ABRV_1 ?? undefined,
+ NAME_ORG1: adPostals[0]?.VNDRNM_1 ?? undefined,
+ KTOKK: bpVengens[0]?.ACNT_GRP ?? undefined,
MASTERFLAG: 'X',
IBND_TYPE: 'U',
// Address mandatory (first)
ADDRNO: addresses[0]?.ADDRNO,
- AD_NATION: adPostals[0]?.INTL_ADR_VER_ID,
- COUNTRY: adPostals[0]?.NTN_CD,
- LANGU_COM: adPostals[0]?.LANG_KEY,
- POST_COD1: adPostals[0]?.CITY_ZIP_NO,
- CITY1: adPostals[0]?.VNDRNM_1,
- MC_STREET: adPostals[0]?.ADR_1,
+ AD_NATION: adPostals[0]?.INTL_ADR_VER_ID ?? undefined,
+ COUNTRY: adPostals[0]?.NTN_CD ?? undefined,
+ LANGU_COM: adPostals[0]?.LANG_KEY ?? undefined,
+ POST_COD1: adPostals[0]?.CITY_ZIP_NO ?? undefined,
+ CITY1: adPostals[0]?.VNDRNM_1 ?? undefined,
+ MC_STREET: adPostals[0]?.ADR_1 ?? undefined,
// Phone/Fax mandatory fields
AD_CONSNO: '001',
- T_COUNTRY: adTels[0]?.CTRY_CD ?? 'KR',
- F_COUNTRY: adFaxes[0]?.CTRY_CD ?? 'KR',
+ T_COUNTRY: adTels[0]?.NTN_CD ?? 'KR',
+ F_COUNTRY: adFaxes[0]?.NTN_CD ?? 'KR',
// Tax
BP_TX_TYP: bpTaxnums[0]?.TX_NO_CTG ?? 'KR2',
- TAXNUM: bpVengens[0]?.VAT_REG_NO,
+ TAXNUM: bpVengens[0]?.VAT_REG_NO ?? undefined,
// Default others can be added as needed
};
@@ -306,7 +306,7 @@ function buildSoapData(vendorData: NonNullable<Awaited<ReturnType<typeof fetchVe
return true;
});
- const supplierMaster: Record<string, any> = {};
+ const supplierMaster: Record<string, string> = {};
uniqueFields.forEach(f => {
supplierMaster[f.field] = mapping[f.field] ?? '';
});
@@ -620,6 +620,98 @@ export async function getVendorSendStatistics(): Promise<{
}
}
+// 테스트용 폼 데이터 송신 함수 (SOAP 라이브러리 사용)
+export async function sendTestVendorDataToMDG(formData: Record<string, string>): Promise<{
+ success: boolean;
+ message: string;
+ responseData?: any;
+}> {
+ try {
+ console.log('🧪 테스트용 VENDOR 데이터 SOAP 송신 시작');
+
+ // CSV 파일 동적 로드 (더 안전함)
+ let csvFields: CsvField[] = [];
+ try {
+ const csvRaw = fs.readFileSync(CSV_PATH, 'utf-8');
+ csvFields = parseCsv(csvRaw);
+ } catch (e) {
+ console.error('CSV 로딩 실패:', e);
+ return {
+ success: false,
+ message: 'CSV 필드 정의 파일을 로드할 수 없습니다.'
+ };
+ }
+
+ // 필수 필드 검증
+ const requiredFields = csvFields.filter(f => f.mandatory).map(f => f.field);
+ const missingFields = requiredFields.filter(field => !formData[field]?.trim());
+
+ if (missingFields.length > 0) {
+ return {
+ success: false,
+ message: `필수 필드가 누락되었습니다: ${missingFields.join(', ')}`
+ };
+ }
+
+ // 필드 순서에 따라 데이터 생성
+ const seen = new Set<string>();
+ const uniqueFields = csvFields.filter(f => {
+ if (seen.has(f.field)) return false;
+ seen.add(f.field);
+ return true;
+ });
+
+ const supplierMaster: Record<string, string> = {};
+ uniqueFields.forEach(f => {
+ supplierMaster[f.field] = formData[f.field] ?? '';
+ });
+
+ // SOAP 요청 구조 생성
+ const soapData = {
+ P2MD3007_S: {
+ SUPPLIER_MASTER: supplierMaster
+ }
+ };
+
+ console.log('📄 테스트 SOAP 데이터 생성 완료');
+
+ // SOAP 클라이언트로 요청 전송
+ const responseData = await withSoapLogging(
+ 'OUTBOUND',
+ 'MDG',
+ 'IF_MDZ_EVCP_VENDOR_MASTER_TEST',
+ JSON.stringify(soapData),
+ async () => {
+ const client = await createSoapClient();
+
+ return new Promise<SoapResponse>((resolve, reject) => {
+ client.P2MD3007_AO(soapData, (err: SoapError | null, result: SoapResponse) => {
+ if (err) {
+ reject(err);
+ } else {
+ console.log('✅ 테스트 MDG 전송 성공');
+ resolve(result);
+ }
+ });
+ });
+ }
+ );
+
+ return {
+ success: true,
+ message: '테스트 송신이 완료되었습니다.',
+ responseData
+ };
+
+ } catch (error) {
+ console.error('❌ 테스트 송신 실패:', error);
+ return {
+ success: false,
+ message: error instanceof Error ? error.message : 'Unknown error'
+ };
+ }
+}
+
// 직접 XML 전송 함수 (기존 호환성 유지)
export async function sendVendorEnvelopeToMDG(envelope: string): Promise<{
success: boolean;
diff --git a/lib/vendors/service.ts b/lib/vendors/service.ts
index 2328752b..853b3701 100644
--- a/lib/vendors/service.ts
+++ b/lib/vendors/service.ts
@@ -2584,4 +2584,125 @@ export async function searchVendors(searchTerm: string = "", limit: number = 100
console.error("벤더 검색 오류:", error);
return [];
}
+}
+
+/**
+ * 벤더 기본정보 조회 (Basic Info 페이지용)
+ * vendorsWithTypesView를 사용하여 기본 정보 + contacts + attachments 조회
+ */
+export async function getVendorBasicInfo(vendorId: number) {
+ unstable_noStore();
+
+ try {
+ return await db.transaction(async (tx) => {
+ // 1. 기본 벤더 정보 조회 (vendorsWithTypesView 사용)
+ const vendor = await tx
+ .select()
+ .from(vendorsWithTypesView)
+ .where(eq(vendorsWithTypesView.id, vendorId))
+ .limit(1)
+ .then(rows => rows[0] || null);
+
+ if (!vendor) {
+ return null;
+ }
+
+ // 2. 연락처 정보 조회
+ const contacts = await tx
+ .select()
+ .from(vendorContacts)
+ .where(eq(vendorContacts.vendorId, vendorId))
+ .orderBy(desc(vendorContacts.isPrimary), asc(vendorContacts.contactName));
+
+ // 3. 첨부파일 정보 조회
+ const attachments = await tx
+ .select()
+ .from(vendorAttachments)
+ .where(eq(vendorAttachments.vendorId, vendorId))
+ .orderBy(asc(vendorAttachments.createdAt));
+
+ // 4. 타입 변환하여 반환 (추후 확장 가능하도록 구조화)
+ return {
+ // 기본 벤더 정보
+ id: vendor.id,
+ vendorName: vendor.vendorName,
+ vendorCode: vendor.vendorCode,
+ taxId: vendor.taxId,
+ address: vendor.address,
+ businessSize: vendor.businessSize || "", // vendorsWithTypesView에 businessSize 필드가 없을 경우 대비
+ country: vendor.country,
+ phone: vendor.phone,
+ fax: vendor.fax || null, // vendorsWithTypesView에 fax 필드가 없을 경우 대비
+ email: vendor.email,
+ website: vendor.website,
+ status: vendor.status,
+ representativeName: vendor.representativeName,
+ representativeBirth: vendor.representativeBirth,
+ representativeEmail: vendor.representativeEmail,
+ representativePhone: vendor.representativePhone,
+ representativeWorkExperience: vendor.representativeWorkExperience ?? false, // vendorsWithTypesView에 해당 필드가 없을 경우 false로 기본값
+ corporateRegistrationNumber: vendor.corporateRegistrationNumber,
+ creditAgency: vendor.creditAgency,
+ creditRating: vendor.creditRating,
+ cashFlowRating: vendor.cashFlowRating,
+ createdAt: vendor.createdAt,
+ updatedAt: vendor.updatedAt,
+
+ // 연락처 정보
+ contacts: contacts.map(contact => ({
+ id: contact.id,
+ contactName: contact.contactName,
+ contactPosition: contact.contactPosition,
+ contactEmail: contact.contactEmail,
+ contactPhone: contact.contactPhone,
+ isPrimary: contact.isPrimary,
+ })),
+
+ // 첨부파일 정보
+ attachments: attachments.map(attachment => ({
+ id: attachment.id,
+ fileName: attachment.fileName,
+ filePath: attachment.filePath,
+ attachmentType: attachment.attachmentType,
+ createdAt: attachment.createdAt,
+ })),
+
+ // 추가 정보는 임시로 null (나중에 실제 데이터로 교체)
+ additionalInfo: {
+ businessType: vendor.vendorTypeId ? `Type ${vendor.vendorTypeId}` : null,
+ employeeCount: 0, // 실제 데이터가 있을 수 있으므로 유지
+ mainBusiness: null,
+ },
+
+ // 매출 정보 (구현 예정 - 나중에 실제 테이블 연결)
+ salesInfo: null, // 구현 시 { "2023": { totalSales: "1000", totalDebt: "500", ... }, "2022": { ... } } 형태로 연도별 키 사용
+
+ // 추가 정보들 (구현 예정 - 나중에 실제 테이블 연결)
+ organization: null,
+
+ factoryInfo: null,
+
+ inspectionInfo: null,
+
+ evaluationInfo: null,
+
+ classificationInfo: {
+ vendorClassification: null,
+ groupCompany: null,
+ preferredLanguage: "한국어", // 기본값으로 유지
+ industryType: "제조업", // 기본값으로 유지
+ isoCertification: null,
+ },
+
+ contractDetails: null,
+
+ capacityInfo: null,
+
+ calculatedMetrics: null, // 구현 시 { "20231231": { debtRatio: 0, ... }, "20221231": { ... } } 형태로 YYYYMMDD 키 사용
+ };
+ });
+ } catch (error) {
+ console.error("Error fetching vendor basic info:", error);
+ return null;
+ }
} \ No newline at end of file