summaryrefslogtreecommitdiff
path: root/lib/pos/get-pos.ts
blob: 6424b880e5fa66fc0d8182267f16aefb90e265e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
'use server';

import { XMLBuilder, XMLParser } from 'fast-xml-parser';
import { withSoapLogging } from '@/lib/soap/utils';
import type { GetEncryptDocumentumFileParams } from './types';
import { POS_SOAP_ENDPOINT } from './types';
import { debugLog, debugError, debugSuccess, debugProcess } from '@/lib/debug-utils';

/**
 * 문서 암호화 파일을 서버에 다운로드하고 경로를 반환하는 POS(Documentum) SOAP 액션
 * 반환값은 서버 내 파일 다운로드 경로입니다. (예: "asd_as_2509131735233768_OP02\asd_as_2509131735233768_OP02.tif")
 * 실제 파일은 \\60.100.99.123\ECM_NAS_PRM\Download\ 경로에 저장됩니다.
 */
export async function getEncryptDocumentumFile(
  params: GetEncryptDocumentumFileParams
): Promise<{
  success: boolean;
  result?: string;
  error?: string;
}> {
  try {
    const {
      objectID,
      sabun = 'EVM0236', // context2.txt에 따라 기본값 설정
      appCode = process.env.POS_APP_CODE || 'SO13', // 환경변수 사용
      fileCreateMode = 1, // context2.txt에 따라 기본값 변경
      securityLevel = 'SedamsClassID',
      isDesign = true, // context2.txt에 따라 기본값 변경
    } = params;

    debugLog(`🌐 POS SOAP API 호출 시작`, { 
      objectID, 
      sabun, 
      appCode, 
      fileCreateMode, 
      securityLevel, 
      isDesign,
      endpoint: POS_SOAP_ENDPOINT
    });

    // 1. SOAP Envelope 생성 (SOAP 1.2)
    debugProcess(`📄 SOAP Envelope 생성 중...`);
    const envelopeObj = {
      'soap12:Envelope': {
        '@_xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
        '@_xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
        '@_xmlns:soap12': 'http://www.w3.org/2003/05/soap-envelope',
        'soap12:Body': {
          GetEncryptDocumentumFile: {
            '@_xmlns': 'Sedams.WebServices.Documentum',
            objectID,
            sabun,
            appCode,
            fileCreateMode: String(fileCreateMode),
            securityLevel,
            isDesign: String(isDesign),
          },
        },
      },
    };

    const builder = new XMLBuilder({
      ignoreAttributes: false,
      attributeNamePrefix: '@_',
      format: false,
      suppressEmptyNode: true,
    });

    const xmlBody = builder.build(envelopeObj);
    debugLog(`📄 생성된 SOAP XML`, { 
      objectID, 
      xmlLength: xmlBody.length, 
      envelope: envelopeObj['soap12:Envelope']['soap12:Body'] 
    });

    // 2. SOAP 호출 (로그 포함)
    debugProcess(`🌐 SOAP 요청 전송 중... (${POS_SOAP_ENDPOINT})`);
    const responseText = await withSoapLogging(
      'OUTBOUND',
      'SEDAMS Documentum',
      'GetEncryptDocumentumFile',
      xmlBody,
      async () => {
        const res = await fetch(POS_SOAP_ENDPOINT, {
          method: 'POST',
          headers: {
            'Content-Type': 'text/xml; charset=utf-8',
            SOAPAction:
              '"Sedams.WebServices.Documentum/GetEncryptDocumentumFile"',
          },
          body: xmlBody,
        });

        const text = await res.text();
        debugLog(`🌐 HTTP 응답 수신`, { 
          objectID, 
          status: res.status, 
          statusText: res.statusText, 
          responseLength: text.length,
          headers: Object.fromEntries(res.headers.entries())
        });

        if (!res.ok) {
          debugError(`❌ HTTP 오류 응답`, { objectID, status: res.status, statusText: res.statusText, responseBody: text });
          throw new Error(`HTTP ${res.status}: ${res.statusText}`);
        }

        return text;
      }
    );

    debugSuccess(`✅ SOAP 응답 수신 완료 (응답 길이: ${responseText.length})`);

    // 3. 응답 XML 파싱
    debugProcess(`📝 XML 응답 파싱 중...`);
    const parser = new XMLParser({
      ignoreAttributes: false,
      attributeNamePrefix: '@_',
    });

    const parsed = parser.parse(responseText);
    debugLog(`📝 파싱된 XML 구조`, { 
      objectID, 
      parsedKeys: Object.keys(parsed),
      parsed: parsed 
    });

    let result: string | undefined;

    try {
      // SOAP 1.2 규격
      debugProcess(`🔍 SOAP 1.2 구조에서 결과 추출 시도...`);
      result =
        parsed['soap:Envelope']['soap:Body'][
          'GetEncryptDocumentumFileResponse'
        ]['GetEncryptDocumentumFileResult'];
      debugLog(`🎯 SOAP 1.2에서 결과 추출 성공`, { objectID, result });
    } catch (e1) {
      debugLog(`⚠️ SOAP 1.2 구조 추출 실패, Fallback 시도...`, { objectID, error: e1 });
      // Fallback: SOAP 1.1 또는 다른 응답 형태
      try {
        debugProcess(`🔍 SOAP 1.1 구조에서 결과 추출 시도...`);
        result =
          parsed['soap:Envelope']['soap:Body'][
            'GetEncryptDocumentumFileResponse'
          ]['GetEncryptDocumentumFileResult'];
        debugLog(`🎯 SOAP 1.1에서 결과 추출 성공`, { objectID, result });
      } catch (e2) {
        debugLog(`⚠️ SOAP 1.1 구조 추출 실패, 단순 string 시도...`, { objectID, error: e2 });
        // HTTP POST 응답 형태 (단순 string)
        try {
          debugProcess(`🔍 단순 string 구조에서 결과 추출 시도...`);
          result = parsed.string;
          debugLog(`🎯 단순 string에서 결과 추출 성공`, { objectID, result });
        } catch (e3) {
          debugError(`❌ 모든 파싱 방법 실패`, { objectID, errors: [e1, e2, e3], parsedStructure: parsed });
        }
      }
    }

    debugSuccess(`✅ POS API 호출 성공`, { objectID, result });
    return { success: true, result };
  } catch (error) {
    debugError('❌ POS SOAP 호출 실패', { 
      objectID: params.objectID, 
      error: error instanceof Error ? error.message : 'Unknown error',
      stack: error instanceof Error ? error.stack : undefined
    });
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error',
    };
  }
}