@connextable/popbill 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,1599 @@
1
+ import { PopbillErrorStage, PopbillErrorType, createInputValidationError, normalizePopbillError } from "@connextable/popbill-compat/errors";
2
+ import { normalizeOptionalString, normalizeRequiredString, toBoolean } from "@connextable/popbill-utils";
3
+ import { createTaxinvoicePromiseService } from "@connextable/popbill-compat/factory";
4
+ //#region src/services/tax-invoice/adapters/error.ts
5
+ /**
6
+ * TaxInvoice facade 메서드를 실행하고 예외를 `PopbillApiError`로 표준화합니다.
7
+ */
8
+ async function invokeTaxInvoiceMethod(context, operation, handler) {
9
+ try {
10
+ return await handler();
11
+ } catch (error) {
12
+ const throwableError = toThrowablePopbillError(normalizePopbillError(error, { operation }));
13
+ safelyDispatchError(context.onError, throwableError);
14
+ throw throwableError;
15
+ }
16
+ }
17
+ /**
18
+ * 에러 훅이 예외를 던져도 원래 API 에러를 보존하기 위해 안전하게 호출합니다.
19
+ */
20
+ function safelyDispatchError(handler, error) {
21
+ if (!handler) return;
22
+ try {
23
+ handler(error);
24
+ } catch {}
25
+ }
26
+ function toThrowablePopbillError(error) {
27
+ return Object.assign(new Error(error.message), error);
28
+ }
29
+ //#endregion
30
+ //#region src/services/tax-invoice/mappers/document.ts
31
+ /**
32
+ * modern 세금계산서 문서 입력을 compat 세금계산서 API 모델로 변환합니다.
33
+ */
34
+ function mapTaxInvoiceDocument(taxInvoiceDocumentInput) {
35
+ return removeUndefinedProperties$1({
36
+ writeSpecification: taxInvoiceDocumentInput.writeSpecificationEnabled,
37
+ writeDate: taxInvoiceDocumentInput.writtenDate,
38
+ chargeDirection: taxInvoiceDocumentInput.chargeDirection,
39
+ issueType: taxInvoiceDocumentInput.issueType,
40
+ purposeType: taxInvoiceDocumentInput.purposeType,
41
+ issueTiming: taxInvoiceDocumentInput.issueTimingCode,
42
+ taxType: taxInvoiceDocumentInput.taxType,
43
+ ...mapSupplierFields(taxInvoiceDocumentInput.supplier),
44
+ ...mapBuyerFields(taxInvoiceDocumentInput.buyer),
45
+ ...mapTrusteeFields(taxInvoiceDocumentInput.trustee),
46
+ taxTotal: taxInvoiceDocumentInput.paymentSummary?.totalTaxAmount,
47
+ supplyCostTotal: taxInvoiceDocumentInput.paymentSummary?.totalSupplyCostAmount,
48
+ totalAmount: taxInvoiceDocumentInput.paymentSummary?.totalAmount,
49
+ cash: taxInvoiceDocumentInput.paymentSummary?.cashAmount,
50
+ chkBill: taxInvoiceDocumentInput.paymentSummary?.checkAmount,
51
+ note: taxInvoiceDocumentInput.paymentSummary?.promissoryNoteAmount,
52
+ credit: taxInvoiceDocumentInput.paymentSummary?.creditAmount,
53
+ modifyCode: taxInvoiceDocumentInput.modification?.modificationReasonCode,
54
+ orgNTSConfirmNum: taxInvoiceDocumentInput.modification?.originalNationalTaxServiceConfirmationNumber,
55
+ serialNum: taxInvoiceDocumentInput.taxInvoiceSerialNumber,
56
+ remark1: taxInvoiceDocumentInput.remarkOne,
57
+ remark2: taxInvoiceDocumentInput.remarkTwo,
58
+ remark3: taxInvoiceDocumentInput.remarkThree,
59
+ kwon: taxInvoiceDocumentInput.bookVolumeNumber,
60
+ ho: taxInvoiceDocumentInput.bookIssueNumber,
61
+ businessLicenseYN: taxInvoiceDocumentInput.includeBusinessLicenseImage,
62
+ bankBookYN: taxInvoiceDocumentInput.includeBankBookImage,
63
+ detailList: taxInvoiceDocumentInput.lineItems?.map(mapLineItem),
64
+ addContactList: taxInvoiceDocumentInput.additionalContacts?.map(mapAdditionalContact)
65
+ });
66
+ }
67
+ /**
68
+ * modern 세금계산서 문서 입력 목록을 compat 세금계산서 API 모델 목록으로 변환합니다.
69
+ */
70
+ function mapTaxInvoiceDocuments(taxInvoiceDocumentInputs) {
71
+ return taxInvoiceDocumentInputs.map(mapTaxInvoiceDocument);
72
+ }
73
+ /**
74
+ * 공급자 입력을 raw 공급자 필드로 변환합니다.
75
+ */
76
+ function mapSupplierFields(supplierInput) {
77
+ if (!supplierInput) return {};
78
+ return removeUndefinedProperties$1({
79
+ invoicerCorpNum: supplierInput.businessNumber,
80
+ invoicerMgtKey: supplierInput.managementKey,
81
+ invoicerTaxRegID: supplierInput.taxRegistrationIdentifier,
82
+ invoicerCorpName: supplierInput.companyName,
83
+ invoicerCEOName: supplierInput.chiefExecutiveOfficerName,
84
+ invoicerAddr: supplierInput.address,
85
+ invoicerBizClass: supplierInput.businessClass,
86
+ invoicerBizType: supplierInput.businessType,
87
+ invoicerContactName: supplierInput.contactName,
88
+ invoicerTEL: supplierInput.telephoneNumber,
89
+ invoicerHP: supplierInput.mobilePhoneNumber,
90
+ invoicerEmail: supplierInput.emailAddress,
91
+ invoicerSMSSendYN: supplierInput.sendTextMessage,
92
+ invoicerPrintYN: supplierInput.printEnabled,
93
+ invoicerRDN: supplierInput.residentRegistrationNumber,
94
+ invoicerOLN: supplierInput.foreignerRegistrationNumber,
95
+ invoicerTaxNum: supplierInput.branchBusinessNumber,
96
+ invoicerPSerialNum: supplierInput.branchSerialNumber,
97
+ invoicerCorpCls: supplierInput.corporationClassification,
98
+ invoicerDeptName: supplierInput.departmentName
99
+ });
100
+ }
101
+ /**
102
+ * 공급받는자 입력을 raw 공급받는자 필드로 변환합니다.
103
+ */
104
+ function mapBuyerFields(buyerInput) {
105
+ if (!buyerInput) return {};
106
+ return removeUndefinedProperties$1({
107
+ invoiceeType: buyerInput.recipientType,
108
+ invoiceeCorpNum: buyerInput.businessNumber,
109
+ invoiceeMgtKey: buyerInput.managementKey,
110
+ invoiceeTaxRegID: buyerInput.taxRegistrationIdentifier,
111
+ invoiceeCorpName: buyerInput.companyName,
112
+ invoiceeCEOName: buyerInput.chiefExecutiveOfficerName,
113
+ invoiceeAddr: buyerInput.address,
114
+ invoiceeBizClass: buyerInput.businessClass,
115
+ invoiceeBizType: buyerInput.businessType,
116
+ invoiceeContactName1: buyerInput.contactName,
117
+ invoiceeTEL1: buyerInput.telephoneNumber,
118
+ invoiceeHP1: buyerInput.mobilePhoneNumber,
119
+ invoiceeEmail1: buyerInput.emailAddress,
120
+ invoiceeContactName2: buyerInput.secondaryContactName,
121
+ invoiceeTEL2: buyerInput.secondaryTelephoneNumber,
122
+ invoiceeHP2: buyerInput.secondaryMobilePhoneNumber,
123
+ invoiceeEmail2: buyerInput.secondaryEmailAddress,
124
+ invoiceeSMSSendYN: buyerInput.sendTextMessage,
125
+ invoiceePrintYN: buyerInput.printEnabled,
126
+ invoiceeRDN: buyerInput.residentRegistrationNumber,
127
+ invoiceeOLN: buyerInput.foreignerRegistrationNumber,
128
+ invoiceeTaxNum: buyerInput.branchBusinessNumber,
129
+ invoiceePSerialNum: buyerInput.branchSerialNumber,
130
+ invoiceeCorpCls: buyerInput.corporationClassification,
131
+ invoiceeDeptName1: buyerInput.primaryDepartmentName ?? buyerInput.departmentName,
132
+ invoiceeDeptName2: buyerInput.secondaryDepartmentName,
133
+ closeDownState: buyerInput.businessStatus,
134
+ closeDownStateDate: buyerInput.businessStatusDate
135
+ });
136
+ }
137
+ /**
138
+ * 수탁자 입력을 raw 수탁자 필드로 변환합니다.
139
+ */
140
+ function mapTrusteeFields(trusteeInput) {
141
+ if (!trusteeInput) return {};
142
+ return removeUndefinedProperties$1({
143
+ trusteeCorpNum: trusteeInput.businessNumber,
144
+ trusteeMgtKey: trusteeInput.managementKey,
145
+ trusteeTaxRegID: trusteeInput.taxRegistrationIdentifier,
146
+ trusteeCorpName: trusteeInput.companyName,
147
+ trusteeCEOName: trusteeInput.chiefExecutiveOfficerName,
148
+ trusteeAddr: trusteeInput.address,
149
+ trusteeBizClass: trusteeInput.businessClass,
150
+ trusteeBizType: trusteeInput.businessType,
151
+ trusteeContactName: trusteeInput.contactName,
152
+ trusteeTEL: trusteeInput.telephoneNumber,
153
+ trusteeHP: trusteeInput.mobilePhoneNumber,
154
+ trusteeEmail: trusteeInput.emailAddress,
155
+ trusteeSMSSendYN: trusteeInput.sendTextMessage,
156
+ trusteePrintYN: trusteeInput.printEnabled,
157
+ trusteeRDN: trusteeInput.residentRegistrationNumber,
158
+ trusteeOLN: trusteeInput.foreignerRegistrationNumber,
159
+ trusteeTaxNum: trusteeInput.branchBusinessNumber,
160
+ trusteePSerialNum: trusteeInput.branchSerialNumber,
161
+ trusteeCorpCls: trusteeInput.corporationClassification,
162
+ trusteeDeptName: trusteeInput.departmentName
163
+ });
164
+ }
165
+ /**
166
+ * 상세 품목 입력을 raw 상세 품목 모델로 변환합니다.
167
+ */
168
+ function mapLineItem(lineItemInput) {
169
+ return {
170
+ serialNum: lineItemInput.lineNumber,
171
+ purchaseDT: lineItemInput.transactionDate,
172
+ itemName: lineItemInput.itemName,
173
+ spec: lineItemInput.specification,
174
+ qty: lineItemInput.quantity,
175
+ unitCost: lineItemInput.unitCostAmount,
176
+ supplyCost: lineItemInput.supplyCostAmount,
177
+ tax: lineItemInput.taxAmount,
178
+ remark: lineItemInput.remark
179
+ };
180
+ }
181
+ /**
182
+ * 추가 담당자 입력을 raw 추가 담당자 모델로 변환합니다.
183
+ */
184
+ function mapAdditionalContact(additionalContactInput) {
185
+ return {
186
+ serialNum: additionalContactInput.sequenceNumber,
187
+ contactName: additionalContactInput.contactName,
188
+ email: additionalContactInput.emailAddress
189
+ };
190
+ }
191
+ /**
192
+ * 객체에서 `undefined` 값만 제거하여 API 요청 본문을 정리합니다.
193
+ */
194
+ function removeUndefinedProperties$1(sourceObject) {
195
+ const definedEntries = Object.entries(sourceObject).filter(([, value]) => value !== void 0);
196
+ return Object.fromEntries(definedEntries);
197
+ }
198
+ //#endregion
199
+ //#region src/services/tax-invoice/mappers/invoice-info.ts
200
+ /**
201
+ * compat `getInfo` 응답을 modern TaxInvoiceInfo로 변환합니다.
202
+ */
203
+ function mapTaxInvoiceInfo(response) {
204
+ return {
205
+ itemKey: response.itemKey,
206
+ taxType: response.taxType,
207
+ writtenDate: response.writeDate,
208
+ registeredAt: response.regDT,
209
+ issueType: response.issueType,
210
+ totalSupplyCost: response.supplyCostTotal,
211
+ totalTax: response.taxTotal,
212
+ purposeType: response.purposeType,
213
+ issuedAt: response.issueDT,
214
+ isLateIssued: toBoolean(response.lateIssueYN),
215
+ isOpen: toBoolean(response.openYN),
216
+ openedAt: response.openDT,
217
+ stateMemo: response.stateMemo,
218
+ stateCode: toRequiredStateCode(response.stateCode),
219
+ stateChangedAt: response.stateDT,
220
+ nationalTaxServiceConfirmationNumber: response.ntsconfirmNum,
221
+ nationalTaxServiceResult: response.ntsresult,
222
+ nationalTaxServiceSentAt: response.ntssendDT,
223
+ nationalTaxServiceResultReceivedAt: response.ntsresultDT,
224
+ nationalTaxServiceSendErrorCode: response.ntssendErrCode,
225
+ modificationCode: response.modifyCode,
226
+ isApiLinkedDocument: toBoolean(response.interOPYN),
227
+ supplierCompanyName: response.invoicerCorpName,
228
+ supplierBusinessNumber: response.invoicerCorpNum,
229
+ supplierManagementKey: response.invoicerMgtKey,
230
+ isSupplierPrinted: toBoolean(response.invoicerPrintYN),
231
+ buyerCompanyName: response.invoiceeCorpName,
232
+ buyerBusinessNumber: response.invoiceeCorpNum,
233
+ buyerManagementKey: response.invoiceeMgtKey,
234
+ isBuyerPrinted: toBoolean(response.invoiceePrintYN),
235
+ buyerBusinessStatus: response.closeDownState,
236
+ buyerBusinessStatusDate: response.closeDownStateDate,
237
+ trusteeCompanyName: response.trusteeCorpName,
238
+ trusteeBusinessNumber: response.trusteeCorpNum,
239
+ trusteeManagementKey: response.trusteeMgtKey,
240
+ isTrusteePrinted: response.trusteePrintYN === void 0 ? void 0 : toBoolean(response.trusteePrintYN)
241
+ };
242
+ }
243
+ function toRequiredStateCode(value) {
244
+ if (typeof value === "number" && Number.isFinite(value)) return value;
245
+ if (typeof value === "string") {
246
+ const normalizedNumber = Number(value);
247
+ if (Number.isFinite(normalizedNumber)) return normalizedNumber;
248
+ }
249
+ throw new Error(`유효하지 않은 stateCode 응답값입니다. (${String(value)})`);
250
+ }
251
+ //#endregion
252
+ //#region src/services/tax-invoice/types/document.ts
253
+ /**
254
+ * 세금계산서 과금 방향 값입니다.
255
+ */
256
+ const TaxInvoiceChargeDirectionValues = {
257
+ /**
258
+ * 값: `정과금`, 의미: 공급자에게 과금되는 일반 방향
259
+ */
260
+ NormalCharge: "정과금",
261
+ /**
262
+ * 값: `역과금`, 의미: 공급받는자에게 과금되는 역방향
263
+ */
264
+ ReverseCharge: "역과금"
265
+ };
266
+ /**
267
+ * 세금계산서 발행 형태 값입니다.
268
+ */
269
+ const TaxInvoiceIssueTypes = {
270
+ /**
271
+ * 값: `정발행`, 의미: 공급자 중심의 일반 발행
272
+ */
273
+ Normal: "정발행",
274
+ /**
275
+ * 값: `역발행`, 의미: 공급받는자 요청 기반 발행
276
+ */
277
+ Reverse: "역발행",
278
+ /**
279
+ * 값: `위수탁`, 의미: 수탁자 대행 발행
280
+ */
281
+ Trustee: "위수탁"
282
+ };
283
+ /**
284
+ * 세금계산서 영수/청구 값입니다.
285
+ */
286
+ const TaxInvoicePurposeTypes = {
287
+ /**
288
+ * 값: `영수`, 의미: 영수 목적
289
+ */
290
+ Receipt: "영수",
291
+ /**
292
+ * 값: `청구`, 의미: 청구 목적
293
+ */
294
+ Claim: "청구",
295
+ /**
296
+ * 값: `없음`, 의미: 목적 구분 없음
297
+ */
298
+ None: "없음"
299
+ };
300
+ /**
301
+ * 세금계산서 과세 유형 값입니다.
302
+ */
303
+ const TaxInvoiceTaxationTypes = {
304
+ /**
305
+ * 값: `과세`, 의미: 일반 과세
306
+ */
307
+ Taxable: "과세",
308
+ /**
309
+ * 값: `영세`, 의미: 영세율
310
+ */
311
+ ZeroRated: "영세",
312
+ /**
313
+ * 값: `면세`, 의미: 면세
314
+ */
315
+ Exempt: "면세"
316
+ };
317
+ /**
318
+ * 공급받는자 구분 값입니다.
319
+ */
320
+ const TaxInvoiceRecipientTypes = {
321
+ /**
322
+ * 값: `사업자`, 의미: 사업자 번호 기반
323
+ */
324
+ Business: "사업자",
325
+ /**
326
+ * 값: `개인`, 의미: 주민등록번호 기반
327
+ */
328
+ Individual: "개인",
329
+ /**
330
+ * 값: `외국인`, 의미: 외국인 식별번호 기반
331
+ */
332
+ Foreigner: "외국인"
333
+ };
334
+ /**
335
+ * 공급받는자 휴폐업 상태 값입니다.
336
+ */
337
+ const TaxInvoiceBusinessStatusValues = {
338
+ /**
339
+ * 값: `null`, 의미: 미확인
340
+ */
341
+ NotChecked: null,
342
+ /**
343
+ * 값: `0`, 의미: 미등록
344
+ */
345
+ NotRegistered: 0,
346
+ /**
347
+ * 값: `1`, 의미: 사업중
348
+ */
349
+ Operating: 1,
350
+ /**
351
+ * 값: `2`, 의미: 폐업
352
+ */
353
+ Closed: 2,
354
+ /**
355
+ * 값: `3`, 의미: 휴업
356
+ */
357
+ Suspended: 3,
358
+ /**
359
+ * 값: `4`, 의미: 확인실패
360
+ */
361
+ CheckFailed: 4
362
+ };
363
+ /**
364
+ * 수정세금계산서 사유코드 값입니다.
365
+ */
366
+ const TaxInvoiceModificationReasonCodes = {
367
+ /**
368
+ * 값: `1`, 의미: 기재사항 착오 정정
369
+ */
370
+ CorrectingEntryErrors: 1,
371
+ /**
372
+ * 값: `2`, 의미: 공급가액 변동
373
+ */
374
+ SupplyAmountAdjustment: 2,
375
+ /**
376
+ * 값: `3`, 의미: 환입
377
+ */
378
+ Return: 3,
379
+ /**
380
+ * 값: `4`, 의미: 계약의 해제
381
+ */
382
+ ContractCancellation: 4,
383
+ /**
384
+ * 값: `5`, 의미: 내국신용장 사후 개설
385
+ */
386
+ PostIssuedDomesticLetterOfCredit: 5,
387
+ /**
388
+ * 값: `6`, 의미: 착오에 의한 이중 발급
389
+ */
390
+ DuplicateIssuanceByMistake: 6
391
+ };
392
+ //#endregion
393
+ //#region src/services/tax-invoice/types/response.ts
394
+ /**
395
+ * 초대량 처리 상태 값입니다.
396
+ */
397
+ const TaxInvoiceBulkIssueSubmissionTransactionStates = {
398
+ /**
399
+ * 값: `0`, 의미: 미처리 상태
400
+ */
401
+ NotProcessed: 0,
402
+ /**
403
+ * 값: `1`, 의미: 처리중 상태
404
+ */
405
+ Processing: 1,
406
+ /**
407
+ * 값: `2`, 의미: 완료 상태
408
+ */
409
+ Completed: 2
410
+ };
411
+ //#endregion
412
+ //#region src/services/tax-invoice/types/index.ts
413
+ /**
414
+ * 세금계산서 문서번호 유형 상수입니다.
415
+ */
416
+ const TaxInvoiceDocumentKeyTypes = {
417
+ /**
418
+ * 코드: `SELL`, 설명: 매출 문서번호 유형
419
+ */
420
+ Sales: "SELL",
421
+ /**
422
+ * 코드: `BUY`, 설명: 매입 문서번호 유형
423
+ */
424
+ Purchase: "BUY",
425
+ /**
426
+ * 코드: `TRUSTEE`, 설명: 위수탁 문서번호 유형
427
+ */
428
+ Trustee: "TRUSTEE"
429
+ };
430
+ /**
431
+ * 세금계산서 문서함 범위 상수입니다.
432
+ */
433
+ const TaxInvoiceBoxScopes = {
434
+ /**
435
+ * 코드: `TBOX`, 설명: 임시 문서함
436
+ */
437
+ TemporaryDocumentBox: "TBOX",
438
+ /**
439
+ * 코드: `SWBOX`, 설명: 매출 발행 대기함
440
+ */
441
+ SalesIssueWaitingBox: "SWBOX",
442
+ /**
443
+ * 코드: `SBOX`, 설명: 매출 문서함
444
+ */
445
+ SalesDocumentBox: "SBOX",
446
+ /**
447
+ * 코드: `PWBOX`, 설명: 매입 발행 대기함
448
+ */
449
+ PurchaseIssueWaitingBox: "PWBOX",
450
+ /**
451
+ * 코드: `PBOX`, 설명: 매입 문서함
452
+ */
453
+ PurchaseDocumentBox: "PBOX",
454
+ /**
455
+ * 코드: `WRITE`, 설명: 정발행 작성
456
+ */
457
+ WriteInvoice: "WRITE"
458
+ };
459
+ /**
460
+ * 검색일자 유형 상수입니다.
461
+ */
462
+ const TaxInvoiceDateType = {
463
+ /**
464
+ * 코드: `R`, 설명: 등록일자
465
+ */
466
+ Registered: "R",
467
+ /**
468
+ * 코드: `W`, 설명: 작성일자
469
+ */
470
+ Written: "W",
471
+ /**
472
+ * 코드: `I`, 설명: 발행일자
473
+ */
474
+ Issued: "I"
475
+ };
476
+ /**
477
+ * 검색 정렬 방향 상수입니다.
478
+ */
479
+ const TaxInvoiceSortOrder = {
480
+ /**
481
+ * 코드: `D`, 설명: 내림차순
482
+ */
483
+ Descending: "D",
484
+ /**
485
+ * 코드: `A`, 설명: 오름차순
486
+ */
487
+ Ascending: "A"
488
+ };
489
+ /**
490
+ * 검색 문서유형 코드 상수입니다.
491
+ */
492
+ const TaxInvoiceSearchInvoiceTypeCodes = {
493
+ /**
494
+ * 코드: `N`, 설명: 세금계산서
495
+ */
496
+ Normal: "N",
497
+ /**
498
+ * 코드: `M`, 설명: 수정세금계산서
499
+ */
500
+ Modified: "M"
501
+ };
502
+ /**
503
+ * 검색 과세형태 코드 상수입니다.
504
+ */
505
+ const TaxInvoiceSearchTaxationTypeCodes = {
506
+ /**
507
+ * 코드: `T`, 설명: 과세
508
+ */
509
+ Taxable: "T",
510
+ /**
511
+ * 코드: `N`, 설명: 면세
512
+ */
513
+ Exempt: "N",
514
+ /**
515
+ * 코드: `Z`, 설명: 영세
516
+ */
517
+ ZeroRated: "Z"
518
+ };
519
+ /**
520
+ * 검색 발행형태 코드 상수입니다.
521
+ */
522
+ const TaxInvoiceSearchIssueTypeCodes = {
523
+ /**
524
+ * 코드: `N`, 설명: 정발행
525
+ */
526
+ Normal: "N",
527
+ /**
528
+ * 코드: `R`, 설명: 역발행
529
+ */
530
+ Reverse: "R",
531
+ /**
532
+ * 코드: `T`, 설명: 위수탁
533
+ */
534
+ Trustee: "T"
535
+ };
536
+ /**
537
+ * 검색 종사업장번호 주체 코드 상수입니다.
538
+ */
539
+ const TaxInvoiceSearchTaxRegistrationIdentifierTypes = {
540
+ /**
541
+ * 코드: `S`, 설명: 공급자
542
+ */
543
+ Supplier: "S",
544
+ /**
545
+ * 코드: `B`, 설명: 공급받는자
546
+ */
547
+ Buyer: "B",
548
+ /**
549
+ * 코드: `T`, 설명: 수탁자
550
+ */
551
+ Trustee: "T"
552
+ };
553
+ /**
554
+ * 검색 종사업장번호 유무 코드 상수입니다.
555
+ */
556
+ const TaxInvoiceSearchTaxRegistrationIdentifierAvailabilities = {
557
+ /**
558
+ * 코드: `0`, 설명: 종사업장번호 없음
559
+ */
560
+ No: "0",
561
+ /**
562
+ * 코드: `1`, 설명: 종사업장번호 있음
563
+ */
564
+ Yes: "1"
565
+ };
566
+ /**
567
+ * 검색 작성유형 코드 상수입니다.
568
+ */
569
+ const TaxInvoiceSearchInteroperabilityTypes = {
570
+ /**
571
+ * 코드: `0`, 설명: 팝빌 웹 작성
572
+ */
573
+ PopbillWeb: "0",
574
+ /**
575
+ * 코드: `1`, 설명: API 작성
576
+ */
577
+ Api: "1"
578
+ };
579
+ /**
580
+ * 검색 등록유형 코드 상수입니다.
581
+ */
582
+ const TaxInvoiceSearchRegistrationTypeCodes = {
583
+ /**
584
+ * 코드: `P`, 설명: 팝빌 등록(발행)
585
+ */
586
+ Popbill: "P",
587
+ /**
588
+ * 코드: `H`, 설명: 홈택스/ASP 등록(발행)
589
+ */
590
+ HomeTax: "H"
591
+ };
592
+ /**
593
+ * 검색 조건의 휴폐업 상태 상수입니다.
594
+ */
595
+ const TaxInvoiceCloseDownStateCodes = {
596
+ /**
597
+ * 코드: `N`, 설명: 미확인
598
+ */
599
+ NotChecked: "N",
600
+ /**
601
+ * 코드: `0`, 설명: 미등록
602
+ */
603
+ NotRegistered: "0",
604
+ /**
605
+ * 코드: `1`, 설명: 사업중
606
+ */
607
+ Operating: "1",
608
+ /**
609
+ * 코드: `2`, 설명: 폐업
610
+ */
611
+ Closed: "2",
612
+ /**
613
+ * 코드: `3`, 설명: 휴업
614
+ */
615
+ Suspended: "3",
616
+ /**
617
+ * 코드: `4`, 설명: 확인실패
618
+ */
619
+ CheckFailed: "4"
620
+ };
621
+ /**
622
+ * 전자명세서 문서유형 코드 상수입니다.
623
+ */
624
+ const TaxInvoiceStatementItemCodes = {
625
+ /**
626
+ * 코드: `121`, 설명: 거래명세서
627
+ */
628
+ TradeStatement: 121,
629
+ /**
630
+ * 코드: `122`, 설명: 청구서
631
+ */
632
+ Invoice: 122,
633
+ /**
634
+ * 코드: `123`, 설명: 견적서
635
+ */
636
+ Estimate: 123,
637
+ /**
638
+ * 코드: `124`, 설명: 발주서
639
+ */
640
+ PurchaseOrder: 124,
641
+ /**
642
+ * 코드: `125`, 설명: 입금표
643
+ */
644
+ Deposit: 125,
645
+ /**
646
+ * 코드: `126`, 설명: 영수증
647
+ */
648
+ Receipt: 126
649
+ };
650
+ /**
651
+ * 메일 전송 유형 코드 상수입니다.
652
+ */
653
+ const TaxInvoiceEmailTypes = {
654
+ /**
655
+ * 코드: `ETC_CERT_EXPIRATION`, 설명: 인증서 만료 안내
656
+ */
657
+ EtcCertExpiration: "ETC_CERT_EXPIRATION",
658
+ /**
659
+ * 코드: `TAX_CANCEL_ISSUE`, 설명: 발행취소
660
+ */
661
+ TaxCancelIssue: "TAX_CANCEL_ISSUE",
662
+ /**
663
+ * 코드: `TAX_CANCEL_REQUEST`, 설명: 역발행 요청 취소
664
+ */
665
+ TaxCancelRequest: "TAX_CANCEL_REQUEST",
666
+ /**
667
+ * 코드: `TAX_CHECK`, 설명: 수신확인
668
+ */
669
+ TaxCheck: "TAX_CHECK",
670
+ /**
671
+ * 코드: `TAX_CLOSEDOWN`, 설명: 휴폐업 알림
672
+ */
673
+ TaxClosedown: "TAX_CLOSEDOWN",
674
+ /**
675
+ * 코드: `TAX_ISSUE`, 설명: 발행완료(수신자)
676
+ */
677
+ TaxIssue: "TAX_ISSUE",
678
+ /**
679
+ * 코드: `TAX_ISSUE_INVOICER`, 설명: 발행완료(공급자)
680
+ */
681
+ TaxIssueInvoicer: "TAX_ISSUE_INVOICER",
682
+ /**
683
+ * 코드: `TAX_NTSFAIL_INVOICER`, 설명: 국세청 전송실패(공급자)
684
+ */
685
+ TaxNtsFailInvoicer: "TAX_NTSFAIL_INVOICER",
686
+ /**
687
+ * 코드: `TAX_REFUSE`, 설명: 역발행 거부
688
+ */
689
+ TaxRefuse: "TAX_REFUSE",
690
+ /**
691
+ * 코드: `TAX_REQUEST`, 설명: 역발행 요청
692
+ */
693
+ TaxRequest: "TAX_REQUEST",
694
+ /**
695
+ * 코드: `TAX_REVERSE_ISSUE`, 설명: 역발행 완료
696
+ */
697
+ TaxReverseIssue: "TAX_REVERSE_ISSUE",
698
+ /**
699
+ * 코드: `TAX_TRUST_CANCEL_ISSUE`, 설명: 위수탁 발행취소
700
+ */
701
+ TaxTrustCancelIssue: "TAX_TRUST_CANCEL_ISSUE",
702
+ /**
703
+ * 코드: `TAX_TRUST_CANCEL_ISSUE_INVOICER`, 설명: 위수탁 발행취소(공급자)
704
+ */
705
+ TaxTrustCancelIssueInvoicer: "TAX_TRUST_CANCEL_ISSUE_INVOICER",
706
+ /**
707
+ * 코드: `TAX_TRUST_ISSUE`, 설명: 위수탁 발행완료
708
+ */
709
+ TaxTrustIssue: "TAX_TRUST_ISSUE",
710
+ /**
711
+ * 코드: `TAX_TRUST_ISSUE_INVOICER`, 설명: 위수탁 발행완료(공급자)
712
+ */
713
+ TaxTrustIssueInvoicer: "TAX_TRUST_ISSUE_INVOICER",
714
+ /**
715
+ * 코드: `TAX_TRUST_ISSUE_TRUSTEE`, 설명: 위수탁 발행완료(수탁자)
716
+ */
717
+ TaxTrustIssueTrustee: "TAX_TRUST_ISSUE_TRUSTEE",
718
+ /**
719
+ * 코드: `TAX_ACCEPT`, 설명: 역발행 승인(legacy)
720
+ */
721
+ TaxAccept: "TAX_ACCEPT",
722
+ /**
723
+ * 코드: `TAX_DENY`, 설명: 역발행 거부(legacy)
724
+ */
725
+ TaxDeny: "TAX_DENY",
726
+ /**
727
+ * 코드: `TAX_CANCEL_SEND`, 설명: 발행안함 취소(legacy)
728
+ */
729
+ TaxCancelSend: "TAX_CANCEL_SEND"
730
+ };
731
+ /**
732
+ * 수정세금계산서 사유코드입니다.
733
+ */
734
+ const TaxInvoiceModificationCodes = TaxInvoiceModificationReasonCodes;
735
+ //#endregion
736
+ //#region src/services/tax-invoice/mappers/response.ts
737
+ /**
738
+ * 공통 API 처리결과를 도메인 처리결과로 변환합니다.
739
+ */
740
+ function mapTaxInvoiceOperationResult(taxInvoiceApiResponse) {
741
+ return {
742
+ resultCode: toRequiredNumber(taxInvoiceApiResponse.code, "code"),
743
+ resultMessage: taxInvoiceApiResponse.message
744
+ };
745
+ }
746
+ /**
747
+ * 발행 결과를 도메인 발행 결과로 변환합니다.
748
+ */
749
+ function mapTaxInvoiceIssueResult(taxInvoiceApiResponse) {
750
+ return removeUndefinedProperties({
751
+ ...mapTaxInvoiceOperationResult(taxInvoiceApiResponse),
752
+ nationalTaxServiceConfirmationNumber: taxInvoiceApiResponse.ntsConfirmNum,
753
+ issuedAt: taxInvoiceApiResponse.issueDT
754
+ });
755
+ }
756
+ /**
757
+ * 초대량 접수 결과를 도메인 결과로 변환합니다.
758
+ */
759
+ function mapTaxInvoiceBulkSubmitResult(taxInvoiceApiResponse) {
760
+ return removeUndefinedProperties({
761
+ ...mapTaxInvoiceOperationResult(taxInvoiceApiResponse),
762
+ receiptIdentifier: taxInvoiceApiResponse.receiptID
763
+ });
764
+ }
765
+ /**
766
+ * 초대량 접수결과 조회 응답을 도메인 결과로 변환합니다.
767
+ */
768
+ function mapTaxInvoiceBulkIssueSubmissionResult(taxInvoiceApiResponse) {
769
+ return removeUndefinedProperties({
770
+ ...mapTaxInvoiceOperationResult(taxInvoiceApiResponse),
771
+ receiptIdentifier: taxInvoiceApiResponse.receiptID,
772
+ submissionIdentifier: taxInvoiceApiResponse.submitID,
773
+ submittedDocumentCount: toOptionalNumber(taxInvoiceApiResponse.submitCount),
774
+ succeededDocumentCount: toOptionalNumber(taxInvoiceApiResponse.successCount),
775
+ failedDocumentCount: toOptionalNumber(taxInvoiceApiResponse.failCount),
776
+ transactionState: toOptionalNumber(taxInvoiceApiResponse.txState),
777
+ transactionStartedAt: taxInvoiceApiResponse.txStartDT,
778
+ transactionCompletedAt: taxInvoiceApiResponse.txEndDT,
779
+ transactionResultCode: toOptionalNumber(taxInvoiceApiResponse.txResultCode),
780
+ issueResults: taxInvoiceApiResponse.issueResult?.map(mapTaxInvoiceBulkIssueSubmissionResultItem)
781
+ });
782
+ }
783
+ /**
784
+ * 다건 문서 요약 응답을 도메인 목록으로 변환합니다.
785
+ */
786
+ function mapTaxInvoiceInfos(taxInvoiceApiResponse) {
787
+ return taxInvoiceApiResponse.map(mapTaxInvoiceInfo);
788
+ }
789
+ /**
790
+ * 문서 상세 응답을 도메인 문서 상세로 변환합니다.
791
+ */
792
+ function mapTaxInvoiceDocumentOutput(taxInvoiceApiResponse) {
793
+ return removeUndefinedProperties({
794
+ writeSpecificationEnabled: taxInvoiceApiResponse.writeSpecification,
795
+ writtenDate: taxInvoiceApiResponse.writeDate,
796
+ chargeDirection: toTaxInvoiceChargeDirection(taxInvoiceApiResponse.chargeDirection),
797
+ issueType: taxInvoiceApiResponse.issueType,
798
+ purposeType: taxInvoiceApiResponse.purposeType,
799
+ issueTimingCode: taxInvoiceApiResponse.issueTiming,
800
+ taxType: taxInvoiceApiResponse.taxType,
801
+ supplier: mapSupplierOutput(taxInvoiceApiResponse),
802
+ buyer: mapBuyerOutput(taxInvoiceApiResponse),
803
+ trustee: mapTrusteeOutput(taxInvoiceApiResponse),
804
+ paymentSummary: removeUndefinedProperties({
805
+ totalTaxAmount: taxInvoiceApiResponse.taxTotal,
806
+ totalSupplyCostAmount: taxInvoiceApiResponse.supplyCostTotal,
807
+ totalAmount: taxInvoiceApiResponse.totalAmount,
808
+ cashAmount: taxInvoiceApiResponse.cash,
809
+ checkAmount: taxInvoiceApiResponse.chkBill,
810
+ promissoryNoteAmount: taxInvoiceApiResponse.note,
811
+ creditAmount: taxInvoiceApiResponse.credit
812
+ }),
813
+ modification: removeUndefinedProperties({
814
+ modificationReasonCode: taxInvoiceApiResponse.modifyCode,
815
+ originalNationalTaxServiceConfirmationNumber: taxInvoiceApiResponse.orgNTSConfirmNum
816
+ }),
817
+ taxInvoiceSerialNumber: taxInvoiceApiResponse.serialNum,
818
+ remarkOne: taxInvoiceApiResponse.remark1,
819
+ remarkTwo: taxInvoiceApiResponse.remark2,
820
+ remarkThree: taxInvoiceApiResponse.remark3,
821
+ bookVolumeNumber: taxInvoiceApiResponse.kwon,
822
+ bookIssueNumber: taxInvoiceApiResponse.ho,
823
+ includeBusinessLicenseImage: toOptionalBoolean(taxInvoiceApiResponse.businessLicenseYN),
824
+ includeBankBookImage: toOptionalBoolean(taxInvoiceApiResponse.bankBookYN),
825
+ lineItems: taxInvoiceApiResponse.detailList?.map((lineItem) => removeUndefinedProperties({
826
+ lineNumber: lineItem.serialNum,
827
+ transactionDate: lineItem.purchaseDT,
828
+ itemName: lineItem.itemName,
829
+ specification: lineItem.spec,
830
+ quantity: lineItem.qty,
831
+ unitCostAmount: lineItem.unitCost,
832
+ supplyCostAmount: lineItem.supplyCost,
833
+ taxAmount: lineItem.tax,
834
+ remark: lineItem.remark
835
+ })),
836
+ additionalContacts: taxInvoiceApiResponse.addContactList?.map((additionalContact) => removeUndefinedProperties({
837
+ sequenceNumber: additionalContact.serialNum,
838
+ contactName: additionalContact.contactName,
839
+ emailAddress: additionalContact.email
840
+ })),
841
+ issuedAt: taxInvoiceApiResponse.issueDT,
842
+ stateCode: toOptionalNumber(taxInvoiceApiResponse.stateCode),
843
+ stateChangedAt: taxInvoiceApiResponse.stateDT,
844
+ isLateIssued: toOptionalBoolean(taxInvoiceApiResponse.lateIssueYN),
845
+ isOpen: toOptionalBoolean(taxInvoiceApiResponse.openYN),
846
+ openedAt: taxInvoiceApiResponse.openDT,
847
+ nationalTaxServiceConfirmationNumber: taxInvoiceApiResponse.ntsconfirmNum,
848
+ nationalTaxServiceResultCode: taxInvoiceApiResponse.ntsresult,
849
+ nationalTaxServiceSentAt: taxInvoiceApiResponse.ntssendDT,
850
+ nationalTaxServiceResultReceivedAt: taxInvoiceApiResponse.ntsresultDT,
851
+ nationalTaxServiceSendErrorCode: taxInvoiceApiResponse.ntssendErrCode,
852
+ isApiLinkedDocument: toOptionalBoolean(taxInvoiceApiResponse.interOPYN)
853
+ });
854
+ }
855
+ /**
856
+ * 문서번호 사용 여부 응답을 도메인 결과로 변환합니다.
857
+ */
858
+ function mapTaxInvoiceInvoiceManagementKeyUsage(taxInvoiceApiResponse) {
859
+ if (typeof taxInvoiceApiResponse === "boolean") return { isInUse: taxInvoiceApiResponse };
860
+ return removeUndefinedProperties({
861
+ isInUse: typeof taxInvoiceApiResponse.itemKey === "string" && taxInvoiceApiResponse.itemKey.length > 0,
862
+ itemKey: taxInvoiceApiResponse.itemKey
863
+ });
864
+ }
865
+ /**
866
+ * XML 조회 응답을 도메인 결과로 변환합니다.
867
+ */
868
+ function mapTaxInvoiceXmlResult(taxInvoiceApiResponse) {
869
+ return removeUndefinedProperties({
870
+ operationResult: taxInvoiceApiResponse.code === void 0 || taxInvoiceApiResponse.message === void 0 ? void 0 : mapTaxInvoiceOperationResult({
871
+ code: taxInvoiceApiResponse.code,
872
+ message: taxInvoiceApiResponse.message
873
+ }),
874
+ itemKey: taxInvoiceApiResponse.itemKey,
875
+ invoiceManagementKey: taxInvoiceApiResponse.mgtKey,
876
+ xmlContent: taxInvoiceApiResponse.retObject
877
+ });
878
+ }
879
+ /**
880
+ * 검색 응답을 도메인 검색 결과로 변환합니다.
881
+ */
882
+ function mapTaxInvoiceSearchResult(taxInvoiceApiResponse) {
883
+ return removeUndefinedProperties({
884
+ operationResult: mapTaxInvoiceOperationResult(taxInvoiceApiResponse),
885
+ totalCount: toOptionalNumber(taxInvoiceApiResponse.total),
886
+ pageSize: toOptionalNumber(taxInvoiceApiResponse.perPage),
887
+ pageNumber: toOptionalNumber(taxInvoiceApiResponse.pageNum),
888
+ pageCount: toOptionalNumber(taxInvoiceApiResponse.pageCount),
889
+ invoiceSummaries: (taxInvoiceApiResponse.list ?? []).map(mapTaxInvoiceInfo)
890
+ });
891
+ }
892
+ /**
893
+ * 문서 로그 응답을 도메인 로그 목록으로 변환합니다.
894
+ */
895
+ function mapTaxInvoiceLogs(taxInvoiceApiResponse) {
896
+ return taxInvoiceApiResponse.map((logEntry) => removeUndefinedProperties({
897
+ documentLogTypeCode: toOptionalNumber(logEntry.docLogType),
898
+ logMessage: logEntry.log,
899
+ processTypeCode: logEntry.procType,
900
+ processCompanyName: logEntry.procCorpName,
901
+ processContactName: logEntry.procContactName,
902
+ processDescription: logEntry.procMemo,
903
+ registeredAt: logEntry.regDT,
904
+ ipAddress: logEntry.ip
905
+ }));
906
+ }
907
+ /**
908
+ * URL 문자열을 URL 응답으로 래핑합니다.
909
+ */
910
+ function mapTaxInvoiceAccessUrlFromString(accessUrl) {
911
+ return { accessUrl };
912
+ }
913
+ /**
914
+ * URL 객체를 URL 응답으로 변환합니다.
915
+ */
916
+ function mapTaxInvoiceAccessUrl(taxInvoiceApiResponse) {
917
+ return { accessUrl: taxInvoiceApiResponse.url };
918
+ }
919
+ /**
920
+ * 첨부파일 목록 응답을 도메인 목록으로 변환합니다.
921
+ */
922
+ function mapTaxInvoiceAttachedFiles(taxInvoiceApiResponse) {
923
+ return taxInvoiceApiResponse.map((attachedFile) => removeUndefinedProperties({
924
+ sequenceNumber: attachedFile.serialNum,
925
+ fileIdentifier: attachedFile.attachedFile,
926
+ displayName: attachedFile.displayName,
927
+ registeredAt: attachedFile.regDT
928
+ }));
929
+ }
930
+ /**
931
+ * 이메일 전송설정 응답을 도메인 목록으로 변환합니다.
932
+ */
933
+ function mapTaxInvoiceEmailSendSettings(taxInvoiceApiResponse) {
934
+ return taxInvoiceApiResponse.map((emailSendSetting) => removeUndefinedProperties({
935
+ emailTypeCode: emailSendSetting.emailType,
936
+ sendEnabled: toOptionalBoolean(emailSendSetting.sendYN)
937
+ }));
938
+ }
939
+ /**
940
+ * 국세청 전송설정 응답을 도메인 설정으로 변환합니다.
941
+ */
942
+ function mapTaxInvoiceSendToNationalTaxServiceSetting(taxInvoiceApiResponse) {
943
+ return { sendToNationalTaxServiceEnabled: toBoolean(taxInvoiceApiResponse.sendToNTS) };
944
+ }
945
+ /**
946
+ * 인증서 만료일 문자열을 도메인 결과로 래핑합니다.
947
+ */
948
+ function mapTaxInvoiceTaxCertificateExpiration(expirationDateTime) {
949
+ return { expirationDateTime };
950
+ }
951
+ /**
952
+ * 인증서 정보 응답을 도메인 정보로 변환합니다.
953
+ */
954
+ function mapTaxInvoiceTaxCertificateInfo(taxInvoiceApiResponse) {
955
+ return removeUndefinedProperties({
956
+ registeredAt: taxInvoiceApiResponse.regDT,
957
+ expiredAt: taxInvoiceApiResponse.expireDT,
958
+ issuerDistinguishedName: taxInvoiceApiResponse.issuerDN,
959
+ subjectDistinguishedName: taxInvoiceApiResponse.subjectDN,
960
+ issuerName: taxInvoiceApiResponse.issuerName,
961
+ policyObjectIdentifier: taxInvoiceApiResponse.OID,
962
+ registeredContactName: taxInvoiceApiResponse.regContactName,
963
+ registeredContactIdentifier: taxInvoiceApiResponse.regContactID
964
+ });
965
+ }
966
+ /**
967
+ * 초대량 개별 처리 결과를 도메인 항목으로 변환합니다.
968
+ */
969
+ function mapTaxInvoiceBulkIssueSubmissionResultItem(taxInvoiceApiResponse) {
970
+ return removeUndefinedProperties({
971
+ invoiceDocumentKeyTypeCode: taxInvoiceApiResponse.keyType,
972
+ supplierInvoiceManagementKey: taxInvoiceApiResponse.invoicerMgtKey,
973
+ trusteeInvoiceManagementKey: taxInvoiceApiResponse.trusteeMgtKey,
974
+ resultCode: toOptionalNumber(taxInvoiceApiResponse.code),
975
+ resultMessage: taxInvoiceApiResponse.message,
976
+ nationalTaxServiceConfirmationNumber: taxInvoiceApiResponse.ntsconfirmNum,
977
+ receivedAt: taxInvoiceApiResponse.receiptDT,
978
+ issuedAt: taxInvoiceApiResponse.issueDT
979
+ });
980
+ }
981
+ /**
982
+ * 공급자 응답 필드를 도메인 공급자 정보로 변환합니다.
983
+ */
984
+ function mapSupplierOutput(taxInvoiceApiResponse) {
985
+ return compactOptionalObject({
986
+ businessNumber: taxInvoiceApiResponse.invoicerCorpNum,
987
+ managementKey: taxInvoiceApiResponse.invoicerMgtKey,
988
+ taxRegistrationIdentifier: taxInvoiceApiResponse.invoicerTaxRegID,
989
+ companyName: taxInvoiceApiResponse.invoicerCorpName,
990
+ chiefExecutiveOfficerName: taxInvoiceApiResponse.invoicerCEOName,
991
+ address: taxInvoiceApiResponse.invoicerAddr,
992
+ businessClass: taxInvoiceApiResponse.invoicerBizClass,
993
+ businessType: taxInvoiceApiResponse.invoicerBizType,
994
+ contactName: taxInvoiceApiResponse.invoicerContactName,
995
+ telephoneNumber: taxInvoiceApiResponse.invoicerTEL,
996
+ mobilePhoneNumber: taxInvoiceApiResponse.invoicerHP,
997
+ emailAddress: taxInvoiceApiResponse.invoicerEmail,
998
+ sendTextMessage: toOptionalBoolean(taxInvoiceApiResponse.invoicerSMSSendYN),
999
+ printEnabled: toOptionalBoolean(taxInvoiceApiResponse.invoicerPrintYN),
1000
+ residentRegistrationNumber: taxInvoiceApiResponse.invoicerRDN,
1001
+ foreignerRegistrationNumber: taxInvoiceApiResponse.invoicerOLN,
1002
+ branchBusinessNumber: taxInvoiceApiResponse.invoicerTaxNum,
1003
+ branchSerialNumber: taxInvoiceApiResponse.invoicerPSerialNum,
1004
+ corporationClassification: taxInvoiceApiResponse.invoicerCorpCls,
1005
+ departmentName: taxInvoiceApiResponse.invoicerDeptName
1006
+ });
1007
+ }
1008
+ /**
1009
+ * 공급받는자 응답 필드를 도메인 공급받는자 정보로 변환합니다.
1010
+ */
1011
+ function mapBuyerOutput(taxInvoiceApiResponse) {
1012
+ return compactOptionalObject({
1013
+ recipientType: taxInvoiceApiResponse.invoiceeType,
1014
+ businessNumber: taxInvoiceApiResponse.invoiceeCorpNum,
1015
+ managementKey: taxInvoiceApiResponse.invoiceeMgtKey,
1016
+ taxRegistrationIdentifier: taxInvoiceApiResponse.invoiceeTaxRegID,
1017
+ companyName: taxInvoiceApiResponse.invoiceeCorpName,
1018
+ chiefExecutiveOfficerName: taxInvoiceApiResponse.invoiceeCEOName,
1019
+ address: taxInvoiceApiResponse.invoiceeAddr,
1020
+ businessClass: taxInvoiceApiResponse.invoiceeBizClass,
1021
+ businessType: taxInvoiceApiResponse.invoiceeBizType,
1022
+ contactName: taxInvoiceApiResponse.invoiceeContactName1,
1023
+ telephoneNumber: taxInvoiceApiResponse.invoiceeTEL1,
1024
+ mobilePhoneNumber: taxInvoiceApiResponse.invoiceeHP1,
1025
+ emailAddress: taxInvoiceApiResponse.invoiceeEmail1,
1026
+ secondaryContactName: taxInvoiceApiResponse.invoiceeContactName2,
1027
+ secondaryTelephoneNumber: taxInvoiceApiResponse.invoiceeTEL2,
1028
+ secondaryMobilePhoneNumber: taxInvoiceApiResponse.invoiceeHP2,
1029
+ secondaryEmailAddress: taxInvoiceApiResponse.invoiceeEmail2,
1030
+ sendTextMessage: toOptionalBoolean(taxInvoiceApiResponse.invoiceeSMSSendYN),
1031
+ printEnabled: toOptionalBoolean(taxInvoiceApiResponse.invoiceePrintYN),
1032
+ residentRegistrationNumber: taxInvoiceApiResponse.invoiceeRDN,
1033
+ foreignerRegistrationNumber: taxInvoiceApiResponse.invoiceeOLN,
1034
+ branchBusinessNumber: taxInvoiceApiResponse.invoiceeTaxNum,
1035
+ branchSerialNumber: taxInvoiceApiResponse.invoiceePSerialNum,
1036
+ corporationClassification: taxInvoiceApiResponse.invoiceeCorpCls,
1037
+ departmentName: taxInvoiceApiResponse.invoiceeDeptName1,
1038
+ primaryDepartmentName: taxInvoiceApiResponse.invoiceeDeptName1,
1039
+ secondaryDepartmentName: taxInvoiceApiResponse.invoiceeDeptName2,
1040
+ businessStatus: taxInvoiceApiResponse.closeDownState,
1041
+ businessStatusDate: taxInvoiceApiResponse.closeDownStateDate
1042
+ });
1043
+ }
1044
+ /**
1045
+ * 수탁자 응답 필드를 도메인 수탁자 정보로 변환합니다.
1046
+ */
1047
+ function mapTrusteeOutput(taxInvoiceApiResponse) {
1048
+ return compactOptionalObject({
1049
+ businessNumber: taxInvoiceApiResponse.trusteeCorpNum,
1050
+ managementKey: taxInvoiceApiResponse.trusteeMgtKey,
1051
+ taxRegistrationIdentifier: taxInvoiceApiResponse.trusteeTaxRegID,
1052
+ companyName: taxInvoiceApiResponse.trusteeCorpName,
1053
+ chiefExecutiveOfficerName: taxInvoiceApiResponse.trusteeCEOName,
1054
+ address: taxInvoiceApiResponse.trusteeAddr,
1055
+ businessClass: taxInvoiceApiResponse.trusteeBizClass,
1056
+ businessType: taxInvoiceApiResponse.trusteeBizType,
1057
+ contactName: taxInvoiceApiResponse.trusteeContactName,
1058
+ telephoneNumber: taxInvoiceApiResponse.trusteeTEL,
1059
+ mobilePhoneNumber: taxInvoiceApiResponse.trusteeHP,
1060
+ emailAddress: taxInvoiceApiResponse.trusteeEmail,
1061
+ sendTextMessage: toOptionalBoolean(taxInvoiceApiResponse.trusteeSMSSendYN),
1062
+ printEnabled: toOptionalBoolean(taxInvoiceApiResponse.trusteePrintYN),
1063
+ residentRegistrationNumber: taxInvoiceApiResponse.trusteeRDN,
1064
+ foreignerRegistrationNumber: taxInvoiceApiResponse.trusteeOLN,
1065
+ branchBusinessNumber: taxInvoiceApiResponse.trusteeTaxNum,
1066
+ branchSerialNumber: taxInvoiceApiResponse.trusteePSerialNum,
1067
+ corporationClassification: taxInvoiceApiResponse.trusteeCorpCls,
1068
+ departmentName: taxInvoiceApiResponse.trusteeDeptName
1069
+ });
1070
+ }
1071
+ /**
1072
+ * 문자열/숫자 값을 숫자로 안전하게 변환합니다.
1073
+ */
1074
+ function toOptionalNumber(value) {
1075
+ if (value === void 0) return;
1076
+ if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
1077
+ const normalizedNumber = Number(value);
1078
+ return Number.isFinite(normalizedNumber) ? normalizedNumber : void 0;
1079
+ }
1080
+ function toRequiredNumber(value, fieldName) {
1081
+ const normalizedNumber = toOptionalNumber(value);
1082
+ if (normalizedNumber !== void 0) return normalizedNumber;
1083
+ throw new Error(`유효하지 않은 ${fieldName} 응답값입니다. (${String(value)})`);
1084
+ }
1085
+ /**
1086
+ * 불리언 문자열/값을 불리언으로 안전하게 변환합니다.
1087
+ */
1088
+ function toOptionalBoolean(value) {
1089
+ if (value === void 0) return;
1090
+ return toBoolean(value);
1091
+ }
1092
+ /**
1093
+ * 과금 방향 문자열을 도메인 과금 방향으로 안전하게 정규화합니다.
1094
+ */
1095
+ function toTaxInvoiceChargeDirection(chargeDirection) {
1096
+ if (chargeDirection === TaxInvoiceChargeDirectionValues.NormalCharge) return TaxInvoiceChargeDirectionValues.NormalCharge;
1097
+ if (chargeDirection === TaxInvoiceChargeDirectionValues.ReverseCharge) return TaxInvoiceChargeDirectionValues.ReverseCharge;
1098
+ }
1099
+ /**
1100
+ * 모든 필드가 비어있으면 `undefined`를 반환하고, 아니면 정리된 객체를 반환합니다.
1101
+ */
1102
+ function compactOptionalObject(sourceObject) {
1103
+ const normalizedObject = removeUndefinedProperties(sourceObject);
1104
+ return Object.keys(normalizedObject).length === 0 ? void 0 : normalizedObject;
1105
+ }
1106
+ /**
1107
+ * 객체에서 `undefined` 값만 제거합니다.
1108
+ */
1109
+ function removeUndefinedProperties(sourceObject) {
1110
+ const definedEntries = Object.entries(sourceObject).filter(([, value]) => value !== void 0);
1111
+ return Object.fromEntries(definedEntries);
1112
+ }
1113
+ //#endregion
1114
+ //#region src/services/tax-invoice/service.ts
1115
+ const KOREA_TIME_ZONE = "Asia/Seoul";
1116
+ const SEARCH_STATE_CODE_PATTERN = /^\d[\d*][\d*]$/;
1117
+ const KOREA_DATE_FORMATTER = new Intl.DateTimeFormat("en-US", {
1118
+ timeZone: KOREA_TIME_ZONE,
1119
+ year: "numeric",
1120
+ month: "2-digit",
1121
+ day: "2-digit"
1122
+ });
1123
+ const SEARCH_INVOICES_OPERATION = "taxInvoice.searchInvoices";
1124
+ /**
1125
+ * TaxInvoice modern facade 서비스를 생성합니다.
1126
+ *
1127
+ * 입력 DTO를 compat positional 인자로 변환하고,
1128
+ * compat 에러를 `PopbillApiError`로 표준화하여 재throw 합니다.
1129
+ */
1130
+ function createTaxInvoiceService(input) {
1131
+ const compatTaxInvoiceService = input.compatTaxInvoiceService;
1132
+ return {
1133
+ issueInvoiceImmediately(request) {
1134
+ return invokeTaxInvoiceMethod(input, "taxInvoice.issueInvoiceImmediately", async () => {
1135
+ return mapTaxInvoiceIssueResult(await compatTaxInvoiceService.registIssue(request.businessNumber, mapTaxInvoiceDocument(request.taxInvoiceDocument), request.writeSpecification, request.forceIssue, request.historyMemo, request.emailSubject, request.dealInvoiceManagementKey, input.defaultUserId));
1136
+ });
1137
+ },
1138
+ submitBulkIssue(request) {
1139
+ return invokeTaxInvoiceMethod(input, "taxInvoice.submitBulkIssue", async () => {
1140
+ return mapTaxInvoiceBulkSubmitResult(await compatTaxInvoiceService.bulkSubmit(request.businessNumber, request.submissionIdentifier, mapTaxInvoiceDocuments(request.taxInvoiceDocuments), request.forceIssue, input.defaultUserId));
1141
+ });
1142
+ },
1143
+ getBulkIssueSubmissionResult(request) {
1144
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getBulkIssueSubmissionResult", async () => {
1145
+ return mapTaxInvoiceBulkIssueSubmissionResult(await compatTaxInvoiceService.getBulkResult(request.businessNumber, request.submissionIdentifier, input.defaultUserId));
1146
+ });
1147
+ },
1148
+ registerInvoice(request) {
1149
+ return invokeTaxInvoiceMethod(input, "taxInvoice.registerInvoice", async () => {
1150
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.register(request.businessNumber, mapTaxInvoiceDocument(request.taxInvoiceDocument), input.defaultUserId));
1151
+ });
1152
+ },
1153
+ updateInvoice(request) {
1154
+ return invokeTaxInvoiceMethod(input, "taxInvoice.updateInvoice", async () => {
1155
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.update(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, mapTaxInvoiceDocument(request.taxInvoiceDocument), input.defaultUserId));
1156
+ });
1157
+ },
1158
+ issueInvoice(request) {
1159
+ return invokeTaxInvoiceMethod(input, "taxInvoice.issueInvoice", async () => {
1160
+ return mapTaxInvoiceIssueResult(await compatTaxInvoiceService.issue(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, request.historyMemo, request.emailSubject, request.forceIssue, input.defaultUserId));
1161
+ });
1162
+ },
1163
+ cancelIssuedInvoice(request) {
1164
+ return invokeTaxInvoiceMethod(input, "taxInvoice.cancelIssuedInvoice", async () => {
1165
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.cancelIssue(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, request.historyMemo, input.defaultUserId));
1166
+ });
1167
+ },
1168
+ requestReverseIssueImmediately(request) {
1169
+ return invokeTaxInvoiceMethod(input, "taxInvoice.requestReverseIssueImmediately", async () => {
1170
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.registRequest(request.businessNumber, mapTaxInvoiceDocument(request.taxInvoiceDocument), request.historyMemo, input.defaultUserId));
1171
+ });
1172
+ },
1173
+ requestReverseIssue(request) {
1174
+ return invokeTaxInvoiceMethod(input, "taxInvoice.requestReverseIssue", async () => {
1175
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.request(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, request.historyMemo, input.defaultUserId));
1176
+ });
1177
+ },
1178
+ cancelReverseIssueRequest(request) {
1179
+ return invokeTaxInvoiceMethod(input, "taxInvoice.cancelReverseIssueRequest", async () => {
1180
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.cancelRequest(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, request.historyMemo, input.defaultUserId));
1181
+ });
1182
+ },
1183
+ refuseReverseIssueRequest(request) {
1184
+ return invokeTaxInvoiceMethod(input, "taxInvoice.refuseReverseIssueRequest", async () => {
1185
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.refuse(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, request.historyMemo, input.defaultUserId));
1186
+ });
1187
+ },
1188
+ deleteInvoice(request) {
1189
+ return invokeTaxInvoiceMethod(input, "taxInvoice.deleteInvoice", async () => {
1190
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.delete(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1191
+ });
1192
+ },
1193
+ sendInvoiceToNTS(request) {
1194
+ return invokeTaxInvoiceMethod(input, "taxInvoice.sendInvoiceToNTS", async () => {
1195
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.sendToNTS(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1196
+ });
1197
+ },
1198
+ async getInvoiceInfo(request) {
1199
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getInvoiceInfo", async () => {
1200
+ return mapTaxInvoiceInfo(await compatTaxInvoiceService.getInfo(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1201
+ });
1202
+ },
1203
+ getInvoicesInfo(request) {
1204
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getInvoicesInfo", async () => {
1205
+ return mapTaxInvoiceInfos(await compatTaxInvoiceService.getInfos(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKeys, input.defaultUserId));
1206
+ });
1207
+ },
1208
+ getInvoiceDetailInfo(request) {
1209
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getInvoiceDetailInfo", async () => {
1210
+ return mapTaxInvoiceDocumentOutput(await compatTaxInvoiceService.getDetailInfo(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1211
+ });
1212
+ },
1213
+ checkInvoiceManagementKeyInUse(request) {
1214
+ return invokeTaxInvoiceMethod(input, "taxInvoice.checkInvoiceManagementKeyInUse", async () => {
1215
+ return mapTaxInvoiceInvoiceManagementKeyUsage(await compatTaxInvoiceService.checkMgtKeyInUse(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1216
+ });
1217
+ },
1218
+ getInvoiceXML(request) {
1219
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getInvoiceXML", async () => {
1220
+ return mapTaxInvoiceXmlResult(await compatTaxInvoiceService.getXML(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1221
+ });
1222
+ },
1223
+ searchInvoices(request) {
1224
+ return invokeTaxInvoiceMethod(input, "taxInvoice.searchInvoices", async () => {
1225
+ const normalizedSearchRequest = normalizeSearchInvoicesRequest(request);
1226
+ return mapTaxInvoiceSearchResult(await compatTaxInvoiceService.search(request.businessNumber, request.invoiceDocumentKeyType, normalizedSearchRequest.searchDateType, normalizedSearchRequest.startDate, normalizedSearchRequest.endDate, normalizedSearchRequest.invoiceStateCodes, normalizedSearchRequest.invoiceTypeCodes, normalizedSearchRequest.taxationTypeCodes, normalizedSearchRequest.lateIssueOnly, normalizedSearchRequest.sortOrder, normalizedSearchRequest.pageNumber, normalizedSearchRequest.pageSize, normalizedSearchRequest.taxRegistrationIdentifierType, normalizedSearchRequest.taxRegistrationIdentifierAvailability, normalizedSearchRequest.taxRegistrationIdentifier, normalizedSearchRequest.queryText, normalizedSearchRequest.interoperabilityType, input.defaultUserId, normalizedSearchRequest.issueTypeCodes, normalizedSearchRequest.registrationTypeCodes, toCompatCloseDownStateCodes(normalizedSearchRequest.closeDownStateCodes), normalizedSearchRequest.invoiceManagementKeyOrNationalTaxServiceConfirmationNumber));
1227
+ });
1228
+ },
1229
+ getInvoiceLogs(request) {
1230
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getInvoiceLogs", async () => {
1231
+ return mapTaxInvoiceLogs(await compatTaxInvoiceService.getLogs(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1232
+ });
1233
+ },
1234
+ getTaxInvoiceBoxURL(request) {
1235
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getTaxInvoiceBoxURL", async () => {
1236
+ return mapTaxInvoiceAccessUrlFromString(await compatTaxInvoiceService.getURL(request.businessNumber, request.taxInvoiceBoxScope, input.defaultUserId));
1237
+ });
1238
+ },
1239
+ getInvoicePopupURL(request) {
1240
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getInvoicePopupURL", async () => {
1241
+ return mapTaxInvoiceAccessUrlFromString(await compatTaxInvoiceService.getPopUpURL(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1242
+ });
1243
+ },
1244
+ getInvoiceViewURL(request) {
1245
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getInvoiceViewURL", async () => {
1246
+ return mapTaxInvoiceAccessUrlFromString(await compatTaxInvoiceService.getViewURL(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1247
+ });
1248
+ },
1249
+ getSupplierInvoicePrintURL(request) {
1250
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getSupplierInvoicePrintURL", async () => {
1251
+ return mapTaxInvoiceAccessUrlFromString(await compatTaxInvoiceService.getPrintURL(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1252
+ });
1253
+ },
1254
+ getBuyerInvoicePrintURL(request) {
1255
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getBuyerInvoicePrintURL", async () => {
1256
+ return mapTaxInvoiceAccessUrlFromString(await compatTaxInvoiceService.getEPrintURL(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1257
+ });
1258
+ },
1259
+ getBulkInvoicePrintURL(request) {
1260
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getBulkInvoicePrintURL", async () => {
1261
+ return mapTaxInvoiceAccessUrlFromString(await compatTaxInvoiceService.getMassPrintURL(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKeys, input.defaultUserId));
1262
+ });
1263
+ },
1264
+ getInvoiceMailURL(request) {
1265
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getInvoiceMailURL", async () => {
1266
+ return mapTaxInvoiceAccessUrlFromString(await compatTaxInvoiceService.getMailURL(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1267
+ });
1268
+ },
1269
+ getInvoicePDFURL(request) {
1270
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getInvoicePDFURL", async () => {
1271
+ return mapTaxInvoiceAccessUrlFromString(await compatTaxInvoiceService.getPDFURL(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1272
+ });
1273
+ },
1274
+ getSealAndAttachmentRegistrationURL(request) {
1275
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getSealAndAttachmentRegistrationURL", async () => {
1276
+ return mapTaxInvoiceAccessUrl(await compatTaxInvoiceService.getSealURL(request.businessNumber, input.defaultUserId));
1277
+ });
1278
+ },
1279
+ attachFileFromPath(request) {
1280
+ return invokeTaxInvoiceMethod(input, "taxInvoice.attachFileFromPath", async () => {
1281
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.attachFile(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, request.displayName, request.filePath, input.defaultUserId));
1282
+ });
1283
+ },
1284
+ attachFileFromBinary(request) {
1285
+ return invokeTaxInvoiceMethod(input, "taxInvoice.attachFileFromBinary", async () => {
1286
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.attachFileBinary(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, {
1287
+ fileName: request.fileName,
1288
+ fileData: request.fileData
1289
+ }, input.defaultUserId));
1290
+ });
1291
+ },
1292
+ deleteAttachedFile(request) {
1293
+ return invokeTaxInvoiceMethod(input, "taxInvoice.deleteAttachedFile", async () => {
1294
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.deleteFile(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, request.fileIdentifier, input.defaultUserId));
1295
+ });
1296
+ },
1297
+ getAttachedFiles(request) {
1298
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getAttachedFiles", async () => {
1299
+ return mapTaxInvoiceAttachedFiles(await compatTaxInvoiceService.getFiles(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, input.defaultUserId));
1300
+ });
1301
+ },
1302
+ resendInvoiceEmail(request) {
1303
+ return invokeTaxInvoiceMethod(input, "taxInvoice.resendInvoiceEmail", async () => {
1304
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.sendEmail(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, request.receiverEmailAddress, input.defaultUserId));
1305
+ });
1306
+ },
1307
+ resendInvoiceSMS(request) {
1308
+ return invokeTaxInvoiceMethod(input, "taxInvoice.resendInvoiceSMS", async () => {
1309
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.sendSMS(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, request.senderPhoneNumber, request.receiverPhoneNumber, request.messageBody, input.defaultUserId));
1310
+ });
1311
+ },
1312
+ resendInvoiceFAX(request) {
1313
+ return invokeTaxInvoiceMethod(input, "taxInvoice.resendInvoiceFAX", async () => {
1314
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.sendFAX(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, request.senderNumber, request.receiverNumber, input.defaultUserId));
1315
+ });
1316
+ },
1317
+ attachInvoiceStatement(request) {
1318
+ return invokeTaxInvoiceMethod(input, "taxInvoice.attachInvoiceStatement", async () => {
1319
+ const statementItemCode = normalizeStatementItemCode(request.statementItemCode, "taxInvoice.attachInvoiceStatement");
1320
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.attachStatement(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, statementItemCode, request.statementManagementKey, input.defaultUserId));
1321
+ });
1322
+ },
1323
+ detachInvoiceStatement(request) {
1324
+ return invokeTaxInvoiceMethod(input, "taxInvoice.detachInvoiceStatement", async () => {
1325
+ const statementItemCode = normalizeStatementItemCode(request.statementItemCode, "taxInvoice.detachInvoiceStatement");
1326
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.detachStatement(request.businessNumber, request.invoiceDocumentKeyType, request.invoiceManagementKey, statementItemCode, request.statementManagementKey, input.defaultUserId));
1327
+ });
1328
+ },
1329
+ assignInvoiceManagementKey(request) {
1330
+ return invokeTaxInvoiceMethod(input, "taxInvoice.assignInvoiceManagementKey", async () => {
1331
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.assignMgtKey(request.businessNumber, request.invoiceDocumentKeyType, request.itemKey, request.invoiceManagementKey, input.defaultUserId));
1332
+ });
1333
+ },
1334
+ getEmailSendSettings(request) {
1335
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getEmailSendSettings", async () => {
1336
+ return mapTaxInvoiceEmailSendSettings(await compatTaxInvoiceService.listEmailConfig(request.businessNumber, input.defaultUserId));
1337
+ });
1338
+ },
1339
+ updateEmailSendSettings(request) {
1340
+ return invokeTaxInvoiceMethod(input, "taxInvoice.updateEmailSendSettings", async () => {
1341
+ const emailType = normalizeEmailType(request.emailType, "taxInvoice.updateEmailSendSettings");
1342
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.updateEmailConfig(request.businessNumber, emailType, request.sendEnabled, input.defaultUserId));
1343
+ });
1344
+ },
1345
+ getSendToNTSSettings(request) {
1346
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getSendToNTSSettings", async () => {
1347
+ return mapTaxInvoiceSendToNationalTaxServiceSetting(await compatTaxInvoiceService.getSendToNTSConfig(request.businessNumber, input.defaultUserId));
1348
+ });
1349
+ },
1350
+ getTaxCertificateRegistrationURL(request) {
1351
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getTaxCertificateRegistrationURL", async () => {
1352
+ return mapTaxInvoiceAccessUrl(await compatTaxInvoiceService.getTaxCertURL(request.businessNumber, input.defaultUserId));
1353
+ });
1354
+ },
1355
+ getTaxCertificateExpirationDate(request) {
1356
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getTaxCertificateExpirationDate", async () => {
1357
+ return mapTaxInvoiceTaxCertificateExpiration(await compatTaxInvoiceService.getCertificateExpireDate(request.businessNumber, input.defaultUserId));
1358
+ });
1359
+ },
1360
+ checkTaxCertificateValidation(request) {
1361
+ return invokeTaxInvoiceMethod(input, "taxInvoice.checkTaxCertificateValidation", async () => {
1362
+ return mapTaxInvoiceOperationResult(await compatTaxInvoiceService.checkCertValidation(request.businessNumber, input.defaultUserId));
1363
+ });
1364
+ },
1365
+ getTaxCertificateInfo(request) {
1366
+ return invokeTaxInvoiceMethod(input, "taxInvoice.getTaxCertificateInfo", async () => {
1367
+ return mapTaxInvoiceTaxCertificateInfo(await compatTaxInvoiceService.getTaxCertInfo(request.businessNumber, input.defaultUserId));
1368
+ });
1369
+ }
1370
+ };
1371
+ }
1372
+ function normalizeSearchInvoicesRequest(request) {
1373
+ return {
1374
+ searchDateType: normalizeCodeValue(request.searchDateType, Object.values(TaxInvoiceDateType), "searchDateType", SEARCH_INVOICES_OPERATION),
1375
+ startDate: normalizeSearchDateInput(request.startDate, "startDate", SEARCH_INVOICES_OPERATION),
1376
+ endDate: normalizeSearchDateInput(request.endDate, "endDate", SEARCH_INVOICES_OPERATION),
1377
+ invoiceStateCodes: normalizeSearchStateCodes(request.invoiceStateCodes),
1378
+ invoiceTypeCodes: normalizeCodeArray(request.invoiceTypeCodes, Object.values(TaxInvoiceSearchInvoiceTypeCodes), "invoiceTypeCodes", SEARCH_INVOICES_OPERATION),
1379
+ taxationTypeCodes: normalizeCodeArray(request.taxationTypeCodes, Object.values(TaxInvoiceSearchTaxationTypeCodes), "taxationTypeCodes", SEARCH_INVOICES_OPERATION),
1380
+ lateIssueOnly: request.lateIssueOnly,
1381
+ sortOrder: normalizeCodeValue(request.sortOrder, Object.values(TaxInvoiceSortOrder), "sortOrder", SEARCH_INVOICES_OPERATION),
1382
+ pageNumber: request.pageNumber,
1383
+ pageSize: request.pageSize,
1384
+ taxRegistrationIdentifierType: normalizeOptionalCodeValue(request.taxRegistrationIdentifierType, Object.values(TaxInvoiceSearchTaxRegistrationIdentifierTypes), "taxRegistrationIdentifierType", SEARCH_INVOICES_OPERATION),
1385
+ taxRegistrationIdentifierAvailability: normalizeOptionalCodeValue(request.taxRegistrationIdentifierAvailability, Object.values(TaxInvoiceSearchTaxRegistrationIdentifierAvailabilities), "taxRegistrationIdentifierAvailability", SEARCH_INVOICES_OPERATION),
1386
+ taxRegistrationIdentifier: request.taxRegistrationIdentifier,
1387
+ queryText: request.queryText,
1388
+ interoperabilityType: normalizeOptionalCodeValue(request.interoperabilityType, Object.values(TaxInvoiceSearchInteroperabilityTypes), "interoperabilityType", SEARCH_INVOICES_OPERATION),
1389
+ issueTypeCodes: normalizeOptionalCodeArray(request.issueTypeCodes, Object.values(TaxInvoiceSearchIssueTypeCodes), "issueTypeCodes", SEARCH_INVOICES_OPERATION),
1390
+ registrationTypeCodes: normalizeOptionalCodeArray(request.registrationTypeCodes, Object.values(TaxInvoiceSearchRegistrationTypeCodes), "registrationTypeCodes", SEARCH_INVOICES_OPERATION),
1391
+ closeDownStateCodes: normalizeOptionalCodeArray(request.closeDownStateCodes, Object.values(TaxInvoiceCloseDownStateCodes), "closeDownStateCodes", SEARCH_INVOICES_OPERATION),
1392
+ invoiceManagementKeyOrNationalTaxServiceConfirmationNumber: request.invoiceManagementKeyOrNationalTaxServiceConfirmationNumber
1393
+ };
1394
+ }
1395
+ function toCompatCloseDownStateCodes(closeDownStateCodes) {
1396
+ return closeDownStateCodes;
1397
+ }
1398
+ function normalizeSearchStateCodes(searchStateCodes) {
1399
+ if (!Array.isArray(searchStateCodes)) throw createInputValidationError("invoiceStateCodes는 배열이어야 해.", {
1400
+ operation: SEARCH_INVOICES_OPERATION,
1401
+ stage: PopbillErrorStage.ValidateInput
1402
+ });
1403
+ return searchStateCodes.map((searchStateCode, index) => {
1404
+ if (typeof searchStateCode !== "string" || !SEARCH_STATE_CODE_PATTERN.test(searchStateCode)) throw createInputValidationError(`invoiceStateCodes[${index}]에 유효하지 않은 상태코드가 있어. 허용 패턴: 숫자 3자리 또는 2/3자리 와일드카드 (예: 300, 3**, 60*)`, {
1405
+ operation: SEARCH_INVOICES_OPERATION,
1406
+ stage: PopbillErrorStage.ValidateInput
1407
+ });
1408
+ return searchStateCode;
1409
+ });
1410
+ }
1411
+ function normalizeSearchDateInput(dateInput, fieldName, operation) {
1412
+ if (dateInput instanceof Date) {
1413
+ if (!Number.isFinite(dateInput.getTime())) throw createInputValidationError(`${fieldName}는 유효한 Date여야 해.`, {
1414
+ operation,
1415
+ stage: PopbillErrorStage.ValidateInput
1416
+ });
1417
+ return formatDateToKoreaDateString(dateInput);
1418
+ }
1419
+ if (typeof dateInput !== "string") throw createInputValidationError(`${fieldName}는 yyyyMMdd 문자열 또는 Date여야 해.`, {
1420
+ operation,
1421
+ stage: PopbillErrorStage.ValidateInput
1422
+ });
1423
+ const normalizedDateInput = dateInput.trim();
1424
+ if (!isValidDateString(normalizedDateInput)) throw createInputValidationError(`${fieldName}는 yyyyMMdd 형식의 유효한 날짜여야 해.`, {
1425
+ operation,
1426
+ stage: PopbillErrorStage.ValidateInput
1427
+ });
1428
+ return normalizedDateInput;
1429
+ }
1430
+ function formatDateToKoreaDateString(date) {
1431
+ let year = "";
1432
+ let month = "";
1433
+ let day = "";
1434
+ for (const datePart of KOREA_DATE_FORMATTER.formatToParts(date)) {
1435
+ if (datePart.type === "year") {
1436
+ year = datePart.value;
1437
+ continue;
1438
+ }
1439
+ if (datePart.type === "month") {
1440
+ month = datePart.value;
1441
+ continue;
1442
+ }
1443
+ if (datePart.type === "day") day = datePart.value;
1444
+ }
1445
+ return `${year}${month}${day}`;
1446
+ }
1447
+ function isValidDateString(dateString) {
1448
+ const match = /^(\d{4})(\d{2})(\d{2})$/.exec(dateString);
1449
+ if (!match) return false;
1450
+ const year = Number(match[1]);
1451
+ const month = Number(match[2]);
1452
+ const day = Number(match[3]);
1453
+ const normalizedDate = new Date(Date.UTC(year, month - 1, day));
1454
+ return normalizedDate.getUTCFullYear() === year && normalizedDate.getUTCMonth() === month - 1 && normalizedDate.getUTCDate() === day;
1455
+ }
1456
+ function normalizeStatementItemCode(statementItemCode, operation) {
1457
+ return normalizeCodeValue(statementItemCode, Object.values(TaxInvoiceStatementItemCodes), "statementItemCode", operation);
1458
+ }
1459
+ function normalizeEmailType(emailType, operation) {
1460
+ return normalizeCodeValue(emailType, Object.values(TaxInvoiceEmailTypes), "emailType", operation);
1461
+ }
1462
+ function normalizeOptionalCodeValue(codeValue, allowedValues, fieldName, operation) {
1463
+ if (codeValue === void 0) return;
1464
+ return normalizeCodeValue(codeValue, allowedValues, fieldName, operation);
1465
+ }
1466
+ function normalizeOptionalCodeArray(codeValues, allowedValues, fieldName, operation) {
1467
+ if (codeValues === void 0) return;
1468
+ return normalizeCodeArray(codeValues, allowedValues, fieldName, operation);
1469
+ }
1470
+ function normalizeCodeArray(codeValues, allowedValues, fieldName, operation) {
1471
+ if (!Array.isArray(codeValues)) throw createInputValidationError(`${fieldName}는 배열이어야 해.`, {
1472
+ operation,
1473
+ stage: PopbillErrorStage.ValidateInput
1474
+ });
1475
+ return codeValues.map((codeValue, index) => normalizeCodeValue(codeValue, allowedValues, `${fieldName}[${index}]`, operation));
1476
+ }
1477
+ function normalizeCodeValue(codeValue, allowedValues, fieldName, operation) {
1478
+ for (const allowedValue of allowedValues) if (codeValue === allowedValue) return allowedValue;
1479
+ throw createInputValidationError(`${fieldName}에 유효하지 않은 값이 있어. 허용값: ${allowedValues.map((allowedValue) => String(allowedValue)).join(", ")} (입력값: ${String(codeValue)})`, {
1480
+ operation,
1481
+ stage: PopbillErrorStage.ValidateInput
1482
+ });
1483
+ }
1484
+ //#endregion
1485
+ //#region src/internal/compat/tax-invoice-service.ts
1486
+ const DEFAULT_REQUEST_TIMEOUT_MILLISECONDS$1 = 18e4;
1487
+ const DEFAULT_ACCEPT_ENCODING$1 = "gzip";
1488
+ /**
1489
+ * `@connextable/popbill-compat` Taxinvoice promise 서비스를 client 단위 인스턴스로 생성합니다.
1490
+ */
1491
+ function createCompatTaxInvoiceService(input) {
1492
+ return createTaxinvoicePromiseService({
1493
+ LinkID: input.linkId,
1494
+ SecretKey: input.secretKey,
1495
+ IsTest: input.isTest ?? false,
1496
+ UseStaticIP: input.useStaticIp ?? false,
1497
+ UseGAIP: input.useGaIp ?? false,
1498
+ UseLocalTimeYN: input.useLocalTime ?? true,
1499
+ IPRestrictOnOff: input.ipRestrictOnOff ?? true,
1500
+ requestTimeoutMs: input.requestTimeoutMilliseconds ?? DEFAULT_REQUEST_TIMEOUT_MILLISECONDS$1,
1501
+ acceptLanguage: normalizeOptionalString(input.acceptLanguage),
1502
+ acceptEncoding: input.acceptEncoding === void 0 ? DEFAULT_ACCEPT_ENCODING$1 : input.acceptEncoding
1503
+ });
1504
+ }
1505
+ //#endregion
1506
+ //#region src/client/index.ts
1507
+ const DEFAULT_REQUEST_TIMEOUT_MILLISECONDS = 18e4;
1508
+ const DEFAULT_ACCEPT_ENCODING = "gzip";
1509
+ /**
1510
+ * modern Popbill client를 생성합니다.
1511
+ */
1512
+ function createPopbillClient(config) {
1513
+ const normalizedConfig = normalizeClientConfiguration(config);
1514
+ return { services: { taxInvoice: createTaxInvoiceService({
1515
+ compatTaxInvoiceService: createCompatTaxInvoiceService(normalizedConfig),
1516
+ defaultUserId: normalizedConfig.userId,
1517
+ onError: normalizedConfig.onError
1518
+ }) } };
1519
+ }
1520
+ /**
1521
+ * 입력 설정을 런타임 안전성 기준으로 정규화합니다.
1522
+ */
1523
+ function normalizeClientConfiguration(config) {
1524
+ return {
1525
+ linkId: normalizeRequiredString(config.linkId, "linkId는 필수입니다."),
1526
+ secretKey: normalizeRequiredString(config.secretKey, "secretKey는 필수입니다."),
1527
+ userId: normalizeRequiredString(config.userId, "userId는 필수입니다."),
1528
+ isTest: config.isTest ?? false,
1529
+ useStaticIp: config.useStaticIp ?? false,
1530
+ useGaIp: config.useGaIp ?? false,
1531
+ useLocalTime: config.useLocalTime ?? true,
1532
+ ipRestrictOnOff: config.ipRestrictOnOff ?? true,
1533
+ acceptEncoding: config.acceptEncoding === void 0 ? DEFAULT_ACCEPT_ENCODING : config.acceptEncoding,
1534
+ acceptLanguage: normalizeOptionalString(config.acceptLanguage),
1535
+ requestTimeoutMilliseconds: normalizeRequestTimeoutMilliseconds(config.requestTimeoutMs),
1536
+ onError: config.onError
1537
+ };
1538
+ }
1539
+ function normalizeRequestTimeoutMilliseconds(requestTimeoutMs) {
1540
+ if (requestTimeoutMs === void 0) return DEFAULT_REQUEST_TIMEOUT_MILLISECONDS;
1541
+ if (!Number.isInteger(requestTimeoutMs) || requestTimeoutMs <= 0) throw new Error("requestTimeoutMs는 1 이상의 정수여야 합니다.");
1542
+ return requestTimeoutMs;
1543
+ }
1544
+ //#endregion
1545
+ //#region src/services/tax-invoice/methods.ts
1546
+ /**
1547
+ * TaxInvoice modern facade 공개 메서드 목록입니다.
1548
+ * 문서 섹션(발행/전송, 정보확인, 보기/인쇄, 부가기능, 인증서 관리) 순서를 유지합니다.
1549
+ */
1550
+ const TAX_INVOICE_METHODS = [
1551
+ "issueInvoiceImmediately",
1552
+ "submitBulkIssue",
1553
+ "getBulkIssueSubmissionResult",
1554
+ "registerInvoice",
1555
+ "updateInvoice",
1556
+ "issueInvoice",
1557
+ "cancelIssuedInvoice",
1558
+ "requestReverseIssueImmediately",
1559
+ "requestReverseIssue",
1560
+ "cancelReverseIssueRequest",
1561
+ "refuseReverseIssueRequest",
1562
+ "deleteInvoice",
1563
+ "sendInvoiceToNTS",
1564
+ "getInvoiceInfo",
1565
+ "getInvoicesInfo",
1566
+ "getInvoiceDetailInfo",
1567
+ "checkInvoiceManagementKeyInUse",
1568
+ "getInvoiceXML",
1569
+ "searchInvoices",
1570
+ "getInvoiceLogs",
1571
+ "getTaxInvoiceBoxURL",
1572
+ "getInvoicePopupURL",
1573
+ "getInvoiceViewURL",
1574
+ "getSupplierInvoicePrintURL",
1575
+ "getBuyerInvoicePrintURL",
1576
+ "getBulkInvoicePrintURL",
1577
+ "getInvoiceMailURL",
1578
+ "getInvoicePDFURL",
1579
+ "getSealAndAttachmentRegistrationURL",
1580
+ "attachFileFromPath",
1581
+ "attachFileFromBinary",
1582
+ "deleteAttachedFile",
1583
+ "getAttachedFiles",
1584
+ "resendInvoiceEmail",
1585
+ "resendInvoiceSMS",
1586
+ "resendInvoiceFAX",
1587
+ "attachInvoiceStatement",
1588
+ "detachInvoiceStatement",
1589
+ "assignInvoiceManagementKey",
1590
+ "getEmailSendSettings",
1591
+ "updateEmailSendSettings",
1592
+ "getSendToNTSSettings",
1593
+ "getTaxCertificateRegistrationURL",
1594
+ "getTaxCertificateExpirationDate",
1595
+ "checkTaxCertificateValidation",
1596
+ "getTaxCertificateInfo"
1597
+ ];
1598
+ //#endregion
1599
+ export { PopbillErrorStage, PopbillErrorType, TAX_INVOICE_METHODS, TaxInvoiceBoxScopes, TaxInvoiceBulkIssueSubmissionTransactionStates, TaxInvoiceBusinessStatusValues, TaxInvoiceChargeDirectionValues, TaxInvoiceCloseDownStateCodes, TaxInvoiceDateType, TaxInvoiceDocumentKeyTypes, TaxInvoiceEmailTypes, TaxInvoiceIssueTypes, TaxInvoiceModificationCodes, TaxInvoiceModificationReasonCodes, TaxInvoicePurposeTypes, TaxInvoiceRecipientTypes, TaxInvoiceSearchInteroperabilityTypes, TaxInvoiceSearchInvoiceTypeCodes, TaxInvoiceSearchIssueTypeCodes, TaxInvoiceSearchRegistrationTypeCodes, TaxInvoiceSearchTaxRegistrationIdentifierAvailabilities, TaxInvoiceSearchTaxRegistrationIdentifierTypes, TaxInvoiceSearchTaxationTypeCodes, TaxInvoiceSortOrder, TaxInvoiceStatementItemCodes, TaxInvoiceTaxationTypes, createPopbillClient };