diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-11-07 06:55:14 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-11-07 06:55:14 +0000 |
| commit | 2072e5d9720bac85e419736b9e201aaab526ecfc (patch) | |
| tree | 7ac43979b98fb83841a6df81f232bbe8472ca09c | |
| parent | 6624adf48ea550dc47ffa27b2f9bf3e019d92f7b (diff) | |
| parent | a78f26bc52a2ff032a8103f36a2a660cefa9fb64 (diff) | |
Merge branch 'dujinkim' of https://github.com/DTS-Development/SHI_EVCP into dujinkim
| -rw-r--r-- | lib/approval/approval-saga.ts | 1 | ||||
| -rw-r--r-- | lib/approval/types.ts | 1 | ||||
| -rw-r--r-- | lib/soap/mdg/send/vendor-master/send-single-vendor.ts | 4 | ||||
| -rw-r--r-- | lib/vendor-regular-registrations/approval-actions.ts | 34 | ||||
| -rw-r--r-- | lib/vendor-regular-registrations/handlers.ts | 11 | ||||
| -rw-r--r-- | lib/vendor-regular-registrations/service.ts | 154 | ||||
| -rw-r--r-- | lib/vendor-regular-registrations/table/vendor-regular-registrations-table-toolbar-actions.tsx | 5 |
7 files changed, 64 insertions, 146 deletions
diff --git a/lib/approval/approval-saga.ts b/lib/approval/approval-saga.ts index 0bbf7836..e04c7e24 100644 --- a/lib/approval/approval-saga.ts +++ b/lib/approval/approval-saga.ts @@ -215,6 +215,7 @@ export class ApprovalSubmissionSaga<T> { approvalLines, { contentsType: 'HTML', // HTML 템플릿 사용 + attachments: this.approvalConfig.attachments, // 첨부파일 전달 } ); diff --git a/lib/approval/types.ts b/lib/approval/types.ts index 7f3fe52b..9b9f0d7b 100644 --- a/lib/approval/types.ts +++ b/lib/approval/types.ts @@ -15,6 +15,7 @@ export interface ApprovalConfig { epId: string | null; email?: string; }; + attachments?: File[]; // 첨부파일 (선택사항) } export interface ApprovalResult { diff --git a/lib/soap/mdg/send/vendor-master/send-single-vendor.ts b/lib/soap/mdg/send/vendor-master/send-single-vendor.ts index d10792b7..bf040b36 100644 --- a/lib/soap/mdg/send/vendor-master/send-single-vendor.ts +++ b/lib/soap/mdg/send/vendor-master/send-single-vendor.ts @@ -194,8 +194,8 @@ function mapVendorToMDGFormat( NATION: '', // 빈 문자열 (보내면 안됨) COUNTRY: vendor.country || 'KR', // 국가코드 (기본값 KR) POST_CODE1: vendor.postalCode || '00000', // 우편번호 (없으면 00000) - CITY1: vendor.addressDetail || '', // 상세주소 - STREET: vendor.address || '', // 기본주소 + CITY1: vendor.addressDetail || '상세주소 정보가 없습니다', // 상세주소 (없으면 fallback) + STREET: vendor.address || '주소 정보가 없습니다', // 기본주소 (없으면 fallback) // === 연락처 정보 === TEL_NUMBER: vendor.phone || '', // 전화번호 diff --git a/lib/vendor-regular-registrations/approval-actions.ts b/lib/vendor-regular-registrations/approval-actions.ts index b90ef2b6..2bd5ec0f 100644 --- a/lib/vendor-regular-registrations/approval-actions.ts +++ b/lib/vendor-regular-registrations/approval-actions.ts @@ -14,6 +14,7 @@ import type { RegistrationRequestData } from '@/components/vendor-regular-regist import db from '@/db/db'; import { eq } from 'drizzle-orm'; import { vendorRegularRegistrations } from '@/db/schema/vendorRegistrations'; +import { users } from '@/db/schema'; /** * 결재를 거쳐 정규업체 등록을 처리하는 서버 액션 @@ -24,7 +25,8 @@ import { vendorRegularRegistrations } from '@/db/schema/vendorRegistrations'; * registrationId: 123, * requestData: registrationData, * currentUser: { id: 1, epId: 'EP001', email: 'user@example.com' }, - * approvers: ['EP002', 'EP003'] + * approvers: ['EP002', 'EP003'], + * attachments: [file1, file2] // 선택사항 * }); * * if (result.status === 'pending_approval') { @@ -38,6 +40,8 @@ export async function registerVendorWithApproval(data: { vendorId?: number; // vendors 테이블에서 정보를 가져오기 위한 vendorId currentUser: { id: number; epId: string | null; email?: string }; approvers?: string[]; // Knox EP ID 배열 (결재선) + attachments?: File[]; // 첨부파일 (선택사항) + title?: string; // 결재 제목 (선택사항, 미지정 시 자동 생성) }) { debugLog('[VendorRegistrationApproval] 정규업체 등록 결재 서버 액션 시작', { registrationId: data.registrationId, @@ -58,7 +62,16 @@ export async function registerVendorWithApproval(data: { throw new Error('등록 ID가 필요합니다'); } - // 1. 템플릿 변수 매핑 + // 1. 유저의 nonsapUserId 조회 (Cronjob 환경을 위해) + debugLog('[VendorRegistrationApproval] nonsapUserId 조회'); + const userResult = await db.query.users.findFirst({ + where: eq(users.id, data.currentUser.id), + columns: { nonsapUserId: true } + }); + const nonsapUserId = userResult?.nonsapUserId || null; + debugLog('[VendorRegistrationApproval] nonsapUserId 조회 완료', { nonsapUserId }); + + // 2. 템플릿 변수 매핑 debugLog('[VendorRegistrationApproval] 템플릿 변수 매핑 시작'); const requestedAt = new Date(); const variables = await mapRegistrationToTemplateVariables({ @@ -70,8 +83,11 @@ export async function registerVendorWithApproval(data: { variableKeys: Object.keys(variables), }); - // 2. 결재 워크플로우 시작 (Saga 패턴) - debugLog('[VendorRegistrationApproval] ApprovalSubmissionSaga 생성'); + // 3. 결재 워크플로우 시작 (Saga 패턴) + debugLog('[VendorRegistrationApproval] ApprovalSubmissionSaga 생성', { + hasAttachments: !!data.attachments, + attachmentCount: data.attachments?.length || 0, + }); const saga = new ApprovalSubmissionSaga( // actionType: 핸들러를 찾을 때 사용할 키 'vendor_regular_registration', @@ -80,23 +96,29 @@ export async function registerVendorWithApproval(data: { { registrationId: data.registrationId, requestData: data.requestData, + currentUser: { // ⚠️ Cronjob 환경을 위한 유저 정보 포함 (headers() 대신) + id: data.currentUser.id, + email: data.currentUser.email, + nonsapUserId: nonsapUserId, // ⚠️ 미리 조회한 nonsapUserId 전달 + }, }, // approvalConfig: 결재 상신 정보 (템플릿 포함) { - title: `정규업체 등록 - ${data.requestData.companyNameKor}`, + title: data.title || `정규업체 등록 - ${data.requestData.companyNameKor}`, description: `${data.requestData.companyNameKor} 정규업체 등록 요청`, templateName: '정규업체 등록', // 한국어 템플릿명 variables, // 치환할 변수들 approvers: data.approvers, currentUser: data.currentUser, + attachments: data.attachments, // 첨부파일 전달 } ); debugLog('[VendorRegistrationApproval] Saga 실행 시작'); const result = await saga.execute(); - // 3. 결재 상신 성공 시 상태를 pending_approval로 변경 + // 4. 결재 상신 성공 시 상태를 pending_approval로 변경 if (result.status === 'pending_approval') { debugLog('[VendorRegistrationApproval] 상태를 pending_approval로 변경'); await db.update(vendorRegularRegistrations) diff --git a/lib/vendor-regular-registrations/handlers.ts b/lib/vendor-regular-registrations/handlers.ts index 7490d81a..262d37ab 100644 --- a/lib/vendor-regular-registrations/handlers.ts +++ b/lib/vendor-regular-registrations/handlers.ts @@ -25,18 +25,25 @@ import { vendorAdditionalInfo, vendorRegularRegistrations } from '@/db/schema/ve export async function registerVendorInternal(payload: { registrationId: number; requestData: RegistrationRequestData; + currentUser?: { // Cronjob 환경을 위한 유저 정보 + id: string | number; + name?: string | null; + email?: string | null; + nonsapUserId?: string | null; + }; }) { debugLog('[VendorRegistrationHandler] 정규업체 등록 핸들러 시작', { registrationId: payload.registrationId, companyName: payload.requestData.companyNameKor, + hasCurrentUser: !!payload.currentUser, }); try { // 1. MDG로 정규업체 등록 요청 데이터 전송 + // sendSingleVendorToMDG 함수를 사용하여 vendors 테이블에서 데이터를 자동으로 조회 debugLog('[VendorRegistrationHandler] sendRegistrationRequestToMDG 호출'); const mdgResult = await sendRegistrationRequestToMDG( - payload.registrationId, - payload.requestData + payload.registrationId ); if (!mdgResult.success) { diff --git a/lib/vendor-regular-registrations/service.ts b/lib/vendor-regular-registrations/service.ts index 30fecfde..eaf62ac7 100644 --- a/lib/vendor-regular-registrations/service.ts +++ b/lib/vendor-regular-registrations/service.ts @@ -10,7 +10,6 @@ import { getServerSession } from "next-auth"; import { authOptions } from "@/app/api/auth/[...nextauth]/route";
import { headers } from "next/headers";
import { sendEmail } from "@/lib/mail/sendEmail";
-import type { RegistrationRequestData } from "@/components/vendor-regular-registrations/registration-request-dialog";
import {
vendors,
vendorRegularRegistrations,
@@ -21,12 +20,11 @@ import { vendorPQSubmissions,
vendorBusinessContacts,
vendorAdditionalInfo,
- basicContractTemplates,
- users
+ basicContractTemplates
} from "@/db/schema";
import db from "@/db/db";
import { inArray, eq, desc, and, lt } from "drizzle-orm";
-import { sendTestVendorDataToMDG } from "@/lib/soap/mdg/send/vendor-master/action";
+import { sendSingleVendorToMDG } from "@/lib/soap/mdg/send/vendor-master/send-single-vendor";
// 3개월 이상 정규등록검토 상태인 등록을 장기미등록으로 변경
async function updatePendingApprovals() {
@@ -833,21 +831,11 @@ export async function fetchRegistrationRequestData(registrationId: number) { // MDG로 정규업체 등록 요청 데이터를 보내는 함수
export async function sendRegistrationRequestToMDG(
- registrationId: number,
- requestData: RegistrationRequestData
+ registrationId: number
) {
try {
console.log('🚀 MDG로 정규업체 등록 요청 데이터 송신 시작');
- // 세션 사용자 정보 가져오기
- const session = await getServerSession(authOptions);
- const userId = session?.user?.id || 'EVCP_USER';
- //users table에서 userid로 nonsapuserid 찾기
- const userResult = await db.query.users.findFirst({
- where: eq(users.id, Number(userId)),
- columns: { nonsapUserId: true }
- });
- const nonsapUserId = userResult?.nonsapUserId || 'EVCP_USER';
// 등록 정보 조회
const registration = await db
.select()
@@ -859,134 +847,28 @@ export async function sendRegistrationRequestToMDG( return { success: false, error: "등록 정보를 찾을 수 없습니다." };
}
- // registration[0].vendorId를 이용해 벤더 정보 조회
- const vendor = await db
- .select()
- .from(vendors)
- .where(eq(vendors.id, registration[0].vendorId))
- .limit(1);
-
- if (!vendor[0]) {
- return { success: false, error: "벤더 정보를 찾을 수 없습니다." };
- }
-
- // MDG 필수 필드 매핑 (이메일 내용 기반)
- const mdgData: Record<string, string> = {
- // 1. BP_HEADER: 벤더코드가 있으면 벤더코드를, 없으면 eVCP에서 관리번호를 보내드리겠습니다. (필수)
- BP_HEADER: vendor[0].vendorCode || vendor[0].id.toString(),
-
- // 2. ZZSRMCD: eVCP에서 내부관리번호를 보내드리겠습니다. (필수)
- ZZSRMCD: vendor[0].id.toString(),
-
- // 3. SORT1: 벤더명 보내드립니다. (필수)
- SORT1: requestData.companyNameKor,
-
- // 4. NAME1: 벤더명 보내드립니다. (필수)
- NAME1: requestData.companyNameKor,
-
- // 5. NAME2: 벤더 영문명 (있는 경우) (선택)
- NAME2: requestData.companyNameEng || '',
-
- // 6. KTOKK: 셈플로 받은자료에는 "LIEF"로 되어 있습니다. 고정값 (필수)
- KTOKK: 'LIEF',
-
- // 7. J_1KFREPRE: 대표자명 (필수)
- J_1KFREPRE: requestData.representativeNameKor,
-
- // 8. MASTERFLAG: 지시자 같은데, 어떤값을 보내면 되나요? -> V (필수)
- MASTERFLAG: 'V',
-
- // 9. IBND_TYPE: 입력가능한 값을 알려주시기 바랍니다. -> 생성 : I, 변경: U (필수)
- IBND_TYPE: 'I',
-
- // 10. ZZREQID: SAP의 USER ID를 보내드리겠습니다. (필수)
- ZZREQID: nonsapUserId,
-
- // 11. ADDRNO: I/F정의서에는 필수입력으로 되어 있습니다. -> 빈값으로 처리 (필수)
- ADDRNO: '',
-
- // 12. COUNTRY: ISO 3166-1의 규약에 따른 국가코드를 보내드릴 예정입니다. (필수)
- COUNTRY: vendor[0].country || 'KR',
-
- // 13. POST_CODE1: 우편번호를 송부하겠습니다. (필수)
- POST_CODE1: vendor[0].postalCode || '',
-
- // 14. CITY1: 상세 주소를 송부하겠습니다. (필수) - 샘플에서는 상세주소가 들어감
- CITY1: vendor[0].addressDetail || '',
-
- // 15. STREET: 주소를 송부하겠습니다. (필수) - 샘플에서는 기본주소가 들어감
- STREET: vendor[0].address || '',
-
- // 16. TEL_NUMBER: 전화번호 (필수)
- TEL_NUMBER: vendor[0].phone || '',
-
- // 17. R3_USER: 전화/휴대폰 구분자로 해석됩니다. 0이면 전화, 1이면 휴대폰 (필수)
- R3_USER: '0', // 일반 전화번호로 가정
-
- // 18. TAXTYPE: 국가 코드에 맞게 하면 됩니다. 국가 KR -> TAXTYPE KR2 (필수)
- TAXTYPE: (vendor[0].country || 'KR') + '2',
-
- // 19. TAXNUM: 사업자번호 (필수)
- TAXNUM: vendor[0].taxId || '',
-
- // 20. BP_TX_TYP: 대표자 주민번호 YYMMDD + 0000000 (YYMMDD0000000) - 대표자 생년월일 기준으로 생성
- BP_TX_TYP: requestData.representativeBirthDate ?
- requestData.representativeBirthDate.replace(/-/g, '') + '0000000' : '',
-
- // 21. STCD3: 법인등록번호 (선택)
- STCD3: requestData.corporateNumber || '',
-
- // 22. CONSNUMBER: 순번 (샘플에서는 1, 2로 설정됨)
- CONSNUMBER: '1',
-
- // 23. ZZIND03: 기업규모 (A,B,C,D 값을 넣는 것으로 알고 있습니다.) (선택)
- ZZIND03: 'B', // 기본값으로 B 설정
-
- // 24. J_1KFTBUS: 사업유형 (샘플에서는 "건설업외")
- J_1KFTBUS: '',
-
- // 25. J_1KFTIND: 산업유형 (샘플에서는 "제조업")
- J_1KFTIND: '',
-
- // 26. SMTP_ADDR: 대표 이메일 주소 (필수)
- SMTP_ADDR: requestData.representativeEmail || vendor[0].email || '',
-
- // 27. URI_ADDR: 웹사이트 주소 (선택)
- URI_ADDR: vendor[0].website || '',
-
- // 28. ZZCNAME1: 해당 벤더의 첫번째 유저의 이름 (영문) (선택)
- ZZCNAME1: requestData.representativeNameEng || '',
-
- // 29. ZZCNAME2: 해당 벤더의 첫번째 유저의 이름 (한글) (선택)
- ZZCNAME2: requestData.representativeNameKor || '',
-
- // 30. ZZTELF1_C: 해당 벤더의 첫번째 유저의 전화번호 (선택)
- ZZTELF1_C: requestData.representativeContact || '',
- };
-
- // MDG로 데이터 전송
- console.log('📤 MDG 송신 데이터:', mdgData);
- const result = await sendTestVendorDataToMDG(mdgData);
+ // sendSingleVendorToMDG 함수를 사용하여 MDG로 전송
+ // 정규 벤더 모드로 전송
+ console.log('📤 sendSingleVendorToMDG 호출 (정규 벤더 모드)');
+ const result = await sendSingleVendorToMDG({
+ vendorId: registration[0].vendorId,
+ mode: 'REGULAR_VENDOR'
+ });
console.log('📤 MDG 송신 결과:', result);
if (!result.success) {
- // 필수 필드 누락 에러인 경우 더 자세한 메시지 제공
- if (result.message.includes('필수 필드가 누락되었습니다')) {
- return {
- success: false,
- error: `MDG 송신 실패: ${result.message}\n\n누락된 필수 필드들을 확인하고 다시 시도해주세요.`
- };
- }
+ return {
+ success: false,
+ error: `MDG 송신 실패: ${result.message}`
+ };
}
return {
- success: result.success,
- message: result.success ?
- 'MDG로 정규업체 등록 요청이 성공적으로 전송되었습니다.' :
- `MDG 송신 실패: ${result.message}`,
- responseData: result.responseData,
- generatedXML: result.generatedXML
+ success: true,
+ message: 'MDG로 정규업체 등록 요청이 성공적으로 전송되었습니다.',
+ responseData: result.responseText,
+ generatedXML: result.requestXml
};
} catch (error) {
diff --git a/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-toolbar-actions.tsx b/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-toolbar-actions.tsx index f879f065..20cd3427 100644 --- a/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-toolbar-actions.tsx +++ b/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-toolbar-actions.tsx @@ -218,6 +218,8 @@ export function VendorRegularRegistrationsTableToolbarActions({ email: session.user.email || undefined, }, approvers: approvers, + attachments: attachments, // 첨부파일 전달 + title: title, // 미리보기에서 수정한 제목 전달 }); if (result.status === 'pending_approval') { @@ -322,6 +324,9 @@ export function VendorRegularRegistrationsTableToolbarActions({ email: session.user.email || undefined, }} onConfirm={handleApprovalSubmit} + enableAttachments={true} + maxAttachments={10} + maxFileSize={100 * 1024 * 1024} // 100MB /> )} </div> |
