@things-factory/quotation 10.1.124 → 10.1.128

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist-client/bootstrap.js +1 -7
  2. package/dist-client/bootstrap.js.map +1 -1
  3. package/dist-client/index.d.ts +2 -1
  4. package/dist-client/index.js +2 -1
  5. package/dist-client/index.js.map +1 -1
  6. package/dist-client/pages/quotation-editor.d.ts +43 -0
  7. package/dist-client/pages/quotation-editor.js +313 -0
  8. package/dist-client/pages/quotation-editor.js.map +1 -0
  9. package/dist-client/pages/quotation-list.d.ts +36 -0
  10. package/dist-client/pages/quotation-list.js +113 -0
  11. package/dist-client/pages/quotation-list.js.map +1 -0
  12. package/dist-client/quotation-attach.d.ts +16 -0
  13. package/dist-client/quotation-attach.js +8 -0
  14. package/dist-client/quotation-attach.js.map +1 -0
  15. package/dist-client/quotation-words.d.ts +1 -0
  16. package/dist-client/quotation-words.js +13 -0
  17. package/dist-client/quotation-words.js.map +1 -0
  18. package/dist-client/route.d.ts +1 -1
  19. package/dist-client/route.js +4 -4
  20. package/dist-client/route.js.map +1 -1
  21. package/dist-client/tsconfig.tsbuildinfo +1 -1
  22. package/dist-server/index.d.ts +1 -0
  23. package/dist-server/index.js +1 -0
  24. package/dist-server/index.js.map +1 -1
  25. package/dist-server/service/index.d.ts +8 -3
  26. package/dist-server/service/index.js +9 -17
  27. package/dist-server/service/index.js.map +1 -1
  28. package/dist-server/service/quotation/index.d.ts +8 -5
  29. package/dist-server/service/quotation/index.js +8 -6
  30. package/dist-server/service/quotation/index.js.map +1 -1
  31. package/dist-server/service/quotation/quotation-event-query.d.ts +9 -0
  32. package/dist-server/service/quotation/quotation-event-query.js +55 -0
  33. package/dist-server/service/quotation/quotation-event-query.js.map +1 -0
  34. package/dist-server/service/quotation/quotation-event.d.ts +22 -0
  35. package/dist-server/service/quotation/quotation-event.js +98 -0
  36. package/dist-server/service/quotation/quotation-event.js.map +1 -0
  37. package/dist-server/service/quotation/quotation-item-query.d.ts +8 -0
  38. package/dist-server/service/quotation/quotation-item-query.js +45 -0
  39. package/dist-server/service/quotation/quotation-item-query.js.map +1 -0
  40. package/dist-server/service/quotation/quotation-item.d.ts +18 -0
  41. package/dist-server/service/quotation/quotation-item.js +75 -0
  42. package/dist-server/service/quotation/quotation-item.js.map +1 -0
  43. package/dist-server/service/quotation/quotation-mutation.d.ts +7 -6
  44. package/dist-server/service/quotation/quotation-mutation.js +66 -140
  45. package/dist-server/service/quotation/quotation-mutation.js.map +1 -1
  46. package/dist-server/service/quotation/quotation-query.d.ts +10 -5
  47. package/dist-server/service/quotation/quotation-query.js +69 -41
  48. package/dist-server/service/quotation/quotation-query.js.map +1 -1
  49. package/dist-server/service/quotation/quotation-rules.d.ts +6 -0
  50. package/dist-server/service/quotation/quotation-rules.js +22 -0
  51. package/dist-server/service/quotation/quotation-rules.js.map +1 -0
  52. package/dist-server/service/quotation/quotation-service.d.ts +23 -0
  53. package/dist-server/service/quotation/quotation-service.js +114 -0
  54. package/dist-server/service/quotation/quotation-service.js.map +1 -0
  55. package/dist-server/service/quotation/quotation-type.d.ts +4 -18
  56. package/dist-server/service/quotation/quotation-type.js +9 -63
  57. package/dist-server/service/quotation/quotation-type.js.map +1 -1
  58. package/dist-server/service/quotation/quotation.d.ts +19 -11
  59. package/dist-server/service/quotation/quotation.js +41 -44
  60. package/dist-server/service/quotation/quotation.js.map +1 -1
  61. package/dist-server/tsconfig.tsbuildinfo +1 -1
  62. package/package.json +16 -6
  63. package/things-factory.config.js +2 -2
  64. package/translations/en.json +36 -1
  65. package/translations/ko.json +36 -1
  66. package/dist-client/actions/main.d.ts +0 -1
  67. package/dist-client/actions/main.js +0 -2
  68. package/dist-client/actions/main.js.map +0 -1
  69. package/dist-client/activities/activity-quotation-edit.d.ts +0 -14
  70. package/dist-client/activities/activity-quotation-edit.js +0 -87
  71. package/dist-client/activities/activity-quotation-edit.js.map +0 -1
  72. package/dist-client/activities/activity-quotation-view.d.ts +0 -14
  73. package/dist-client/activities/activity-quotation-view.js +0 -87
  74. package/dist-client/activities/activity-quotation-view.js.map +0 -1
  75. package/dist-client/pages/main.d.ts +0 -1
  76. package/dist-client/pages/main.js +0 -36
  77. package/dist-client/pages/main.js.map +0 -1
  78. package/dist-client/pages/quotation/quotation-importer.d.ts +0 -23
  79. package/dist-client/pages/quotation/quotation-importer.js +0 -93
  80. package/dist-client/pages/quotation/quotation-importer.js.map +0 -1
  81. package/dist-client/pages/quotation/quotation-list-page.d.ts +0 -55
  82. package/dist-client/pages/quotation/quotation-list-page.js +0 -262
  83. package/dist-client/pages/quotation/quotation-list-page.js.map +0 -1
  84. package/dist-client/reducers/main.d.ts +0 -6
  85. package/dist-client/reducers/main.js +0 -14
  86. package/dist-client/reducers/main.js.map +0 -1
  87. package/dist-server/activities/activity-quotation.d.ts +0 -42
  88. package/dist-server/activities/activity-quotation.js +0 -114
  89. package/dist-server/activities/activity-quotation.js.map +0 -1
  90. package/dist-server/activities/index.d.ts +0 -1
  91. package/dist-server/activities/index.js +0 -17
  92. package/dist-server/activities/index.js.map +0 -1
  93. package/dist-server/service/quotation/event-subscriber.d.ts +0 -7
  94. package/dist-server/service/quotation/event-subscriber.js +0 -21
  95. package/dist-server/service/quotation/event-subscriber.js.map +0 -1
  96. package/dist-server/service/quotation/quotation-history.d.ts +0 -25
  97. package/dist-server/service/quotation/quotation-history.js +0 -132
  98. package/dist-server/service/quotation/quotation-history.js.map +0 -1
@@ -1,8 +1,2 @@
1
- import { store } from '@operato/shell';
2
- import quotation from './reducers/main';
3
- export default function bootstrap() {
4
- store.addReducers({
5
- quotation
6
- });
7
- }
1
+ export default function bootstrap() { }
8
2
  //# sourceMappingURL=bootstrap.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,SAAS,MAAM,iBAAiB,CAAA;AAEvC,MAAM,CAAC,OAAO,UAAU,SAAS;IAC/B,KAAK,CAAC,WAAW,CAAC;QAChB,SAAS;KACV,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { store } from '@operato/shell'\nimport quotation from './reducers/main'\n\nexport default function bootstrap() {\n store.addReducers({\n quotation\n })\n}\n"]}
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../client/bootstrap.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,SAAS,KAAI,CAAC","sourcesContent":["export default function bootstrap() {}\n"]}
@@ -1 +1,2 @@
1
- export * from './actions/main';
1
+ export { configureQuotationSection, type QuotationSection } from './quotation-attach.js';
2
+ export { quotationStatusWord } from './quotation-words.js';
@@ -1,2 +1,3 @@
1
- export * from './actions/main';
1
+ export { configureQuotationSection } from './quotation-attach.js';
2
+ export { quotationStatusWord } from './quotation-words.js';
2
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA","sourcesContent":["export * from './actions/main'"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAyB,MAAM,uBAAuB,CAAA;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA","sourcesContent":["export { configureQuotationSection, type QuotationSection } from './quotation-attach.js'\nexport { quotationStatusWord } from './quotation-words.js'\n"]}
@@ -0,0 +1,43 @@
1
+ import '@operato/data-grist/ox-grist.js';
2
+ import '@operato/list-state/ox-page-state.js';
3
+ import { PageView } from '@operato/shell';
4
+ import { type DocumentValue } from '@things-factory/invoice/dist-client';
5
+ declare const QuotationEditor_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
6
+ /**
7
+ * 견적 편집 — the same head, lines and totals as an invoice, valid until a day.
8
+ *
9
+ * A draft is saved and sent; once sent its amounts are fixed, and the buyer's answer is recorded — accepted, or
10
+ * declined with a reason. To change a sent quotation, revise it: the next version keeps the number.
11
+ */
12
+ export declare class QuotationEditor extends QuotationEditor_base {
13
+ static styles: import("lit").CSSResult[];
14
+ quotation: DocumentValue | null;
15
+ form: DocumentValue;
16
+ loading: boolean;
17
+ error: unknown;
18
+ busy: boolean;
19
+ reason: string;
20
+ gristConfig: any;
21
+ private grist?;
22
+ get editable(): boolean;
23
+ get context(): {
24
+ frame: string;
25
+ actions: any[];
26
+ description?: string | undefined;
27
+ title: string;
28
+ };
29
+ pageUpdated(changes: any, lifecycle: any): Promise<void>;
30
+ render(): import("lit-html").TemplateResult<1>;
31
+ private renderDecline;
32
+ private configure;
33
+ private load;
34
+ private show;
35
+ private run;
36
+ private input;
37
+ private save;
38
+ /** Save what is on screen, then send it — its amounts are fixed from here on. */
39
+ private send;
40
+ private change;
41
+ private print;
42
+ }
43
+ export {};
@@ -0,0 +1,313 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@operato/data-grist/ox-grist.js';
3
+ import '@operato/list-state/ox-page-state.js';
4
+ import gql from 'graphql-tag';
5
+ import { css, html, nothing } from 'lit';
6
+ import { customElement, query, state } from 'lit/decorators.js';
7
+ import { DataGrist } from '@operato/data-grist';
8
+ import { client } from '@operato/graphql';
9
+ import { i18next, localize } from '@operato/i18n';
10
+ import { notify } from '@operato/layout';
11
+ import { navigate, PageView } from '@operato/shell';
12
+ import { ButtonStyles, CommonGristStyles, DocumentPageStyles, FormFieldStyles, ScrollbarStyles } from '@operato/styles';
13
+ import { documentHtml, DocumentFormStyles, documentLinesConfig, linesOf, printDocument, renderDocumentHead, renderDocumentTotals } from '@things-factory/invoice/dist-client';
14
+ import { quotationSection } from '../quotation-attach';
15
+ import { quotationStatusWord } from '../quotation-words';
16
+ const FIELDS = `
17
+ id number version status validUntil outcomeReason direction currency language supplierName supplierAddress supplierRegistrationNumber
18
+ buyerName buyerAddress buyerRegistrationNumber issueDate purchaseOrder paymentTerms bankDetails notes sourceReference
19
+ supplyAmount taxAmount totalAmount taxRounding currencyDigits
20
+ items { position description quantity unitPrice discount taxKind taxRate supplyAmount }
21
+ taxGroups { taxKind taxRate supplyAmount taxAmount }
22
+ `;
23
+ const HEAD = [
24
+ 'number',
25
+ 'direction',
26
+ 'currency',
27
+ 'language',
28
+ 'supplierName',
29
+ 'supplierAddress',
30
+ 'supplierRegistrationNumber',
31
+ 'buyerName',
32
+ 'buyerAddress',
33
+ 'buyerRegistrationNumber',
34
+ 'issueDate',
35
+ 'purchaseOrder',
36
+ 'paymentTerms',
37
+ 'bankDetails',
38
+ 'notes',
39
+ 'sourceReference',
40
+ 'validUntil'
41
+ ];
42
+ const today = () => new Date().toLocaleDateString('en-CA');
43
+ /**
44
+ * 견적 편집 — the same head, lines and totals as an invoice, valid until a day.
45
+ *
46
+ * A draft is saved and sent; once sent its amounts are fixed, and the buyer's answer is recorded — accepted, or
47
+ * declined with a reason. To change a sent quotation, revise it: the next version keeps the number.
48
+ */
49
+ let QuotationEditor = class QuotationEditor extends localize(i18next)(PageView) {
50
+ constructor() {
51
+ super(...arguments);
52
+ this.quotation = null;
53
+ this.form = blank();
54
+ this.loading = false;
55
+ this.error = null;
56
+ this.busy = false;
57
+ this.reason = '';
58
+ }
59
+ static { this.styles = [
60
+ FormFieldStyles,
61
+ ButtonStyles,
62
+ DocumentPageStyles,
63
+ CommonGristStyles,
64
+ ScrollbarStyles,
65
+ DocumentFormStyles,
66
+ css `
67
+ ox-grist {
68
+ height: calc(var(--form-element-height-medium) * 10);
69
+ }
70
+ `
71
+ ]; }
72
+ get editable() {
73
+ return !this.quotation || this.quotation.status === 'DRAFT';
74
+ }
75
+ get context() {
76
+ const status = this.quotation?.status;
77
+ const actions = [];
78
+ if (this.editable) {
79
+ actions.push({ title: i18next.t('button.save'), icon: 'save', action: () => this.save() });
80
+ actions.push({ title: i18next.t('button.quotation-send'), icon: 'send', emphasis: { raised: true }, action: () => this.send() });
81
+ }
82
+ if (status === 'SENT') {
83
+ if (this.quotation.validUntil < today())
84
+ actions.push({ title: i18next.t('button.quotation-expire'), action: () => this.change('expireQuotation') });
85
+ else
86
+ actions.push({ title: i18next.t('button.quotation-accept'), emphasis: { raised: true }, action: () => this.change('acceptQuotation') });
87
+ }
88
+ if (['SENT', 'REJECTED', 'EXPIRED'].includes(status))
89
+ actions.push({ title: i18next.t('button.quotation-revise'), icon: 'edit_document', action: () => this.change('reviseQuotation') });
90
+ if (this.quotation)
91
+ actions.push({ title: i18next.t('button.quotation-print'), icon: 'print', action: () => this.print() });
92
+ return {
93
+ title: this.quotation ? `${i18next.t('title.quotation')} ${this.quotation.number} · v${this.quotation.version}` : i18next.t('title.quotation-new'),
94
+ ...(this.quotation ? { description: quotationStatusWord(status) } : {}),
95
+ frame: 'document',
96
+ actions: this.error ? [] : actions
97
+ };
98
+ }
99
+ async pageUpdated(changes, lifecycle) {
100
+ if (!this.active || !(changes.active || changes.params))
101
+ return;
102
+ const id = lifecycle?.params?.id;
103
+ if (!id) {
104
+ this.quotation = null;
105
+ this.form = blank();
106
+ this.configure();
107
+ this.updateContext();
108
+ return;
109
+ }
110
+ if (id !== this.quotation?.id)
111
+ await this.load(id);
112
+ }
113
+ render() {
114
+ const attached = this.quotation ? quotationSection() : undefined;
115
+ const editable = this.editable && !this.busy;
116
+ return html `<ox-page-state .loading=${this.loading} .error=${this.error} @retry=${() => this.quotation && this.load(this.quotation.id)}>
117
+ <div class="page">
118
+ <section class="page-section">
119
+ <header class="page-section-header"><h3>${i18next.t('text.invoice-section-head')}</h3></header>
120
+ ${renderDocumentHead(this.form, editable, patch => (this.form = { ...this.form, ...patch }), html `<label
121
+ >${i18next.t('field.quotation-valid-until')}
122
+ <input type="date" .value=${this.form.validUntil ?? ''} ?disabled=${!editable} @input=${(e) => (this.form = { ...this.form, validUntil: e.target.value })}
123
+ /></label>`)}
124
+ </section>
125
+ <section class="page-section">
126
+ <header class="page-section-header"><h3>${i18next.t('text.invoice-section-lines')}</h3></header>
127
+ <ox-grist mode="GRID" .config=${this.gristConfig} .fetchHandler=${() => ({ total: this.form.items.length, records: this.form.items })}></ox-grist>
128
+ </section>
129
+ ${this.quotation
130
+ ? html `<section class="page-section">
131
+ <header class="page-section-header"><h3>${i18next.t('text.invoice-section-totals')}</h3></header>
132
+ ${renderDocumentTotals(this.quotation)}
133
+ </section>`
134
+ : nothing}
135
+ ${this.quotation?.status === 'SENT' ? this.renderDecline() : nothing}
136
+ ${this.quotation?.outcomeReason
137
+ ? html `<section class="page-section">
138
+ <header class="page-section-header"><h3>${i18next.t('field.quotation-outcome-reason')}</h3></header>
139
+ <p>${this.quotation.outcomeReason}</p>
140
+ </section>`
141
+ : nothing}
142
+ ${attached && this.quotation
143
+ ? html `<section class="page-section">
144
+ <header class="page-section-header"><h3>${attached.heading()}</h3></header>
145
+ ${attached.render(this.quotation)}
146
+ </section>`
147
+ : nothing}
148
+ </div>
149
+ </ox-page-state>`;
150
+ }
151
+ renderDecline() {
152
+ return html `<section class="page-section">
153
+ <header class="page-section-header">
154
+ <h3>${i18next.t('text.quotation-section-decline')}</h3>
155
+ <div class="page-section-actions">
156
+ <button ?disabled=${this.busy || !this.reason.trim()} @click=${() => this.change('rejectQuotation', this.reason.trim())}>${i18next.t('button.quotation-reject')}</button>
157
+ </div>
158
+ </header>
159
+ <div class="form">
160
+ <label class="wide"
161
+ >${i18next.t('field.quotation-outcome-reason')}
162
+ <input .value=${this.reason} ?disabled=${this.busy} @input=${(e) => (this.reason = e.target.value)}
163
+ /></label>
164
+ </div>
165
+ </section>`;
166
+ }
167
+ configure() {
168
+ this.gristConfig = documentLinesConfig({ editable: this.editable, currency: this.form.currency || 'KRW' });
169
+ }
170
+ async load(id) {
171
+ this.loading = true;
172
+ this.error = null;
173
+ try {
174
+ const response = await client.query({ query: gql(`query ($id: String!) { quotation(id: $id) { ${FIELDS} } }`), variables: { id }, fetchPolicy: 'no-cache' });
175
+ if (response.errors?.length)
176
+ throw response;
177
+ if (!response.data.quotation)
178
+ throw new Error(i18next.t('text.quotation-not-found'));
179
+ this.show(response.data.quotation);
180
+ }
181
+ catch (error) {
182
+ this.error = error;
183
+ }
184
+ finally {
185
+ this.loading = false;
186
+ this.updateContext();
187
+ }
188
+ }
189
+ show(quotation) {
190
+ this.quotation = quotation;
191
+ this.form = { ...quotation, items: quotation.items.map((item) => ({ ...item })) };
192
+ this.reason = '';
193
+ this.configure();
194
+ this.grist?.fetch();
195
+ }
196
+ async run(work) {
197
+ if (this.busy)
198
+ return undefined;
199
+ this.busy = true;
200
+ try {
201
+ return await work();
202
+ }
203
+ catch (error) {
204
+ notify({ level: 'error', message: error?.graphQLErrors?.[0]?.message ?? error?.errors?.[0]?.message ?? error?.message ?? String(error) });
205
+ return undefined;
206
+ }
207
+ finally {
208
+ this.busy = false;
209
+ }
210
+ }
211
+ input() {
212
+ const input = Object.fromEntries(HEAD.map(key => [key, this.form[key] === '' ? null : this.form[key] ?? null]));
213
+ input.items = linesOf(this.grist).map(({ receivedTaxAmount, ...line }) => line);
214
+ return input;
215
+ }
216
+ async save() {
217
+ const id = this.quotation?.id;
218
+ const saved = await this.run(async () => {
219
+ const response = await client.mutate({
220
+ mutation: gql(id
221
+ ? `mutation ($id: String!, $quotation: NewQuotation!) { quotation: updateQuotation(id: $id, quotation: $quotation) { ${FIELDS} } }`
222
+ : `mutation ($quotation: NewQuotation!) { quotation: createQuotation(quotation: $quotation) { ${FIELDS} } }`),
223
+ variables: { ...(id ? { id } : {}), quotation: this.input() }
224
+ });
225
+ if (response.errors?.length)
226
+ throw response;
227
+ return response.data.quotation;
228
+ });
229
+ if (!saved)
230
+ return undefined;
231
+ this.show(saved);
232
+ this.updateContext();
233
+ if (!id)
234
+ navigate(`quotation-editor?id=${saved.id}`);
235
+ return saved;
236
+ }
237
+ /** Save what is on screen, then send it — its amounts are fixed from here on. */
238
+ async send() {
239
+ const saved = await this.save();
240
+ if (saved)
241
+ await this.change('sendQuotation');
242
+ }
243
+ async change(mutation, reason) {
244
+ const changed = await this.run(async () => {
245
+ const response = await client.mutate({
246
+ mutation: gql(reason === undefined
247
+ ? `mutation ($id: String!) { quotation: ${mutation}(id: $id) { ${FIELDS} } }`
248
+ : `mutation ($id: String!, $reason: String!) { quotation: ${mutation}(id: $id, reason: $reason) { ${FIELDS} } }`),
249
+ variables: { id: this.quotation.id, ...(reason === undefined ? {} : { reason }) }
250
+ });
251
+ if (response.errors?.length)
252
+ throw response;
253
+ return response.data.quotation;
254
+ });
255
+ if (!changed)
256
+ return;
257
+ if (changed.id !== this.quotation?.id)
258
+ navigate(`quotation-editor?id=${changed.id}`);
259
+ this.show(changed);
260
+ this.updateContext();
261
+ }
262
+ print() {
263
+ const quotation = this.quotation;
264
+ const lng = quotation.language === 'en' ? 'en' : 'ko';
265
+ printDocument(documentHtml(quotation, {
266
+ title: i18next.t('title.quotation-print', { lng }),
267
+ terms: [
268
+ { label: i18next.t('field.quotation-version', { lng }), value: `v${quotation.version}` },
269
+ { label: i18next.t('field.quotation-valid-until', { lng }), value: quotation.validUntil }
270
+ ]
271
+ }));
272
+ }
273
+ };
274
+ __decorate([
275
+ state(),
276
+ __metadata("design:type", Object)
277
+ ], QuotationEditor.prototype, "quotation", void 0);
278
+ __decorate([
279
+ state(),
280
+ __metadata("design:type", Object)
281
+ ], QuotationEditor.prototype, "form", void 0);
282
+ __decorate([
283
+ state(),
284
+ __metadata("design:type", Object)
285
+ ], QuotationEditor.prototype, "loading", void 0);
286
+ __decorate([
287
+ state(),
288
+ __metadata("design:type", Object)
289
+ ], QuotationEditor.prototype, "error", void 0);
290
+ __decorate([
291
+ state(),
292
+ __metadata("design:type", Object)
293
+ ], QuotationEditor.prototype, "busy", void 0);
294
+ __decorate([
295
+ state(),
296
+ __metadata("design:type", Object)
297
+ ], QuotationEditor.prototype, "reason", void 0);
298
+ __decorate([
299
+ state(),
300
+ __metadata("design:type", Object)
301
+ ], QuotationEditor.prototype, "gristConfig", void 0);
302
+ __decorate([
303
+ query('ox-grist'),
304
+ __metadata("design:type", DataGrist)
305
+ ], QuotationEditor.prototype, "grist", void 0);
306
+ QuotationEditor = __decorate([
307
+ customElement('quotation-editor')
308
+ ], QuotationEditor);
309
+ export { QuotationEditor };
310
+ function blank() {
311
+ return { number: '', direction: 'SALES', currency: 'KRW', language: 'ko', supplierName: '', buyerName: '', issueDate: today(), validUntil: '', items: [] };
312
+ }
313
+ //# sourceMappingURL=quotation-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quotation-editor.js","sourceRoot":"","sources":["../../client/pages/quotation-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 { navigate, PageView } from '@operato/shell'\nimport { ButtonStyles, CommonGristStyles, DocumentPageStyles, FormFieldStyles, ScrollbarStyles } from '@operato/styles'\nimport {\n documentHtml,\n DocumentFormStyles,\n documentLinesConfig,\n linesOf,\n printDocument,\n renderDocumentHead,\n renderDocumentTotals,\n type DocumentValue\n} from '@things-factory/invoice/dist-client'\n\nimport { quotationSection } from '../quotation-attach'\nimport { quotationStatusWord } from '../quotation-words'\n\nconst FIELDS = `\n id number version status validUntil outcomeReason direction currency language supplierName supplierAddress supplierRegistrationNumber\n buyerName buyerAddress buyerRegistrationNumber issueDate purchaseOrder paymentTerms bankDetails notes sourceReference\n supplyAmount taxAmount totalAmount taxRounding currencyDigits\n items { position description quantity unitPrice discount taxKind taxRate supplyAmount }\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 'purchaseOrder',\n 'paymentTerms',\n 'bankDetails',\n 'notes',\n 'sourceReference',\n 'validUntil'\n]\n\nconst today = () => new Date().toLocaleDateString('en-CA')\n\n/**\n * 견적 편집 — the same head, lines and totals as an invoice, valid until a day.\n *\n * A draft is saved and sent; once sent its amounts are fixed, and the buyer's answer is recorded — accepted, or\n * declined with a reason. To change a sent quotation, revise it: the next version keeps the number.\n */\n@customElement('quotation-editor')\nexport class QuotationEditor 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() quotation: DocumentValue | null = null\n @state() form: DocumentValue = blank()\n @state() loading = false\n @state() error: unknown = null\n @state() busy = false\n @state() reason = ''\n @state() gristConfig: any\n\n @query('ox-grist') private grist?: DataGrist\n\n get editable() {\n return !this.quotation || this.quotation.status === 'DRAFT'\n }\n\n get context() {\n const status = this.quotation?.status\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.quotation-send'), icon: 'send', emphasis: { raised: true }, action: () => this.send() })\n }\n if (status === 'SENT') {\n if (this.quotation!.validUntil < today()) actions.push({ title: i18next.t('button.quotation-expire'), action: () => this.change('expireQuotation') })\n else actions.push({ title: i18next.t('button.quotation-accept'), emphasis: { raised: true }, action: () => this.change('acceptQuotation') })\n }\n if (['SENT', 'REJECTED', 'EXPIRED'].includes(status)) actions.push({ title: i18next.t('button.quotation-revise'), icon: 'edit_document', action: () => this.change('reviseQuotation') })\n if (this.quotation) actions.push({ title: i18next.t('button.quotation-print'), icon: 'print', action: () => this.print() })\n return {\n title: this.quotation ? `${i18next.t('title.quotation')} ${this.quotation.number} · v${this.quotation.version}` : i18next.t('title.quotation-new'),\n ...(this.quotation ? { description: quotationStatusWord(status) } : {}),\n frame: 'document',\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.quotation = null\n this.form = blank()\n this.configure()\n this.updateContext()\n return\n }\n if (id !== this.quotation?.id) await this.load(id)\n }\n\n render() {\n const attached = this.quotation ? quotationSection() : undefined\n const editable = this.editable && !this.busy\n return html`<ox-page-state .loading=${this.loading} .error=${this.error} @retry=${() => this.quotation && this.load(this.quotation.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(\n this.form,\n editable,\n patch => (this.form = { ...this.form, ...patch }),\n html`<label\n >${i18next.t('field.quotation-valid-until')}\n <input type=\"date\" .value=${this.form.validUntil ?? ''} ?disabled=${!editable} @input=${(e: any) => (this.form = { ...this.form, validUntil: e.target.value })}\n /></label>`\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 mode=\"GRID\" .config=${this.gristConfig} .fetchHandler=${() => ({ total: this.form.items.length, records: this.form.items })}></ox-grist>\n </section>\n ${this.quotation\n ? html`<section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${i18next.t('text.invoice-section-totals')}</h3></header>\n ${renderDocumentTotals(this.quotation)}\n </section>`\n : nothing}\n ${this.quotation?.status === 'SENT' ? this.renderDecline() : nothing}\n ${this.quotation?.outcomeReason\n ? html`<section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${i18next.t('field.quotation-outcome-reason')}</h3></header>\n <p>${this.quotation.outcomeReason}</p>\n </section>`\n : nothing}\n ${attached && this.quotation\n ? html`<section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${attached.heading()}</h3></header>\n ${attached.render(this.quotation as any)}\n </section>`\n : nothing}\n </div>\n </ox-page-state>`\n }\n\n private renderDecline() {\n return html`<section class=\"page-section\">\n <header class=\"page-section-header\">\n <h3>${i18next.t('text.quotation-section-decline')}</h3>\n <div class=\"page-section-actions\">\n <button ?disabled=${this.busy || !this.reason.trim()} @click=${() => this.change('rejectQuotation', this.reason.trim())}>${i18next.t('button.quotation-reject')}</button>\n </div>\n </header>\n <div class=\"form\">\n <label class=\"wide\"\n >${i18next.t('field.quotation-outcome-reason')}\n <input .value=${this.reason} ?disabled=${this.busy} @input=${(e: any) => (this.reason = e.target.value)}\n /></label>\n </div>\n </section>`\n }\n\n private configure() {\n this.gristConfig = documentLinesConfig({ editable: this.editable, 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!) { quotation(id: $id) { ${FIELDS} } }`), variables: { id }, fetchPolicy: 'no-cache' })\n if (response.errors?.length) throw response\n if (!response.data.quotation) throw new Error(i18next.t('text.quotation-not-found'))\n this.show(response.data.quotation)\n } catch (error) {\n this.error = error\n } finally {\n this.loading = false\n this.updateContext()\n }\n }\n\n private show(quotation: DocumentValue) {\n this.quotation = quotation\n this.form = { ...quotation, items: quotation.items.map((item: any) => ({ ...item })) }\n this.reason = ''\n this.configure()\n this.grist?.fetch()\n }\n\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.items = linesOf(this.grist).map(({ receivedTaxAmount, ...line }: any) => line)\n return input\n }\n\n private async save(): Promise<DocumentValue | undefined> {\n const id = this.quotation?.id\n const saved = await this.run(async () => {\n const response = await client.mutate({\n mutation: gql(\n id\n ? `mutation ($id: String!, $quotation: NewQuotation!) { quotation: updateQuotation(id: $id, quotation: $quotation) { ${FIELDS} } }`\n : `mutation ($quotation: NewQuotation!) { quotation: createQuotation(quotation: $quotation) { ${FIELDS} } }`\n ),\n variables: { ...(id ? { id } : {}), quotation: this.input() }\n })\n if (response.errors?.length) throw response\n return response.data.quotation as DocumentValue\n })\n if (!saved) return undefined\n this.show(saved)\n this.updateContext()\n if (!id) navigate(`quotation-editor?id=${saved.id}`)\n return saved\n }\n\n /** Save what is on screen, then send it — its amounts are fixed from here on. */\n private async send() {\n const saved = await this.save()\n if (saved) await this.change('sendQuotation')\n }\n\n private async change(mutation: string, reason?: string) {\n const changed = await this.run(async () => {\n const response = await client.mutate({\n mutation: gql(\n reason === undefined\n ? `mutation ($id: String!) { quotation: ${mutation}(id: $id) { ${FIELDS} } }`\n : `mutation ($id: String!, $reason: String!) { quotation: ${mutation}(id: $id, reason: $reason) { ${FIELDS} } }`\n ),\n variables: { id: this.quotation!.id, ...(reason === undefined ? {} : { reason }) }\n })\n if (response.errors?.length) throw response\n return response.data.quotation as DocumentValue\n })\n if (!changed) return\n if (changed.id !== this.quotation?.id) navigate(`quotation-editor?id=${changed.id}`)\n this.show(changed)\n this.updateContext()\n }\n\n private print() {\n const quotation = this.quotation!\n const lng = quotation.language === 'en' ? 'en' : 'ko'\n printDocument(\n documentHtml(quotation, {\n title: i18next.t('title.quotation-print', { lng }),\n terms: [\n { label: i18next.t('field.quotation-version', { lng }), value: `v${quotation.version}` },\n { label: i18next.t('field.quotation-valid-until', { lng }), value: quotation.validUntil }\n ]\n })\n )\n }\n}\n\nfunction blank(): DocumentValue {\n return { number: '', direction: 'SALES', currency: 'KRW', language: 'ko', supplierName: '', buyerName: '', issueDate: today(), validUntil: '', items: [] }\n}\n"]}
@@ -0,0 +1,36 @@
1
+ import '@operato/data-grist/ox-grist.js';
2
+ import { FetchOption } from '@operato/data-grist';
3
+ import { PageView } from '@operato/shell';
4
+ declare const QuotationList_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
5
+ /** 견적 — every version of every quotation; the latest of a number is the one still in play. */
6
+ export declare class QuotationList extends QuotationList_base {
7
+ static styles: import("lit").CSSResult[];
8
+ gristConfig: any;
9
+ private grist;
10
+ get context(): {
11
+ title: string;
12
+ search: {
13
+ handler: (search: string) => void;
14
+ value: string;
15
+ };
16
+ actions: {
17
+ title: string;
18
+ icon: string;
19
+ emphasis: {
20
+ raised: boolean;
21
+ };
22
+ action: () => void;
23
+ }[];
24
+ exportable: {
25
+ name: string;
26
+ data: () => any[];
27
+ };
28
+ };
29
+ render(): import("lit-html").TemplateResult<1>;
30
+ pageInitialized(): Promise<void>;
31
+ fetchHandler({ page, limit, sortings, filters, search }: FetchOption): Promise<{
32
+ total: any;
33
+ records: any;
34
+ }>;
35
+ }
36
+ export {};
@@ -0,0 +1,113 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@operato/data-grist/ox-grist.js';
3
+ import gql from 'graphql-tag';
4
+ import { html } from 'lit';
5
+ import { customElement, query, state } from 'lit/decorators.js';
6
+ import { DataGrist } from '@operato/data-grist';
7
+ import { client } from '@operato/graphql';
8
+ import { i18next, localize } from '@operato/i18n';
9
+ import { navigate, PageView } from '@operato/shell';
10
+ import { CommonGristStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
11
+ import { isMobileDevice } from '@operato/utils';
12
+ import { counterpartOf, documentAmount } from '@things-factory/invoice/dist-client';
13
+ import { quotationStatusWord } from '../quotation-words';
14
+ /** 견적 — every version of every quotation; the latest of a number is the one still in play. */
15
+ let QuotationList = class QuotationList extends localize(i18next)(PageView) {
16
+ static { this.styles = [WorkSurfacePageStyles, CommonGristStyles, ScrollbarStyles]; }
17
+ get context() {
18
+ return {
19
+ title: i18next.t('title.quotation-list'),
20
+ search: {
21
+ handler: (search) => {
22
+ this.grist.searchText = search;
23
+ },
24
+ value: this.grist?.searchText || ''
25
+ },
26
+ actions: [{ title: i18next.t('button.quotation-new'), icon: 'add', emphasis: { raised: true }, action: () => navigate('quotation-editor') }],
27
+ exportable: { name: i18next.t('title.quotation-list'), data: () => this.grist.exportRecords() }
28
+ };
29
+ }
30
+ render() {
31
+ return html `<ox-grist
32
+ class="page-fill"
33
+ search-mode="term"
34
+ .mode=${isMobileDevice() ? 'CARD' : 'GRID'}
35
+ .config=${this.gristConfig}
36
+ .fetchHandler=${this.fetchHandler.bind(this)}
37
+ ></ox-grist>`;
38
+ }
39
+ async pageInitialized() {
40
+ const open = (record) => record?.id && navigate(`quotation-editor?id=${record.id}`);
41
+ const readonly = (type, name, header, width, extra = {}) => ({
42
+ type,
43
+ name,
44
+ header,
45
+ width,
46
+ sortable: true,
47
+ ...extra,
48
+ record: { editable: false, ...extra.record }
49
+ });
50
+ this.gristConfig = {
51
+ rows: { appendable: false, selectable: false },
52
+ pagination: { limit: 50, pages: [50, 100, 500] },
53
+ emptyNote: { title: i18next.t('text.quotation-empty'), description: i18next.t('text.quotation-empty-description') },
54
+ list: { fields: ['counterpart', 'number'], details: ['status', 'validUntil', 'totalAmount'] },
55
+ columns: [
56
+ { type: 'gutter', gutterName: 'sequence' },
57
+ { type: 'gutter', gutterName: 'button', icon: 'edit_note', handlers: { click: (_c, _d, _col, record) => open(record) } },
58
+ readonly('string', 'counterpart', i18next.t('field.invoice-counterpart'), 200, { sortable: false, record: { renderer: (_v, _c, record) => counterpartOf(record) } }),
59
+ readonly('string', 'number', i18next.t('field.invoice-number'), 140),
60
+ readonly('integer', 'version', i18next.t('field.quotation-version'), 60),
61
+ readonly('string', 'status', i18next.t('field.invoice-status'), 90, { record: { renderer: (value) => quotationStatusWord(value) } }),
62
+ readonly('string', 'issueDate', i18next.t('field.invoice-issue-date'), 110),
63
+ readonly('string', 'validUntil', i18next.t('field.quotation-valid-until'), 110),
64
+ readonly('float', 'totalAmount', i18next.t('field.invoice-total-amount'), 160, {
65
+ record: { align: 'right', renderer: (value, _c, record) => documentAmount(value, record?.currency || 'KRW') }
66
+ })
67
+ ],
68
+ sorters: [{ name: 'issueDate', desc: true }]
69
+ };
70
+ }
71
+ async fetchHandler({ page = 1, limit = 50, sortings = [], filters = [], search }) {
72
+ const response = await client.query({
73
+ query: gql `
74
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $search: String) {
75
+ responses: quotations(filters: $filters, pagination: $pagination, sortings: $sortings, search: $search) {
76
+ items {
77
+ id
78
+ number
79
+ version
80
+ status
81
+ direction
82
+ currency
83
+ supplierName
84
+ buyerName
85
+ issueDate
86
+ validUntil
87
+ totalAmount
88
+ }
89
+ total
90
+ }
91
+ }
92
+ `,
93
+ variables: { filters, pagination: { page, limit }, sortings, search: search?.trim() || undefined },
94
+ fetchPolicy: 'network-only'
95
+ });
96
+ if (response.errors?.length)
97
+ throw response;
98
+ return { total: response.data.responses.total, records: response.data.responses.items };
99
+ }
100
+ };
101
+ __decorate([
102
+ state(),
103
+ __metadata("design:type", Object)
104
+ ], QuotationList.prototype, "gristConfig", void 0);
105
+ __decorate([
106
+ query('ox-grist'),
107
+ __metadata("design:type", DataGrist)
108
+ ], QuotationList.prototype, "grist", void 0);
109
+ QuotationList = __decorate([
110
+ customElement('quotation-list')
111
+ ], QuotationList);
112
+ export { QuotationList };
113
+ //# sourceMappingURL=quotation-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quotation-list.js","sourceRoot":"","sources":["../../client/pages/quotation-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 { navigate, PageView } from '@operato/shell'\nimport { CommonGristStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\nimport { counterpartOf, documentAmount } from '@things-factory/invoice/dist-client'\n\nimport { quotationStatusWord } from '../quotation-words'\n\n/** 견적 — every version of every quotation; the latest of a number is the one still in play. */\n@customElement('quotation-list')\nexport class QuotationList 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.quotation-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.quotation-new'), icon: 'add', emphasis: { raised: true }, action: () => navigate('quotation-editor') }],\n exportable: { name: i18next.t('title.quotation-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 open = (record: any) => record?.id && navigate(`quotation-editor?id=${record.id}`)\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.quotation-empty'), description: i18next.t('text.quotation-empty-description') },\n list: { fields: ['counterpart', 'number'], details: ['status', 'validUntil', 'totalAmount'] },\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n { type: 'gutter', gutterName: 'button', icon: 'edit_note', handlers: { click: (_c: any, _d: any, _col: any, record: any) => open(record) } },\n readonly('string', 'counterpart', i18next.t('field.invoice-counterpart'), 200, { sortable: false, record: { renderer: (_v: any, _c: any, record: any) => counterpartOf(record) } }),\n readonly('string', 'number', i18next.t('field.invoice-number'), 140),\n readonly('integer', 'version', i18next.t('field.quotation-version'), 60),\n readonly('string', 'status', i18next.t('field.invoice-status'), 90, { record: { renderer: (value: string) => quotationStatusWord(value) } }),\n readonly('string', 'issueDate', i18next.t('field.invoice-issue-date'), 110),\n readonly('string', 'validUntil', i18next.t('field.quotation-valid-until'), 110),\n readonly('float', 'totalAmount', i18next.t('field.invoice-total-amount'), 160, {\n record: { align: 'right', renderer: (value: number, _c: 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: quotations(filters: $filters, pagination: $pagination, sortings: $sortings, search: $search) {\n items {\n id\n number\n version\n status\n direction\n currency\n supplierName\n buyerName\n issueDate\n validUntil\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"]}
@@ -0,0 +1,16 @@
1
+ import { type TemplateResult } from 'lit';
2
+ export type QuotationSection = {
3
+ /** The section's heading, already in the reader's words. */
4
+ heading: () => string;
5
+ /** The section's body for one saved quotation; it reads and writes through the application's own API. */
6
+ render: (quotation: {
7
+ id: string;
8
+ number: string;
9
+ version: number;
10
+ status: string;
11
+ currency: string;
12
+ totalAmount: number;
13
+ }) => TemplateResult;
14
+ };
15
+ export declare function configureQuotationSection(one: QuotationSection): void;
16
+ export declare function quotationSection(): QuotationSection | undefined;
@@ -0,0 +1,8 @@
1
+ let section;
2
+ export function configureQuotationSection(one) {
3
+ section = one;
4
+ }
5
+ export function quotationSection() {
6
+ return section;
7
+ }
8
+ //# sourceMappingURL=quotation-attach.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quotation-attach.js","sourceRoot":"","sources":["../client/quotation-attach.ts"],"names":[],"mappings":"AAcA,IAAI,OAAqC,CAAA;AAEzC,MAAM,UAAU,yBAAyB,CAAC,GAAqB;IAC7D,OAAO,GAAG,GAAG,CAAA;AACf,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,OAAO,CAAA;AAChB,CAAC","sourcesContent":["import { type TemplateResult } from 'lit'\n\n/*\n * Where an application attaches its own work to a quotation — Office turns an accepted quotation into a contract\n * (ADR-0120 decisions 2 and 9). The quotation module knows no application words.\n */\n\nexport type QuotationSection = {\n /** The section's heading, already in the reader's words. */\n heading: () => string\n /** The section's body for one saved quotation; it reads and writes through the application's own API. */\n render: (quotation: { id: string; number: string; version: number; status: string; currency: string; totalAmount: number }) => TemplateResult\n}\n\nlet section: QuotationSection | undefined\n\nexport function configureQuotationSection(one: QuotationSection): void {\n section = one\n}\n\nexport function quotationSection(): QuotationSection | undefined {\n return section\n}\n"]}