@things-factory/invoice 0.0.0-stage → 10.1.130

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 (91) hide show
  1. package/README.md +21 -2
  2. package/dist-client/bootstrap.d.ts +1 -0
  3. package/dist-client/bootstrap.js +5 -0
  4. package/dist-client/bootstrap.js.map +1 -0
  5. package/dist-client/document/document-amount.d.ts +6 -0
  6. package/dist-client/document/document-amount.js +19 -0
  7. package/dist-client/document/document-amount.js.map +1 -0
  8. package/dist-client/document/document-form.d.ts +14 -0
  9. package/dist-client/document/document-form.js +145 -0
  10. package/dist-client/document/document-form.js.map +1 -0
  11. package/dist-client/document/document-lines.d.ts +104 -0
  12. package/dist-client/document/document-lines.js +61 -0
  13. package/dist-client/document/document-lines.js.map +1 -0
  14. package/dist-client/document/document-print.d.ts +15 -0
  15. package/dist-client/document/document-print.js +60 -0
  16. package/dist-client/document/document-print.js.map +1 -0
  17. package/dist-client/entity360/invoice-360.d.ts +19 -0
  18. package/dist-client/entity360/invoice-360.js +116 -0
  19. package/dist-client/entity360/invoice-360.js.map +1 -0
  20. package/dist-client/index.d.ts +6 -0
  21. package/dist-client/index.js +7 -0
  22. package/dist-client/index.js.map +1 -0
  23. package/dist-client/invoice-attach.d.ts +19 -0
  24. package/dist-client/invoice-attach.js +19 -0
  25. package/dist-client/invoice-attach.js.map +1 -0
  26. package/dist-client/pages/invoice-editor.d.ts +48 -0
  27. package/dist-client/pages/invoice-editor.js +341 -0
  28. package/dist-client/pages/invoice-editor.js.map +1 -0
  29. package/dist-client/pages/invoice-list.d.ts +39 -0
  30. package/dist-client/pages/invoice-list.js +125 -0
  31. package/dist-client/pages/invoice-list.js.map +1 -0
  32. package/dist-client/route.d.ts +1 -0
  33. package/dist-client/route.js +11 -0
  34. package/dist-client/route.js.map +1 -0
  35. package/dist-client/tsconfig.tsbuildinfo +1 -0
  36. package/dist-server/index.d.ts +2 -0
  37. package/dist-server/index.js +6 -0
  38. package/dist-server/index.js.map +1 -0
  39. package/dist-server/routes.d.ts +1 -0
  40. package/dist-server/routes.js +3 -0
  41. package/dist-server/routes.js.map +1 -0
  42. package/dist-server/service/index.d.ts +12 -0
  43. package/dist-server/service/index.js +19 -0
  44. package/dist-server/service/index.js.map +1 -0
  45. package/dist-server/service/invoice/commercial-document.d.ts +44 -0
  46. package/dist-server/service/invoice/commercial-document.js +200 -0
  47. package/dist-server/service/invoice/commercial-document.js.map +1 -0
  48. package/dist-server/service/invoice/index.d.ts +6 -0
  49. package/dist-server/service/invoice/index.js +10 -0
  50. package/dist-server/service/invoice/index.js.map +1 -0
  51. package/dist-server/service/invoice/invoice-mutation.d.ts +8 -0
  52. package/dist-server/service/invoice/invoice-mutation.js +75 -0
  53. package/dist-server/service/invoice/invoice-mutation.js.map +1 -0
  54. package/dist-server/service/invoice/invoice-query.d.ts +16 -0
  55. package/dist-server/service/invoice/invoice-query.js +117 -0
  56. package/dist-server/service/invoice/invoice-query.js.map +1 -0
  57. package/dist-server/service/invoice/invoice-rules.d.ts +83 -0
  58. package/dist-server/service/invoice/invoice-rules.js +202 -0
  59. package/dist-server/service/invoice/invoice-rules.js.map +1 -0
  60. package/dist-server/service/invoice/invoice-service.d.ts +26 -0
  61. package/dist-server/service/invoice/invoice-service.js +133 -0
  62. package/dist-server/service/invoice/invoice-service.js.map +1 -0
  63. package/dist-server/service/invoice/invoice-type.d.ts +40 -0
  64. package/dist-server/service/invoice/invoice-type.js +146 -0
  65. package/dist-server/service/invoice/invoice-type.js.map +1 -0
  66. package/dist-server/service/invoice/invoice.d.ts +30 -0
  67. package/dist-server/service/invoice/invoice.js +108 -0
  68. package/dist-server/service/invoice/invoice.js.map +1 -0
  69. package/dist-server/service/invoice-event/index.d.ts +5 -0
  70. package/dist-server/service/invoice-event/index.js +9 -0
  71. package/dist-server/service/invoice-event/index.js.map +1 -0
  72. package/dist-server/service/invoice-event/invoice-event-query.d.ts +9 -0
  73. package/dist-server/service/invoice-event/invoice-event-query.js +57 -0
  74. package/dist-server/service/invoice-event/invoice-event-query.js.map +1 -0
  75. package/dist-server/service/invoice-event/invoice-event.d.ts +22 -0
  76. package/dist-server/service/invoice-event/invoice-event.js +98 -0
  77. package/dist-server/service/invoice-event/invoice-event.js.map +1 -0
  78. package/dist-server/service/invoice-item/index.d.ts +5 -0
  79. package/dist-server/service/invoice-item/index.js +9 -0
  80. package/dist-server/service/invoice-item/index.js.map +1 -0
  81. package/dist-server/service/invoice-item/invoice-item-query.d.ts +8 -0
  82. package/dist-server/service/invoice-item/invoice-item-query.js +47 -0
  83. package/dist-server/service/invoice-item/invoice-item-query.js.map +1 -0
  84. package/dist-server/service/invoice-item/invoice-item.d.ts +19 -0
  85. package/dist-server/service/invoice-item/invoice-item.js +80 -0
  86. package/dist-server/service/invoice-item/invoice-item.js.map +1 -0
  87. package/dist-server/tsconfig.tsbuildinfo +1 -0
  88. package/package.json +44 -4
  89. package/things-factory.config.js +11 -0
  90. package/translations/en.json +81 -0
  91. package/translations/ko.json +81 -0
@@ -0,0 +1,116 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import gql from 'graphql-tag';
3
+ import { css, html, LitElement } from 'lit';
4
+ import { customElement, property, state } from 'lit/decorators.js';
5
+ import { client } from '@operato/graphql';
6
+ import { i18next } from '@operato/i18n';
7
+ import { readEntity360Door, registerEntity360Kind, registerEntity360Section } from '@operato/layout';
8
+ import { DocumentFormStyles, renderDocumentTotals } from '../document/document-form';
9
+ import { invoice360Query } from '../invoice-attach';
10
+ /** The other party: the buyer of a sale, the supplier of a purchase. */
11
+ export const counterpartOf = (value) => (value.direction === 'PURCHASE' ? value.supplierName : value.buyerName) || '';
12
+ export const invoiceStatusWord = (status) => status === 'ISSUED' ? i18next.t('text.invoice-status-issued') : status === 'VOID' ? i18next.t('text.invoice-status-void') : i18next.t('text.invoice-status-draft');
13
+ /** An invoice's 360 (ADR-0067). The module draws the invoice; an application hangs its own sections on 'invoice'. */
14
+ export function registerInvoiceKind() {
15
+ registerEntity360Kind({
16
+ kind: 'invoice',
17
+ typenames: ['Invoice'],
18
+ title: ({ value }) => `${i18next.t('title.invoice')} · ${counterpartOf(value) || value.number || ''}`,
19
+ context: ({ value }) => [value.number, value.issueDate, value.status ? invoiceStatusWord(value.status) : ''].filter(Boolean).join(' · ')
20
+ });
21
+ registerEntity360Section('invoice', {
22
+ name: 'overview',
23
+ order: 10,
24
+ render: subject => html `<invoice-overview-section .subject=${subject}></invoice-overview-section>`
25
+ });
26
+ }
27
+ let InvoiceOverviewSection = class InvoiceOverviewSection extends LitElement {
28
+ static { this.styles = [
29
+ DocumentFormStyles,
30
+ css `
31
+ :host {
32
+ font-size: var(--ui-t-body);
33
+ line-height: 1.5;
34
+ }
35
+ dl {
36
+ margin: 0 0 var(--spacing-large);
37
+ display: grid;
38
+ grid-template-columns: max-content 1fr;
39
+ gap: var(--spacing-small) var(--spacing-large);
40
+ }
41
+ dt {
42
+ color: var(--ui-muted);
43
+ }
44
+ dd {
45
+ margin: 0;
46
+ overflow-wrap: anywhere;
47
+ font-variant-numeric: tabular-nums;
48
+ }
49
+ `
50
+ ]; }
51
+ updated(changed) {
52
+ if (changed.has('subject'))
53
+ this.read();
54
+ }
55
+ async read() {
56
+ const id = this.subject?.id;
57
+ this.answer = undefined;
58
+ if (!id)
59
+ return;
60
+ let response;
61
+ try {
62
+ response = await client.query({
63
+ query: gql(`
64
+ query ($id: String!) {
65
+ invoice: ${invoice360Query()}(id: $id) {
66
+ id number status direction currency issueDate dueDate supplierName buyerName purchaseOrder
67
+ supplyAmount taxAmount totalAmount taxGroups { taxKind taxRate supplyAmount taxAmount }
68
+ }
69
+ }
70
+ `),
71
+ variables: { id },
72
+ fetchPolicy: 'no-cache',
73
+ errorPolicy: 'all'
74
+ });
75
+ }
76
+ catch (e) {
77
+ response = { data: null, errors: e?.graphQLErrors?.length ? e.graphQLErrors : [{ message: e?.message ?? String(e) }] };
78
+ }
79
+ if (this.subject?.id !== id)
80
+ return;
81
+ this.answer = readEntity360Door(response, data => data?.invoice);
82
+ }
83
+ render() {
84
+ const one = this.answer?.data;
85
+ return html `<ox-entity360-section .heading=${i18next.t('title.invoice')} .state=${this.answer?.state ?? 'loading'} .message=${this.answer?.message ?? ''}>
86
+ ${one
87
+ ? html `<dl>
88
+ <dt>${i18next.t('field.invoice-number')}</dt>
89
+ <dd>${one.number} · ${invoiceStatusWord(one.status)}</dd>
90
+ <dt>${i18next.t('field.invoice-supplier-name')}</dt>
91
+ <dd>${one.supplierName}</dd>
92
+ <dt>${i18next.t('field.invoice-buyer-name')}</dt>
93
+ <dd>${one.buyerName}</dd>
94
+ <dt>${i18next.t('field.invoice-issue-date')}</dt>
95
+ <dd>${one.issueDate ?? '—'}</dd>
96
+ <dt>${i18next.t('field.invoice-due-date')}</dt>
97
+ <dd>${one.dueDate ?? '—'}</dd>
98
+ </dl>
99
+ ${renderDocumentTotals(one)}`
100
+ : ''}
101
+ </ox-entity360-section>`;
102
+ }
103
+ };
104
+ __decorate([
105
+ property({ attribute: false }),
106
+ __metadata("design:type", Object)
107
+ ], InvoiceOverviewSection.prototype, "subject", void 0);
108
+ __decorate([
109
+ state(),
110
+ __metadata("design:type", Object)
111
+ ], InvoiceOverviewSection.prototype, "answer", void 0);
112
+ InvoiceOverviewSection = __decorate([
113
+ customElement('invoice-overview-section')
114
+ ], InvoiceOverviewSection);
115
+ export { InvoiceOverviewSection };
116
+ //# sourceMappingURL=invoice-360.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invoice-360.js","sourceRoot":"","sources":["../../client/entity360/invoice-360.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { readEntity360Door, registerEntity360Kind, registerEntity360Section, type Entity360DoorAnswer, type Entity360Subject } from '@operato/layout'\n\nimport { DocumentFormStyles, renderDocumentTotals } from '../document/document-form'\nimport { invoice360Query } from '../invoice-attach'\n\n/** The other party: the buyer of a sale, the supplier of a purchase. */\nexport const counterpartOf = (value: { direction?: string; supplierName?: string; buyerName?: string }) =>\n (value.direction === 'PURCHASE' ? value.supplierName : value.buyerName) || ''\n\nexport const invoiceStatusWord = (status?: string) =>\n status === 'ISSUED' ? i18next.t('text.invoice-status-issued') : status === 'VOID' ? i18next.t('text.invoice-status-void') : i18next.t('text.invoice-status-draft')\n\n/** An invoice's 360 (ADR-0067). The module draws the invoice; an application hangs its own sections on 'invoice'. */\nexport function registerInvoiceKind() {\n registerEntity360Kind({\n kind: 'invoice',\n typenames: ['Invoice'],\n title: ({ value }) => `${i18next.t('title.invoice')} · ${counterpartOf(value) || value.number || ''}`,\n context: ({ value }) => [value.number, value.issueDate, value.status ? invoiceStatusWord(value.status) : ''].filter(Boolean).join(' · ')\n })\n registerEntity360Section('invoice', {\n name: 'overview',\n order: 10,\n render: subject => html`<invoice-overview-section .subject=${subject}></invoice-overview-section>`\n })\n}\n\n@customElement('invoice-overview-section')\nexport class InvoiceOverviewSection extends LitElement {\n static styles = [\n DocumentFormStyles,\n css`\n :host {\n font-size: var(--ui-t-body);\n line-height: 1.5;\n }\n dl {\n margin: 0 0 var(--spacing-large);\n display: grid;\n grid-template-columns: max-content 1fr;\n gap: var(--spacing-small) var(--spacing-large);\n }\n dt {\n color: var(--ui-muted);\n }\n dd {\n margin: 0;\n overflow-wrap: anywhere;\n font-variant-numeric: tabular-nums;\n }\n `\n ]\n\n @property({ attribute: false }) subject?: Entity360Subject\n @state() answer?: Entity360DoorAnswer<any>\n\n updated(changed: Map<string, unknown>) {\n if (changed.has('subject')) this.read()\n }\n\n private async read() {\n const id = this.subject?.id\n this.answer = undefined\n if (!id) return\n let response: any\n try {\n response = await client.query({\n query: gql(`\n query ($id: String!) {\n invoice: ${invoice360Query()}(id: $id) {\n id number status direction currency issueDate dueDate supplierName buyerName purchaseOrder\n supplyAmount taxAmount totalAmount taxGroups { taxKind taxRate supplyAmount taxAmount }\n }\n }\n `),\n variables: { id },\n fetchPolicy: 'no-cache',\n errorPolicy: 'all'\n } as any)\n } catch (e: any) {\n response = { data: null, errors: e?.graphQLErrors?.length ? e.graphQLErrors : [{ message: e?.message ?? String(e) }] }\n }\n if (this.subject?.id !== id) return\n this.answer = readEntity360Door(response, data => data?.invoice)\n }\n\n render() {\n const one = this.answer?.data\n return html`<ox-entity360-section .heading=${i18next.t('title.invoice')} .state=${this.answer?.state ?? 'loading'} .message=${this.answer?.message ?? ''}>\n ${one\n ? html`<dl>\n <dt>${i18next.t('field.invoice-number')}</dt>\n <dd>${one.number} · ${invoiceStatusWord(one.status)}</dd>\n <dt>${i18next.t('field.invoice-supplier-name')}</dt>\n <dd>${one.supplierName}</dd>\n <dt>${i18next.t('field.invoice-buyer-name')}</dt>\n <dd>${one.buyerName}</dd>\n <dt>${i18next.t('field.invoice-issue-date')}</dt>\n <dd>${one.issueDate ?? '—'}</dd>\n <dt>${i18next.t('field.invoice-due-date')}</dt>\n <dd>${one.dueDate ?? '—'}</dd>\n </dl>\n ${renderDocumentTotals(one)}`\n : ''}\n </ox-entity360-section>`\n }\n}\n"]}
@@ -0,0 +1,6 @@
1
+ export { configureInvoiceLinkSection, configureInvoice360Query, type InvoiceLinkSection } from './invoice-attach.js';
2
+ export { counterpartOf, invoiceStatusWord } from './entity360/invoice-360.js';
3
+ export { currencyChoices, currencyDigits, documentAmount } from './document/document-amount.js';
4
+ export { DocumentFormStyles, HEAD_FIELDS, renderDocumentHead, renderDocumentTotals, type DocumentValue } from './document/document-form.js';
5
+ export { documentLinesConfig, linesOf } from './document/document-lines.js';
6
+ export { documentHtml, printDocument } from './document/document-print.js';
@@ -0,0 +1,7 @@
1
+ export { configureInvoiceLinkSection, configureInvoice360Query } from './invoice-attach.js';
2
+ export { counterpartOf, invoiceStatusWord } from './entity360/invoice-360.js';
3
+ export { currencyChoices, currencyDigits, documentAmount } from './document/document-amount.js';
4
+ export { DocumentFormStyles, HEAD_FIELDS, renderDocumentHead, renderDocumentTotals } from './document/document-form.js';
5
+ export { documentLinesConfig, linesOf } from './document/document-lines.js';
6
+ export { documentHtml, printDocument } from './document/document-print.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,wBAAwB,EAA2B,MAAM,qBAAqB,CAAA;AACpH,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAC/F,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,kBAAkB,EAAE,oBAAoB,EAAsB,MAAM,6BAA6B,CAAA;AAC3I,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA;AAC3E,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA","sourcesContent":["export { configureInvoiceLinkSection, configureInvoice360Query, type InvoiceLinkSection } from './invoice-attach.js'\nexport { counterpartOf, invoiceStatusWord } from './entity360/invoice-360.js'\nexport { currencyChoices, currencyDigits, documentAmount } from './document/document-amount.js'\nexport { DocumentFormStyles, HEAD_FIELDS, renderDocumentHead, renderDocumentTotals, type DocumentValue } from './document/document-form.js'\nexport { documentLinesConfig, linesOf } from './document/document-lines.js'\nexport { documentHtml, printDocument } from './document/document-print.js'\n"]}
@@ -0,0 +1,19 @@
1
+ import { type TemplateResult } from 'lit';
2
+ export type InvoiceLinkSection = {
3
+ /** The section's heading, already in the reader's words. */
4
+ heading: () => string;
5
+ /** The section's body for one saved invoice; it reads and writes through the application's own API. */
6
+ render: (invoice: {
7
+ id: string;
8
+ status: string;
9
+ direction: string;
10
+ currency: string;
11
+ totalAmount: number;
12
+ }) => TemplateResult;
13
+ };
14
+ /** The 「links」 section of the invoice editor — Office ties an invoice to contract rounds, payments and tax invoices. */
15
+ export declare function configureInvoiceLinkSection(section: InvoiceLinkSection): void;
16
+ export declare function invoiceLinkSection(): InvoiceLinkSection | undefined;
17
+ /** An application may read the 360's invoice through its own domain-scoped door. */
18
+ export declare function configureInvoice360Query(field: string): void;
19
+ export declare function invoice360Query(): string;
@@ -0,0 +1,19 @@
1
+ let linkSection;
2
+ /** The 「links」 section of the invoice editor — Office ties an invoice to contract rounds, payments and tax invoices. */
3
+ export function configureInvoiceLinkSection(section) {
4
+ linkSection = section;
5
+ }
6
+ export function invoiceLinkSection() {
7
+ return linkSection;
8
+ }
9
+ let invoiceQueryField = 'invoice';
10
+ /** An application may read the 360's invoice through its own domain-scoped door. */
11
+ export function configureInvoice360Query(field) {
12
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(field))
13
+ throw new Error('Invalid invoice query field');
14
+ invoiceQueryField = field;
15
+ }
16
+ export function invoice360Query() {
17
+ return invoiceQueryField;
18
+ }
19
+ //# sourceMappingURL=invoice-attach.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invoice-attach.js","sourceRoot":"","sources":["../client/invoice-attach.ts"],"names":[],"mappings":"AAcA,IAAI,WAA2C,CAAA;AAE/C,wHAAwH;AACxH,MAAM,UAAU,2BAA2B,CAAC,OAA2B;IACrE,WAAW,GAAG,OAAO,CAAA;AACvB,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,WAAW,CAAA;AACpB,CAAC;AAED,IAAI,iBAAiB,GAAG,SAAS,CAAA;AAEjC,oFAAoF;AACpF,MAAM,UAAU,wBAAwB,CAAC,KAAa;IACpD,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;IAC3F,iBAAiB,GAAG,KAAK,CAAA;AAC3B,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,iBAAiB,CAAA;AAC1B,CAAC","sourcesContent":["import { type TemplateResult } from 'lit'\n\n/*\n * Where an application attaches its own work to an invoice — the same shape as tax-invoice's\n * configureTaxInvoice360Query (ADR-0120 decision 2). The invoice module knows no application words.\n */\n\nexport type InvoiceLinkSection = {\n /** The section's heading, already in the reader's words. */\n heading: () => string\n /** The section's body for one saved invoice; it reads and writes through the application's own API. */\n render: (invoice: { id: string; status: string; direction: string; currency: string; totalAmount: number }) => TemplateResult\n}\n\nlet linkSection: InvoiceLinkSection | undefined\n\n/** The 「links」 section of the invoice editor — Office ties an invoice to contract rounds, payments and tax invoices. */\nexport function configureInvoiceLinkSection(section: InvoiceLinkSection): void {\n linkSection = section\n}\n\nexport function invoiceLinkSection(): InvoiceLinkSection | undefined {\n return linkSection\n}\n\nlet invoiceQueryField = 'invoice'\n\n/** An application may read the 360's invoice through its own domain-scoped door. */\nexport function configureInvoice360Query(field: string): void {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(field)) throw new Error('Invalid invoice query field')\n invoiceQueryField = field\n}\n\nexport function invoice360Query(): string {\n return invoiceQueryField\n}\n"]}
@@ -0,0 +1,48 @@
1
+ import '@operato/data-grist/ox-grist.js';
2
+ import '@operato/list-state/ox-page-state.js';
3
+ import { PageView } from '@operato/shell';
4
+ import { type DocumentValue } from '../document/document-form';
5
+ declare const InvoiceEditor_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
6
+ /**
7
+ * 청구서 편집 — the head, the lines, the totals by tax kind and rate, and what an application links it to.
8
+ *
9
+ * A draft is written and saved; 「발행」 saves what is on screen and issues it, after which its amounts never change.
10
+ * An issued invoice is voided with a reason, in its own section. While a request runs only the inputs wait.
11
+ */
12
+ export declare class InvoiceEditor extends InvoiceEditor_base {
13
+ static styles: import("lit").CSSResult[];
14
+ invoice: DocumentValue | null;
15
+ form: DocumentValue;
16
+ loading: boolean;
17
+ error: unknown;
18
+ busy: boolean;
19
+ voidReason: string;
20
+ gristConfig: any;
21
+ private grist?;
22
+ get editable(): boolean;
23
+ get context(): {
24
+ frame: string;
25
+ menu: string;
26
+ actions: any[];
27
+ description?: string;
28
+ title: string;
29
+ };
30
+ pageUpdated(changes: any, lifecycle: any): Promise<void>;
31
+ render(): import("lit-html").TemplateResult<1>;
32
+ private renderTerms;
33
+ private renderVoid;
34
+ private changeTaxBasis;
35
+ private configure;
36
+ private load;
37
+ private show;
38
+ /** Runs one request at a time; a refusal is said in the server's words. */
39
+ private run;
40
+ private input;
41
+ private save;
42
+ /** Save what is on screen, then issue it — its amounts are fixed from here on. */
43
+ private issue;
44
+ private void;
45
+ private mutate;
46
+ private print;
47
+ }
48
+ export {};
@@ -0,0 +1,341 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@operato/data-grist/ox-grist.js';
3
+ import '@operato/list-state/ox-page-state.js';
4
+ import gql from 'graphql-tag';
5
+ import { css, html, nothing } from 'lit';
6
+ import { customElement, query, state } from 'lit/decorators.js';
7
+ import { DataGrist } from '@operato/data-grist';
8
+ import { client } from '@operato/graphql';
9
+ import { i18next, localize } from '@operato/i18n';
10
+ import { notify } from '@operato/layout';
11
+ import { OxPrompt } from '@operato/popup/ox-prompt.js';
12
+ import { navigate, PageView } from '@operato/shell';
13
+ import { ButtonStyles, CommonGristStyles, DocumentPageStyles, FormFieldStyles, ScrollbarStyles } from '@operato/styles';
14
+ import { DocumentFormStyles, renderDocumentHead, renderDocumentTotals } from '../document/document-form';
15
+ import { documentLinesConfig, linesOf } from '../document/document-lines';
16
+ import { documentHtml, printDocument } from '../document/document-print';
17
+ import { invoiceStatusWord } from '../entity360/invoice-360';
18
+ import { invoiceLinkSection } from '../invoice-attach';
19
+ const FIELDS = `
20
+ id number status direction currency language supplierName supplierAddress supplierRegistrationNumber buyerName buyerAddress
21
+ buyerRegistrationNumber issueDate dueDate purchaseOrder paymentTerms bankDetails notes sourceReference taxBasis voidReason
22
+ supplyAmount taxAmount totalAmount taxRounding currencyDigits
23
+ items { position description quantity unitPrice discount taxKind taxRate supplyAmount receivedTaxAmount }
24
+ taxGroups { taxKind taxRate supplyAmount taxAmount }
25
+ `;
26
+ const HEAD = [
27
+ 'number',
28
+ 'direction',
29
+ 'currency',
30
+ 'language',
31
+ 'supplierName',
32
+ 'supplierAddress',
33
+ 'supplierRegistrationNumber',
34
+ 'buyerName',
35
+ 'buyerAddress',
36
+ 'buyerRegistrationNumber',
37
+ 'issueDate',
38
+ 'dueDate',
39
+ 'purchaseOrder',
40
+ 'paymentTerms',
41
+ 'bankDetails',
42
+ 'notes',
43
+ 'sourceReference',
44
+ 'taxBasis'
45
+ ];
46
+ const today = () => new Date().toLocaleDateString('en-CA');
47
+ /**
48
+ * 청구서 편집 — the head, the lines, the totals by tax kind and rate, and what an application links it to.
49
+ *
50
+ * A draft is written and saved; 「발행」 saves what is on screen and issues it, after which its amounts never change.
51
+ * An issued invoice is voided with a reason, in its own section. While a request runs only the inputs wait.
52
+ */
53
+ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
54
+ constructor() {
55
+ super(...arguments);
56
+ this.invoice = null;
57
+ this.form = blank();
58
+ this.loading = false;
59
+ this.error = null;
60
+ this.busy = false;
61
+ this.voidReason = '';
62
+ }
63
+ static { this.styles = [
64
+ FormFieldStyles,
65
+ ButtonStyles,
66
+ DocumentPageStyles,
67
+ CommonGristStyles,
68
+ ScrollbarStyles,
69
+ DocumentFormStyles,
70
+ css `
71
+ ox-grist {
72
+ height: calc(var(--form-element-height-medium) * 10);
73
+ }
74
+ `
75
+ ]; }
76
+ get editable() {
77
+ return !this.invoice || this.invoice.status === 'DRAFT';
78
+ }
79
+ get context() {
80
+ const actions = [];
81
+ if (this.editable) {
82
+ actions.push({ title: i18next.t('button.save'), icon: 'save', action: () => this.save() });
83
+ actions.push({ title: i18next.t('button.invoice-issue'), icon: 'send', emphasis: { raised: true }, action: () => this.issue() });
84
+ }
85
+ if (this.invoice)
86
+ actions.push({ title: i18next.t('button.invoice-print'), icon: 'print', action: () => this.print() });
87
+ return {
88
+ title: this.invoice ? `${i18next.t('title.invoice')} ${this.invoice.number}` : i18next.t('title.invoice-new'),
89
+ ...(this.invoice ? { description: invoiceStatusWord(this.invoice.status) } : {}),
90
+ frame: 'document',
91
+ /* Opened from the invoice list; the menu marks it. */
92
+ menu: 'invoice-list',
93
+ actions: this.error ? [] : actions
94
+ };
95
+ }
96
+ async pageUpdated(changes, lifecycle) {
97
+ if (!this.active || !(changes.active || changes.params))
98
+ return;
99
+ const id = lifecycle?.params?.id;
100
+ if (!id) {
101
+ this.invoice = null;
102
+ this.form = blank();
103
+ this.configure();
104
+ this.updateContext();
105
+ return;
106
+ }
107
+ if (id !== this.invoice?.id)
108
+ await this.load(id);
109
+ }
110
+ render() {
111
+ const links = this.invoice ? invoiceLinkSection() : undefined;
112
+ return html `<ox-page-state .loading=${this.loading} .error=${this.error} @retry=${() => this.invoice && this.load(this.invoice.id)}>
113
+ <div class="page">
114
+ <section class="page-section">
115
+ <header class="page-section-header"><h3>${i18next.t('text.invoice-section-head')}</h3></header>
116
+ ${renderDocumentHead(this.form, this.editable && !this.busy, patch => (this.form = { ...this.form, ...patch }), this.renderTerms())}
117
+ </section>
118
+ <section class="page-section">
119
+ <header class="page-section-header"><h3>${i18next.t('text.invoice-section-lines')}</h3></header>
120
+ <ox-grist mode="GRID" .config=${this.gristConfig} .fetchHandler=${() => ({ total: this.form.items.length, records: this.form.items })}></ox-grist>
121
+ </section>
122
+ ${this.invoice
123
+ ? html `<section class="page-section">
124
+ <header class="page-section-header"><h3>${i18next.t('text.invoice-section-totals')}</h3></header>
125
+ ${renderDocumentTotals(this.invoice)}
126
+ </section>`
127
+ : nothing}
128
+ ${links && this.invoice
129
+ ? html `<section class="page-section">
130
+ <header class="page-section-header"><h3>${links.heading()}</h3></header>
131
+ ${links.render(this.invoice)}
132
+ </section>`
133
+ : nothing}
134
+ ${this.invoice?.status === 'ISSUED' ? this.renderVoid() : nothing}
135
+ </div>
136
+ </ox-page-state>`;
137
+ }
138
+ renderTerms() {
139
+ const editable = this.editable && !this.busy;
140
+ return html `<label
141
+ >${i18next.t('field.invoice-due-date')}
142
+ <input type="date" .value=${this.form.dueDate ?? ''} ?disabled=${!editable} @input=${(e) => (this.form = { ...this.form, dueDate: e.target.value })}
143
+ /></label>
144
+ ${this.form.direction === 'PURCHASE'
145
+ ? html `<label
146
+ >${i18next.t('field.invoice-tax-basis')}
147
+ <select ?disabled=${!editable} @change=${(e) => this.changeTaxBasis(e.target.value)}>
148
+ <option value="CALCULATED" ?selected=${this.form.taxBasis !== 'RECEIVED'}>${i18next.t('text.invoice-tax-basis-calculated')}</option>
149
+ <option value="RECEIVED" ?selected=${this.form.taxBasis === 'RECEIVED'}>${i18next.t('text.invoice-tax-basis-received')}</option>
150
+ </select></label
151
+ >`
152
+ : nothing}`;
153
+ }
154
+ renderVoid() {
155
+ return html `<section class="page-section">
156
+ <header class="page-section-header">
157
+ <h3>${i18next.t('text.invoice-section-void')}</h3>
158
+ <div class="page-section-actions">
159
+ <button danger ?disabled=${this.busy || !this.voidReason.trim()} @click=${() => this.void()}>${i18next.t('button.invoice-void')}</button>
160
+ </div>
161
+ </header>
162
+ <div class="form">
163
+ <label class="wide"
164
+ >${i18next.t('field.invoice-void-reason')}
165
+ <input .value=${this.voidReason} ?disabled=${this.busy} @input=${(e) => (this.voidReason = e.target.value)}
166
+ /></label>
167
+ </div>
168
+ </section>`;
169
+ }
170
+ changeTaxBasis(taxBasis) {
171
+ this.form = { ...this.form, items: linesOf(this.grist), taxBasis };
172
+ this.configure();
173
+ }
174
+ configure() {
175
+ this.gristConfig = documentLinesConfig({ editable: this.editable, received: this.form.taxBasis === 'RECEIVED', currency: this.form.currency || 'KRW' });
176
+ }
177
+ async load(id) {
178
+ this.loading = true;
179
+ this.error = null;
180
+ try {
181
+ const response = await client.query({ query: gql(`query ($id: String!) { invoice(id: $id) { ${FIELDS} } }`), variables: { id }, fetchPolicy: 'no-cache' });
182
+ if (response.errors?.length)
183
+ throw response;
184
+ if (!response.data.invoice)
185
+ throw new Error(i18next.t('text.invoice-not-found'));
186
+ this.show(response.data.invoice);
187
+ }
188
+ catch (error) {
189
+ this.error = error;
190
+ }
191
+ finally {
192
+ this.loading = false;
193
+ this.updateContext();
194
+ }
195
+ }
196
+ show(invoice) {
197
+ this.invoice = invoice;
198
+ this.form = { ...invoice, items: invoice.items.map((item) => ({ ...item })) };
199
+ this.voidReason = '';
200
+ this.configure();
201
+ this.grist?.fetch();
202
+ }
203
+ /** Runs one request at a time; a refusal is said in the server's words. */
204
+ async run(work) {
205
+ if (this.busy)
206
+ return undefined;
207
+ this.busy = true;
208
+ try {
209
+ return await work();
210
+ }
211
+ catch (error) {
212
+ notify({ level: 'error', message: error?.graphQLErrors?.[0]?.message ?? error?.errors?.[0]?.message ?? error?.message ?? String(error) });
213
+ return undefined;
214
+ }
215
+ finally {
216
+ this.busy = false;
217
+ }
218
+ }
219
+ input() {
220
+ const input = Object.fromEntries(HEAD.map(key => [key, this.form[key] === '' ? null : this.form[key] ?? null]));
221
+ input.taxBasis = input.direction === 'PURCHASE' ? input.taxBasis || 'CALCULATED' : 'CALCULATED';
222
+ input.items = linesOf(this.grist);
223
+ return input;
224
+ }
225
+ async save() {
226
+ const id = this.invoice?.id;
227
+ const saved = await this.run(async () => {
228
+ const response = await client.mutate({
229
+ mutation: gql(id
230
+ ? `mutation ($id: String!, $invoice: NewInvoice!) { invoice: updateInvoice(id: $id, invoice: $invoice) { ${FIELDS} } }`
231
+ : `mutation ($invoice: NewInvoice!) { invoice: createInvoice(invoice: $invoice) { ${FIELDS} } }`),
232
+ variables: { ...(id ? { id } : {}), invoice: this.input() }
233
+ });
234
+ if (response.errors?.length)
235
+ throw response;
236
+ return response.data.invoice;
237
+ });
238
+ if (!saved)
239
+ return undefined;
240
+ this.show(saved);
241
+ this.updateContext();
242
+ if (!id)
243
+ navigate(`invoice-editor?id=${saved.id}`);
244
+ return saved;
245
+ }
246
+ /** Save what is on screen, then issue it — its amounts are fixed from here on. */
247
+ async issue() {
248
+ const saved = await this.save();
249
+ if (!saved)
250
+ return;
251
+ const issued = await this.mutate(`mutation ($id: String!) { invoice: issueInvoice(id: $id) { ${FIELDS} } }`, { id: saved.id });
252
+ if (issued)
253
+ notify({ level: 'info', message: i18next.t('text.invoice-issued') });
254
+ }
255
+ async void() {
256
+ const confirmed = await OxPrompt.open({
257
+ title: i18next.t('button.invoice-void'),
258
+ text: i18next.t('text.invoice-void-confirm'),
259
+ confirmButton: { text: i18next.t('button.invoice-void'), destructive: true },
260
+ cancelButton: { text: i18next.t('button.cancel') }
261
+ });
262
+ if (!confirmed)
263
+ return;
264
+ await this.mutate(`mutation ($id: String!, $reason: String!) { invoice: voidInvoice(id: $id, reason: $reason) { ${FIELDS} } }`, {
265
+ id: this.invoice.id,
266
+ reason: this.voidReason.trim()
267
+ });
268
+ }
269
+ async mutate(mutation, variables) {
270
+ const changed = await this.run(async () => {
271
+ const response = await client.mutate({ mutation: gql(mutation), variables });
272
+ if (response.errors?.length)
273
+ throw response;
274
+ return response.data.invoice;
275
+ });
276
+ if (changed) {
277
+ this.show(changed);
278
+ this.updateContext();
279
+ }
280
+ return changed;
281
+ }
282
+ print() {
283
+ const invoice = this.invoice;
284
+ const lng = invoice.language === 'en' ? 'en' : 'ko';
285
+ printDocument(documentHtml(invoice, {
286
+ title: i18next.t('title.invoice-print', { lng }),
287
+ terms: [{ label: i18next.t('field.invoice-due-date', { lng }), value: invoice.dueDate }]
288
+ }));
289
+ }
290
+ };
291
+ __decorate([
292
+ state(),
293
+ __metadata("design:type", Object)
294
+ ], InvoiceEditor.prototype, "invoice", void 0);
295
+ __decorate([
296
+ state(),
297
+ __metadata("design:type", Object)
298
+ ], InvoiceEditor.prototype, "form", void 0);
299
+ __decorate([
300
+ state(),
301
+ __metadata("design:type", Object)
302
+ ], InvoiceEditor.prototype, "loading", void 0);
303
+ __decorate([
304
+ state(),
305
+ __metadata("design:type", Object)
306
+ ], InvoiceEditor.prototype, "error", void 0);
307
+ __decorate([
308
+ state(),
309
+ __metadata("design:type", Object)
310
+ ], InvoiceEditor.prototype, "busy", void 0);
311
+ __decorate([
312
+ state(),
313
+ __metadata("design:type", Object)
314
+ ], InvoiceEditor.prototype, "voidReason", void 0);
315
+ __decorate([
316
+ state(),
317
+ __metadata("design:type", Object)
318
+ ], InvoiceEditor.prototype, "gristConfig", void 0);
319
+ __decorate([
320
+ query('ox-grist'),
321
+ __metadata("design:type", DataGrist)
322
+ ], InvoiceEditor.prototype, "grist", void 0);
323
+ InvoiceEditor = __decorate([
324
+ customElement('invoice-editor')
325
+ ], InvoiceEditor);
326
+ export { InvoiceEditor };
327
+ function blank() {
328
+ return {
329
+ number: '',
330
+ direction: 'SALES',
331
+ currency: 'KRW',
332
+ language: 'ko',
333
+ supplierName: '',
334
+ buyerName: '',
335
+ issueDate: today(),
336
+ dueDate: '',
337
+ taxBasis: 'CALCULATED',
338
+ items: []
339
+ };
340
+ }
341
+ //# sourceMappingURL=invoice-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invoice-editor.js","sourceRoot":"","sources":["../../client/pages/invoice-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist/ox-grist.js'\nimport '@operato/list-state/ox-page-state.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, nothing } from 'lit'\nimport { customElement, query, state } from 'lit/decorators.js'\n\nimport { DataGrist } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { OxPrompt } from '@operato/popup/ox-prompt.js'\nimport { navigate, PageView } from '@operato/shell'\nimport { ButtonStyles, CommonGristStyles, DocumentPageStyles, FormFieldStyles, ScrollbarStyles } from '@operato/styles'\n\nimport { DocumentFormStyles, renderDocumentHead, renderDocumentTotals, type DocumentValue } from '../document/document-form'\nimport { documentLinesConfig, linesOf } from '../document/document-lines'\nimport { documentHtml, printDocument } from '../document/document-print'\nimport { invoiceStatusWord } from '../entity360/invoice-360'\nimport { invoiceLinkSection } from '../invoice-attach'\n\nconst FIELDS = `\n id number status direction currency language supplierName supplierAddress supplierRegistrationNumber buyerName buyerAddress\n buyerRegistrationNumber issueDate dueDate purchaseOrder paymentTerms bankDetails notes sourceReference taxBasis voidReason\n supplyAmount taxAmount totalAmount taxRounding currencyDigits\n items { position description quantity unitPrice discount taxKind taxRate supplyAmount receivedTaxAmount }\n taxGroups { taxKind taxRate supplyAmount taxAmount }\n`\n\nconst HEAD = [\n 'number',\n 'direction',\n 'currency',\n 'language',\n 'supplierName',\n 'supplierAddress',\n 'supplierRegistrationNumber',\n 'buyerName',\n 'buyerAddress',\n 'buyerRegistrationNumber',\n 'issueDate',\n 'dueDate',\n 'purchaseOrder',\n 'paymentTerms',\n 'bankDetails',\n 'notes',\n 'sourceReference',\n 'taxBasis'\n]\n\nconst today = () => new Date().toLocaleDateString('en-CA')\n\n/**\n * 청구서 편집 — the head, the lines, the totals by tax kind and rate, and what an application links it to.\n *\n * A draft is written and saved; 「발행」 saves what is on screen and issues it, after which its amounts never change.\n * An issued invoice is voided with a reason, in its own section. While a request runs only the inputs wait.\n */\n@customElement('invoice-editor')\nexport class InvoiceEditor extends localize(i18next)(PageView) {\n static styles = [\n FormFieldStyles,\n ButtonStyles,\n DocumentPageStyles,\n CommonGristStyles,\n ScrollbarStyles,\n DocumentFormStyles,\n css`\n ox-grist {\n height: calc(var(--form-element-height-medium) * 10);\n }\n `\n ]\n\n @state() invoice: DocumentValue | null = null\n @state() form: DocumentValue = blank()\n @state() loading = false\n @state() error: unknown = null\n @state() busy = false\n @state() voidReason = ''\n @state() gristConfig: any\n\n @query('ox-grist') private grist?: DataGrist\n\n get editable() {\n return !this.invoice || this.invoice.status === 'DRAFT'\n }\n\n get context() {\n const actions: any[] = []\n if (this.editable) {\n actions.push({ title: i18next.t('button.save'), icon: 'save', action: () => this.save() })\n actions.push({ title: i18next.t('button.invoice-issue'), icon: 'send', emphasis: { raised: true }, action: () => this.issue() })\n }\n if (this.invoice) actions.push({ title: i18next.t('button.invoice-print'), icon: 'print', action: () => this.print() })\n return {\n title: this.invoice ? `${i18next.t('title.invoice')} ${this.invoice.number}` : i18next.t('title.invoice-new'),\n ...(this.invoice ? { description: invoiceStatusWord(this.invoice.status) } : {}),\n frame: 'document',\n /* Opened from the invoice list; the menu marks it. */\n menu: 'invoice-list',\n actions: this.error ? [] : actions\n }\n }\n\n async pageUpdated(changes: any, lifecycle: any) {\n if (!this.active || !(changes.active || changes.params)) return\n const id = lifecycle?.params?.id\n if (!id) {\n this.invoice = null\n this.form = blank()\n this.configure()\n this.updateContext()\n return\n }\n if (id !== this.invoice?.id) await this.load(id)\n }\n\n render() {\n const links = this.invoice ? invoiceLinkSection() : undefined\n return html`<ox-page-state .loading=${this.loading} .error=${this.error} @retry=${() => this.invoice && this.load(this.invoice.id)}>\n <div class=\"page\">\n <section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${i18next.t('text.invoice-section-head')}</h3></header>\n ${renderDocumentHead(this.form, this.editable && !this.busy, patch => (this.form = { ...this.form, ...patch }), this.renderTerms())}\n </section>\n <section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${i18next.t('text.invoice-section-lines')}</h3></header>\n <ox-grist mode=\"GRID\" .config=${this.gristConfig} .fetchHandler=${() => ({ total: this.form.items.length, records: this.form.items })}></ox-grist>\n </section>\n ${this.invoice\n ? html`<section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${i18next.t('text.invoice-section-totals')}</h3></header>\n ${renderDocumentTotals(this.invoice)}\n </section>`\n : nothing}\n ${links && this.invoice\n ? html`<section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${links.heading()}</h3></header>\n ${links.render(this.invoice as any)}\n </section>`\n : nothing}\n ${this.invoice?.status === 'ISSUED' ? this.renderVoid() : nothing}\n </div>\n </ox-page-state>`\n }\n\n private renderTerms() {\n const editable = this.editable && !this.busy\n return html`<label\n >${i18next.t('field.invoice-due-date')}\n <input type=\"date\" .value=${this.form.dueDate ?? ''} ?disabled=${!editable} @input=${(e: any) => (this.form = { ...this.form, dueDate: e.target.value })}\n /></label>\n ${this.form.direction === 'PURCHASE'\n ? html`<label\n >${i18next.t('field.invoice-tax-basis')}\n <select ?disabled=${!editable} @change=${(e: any) => this.changeTaxBasis(e.target.value)}>\n <option value=\"CALCULATED\" ?selected=${this.form.taxBasis !== 'RECEIVED'}>${i18next.t('text.invoice-tax-basis-calculated')}</option>\n <option value=\"RECEIVED\" ?selected=${this.form.taxBasis === 'RECEIVED'}>${i18next.t('text.invoice-tax-basis-received')}</option>\n </select></label\n >`\n : nothing}`\n }\n\n private renderVoid() {\n return html`<section class=\"page-section\">\n <header class=\"page-section-header\">\n <h3>${i18next.t('text.invoice-section-void')}</h3>\n <div class=\"page-section-actions\">\n <button danger ?disabled=${this.busy || !this.voidReason.trim()} @click=${() => this.void()}>${i18next.t('button.invoice-void')}</button>\n </div>\n </header>\n <div class=\"form\">\n <label class=\"wide\"\n >${i18next.t('field.invoice-void-reason')}\n <input .value=${this.voidReason} ?disabled=${this.busy} @input=${(e: any) => (this.voidReason = e.target.value)}\n /></label>\n </div>\n </section>`\n }\n\n private changeTaxBasis(taxBasis: string) {\n this.form = { ...this.form, items: linesOf(this.grist), taxBasis }\n this.configure()\n }\n\n private configure() {\n this.gristConfig = documentLinesConfig({ editable: this.editable, received: this.form.taxBasis === 'RECEIVED', currency: this.form.currency || 'KRW' })\n }\n\n private async load(id: string) {\n this.loading = true\n this.error = null\n try {\n const response = await client.query({ query: gql(`query ($id: String!) { invoice(id: $id) { ${FIELDS} } }`), variables: { id }, fetchPolicy: 'no-cache' })\n if (response.errors?.length) throw response\n if (!response.data.invoice) throw new Error(i18next.t('text.invoice-not-found'))\n this.show(response.data.invoice)\n } catch (error) {\n this.error = error\n } finally {\n this.loading = false\n this.updateContext()\n }\n }\n\n private show(invoice: DocumentValue) {\n this.invoice = invoice\n this.form = { ...invoice, items: invoice.items.map((item: any) => ({ ...item })) }\n this.voidReason = ''\n this.configure()\n this.grist?.fetch()\n }\n\n /** Runs one request at a time; a refusal is said in the server's words. */\n private async run<T>(work: () => Promise<T>): Promise<T | undefined> {\n if (this.busy) return undefined\n this.busy = true\n try {\n return await work()\n } catch (error: any) {\n notify({ level: 'error', message: error?.graphQLErrors?.[0]?.message ?? error?.errors?.[0]?.message ?? error?.message ?? String(error) })\n return undefined\n } finally {\n this.busy = false\n }\n }\n\n private input() {\n const input: DocumentValue = Object.fromEntries(HEAD.map(key => [key, this.form[key] === '' ? null : this.form[key] ?? null]))\n input.taxBasis = input.direction === 'PURCHASE' ? input.taxBasis || 'CALCULATED' : 'CALCULATED'\n input.items = linesOf(this.grist)\n return input\n }\n\n private async save(): Promise<DocumentValue | undefined> {\n const id = this.invoice?.id\n const saved = await this.run(async () => {\n const response = await client.mutate({\n mutation: gql(\n id\n ? `mutation ($id: String!, $invoice: NewInvoice!) { invoice: updateInvoice(id: $id, invoice: $invoice) { ${FIELDS} } }`\n : `mutation ($invoice: NewInvoice!) { invoice: createInvoice(invoice: $invoice) { ${FIELDS} } }`\n ),\n variables: { ...(id ? { id } : {}), invoice: this.input() }\n })\n if (response.errors?.length) throw response\n return response.data.invoice as DocumentValue\n })\n if (!saved) return undefined\n this.show(saved)\n this.updateContext()\n if (!id) navigate(`invoice-editor?id=${saved.id}`)\n return saved\n }\n\n /** Save what is on screen, then issue it — its amounts are fixed from here on. */\n private async issue() {\n const saved = await this.save()\n if (!saved) return\n const issued = await this.mutate(`mutation ($id: String!) { invoice: issueInvoice(id: $id) { ${FIELDS} } }`, { id: saved.id })\n if (issued) notify({ level: 'info', message: i18next.t('text.invoice-issued') })\n }\n\n private async void() {\n const confirmed = await OxPrompt.open({\n title: i18next.t('button.invoice-void'),\n text: i18next.t('text.invoice-void-confirm'),\n confirmButton: { text: i18next.t('button.invoice-void'), destructive: true },\n cancelButton: { text: i18next.t('button.cancel') }\n })\n if (!confirmed) return\n await this.mutate(`mutation ($id: String!, $reason: String!) { invoice: voidInvoice(id: $id, reason: $reason) { ${FIELDS} } }`, {\n id: this.invoice!.id,\n reason: this.voidReason.trim()\n })\n }\n\n private async mutate(mutation: string, variables: any) {\n const changed = await this.run(async () => {\n const response = await client.mutate({ mutation: gql(mutation), variables })\n if (response.errors?.length) throw response\n return response.data.invoice as DocumentValue\n })\n if (changed) {\n this.show(changed)\n this.updateContext()\n }\n return changed\n }\n\n private print() {\n const invoice = this.invoice!\n const lng = invoice.language === 'en' ? 'en' : 'ko'\n printDocument(\n documentHtml(invoice, {\n title: i18next.t('title.invoice-print', { lng }),\n terms: [{ label: i18next.t('field.invoice-due-date', { lng }), value: invoice.dueDate }]\n })\n )\n }\n}\n\nfunction blank(): DocumentValue {\n return {\n number: '',\n direction: 'SALES',\n currency: 'KRW',\n language: 'ko',\n supplierName: '',\n buyerName: '',\n issueDate: today(),\n dueDate: '',\n taxBasis: 'CALCULATED',\n items: []\n }\n}\n"]}