diff options
Diffstat (limited to 'lib/knox-api/approval/approval.ts')
| -rw-r--r-- | lib/knox-api/approval/approval.ts | 603 |
1 files changed, 603 insertions, 0 deletions
diff --git a/lib/knox-api/approval/approval.ts b/lib/knox-api/approval/approval.ts new file mode 100644 index 00000000..6a21e113 --- /dev/null +++ b/lib/knox-api/approval/approval.ts @@ -0,0 +1,603 @@ +"use server" + +// Knox API Approval 서버 액션들 +// 가이드: lib/knox-api/approval/guide.html + +// ========== 타입 정의 ========== + +// 공통 응답 타입 +export interface BaseResponse { + result: string; +} + +// 결재 경로 타입 +export interface ApprovalLine { + epId?: string; + userId?: string; + emailAddress?: string; + seq: string; + role: string; // 기안(0), 결재(1), 합의(2), 후결(3), 병렬합의(4), 병렬결재(7), 통보(9) + aplnStatsCode: string; // 미결(0), 결재(1), 반려(2), 전결(3), 자동결재(5) + arbPmtYn: string; // 전결권한여부 + contentsMdfyPmtYn: string; // 본문수정권한여부 + aplnMdfyPmtYn: string; // 경로변경권한여부 + opinion?: string; // 상신의견 (상신자만) +} + +// 결재 상신 요청 타입 +export interface SubmitApprovalRequest { + contents: string; // 결재본문 + contentsType: string; // 본문종류 (TEXT, HTML, MIME) + docSecuType: string; // 보안문서타입 (PERSONAL, CONFIDENTIAL, CONFIDENTIAL_STRICT) + notifyOption: string; // 통보옵션 (0-3) + urgYn: string; // 긴급여부 (Y/N) + sbmDt: string; // 상신일시 (YYYYMMDDHHMMSS) + timeZone: string; // 타임존 (GMT, GMT+9 등) + docMngSaveCode: string; // 문서관리저장코드 (0: 안함, 1: 저장) + subject: string; // 결재제목 + sbmLang: string; // 상신언어 (ko, ja, zh, en) + apInfId: string; // 연계ID (32자리 고유값) + importantYn?: string; // 중요여부 (Y/N) + aplns: ApprovalLine[]; // 결재경로 + attachments?: File[]; // 첨부파일 +} + +// 결재 상신 응답 타입 +export interface SubmitApprovalResponse extends BaseResponse { + data: { + apInfId: string; + }; +} + +// 결재 상세 조회 응답 타입 +export interface ApprovalDetailResponse extends BaseResponse { + data: { + contentsType: string; + sbmDt: string; + sbmLang: string; + apInfId: string; + systemId: string; + notifyOption: string; + urgYn: string; + docSecuType: string; + status: string; // 암호화실패(-3), 암호화중(-2), 예약상신(-1), 보류(0), 진행중(1), 완결(2), 반려(3), 상신취소(4), 전결(5), 후완결(6) + timeZone: string; + subject: string; + aplns: any[]; + attachments?: any[]; + }; +} + +// 결재 본문 조회 응답 타입 +export interface ApprovalContentResponse extends BaseResponse { + data: { + contents: string; + contentsType: string; + apInfId: string; + }; +} + +// 결재 상황 조회 요청 타입 +export interface ApprovalStatusRequest { + apinfids: { apinfid: string }[]; +} + +// 결재 상황 조회 응답 타입 +export interface ApprovalStatusResponse extends BaseResponse { + data: { + apInfId: string; + docChgNum: string; + status: string; + }[]; +} + +// 상신 취소 응답 타입 +export interface CancelApprovalResponse extends BaseResponse { + data: { + apInfId: string; + }; +} + +// 개인 결재경로 목록 조회 응답 타입 +export interface OwnApprovalLineListResponse extends BaseResponse { + data: any[]; +} + +// 개인 결재경로 상세 조회 응답 타입 +export interface OwnApprovalLineDetailResponse extends BaseResponse { + data: any; +} + +// 상신함 리스트 조회 응답 타입 +export interface SubmissionListResponse extends BaseResponse { + data: any[]; +} + +// 연계 이력 조회 응답 타입 +export interface ApprovalHistoryResponse extends BaseResponse { + data: any[]; +} + +// 연계 ID 조회 응답 타입 +export interface ApprovalIdsResponse extends BaseResponse { + data: any[]; +} + +// ========== 서버 액션 함수들 ========== + +/** + * 결재 상신 + * POST /approval/api/v2.0/approvals/submit + */ +export async function submitApproval( + request: SubmitApprovalRequest, + systemId: string +): Promise<SubmitApprovalResponse> { + try { + const formData = new FormData(); + + // JSON 데이터 생성 + const approvalData = { + contents: request.contents, + contentsType: request.contentsType, + docSecuType: request.docSecuType, + notifyOption: request.notifyOption, + urgYn: request.urgYn, + sbmDt: request.sbmDt, + timeZone: request.timeZone, + docMngSaveCode: request.docMngSaveCode, + subject: request.subject, + sbmLang: request.sbmLang, + apInfId: request.apInfId, + importantYn: request.importantYn, + aplns: request.aplns + }; + + formData.append('approval', JSON.stringify(approvalData)); + + // 첨부파일 처리 + if (request.attachments) { + request.attachments.forEach((file) => { + formData.append('attachments', file); + }); + } + + const response = await fetch(`${process.env.KNOX_API_BASE_URL}/approval/api/v2.0/approvals/submit`, { + method: 'POST', + headers: { + 'System-ID': systemId, + }, + body: formData, + }); + + if (!response.ok) { + throw new Error(`결재 상신 실패: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error('결재 상신 오류:', error); + throw error; + } +} + +/** + * 보안 결재 상신 + * POST /approval/api/v2.0/approvals/secu-submit + */ +export async function submitSecurityApproval( + request: SubmitApprovalRequest, + systemId: string +): Promise<SubmitApprovalResponse> { + try { + const formData = new FormData(); + + // JSON 데이터 생성 + const approvalData = { + contents: request.contents, + contentsType: request.contentsType, + docSecuType: request.docSecuType, // CONFIDENTIAL 또는 CONFIDENTIAL_STRICT + notifyOption: request.notifyOption, + urgYn: request.urgYn, + sbmDt: request.sbmDt, + timeZone: request.timeZone, + docMngSaveCode: request.docMngSaveCode, + subject: request.subject, + sbmLang: request.sbmLang, + apInfId: request.apInfId, + importantYn: request.importantYn, + aplns: request.aplns + }; + + formData.append('approval', JSON.stringify(approvalData)); + + // 첨부파일 처리 + if (request.attachments) { + request.attachments.forEach((file) => { + formData.append('attachments', file); + }); + } + + const response = await fetch(`${process.env.KNOX_API_BASE_URL}/approval/api/v2.0/approvals/secu-submit`, { + method: 'POST', + headers: { + 'System-ID': systemId, + }, + body: formData, + }); + + if (!response.ok) { + throw new Error(`보안 결재 상신 실패: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error('보안 결재 상신 오류:', error); + throw error; + } +} + +/** + * 결재 상세 상황 조회 + * GET /approval/api/v2.0/approvals/{apInfId}/detail + */ +export async function getApprovalDetail( + apInfId: string, + systemId: string +): Promise<ApprovalDetailResponse> { + try { + const response = await fetch(`${process.env.KNOX_API_BASE_URL}/approval/api/v2.0/approvals/${apInfId}/detail`, { + method: 'GET', + headers: { + 'System-ID': systemId, + }, + }); + + if (!response.ok) { + throw new Error(`결재 상세 조회 실패: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error('결재 상세 조회 오류:', error); + throw error; + } +} + +/** + * 결재 본문 조회 + * GET /approval/api/v2.0/approvals/{apInfId}/content + */ +export async function getApprovalContent( + apInfId: string, + systemId: string +): Promise<ApprovalContentResponse> { + try { + const response = await fetch(`${process.env.KNOX_API_BASE_URL}/approval/api/v2.0/approvals/${apInfId}/content`, { + method: 'GET', + headers: { + 'System-ID': systemId, + }, + }); + + if (!response.ok) { + throw new Error(`결재 본문 조회 실패: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error('결재 본문 조회 오류:', error); + throw error; + } +} + +/** + * 결재 상황 조회 + * POST /approval/api/v2.0/approvals/status + */ +export async function getApprovalStatus( + request: ApprovalStatusRequest, + systemId: string +): Promise<ApprovalStatusResponse> { + try { + const response = await fetch(`${process.env.KNOX_API_BASE_URL}/approval/api/v2.0/approvals/status`, { + method: 'POST', + headers: { + 'System-ID': systemId, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(request.apinfids), + }); + + if (!response.ok) { + throw new Error(`결재 상황 조회 실패: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error('결재 상황 조회 오류:', error); + throw error; + } +} + +/** + * 결재 연계 ID 조회 + * GET /approval/api/v2.0/approvals/apinfids + */ +export async function getApprovalIds( + systemId: string, + apIds?: string[] +): Promise<ApprovalIdsResponse> { + try { + let url = `${process.env.KNOX_API_BASE_URL}/approval/api/v2.0/approvals/apinfids`; + + if (apIds && apIds.length > 0) { + const params = new URLSearchParams(); + apIds.forEach(id => params.append('apId', id)); + url += `?${params.toString()}`; + } + + const response = await fetch(url, { + method: 'GET', + headers: { + 'System-ID': systemId, + }, + }); + + if (!response.ok) { + throw new Error(`결재 연계 ID 조회 실패: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error('결재 연계 ID 조회 오류:', error); + throw error; + } +} + +/** + * 상신함 리스트 조회 + * GET /approval/api/v2.0/approvals/submission + */ +export async function getSubmissionList( + systemId: string, + params?: Record<string, string> +): Promise<SubmissionListResponse> { + try { + let url = `${process.env.KNOX_API_BASE_URL}/approval/api/v2.0/approvals/submission`; + + if (params) { + const searchParams = new URLSearchParams(params); + url += `?${searchParams.toString()}`; + } + + const response = await fetch(url, { + method: 'GET', + headers: { + 'System-ID': systemId, + }, + }); + + if (!response.ok) { + throw new Error(`상신함 리스트 조회 실패: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error('상신함 리스트 조회 오류:', error); + throw error; + } +} + +/** + * 연계 이력 조회 + * GET /approval/api/v2.0/approvals/apinfidinfos + */ +export async function getApprovalHistory( + systemId: string, + params?: Record<string, string> +): Promise<ApprovalHistoryResponse> { + try { + let url = `${process.env.KNOX_API_BASE_URL}/approval/api/v2.0/approvals/apinfidinfos`; + + if (params) { + const searchParams = new URLSearchParams(params); + url += `?${searchParams.toString()}`; + } + + const response = await fetch(url, { + method: 'GET', + headers: { + 'System-ID': systemId, + }, + }); + + if (!response.ok) { + throw new Error(`연계 이력 조회 실패: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error('연계 이력 조회 오류:', error); + throw error; + } +} + +/** + * 상신 취소 + * POST /approval/api/v2.0/approvals/{apInfId}/cancel + */ +export async function cancelApproval( + apInfId: string, + systemId: string +): Promise<CancelApprovalResponse> { + try { + const response = await fetch(`${process.env.KNOX_API_BASE_URL}/approval/api/v2.0/approvals/${apInfId}/cancel`, { + method: 'POST', + headers: { + 'System-ID': systemId, + }, + }); + + if (!response.ok) { + throw new Error(`상신 취소 실패: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error('상신 취소 오류:', error); + throw error; + } +} + +/** + * 저장된 결재경로 목록 조회 + * GET /approval/api/v2.0/approvals/ownaplnlist + */ +export async function getOwnApprovalLineList( + systemId: string, + params?: Record<string, string> +): Promise<OwnApprovalLineListResponse> { + try { + let url = `${process.env.KNOX_API_BASE_URL}/approval/api/v2.0/approvals/ownaplnlist`; + + if (params) { + const searchParams = new URLSearchParams(params); + url += `?${searchParams.toString()}`; + } + + const response = await fetch(url, { + method: 'GET', + headers: { + 'System-ID': systemId, + }, + }); + + if (!response.ok) { + throw new Error(`저장된 결재경로 목록 조회 실패: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error('저장된 결재경로 목록 조회 오류:', error); + throw error; + } +} + +/** + * 저장된 결재경로 상세 조회 + * GET /approval/api/v2.0/approvals/{pslAplnId}/ownaplndetail + */ +export async function getOwnApprovalLineDetail( + pslAplnId: string, + systemId: string +): Promise<OwnApprovalLineDetailResponse> { + try { + const response = await fetch(`${process.env.KNOX_API_BASE_URL}/approval/api/v2.0/approvals/${pslAplnId}/ownaplndetail`, { + method: 'GET', + headers: { + 'System-ID': systemId, + }, + }); + + if (!response.ok) { + throw new Error(`저장된 결재경로 상세 조회 실패: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error('저장된 결재경로 상세 조회 오류:', error); + throw error; + } +} + +// ========== 유틸리티 함수들 ========== + +/** + * 결재 상신 요청 데이터 생성 도우미 + */ +export async function createSubmitApprovalRequest( + contents: string, + subject: string, + approvalLines: ApprovalLine[], + options: Partial<SubmitApprovalRequest> = {} +): Promise<SubmitApprovalRequest> { + const now = new Date(); + const sbmDt = now.toISOString().replace(/[-:T]/g, '').slice(0, 14); + const apInfId = `${process.env.KNOX_SYSTEM_ID || 'DEFAULT'}${sbmDt}${Math.random().toString(36).substr(2, 9)}`.padEnd(32, '0'); + + return { + contents, + subject, + aplns: approvalLines, + contentsType: 'TEXT', + docSecuType: 'PERSONAL', + notifyOption: '0', + urgYn: 'N', + sbmDt, + timeZone: 'GMT+9', + docMngSaveCode: '0', + sbmLang: 'ko', + apInfId, + importantYn: 'N', + ...options + }; +} + +/** + * 결재 라인 생성 도우미 + */ +export async function createApprovalLine( + userInfo: { epId?: string; userId?: string; emailAddress?: string }, + role: string, + seq: string, + options: Partial<ApprovalLine> = {} +): Promise<ApprovalLine> { + return { + ...userInfo, + seq, + role, + aplnStatsCode: '0', + arbPmtYn: 'Y', + contentsMdfyPmtYn: 'Y', + aplnMdfyPmtYn: 'Y', + ...options + }; +} + +/** + * 결재 상태 문자열 변환 + */ +export async function getApprovalStatusText(status: string): Promise<string> { + const statusMap: Record<string, string> = { + '-3': '암호화실패', + '-2': '암호화중', + '-1': '예약상신', + '0': '보류', + '1': '진행중', + '2': '완결', + '3': '반려', + '4': '상신취소', + '5': '전결', + '6': '후완결' + }; + + return statusMap[status] || '알 수 없음'; +} + +/** + * 결재 역할 문자열 변환 + */ +export async function getApprovalRoleText(role: string): Promise<string> { + const roleMap: Record<string, string> = { + '0': '기안', + '1': '결재', + '2': '합의', + '3': '후결', + '4': '병렬합의', + '7': '병렬결재', + '9': '통보' + }; + + return roleMap[role] || '알 수 없음'; +} |
