@things-factory/tax-invoice 8.0.0-beta.9 → 8.0.2

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.
Files changed (51) hide show
  1. package/client/bootstrap.ts +1 -0
  2. package/client/index.ts +0 -0
  3. package/client/pages/main.ts +25 -0
  4. package/client/pages/tax-audit-result/tax-audit-result-importer.ts +87 -0
  5. package/client/pages/tax-audit-result/tax-audit-result-list-page.ts +331 -0
  6. package/client/pages/tax-invoice/tax-invoice-detail-popup.ts +454 -0
  7. package/client/pages/tax-invoice/tax-invoice-list-page.ts +525 -0
  8. package/client/pages/tax-invoice-api/tax-invoice-api-page.ts +418 -0
  9. package/client/pages/tax-invoice-company/tax-invoice-company-list-page.ts +447 -0
  10. package/client/pages/tax-invoice-send/company-list-popup.ts +188 -0
  11. package/client/pages/tax-invoice-send/tax-invoice-send-page.ts +196 -0
  12. package/client/pages/tax-invoice-send/tax-invoice-send.ts +1181 -0
  13. package/client/route.ts +23 -0
  14. package/client/tsconfig.json +11 -0
  15. package/dist-client/tsconfig.tsbuildinfo +1 -1
  16. package/dist-server/tsconfig.tsbuildinfo +1 -1
  17. package/package.json +8 -8
  18. package/server/index.ts +2 -0
  19. package/server/routes.ts +28 -0
  20. package/server/service/index.ts +37 -0
  21. package/server/service/tax-audit-result/event-subscriber.ts +17 -0
  22. package/server/service/tax-audit-result/index.ts +9 -0
  23. package/server/service/tax-audit-result/tax-audit-result-history.ts +120 -0
  24. package/server/service/tax-audit-result/tax-audit-result-mutation.ts +198 -0
  25. package/server/service/tax-audit-result/tax-audit-result-query.ts +65 -0
  26. package/server/service/tax-audit-result/tax-audit-result-type.ts +61 -0
  27. package/server/service/tax-audit-result/tax-audit-result.ts +99 -0
  28. package/server/service/tax-invoice/index.ts +6 -0
  29. package/server/service/tax-invoice/tax-invoice-mutation.ts +138 -0
  30. package/server/service/tax-invoice/tax-invoice-query.ts +99 -0
  31. package/server/service/tax-invoice/tax-invoice-type.ts +236 -0
  32. package/server/service/tax-invoice/tax-invoice-util.ts +224 -0
  33. package/server/service/tax-invoice/tax-invoice.ts +393 -0
  34. package/server/service/tax-invoice-api/index.ts +6 -0
  35. package/server/service/tax-invoice-api/tax-invoice-api-mutation.ts +275 -0
  36. package/server/service/tax-invoice-api/tax-invoice-api-query.ts +40 -0
  37. package/server/service/tax-invoice-api/tax-invoice-api-type.ts +83 -0
  38. package/server/service/tax-invoice-api/tax-invoice-api.ts +128 -0
  39. package/server/service/tax-invoice-company/index.ts +6 -0
  40. package/server/service/tax-invoice-company/tax-invoice-company-mutation.ts +84 -0
  41. package/server/service/tax-invoice-company/tax-invoice-company-query.ts +86 -0
  42. package/server/service/tax-invoice-company/tax-invoice-company-type.ts +105 -0
  43. package/server/service/tax-invoice-company/tax-invoice-company.ts +128 -0
  44. package/server/service/tax-invoice-item/index.ts +6 -0
  45. package/server/service/tax-invoice-item/tax-invoice-item-mutation.ts +128 -0
  46. package/server/service/tax-invoice-item/tax-invoice-item-query.ts +60 -0
  47. package/server/service/tax-invoice-item/tax-invoice-item-type.ts +77 -0
  48. package/server/service/tax-invoice-item/tax-invoice-item.ts +95 -0
  49. package/server/service/unipost-api/tax-invoice-inquiry.ts +99 -0
  50. package/server/service/unipost-api/tax-invoice-send.ts +32 -0
  51. package/server/tsconfig.json +10 -0
@@ -0,0 +1,393 @@
1
+ import {
2
+ CreateDateColumn,
3
+ UpdateDateColumn,
4
+ DeleteDateColumn,
5
+ Entity,
6
+ Index,
7
+ Column,
8
+ RelationId,
9
+ ManyToOne,
10
+ OneToMany,
11
+ PrimaryGeneratedColumn
12
+ } from 'typeorm'
13
+ import { ObjectType, Field, ID, registerEnumType } from 'type-graphql'
14
+ import { encryptTransformer } from '@things-factory/shell'
15
+
16
+ import { Domain } from '@things-factory/shell'
17
+ import { User } from '@things-factory/auth-base'
18
+ import { TaxInvoiceItem } from '../tax-invoice-item/tax-invoice-item'
19
+
20
+ export enum Category {
21
+ EXPORT = '10', // 매출
22
+ IMPORT = '20', // 매입
23
+ NTS = '30' // NTS
24
+ }
25
+ // 세금계산서 종류
26
+ export enum InvoiceType {
27
+ GENERAL_TAX_INVOICE = '0101', // 일반 전자세금계산서
28
+ ZERO_RATED_TAX_INVOICE = '0102', // 영세율 전자세금계산서
29
+ CONSIGNMENT_TAX_INVOICE = '0103', // 위수탁 전자세금계산서
30
+ IMPORT__RATED_CONSIGNMENT_TAX_INVOICE = '0105', // 영세율 위수탁 전자세금계산서
31
+ REVISED_GENERAL_TAX_INVOICE = '0201', // 수정 일반 전자세금계산서
32
+ REVISED_ZERORATED_TAX_INVOICE = '0202', // 수정 영세율 전자세금계산서
33
+ REVISED_CONSIGNMENT_TAX_INVOICE = '0203', // 수정 위수탁 전자세금계산서
34
+ REVISED_IMPORT_TAX_INVOICE = '0204', // 수정 수입 전자세금계산서
35
+ REVISED_ZERORATED_CONSIGNMENT_TAX_INVOICE = '0205', // 수정 영세율 위수탁 전자세금계산서
36
+ GENERAL_INVOICE = '0301', // 일반 전자계산서
37
+ CONSIGNMENT_INVOICE = '0303', // 위수탁 전자계산서
38
+ IMPORT_INVOICE = '0304', // 수입 전자계산서
39
+ REVISED_GENERAL_INVOICE = '0401', // 수정 일반 전자계산서
40
+ REVISED_CONSIGNMENT_INVOICE = '0403', // 수정 위수탁 전자계산서
41
+ REVISED_IMPORT_INVOICE = '0404' // 수정 수입 전자계산서
42
+ }
43
+ // 세금계산서 영수/청구 구분 지시자
44
+ export enum Purpose {
45
+ RECEIPT = '01', // 영수
46
+ BILLING = '02' // 청구
47
+ }
48
+ // 세금계산서 수정사유 코드
49
+ export enum RevisedReason {
50
+ ENTRY_ERROR_CORRECTION = '01', // 기재사항 착오·정정
51
+ SUPPLY_VALUE_CHANGE = '02', // 공급가액 변동
52
+ REVERSAL_ENTRY = '03', // 환입
53
+ CONTRACT_CANCELLATION = '04', // 계약의 해제
54
+ POST_FACTO_DOMESTIC_LC_ISSUANCE = '05', // 내국신용장 사후 개설
55
+ ERROR_BASED_DUPLICATE_ISSUANCE = '06' // 착오에 의한 이중발급
56
+ }
57
+ // 세금계산서 공급받는자 사업자등록번호 구분코드
58
+ export enum BusinessRegistrationCategory {
59
+ BUSINESS_REGISTRATION_NUMBER = '01', // 사업자등록번호
60
+ RESIDENT_REGISTRATION_NUMBER = '02', // 주민등록번호
61
+ FOREIGNER_REGISTRATION_NUMBER = '03' // 외국인등록번호
62
+ }
63
+
64
+ registerEnumType(Category, {
65
+ name: 'Category',
66
+ description: 'category'
67
+ })
68
+ registerEnumType(InvoiceType, {
69
+ name: 'InvoiceType',
70
+ description: 'invoice type'
71
+ })
72
+ registerEnumType(Purpose, {
73
+ name: 'Purpose',
74
+ description: 'purpose'
75
+ })
76
+ registerEnumType(RevisedReason, {
77
+ name: 'RevisedReason',
78
+ description: 'revised reason'
79
+ })
80
+ registerEnumType(BusinessRegistrationCategory, {
81
+ name: 'BusinessRegistrationCategory',
82
+ description: 'business registration category'
83
+ })
84
+
85
+ @Entity()
86
+ @Index('ix_tax_invoice_0', (taxInvoice: TaxInvoice) => [taxInvoice.domain, taxInvoice.id, taxInvoice.deletedAt], {
87
+ unique: true
88
+ })
89
+ @Index('ix_tax_invoice_1', (taxInvoice: TaxInvoice) => [taxInvoice.domain, taxInvoice.issueDate])
90
+ @Index('ix_approval_no', (taxInvoice: TaxInvoice) => [taxInvoice.domain, taxInvoice.approvalNo], { unique: true })
91
+ @ObjectType({ description: 'Entity for TaxInvoice' })
92
+ export class TaxInvoice {
93
+ @PrimaryGeneratedColumn('uuid')
94
+ @Field(type => ID)
95
+ readonly id!: string
96
+
97
+ @ManyToOne(type => Domain)
98
+ @Field(type => Domain)
99
+ domain?: Domain
100
+
101
+ @RelationId((taxInvoice: TaxInvoice) => taxInvoice.domain)
102
+ domainId?: string
103
+
104
+ @OneToMany(type => TaxInvoiceItem, taxInvoiceItem => taxInvoiceItem.taxInvoice)
105
+ @Field(type => [TaxInvoiceItem], { nullable: true })
106
+ taxInvoiceItems?: TaxInvoiceItem[]
107
+
108
+ @Column({ nullable: true, comment: '메모' })
109
+ @Field({ nullable: true, description: '메모' })
110
+ memo?: string
111
+
112
+ @Column({ nullable: false, comment: '세금계산서 구분 (매출: 10, 매입: 20, NTS: 30)' })
113
+ @Field({ nullable: false, description: '세금계산서 구분 (매출: 10, 매입: 20, NTS: 30)' })
114
+ category!: Category
115
+
116
+ @Column({ nullable: true, comment: '연동 번호 (작성 시 번호, 승인번호와 동일)' })
117
+ @Field({ nullable: true, description: '연동 번호 (작성 시 번호, 승인번호와 동일)' })
118
+ issueNo?: string
119
+
120
+ @Column({ nullable: true, comment: '승인 번호 (24자리)' })
121
+ @Field({ nullable: true, description: '승인 번호 (24자리)' })
122
+ approvalNo?: string
123
+
124
+ @Column({ nullable: true, default: '', comment: '원 승인 번호 (계산서 수정시 원래의 승인 번호)' })
125
+ @Field({ nullable: true, description: '원 승인 번호 (계산서 수정시 원래의 승인 번호)' })
126
+ originalApprovalNo?: string
127
+
128
+ @Column({ nullable: true, comment: '세금계산서 작성 일자 (YYYY-MM-DD)' })
129
+ @Field({ nullable: true, description: '세금계산서 작성 일자 (YYYY-MM-DD)' })
130
+ issueDate!: Date
131
+
132
+ @Column({ nullable: true, comment: '세금계산서 전자 서명 일자 (YYYY-MM-DD)' })
133
+ @Field({ nullable: true, description: '세금계산서 전자 서명 일자 (YYYY-MM-DD)' })
134
+ signatureDate?: Date
135
+
136
+ @Column({ nullable: false, comment: '세금계산서 종류 코드 (일반, 영세율, 위수탁)' })
137
+ @Field({ nullable: false, description: '세금계산서 종류 코드 (일반, 영세율, 위수탁)' })
138
+ invoiceType!: InvoiceType
139
+
140
+ @Column({ nullable: false, comment: '세금계산서의 영수/청구 구분 지시자 코드' })
141
+ @Field({ nullable: false, description: '세금계산서의 영수/청구 구분 지시자 코드' })
142
+ purpose!: Purpose
143
+
144
+ @Column({ nullable: true, comment: '수정 사유 코드' })
145
+ @Field({ nullable: true, description: '수정 사유 코드' })
146
+ revisedReason?: RevisedReason
147
+
148
+ @Column({ nullable: true, comment: '비고0' })
149
+ @Field({ nullable: true, description: '비고0' })
150
+ remark0?: string
151
+
152
+ @Column({ nullable: true, comment: '비고1' })
153
+ @Field({ nullable: true, description: '비고1' })
154
+ remark1?: string
155
+
156
+ @Column({ nullable: true, comment: '비고2' })
157
+ @Field({ nullable: true, description: '비고2' })
158
+ remark2?: string
159
+
160
+ @Column({ nullable: true, default: false, comment: 'API를 통한 발행 여부' })
161
+ @Field({ nullable: true, description: 'API를 통한 발행 여부' })
162
+ isSentByApi?: boolean
163
+
164
+ @Column({ nullable: true, comment: '공급자 사업자등록번호 구분 코드' })
165
+ @Field({ nullable: true, description: '공급자 사업자등록번호 구분 코드' })
166
+ supplierBusinessRegistrationCategory?: BusinessRegistrationCategory
167
+
168
+ @Column({ nullable: false, comment: '공급자 사업자등록번호', transformer: encryptTransformer })
169
+ @Field({ nullable: false, description: '공급자 사업자등록번호' })
170
+ supplierBusinessRegistrationNumber!: string
171
+
172
+ @Column({ nullable: true, default: '0', comment: '종사업장 식별 코드' })
173
+ @Field({ nullable: true, description: '종사업장 식별 코드' })
174
+ supplierBranchIdentification?: string
175
+
176
+ @Column({ nullable: false, comment: '공급자 사업자명' })
177
+ @Field({ nullable: false, description: '공급자 사업자명' })
178
+ supplierBusinessName!: string
179
+
180
+ @Column({ nullable: false, comment: '공급자 대표자명' })
181
+ @Field({ nullable: false, description: '공급자 대표자명' })
182
+ supplierRepresentativeName!: string
183
+
184
+ @Column({ nullable: true, comment: '공급자 주소', transformer: encryptTransformer })
185
+ @Field({ nullable: true, description: '공급자 주소' })
186
+ supplierAddress?: string
187
+
188
+ @Column({ nullable: true, comment: '공급자 업태' })
189
+ @Field({ nullable: true, description: '공급자 업태' })
190
+ supplierBusinessType?: string
191
+
192
+ @Column({ nullable: true, comment: '공급자 업종' })
193
+ @Field({ nullable: true, description: '공급자 업종' })
194
+ supplierIndustryType?: string
195
+
196
+ @Column({ nullable: true, comment: '공급자 담당 부서' })
197
+ @Field({ nullable: true, description: '공급자 담당 부서' })
198
+ supplierDepartment?: string
199
+
200
+ @Column({ nullable: true, comment: '공급자 담당자명', transformer: encryptTransformer })
201
+ @Field({ nullable: true, description: '공급자 담당자명' })
202
+ supplierContactName?: string
203
+
204
+ @Column({ nullable: true, comment: '공급자 담당자 전화번호', transformer: encryptTransformer })
205
+ @Field({ nullable: true, description: '공급자 담당자 전화번호' })
206
+ supplierContactPhone?: string
207
+
208
+ @Column({ nullable: true, comment: '공급자 담당자 이메일', transformer: encryptTransformer })
209
+ @Field({ nullable: true, description: '공급자 담당자 이메일' })
210
+ supplierContactEmail?: string
211
+
212
+ @Column({ nullable: true, comment: '공급자 담당자 핸드폰 번호', transformer: encryptTransformer })
213
+ @Field({ nullable: true, description: '공급자 담당자 핸드폰 번호' })
214
+ supplierContactCellPhone?: string
215
+
216
+ @Column({ nullable: true, comment: '공급받는자 사업자등록번호 구분 코드' })
217
+ @Field({ nullable: true, description: '공급받는자 사업자등록번호 구분 코드' })
218
+ buyerBusinessRegistrationCategory?: BusinessRegistrationCategory
219
+
220
+ @Column({ nullable: false, comment: '공급받는자 사업자등록번호', transformer: encryptTransformer })
221
+ @Field({ nullable: false, description: '공급받는자 사업자등록번호' })
222
+ buyerBusinessRegistrationNumber!: string
223
+
224
+ @Column({ nullable: true, default: '0', comment: '공급받는자 종사업장 식별 코드' })
225
+ @Field({ nullable: true, description: '공급받는자 종사업장 식별 코드' })
226
+ buyerBranchIdentification?: string
227
+
228
+ @Column({ nullable: false, comment: '공급받는자 사업자명' })
229
+ @Field({ nullable: false, description: '공급받는자 사업자명' })
230
+ buyerBusinessName!: string
231
+
232
+ @Column({ nullable: false, comment: '공급받는자 대표자명' })
233
+ @Field({ nullable: false, description: '공급받는자 대표자명' })
234
+ buyerRepresentativeName!: string
235
+
236
+ @Column({ nullable: true, comment: '공급받는자 주소', transformer: encryptTransformer })
237
+ @Field({ nullable: true, description: '공급받는자 주소' })
238
+ buyerAddress?: string
239
+
240
+ @Column({ nullable: true, comment: '공급받는자 업태' })
241
+ @Field({ nullable: true, description: '공급받는자 업태' })
242
+ buyerBusinessType?: string
243
+
244
+ @Column({ nullable: true, comment: '공급받는자 업종' })
245
+ @Field({ nullable: true, description: '공급받는자 업종' })
246
+ buyerIndustryType?: string
247
+
248
+ @Column({ nullable: true, comment: '공급받는자 1st 담당부서' })
249
+ @Field({ nullable: true, description: '공급받는자 1st 담당부서' })
250
+ buyer1stDepartment?: string
251
+
252
+ @Column({ nullable: true, comment: '공급받는자 1st 담당자명', transformer: encryptTransformer })
253
+ @Field({ nullable: true, description: '공급받는자 1st 담당자명' })
254
+ buyer1stContactName?: string
255
+
256
+ @Column({ nullable: true, comment: '공급받는자 1st 담당자 전화번호', transformer: encryptTransformer })
257
+ @Field({ nullable: true, description: '공급받는자 1st 담당자 전화번호' })
258
+ buyer1stContactPhone?: string
259
+
260
+ @Column({ nullable: true, comment: '공급받는자 1st 담당자 이메일', transformer: encryptTransformer })
261
+ @Field({ nullable: true, description: '공급받는자 1st 담당자 이메일' })
262
+ buyer1stContactEmail?: string
263
+
264
+ @Column({ nullable: true, comment: '공급받는자 1st 담당자 핸드폰번호', transformer: encryptTransformer })
265
+ @Field({ nullable: true, description: '공급받는자 1st 담당자 핸드폰번호' })
266
+ buyer1stContactCellPhone?: string
267
+
268
+ @Column({ nullable: true, comment: '공급받는자 2nd 담당부서' })
269
+ @Field({ nullable: true, description: '공급받는자 2nd 담당부서' })
270
+ buyer2ndDepartment?: string
271
+
272
+ @Column({ nullable: true, comment: '공급받는자 2nd 담당자명', transformer: encryptTransformer })
273
+ @Field({ nullable: true, description: '공급받는자 2nd 담당자명' })
274
+ buyer2ndContactName?: string
275
+
276
+ @Column({ nullable: true, comment: '공급받는자 2nd 담당자 전화번호', transformer: encryptTransformer })
277
+ @Field({ nullable: true, description: '공급받는자 2nd 담당자 전화번호' })
278
+ buyer2ndContactPhone?: string
279
+
280
+ @Column({ nullable: true, comment: '공급받는자 2nd 담당자 이메일', transformer: encryptTransformer })
281
+ @Field({ nullable: true, description: '공급받는자 2nd 담당자 이메일' })
282
+ buyer2ndContactEmail?: string
283
+
284
+ @Column({ nullable: true, comment: '공급받는자 2nd 담당자 핸드폰번호', transformer: encryptTransformer })
285
+ @Field({ nullable: true, description: '공급받는자 2nd 담당자 핸드폰번호' })
286
+ buyer2ndContactCellPhone?: string
287
+
288
+ @Column({ nullable: true, comment: '수탁사업자 사업자등록번호 구분 코드' })
289
+ @Field({ nullable: true, description: '수탁사업자 사업자등록번호 구분 코드' })
290
+ agentBusinessRegistrationCategory?: BusinessRegistrationCategory
291
+
292
+ @Column({ nullable: true, comment: '수탁사업자 사업자등록번호 (nnnnnnnnnn)', transformer: encryptTransformer })
293
+ @Field({ nullable: true, description: '수탁사업자 사업자등록번호 (nnnnnnnnnn)' })
294
+ agentBusinessRegistrationNumber?: string
295
+
296
+ @Column({ nullable: true, default: '', comment: '수탁사업자 종사업장 식별코드' })
297
+ @Field({ nullable: true, description: '수탁사업자 종사업장 식별코드' })
298
+ agentBranchIdentification?: string
299
+
300
+ @Column({ nullable: true, comment: '수탁사업자 사업자명' })
301
+ @Field({ nullable: true, description: '수탁사업자 사업자명' })
302
+ agentBusinessName?: string
303
+
304
+ @Column({ nullable: true, comment: '수탁사업자 대표자명' })
305
+ @Field({ nullable: true, description: '수탁사업자 대표자명' })
306
+ agentRepresentativeName?: string
307
+
308
+ @Column({ nullable: true, comment: '수탁사업자 주소', transformer: encryptTransformer })
309
+ @Field({ nullable: true, description: '수탁사업자 주소' })
310
+ agentAddress?: string
311
+
312
+ @Column({ nullable: true, comment: '수탁사업자 업태' })
313
+ @Field({ nullable: true, description: '수탁사업자 업태' })
314
+ agentBusinessType?: string
315
+
316
+ @Column({ nullable: true, comment: '수탁사업자 업종' })
317
+ @Field({ nullable: true, description: '수탁사업자 업종' })
318
+ agentIndustryType?: string
319
+
320
+ @Column({ nullable: true, comment: '수탁사업자 담당부서' })
321
+ @Field({ nullable: true, description: '수탁사업자 담당부서' })
322
+ agentDepartment?: string
323
+
324
+ @Column({ nullable: true, comment: '수탁사업자 담당자명', transformer: encryptTransformer })
325
+ @Field({ nullable: true, description: '수탁사업자 담당자명' })
326
+ agentContactName?: string
327
+
328
+ @Column({ nullable: true, comment: '수탁사업자 담당자 전화번호', transformer: encryptTransformer })
329
+ @Field({ nullable: true, description: '수탁사업자 담당자 전화번호' })
330
+ agentContactPhone?: string
331
+
332
+ @Column({ nullable: true, comment: '수탁사업자 담당자 이메일', transformer: encryptTransformer })
333
+ @Field({ nullable: true, description: '수탁사업자 담당자 이메일' })
334
+ agentContactEmail?: string
335
+
336
+ @Column({ nullable: true, comment: '수탁사업자 담당자 핸드폰번호', transformer: encryptTransformer })
337
+ @Field({ nullable: true, description: '수탁사업자 담당자 핸드폰번호' })
338
+ agentContactCellPhone?: string
339
+
340
+ @Column({ nullable: true, comment: '결제 금액 - 현금' })
341
+ @Field({ nullable: true, description: '결제 금액 - 현금' })
342
+ paymentAmountCash?: number
343
+
344
+ @Column({ nullable: true, comment: '결제 금액 - 수표' })
345
+ @Field({ nullable: true, description: '결제 금액 - 수표' })
346
+ paymentAmountCheck?: number
347
+
348
+ @Column({ nullable: true, comment: '결제 금액 - 어음' })
349
+ @Field({ nullable: true, description: '결제 금액 - 어음' })
350
+ paymentAmountPromissoryNote?: number
351
+
352
+ @Column({ nullable: true, comment: '결제 금액 - 외상 미수금' })
353
+ @Field({ nullable: true, description: '결제 금액 - 외상 미수금' })
354
+ paymentAmountAccountsReceivable?: number
355
+
356
+ @Column({ nullable: false, comment: '공급 가액' })
357
+ @Field({ nullable: false, description: '공급 가액' })
358
+ supplyAmount!: number
359
+
360
+ @Column({ nullable: true, comment: '세액' })
361
+ @Field({ nullable: true, description: '세액' })
362
+ taxAmount?: number
363
+
364
+ @Column({ nullable: false, comment: '총액 = 공급 가액 + 세액' })
365
+ @Field({ nullable: false, description: '총액 = 공급 가액 + 세액' })
366
+ totalAmount!: number
367
+
368
+ @CreateDateColumn()
369
+ @Field({ nullable: true })
370
+ createdAt?: Date
371
+
372
+ @UpdateDateColumn()
373
+ @Field({ nullable: true })
374
+ updatedAt?: Date
375
+
376
+ @DeleteDateColumn()
377
+ @Field({ nullable: true })
378
+ deletedAt?: Date
379
+
380
+ @ManyToOne(type => User, { nullable: true })
381
+ @Field(type => User, { nullable: true })
382
+ creator?: User
383
+
384
+ @RelationId((taxInvoice: TaxInvoice) => taxInvoice.creator)
385
+ creatorId?: string
386
+
387
+ @ManyToOne(type => User, { nullable: true })
388
+ @Field(type => User, { nullable: true })
389
+ updater?: User
390
+
391
+ @RelationId((taxInvoice: TaxInvoice) => taxInvoice.updater)
392
+ updaterId?: string
393
+ }
@@ -0,0 +1,6 @@
1
+ import { TaxInvoiceApi } from './tax-invoice-api'
2
+ import { TaxInvoiceApiQuery } from './tax-invoice-api-query'
3
+ import { TaxInvoiceApiMutation } from './tax-invoice-api-mutation'
4
+
5
+ export const entities = [TaxInvoiceApi]
6
+ export const resolvers = [TaxInvoiceApiQuery, TaxInvoiceApiMutation]
@@ -0,0 +1,275 @@
1
+ import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'
2
+ import { In } from 'typeorm'
3
+
4
+ import { TaxInvoiceApi } from './tax-invoice-api'
5
+ import { TaxInvoiceApiPatch, TaxInvoiceSend } from './tax-invoice-api-type'
6
+ import { TaxInvoiceItem } from '../tax-invoice-item/tax-invoice-item'
7
+ import { Category, InvoiceType, TaxInvoice } from '../tax-invoice/tax-invoice'
8
+ import { sendTaxInvoiceByUniposApi } from '../unipost-api/tax-invoice-send'
9
+ import { parseTaxInvoiceByUnipostFormat } from '../tax-invoice/tax-invoice-util'
10
+
11
+ @Resolver(TaxInvoiceApi)
12
+ export class TaxInvoiceApiMutation {
13
+ @Directive('@transaction')
14
+ @Mutation(returns => [TaxInvoiceApi], { description: 'To modify Tax Invoice Api information' })
15
+ async updateMultipleTaxInvoiceApi(
16
+ @Arg('patches', type => [TaxInvoiceApiPatch]) patches: TaxInvoiceApiPatch[],
17
+ @Ctx() context: ResolverContext
18
+ ): Promise<TaxInvoiceApi[]> {
19
+ const { domain, user, tx } = context.state
20
+
21
+ let results = []
22
+ const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')
23
+ const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')
24
+ const taxInvoiceApiRepo = tx.getRepository(TaxInvoiceApi)
25
+
26
+ if (_createRecords.length > 0) {
27
+ for (let i = 0; i < _createRecords.length; i++) {
28
+ const newRecord = _createRecords[i]
29
+
30
+ const result = await taxInvoiceApiRepo.save({
31
+ ...newRecord,
32
+ domain,
33
+ creator: user,
34
+ updater: user
35
+ })
36
+
37
+ results.push({ ...result, cuFlag: '+' })
38
+ }
39
+ }
40
+
41
+ if (_updateRecords.length > 0) {
42
+ for (let i = 0; i < _updateRecords.length; i++) {
43
+ const updateRecord = _updateRecords[i]
44
+ const taxAuditResult = await taxInvoiceApiRepo.findOneBy({ id: updateRecord.id })
45
+
46
+ const result = await taxInvoiceApiRepo.save({
47
+ ...taxAuditResult,
48
+ ...updateRecord,
49
+ updater: user
50
+ })
51
+
52
+ results.push({ ...result, cuFlag: 'M' })
53
+ }
54
+ }
55
+
56
+ return results
57
+ }
58
+
59
+ @Directive('@transaction')
60
+ @Mutation(returns => Boolean, { description: 'To delete multiple Tax Invoice Api' })
61
+ async deleteTaxInvoiceApis(@Arg('ids', type => [String]) ids: string[], @Ctx() context: ResolverContext): Promise<boolean> {
62
+ const { domain, tx } = context.state
63
+
64
+ await tx.getRepository(TaxInvoiceApi).delete({
65
+ domain: { id: domain.id },
66
+ id: In(ids)
67
+ })
68
+
69
+ return true
70
+ }
71
+
72
+ @Directive('@transaction')
73
+ @Mutation(returns => Boolean, { description: 'To Send Tax Invoices By Api' })
74
+ async sendTaxInvoicesByApi(
75
+ @Arg('taxInvoiceSendList', type => [TaxInvoiceSend]) taxInvoiceSendList: TaxInvoiceSend[],
76
+ @Ctx() context: ResolverContext
77
+ ): Promise<boolean> {
78
+ if (taxInvoiceSendList.length === 0) throw new Error('tax invoice send exception: no list')
79
+
80
+ const { domain, user, tx } = context.state
81
+ const taxInvoiceRepo = tx.getRepository(TaxInvoice)
82
+ const taxInvoiceItemRepo = tx.getRepository(TaxInvoiceItem)
83
+ const taxInvoiceApiRepo = tx.getRepository(TaxInvoiceApi)
84
+
85
+ const apiInfo = await taxInvoiceApiRepo.findOneBy({ isDefault: true })
86
+ const businessRegistrationNumber = apiInfo.businessRegistrationNumber
87
+ const { aid = '', bearer = '', customer_no = '' } = apiInfo?.attributes
88
+ let failCount = 0
89
+ let failMessage = []
90
+
91
+ // 1. 밸리데이션 및 데이터 파싱
92
+ let newTaxInvoiceSendList = taxInvoiceSendList.map(taxInvoiceSend => this._parseTaxInvoiceSendForApi(taxInvoiceSend, aid, customer_no))
93
+
94
+ // 2. 세금계산서 발행 API 호출
95
+ const apiResult = await sendTaxInvoiceByUniposApi(businessRegistrationNumber, aid, bearer, newTaxInvoiceSendList)
96
+ if (apiResult === false) {
97
+ // TODO 로그 찍기
98
+ throw new Error('tax invoice send exception: api error')
99
+ }
100
+
101
+ // 3. 성공하면 세금계산서 DB에 저장
102
+ for (let item of apiResult) {
103
+ if (item?.success) {
104
+ const { taxInvoice, taxInvoiceItems } = parseTaxInvoiceByUnipostFormat(item?.tAliceEntry, item?.tAliceEntry?.tAliceItemList, Category.EXPORT)
105
+
106
+ // 세금계산서 저장
107
+ const newTaxInvoice = await taxInvoiceRepo.save({
108
+ ...taxInvoice,
109
+ domain,
110
+ creator: user,
111
+ updater: user
112
+ })
113
+
114
+ // 아이템 저장
115
+ for (const item of taxInvoiceItems) {
116
+ await taxInvoiceItemRepo.save({ ...item, taxInvoice: newTaxInvoice, domain, creator: user })
117
+ }
118
+ } else {
119
+ failCount++
120
+ failMessage.push(`${item.inv_seq}: ${item.message}`)
121
+ }
122
+ }
123
+
124
+ // 실패가 1개라도 있으면 에러
125
+ if (failCount > 0) {
126
+ throw new Error(failCount + '개의 계산서 등록에 실패하였습니다.\n' + failMessage.join('\n'))
127
+ }
128
+
129
+ return true
130
+ }
131
+
132
+ // 유니스포트에 받을수 있는 포맷으로 데이터 파싱
133
+ private _parseTaxInvoiceSendForApi(taxInvoiceSend, aid, customer_no) {
134
+ const { taxInvoice, taxInvoiceItems } = taxInvoiceSend
135
+ let newTaxInvoiceItems: any = []
136
+ const today = new Intl.DateTimeFormat('fr-CA', { timeZone: 'Asia/Seoul' }).format(new Date()) // YYYY-MM-DD
137
+
138
+ // 필수값 체크
139
+ if (
140
+ !taxInvoice.supplierBusinessRegistrationNumber ||
141
+ !taxInvoice.supplierBusinessName ||
142
+ !taxInvoice.supplierRepresentativeName ||
143
+ !taxInvoice.buyerBusinessRegistrationNumber ||
144
+ !taxInvoice.buyerBusinessName ||
145
+ !taxInvoice.buyerRepresentativeName ||
146
+ !taxInvoice.issueDate
147
+ ) {
148
+ throw new Error('tax invoice send exception: no essential value')
149
+ }
150
+
151
+ // 공급자 사업자 등록번호가 전부 숫자이며 10자리 인지 체크
152
+ if (isNaN(taxInvoice.supplierBusinessRegistrationNumber) || taxInvoice.supplierBusinessRegistrationNumber.length !== 10) {
153
+ throw new Error('tax invoice send exception: Supplier Business Registration Number is wrong')
154
+ }
155
+
156
+ // 공급받는자 사업자 등록번호가 전부 숫자이며 10자리 인지 체크
157
+ if (isNaN(taxInvoice.buyerBusinessRegistrationNumber) || taxInvoice.buyerBusinessRegistrationNumber.length !== 10) {
158
+ throw new Error('tax invoice send exception: Buyer Business Registration Number is wrong')
159
+ }
160
+
161
+ // 작성일자가 오늘 날짜를 넘어가면 에러
162
+ if (taxInvoice.issueDate > today) {
163
+ throw new Error('tax invoice send exception: issueDate error')
164
+ }
165
+
166
+ // 현금, 수표, 어음, 외상미수금이 있을시 총 합계금액과 금액 동일 체크
167
+ const paymentAmount: number =
168
+ taxInvoice.paymentAmountCash + taxInvoice.paymentAmountCheck + taxInvoice.paymentAmountPromissoryNote + taxInvoice.paymentAmountAccountsReceivable
169
+ if (paymentAmount > 0 && paymentAmount !== taxInvoice.totalAmount) {
170
+ throw new Error('tax invoice send exception: summary is not same')
171
+ }
172
+
173
+ // 영세업자인데 세금이 있으면 에러
174
+ if (taxInvoice.invoiceType === InvoiceType.ZERO_RATED_TAX_INVOICE && taxInvoice.taxAmount > 0) {
175
+ throw new Error('tax invoice send exception: tax price is exist')
176
+ }
177
+
178
+ for (let item of taxInvoiceItems) {
179
+ // 아이템 필수값 체크
180
+ if (!item.supplyDate || !item.itemName || !item.quantity || !item.unitPrice) {
181
+ throw new Error('tax invoice send exception: no item essential value')
182
+ }
183
+
184
+ // 아이템의 일자가 작성일자보다 크면 에러
185
+ if (taxInvoice.issueDate < item.supplyDate) {
186
+ throw new Error('tax invoice send exception: item supplyDate is bigger than issueDate')
187
+ }
188
+
189
+ // 영세업자인데 아이템 세금이 있으면 에러
190
+ if (taxInvoice.invoiceType === InvoiceType.ZERO_RATED_TAX_INVOICE && item.taxPrice > 0) {
191
+ throw new Error('tax invoice send exception: item tax price is exist')
192
+ }
193
+
194
+ newTaxInvoiceItems.push({
195
+ tii_seqnumeric: item.sequence,
196
+ tii_purchaseexpirydatetime: item.supplyDate.replace(/-/g, ''),
197
+ tii_nametext: item.itemName,
198
+ tii_informationtext: item.specification,
199
+ tii_chargeableunitquantity: item.quantity,
200
+ tii_unitprice_unitamount: item.unitPrice,
201
+ tii_invoiceamount: item.supplyPrice,
202
+ tii_totaltax_calcamount: item.taxPrice,
203
+ tii_descriptiontext: item.remark
204
+ })
205
+ }
206
+
207
+ return {
208
+ aid: aid,
209
+ inv_seq: today.replace(/-/g, '') + customer_no,
210
+ exd_refdoc_id: null,
211
+ tid_issuedatetime: taxInvoice.issueDate.replace(/-/g, ''),
212
+ tid_typecode: taxInvoice.invoiceType,
213
+ tid_purposecode: taxInvoice.purpose,
214
+ tid_amendcode: taxInvoice.revisedReason,
215
+ tid_originalissueid: null,
216
+ tid_desc0: taxInvoice.remark0,
217
+ tid_desc1: null,
218
+ tid_desc2: null,
219
+ tit_alice_specorg_biztypecode: taxInvoice.supplierBusinessRegistrationCategory,
220
+ tit_alice_id: taxInvoice.supplierBusinessRegistrationNumber,
221
+ tit_alice_specorg_taxregid: taxInvoice.supplierBranchIdentification,
222
+ tit_alice_name: taxInvoice.supplierBusinessName,
223
+ tit_alice_specperson_name: taxInvoice.supplierRepresentativeName,
224
+ tit_alice_specaddr_lineone: taxInvoice.supplierAddress,
225
+ tit_alice_typecode: taxInvoice.supplierBusinessType,
226
+ tit_alice_classcode: taxInvoice.supplierIndustryType,
227
+ tit_alice_defcont_deptname: taxInvoice.supplierDepartment,
228
+ tit_alice_defcont_personname: taxInvoice.supplierContactName,
229
+ tit_alice_defcont_telcomm: taxInvoice.supplierContactPhone,
230
+ tit_alice_defcont_uricomm: taxInvoice.supplierContactEmail,
231
+ tit_alice_defcont_cellphone: taxInvoice.supplierContactCellPhone,
232
+ tit_bob_specorg_biztypecode: taxInvoice.buyerBusinessRegistrationCategory,
233
+ tit_bob_id: taxInvoice.buyerBusinessRegistrationNumber,
234
+ tit_bob_specorg_taxregid: taxInvoice.buyerBranchIdentification,
235
+ tit_bob_name: taxInvoice.buyerBusinessName,
236
+ tit_bob_specperson_name: taxInvoice.buyerRepresentativeName,
237
+ tit_bob_specaddr_lineone: taxInvoice.buyerAddress,
238
+ tit_bob_typecode: taxInvoice.buyerBusinessType,
239
+ tit_bob_classcode: taxInvoice.buyerIndustryType,
240
+ tit_bob_1stdefcont_deptname: taxInvoice.buyer1stDepartment,
241
+ tit_bob_1stdefcont_personname: taxInvoice.buyer1stContactName,
242
+ tit_bob_1stdefcont_telcomm: taxInvoice.buyer1stContactPhone,
243
+ tit_bob_1stdefcont_uricomm: taxInvoice.buyer1stContactEmail,
244
+ tit_bob_1stdefcont_cellphone: taxInvoice.buyer1stContactCellPhone,
245
+ tit_bob_2nddefcont_deptname: taxInvoice.buyer2ndDepartment,
246
+ tit_bob_2nddefcont_personname: taxInvoice.buyer2ndContactName,
247
+ tit_bob_2nddefcont_telcomm: taxInvoice.buyer2ndContactPhone,
248
+ tit_bob_2nddefcont_uricomm: taxInvoice.buyer2ndContactEmail,
249
+ tit_bob_2nddefcont_cellphone: taxInvoice.buyer2ndContactCellPhone,
250
+ tit_broker_specorg_biztypecode: taxInvoice.agentBusinessRegistrationCategory,
251
+ tit_broker_id: taxInvoice.agentBusinessRegistrationNumber,
252
+ tit_broker_specorg_taxregid: taxInvoice.agentBranchIdentification,
253
+ tit_broker_name: taxInvoice.agentBusinessName,
254
+ tit_broker_specperson_name: taxInvoice.agentRepresentativeName,
255
+ tit_broker_specaddr_lineone: taxInvoice.agentAddress,
256
+ tit_broker_typecode: taxInvoice.agentBusinessType,
257
+ tit_broker_classcode: taxInvoice.agentIndustryType,
258
+ tit_broker_defcont_deptname: taxInvoice.agentDepartment,
259
+ tit_broker_defcont_personname: taxInvoice.agentContactName,
260
+ tit_broker_defcont_telcomm: taxInvoice.agentContactPhone,
261
+ tit_broker_defcont_uricomm: taxInvoice.agentContactEmail,
262
+ tit_broker_defcont_cellphone: taxInvoice.agentContactCellPhone,
263
+ tit_specpay_paidamount10: taxInvoice.paymentAmountCash,
264
+ tit_specpay_paidamount20: taxInvoice.paymentAmountCheck,
265
+ tit_specpay_paidamount30: taxInvoice.paymentAmountPromissoryNote,
266
+ tit_specpay_paidamount40: taxInvoice.paymentAmountAccountsReceivable,
267
+ tit_specsum_chargeamount: taxInvoice.supplyAmount,
268
+ tit_specsum_taxamount: taxInvoice.taxAmount,
269
+ tit_specsum_grandamount: taxInvoice.totalAmount,
270
+ inv_sign: '',
271
+ biz_tocharlesconfirmstatus: null,
272
+ tAliceItemList: newTaxInvoiceItems
273
+ }
274
+ }
275
+ }