@things-factory/invoice 10.1.208 → 10.1.212
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/document/document-form.d.ts +2 -1
- package/dist-client/document/document-form.js +3 -2
- package/dist-client/document/document-form.js.map +1 -1
- package/dist-client/document/document-print.d.ts +2 -1
- package/dist-client/document/document-print.js +2 -2
- package/dist-client/document/document-print.js.map +1 -1
- package/dist-client/entity360/invoice-360.d.ts +8 -0
- package/dist-client/entity360/invoice-360.js +12 -2
- package/dist-client/entity360/invoice-360.js.map +1 -1
- package/dist-client/invoice-files.d.ts +32 -0
- package/dist-client/invoice-files.js +249 -0
- package/dist-client/invoice-files.js.map +1 -0
- package/dist-client/pages/invoice-editor.d.ts +16 -0
- package/dist-client/pages/invoice-editor.js +88 -3
- package/dist-client/pages/invoice-editor.js.map +1 -1
- package/dist-client/pages/invoice-list.js +8 -4
- package/dist-client/pages/invoice-list.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/index.d.ts +1 -0
- package/dist-server/service/index.js +1 -0
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/invoice/index.d.ts +1 -1
- package/dist-server/service/invoice/invoice-files.d.ts +14 -0
- package/dist-server/service/invoice/invoice-files.js +43 -0
- package/dist-server/service/invoice/invoice-files.js.map +1 -0
- package/dist-server/service/invoice/invoice-mutation.d.ts +2 -0
- package/dist-server/service/invoice/invoice-mutation.js +18 -0
- package/dist-server/service/invoice/invoice-mutation.js.map +1 -1
- package/dist-server/service/invoice/invoice-query.d.ts +4 -0
- package/dist-server/service/invoice/invoice-query.js +23 -0
- package/dist-server/service/invoice/invoice-query.js.map +1 -1
- package/dist-server/service/invoice/invoice-rules.d.ts +2 -2
- package/dist-server/service/invoice/invoice-service.js +5 -0
- package/dist-server/service/invoice/invoice-service.js.map +1 -1
- package/dist-server/service/invoice/invoice-type.d.ts +1 -0
- package/dist-server/service/invoice/invoice-type.js +4 -0
- package/dist-server/service/invoice/invoice-type.js.map +1 -1
- package/dist-server/service/invoice/invoice.d.ts +3 -0
- package/dist-server/service/invoice/invoice.js +11 -0
- package/dist-server/service/invoice/invoice.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -4
- package/translations/en.json +13 -1
- package/translations/es.json +13 -1
- package/translations/ja.json +13 -1
- package/translations/ko.json +13 -1
- package/translations/ms.json +13 -1
- package/translations/zh.json +13 -1
|
@@ -2,6 +2,12 @@ import '@operato/data-grist/ox-grist.js';
|
|
|
2
2
|
import '@operato/list-state/ox-page-state.js';
|
|
3
3
|
import { PageView } from '@operato/shell';
|
|
4
4
|
import { type DocumentValue } from '../document/document-form';
|
|
5
|
+
import '../invoice-files';
|
|
6
|
+
type Party = {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
businessNumber?: string | null;
|
|
10
|
+
};
|
|
5
11
|
declare const InvoiceEditor_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
|
|
6
12
|
/**
|
|
7
13
|
* 청구서 편집 — the head, the lines, the totals by tax kind and rate, and what an application links it to.
|
|
@@ -17,6 +23,9 @@ export declare class InvoiceEditor extends InvoiceEditor_base {
|
|
|
17
23
|
error: unknown;
|
|
18
24
|
busy: boolean;
|
|
19
25
|
voidReason: string;
|
|
26
|
+
/** The counterparty search: what was typed, and what it found when more than one. */
|
|
27
|
+
partySearch: string;
|
|
28
|
+
partiesFound: Party[];
|
|
20
29
|
gristConfig: any;
|
|
21
30
|
private grist?;
|
|
22
31
|
get editable(): boolean;
|
|
@@ -30,6 +39,13 @@ export declare class InvoiceEditor extends InvoiceEditor_base {
|
|
|
30
39
|
pageUpdated(changes: any, lifecycle: any): Promise<void>;
|
|
31
40
|
render(): import("lit-html").TemplateResult<1>;
|
|
32
41
|
private renderTerms;
|
|
42
|
+
/**
|
|
43
|
+
* Who the other party is among the domain's counterparties - the buyer of a sale, the supplier of a purchase. Found by
|
|
44
|
+
* name or business number; choosing one writes its name and number onto the printed side, which stays editable.
|
|
45
|
+
*/
|
|
46
|
+
private renderParty;
|
|
47
|
+
private chooseParty;
|
|
48
|
+
private findParties;
|
|
33
49
|
private renderVoid;
|
|
34
50
|
private changeTaxBasis;
|
|
35
51
|
private configure;
|
|
@@ -16,8 +16,9 @@ import { documentLinesConfig, linesOf } from '../document/document-lines';
|
|
|
16
16
|
import { documentHtml, printDocument } from '../document/document-print';
|
|
17
17
|
import { invoiceStatusWord } from '../entity360/invoice-360';
|
|
18
18
|
import { invoiceLinkSection } from '../invoice-attach';
|
|
19
|
+
import '../invoice-files';
|
|
19
20
|
const FIELDS = `
|
|
20
|
-
id number status direction currency language supplierName supplierAddress supplierRegistrationNumber buyerName buyerAddress
|
|
21
|
+
id number status direction currency language counterpartyId counterparty { id name } supplierName supplierAddress supplierRegistrationNumber buyerName buyerAddress
|
|
21
22
|
buyerRegistrationNumber issueDate dueDate purchaseOrder paymentTerms bankDetails notes sourceReference taxBasis voidReason
|
|
22
23
|
supplyAmount taxAmount totalAmount taxRounding currencyDigits
|
|
23
24
|
items { position description quantity unitPrice discount taxKind taxRate supplyAmount receivedTaxAmount }
|
|
@@ -25,6 +26,7 @@ const FIELDS = `
|
|
|
25
26
|
`;
|
|
26
27
|
const HEAD = [
|
|
27
28
|
'number',
|
|
29
|
+
'counterpartyId',
|
|
28
30
|
'direction',
|
|
29
31
|
'currency',
|
|
30
32
|
'language',
|
|
@@ -59,6 +61,9 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
59
61
|
this.error = null;
|
|
60
62
|
this.busy = false;
|
|
61
63
|
this.voidReason = '';
|
|
64
|
+
/** The counterparty search: what was typed, and what it found when more than one. */
|
|
65
|
+
this.partySearch = '';
|
|
66
|
+
this.partiesFound = [];
|
|
62
67
|
}
|
|
63
68
|
static { this.styles = [
|
|
64
69
|
FormFieldStyles,
|
|
@@ -71,6 +76,14 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
71
76
|
ox-grist {
|
|
72
77
|
height: calc(var(--form-element-height-medium) * 10);
|
|
73
78
|
}
|
|
79
|
+
.party {
|
|
80
|
+
display: flex;
|
|
81
|
+
gap: var(--spacing-small);
|
|
82
|
+
align-items: center;
|
|
83
|
+
}
|
|
84
|
+
.party input {
|
|
85
|
+
flex: 1;
|
|
86
|
+
}
|
|
74
87
|
`
|
|
75
88
|
]; }
|
|
76
89
|
get editable() {
|
|
@@ -113,7 +126,7 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
113
126
|
<div class="page">
|
|
114
127
|
<section class="page-section">
|
|
115
128
|
<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())}
|
|
129
|
+
${renderDocumentHead(this.form, this.editable && !this.busy, patch => (this.form = { ...this.form, ...patch }), this.renderTerms(), 'field.invoice-number')}
|
|
117
130
|
</section>
|
|
118
131
|
<section class="page-section">
|
|
119
132
|
<header class="page-section-header"><h3>${i18next.t('text.invoice-section-lines')}</h3></header>
|
|
@@ -123,6 +136,10 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
123
136
|
? html `<section class="page-section">
|
|
124
137
|
<header class="page-section-header"><h3>${i18next.t('text.invoice-section-totals')}</h3></header>
|
|
125
138
|
${renderDocumentTotals(this.invoice)}
|
|
139
|
+
</section>
|
|
140
|
+
<section class="page-section">
|
|
141
|
+
<header class="page-section-header"><h3>${i18next.t('text.invoice-section-files')}</h3></header>
|
|
142
|
+
<invoice-files .invoiceId=${this.invoice.id}></invoice-files>
|
|
126
143
|
</section>`
|
|
127
144
|
: nothing}
|
|
128
145
|
${links && this.invoice
|
|
@@ -137,7 +154,7 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
137
154
|
}
|
|
138
155
|
renderTerms() {
|
|
139
156
|
const editable = this.editable && !this.busy;
|
|
140
|
-
return html
|
|
157
|
+
return html `${this.renderParty(editable)}<label
|
|
141
158
|
>${i18next.t('field.invoice-due-date')}
|
|
142
159
|
<input type="date" .value=${this.form.dueDate ?? ''} ?disabled=${!editable} @input=${(e) => (this.form = { ...this.form, dueDate: e.target.value })}
|
|
143
160
|
/></label>
|
|
@@ -151,6 +168,66 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
151
168
|
>`
|
|
152
169
|
: nothing}`;
|
|
153
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Who the other party is among the domain's counterparties - the buyer of a sale, the supplier of a purchase. Found by
|
|
173
|
+
* name or business number; choosing one writes its name and number onto the printed side, which stays editable.
|
|
174
|
+
*/
|
|
175
|
+
renderParty(editable) {
|
|
176
|
+
const chosen = this.form.counterparty;
|
|
177
|
+
return html `<label
|
|
178
|
+
>${i18next.t('field.invoice-counterparty')}
|
|
179
|
+
<span class="party">
|
|
180
|
+
<input
|
|
181
|
+
.value=${this.partySearch}
|
|
182
|
+
placeholder=${chosen?.name ?? i18next.t('text.invoice-counterparty-search')}
|
|
183
|
+
?disabled=${!editable}
|
|
184
|
+
@input=${(e) => (this.partySearch = e.target.value)}
|
|
185
|
+
@keydown=${(e) => e.key === 'Enter' && this.findParties()}
|
|
186
|
+
/>
|
|
187
|
+
<button ?disabled=${!editable} @click=${() => this.findParties()}>${i18next.t('button.invoice-counterparty-find')}</button>
|
|
188
|
+
${chosen ? html `<button ?disabled=${!editable} @click=${() => this.chooseParty(null)}>${i18next.t('button.invoice-counterparty-clear')}</button>` : nothing}
|
|
189
|
+
</span>
|
|
190
|
+
${this.partiesFound.length
|
|
191
|
+
? html `<select ?disabled=${!editable} @change=${(e) => this.chooseParty(this.partiesFound.find(one => one.id === e.target.value) ?? null)}>
|
|
192
|
+
<option value="">${chosen?.name ?? ''}</option>
|
|
193
|
+
${this.partiesFound.map(one => html `<option value=${one.id}>${one.name}${one.businessNumber ? ` (${one.businessNumber})` : ''}</option>`)}
|
|
194
|
+
</select>`
|
|
195
|
+
: nothing}
|
|
196
|
+
</label>`;
|
|
197
|
+
}
|
|
198
|
+
chooseParty(party) {
|
|
199
|
+
const side = this.form.direction === 'PURCHASE' ? 'supplier' : 'buyer';
|
|
200
|
+
this.form = {
|
|
201
|
+
...this.form,
|
|
202
|
+
counterpartyId: party?.id ?? null,
|
|
203
|
+
counterparty: party,
|
|
204
|
+
...(party ? { [`${side}Name`]: party.name, [`${side}RegistrationNumber`]: party.businessNumber ?? this.form[`${side}RegistrationNumber`] } : {})
|
|
205
|
+
};
|
|
206
|
+
this.partySearch = '';
|
|
207
|
+
this.partiesFound = [];
|
|
208
|
+
}
|
|
209
|
+
async findParties() {
|
|
210
|
+
await this.run(async () => {
|
|
211
|
+
const response = await client.query({
|
|
212
|
+
query: gql `
|
|
213
|
+
query ($search: String, $pagination: Pagination) {
|
|
214
|
+
counterparties: counterpartyChoices(search: $search, pagination: $pagination) {
|
|
215
|
+
items { id name businessNumber }
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
`,
|
|
219
|
+
variables: { search: this.partySearch.trim() || undefined, pagination: { page: 1, limit: 30 } },
|
|
220
|
+
fetchPolicy: 'no-cache'
|
|
221
|
+
});
|
|
222
|
+
if (response.errors?.length)
|
|
223
|
+
throw response;
|
|
224
|
+
const found = response.data.counterparties.items ?? [];
|
|
225
|
+
if (found.length === 1)
|
|
226
|
+
this.chooseParty(found[0]);
|
|
227
|
+
else
|
|
228
|
+
this.partiesFound = found;
|
|
229
|
+
});
|
|
230
|
+
}
|
|
154
231
|
renderVoid() {
|
|
155
232
|
return html `<section class="page-section">
|
|
156
233
|
<header class="page-section-header">
|
|
@@ -312,6 +389,14 @@ __decorate([
|
|
|
312
389
|
state(),
|
|
313
390
|
__metadata("design:type", Object)
|
|
314
391
|
], InvoiceEditor.prototype, "voidReason", void 0);
|
|
392
|
+
__decorate([
|
|
393
|
+
state(),
|
|
394
|
+
__metadata("design:type", Object)
|
|
395
|
+
], InvoiceEditor.prototype, "partySearch", void 0);
|
|
396
|
+
__decorate([
|
|
397
|
+
state(),
|
|
398
|
+
__metadata("design:type", Array)
|
|
399
|
+
], InvoiceEditor.prototype, "partiesFound", void 0);
|
|
315
400
|
__decorate([
|
|
316
401
|
state(),
|
|
317
402
|
__metadata("design:type", Object)
|
|
@@ -1 +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"]}
|
|
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'\nimport '../invoice-files'\n\nconst FIELDS = `\n id number status direction currency language counterpartyId counterparty { id name } 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 'counterpartyId',\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\ntype Party = { id: string; name: string; businessNumber?: string | null }\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 .party {\n display: flex;\n gap: var(--spacing-small);\n align-items: center;\n }\n .party input {\n flex: 1;\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 /** The counterparty search: what was typed, and what it found when more than one. */\n @state() partySearch = ''\n @state() partiesFound: Party[] = []\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(), 'field.invoice-number')}\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 <section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${i18next.t('text.invoice-section-files')}</h3></header>\n <invoice-files .invoiceId=${this.invoice.id}></invoice-files>\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`${this.renderParty(editable)}<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 /**\n * Who the other party is among the domain's counterparties - the buyer of a sale, the supplier of a purchase. Found by\n * name or business number; choosing one writes its name and number onto the printed side, which stays editable.\n */\n private renderParty(editable: boolean) {\n const chosen = this.form.counterparty as Party | null | undefined\n return html`<label\n >${i18next.t('field.invoice-counterparty')}\n <span class=\"party\">\n <input\n .value=${this.partySearch}\n placeholder=${chosen?.name ?? i18next.t('text.invoice-counterparty-search')}\n ?disabled=${!editable}\n @input=${(e: any) => (this.partySearch = e.target.value)}\n @keydown=${(e: KeyboardEvent) => e.key === 'Enter' && this.findParties()}\n />\n <button ?disabled=${!editable} @click=${() => this.findParties()}>${i18next.t('button.invoice-counterparty-find')}</button>\n ${chosen ? html`<button ?disabled=${!editable} @click=${() => this.chooseParty(null)}>${i18next.t('button.invoice-counterparty-clear')}</button>` : nothing}\n </span>\n ${this.partiesFound.length\n ? html`<select ?disabled=${!editable} @change=${(e: any) => this.chooseParty(this.partiesFound.find(one => one.id === e.target.value) ?? null)}>\n <option value=\"\">${chosen?.name ?? ''}</option>\n ${this.partiesFound.map(one => html`<option value=${one.id}>${one.name}${one.businessNumber ? ` (${one.businessNumber})` : ''}</option>`)}\n </select>`\n : nothing}\n </label>`\n }\n\n private chooseParty(party: Party | null) {\n const side = this.form.direction === 'PURCHASE' ? 'supplier' : 'buyer'\n this.form = {\n ...this.form,\n counterpartyId: party?.id ?? null,\n counterparty: party,\n ...(party ? { [`${side}Name`]: party.name, [`${side}RegistrationNumber`]: party.businessNumber ?? this.form[`${side}RegistrationNumber`] } : {})\n }\n this.partySearch = ''\n this.partiesFound = []\n }\n\n private async findParties() {\n await this.run(async () => {\n const response = await client.query({\n query: gql`\n query ($search: String, $pagination: Pagination) {\n counterparties: counterpartyChoices(search: $search, pagination: $pagination) {\n items { id name businessNumber }\n }\n }\n `,\n variables: { search: this.partySearch.trim() || undefined, pagination: { page: 1, limit: 30 } },\n fetchPolicy: 'no-cache'\n })\n if (response.errors?.length) throw response\n const found: Party[] = response.data.counterparties.items ?? []\n if (found.length === 1) this.chooseParty(found[0])\n else this.partiesFound = found\n })\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"]}
|
|
@@ -11,7 +11,7 @@ import { navigate, PageView } from '@operato/shell';
|
|
|
11
11
|
import { CommonGristStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
|
|
12
12
|
import { isMobileDevice } from '@operato/utils';
|
|
13
13
|
import { documentAmount } from '../document/document-amount';
|
|
14
|
-
import {
|
|
14
|
+
import { counterpartCell, invoiceStatusWord } from '../entity360/invoice-360';
|
|
15
15
|
/**
|
|
16
16
|
* 청구서 — every invoice the domain sent or received. The other party's name opens the invoice's 360; the edit gutter
|
|
17
17
|
* opens the editor. Search is the server's: number, parties, purchase order and notes.
|
|
@@ -54,7 +54,7 @@ let InvoiceList = class InvoiceList extends localize(i18next)(PageView) {
|
|
|
54
54
|
rows: { appendable: false, selectable: false },
|
|
55
55
|
pagination: { limit: 50, pages: [50, 100, 500] },
|
|
56
56
|
emptyNote: { title: i18next.t('text.invoice-empty'), description: i18next.t('text.invoice-empty-description') },
|
|
57
|
-
list: { fields: ['
|
|
57
|
+
list: { fields: ['number', 'counterpart'], details: ['status', 'dueDate', 'totalAmount'] },
|
|
58
58
|
columns: [
|
|
59
59
|
{ type: 'gutter', gutterName: 'sequence' },
|
|
60
60
|
{
|
|
@@ -63,11 +63,14 @@ let InvoiceList = class InvoiceList extends localize(i18next)(PageView) {
|
|
|
63
63
|
icon: 'edit_note',
|
|
64
64
|
handlers: { click: (_columns, _data, _column, record) => record?.id && navigate(`invoice-editor?id=${record.id}`) }
|
|
65
65
|
},
|
|
66
|
+
/* The number is the invoice's own name and opens its 360; the other party opens the counterparty's (ADR-0067 decision 1). */
|
|
67
|
+
readonly('string', 'number', i18next.t('field.invoice-number'), 140, {
|
|
68
|
+
record: { renderer: (value, _column, record) => (record?.id ? entity360Name({ __typename: 'Invoice', ...record }, value) : value) }
|
|
69
|
+
}),
|
|
66
70
|
readonly('string', 'counterpart', i18next.t('field.invoice-counterpart'), 200, {
|
|
67
71
|
sortable: false,
|
|
68
|
-
record: { renderer: (_value, _column, record) => (record
|
|
72
|
+
record: { renderer: (_value, _column, record) => counterpartCell(record) }
|
|
69
73
|
}),
|
|
70
|
-
readonly('string', 'number', i18next.t('field.invoice-number'), 140),
|
|
71
74
|
readonly('string', 'status', i18next.t('field.invoice-status'), 80, { record: { renderer: (value) => invoiceStatusWord(value) } }),
|
|
72
75
|
readonly('string', 'direction', i18next.t('field.invoice-direction'), 80, {
|
|
73
76
|
record: { renderer: (value) => (value === 'PURCHASE' ? i18next.t('text.invoice-direction-purchase') : i18next.t('text.invoice-direction-sales')) }
|
|
@@ -92,6 +95,7 @@ let InvoiceList = class InvoiceList extends localize(i18next)(PageView) {
|
|
|
92
95
|
status
|
|
93
96
|
direction
|
|
94
97
|
currency
|
|
98
|
+
counterpartyId
|
|
95
99
|
supplierName
|
|
96
100
|
buyerName
|
|
97
101
|
issueDate
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoice-list.js","sourceRoot":"","sources":["../../client/pages/invoice-list.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist/ox-grist.js'\n\nimport gql from 'graphql-tag'\nimport { html } from 'lit'\nimport { customElement, query, state } from 'lit/decorators.js'\n\nimport { DataGrist, FetchOption } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { entity360Name } from '@operato/layout'\nimport { navigate, PageView } from '@operato/shell'\nimport { CommonGristStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n\nimport { documentAmount } from '../document/document-amount'\nimport { counterpartOf, invoiceStatusWord } from '../entity360/invoice-360'\n\n/**\n * 청구서 — every invoice the domain sent or received. The other party's name opens the invoice's 360; the edit gutter\n * opens the editor. Search is the server's: number, parties, purchase order and notes.\n */\n@customElement('invoice-list')\nexport class InvoiceList extends localize(i18next)(PageView) {\n static styles = [WorkSurfacePageStyles, CommonGristStyles, ScrollbarStyles]\n\n @state() gristConfig: any\n @query('ox-grist') private grist!: DataGrist\n\n get context() {\n return {\n title: i18next.t('title.invoice-list'),\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n },\n actions: [{ title: i18next.t('button.invoice-new'), icon: 'add', emphasis: { raised: true }, action: () => navigate('invoice-editor') }],\n exportable: { name: i18next.t('title.invoice-list'), data: () => this.grist.exportRecords() }\n }\n }\n\n render() {\n return html`<ox-grist\n class=\"page-fill\"\n search-mode=\"term\"\n .mode=${isMobileDevice() ? 'CARD' : 'GRID'}\n .config=${this.gristConfig}\n .fetchHandler=${this.fetchHandler.bind(this)}\n ></ox-grist>`\n }\n\n async pageInitialized() {\n const readonly = (type: string, name: string, header: string, width: number, extra: any = {}) => ({\n type,\n name,\n header,\n width,\n sortable: true,\n ...extra,\n record: { editable: false, ...extra.record }\n })\n this.gristConfig = {\n rows: { appendable: false, selectable: false },\n pagination: { limit: 50, pages: [50, 100, 500] },\n emptyNote: { title: i18next.t('text.invoice-empty'), description: i18next.t('text.invoice-empty-description') },\n list: { fields: ['counterpart', 'number'], details: ['status', 'dueDate', 'totalAmount'] },\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n {\n type: 'gutter',\n gutterName: 'button',\n icon: 'edit_note',\n handlers: { click: (_columns: any, _data: any, _column: any, record: any) => record?.id && navigate(`invoice-editor?id=${record.id}`) }\n },\n readonly('string', 'counterpart', i18next.t('field.invoice-counterpart'), 200, {\n sortable: false,\n record: { renderer: (_value: any, _column: any, record: any) => (record?.id ? entity360Name({ __typename: 'Invoice', ...record }, counterpartOf(record)) : '') }\n }),\n readonly('string', 'number', i18next.t('field.invoice-number'), 140),\n readonly('string', 'status', i18next.t('field.invoice-status'), 80, { record: { renderer: (value: string) => invoiceStatusWord(value) } }),\n readonly('string', 'direction', i18next.t('field.invoice-direction'), 80, {\n record: { renderer: (value: string) => (value === 'PURCHASE' ? i18next.t('text.invoice-direction-purchase') : i18next.t('text.invoice-direction-sales')) }\n }),\n readonly('string', 'issueDate', i18next.t('field.invoice-issue-date'), 110),\n readonly('string', 'dueDate', i18next.t('field.invoice-due-date'), 110),\n readonly('float', 'totalAmount', i18next.t('field.invoice-total-amount'), 160, {\n record: { align: 'right', renderer: (value: number, _column: any, record: any) => documentAmount(value, record?.currency || 'KRW') }\n })\n ],\n sorters: [{ name: 'issueDate', desc: true }]\n }\n }\n\n async fetchHandler({ page = 1, limit = 50, sortings = [], filters = [], search }: FetchOption) {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $search: String) {\n responses: invoices(filters: $filters, pagination: $pagination, sortings: $sortings, search: $search) {\n items {\n id\n number\n status\n direction\n currency\n supplierName\n buyerName\n issueDate\n dueDate\n totalAmount\n }\n total\n }\n }\n `,\n variables: { filters, pagination: { page, limit }, sortings, search: search?.trim() || undefined },\n fetchPolicy: 'network-only'\n })\n if (response.errors?.length) throw response\n return { total: response.data.responses.total, records: response.data.responses.items }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"invoice-list.js","sourceRoot":"","sources":["../../client/pages/invoice-list.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist/ox-grist.js'\n\nimport gql from 'graphql-tag'\nimport { html } from 'lit'\nimport { customElement, query, state } from 'lit/decorators.js'\n\nimport { DataGrist, FetchOption } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { entity360Name } from '@operato/layout'\nimport { navigate, PageView } from '@operato/shell'\nimport { CommonGristStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n\nimport { documentAmount } from '../document/document-amount'\nimport { counterpartCell, invoiceStatusWord } from '../entity360/invoice-360'\n\n/**\n * 청구서 — every invoice the domain sent or received. The other party's name opens the invoice's 360; the edit gutter\n * opens the editor. Search is the server's: number, parties, purchase order and notes.\n */\n@customElement('invoice-list')\nexport class InvoiceList extends localize(i18next)(PageView) {\n static styles = [WorkSurfacePageStyles, CommonGristStyles, ScrollbarStyles]\n\n @state() gristConfig: any\n @query('ox-grist') private grist!: DataGrist\n\n get context() {\n return {\n title: i18next.t('title.invoice-list'),\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n },\n actions: [{ title: i18next.t('button.invoice-new'), icon: 'add', emphasis: { raised: true }, action: () => navigate('invoice-editor') }],\n exportable: { name: i18next.t('title.invoice-list'), data: () => this.grist.exportRecords() }\n }\n }\n\n render() {\n return html`<ox-grist\n class=\"page-fill\"\n search-mode=\"term\"\n .mode=${isMobileDevice() ? 'CARD' : 'GRID'}\n .config=${this.gristConfig}\n .fetchHandler=${this.fetchHandler.bind(this)}\n ></ox-grist>`\n }\n\n async pageInitialized() {\n const readonly = (type: string, name: string, header: string, width: number, extra: any = {}) => ({\n type,\n name,\n header,\n width,\n sortable: true,\n ...extra,\n record: { editable: false, ...extra.record }\n })\n this.gristConfig = {\n rows: { appendable: false, selectable: false },\n pagination: { limit: 50, pages: [50, 100, 500] },\n emptyNote: { title: i18next.t('text.invoice-empty'), description: i18next.t('text.invoice-empty-description') },\n list: { fields: ['number', 'counterpart'], details: ['status', 'dueDate', 'totalAmount'] },\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n {\n type: 'gutter',\n gutterName: 'button',\n icon: 'edit_note',\n handlers: { click: (_columns: any, _data: any, _column: any, record: any) => record?.id && navigate(`invoice-editor?id=${record.id}`) }\n },\n /* The number is the invoice's own name and opens its 360; the other party opens the counterparty's (ADR-0067 decision 1). */\n readonly('string', 'number', i18next.t('field.invoice-number'), 140, {\n record: { renderer: (value: string, _column: any, record: any) => (record?.id ? entity360Name({ __typename: 'Invoice', ...record }, value) : value) }\n }),\n readonly('string', 'counterpart', i18next.t('field.invoice-counterpart'), 200, {\n sortable: false,\n record: { renderer: (_value: any, _column: any, record: any) => counterpartCell(record) }\n }),\n readonly('string', 'status', i18next.t('field.invoice-status'), 80, { record: { renderer: (value: string) => invoiceStatusWord(value) } }),\n readonly('string', 'direction', i18next.t('field.invoice-direction'), 80, {\n record: { renderer: (value: string) => (value === 'PURCHASE' ? i18next.t('text.invoice-direction-purchase') : i18next.t('text.invoice-direction-sales')) }\n }),\n readonly('string', 'issueDate', i18next.t('field.invoice-issue-date'), 110),\n readonly('string', 'dueDate', i18next.t('field.invoice-due-date'), 110),\n readonly('float', 'totalAmount', i18next.t('field.invoice-total-amount'), 160, {\n record: { align: 'right', renderer: (value: number, _column: any, record: any) => documentAmount(value, record?.currency || 'KRW') }\n })\n ],\n sorters: [{ name: 'issueDate', desc: true }]\n }\n }\n\n async fetchHandler({ page = 1, limit = 50, sortings = [], filters = [], search }: FetchOption) {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $search: String) {\n responses: invoices(filters: $filters, pagination: $pagination, sortings: $sortings, search: $search) {\n items {\n id\n number\n status\n direction\n currency\n counterpartyId\n supplierName\n buyerName\n issueDate\n dueDate\n totalAmount\n }\n total\n }\n }\n `,\n variables: { filters, pagination: { page, limit }, sortings, search: search?.trim() || undefined },\n fetchPolicy: 'network-only'\n })\n if (response.errors?.length) throw response\n return { total: response.data.responses.total, records: response.data.responses.items }\n }\n}\n"]}
|