@things-factory/invoice 10.1.223 → 10.1.227
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-amount.d.ts +7 -2
- package/dist-client/document/document-amount.js +11 -6
- package/dist-client/document/document-amount.js.map +1 -1
- package/dist-client/document/document-defaults.d.ts +24 -0
- package/dist-client/document/document-defaults.js +43 -0
- package/dist-client/document/document-defaults.js.map +1 -0
- package/dist-client/document/document-form.d.ts +24 -6
- package/dist-client/document/document-form.js +126 -15
- package/dist-client/document/document-form.js.map +1 -1
- package/dist-client/document/document-lines.d.ts +35 -1
- package/dist-client/document/document-lines.js +58 -9
- package/dist-client/document/document-lines.js.map +1 -1
- package/dist-client/document/document-party.d.ts +37 -0
- package/dist-client/document/document-party.js +217 -0
- package/dist-client/document/document-party.js.map +1 -0
- package/dist-client/document/document-preview.d.ts +37 -0
- package/dist-client/document/document-preview.js +181 -0
- package/dist-client/document/document-preview.js.map +1 -0
- package/dist-client/document/document-print.d.ts +3 -13
- package/dist-client/document/document-print.js +3 -45
- package/dist-client/document/document-print.js.map +1 -1
- package/dist-client/index.d.ts +9 -3
- package/dist-client/index.js +9 -3
- package/dist-client/index.js.map +1 -1
- package/dist-client/pages/invoice-editor.d.ts +37 -12
- package/dist-client/pages/invoice-editor.js +171 -79
- package/dist-client/pages/invoice-editor.js.map +1 -1
- package/dist-client/pages/invoice-list.d.ts +21 -1
- package/dist-client/pages/invoice-list.js +145 -14
- package/dist-client/pages/invoice-list.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/viewparts/document-defaults-setting-let.d.ts +19 -0
- package/dist-client/viewparts/document-defaults-setting-let.js +139 -0
- package/dist-client/viewparts/document-defaults-setting-let.js.map +1 -0
- package/dist-server/role-tasks.js +5 -2
- package/dist-server/role-tasks.js.map +1 -1
- package/dist-server/service/document-defaults/document-defaults-resolver.d.ts +28 -0
- package/dist-server/service/document-defaults/document-defaults-resolver.js +136 -0
- package/dist-server/service/document-defaults/document-defaults-resolver.js.map +1 -0
- package/dist-server/service/document-defaults/document-defaults-rules.d.ts +25 -0
- package/dist-server/service/document-defaults/document-defaults-rules.js +50 -0
- package/dist-server/service/document-defaults/document-defaults-rules.js.map +1 -0
- package/dist-server/service/document-defaults/index.d.ts +6 -0
- package/dist-server/service/document-defaults/index.js +11 -0
- package/dist-server/service/document-defaults/index.js.map +1 -0
- package/dist-server/service/index.d.ts +2 -0
- package/dist-server/service/index.js +4 -1
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/invoice/commercial-document.d.ts +2 -0
- package/dist-server/service/invoice/commercial-document.js +11 -1
- package/dist-server/service/invoice/commercial-document.js.map +1 -1
- package/dist-server/service/invoice/invoice-document-file.d.ts +20 -0
- package/dist-server/service/invoice/invoice-document-file.js +38 -0
- package/dist-server/service/invoice/invoice-document-file.js.map +1 -0
- package/dist-server/service/invoice/invoice-query.d.ts +3 -1
- package/dist-server/service/invoice/invoice-query.js +33 -0
- package/dist-server/service/invoice/invoice-query.js.map +1 -1
- package/dist-server/service/invoice/invoice-rules.d.ts +18 -11
- package/dist-server/service/invoice/invoice-rules.js +49 -96
- package/dist-server/service/invoice/invoice-rules.js.map +1 -1
- package/dist-server/service/invoice/invoice-service.d.ts +1 -0
- package/dist-server/service/invoice/invoice-service.js +5 -2
- package/dist-server/service/invoice/invoice-service.js.map +1 -1
- package/dist-server/service/invoice/invoice-type.d.ts +12 -0
- package/dist-server/service/invoice/invoice-type.js +37 -1
- package/dist-server/service/invoice/invoice-type.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/dist-shared/document-amounts.d.ts +56 -0
- package/dist-shared/document-amounts.js +134 -0
- package/dist-shared/document-amounts.js.map +1 -0
- package/dist-shared/document-money.d.ts +12 -0
- package/dist-shared/document-money.js +38 -0
- package/dist-shared/document-money.js.map +1 -0
- package/dist-shared/document-print.d.ts +37 -0
- package/dist-shared/document-print.js +87 -0
- package/dist-shared/document-print.js.map +1 -0
- package/dist-shared/document-start.d.ts +15 -0
- package/dist-shared/document-start.js +51 -0
- package/dist-shared/document-start.js.map +1 -0
- package/dist-shared/invoice-standing.d.ts +25 -0
- package/dist-shared/invoice-standing.js +51 -0
- package/dist-shared/invoice-standing.js.map +1 -0
- package/package.json +9 -7
- package/shared/document-amounts.ts +209 -0
- package/shared/document-money.ts +33 -0
- package/shared/document-print.ts +131 -0
- package/shared/document-start.ts +46 -0
- package/shared/invoice-standing.ts +49 -0
- package/translations/en.json +32 -6
- package/translations/es.json +22 -1
- package/translations/ja.json +22 -1
- package/translations/ko.json +32 -6
- package/translations/ms.json +22 -1
- package/translations/zh.json +22 -1
- package/tsconfig.shared.tsbuildinfo +1 -1
|
@@ -11,17 +11,21 @@ import { notify } from '@operato/layout';
|
|
|
11
11
|
import { OxPrompt } from '@operato/popup/ox-prompt.js';
|
|
12
12
|
import { navigate, PageView } from '@operato/shell';
|
|
13
13
|
import { ButtonStyles, CommonGristStyles, DocumentPageStyles, FormFieldStyles, ScrollbarStyles } from '@operato/styles';
|
|
14
|
+
import { daysAfter, nextInvoiceNumber } from '@things-factory/invoice/dist-shared/document-start.js';
|
|
15
|
+
import { documentAmount } from '../document/document-amount';
|
|
14
16
|
import { DocumentFormStyles, renderDocumentHead, renderDocumentTotals } from '../document/document-form';
|
|
15
|
-
import { documentLinesConfig, linesOf } from '../document/document-lines';
|
|
16
|
-
import {
|
|
17
|
+
import { documentLinesConfig, linesOf, onLineChange, reckonLines } from '../document/document-lines';
|
|
18
|
+
import { partyOfName } from '../document/document-party';
|
|
19
|
+
import { documentDefaults, headFromDefaults, OUR_SIDE_FIELDS, oursFromLast } from '../document/document-defaults';
|
|
20
|
+
import { openDocumentPreview } from '../document/document-preview';
|
|
17
21
|
import { invoiceStatusWord } from '../entity360/invoice-360';
|
|
18
22
|
import { invoiceLinkSection } from '../invoice-attach';
|
|
19
23
|
import '../invoice-files';
|
|
20
24
|
const FIELDS = `
|
|
21
25
|
id number status direction currency language counterpartyId counterparty { id name } supplierName supplierAddress supplierRegistrationNumber buyerName buyerAddress
|
|
22
26
|
buyerRegistrationNumber issueDate dueDate purchaseOrder paymentTerms bankDetails notes sourceReference taxBasis voidReason
|
|
23
|
-
supplyAmount taxAmount totalAmount taxRounding currencyDigits
|
|
24
|
-
items { position description quantity unitPrice discount taxKind taxRate supplyAmount receivedTaxAmount }
|
|
27
|
+
discountAmount lineSupplyAmount supplyAmount taxAmount totalAmount taxRounding currencyDigits
|
|
28
|
+
items { position description quantity unit unitPrice discount taxKind taxRate supplyAmount receivedTaxAmount }
|
|
25
29
|
taxGroups { taxKind taxRate supplyAmount taxAmount }
|
|
26
30
|
`;
|
|
27
31
|
const HEAD = [
|
|
@@ -43,9 +47,12 @@ const HEAD = [
|
|
|
43
47
|
'bankDetails',
|
|
44
48
|
'notes',
|
|
45
49
|
'sourceReference',
|
|
46
|
-
'taxBasis'
|
|
50
|
+
'taxBasis',
|
|
51
|
+
'discountAmount'
|
|
47
52
|
];
|
|
48
53
|
const today = () => new Date().toLocaleDateString('en-CA');
|
|
54
|
+
/** Days an invoice is due after its issue unless the company says otherwise (ADR-0170 decision 11). */
|
|
55
|
+
const PAYMENT_DAYS = 30;
|
|
49
56
|
/**
|
|
50
57
|
* 청구서 편집 — the head, the lines, the totals by tax kind and rate, and what an application links it to.
|
|
51
58
|
*
|
|
@@ -61,9 +68,12 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
61
68
|
this.error = null;
|
|
62
69
|
this.busy = false;
|
|
63
70
|
this.voidReason = '';
|
|
64
|
-
/** The
|
|
65
|
-
this.
|
|
66
|
-
|
|
71
|
+
/** The totals of the lines as typed - reckoned as the invoice will keep them, shown before it is saved. */
|
|
72
|
+
this.amounts = {};
|
|
73
|
+
/** The company's words a new invoice starts with, and the payment terms it offers (ADR-0170). */
|
|
74
|
+
this.defaults = null;
|
|
75
|
+
/** The number a new invoice was offered - it follows the direction while the person leaves it. */
|
|
76
|
+
this.suggestedNumber = '';
|
|
67
77
|
}
|
|
68
78
|
static { this.styles = [
|
|
69
79
|
FormFieldStyles,
|
|
@@ -76,16 +86,11 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
76
86
|
ox-grist {
|
|
77
87
|
height: calc(var(--form-element-height-medium) * 10);
|
|
78
88
|
}
|
|
79
|
-
.party {
|
|
80
|
-
display: flex;
|
|
81
|
-
gap: var(--spacing-small);
|
|
82
|
-
align-items: center;
|
|
83
|
-
}
|
|
84
|
-
.party input {
|
|
85
|
-
flex: 1;
|
|
86
|
-
}
|
|
87
89
|
`
|
|
88
90
|
]; }
|
|
91
|
+
get received() {
|
|
92
|
+
return this.form.taxBasis === 'RECEIVED';
|
|
93
|
+
}
|
|
89
94
|
get editable() {
|
|
90
95
|
return !this.invoice || this.invoice.status === 'DRAFT';
|
|
91
96
|
}
|
|
@@ -96,7 +101,7 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
96
101
|
actions.push({ title: i18next.t('button.invoice-issue'), icon: 'send', emphasis: { raised: true }, action: () => this.issue() });
|
|
97
102
|
}
|
|
98
103
|
if (this.invoice)
|
|
99
|
-
actions.push({ title: i18next.t('button.invoice-
|
|
104
|
+
actions.push({ title: i18next.t('button.invoice-preview'), icon: 'preview', action: () => this.preview() });
|
|
100
105
|
return {
|
|
101
106
|
title: this.invoice ? `${i18next.t('title.invoice')} ${this.invoice.number}` : i18next.t('title.invoice-new'),
|
|
102
107
|
...(this.invoice ? { description: invoiceStatusWord(this.invoice.status) } : {}),
|
|
@@ -110,11 +115,16 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
110
115
|
if (!this.active || !(changes.active || changes.params))
|
|
111
116
|
return;
|
|
112
117
|
const id = lifecycle?.params?.id;
|
|
118
|
+
if (!this.defaults)
|
|
119
|
+
this.defaults = await documentDefaults();
|
|
113
120
|
if (!id) {
|
|
114
121
|
this.invoice = null;
|
|
115
122
|
this.form = blank();
|
|
123
|
+
this.amounts = {};
|
|
116
124
|
this.configure();
|
|
117
125
|
this.updateContext();
|
|
126
|
+
/* Started, not waited for - the page's title stands meanwhile. */
|
|
127
|
+
this.prefill();
|
|
118
128
|
return;
|
|
119
129
|
}
|
|
120
130
|
if (id !== this.invoice?.id)
|
|
@@ -126,18 +136,26 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
126
136
|
<div class="page">
|
|
127
137
|
<section class="page-section">
|
|
128
138
|
<header class="page-section-header"><h3>${i18next.t('text.invoice-section-head')}</h3></header>
|
|
129
|
-
${renderDocumentHead(this.form, this.editable && !this.busy, patch =>
|
|
139
|
+
${renderDocumentHead(this.form, this.editable && !this.busy, patch => this.edit(patch), this.renderTerms(), 'field.invoice-number', {
|
|
140
|
+
terms: this.defaults?.paymentTerms,
|
|
141
|
+
party: this.renderParty(this.editable && !this.busy)
|
|
142
|
+
})}
|
|
130
143
|
</section>
|
|
131
144
|
<section class="page-section">
|
|
132
145
|
<header class="page-section-header"><h3>${i18next.t('text.invoice-section-lines')}</h3></header>
|
|
133
|
-
<ox-grist
|
|
146
|
+
<ox-grist
|
|
147
|
+
mode="GRID"
|
|
148
|
+
.config=${this.gristConfig}
|
|
149
|
+
.fetchHandler=${() => ({ total: this.form.items.length, records: this.form.items })}
|
|
150
|
+
@record-change=${(e) => (this.amounts = onLineChange(this.grist, e, this.form.currency, this.received, this.form.discountAmount))}
|
|
151
|
+
></ox-grist>
|
|
152
|
+
</section>
|
|
153
|
+
<section class="page-section">
|
|
154
|
+
<header class="page-section-header"><h3>${i18next.t('text.invoice-section-totals')}</h3></header>
|
|
155
|
+
${renderDocumentTotals({ ...this.amounts, currency: this.form.currency }, { value: this.form.discountAmount, editable: this.editable && !this.busy, change: value => this.discount(value) })}
|
|
134
156
|
</section>
|
|
135
157
|
${this.invoice
|
|
136
158
|
? html `<section class="page-section">
|
|
137
|
-
<header class="page-section-header"><h3>${i18next.t('text.invoice-section-totals')}</h3></header>
|
|
138
|
-
${renderDocumentTotals(this.invoice)}
|
|
139
|
-
</section>
|
|
140
|
-
<section class="page-section">
|
|
141
159
|
<header class="page-section-header"><h3>${i18next.t('text.invoice-section-files')}</h3></header>
|
|
142
160
|
<invoice-files .invoiceId=${this.invoice.id}></invoice-files>
|
|
143
161
|
</section>`
|
|
@@ -154,7 +172,7 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
154
172
|
}
|
|
155
173
|
renderTerms() {
|
|
156
174
|
const editable = this.editable && !this.busy;
|
|
157
|
-
return html
|
|
175
|
+
return html `<label
|
|
158
176
|
>${i18next.t('field.invoice-due-date')}
|
|
159
177
|
<input type="date" .value=${this.form.dueDate ?? ''} ?disabled=${!editable} @input=${(e) => (this.form = { ...this.form, dueDate: e.target.value })}
|
|
160
178
|
/></label>
|
|
@@ -170,31 +188,66 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
170
188
|
}
|
|
171
189
|
/**
|
|
172
190
|
* 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.
|
|
191
|
+
* name or business number; choosing one writes its name and number onto the printed side, which stays editable. A
|
|
192
|
+
* saved invoice whose party is none of them says so under the picker (ADR-0170 decision 11).
|
|
174
193
|
*/
|
|
175
194
|
renderParty(editable) {
|
|
176
|
-
const
|
|
195
|
+
const name = this.form.direction === 'PURCHASE' ? this.form.supplierName : this.form.buyerName;
|
|
177
196
|
return html `<label
|
|
178
197
|
>${i18next.t('field.invoice-counterparty')}
|
|
179
|
-
<
|
|
180
|
-
|
|
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}
|
|
198
|
+
<document-party-select .party=${this.form.counterparty ?? null} ?disabled=${!editable} @party=${(e) => this.chooseParty(e.detail)}></document-party-select>
|
|
199
|
+
${this.invoice && !this.form.counterpartyId && String(name ?? '').trim() ? html `<span class="quiet">${i18next.t('text.invoice-counterparty-unlinked')}</span>` : nothing}
|
|
196
200
|
</label>`;
|
|
197
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* A party typed by name and not picked is the counterparty of that name when exactly one is - case and spaces aside;
|
|
204
|
+
* otherwise it stays unlinked and the editor says so.
|
|
205
|
+
*/
|
|
206
|
+
async linkByName() {
|
|
207
|
+
if (this.form.counterpartyId)
|
|
208
|
+
return;
|
|
209
|
+
const party = await partyOfName(this.form.direction === 'PURCHASE' ? this.form.supplierName : this.form.buyerName);
|
|
210
|
+
if (party)
|
|
211
|
+
this.form = { ...this.form, counterpartyId: party.id, counterparty: party };
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* What a new invoice starts with, so a person writes only what is new: the number after the last sales invoice's, the
|
|
215
|
+
* due date the company's days after the issue, the company's own words (ADR-0170 decision 6), and what they leave
|
|
216
|
+
* blank of our side as the last sales invoice wrote it.
|
|
217
|
+
*/
|
|
218
|
+
async prefill() {
|
|
219
|
+
let last;
|
|
220
|
+
try {
|
|
221
|
+
const response = await client.query({
|
|
222
|
+
query: gql `
|
|
223
|
+
query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
|
|
224
|
+
invoices(filters: $filters, pagination: $pagination, sortings: $sortings) { items { number ${OUR_SIDE_FIELDS.join(' ')} } }
|
|
225
|
+
}
|
|
226
|
+
`,
|
|
227
|
+
variables: { filters: [{ name: 'direction', operator: 'eq', value: 'SALES' }], pagination: { page: 1, limit: 1 }, sortings: [{ name: 'createdAt', desc: true }] },
|
|
228
|
+
fetchPolicy: 'no-cache'
|
|
229
|
+
});
|
|
230
|
+
last = response.data?.invoices?.items?.[0];
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
/* Nothing to follow - the first number of the year, and our side from the company's words alone. */
|
|
234
|
+
}
|
|
235
|
+
/* An invoice opened meanwhile is not a new one. */
|
|
236
|
+
if (this.invoice)
|
|
237
|
+
return;
|
|
238
|
+
this.suggestedNumber = nextInvoiceNumber(last?.number, Number(this.form.issueDate.slice(0, 4)));
|
|
239
|
+
this.form = { ...this.form, ...headFromDefaults(this.form, this.defaults) };
|
|
240
|
+
this.form = {
|
|
241
|
+
...this.form,
|
|
242
|
+
...oursFromLast(this.form, last),
|
|
243
|
+
number: this.form.number || this.suggestedNumber,
|
|
244
|
+
dueDate: this.form.dueDate || daysAfter(this.form.issueDate, this.paymentDays)
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
/** Days an invoice is due - the company's, or thirty. */
|
|
248
|
+
get paymentDays() {
|
|
249
|
+
return this.defaults?.paymentDays ?? PAYMENT_DAYS;
|
|
250
|
+
}
|
|
198
251
|
chooseParty(party) {
|
|
199
252
|
const side = this.form.direction === 'PURCHASE' ? 'supplier' : 'buyer';
|
|
200
253
|
this.form = {
|
|
@@ -203,30 +256,6 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
203
256
|
counterparty: party,
|
|
204
257
|
...(party ? { [`${side}Name`]: party.name, [`${side}RegistrationNumber`]: party.businessNumber ?? this.form[`${side}RegistrationNumber`] } : {})
|
|
205
258
|
};
|
|
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
259
|
}
|
|
231
260
|
renderVoid() {
|
|
232
261
|
return html `<section class="page-section">
|
|
@@ -247,6 +276,33 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
247
276
|
changeTaxBasis(taxBasis) {
|
|
248
277
|
this.form = { ...this.form, items: linesOf(this.grist), taxBasis };
|
|
249
278
|
this.configure();
|
|
279
|
+
this.updateComplete.then(() => (this.amounts = reckonLines(this.grist, this.form.currency, this.received, this.form.discountAmount)));
|
|
280
|
+
}
|
|
281
|
+
/** The discount of the whole invoice as typed, and the totals after it. */
|
|
282
|
+
discount(value) {
|
|
283
|
+
this.form = { ...this.form, discountAmount: value };
|
|
284
|
+
this.amounts = reckonLines(this.grist, this.form.currency, this.received, value);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* A change of the head; a new currency reckons the lines in its minor unit; the due date follows a moved issue date
|
|
288
|
+
* while it is the one offered. A new invoice's offered number is ours - a purchase carries its sender's, so it goes
|
|
289
|
+
* while the person leaves it, and comes back with a sale.
|
|
290
|
+
*/
|
|
291
|
+
edit(patch) {
|
|
292
|
+
const currency = this.form.currency;
|
|
293
|
+
const following = patch.issueDate && this.form.dueDate === daysAfter(this.form.issueDate, this.paymentDays);
|
|
294
|
+
const number = this.invoice || !patch.direction
|
|
295
|
+
? {}
|
|
296
|
+
: patch.direction === 'PURCHASE' && this.form.number === this.suggestedNumber
|
|
297
|
+
? { number: '' }
|
|
298
|
+
: patch.direction === 'SALES' && !String(this.form.number ?? '').trim()
|
|
299
|
+
? { number: this.suggestedNumber }
|
|
300
|
+
: {};
|
|
301
|
+
this.form = { ...this.form, ...patch, ...number, ...(following ? { dueDate: daysAfter(patch.issueDate, this.paymentDays) } : {}) };
|
|
302
|
+
if (patch.currency && patch.currency !== currency) {
|
|
303
|
+
this.configure();
|
|
304
|
+
this.amounts = reckonLines(this.grist, this.form.currency, this.received, this.form.discountAmount);
|
|
305
|
+
}
|
|
250
306
|
}
|
|
251
307
|
configure() {
|
|
252
308
|
this.gristConfig = documentLinesConfig({ editable: this.editable, received: this.form.taxBasis === 'RECEIVED', currency: this.form.currency || 'KRW' });
|
|
@@ -273,6 +329,7 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
273
329
|
show(invoice) {
|
|
274
330
|
this.invoice = invoice;
|
|
275
331
|
this.form = { ...invoice, items: invoice.items.map((item) => ({ ...item })) };
|
|
332
|
+
this.amounts = invoice;
|
|
276
333
|
this.voidReason = '';
|
|
277
334
|
this.configure();
|
|
278
335
|
this.grist?.fetch();
|
|
@@ -297,10 +354,14 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
297
354
|
const input = Object.fromEntries(HEAD.map(key => [key, this.form[key] === '' ? null : this.form[key] ?? null]));
|
|
298
355
|
input.taxBasis = input.direction === 'PURCHASE' ? input.taxBasis || 'CALCULATED' : 'CALCULATED';
|
|
299
356
|
input.items = linesOf(this.grist);
|
|
357
|
+
input.discountAmount = input.discountAmount === null ? 0 : Number(input.discountAmount);
|
|
300
358
|
return input;
|
|
301
359
|
}
|
|
302
360
|
async save() {
|
|
303
361
|
const id = this.invoice?.id;
|
|
362
|
+
if (this.busy)
|
|
363
|
+
return undefined;
|
|
364
|
+
await this.linkByName();
|
|
304
365
|
const saved = await this.run(async () => {
|
|
305
366
|
const response = await client.mutate({
|
|
306
367
|
mutation: gql(id
|
|
@@ -320,8 +381,21 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
320
381
|
navigate(`invoice-editor?id=${saved.id}`);
|
|
321
382
|
return saved;
|
|
322
383
|
}
|
|
323
|
-
/**
|
|
384
|
+
/** Asked first - to whom and how much, fixed after - then save what is on screen and issue it. */
|
|
324
385
|
async issue() {
|
|
386
|
+
const purchase = this.form.direction === 'PURCHASE';
|
|
387
|
+
const words = {
|
|
388
|
+
party: (purchase ? this.form.supplierName : this.form.buyerName) || '—',
|
|
389
|
+
total: documentAmount(this.amounts.totalAmount ?? 0, this.form.currency || 'KRW')
|
|
390
|
+
};
|
|
391
|
+
const confirmed = await OxPrompt.open({
|
|
392
|
+
title: i18next.t('button.invoice-issue'),
|
|
393
|
+
text: purchase ? i18next.t('text.invoice-issue-confirm-purchase', words) : i18next.t('text.invoice-issue-confirm', words),
|
|
394
|
+
confirmButton: { text: i18next.t('button.invoice-issue') },
|
|
395
|
+
cancelButton: { text: i18next.t('button.cancel') }
|
|
396
|
+
});
|
|
397
|
+
if (!confirmed)
|
|
398
|
+
return;
|
|
325
399
|
const saved = await this.save();
|
|
326
400
|
if (!saved)
|
|
327
401
|
return;
|
|
@@ -356,13 +430,26 @@ let InvoiceEditor = class InvoiceEditor extends localize(i18next)(PageView) {
|
|
|
356
430
|
}
|
|
357
431
|
return changed;
|
|
358
432
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
433
|
+
/**
|
|
434
|
+
* The saved invoice as it goes out (ADR-0170 decision 10) - the server's page in the language chosen there, the
|
|
435
|
+
* invoice's own first, to download as PDF or print. What is on screen and not saved is not in it.
|
|
436
|
+
*/
|
|
437
|
+
preview() {
|
|
438
|
+
const { id, number, language } = this.invoice;
|
|
439
|
+
openDocumentPreview(async (format, lng) => {
|
|
440
|
+
const response = await client.query({
|
|
441
|
+
query: gql `
|
|
442
|
+
query ($id: String!, $format: DocumentFileFormat!, $language: String) {
|
|
443
|
+
invoiceDocumentFile(id: $id, format: $format, language: $language) { fileName mimeType content }
|
|
444
|
+
}
|
|
445
|
+
`,
|
|
446
|
+
variables: { id, format, language: lng },
|
|
447
|
+
fetchPolicy: 'no-cache'
|
|
448
|
+
});
|
|
449
|
+
if (!response.data?.invoiceDocumentFile)
|
|
450
|
+
throw response.errors?.[0] ?? new Error(i18next.t('text.invoice-not-found'));
|
|
451
|
+
return response.data.invoiceDocumentFile;
|
|
452
|
+
}, language, `${i18next.t('title.invoice-preview')} · ${number}`);
|
|
366
453
|
}
|
|
367
454
|
};
|
|
368
455
|
__decorate([
|
|
@@ -392,15 +479,19 @@ __decorate([
|
|
|
392
479
|
__decorate([
|
|
393
480
|
state(),
|
|
394
481
|
__metadata("design:type", Object)
|
|
395
|
-
], InvoiceEditor.prototype, "
|
|
482
|
+
], InvoiceEditor.prototype, "gristConfig", void 0);
|
|
483
|
+
__decorate([
|
|
484
|
+
state(),
|
|
485
|
+
__metadata("design:type", Object)
|
|
486
|
+
], InvoiceEditor.prototype, "amounts", void 0);
|
|
396
487
|
__decorate([
|
|
397
488
|
state(),
|
|
398
|
-
__metadata("design:type",
|
|
399
|
-
], InvoiceEditor.prototype, "
|
|
489
|
+
__metadata("design:type", Object)
|
|
490
|
+
], InvoiceEditor.prototype, "defaults", void 0);
|
|
400
491
|
__decorate([
|
|
401
492
|
state(),
|
|
402
493
|
__metadata("design:type", Object)
|
|
403
|
-
], InvoiceEditor.prototype, "
|
|
494
|
+
], InvoiceEditor.prototype, "suggestedNumber", void 0);
|
|
404
495
|
__decorate([
|
|
405
496
|
query('ox-grist'),
|
|
406
497
|
__metadata("design:type", DataGrist)
|
|
@@ -420,6 +511,7 @@ function blank() {
|
|
|
420
511
|
issueDate: today(),
|
|
421
512
|
dueDate: '',
|
|
422
513
|
taxBasis: 'CALCULATED',
|
|
514
|
+
discountAmount: 0,
|
|
423
515
|
items: []
|
|
424
516
|
};
|
|
425
517
|
}
|
|
@@ -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'\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"]}
|
|
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 { daysAfter, nextInvoiceNumber } from '@things-factory/invoice/dist-shared/document-start.js'\n\nimport { documentAmount } from '../document/document-amount'\nimport { DocumentFormStyles, renderDocumentHead, renderDocumentTotals, type DocumentValue } from '../document/document-form'\nimport { documentLinesConfig, linesOf, onLineChange, reckonLines } from '../document/document-lines'\nimport { partyOfName, type DocumentParty } from '../document/document-party'\nimport { documentDefaults, headFromDefaults, OUR_SIDE_FIELDS, oursFromLast, type DocumentDefaults } from '../document/document-defaults'\nimport { openDocumentPreview, type DocumentFileFormat } from '../document/document-preview'\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 discountAmount lineSupplyAmount supplyAmount taxAmount totalAmount taxRounding currencyDigits\n items { position description quantity unit 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 'discountAmount'\n]\n\nconst today = () => new Date().toLocaleDateString('en-CA')\n\n/** Days an invoice is due after its issue unless the company says otherwise (ADR-0170 decision 11). */\nconst PAYMENT_DAYS = 30\n\ntype Party = DocumentParty\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 /** The totals of the lines as typed - reckoned as the invoice will keep them, shown before it is saved. */\n @state() amounts: Partial<DocumentValue> = {}\n /** The company's words a new invoice starts with, and the payment terms it offers (ADR-0170). */\n @state() defaults: DocumentDefaults | null = null\n /** The number a new invoice was offered - it follows the direction while the person leaves it. */\n @state() suggestedNumber = ''\n\n @query('ox-grist') private grist?: DataGrist\n\n private get received() {\n return this.form.taxBasis === 'RECEIVED'\n }\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-preview'), icon: 'preview', action: () => this.preview() })\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 (!this.defaults) this.defaults = await documentDefaults()\n if (!id) {\n this.invoice = null\n this.form = blank()\n this.amounts = {}\n this.configure()\n this.updateContext()\n /* Started, not waited for - the page's title stands meanwhile. */\n this.prefill()\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.edit(patch), this.renderTerms(), 'field.invoice-number', {\n terms: this.defaults?.paymentTerms,\n party: this.renderParty(this.editable && !this.busy)\n })}\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\n mode=\"GRID\"\n .config=${this.gristConfig}\n .fetchHandler=${() => ({ total: this.form.items.length, records: this.form.items })}\n @record-change=${(e: CustomEvent) => (this.amounts = onLineChange(this.grist, e, this.form.currency, this.received, this.form.discountAmount))}\n ></ox-grist>\n </section>\n <section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${i18next.t('text.invoice-section-totals')}</h3></header>\n ${renderDocumentTotals(\n { ...this.amounts, currency: this.form.currency },\n { value: this.form.discountAmount, editable: this.editable && !this.busy, change: value => this.discount(value) }\n )}\n </section>\n ${this.invoice\n ? html`<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`<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. A\n * saved invoice whose party is none of them says so under the picker (ADR-0170 decision 11).\n */\n private renderParty(editable: boolean) {\n const name = this.form.direction === 'PURCHASE' ? this.form.supplierName : this.form.buyerName\n return html`<label\n >${i18next.t('field.invoice-counterparty')}\n <document-party-select .party=${this.form.counterparty ?? null} ?disabled=${!editable} @party=${(e: CustomEvent) => this.chooseParty(e.detail)}></document-party-select>\n ${this.invoice && !this.form.counterpartyId && String(name ?? '').trim() ? html`<span class=\"quiet\">${i18next.t('text.invoice-counterparty-unlinked')}</span>` : nothing}\n </label>`\n }\n\n /**\n * A party typed by name and not picked is the counterparty of that name when exactly one is - case and spaces aside;\n * otherwise it stays unlinked and the editor says so.\n */\n private async linkByName() {\n if (this.form.counterpartyId) return\n const party = await partyOfName(this.form.direction === 'PURCHASE' ? this.form.supplierName : this.form.buyerName)\n if (party) this.form = { ...this.form, counterpartyId: party.id, counterparty: party }\n }\n\n /**\n * What a new invoice starts with, so a person writes only what is new: the number after the last sales invoice's, the\n * due date the company's days after the issue, the company's own words (ADR-0170 decision 6), and what they leave\n * blank of our side as the last sales invoice wrote it.\n */\n private async prefill() {\n let last: DocumentValue | undefined\n try {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n invoices(filters: $filters, pagination: $pagination, sortings: $sortings) { items { number ${OUR_SIDE_FIELDS.join(' ')} } }\n }\n `,\n variables: { filters: [{ name: 'direction', operator: 'eq', value: 'SALES' }], pagination: { page: 1, limit: 1 }, sortings: [{ name: 'createdAt', desc: true }] },\n fetchPolicy: 'no-cache'\n })\n last = response.data?.invoices?.items?.[0]\n } catch {\n /* Nothing to follow - the first number of the year, and our side from the company's words alone. */\n }\n /* An invoice opened meanwhile is not a new one. */\n if (this.invoice) return\n this.suggestedNumber = nextInvoiceNumber(last?.number, Number(this.form.issueDate.slice(0, 4)))\n this.form = { ...this.form, ...headFromDefaults(this.form, this.defaults) }\n this.form = {\n ...this.form,\n ...oursFromLast(this.form, last),\n number: this.form.number || this.suggestedNumber,\n dueDate: this.form.dueDate || daysAfter(this.form.issueDate, this.paymentDays)\n }\n }\n\n /** Days an invoice is due - the company's, or thirty. */\n private get paymentDays() {\n return this.defaults?.paymentDays ?? PAYMENT_DAYS\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 }\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 this.updateComplete.then(() => (this.amounts = reckonLines(this.grist, this.form.currency, this.received, this.form.discountAmount)))\n }\n\n /** The discount of the whole invoice as typed, and the totals after it. */\n private discount(value: string) {\n this.form = { ...this.form, discountAmount: value }\n this.amounts = reckonLines(this.grist, this.form.currency, this.received, value)\n }\n\n /**\n * A change of the head; a new currency reckons the lines in its minor unit; the due date follows a moved issue date\n * while it is the one offered. A new invoice's offered number is ours - a purchase carries its sender's, so it goes\n * while the person leaves it, and comes back with a sale.\n */\n private edit(patch: DocumentValue) {\n const currency = this.form.currency\n const following = patch.issueDate && this.form.dueDate === daysAfter(this.form.issueDate, this.paymentDays)\n const number =\n this.invoice || !patch.direction\n ? {}\n : patch.direction === 'PURCHASE' && this.form.number === this.suggestedNumber\n ? { number: '' }\n : patch.direction === 'SALES' && !String(this.form.number ?? '').trim()\n ? { number: this.suggestedNumber }\n : {}\n this.form = { ...this.form, ...patch, ...number, ...(following ? { dueDate: daysAfter(patch.issueDate, this.paymentDays) } : {}) }\n if (patch.currency && patch.currency !== currency) {\n this.configure()\n this.amounts = reckonLines(this.grist, this.form.currency, this.received, this.form.discountAmount)\n }\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.amounts = invoice\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 input.discountAmount = input.discountAmount === null ? 0 : Number(input.discountAmount)\n return input\n }\n\n private async save(): Promise<DocumentValue | undefined> {\n const id = this.invoice?.id\n if (this.busy) return undefined\n await this.linkByName()\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 /** Asked first - to whom and how much, fixed after - then save what is on screen and issue it. */\n private async issue() {\n const purchase = this.form.direction === 'PURCHASE'\n const words = {\n party: (purchase ? this.form.supplierName : this.form.buyerName) || '—',\n total: documentAmount(this.amounts.totalAmount ?? 0, this.form.currency || 'KRW')\n }\n const confirmed = await OxPrompt.open({\n title: i18next.t('button.invoice-issue'),\n text: purchase ? i18next.t('text.invoice-issue-confirm-purchase', words) : i18next.t('text.invoice-issue-confirm', words),\n confirmButton: { text: i18next.t('button.invoice-issue') },\n cancelButton: { text: i18next.t('button.cancel') }\n })\n if (!confirmed) return\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 /**\n * The saved invoice as it goes out (ADR-0170 decision 10) - the server's page in the language chosen there, the\n * invoice's own first, to download as PDF or print. What is on screen and not saved is not in it.\n */\n private preview() {\n const { id, number, language } = this.invoice!\n openDocumentPreview(\n async (format: DocumentFileFormat, lng: string) => {\n const response = await client.query({\n query: gql`\n query ($id: String!, $format: DocumentFileFormat!, $language: String) {\n invoiceDocumentFile(id: $id, format: $format, language: $language) { fileName mimeType content }\n }\n `,\n variables: { id, format, language: lng },\n fetchPolicy: 'no-cache'\n })\n if (!response.data?.invoiceDocumentFile) throw response.errors?.[0] ?? new Error(i18next.t('text.invoice-not-found'))\n return response.data.invoiceDocumentFile\n },\n language,\n `${i18next.t('title.invoice-preview')} · ${number}`\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 discountAmount: 0,\n items: []\n }\n}\n"]}
|
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
import '@operato/data-grist/ox-grist.js';
|
|
2
|
+
import '@operato/input/ox-select.js';
|
|
3
|
+
import '@operato/popup/ox-popup-list.js';
|
|
2
4
|
import { FetchOption } from '@operato/data-grist';
|
|
3
5
|
import { PageView } from '@operato/shell';
|
|
4
6
|
declare const InvoiceList_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
|
|
5
7
|
/**
|
|
6
8
|
* 청구서 — every invoice the domain sent or received. The other party's name opens the invoice's 360; the edit gutter
|
|
7
9
|
* opens the editor. Search is the server's: number, parties, purchase order and notes. Rows picked go to the assistant
|
|
8
|
-
* (「AI와 작업」) as `invoice:<uuid>`, read by the invoice list's read (server invoice-read.ts).
|
|
10
|
+
* (「AI와 작업」) as `invoice:<uuid>`, read by the invoice list's read (server invoice-read.ts). The headroom narrows it by
|
|
11
|
+
* status, direction and issue period; the totals of the rows shown stand over it (ADR-0170 decision 11).
|
|
9
12
|
*/
|
|
10
13
|
export declare class InvoiceList extends InvoiceList_base {
|
|
11
14
|
static styles: import("lit").CSSResult[];
|
|
12
15
|
gristConfig: any;
|
|
16
|
+
status: string;
|
|
17
|
+
direction: string;
|
|
18
|
+
period: string;
|
|
19
|
+
/** The totals of the rows on the page, by direction and currency. */
|
|
20
|
+
totals: {
|
|
21
|
+
direction: string;
|
|
22
|
+
currency: string;
|
|
23
|
+
amount: number;
|
|
24
|
+
}[];
|
|
13
25
|
private grist;
|
|
14
26
|
get context(): {
|
|
15
27
|
title: string;
|
|
@@ -17,6 +29,9 @@ export declare class InvoiceList extends InvoiceList_base {
|
|
|
17
29
|
handler: (search: string) => void;
|
|
18
30
|
value: string;
|
|
19
31
|
};
|
|
32
|
+
filter: {
|
|
33
|
+
handler: () => void;
|
|
34
|
+
};
|
|
20
35
|
actions: {
|
|
21
36
|
title: string;
|
|
22
37
|
icon: string;
|
|
@@ -36,5 +51,10 @@ export declare class InvoiceList extends InvoiceList_base {
|
|
|
36
51
|
total: any;
|
|
37
52
|
records: any;
|
|
38
53
|
}>;
|
|
54
|
+
/**
|
|
55
|
+
* The headroom's choices as the list's filters. Overdue is issued and due before today - the invoice module keeps no
|
|
56
|
+
* payments, so the list reads it from the status and the due date alone (invoice-standing.ts).
|
|
57
|
+
*/
|
|
58
|
+
private headroomFilters;
|
|
39
59
|
}
|
|
40
60
|
export {};
|