@things-factory/tax-invoice 6.2.147 → 6.2.152

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 (34) hide show
  1. package/client/pages/tax-invoice-send/company-list-popup.ts +3 -0
  2. package/client/pages/tax-invoice-send/tax-invoice-send-page.ts +9 -898
  3. package/client/pages/tax-invoice-send/tax-invoice-send.ts +951 -0
  4. package/dist-client/pages/tax-invoice-send/company-list-popup.d.ts +3 -0
  5. package/dist-client/pages/tax-invoice-send/company-list-popup.js +3 -0
  6. package/dist-client/pages/tax-invoice-send/company-list-popup.js.map +1 -1
  7. package/dist-client/pages/tax-invoice-send/tax-invoice-send-page.d.ts +2 -79
  8. package/dist-client/pages/tax-invoice-send/tax-invoice-send-page.js +8 -796
  9. package/dist-client/pages/tax-invoice-send/tax-invoice-send-page.js.map +1 -1
  10. package/dist-client/pages/tax-invoice-send/tax-invoice-send.d.ts +112 -0
  11. package/dist-client/pages/tax-invoice-send/tax-invoice-send.js +869 -0
  12. package/dist-client/pages/tax-invoice-send/tax-invoice-send.js.map +1 -0
  13. package/dist-client/route.d.ts +1 -1
  14. package/dist-client/tsconfig.tsbuildinfo +1 -1
  15. package/dist-server/service/index.js +1 -0
  16. package/dist-server/service/index.js.map +1 -1
  17. package/dist-server/service/tax-invoice/tax-invoice-mutation.js +0 -4
  18. package/dist-server/service/tax-invoice/tax-invoice-mutation.js.map +1 -1
  19. package/dist-server/service/tax-invoice/tax-invoice-query.js +18 -6
  20. package/dist-server/service/tax-invoice/tax-invoice-query.js.map +1 -1
  21. package/dist-server/service/tax-invoice/tax-invoice-type.js +4 -0
  22. package/dist-server/service/tax-invoice/tax-invoice-type.js.map +1 -1
  23. package/dist-server/service/tax-invoice/tax-invoice-util.js +1 -0
  24. package/dist-server/service/tax-invoice/tax-invoice-util.js.map +1 -1
  25. package/dist-server/service/tax-invoice/tax-invoice.js +5 -0
  26. package/dist-server/service/tax-invoice/tax-invoice.js.map +1 -1
  27. package/dist-server/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +3 -3
  29. package/server/service/index.ts +1 -0
  30. package/server/service/tax-invoice/tax-invoice-mutation.ts +0 -3
  31. package/server/service/tax-invoice/tax-invoice-query.ts +19 -7
  32. package/server/service/tax-invoice/tax-invoice-type.ts +3 -0
  33. package/server/service/tax-invoice/tax-invoice-util.ts +1 -0
  34. package/server/service/tax-invoice/tax-invoice.ts +4 -0
@@ -0,0 +1,951 @@
1
+ import '@operato/data-grist'
2
+
3
+ import { css, html, LitElement } from 'lit'
4
+ import { CommonGristStyles, ScrollbarStyles } from '@operato/styles'
5
+ import { property, customElement } from 'lit/decorators.js'
6
+ import { client } from '@operato/graphql'
7
+ import { i18next, localize } from '@operato/i18n'
8
+ import gql from 'graphql-tag'
9
+ import { BUSINESS_REGISTRATION_CATEGORY, BusinessRegistrationCategory, Category, INVOICE_TYPE, InvoiceType, PURPOSE, Purpose } from '../tax-invoice/tax-invoice-list-page'
10
+ import { openPopup } from '@operato/layout'
11
+
12
+ export const SHORT_INVOICE_TYPE = {
13
+ TAX_INVOICE: {
14
+ [InvoiceType.TAX_INVOICE]: '일반',
15
+ [InvoiceType.SMALL_BUSINESS_TAX_INVOICE]: '영세율',
16
+ [InvoiceType.CONSIGNMENT_TAX_INVOICE]: '위수탁',
17
+ [InvoiceType.SMALL_BUSINESS_CONSIGNMENT_TAX_INVOICE]: '위수탁영세율'
18
+ },
19
+ INVOICE: {
20
+ [InvoiceType.INVOICE]: '일반',
21
+ [InvoiceType.CONSIGNMENT_INVOICE]: '위수탁'
22
+ // [InvoiceType.IMPORT_INVOICE]: INVOICE_TYPE[IMPORT_INVOICE],
23
+ }
24
+ }
25
+
26
+ export const SHORT_BUSINESS_REGISTRATION_CATEGORY = {
27
+ [BusinessRegistrationCategory.BUSINESS_REGISTRATION_NUMBER]: '사업자',
28
+ [BusinessRegistrationCategory.RESIDENT_REGISTRATION_NUMBER]: '개인',
29
+ [BusinessRegistrationCategory.FOREIGNER_REGISTRATION_NUMBER]: '외국인'
30
+ }
31
+
32
+ export interface Supplier {
33
+ supplierBusinessRegistrationCategory: string
34
+ supplierBusinessRegistrationNumber: string
35
+ supplierBranchIdentification?: string
36
+ supplierBusinessName: string
37
+ supplierRepresentativeName: string
38
+ supplierAddress?: string
39
+ supplierBusinessType?: string
40
+ supplierIndustryType?: string
41
+ supplierDepartment?: string
42
+ supplierContactName?: string
43
+ supplierContactPhone?: string
44
+ supplierContactEmail?: string
45
+ supplierContactCellPhone?: string
46
+ }
47
+ export interface Buyer {
48
+ buyerBusinessRegistrationCategory: BusinessRegistrationCategory
49
+ buyerBusinessRegistrationNumber: string
50
+ buyerBranchIdentification?: string
51
+ buyerBusinessName: string
52
+ buyerRepresentativeName: string
53
+ buyerAddress?: string
54
+ buyerBusinessType?: string
55
+ buyerIndustryType?: string
56
+ buyer1stDepartment?: string
57
+ buyer1stContactName?: string
58
+ buyer1stContactPhone?: string
59
+ buyer1stContactEmail?: string
60
+ buyer1stContactCellPhone?: string
61
+ buyer2ndDepartment?: string
62
+ buyer2ndContactName?: string
63
+ buyer2ndContactPhone?: string
64
+ buyer2ndContactEmail?: string
65
+ buyer2ndContactCellPhone?: string
66
+ }
67
+ export interface TaxInvoice {
68
+ category: Category
69
+ issueNo?: string
70
+ approvalNo?: string
71
+ originalApprovalNo?: string
72
+ issueDate: string
73
+ signatureDate?: string
74
+ invoiceType: InvoiceType
75
+ purpose: Purpose
76
+ remark0?: string
77
+ remark1?: string
78
+ remark2?: string
79
+ paymentAmountCash?: number
80
+ paymentAmountCheck?: number
81
+ paymentAmountPromissoryNote?: number
82
+ paymentAmountAccountsReceivable?: number
83
+ supplyAmount: number
84
+ taxAmount: number
85
+ totalAmount: number
86
+ // revisedReason?: RevisedReason
87
+ }
88
+ export interface TaxInvoiceItem {
89
+ sequence: number
90
+ supplyDate: string
91
+ itemName: string
92
+ specification: string
93
+ quantity: number
94
+ unitPrice: number
95
+ supplyPrice: number
96
+ taxPrice: number
97
+ remark?: string
98
+ }
99
+
100
+ @customElement('tax-invoice-send')
101
+ export class TaxInvoiceSend extends localize(i18next)(LitElement) {
102
+ static styles = [
103
+ ScrollbarStyles,
104
+ CommonGristStyles,
105
+ css`
106
+ :host {
107
+ display: flex;
108
+ flex-direction: column;
109
+ overflow-y: auto;
110
+ overflow-x: hidden;
111
+
112
+ width: 100%;
113
+ min-width: 850px;
114
+ padding: 0 40px 40px 40px;
115
+
116
+ --grid-record-emphasized-background-color: red;
117
+ --grid-record-emphasized-color: yellow;
118
+ }
119
+
120
+ .flex-row {
121
+ display: flex;
122
+ flex-direction: row;
123
+ }
124
+ .flex-column {
125
+ display: flex;
126
+ flex-direction: column;
127
+ }
128
+
129
+ input[type='text'],
130
+ input[type='date'],
131
+ input[type='number'] {
132
+ width: 85%;
133
+ max-width: calc(100% - 12px);
134
+ height: 14px;
135
+ margin: 0;
136
+ padding: 4px 5px 5px;
137
+ line-height: 14px;
138
+ border: 1px solid #bbb;
139
+ background: #fff;
140
+ letter-spacing: 0.5px;
141
+ }
142
+ input[type='date'] {
143
+ width: auto;
144
+ }
145
+ input[readonly],
146
+ input:disabled {
147
+ background-color: #eee;
148
+ }
149
+
150
+ div.invoice-type {
151
+ font-size: 18px;
152
+ margin-top: 15px;
153
+ }
154
+
155
+ table {
156
+ border: solid;
157
+ border-width: 2px 0;
158
+ border-collapse: collapse;
159
+ border-spacing: 0;
160
+ }
161
+
162
+ .title table {
163
+ border-color: #d3dbe5;
164
+ width: 100%;
165
+ height: 33px;
166
+ margin-top: 10px;
167
+ font-size: 12px;
168
+
169
+ th {
170
+ font-size: 13px;
171
+ background-color: #e9edf6;
172
+ min-width: 140px;
173
+ }
174
+ td {
175
+ width: 50%;
176
+ padding-left: 10px;
177
+
178
+ & > * {
179
+ vertical-align: middle;
180
+ }
181
+ & > input {
182
+ margin: 0 5px 0 1px;
183
+ }
184
+ }
185
+ }
186
+
187
+ div.body {
188
+ margin-top: 15px;
189
+ font-size: 14px;
190
+
191
+ div.data {
192
+ display: flex;
193
+ margin-top: 5px;
194
+
195
+ table {
196
+ flex: 1;
197
+
198
+ td,
199
+ th {
200
+ padding: 5px;
201
+ min-width: 60px;
202
+ }
203
+ td {
204
+ padding-left: 8px;
205
+ }
206
+ th.target {
207
+ width: 25px;
208
+ writing-mode: vertical-rl;
209
+ min-width: unset;
210
+ }
211
+
212
+ &.supplier {
213
+ border-color: #f64843;
214
+
215
+ td,
216
+ th {
217
+ background-color: #fef5f7;
218
+ border: solid 1.5px #f5b1b1;
219
+ }
220
+ th.target {
221
+ background-color: #fedbde;
222
+ }
223
+ }
224
+ &.buyer {
225
+ border-color: #007ed9;
226
+
227
+ td,
228
+ th {
229
+ background-color: #f7f7ff;
230
+ border: solid 1.5px #a7bcff;
231
+ }
232
+ th.target {
233
+ background-color: #c6daf6;
234
+ }
235
+ }
236
+ }
237
+ }
238
+
239
+ div.header {
240
+ display: flex;
241
+
242
+ span {
243
+ flex: 1;
244
+ }
245
+ }
246
+
247
+ div.info {
248
+ margin-top: 15px;
249
+ border: solid;
250
+ border-color: #000;
251
+ border-width: 2px 0px 0px 0px;
252
+
253
+ div.flex-row div {
254
+ border: solid #c4d2ff;
255
+ border-width: 0px 1.5px 1.5px 1.5px;
256
+ margin-right: -1px;
257
+ padding: 5px;
258
+ text-align: center;
259
+
260
+ &.title {
261
+ background-color: #e9edf5;
262
+ font-weight: bold;
263
+ flex: 1;
264
+ }
265
+ &.value {
266
+ flex: 3;
267
+ text-align: left;
268
+
269
+ .desc {
270
+ font-size: 11px;
271
+ color: #c90000;
272
+ }
273
+ }
274
+ }
275
+ }
276
+
277
+ div.items,
278
+ div.summary {
279
+ margin-top: 20px;
280
+
281
+ table {
282
+ width: 100%;
283
+ border-color: #000;
284
+ border-width: 2px 0px 0px 0px;
285
+
286
+ th {
287
+ background-color: #e9edf5;
288
+ }
289
+ th,
290
+ td {
291
+ border: solid 1.5px #c4d2ff;
292
+ padding: 5px;
293
+ text-align: center;
294
+ }
295
+ }
296
+ }
297
+
298
+ div.summary {
299
+ display: flex;
300
+
301
+ & > table {
302
+ flex: 6.7;
303
+ }
304
+ & > div {
305
+ flex: 3.2;
306
+ display: flex;
307
+ justify-content: center;
308
+ align-items: center;
309
+ border: 1.5px solid #c4d2ff;
310
+ border-top: 2px solid #000;
311
+ }
312
+
313
+ span.type-wrapper {
314
+ margin: 0 10px;
315
+
316
+ & > div {
317
+ display: flex;
318
+ justify-content: center;
319
+ align-items: center;
320
+ gap: 4px;
321
+
322
+ input[type='radio' i] {
323
+ margin: 0px;
324
+ }
325
+ }
326
+ }
327
+ }
328
+
329
+ div.items {
330
+ div.desc {
331
+ font-weight: 400;
332
+ font-size: 12px;
333
+ margin-bottom: 5px;
334
+ }
335
+ div.desc-date {
336
+ color: #005d98;
337
+ }
338
+ button {
339
+ font-size: 13px;
340
+ height: 25px;
341
+ cursor: pointer;
342
+ text-align: center;
343
+ font-weight: 600;
344
+ border-radius: 2px;
345
+ border-color: #ccc;
346
+ }
347
+ .btn-add {
348
+ color: #333;
349
+ background-color: #f9f9f9;
350
+ }
351
+ .btn-delete {
352
+ color: #fff;
353
+ background-color: #5c636e;
354
+ border: none;
355
+ }
356
+ }
357
+
358
+ *[required]::before {
359
+ content: '*';
360
+ color: red;
361
+ margin-right: 2px;
362
+ }
363
+ }
364
+ `
365
+ ]
366
+
367
+ // 오늘 날짜 YYYY-MM-DD 형식으로 뽑기
368
+ private today: string = new Intl.DateTimeFormat('fr-CA', { timeZone: 'Asia/Seoul' }).format(new Date())
369
+ private isTaxFree = false
370
+ private defaultSupplier = {
371
+ supplierBusinessRegistrationCategory: '01',
372
+ supplierBusinessRegistrationNumber: '',
373
+ supplierBranchIdentification: '',
374
+ supplierBusinessName: '',
375
+ supplierRepresentativeName: ''
376
+ }
377
+ private defaultBuyer = {
378
+ buyerBusinessRegistrationCategory: BusinessRegistrationCategory.BUSINESS_REGISTRATION_NUMBER,
379
+ buyerBusinessRegistrationNumber: '',
380
+ buyerBusinessName: '',
381
+ buyerRepresentativeName: ''
382
+ }
383
+ private defaultTaxInvoice = {
384
+ invoiceType: InvoiceType.TAX_INVOICE,
385
+ category: Category.EXPORT,
386
+ issueDate: this.today,
387
+ purpose: Purpose.INVOICE,
388
+ supplyAmount: 0,
389
+ taxAmount: 0,
390
+ totalAmount: 0
391
+ }
392
+ private defaultTaxInvoiceItem = {
393
+ sequence: new Date().getTime(), // 구분용 임시 값 (중복되면 안되니 생성 마다 넣어주기)
394
+ supplyDate: '',
395
+ itemName: '',
396
+ specification: '',
397
+ quantity: 0,
398
+ unitPrice: 0,
399
+ supplyPrice: 0,
400
+ taxPrice: 0
401
+ }
402
+
403
+ @property({ type: Object }) supplier: Supplier = this.defaultSupplier
404
+ @property({ type: Object }) buyer: Buyer = this.defaultBuyer
405
+ @property({ type: Object }) taxInvoice: TaxInvoice = this.defaultTaxInvoice
406
+ @property({ type: Array }) taxInvoiceItems: TaxInvoiceItem[] = [{ ...this.defaultTaxInvoiceItem }]
407
+
408
+ render() {
409
+ return html`
410
+ <div class="invoice-type">
411
+ * ${INVOICE_TYPE[this.taxInvoice?.invoiceType]} (${SHORT_BUSINESS_REGISTRATION_CATEGORY[this.buyer.buyerBusinessRegistrationCategory]})
412
+ </div>
413
+
414
+ <div class="title">
415
+ <table>
416
+ <tr>
417
+ <th>${i18next.t('field.short invoice type')}</th>
418
+ <td>
419
+ ${Object.keys(SHORT_INVOICE_TYPE['TAX_INVOICE']).map(key => {
420
+ const disabled: boolean = key !== InvoiceType.TAX_INVOICE && key !== InvoiceType.SMALL_BUSINESS_TAX_INVOICE
421
+ const checked: boolean = key === InvoiceType.TAX_INVOICE
422
+ return html`
423
+ <label for="${'tax_' + key}">${SHORT_INVOICE_TYPE['TAX_INVOICE'][key]}</label>
424
+ <input
425
+ type="radio"
426
+ id="${'tax_' + key}"
427
+ .value="${key}"
428
+ name="invoiceType"
429
+ ?checked=${checked}
430
+ ?disabled=${disabled}
431
+ @change=${this._onInputTaxInvoice}
432
+ />
433
+ `
434
+ })}
435
+ </td>
436
+ <th>${i18next.t('field.tax invoice buyer registration category')}</th>
437
+ <td>
438
+ ${Object.keys(BUSINESS_REGISTRATION_CATEGORY).map(key => {
439
+ const disabled: boolean = key !== BusinessRegistrationCategory.BUSINESS_REGISTRATION_NUMBER
440
+ const checked: boolean = key === BusinessRegistrationCategory.BUSINESS_REGISTRATION_NUMBER
441
+ return html`
442
+ <label for="${'tax_' + key}">${BUSINESS_REGISTRATION_CATEGORY[key]}</label>
443
+ <input type="radio" id="${'tax_' + key}" value="${key}" name="buyerBusinessRegistrationCategory" ?checked=${checked} ?disabled=${disabled} />
444
+ `
445
+ })}
446
+ </td>
447
+ </tr>
448
+ </table>
449
+ </div>
450
+
451
+ <div class="body">
452
+ <div class="header">
453
+ <span><button @click=${this._openSupplierPopup}>공급처 선택</button></span>
454
+ <span><button @click=${this._openBuyerPopup}>공급받는자 선택</button></span>
455
+ </div>
456
+
457
+ <div class="data">
458
+ <table class="supplier">
459
+ <colgroup>
460
+ <col width="150px" />
461
+ <col width="18%" />
462
+ <col width="32%" />
463
+ <col width="18%" />
464
+ <col width="32%" />
465
+ </colgroup>
466
+ <tr>
467
+ <th rowspan="6" class="target">${i18next.t('field.tax invoice supplier')}</th>
468
+ <th required>${i18next.t('field.short business registration number')}</th>
469
+ <td>${this.supplier?.supplierBusinessRegistrationNumber?.replace(/(\S{3})(\S{2})(\S{5})/g, '$1-$2-$3')}</td>
470
+ <th>${i18next.t('field.short branch identification')}</th>
471
+ <td>${this.supplier?.supplierBranchIdentification}</td>
472
+ </tr>
473
+ <tr>
474
+ <th required>${i18next.t('field.short tax invoice business name')}</th>
475
+ <td><input type="text" name="supplierBusinessName" .value=${this.supplier?.supplierBusinessName || ''} @input=${this._onInputTaxInvoice} /></td>
476
+ <th required>${i18next.t('field.tax invoice representative name')}</th>
477
+ <td>
478
+ <input type="text" name="supplierRepresentativeName" .value=${this.supplier?.supplierRepresentativeName || ''} @input=${this._onInputTaxInvoice} />
479
+ </td>
480
+ </tr>
481
+ <tr>
482
+ <th>${i18next.t('field.address')}</th>
483
+ <td colspan="3">${this.supplier?.supplierAddress}</td>
484
+ </tr>
485
+ <tr>
486
+ <th>${i18next.t('field.business type')}</th>
487
+ <td><input type="text" name="supplierBusinessType" .value=${this.supplier?.supplierBusinessType || ''} @input=${this._onInputTaxInvoice} /></td>
488
+ <th>${i18next.t('field.industry type')}</th>
489
+ <td><input type="text" name="supplierIndustryType" .value=${this.supplier?.supplierIndustryType || ''} @input=${this._onInputTaxInvoice} /></td>
490
+ </tr>
491
+ <tr>
492
+ <th rowspan="2">${i18next.t('field.email')}</th>
493
+ <td rowspan="2" colspan="3">
494
+ <input type="text" name="supplierContactEmail" .value=${this.supplier?.supplierContactEmail || ''} @input=${this._onInputTaxInvoice} />
495
+ </td>
496
+ </tr>
497
+ <tr></tr>
498
+ </table>
499
+
500
+ <table class="buyer">
501
+ <colgroup>
502
+ <col width="150px" />
503
+ <col width="18%" />
504
+ <col width="32%" />
505
+ <col width="18%" />
506
+ <col width="32%" />
507
+ </colgroup>
508
+ <tr>
509
+ <th rowspan="6" class="target">${i18next.t('field.tax invoice buyer')}</th>
510
+ <th required>${i18next.t('field.short business registration number')}</th>
511
+ <td>
512
+ <input
513
+ type="text"
514
+ maxlength="10"
515
+ name="buyerBusinessRegistrationNumber"
516
+ .value=${this.buyer?.buyerBusinessRegistrationNumber || ''}
517
+ @input=${this._onInputTaxInvoice}
518
+ />
519
+ </td>
520
+ <th>${i18next.t('field.short branch identification')}</th>
521
+ <td><input type="text" name="buyerBranchIdentification" .value=${this.buyer?.buyerBranchIdentification || ''} @input=${this._onInputTaxInvoice} /></td>
522
+ </tr>
523
+ <tr>
524
+ <th required>${i18next.t('field.short tax invoice business name')}</th>
525
+ <td><input type="text" name="buyerBusinessName" .value=${this.buyer?.buyerBusinessName || ''} @input=${this._onInputTaxInvoice} /></td>
526
+ <th required>${i18next.t('field.tax invoice representative name')}</th>
527
+ <td><input type="text" name="buyerRepresentativeName" .value=${this.buyer?.buyerRepresentativeName || ''} @input=${this._onInputTaxInvoice} /></td>
528
+ </tr>
529
+ <tr>
530
+ <th>${i18next.t('field.address')}</th>
531
+ <td colspan="3"><input type="text" name="buyerAddress" .value=${this.buyer?.buyerAddress || ''} @input=${this._onInputTaxInvoice} /></td>
532
+ </tr>
533
+ <tr>
534
+ <th>${i18next.t('field.business type')}</th>
535
+ <td><input type="text" name="buyerBusinessType" .value=${this.buyer?.buyerBusinessType || ''} @input=${this._onInputTaxInvoice} /></td>
536
+
537
+ <th>${i18next.t('field.industry type')}</th>
538
+ <td><input type="text" name="buyerIndustryType" .value=${this.buyer?.buyerIndustryType || ''} @input=${this._onInputTaxInvoice} /></td>
539
+ </tr>
540
+ <tr>
541
+ <th>${i18next.t('field.email')}</th>
542
+ <td colspan="3"><input type="text" name="buyer1stContactEmail" .value=${this.buyer?.buyer1stContactEmail || ''} @input=${this._onInputTaxInvoice} /></td>
543
+ </tr>
544
+ <tr>
545
+ <th>${i18next.t('field.email')}</th>
546
+ <td colspan="3"><input type="text" name="buyer2ndContactEmail" .value=${this.buyer?.buyer2ndContactEmail || ''} @input=${this._onInputTaxInvoice} /></td>
547
+ </tr>
548
+ </table>
549
+ </div>
550
+
551
+ <div class="info flex-column">
552
+ <div class="flex-row">
553
+ <div class="title" required>${i18next.t('field.issue date')}</div>
554
+ <div class="value">
555
+ <input type="date" name="issueDate" .value=${this.taxInvoice.issueDate} @input=${this._onInputTaxInvoice} />
556
+ <span class="desc">※ 작성일자는 공급 연월일을 의미함</span>
557
+ </div>
558
+ <div class="title">${i18next.t('field.remark0')}</div>
559
+ <div class="value"><input type="text" name="remark0" .value=${this.taxInvoice?.remark0 || ''} @input=${this._onInputTaxInvoice} /></div>
560
+ </div>
561
+ <div class="flex-row">
562
+ <div class="title">${i18next.t('field.total amount')}</div>
563
+ <div class="value">${this._numberFormat(this.taxInvoice?.totalAmount)}</div>
564
+ <div class="title">${i18next.t('field.supply amount')}</div>
565
+ <div class="value">${this._numberFormat(this.taxInvoice?.supplyAmount)}</div>
566
+ <div class="title">${i18next.t('field.tax amount')}</div>
567
+ <div class="value">${this._numberFormat(this.taxInvoice?.taxAmount)}</div>
568
+ </div>
569
+ </div>
570
+
571
+ <div class="items">
572
+ <div class="desc desc-date">
573
+ ※ 아래 '품목'의 '월'은 상단 '작성일자'의 '월'이 자동 반영됩니다. 합계의 '계산' 버튼은 금액을 공급가액과 세액으로 계산할 수 있습니다.
574
+ </div>
575
+ <div class="desc"><button class="btn-add" @click=${this._onAddInvoiceItem}>품목추가</button> 품목은 최대 16개까지 추가, 삭제 가능</div>
576
+
577
+ <table>
578
+ <colgroup>
579
+ <col width="5%" />
580
+ <col width="5%" />
581
+ <col width="14%" />
582
+ <col width="7%" />
583
+ <col width="7%" />
584
+ <col width="12%" />
585
+ <col width="12%" />
586
+ <col width="12%" />
587
+ <col width="16%" />
588
+ <col width="8%" />
589
+ </colgroup>
590
+ <tr>
591
+ <th>${i18next.t('field.tax invoice month')}</th>
592
+ <th required>${i18next.t('field.tax invoice day')}</th>
593
+ <th required>${i18next.t('field.tax invoice item name')}</th>
594
+ <th>${i18next.t('field.tax invoice ea')}</th>
595
+ <th required>${i18next.t('field.tax invoice quantity')}</th>
596
+ <th required>${i18next.t('field.tax invoice price')}</th>
597
+ <th>${i18next.t('field.supply amount')}</th>
598
+ <th>${i18next.t('field.tax amount')}</th>
599
+ <th>${i18next.t('field.remark0')}</th>
600
+ <th>${i18next.t('field.delete')}</th>
601
+ </tr>
602
+
603
+ ${this.taxInvoiceItems.map(
604
+ (item, idx) => html`
605
+ <tr>
606
+ <input type="hidden" name="sequence" value=${item.sequence} />
607
+ <td>${this.taxInvoice.issueDate.split('-')[1]}</td>
608
+ <td><input type="text" numeric maxlength="2" name="supplyDate" @input=${e => this._onInputItem(e, idx)} /></td>
609
+ <td><input type="text" name="itemName" .value=${item.itemName} @input=${e => this._onInputItem(e, idx)} /></td>
610
+ <td><input type="text" name="specification" .value=${item.specification} @input=${e => this._onInputItem(e, idx)} /></td>
611
+ <td><input type="text" numeric name="quantity" .value=${this._numberFormat(item.quantity)} @input=${e => this._onInputItem(e, idx)} /></td>
612
+ <td><input type="text" numeric name="unitPrice" .value=${this._numberFormat(item.unitPrice)} @input=${e => this._onInputItem(e, idx)} /></td>
613
+ <td><input type="text" numeric name="supplyPrice" .value=${this._numberFormat(item.supplyPrice)} @input=${e => this._onInputItem(e, idx)} /></td>
614
+ <td>
615
+ <input
616
+ type="text"
617
+ numeric
618
+ name="taxPrice"
619
+ .value=${this._numberFormat(item.taxPrice)}
620
+ @input=${e => this._onInputItem(e, idx)}
621
+ .disabled=${this.isTaxFree}
622
+ />
623
+ </td>
624
+ <td><input type="text" name="remark" .value=${item.remark || ''} @input=${e => this._onInputItem(e, idx)} /></td>
625
+ <td><button class="btn-delete" @click=${e => this._onRemoveInvoiceItem(e, item.sequence)}>삭제</button></td>
626
+ </tr>
627
+ `
628
+ )}
629
+ </table>
630
+ </div>
631
+
632
+ <div class="summary">
633
+ <table>
634
+ <colgroup>
635
+ <col width="25%" />
636
+ <col width="25%" />
637
+ <col width="25%" />
638
+ <col width="25%" />
639
+ </colgroup>
640
+ <tr>
641
+ <th>${i18next.t('field.tax invoice payment cash')}</th>
642
+ <th>${i18next.t('field.tax invoice payment check')}</th>
643
+ <th>${i18next.t('field.tax invoice payment promissory note')}</th>
644
+ <th>${i18next.t('field.tax invoice payment accounts receivable')}</th>
645
+ </tr>
646
+ <tr>
647
+ <td><input type="text" numeric name="paymentAmountCash" .value=${this.taxInvoice?.paymentAmountCash || ''} @input=${this._onInputTaxInvoice} /></td>
648
+ <td><input type="text" numeric name="paymentAmountCheck" .value=${this.taxInvoice?.paymentAmountCheck || ''} @input=${this._onInputTaxInvoice} /></td>
649
+ <td>
650
+ <input
651
+ type="text"
652
+ numeric
653
+ name="paymentAmountPromissoryNote"
654
+ .value=${this.taxInvoice?.paymentAmountPromissoryNote || ''}
655
+ @input=${this._onInputTaxInvoice}
656
+ />
657
+ </td>
658
+ <td>
659
+ <input
660
+ type="text"
661
+ numeric
662
+ name="paymentAmountAccountsReceivable"
663
+ .value=${this.taxInvoice?.paymentAmountAccountsReceivable || ''}
664
+ @input=${this._onInputTaxInvoice}
665
+ />
666
+ </td>
667
+ </tr>
668
+ </table>
669
+ <div>
670
+ ${i18next.t('text.prev tax invoice description payment') + ' ('}
671
+ <span class="type-wrapper">
672
+ <div>
673
+ <input type="radio" id="purpose_20" name="purpose" .value=${Purpose.INVOICE} @change=${this._onInputTaxInvoice} checked />
674
+ <label for="purpose_20">${PURPOSE[Purpose.INVOICE]}</label>
675
+ </div>
676
+ <div>
677
+ <input type="radio" id="purpose_10" name="purpose" .value=${Purpose.RECEIPT} @change=${this._onInputTaxInvoice} />
678
+ <label for="purpose_10">${PURPOSE[Purpose.RECEIPT]}</label>
679
+ </div>
680
+ </span>
681
+ ${') ' + i18next.t('text.next tax invoice description payment')}
682
+ </div>
683
+ </div>
684
+ </div>
685
+ `
686
+ }
687
+
688
+ async firstUpdated() {
689
+ this._fetchSupplier()
690
+ }
691
+
692
+ async _fetchSupplier() {
693
+ const response = await client.query({
694
+ query: gql`
695
+ query taxInvoiceDefaultCompany {
696
+ response: taxInvoiceDefaultCompany {
697
+ businessRegistrationNumber
698
+ branchIdentification
699
+ businessName
700
+ representativeName
701
+ address
702
+ businessType
703
+ industryType
704
+ department
705
+ contactName
706
+ contactPhone
707
+ contactEmail
708
+ contactCellPhone
709
+ }
710
+ }
711
+ `
712
+ })
713
+
714
+ const supplier = response.data.response
715
+ this.supplier = {
716
+ supplierBusinessRegistrationCategory: supplier.businessRegistrationCategory,
717
+ supplierBusinessRegistrationNumber: supplier.businessRegistrationNumber,
718
+ supplierBranchIdentification: supplier.branchIdentification,
719
+ supplierBusinessName: supplier.businessName,
720
+ supplierRepresentativeName: supplier.representativeName,
721
+ supplierAddress: supplier.address,
722
+ supplierBusinessType: supplier.businessType,
723
+ supplierIndustryType: supplier.industryType,
724
+ supplierDepartment: supplier.department,
725
+ supplierContactName: supplier.contactName,
726
+ supplierContactPhone: supplier.contactPhone,
727
+ supplierContactEmail: supplier.contactEmail,
728
+ supplierContactCellPhone: supplier.contactCellPhone
729
+ }
730
+ }
731
+
732
+ private _numberFormat(value: number): string {
733
+ return !value ? '' : new Intl.NumberFormat('en-US').format(value) || ''
734
+ }
735
+
736
+ // Input 요소의 값이 변경될 때 호출되는 콜백 함수
737
+ private _onInputTaxInvoice(event: InputEvent) {
738
+ const target = event.target as HTMLInputElement
739
+
740
+ // 숫자 타입은 다른 문자 입력 제거
741
+ if (target.hasAttribute('numeric')) {
742
+ target.value = target.value.replace(/\D/g, '')
743
+ }
744
+
745
+ if (target.name.startsWith('supplier')) {
746
+ this.supplier[target.name] = target.value
747
+ } else if (target.name.startsWith('buyer')) {
748
+ this.buyer[target.name] = target.value
749
+ } else {
750
+ // 날짜 체크가 오늘 날짜를 넘어가면 값 변경 되면 안됨
751
+ if (target.name === 'issueDate' && target.value > this.today) {
752
+ target.value = this.taxInvoice['issueDate']
753
+ alert('작성일자는 현재일까지 입력하시기 바랍니다.')
754
+ return
755
+ }
756
+
757
+ // 세금이 없는 영세율이 선택 시 모든 아이템의 세금 0원으로 초기화
758
+ if (target.name === 'invoiceType' && target.value === InvoiceType.SMALL_BUSINESS_TAX_INVOICE) {
759
+ this.isTaxFree = true
760
+ this.taxInvoice = { ...this.taxInvoice, taxAmount: 0 }
761
+ this.taxInvoiceItems = this.taxInvoiceItems.map(item => ({ ...item, taxPrice: 0 }))
762
+ }
763
+
764
+ // 변경시에는 아이템 변경도 리 렌더가 필요해서 데이터 갱신
765
+ this.taxInvoice[target.name] = target.value
766
+ this.taxInvoice = { ...this.taxInvoice }
767
+ }
768
+ }
769
+
770
+ // Input 요소의 값이 변경될 때 호출되는 콜백 함수
771
+ private _onInputItem(e: InputEvent, idx: number) {
772
+ const target = e.target as HTMLInputElement
773
+ let inputVal: any = target.value
774
+
775
+ // 숫자 타입은 다른 문자 입력 제거
776
+ if (target.hasAttribute('numeric')) {
777
+ inputVal = Number(inputVal.replace(/\D/g, ''))
778
+ target.value = inputVal
779
+ }
780
+
781
+ // 공급일자 케이스 시 => 세금계산서의 작성일자의 YYYY-MM + 아이템의 입력된 DD
782
+ if (target.name === 'supplyDate') {
783
+ const itemDate = this.taxInvoice.issueDate.substring(0, 8) + inputVal.toString().padStart(2, '0')
784
+ if (itemDate > this.taxInvoice.issueDate) {
785
+ alert('품목의 일자는 작성일자보다 클 수 없습니다.')
786
+ target.value = ''
787
+ }
788
+ inputVal = itemDate
789
+ }
790
+
791
+ // 수량, 단가 수정시 공급가액/세액 자동 계산
792
+ if (target.name == 'quantity' || target.name == 'unitPrice') {
793
+ const supplyPrice = target.name == 'quantity' ? Number(inputVal) * this.taxInvoiceItems[idx]['unitPrice'] : Number(inputVal) * this.taxInvoiceItems[idx]['quantity']
794
+ this.taxInvoiceItems[idx]['supplyPrice'] = supplyPrice
795
+ this.taxInvoiceItems[idx]['taxPrice'] = this.isTaxFree ? 0 : Math.floor(supplyPrice / 10)
796
+ }
797
+
798
+ // 인풋에 값 넣기
799
+ this.taxInvoiceItems[idx][target.name] = inputVal
800
+
801
+ // 아이템 금액에 관련된 필드 수정시 합계 계산
802
+ if (['quantity', 'unitPrice', 'supplyPrice', 'taxPrice'].includes(target.name)) {
803
+ this.taxInvoiceItems = [...this.taxInvoiceItems]
804
+ this._setTaxInvoiceSummaryCalc()
805
+ }
806
+ }
807
+
808
+ private async _openSupplierPopup() {
809
+ const response = await client.query({
810
+ query: gql`
811
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
812
+ responses: taxInvoiceApis(filters: $filters, pagination: $pagination, sortings: $sortings) {
813
+ items {
814
+ id
815
+ name: provider
816
+ businessRegistrationNumber
817
+ branchIdentification
818
+ businessName
819
+ representativeName
820
+ address
821
+ businessType
822
+ industryType
823
+ department
824
+ contactName
825
+ contactPhone
826
+ contactEmail
827
+ contactCellPhone
828
+ }
829
+ }
830
+ }
831
+ `
832
+ })
833
+
834
+ const items = response.data.responses.items || []
835
+ openPopup(
836
+ html`
837
+ <company-list-popup
838
+ .companyList=${items}
839
+ @selected=${e => {
840
+ this.supplier = {
841
+ supplierBusinessRegistrationCategory: BusinessRegistrationCategory.BUSINESS_REGISTRATION_NUMBER,
842
+ supplierBusinessRegistrationNumber: e.detail.businessRegistrationNumber || '',
843
+ supplierBranchIdentification: e.detail.branchIdentification || '',
844
+ supplierBusinessName: e.detail.businessName || '',
845
+ supplierRepresentativeName: e.detail.representativeName || '',
846
+ supplierAddress: e.detail.address || '',
847
+ supplierBusinessType: e.detail.businessType || '',
848
+ supplierIndustryType: e.detail.industryType || '',
849
+ supplierDepartment: e.detail.department || '',
850
+ supplierContactName: e.detail.contactName || '',
851
+ supplierContactPhone: e.detail.contactPhone || '',
852
+ supplierContactEmail: e.detail.contactEmail || '',
853
+ supplierContactCellPhone: e.detail.contactCellPhone || ''
854
+ }
855
+
856
+ history.back()
857
+ }}
858
+ >
859
+ </company-list-popup>
860
+ `,
861
+ {
862
+ backdrop: true,
863
+ size: 'large',
864
+ title: i18next.t('title.company list popup')
865
+ }
866
+ )
867
+ }
868
+
869
+ private async _openBuyerPopup() {
870
+ const response = await client.query({
871
+ query: gql`
872
+ query TaxInvoiceBuyerList {
873
+ responses: taxInvoiceBuyerList {
874
+ id
875
+ name
876
+ businessRegistrationNumber
877
+ branchIdentification
878
+ businessName
879
+ representativeName
880
+ address
881
+ businessType
882
+ industryType
883
+ department
884
+ contactName
885
+ contactPhone
886
+ contactEmail
887
+ contactCellPhone
888
+ }
889
+ }
890
+ `
891
+ })
892
+
893
+ const items = response.data.responses || []
894
+ openPopup(
895
+ html`
896
+ <company-list-popup
897
+ .companyList=${items}
898
+ @selected=${e => {
899
+ this.buyer = {
900
+ buyerBusinessRegistrationCategory: BusinessRegistrationCategory.BUSINESS_REGISTRATION_NUMBER,
901
+ buyerBusinessRegistrationNumber: e.detail.businessRegistrationNumber || '',
902
+ buyerBranchIdentification: e.detail.branchIdentification || '',
903
+ buyerBusinessName: e.detail.businessName || '',
904
+ buyerRepresentativeName: e.detail.representativeName || '',
905
+ buyerAddress: e.detail.address || '',
906
+ buyerBusinessType: e.detail.businessType || '',
907
+ buyerIndustryType: e.detail.industryType || '',
908
+ buyer1stDepartment: e.detail.department || '',
909
+ buyer1stContactName: e.detail.contactName || '',
910
+ buyer1stContactPhone: e.detail.contactPhone || '',
911
+ buyer1stContactEmail: e.detail.contactEmail || '',
912
+ buyer1stContactCellPhone: e.detail.contactCellPhone || ''
913
+ }
914
+
915
+ history.back()
916
+ }}
917
+ >
918
+ </company-list-popup>
919
+ `,
920
+ {
921
+ backdrop: true,
922
+ size: 'large',
923
+ title: i18next.t('title.company list popup')
924
+ }
925
+ )
926
+ }
927
+
928
+ private _onAddInvoiceItem(e: Event) {
929
+ e.preventDefault()
930
+ if (this.taxInvoiceItems.length >= 16) {
931
+ alert('품목은 최대 16개까지 추가 가능합니다.')
932
+ return
933
+ }
934
+
935
+ this.taxInvoiceItems = [...this.taxInvoiceItems, { ...this.defaultTaxInvoiceItem, sequence: new Date().getTime() }]
936
+ }
937
+
938
+ private _onRemoveInvoiceItem(e: Event, sequence: number) {
939
+ e.preventDefault()
940
+ this.taxInvoiceItems = [...this.taxInvoiceItems.filter(item => item.sequence != sequence)]
941
+ this._setTaxInvoiceSummaryCalc()
942
+ }
943
+
944
+ private _setTaxInvoiceSummaryCalc() {
945
+ const supplyPrice: number = this.taxInvoiceItems.reduce((prev, item) => prev + Number(item.supplyPrice), 0) || 0
946
+ const taxPrice: number = this.isTaxFree ? 0 : this.taxInvoiceItems.reduce((prev, item) => prev + Number(item.taxPrice), 0) || 0
947
+ const totalAmount: number = supplyPrice + taxPrice
948
+
949
+ this.taxInvoice = { ...this.taxInvoice, supplyAmount: supplyPrice, taxAmount: taxPrice, totalAmount: totalAmount }
950
+ }
951
+ }