@things-factory/invoice 10.1.255 → 10.1.257

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 (36) hide show
  1. package/dist-client/document/document-defaults.d.ts +11 -2
  2. package/dist-client/document/document-defaults.js +7 -15
  3. package/dist-client/document/document-defaults.js.map +1 -1
  4. package/dist-client/document/document-party.d.ts +5 -2
  5. package/dist-client/document/document-party.js +21 -21
  6. package/dist-client/document/document-party.js.map +1 -1
  7. package/dist-client/entity360/invoice-360.d.ts +3 -4
  8. package/dist-client/entity360/invoice-360.js +17 -38
  9. package/dist-client/entity360/invoice-360.js.map +1 -1
  10. package/dist-client/index.d.ts +1 -1
  11. package/dist-client/index.js +1 -1
  12. package/dist-client/index.js.map +1 -1
  13. package/dist-client/invoice-files.d.ts +4 -10
  14. package/dist-client/invoice-files.js +19 -58
  15. package/dist-client/invoice-files.js.map +1 -1
  16. package/dist-client/pages/invoice-editor.d.ts +42 -19
  17. package/dist-client/pages/invoice-editor.js +150 -179
  18. package/dist-client/pages/invoice-editor.js.map +1 -1
  19. package/dist-client/tsconfig.tsbuildinfo +1 -1
  20. package/dist-client/viewparts/document-defaults-setting-let.d.ts +7 -2
  21. package/dist-client/viewparts/document-defaults-setting-let.js +30 -35
  22. package/dist-client/viewparts/document-defaults-setting-let.js.map +1 -1
  23. package/dist-server/index.d.ts +1 -0
  24. package/dist-server/index.js +1 -0
  25. package/dist-server/index.js.map +1 -1
  26. package/dist-server/tsconfig.tsbuildinfo +1 -1
  27. package/dist-server/work-doors.d.ts +1 -0
  28. package/dist-server/work-doors.js +11 -0
  29. package/dist-server/work-doors.js.map +1 -0
  30. package/package.json +12 -12
  31. package/translations/en.json +2 -1
  32. package/translations/es.json +2 -1
  33. package/translations/ja.json +2 -1
  34. package/translations/ko.json +2 -1
  35. package/translations/ms.json +2 -1
  36. package/translations/zh.json +2 -1
@@ -11,8 +11,17 @@ export type DocumentDefaults = {
11
11
  paymentDays: number;
12
12
  };
13
13
  export declare const DOCUMENT_DEFAULTS_FIELDS = "supplierName supplierRegistrationNumber supplierAddress bankDetails paymentTerms notes validDays paymentDays";
14
- /** The company's words, or null when this person may not read them or they could not be read - the editor then starts empty. */
15
- export declare function documentDefaults(): Promise<DocumentDefaults | null>;
14
+ /**
15
+ * Whom the company's words are read for - a screen declares DOCUMENT_DEFAULTS with no variables until `hasPrivilege` of
16
+ * this says yes, as a refusal would be shown to someone who never asked for it; an editor then starts empty.
17
+ */
18
+ export declare const DOCUMENT_DEFAULTS_READER: {
19
+ category: string;
20
+ privilege: string;
21
+ domainOwnerGranted: boolean;
22
+ };
23
+ /** The company's words, as a QueryController reads them (ADR-0190). */
24
+ export declare const DOCUMENT_DEFAULTS: import("graphql").DocumentNode;
16
25
  /** A new sales document's head from the company's words - only the fields still blank, so a person's typing stays. */
17
26
  export declare function headFromDefaults(form: Record<string, any>, defaults: DocumentDefaults | null): Record<string, any>;
18
27
  /** Our side of a sales document, as a person writes it once - our name, number and address, the account, the terms. */
@@ -1,20 +1,12 @@
1
1
  import gql from 'graphql-tag';
2
- import { client } from '@operato/graphql';
3
- import { hasPrivilege } from '@things-factory/auth-base/dist-client';
4
2
  export const DOCUMENT_DEFAULTS_FIELDS = 'supplierName supplierRegistrationNumber supplierAddress bankDetails paymentTerms notes validDays paymentDays';
5
- /** The company's words, or null when this person may not read them or they could not be read - the editor then starts empty. */
6
- export async function documentDefaults() {
7
- /* Asked only of whoever may read them - a refusal would be shown to someone who never asked for it. */
8
- if (!(await hasPrivilege({ category: 'invoice-published', privilege: 'query', domainOwnerGranted: true })))
9
- return null;
10
- try {
11
- const response = await client.query({ query: gql(`query { documentDefaults { ${DOCUMENT_DEFAULTS_FIELDS} } }`), fetchPolicy: 'no-cache', errorPolicy: 'all' });
12
- return response.data?.documentDefaults ?? null;
13
- }
14
- catch {
15
- return null;
16
- }
17
- }
3
+ /**
4
+ * Whom the company's words are read for - a screen declares DOCUMENT_DEFAULTS with no variables until `hasPrivilege` of
5
+ * this says yes, as a refusal would be shown to someone who never asked for it; an editor then starts empty.
6
+ */
7
+ export const DOCUMENT_DEFAULTS_READER = { category: 'invoice-published', privilege: 'query', domainOwnerGranted: true };
8
+ /** The company's words, as a QueryController reads them (ADR-0190). */
9
+ export const DOCUMENT_DEFAULTS = gql(`query { documentDefaults { ${DOCUMENT_DEFAULTS_FIELDS} } }`);
18
10
  /** A new sales document's head from the company's words - only the fields still blank, so a person's typing stays. */
19
11
  export function headFromDefaults(form, defaults) {
20
12
  if (!defaults || form.direction === 'PURCHASE')
@@ -1 +1 @@
1
- {"version":3,"file":"document-defaults.js","sourceRoot":"","sources":["../../client/document/document-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,aAAa,CAAA;AAE7B,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAA;AAepE,MAAM,CAAC,MAAM,wBAAwB,GAAG,8GAA8G,CAAA;AAEtJ,gIAAgI;AAChI,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,uGAAuG;IACvG,IAAI,CAAC,CAAC,MAAM,YAAY,CAAC,EAAE,QAAQ,EAAE,mBAAmB,EAAE,SAAS,EAAE,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IACvH,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,8BAA8B,wBAAwB,MAAM,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAA;QAC9J,OAAO,QAAQ,CAAC,IAAI,EAAE,gBAAgB,IAAI,IAAI,CAAA;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,sHAAsH;AACtH,MAAM,UAAU,gBAAgB,CAAC,IAAyB,EAAE,QAAiC;IAC3F,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,SAAS,KAAK,UAAU;QAAE,OAAO,EAAE,CAAA;IACzD,MAAM,KAAK,GAA2B;QACpC,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,0BAA0B,EAAE,QAAQ,CAAC,0BAA0B;QAC/D,eAAe,EAAE,QAAQ,CAAC,eAAe;QACzC,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,EAAE;QAC5C,KAAK,EAAE,QAAQ,CAAC,KAAK;KACtB,CAAA;IACD,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;AACrH,CAAC;AAED,uHAAuH;AACvH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,cAAc,EAAE,iBAAiB,EAAE,4BAA4B,EAAE,aAAa,EAAE,cAAc,CAAC,CAAA;AAE/H;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAyB,EAAE,IAA4C;IAClG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,KAAK,UAAU;QAAE,OAAO,EAAE,CAAA;IACrD,OAAO,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;AACrI,CAAC","sourcesContent":["import gql from 'graphql-tag'\n\nimport { client } from '@operato/graphql'\nimport { hasPrivilege } from '@things-factory/auth-base/dist-client'\n\n/** The company's own words every new quotation and invoice starts with (ADR-0170) - as the Settings screen keeps them. */\nexport type DocumentDefaults = {\n supplierName: string\n supplierRegistrationNumber: string\n supplierAddress: string\n bankDetails: string\n paymentTerms: string[]\n notes: string\n validDays: number\n /** Days an invoice is due after its issue day. */\n paymentDays: number\n}\n\nexport const DOCUMENT_DEFAULTS_FIELDS = 'supplierName supplierRegistrationNumber supplierAddress bankDetails paymentTerms notes validDays paymentDays'\n\n/** The company's words, or null when this person may not read them or they could not be read - the editor then starts empty. */\nexport async function documentDefaults(): Promise<DocumentDefaults | null> {\n /* Asked only of whoever may read them - a refusal would be shown to someone who never asked for it. */\n if (!(await hasPrivilege({ category: 'invoice-published', privilege: 'query', domainOwnerGranted: true }))) return null\n try {\n const response = await client.query({ query: gql(`query { documentDefaults { ${DOCUMENT_DEFAULTS_FIELDS} } }`), fetchPolicy: 'no-cache', errorPolicy: 'all' })\n return response.data?.documentDefaults ?? null\n } catch {\n return null\n }\n}\n\n/** A new sales document's head from the company's words - only the fields still blank, so a person's typing stays. */\nexport function headFromDefaults(form: Record<string, any>, defaults: DocumentDefaults | null): Record<string, any> {\n if (!defaults || form.direction === 'PURCHASE') return {}\n const words: Record<string, string> = {\n supplierName: defaults.supplierName,\n supplierRegistrationNumber: defaults.supplierRegistrationNumber,\n supplierAddress: defaults.supplierAddress,\n bankDetails: defaults.bankDetails,\n paymentTerms: defaults.paymentTerms[0] ?? '',\n notes: defaults.notes\n }\n return Object.fromEntries(Object.entries(words).filter(([key, value]) => value && !String(form[key] ?? '').trim()))\n}\n\n/** Our side of a sales document, as a person writes it once - our name, number and address, the account, the terms. */\nexport const OUR_SIDE_FIELDS = ['supplierName', 'supplierAddress', 'supplierRegistrationNumber', 'bankDetails', 'paymentTerms']\n\n/**\n * What `last` - the last sales document of the same kind - wrote of our side, for those fields still blank on `form`;\n * nothing for a purchase, whose supplier is the other party.\n */\nexport function oursFromLast(form: Record<string, any>, last: Record<string, any> | null | undefined): Record<string, any> {\n if (!last || form.direction === 'PURCHASE') return {}\n return Object.fromEntries(OUR_SIDE_FIELDS.filter(key => last[key] && !String(form[key] ?? '').trim()).map(key => [key, last[key]]))\n}\n"]}
1
+ {"version":3,"file":"document-defaults.js","sourceRoot":"","sources":["../../client/document/document-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,aAAa,CAAA;AAe7B,MAAM,CAAC,MAAM,wBAAwB,GAAG,8GAA8G,CAAA;AAEtJ;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,QAAQ,EAAE,mBAAmB,EAAE,SAAS,EAAE,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAA;AAEvH,uEAAuE;AACvE,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC,8BAA8B,wBAAwB,MAAM,CAAC,CAAA;AAElG,sHAAsH;AACtH,MAAM,UAAU,gBAAgB,CAAC,IAAyB,EAAE,QAAiC;IAC3F,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,SAAS,KAAK,UAAU;QAAE,OAAO,EAAE,CAAA;IACzD,MAAM,KAAK,GAA2B;QACpC,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,0BAA0B,EAAE,QAAQ,CAAC,0BAA0B;QAC/D,eAAe,EAAE,QAAQ,CAAC,eAAe;QACzC,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,EAAE;QAC5C,KAAK,EAAE,QAAQ,CAAC,KAAK;KACtB,CAAA;IACD,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;AACrH,CAAC;AAED,uHAAuH;AACvH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,cAAc,EAAE,iBAAiB,EAAE,4BAA4B,EAAE,aAAa,EAAE,cAAc,CAAC,CAAA;AAE/H;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAyB,EAAE,IAA4C;IAClG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,KAAK,UAAU;QAAE,OAAO,EAAE,CAAA;IACrD,OAAO,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;AACrI,CAAC","sourcesContent":["import gql from 'graphql-tag'\n\n/** The company's own words every new quotation and invoice starts with (ADR-0170) - as the Settings screen keeps them. */\nexport type DocumentDefaults = {\n supplierName: string\n supplierRegistrationNumber: string\n supplierAddress: string\n bankDetails: string\n paymentTerms: string[]\n notes: string\n validDays: number\n /** Days an invoice is due after its issue day. */\n paymentDays: number\n}\n\nexport const DOCUMENT_DEFAULTS_FIELDS = 'supplierName supplierRegistrationNumber supplierAddress bankDetails paymentTerms notes validDays paymentDays'\n\n/**\n * Whom the company's words are read for - a screen declares DOCUMENT_DEFAULTS with no variables until `hasPrivilege` of\n * this says yes, as a refusal would be shown to someone who never asked for it; an editor then starts empty.\n */\nexport const DOCUMENT_DEFAULTS_READER = { category: 'invoice-published', privilege: 'query', domainOwnerGranted: true }\n\n/** The company's words, as a QueryController reads them (ADR-0190). */\nexport const DOCUMENT_DEFAULTS = gql(`query { documentDefaults { ${DOCUMENT_DEFAULTS_FIELDS} } }`)\n\n/** A new sales document's head from the company's words - only the fields still blank, so a person's typing stays. */\nexport function headFromDefaults(form: Record<string, any>, defaults: DocumentDefaults | null): Record<string, any> {\n if (!defaults || form.direction === 'PURCHASE') return {}\n const words: Record<string, string> = {\n supplierName: defaults.supplierName,\n supplierRegistrationNumber: defaults.supplierRegistrationNumber,\n supplierAddress: defaults.supplierAddress,\n bankDetails: defaults.bankDetails,\n paymentTerms: defaults.paymentTerms[0] ?? '',\n notes: defaults.notes\n }\n return Object.fromEntries(Object.entries(words).filter(([key, value]) => value && !String(form[key] ?? '').trim()))\n}\n\n/** Our side of a sales document, as a person writes it once - our name, number and address, the account, the terms. */\nexport const OUR_SIDE_FIELDS = ['supplierName', 'supplierAddress', 'supplierRegistrationNumber', 'bankDetails', 'paymentTerms']\n\n/**\n * What `last` - the last sales document of the same kind - wrote of our side, for those fields still blank on `form`;\n * nothing for a purchase, whose supplier is the other party.\n */\nexport function oursFromLast(form: Record<string, any>, last: Record<string, any> | null | undefined): Record<string, any> {\n if (!last || form.direction === 'PURCHASE') return {}\n return Object.fromEntries(OUR_SIDE_FIELDS.filter(key => last[key] && !String(form[key] ?? '').trim()).map(key => [key, last[key]]))\n}\n"]}
@@ -24,10 +24,13 @@ export declare class DocumentPartySelect extends DocumentPartySelect_base {
24
24
  party: DocumentParty | null;
25
25
  disabled: boolean;
26
26
  private search;
27
- private found;
27
+ /** The words the list is found by - undefined while no list is open. */
28
+ private finding?;
28
29
  private active;
29
30
  private timer?;
30
- private asked;
31
+ private choices;
32
+ /** The list under the field: what was found, or null while it is closed or not read. */
33
+ private get found();
31
34
  render(): import("lit-html").TemplateResult<1>;
32
35
  private findSoon;
33
36
  private find;
@@ -3,7 +3,7 @@ import '@material/web/icon/icon.js';
3
3
  import gql from 'graphql-tag';
4
4
  import { css, html, LitElement, nothing } from 'lit';
5
5
  import { customElement, property, state } from 'lit/decorators.js';
6
- import { client } from '@operato/graphql';
6
+ import { client, QueryController } from '@operato/graphql';
7
7
  import { i18next, localize } from '@operato/i18n';
8
8
  import { ButtonStyles } from '@operato/styles';
9
9
  import { partyNamed } from '@things-factory/invoice/dist-shared/document-start.js';
@@ -45,9 +45,13 @@ let DocumentPartySelect = class DocumentPartySelect extends localize(i18next)(Li
45
45
  this.party = null;
46
46
  this.disabled = false;
47
47
  this.search = '';
48
- this.found = null;
49
48
  this.active = 0;
50
- this.asked = 0;
49
+ /* The choices for the words found by - only the answer to the last thing typed is shown, and the list found before
50
+ stays while the next is read (ADR-0190). */
51
+ this.choices = new QueryController(this, CHOICES, {
52
+ keepPrevious: true,
53
+ variables: () => this.finding === undefined || this.disabled ? undefined : { search: this.finding.trim() || undefined, pagination: { page: 1, limit: 30 } }
54
+ });
51
55
  }
52
56
  static { this.styles = [
53
57
  ButtonStyles,
@@ -119,6 +123,12 @@ let DocumentPartySelect = class DocumentPartySelect extends localize(i18next)(Li
119
123
  }
120
124
  `
121
125
  ]; }
126
+ /** The list under the field: what was found, or null while it is closed or not read. */
127
+ get found() {
128
+ if (this.finding === undefined || !this.choices.data)
129
+ return null;
130
+ return this.choices.data.counterparties?.items ?? [];
131
+ }
122
132
  render() {
123
133
  return html `
124
134
  <div class="field">
@@ -130,7 +140,7 @@ let DocumentPartySelect = class DocumentPartySelect extends localize(i18next)(Li
130
140
  @focus=${() => this.find()}
131
141
  @input=${(e) => ((this.search = e.target.value), this.findSoon())}
132
142
  @keydown=${(e) => this.key(e)}
133
- @blur=${() => setTimeout(() => (this.found = null), 150)}
143
+ @blur=${() => setTimeout(() => (this.finding = undefined), 150)}
134
144
  />
135
145
  ${this.party && !this.disabled
136
146
  ? html `<button quiet icon-only title=${i18next.t('button.invoice-counterparty-clear')} aria-label=${i18next.t('button.invoice-counterparty-clear')} @click=${() => this.choose(null)}>
@@ -153,21 +163,11 @@ let DocumentPartySelect = class DocumentPartySelect extends localize(i18next)(Li
153
163
  clearTimeout(this.timer);
154
164
  this.timer = setTimeout(() => this.find(), 250);
155
165
  }
156
- async find() {
166
+ find() {
157
167
  if (this.disabled)
158
168
  return;
159
- const asked = ++this.asked;
160
- try {
161
- const response = await client.query({ query: CHOICES, variables: { search: this.search.trim() || undefined, pagination: { page: 1, limit: 30 } }, fetchPolicy: 'no-cache' });
162
- /* Only the answer to the last thing typed is shown. */
163
- if (asked !== this.asked)
164
- return;
165
- this.found = response.data?.counterparties?.items ?? [];
166
- this.active = 0;
167
- }
168
- catch {
169
- this.found = null;
170
- }
169
+ this.finding = this.search;
170
+ this.active = 0;
171
171
  }
172
172
  key(e) {
173
173
  if (!this.found?.length || e.isComposing)
@@ -179,14 +179,14 @@ let DocumentPartySelect = class DocumentPartySelect extends localize(i18next)(Li
179
179
  else if (e.key === 'Enter')
180
180
  this.choose(this.found[this.active]);
181
181
  else if (e.key === 'Escape')
182
- this.found = null;
182
+ this.finding = undefined;
183
183
  else
184
184
  return;
185
185
  e.preventDefault();
186
186
  }
187
187
  choose(party) {
188
188
  this.search = '';
189
- this.found = null;
189
+ this.finding = undefined;
190
190
  this.dispatchEvent(new CustomEvent('party', { detail: party, bubbles: true, composed: true }));
191
191
  }
192
192
  };
@@ -204,8 +204,8 @@ __decorate([
204
204
  ], DocumentPartySelect.prototype, "search", void 0);
205
205
  __decorate([
206
206
  state(),
207
- __metadata("design:type", Array)
208
- ], DocumentPartySelect.prototype, "found", void 0);
207
+ __metadata("design:type", String)
208
+ ], DocumentPartySelect.prototype, "finding", void 0);
209
209
  __decorate([
210
210
  state(),
211
211
  __metadata("design:type", Object)
@@ -1 +1 @@
1
- {"version":3,"file":"document-party.js","sourceRoot":"","sources":["../../client/document/document-party.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { ButtonStyles } from '@operato/styles'\nimport { partyNamed } from '@things-factory/invoice/dist-shared/document-start.js'\n\n/** A counterparty as a document's party - which one, its name and registration number (`counterpartyChoices`). */\nexport type DocumentParty = { id: string; name: string; businessNumber?: string | null }\n\nconst CHOICES = gql`\n query ($search: String, $pagination: Pagination) {\n counterparties: counterpartyChoices(search: $search, pagination: $pagination) {\n items { id name businessNumber }\n }\n }\n`\n\n/**\n * The counterparty a party's name is - the one choice of that name, case and spaces aside (ADR-0170 decision 11); null\n * when none or more than one is, or the choices cannot be read. Searched by the name's longest word, so 「(주) 하티오랩」\n * finds 「(주)하티오랩」.\n */\nexport async function partyOfName(name: unknown): Promise<DocumentParty | null> {\n const word = String(name ?? '')\n .split(/\\s+/)\n .reduce((longest, one) => (one.length > longest.length ? one : longest), '')\n if (!word) return null\n try {\n const response = await client.query({ query: CHOICES, variables: { search: word, pagination: { page: 1, limit: 100 } }, fetchPolicy: 'no-cache' })\n return partyNamed(name, (response.data?.counterparties?.items ?? []) as DocumentParty[]) ?? null\n } catch {\n return null\n }\n}\n\n/**\n * Picking a counterparty for a document - one field that finds as it is typed and lists what it found under it; a\n * click takes one and fires `party` with it (or with null when cleared). Every editor of a commercial document picks\n * its party here - invoice and quotation (ADR-0120 decision 1). Reads `counterpartyChoices`, which every seat may.\n */\n@customElement('document-party-select')\nexport class DocumentPartySelect extends localize(i18next)(LitElement) {\n static styles = [\n ButtonStyles,\n css`\n :host {\n position: relative;\n display: block;\n }\n .field {\n display: flex;\n gap: var(--spacing-small, 4px);\n align-items: center;\n }\n input {\n flex: 1;\n min-width: 0;\n box-sizing: border-box;\n height: var(--form-element-height-medium, 32px);\n padding: 0 var(--spacing-medium, 8px);\n border: var(--input-field-border, 1px solid var(--md-sys-color-outline));\n border-radius: var(--input-field-border-radius, var(--md-sys-shape-corner-small, 4px));\n background: var(--input-field-background, var(--md-sys-color-surface-container-highest));\n font: inherit;\n font-size: var(--ui-t-body, 13px);\n color: var(--ui-ink, var(--md-sys-color-on-surface));\n }\n input:focus-visible {\n outline: none;\n border-color: var(--md-sys-color-primary);\n }\n ul {\n position: absolute;\n z-index: 10;\n left: 0;\n right: 0;\n top: calc(100% + 2px);\n max-height: 260px;\n overflow-y: auto;\n margin: 0;\n padding: var(--spacing-small, 4px) 0;\n list-style: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: var(--ui-r, 10px);\n background: var(--md-sys-color-surface-container-lowest);\n box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);\n }\n li {\n display: flex;\n justify-content: space-between;\n gap: var(--spacing-large, 12px);\n padding: 6px var(--spacing-large, 12px);\n cursor: pointer;\n font-size: var(--ui-t-body, 13px);\n color: var(--ui-ink, var(--md-sys-color-on-surface));\n }\n li:hover,\n li[active] {\n background: var(--md-sys-color-surface-container-high);\n }\n li small {\n white-space: nowrap;\n }\n li small,\n li.none {\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n li.none {\n cursor: default;\n }\n `\n ]\n\n /** The party chosen, shown as the field's placeholder until something is typed. */\n @property({ attribute: false }) party: DocumentParty | null = null\n @property({ type: Boolean }) disabled = false\n\n @state() private search = ''\n @state() private found: DocumentParty[] | null = null\n @state() private active = 0\n\n private timer?: ReturnType<typeof setTimeout>\n private asked = 0\n\n render() {\n return html`\n <div class=\"field\">\n <input\n .value=${this.search}\n placeholder=${this.party?.name ?? i18next.t('text.invoice-counterparty-search')}\n aria-label=${i18next.t('field.counterparty')}\n ?disabled=${this.disabled}\n @focus=${() => this.find()}\n @input=${(e: any) => ((this.search = e.target.value), this.findSoon())}\n @keydown=${(e: KeyboardEvent) => this.key(e)}\n @blur=${() => setTimeout(() => (this.found = null), 150)}\n />\n ${this.party && !this.disabled\n ? html`<button quiet icon-only title=${i18next.t('button.invoice-counterparty-clear')} aria-label=${i18next.t('button.invoice-counterparty-clear')} @click=${() => this.choose(null)}>\n <md-icon>close</md-icon>\n </button>`\n : nothing}\n </div>\n ${this.found\n ? html`<ul role=\"listbox\">\n ${this.found.length\n ? this.found.map(\n (one, index) =>\n html`<li role=\"option\" ?active=${index === this.active} @mousedown=${(e: Event) => (e.preventDefault(), this.choose(one))}>\n <span>${one.name}</span>${one.businessNumber ? html`<small>${one.businessNumber}</small>` : nothing}\n </li>`\n )\n : html`<li class=\"none\">${i18next.t('text.invoice-counterparty-none')}</li>`}\n </ul>`\n : nothing}\n `\n }\n\n private findSoon() {\n clearTimeout(this.timer)\n this.timer = setTimeout(() => this.find(), 250)\n }\n\n private async find() {\n if (this.disabled) return\n const asked = ++this.asked\n try {\n const response = await client.query({ query: CHOICES, variables: { search: this.search.trim() || undefined, pagination: { page: 1, limit: 30 } }, fetchPolicy: 'no-cache' })\n /* Only the answer to the last thing typed is shown. */\n if (asked !== this.asked) return\n this.found = response.data?.counterparties?.items ?? []\n this.active = 0\n } catch {\n this.found = null\n }\n }\n\n private key(e: KeyboardEvent) {\n if (!this.found?.length || e.isComposing) return\n if (e.key === 'ArrowDown') this.active = Math.min(this.active + 1, this.found.length - 1)\n else if (e.key === 'ArrowUp') this.active = Math.max(this.active - 1, 0)\n else if (e.key === 'Enter') this.choose(this.found[this.active])\n else if (e.key === 'Escape') this.found = null\n else return\n e.preventDefault()\n }\n\n private choose(party: DocumentParty | null) {\n this.search = ''\n this.found = null\n this.dispatchEvent(new CustomEvent('party', { detail: party, bubbles: true, composed: true }))\n }\n}\n"]}
1
+ {"version":3,"file":"document-party.js","sourceRoot":"","sources":["../../client/document/document-party.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { client, QueryController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { ButtonStyles } from '@operato/styles'\nimport { partyNamed } from '@things-factory/invoice/dist-shared/document-start.js'\n\n/** A counterparty as a document's party - which one, its name and registration number (`counterpartyChoices`). */\nexport type DocumentParty = { id: string; name: string; businessNumber?: string | null }\n\nconst CHOICES = gql`\n query ($search: String, $pagination: Pagination) {\n counterparties: counterpartyChoices(search: $search, pagination: $pagination) {\n items { id name businessNumber }\n }\n }\n`\n\n/**\n * The counterparty a party's name is - the one choice of that name, case and spaces aside (ADR-0170 decision 11); null\n * when none or more than one is, or the choices cannot be read. Searched by the name's longest word, so 「(주) 하티오랩」\n * finds 「(주)하티오랩」.\n */\nexport async function partyOfName(name: unknown): Promise<DocumentParty | null> {\n const word = String(name ?? '')\n .split(/\\s+/)\n .reduce((longest, one) => (one.length > longest.length ? one : longest), '')\n if (!word) return null\n try {\n const response = await client.query({ query: CHOICES, variables: { search: word, pagination: { page: 1, limit: 100 } }, fetchPolicy: 'no-cache' })\n return partyNamed(name, (response.data?.counterparties?.items ?? []) as DocumentParty[]) ?? null\n } catch {\n return null\n }\n}\n\n/**\n * Picking a counterparty for a document - one field that finds as it is typed and lists what it found under it; a\n * click takes one and fires `party` with it (or with null when cleared). Every editor of a commercial document picks\n * its party here - invoice and quotation (ADR-0120 decision 1). Reads `counterpartyChoices`, which every seat may.\n */\n@customElement('document-party-select')\nexport class DocumentPartySelect extends localize(i18next)(LitElement) {\n static styles = [\n ButtonStyles,\n css`\n :host {\n position: relative;\n display: block;\n }\n .field {\n display: flex;\n gap: var(--spacing-small, 4px);\n align-items: center;\n }\n input {\n flex: 1;\n min-width: 0;\n box-sizing: border-box;\n height: var(--form-element-height-medium, 32px);\n padding: 0 var(--spacing-medium, 8px);\n border: var(--input-field-border, 1px solid var(--md-sys-color-outline));\n border-radius: var(--input-field-border-radius, var(--md-sys-shape-corner-small, 4px));\n background: var(--input-field-background, var(--md-sys-color-surface-container-highest));\n font: inherit;\n font-size: var(--ui-t-body, 13px);\n color: var(--ui-ink, var(--md-sys-color-on-surface));\n }\n input:focus-visible {\n outline: none;\n border-color: var(--md-sys-color-primary);\n }\n ul {\n position: absolute;\n z-index: 10;\n left: 0;\n right: 0;\n top: calc(100% + 2px);\n max-height: 260px;\n overflow-y: auto;\n margin: 0;\n padding: var(--spacing-small, 4px) 0;\n list-style: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: var(--ui-r, 10px);\n background: var(--md-sys-color-surface-container-lowest);\n box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);\n }\n li {\n display: flex;\n justify-content: space-between;\n gap: var(--spacing-large, 12px);\n padding: 6px var(--spacing-large, 12px);\n cursor: pointer;\n font-size: var(--ui-t-body, 13px);\n color: var(--ui-ink, var(--md-sys-color-on-surface));\n }\n li:hover,\n li[active] {\n background: var(--md-sys-color-surface-container-high);\n }\n li small {\n white-space: nowrap;\n }\n li small,\n li.none {\n color: var(--ui-muted, var(--md-sys-color-on-surface-variant));\n }\n li.none {\n cursor: default;\n }\n `\n ]\n\n /** The party chosen, shown as the field's placeholder until something is typed. */\n @property({ attribute: false }) party: DocumentParty | null = null\n @property({ type: Boolean }) disabled = false\n\n @state() private search = ''\n /** The words the list is found by - undefined while no list is open. */\n @state() private finding?: string\n @state() private active = 0\n\n private timer?: ReturnType<typeof setTimeout>\n\n /* The choices for the words found by - only the answer to the last thing typed is shown, and the list found before\n stays while the next is read (ADR-0190). */\n private choices = new QueryController(this, CHOICES, {\n keepPrevious: true,\n variables: () =>\n this.finding === undefined || this.disabled ? undefined : { search: this.finding.trim() || undefined, pagination: { page: 1, limit: 30 } }\n })\n\n /** The list under the field: what was found, or null while it is closed or not read. */\n private get found(): DocumentParty[] | null {\n if (this.finding === undefined || !this.choices.data) return null\n return this.choices.data.counterparties?.items ?? []\n }\n\n render() {\n return html`\n <div class=\"field\">\n <input\n .value=${this.search}\n placeholder=${this.party?.name ?? i18next.t('text.invoice-counterparty-search')}\n aria-label=${i18next.t('field.counterparty')}\n ?disabled=${this.disabled}\n @focus=${() => this.find()}\n @input=${(e: any) => ((this.search = e.target.value), this.findSoon())}\n @keydown=${(e: KeyboardEvent) => this.key(e)}\n @blur=${() => setTimeout(() => (this.finding = undefined), 150)}\n />\n ${this.party && !this.disabled\n ? html`<button quiet icon-only title=${i18next.t('button.invoice-counterparty-clear')} aria-label=${i18next.t('button.invoice-counterparty-clear')} @click=${() => this.choose(null)}>\n <md-icon>close</md-icon>\n </button>`\n : nothing}\n </div>\n ${this.found\n ? html`<ul role=\"listbox\">\n ${this.found.length\n ? this.found.map(\n (one, index) =>\n html`<li role=\"option\" ?active=${index === this.active} @mousedown=${(e: Event) => (e.preventDefault(), this.choose(one))}>\n <span>${one.name}</span>${one.businessNumber ? html`<small>${one.businessNumber}</small>` : nothing}\n </li>`\n )\n : html`<li class=\"none\">${i18next.t('text.invoice-counterparty-none')}</li>`}\n </ul>`\n : nothing}\n `\n }\n\n private findSoon() {\n clearTimeout(this.timer)\n this.timer = setTimeout(() => this.find(), 250)\n }\n\n private find() {\n if (this.disabled) return\n this.finding = this.search\n this.active = 0\n }\n\n private key(e: KeyboardEvent) {\n if (!this.found?.length || e.isComposing) return\n if (e.key === 'ArrowDown') this.active = Math.min(this.active + 1, this.found.length - 1)\n else if (e.key === 'ArrowUp') this.active = Math.max(this.active - 1, 0)\n else if (e.key === 'Enter') this.choose(this.found[this.active])\n else if (e.key === 'Escape') this.finding = undefined\n else return\n e.preventDefault()\n }\n\n private choose(party: DocumentParty | null) {\n this.search = ''\n this.finding = undefined\n this.dispatchEvent(new CustomEvent('party', { detail: party, bubbles: true, composed: true }))\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { LitElement } from 'lit';
2
- import { type Entity360DoorAnswer, type Entity360Subject } from '@operato/layout';
2
+ import { type Entity360Subject } from '@operato/layout';
3
3
  import '../invoice-files';
4
4
  /** The other party: the buyer of a sale, the supplier of a purchase. */
5
5
  export declare const counterpartOf: (value: {
@@ -20,8 +20,7 @@ export declare function registerInvoiceKind(): void;
20
20
  export declare class InvoiceOverviewSection extends LitElement {
21
21
  static styles: import("lit").CSSResult[];
22
22
  subject?: Entity360Subject;
23
- answer?: Entity360DoorAnswer<any>;
24
- updated(changed: Map<string, unknown>): void;
25
- private read;
23
+ private invoice;
24
+ get answer(): import("@operato/layout").Entity360DoorAnswer<any>;
26
25
  render(): import("lit-html").TemplateResult<1>;
27
26
  }
@@ -1,10 +1,10 @@
1
1
  import { __decorate, __metadata } from "tslib";
2
2
  import gql from 'graphql-tag';
3
3
  import { css, html, LitElement } from 'lit';
4
- import { customElement, property, state } from 'lit/decorators.js';
5
- import { client } from '@operato/graphql';
4
+ import { customElement, property } from 'lit/decorators.js';
5
+ import { QueryController } from '@operato/graphql';
6
6
  import { i18next } from '@operato/i18n';
7
- import { entity360Name, readEntity360Door, registerEntity360Kind, registerEntity360Section } from '@operato/layout';
7
+ import { entity360Answer, entity360Name, registerEntity360Kind, registerEntity360Section } from '@operato/layout';
8
8
  import { DocumentFormStyles, renderDocumentTotals } from '../document/document-form';
9
9
  import { invoice360Query } from '../invoice-attach';
10
10
  import '../invoice-files';
@@ -34,6 +34,18 @@ export function registerInvoiceKind() {
34
34
  });
35
35
  }
36
36
  let InvoiceOverviewSection = class InvoiceOverviewSection extends LitElement {
37
+ constructor() {
38
+ super(...arguments);
39
+ /* The invoice of the subject shown (ADR-0190). */
40
+ this.invoice = new QueryController(this, gql(`
41
+ query ($id: String!) {
42
+ invoice: ${invoice360Query()}(id: $id) {
43
+ id number status direction currency issueDate dueDate counterpartyId supplierName buyerName purchaseOrder
44
+ supplyAmount taxAmount totalAmount taxGroups { taxKind taxRate supplyAmount taxAmount }
45
+ }
46
+ }
47
+ `), { variables: () => (this.subject?.id ? { id: this.subject.id } : undefined) });
48
+ }
37
49
  static { this.styles = [
38
50
  DocumentFormStyles,
39
51
  css `
@@ -57,37 +69,8 @@ let InvoiceOverviewSection = class InvoiceOverviewSection extends LitElement {
57
69
  }
58
70
  `
59
71
  ]; }
60
- updated(changed) {
61
- if (changed.has('subject'))
62
- this.read();
63
- }
64
- async read() {
65
- const id = this.subject?.id;
66
- this.answer = undefined;
67
- if (!id)
68
- return;
69
- let response;
70
- try {
71
- response = await client.query({
72
- query: gql(`
73
- query ($id: String!) {
74
- invoice: ${invoice360Query()}(id: $id) {
75
- id number status direction currency issueDate dueDate counterpartyId supplierName buyerName purchaseOrder
76
- supplyAmount taxAmount totalAmount taxGroups { taxKind taxRate supplyAmount taxAmount }
77
- }
78
- }
79
- `),
80
- variables: { id },
81
- fetchPolicy: 'no-cache',
82
- errorPolicy: 'all'
83
- });
84
- }
85
- catch (e) {
86
- response = { data: null, errors: e?.graphQLErrors?.length ? e.graphQLErrors : [{ message: e?.message ?? String(e) }] };
87
- }
88
- if (this.subject?.id !== id)
89
- return;
90
- this.answer = readEntity360Door(response, data => data?.invoice);
72
+ get answer() {
73
+ return entity360Answer(this.invoice, data => data?.invoice);
91
74
  }
92
75
  render() {
93
76
  const one = this.answer?.data;
@@ -116,10 +99,6 @@ __decorate([
116
99
  property({ attribute: false }),
117
100
  __metadata("design:type", Object)
118
101
  ], InvoiceOverviewSection.prototype, "subject", void 0);
119
- __decorate([
120
- state(),
121
- __metadata("design:type", Object)
122
- ], InvoiceOverviewSection.prototype, "answer", void 0);
123
102
  InvoiceOverviewSection = __decorate([
124
103
  customElement('invoice-overview-section')
125
104
  ], InvoiceOverviewSection);
@@ -1 +1 @@
1
- {"version":3,"file":"invoice-360.js","sourceRoot":"","sources":["../../client/entity360/invoice-360.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { entity360Name, readEntity360Door, registerEntity360Kind, registerEntity360Section, type Entity360DoorAnswer, type Entity360Subject } from '@operato/layout'\n\nimport { DocumentFormStyles, renderDocumentTotals } from '../document/document-form'\nimport { invoice360Query } from '../invoice-attach'\nimport '../invoice-files'\n\n/** The other party: the buyer of a sale, the supplier of a purchase. */\nexport const counterpartOf = (value: { direction?: string; supplierName?: string; buyerName?: string }) =>\n (value.direction === 'PURCHASE' ? value.supplierName : value.buyerName) || ''\n\n/** The other party as printed - a link to its counterparty's 360 when the invoice names one, else the printed name. */\nexport const counterpartCell = (value: { counterpartyId?: string | null; direction?: string; supplierName?: string; buyerName?: string }) =>\n value.counterpartyId ? entity360Name({ __typename: 'Counterparty', id: value.counterpartyId, name: counterpartOf(value) }, counterpartOf(value)) : counterpartOf(value)\n\nexport const invoiceStatusWord = (status?: string) =>\n status === 'ISSUED' ? i18next.t('text.invoice-status-issued') : status === 'VOID' ? i18next.t('text.invoice-status-void') : i18next.t('text.invoice-status-draft')\n\n/** An invoice's 360 (ADR-0067). The module draws the invoice; an application hangs its own sections on 'invoice'. */\nexport function registerInvoiceKind() {\n registerEntity360Kind({\n kind: 'invoice',\n typenames: ['Invoice'],\n assistantSubject: true,\n title: ({ value }) => `${i18next.t('title.invoice')} · ${counterpartOf(value) || value.number || ''}`,\n context: ({ value }) => [value.number, value.issueDate, value.status ? invoiceStatusWord(value.status) : ''].filter(Boolean).join(' · ')\n })\n registerEntity360Section('invoice', {\n name: 'overview',\n order: 10,\n render: subject => html`<invoice-overview-section .subject=${subject}></invoice-overview-section>`\n })\n registerEntity360Section('invoice', {\n name: 'files',\n order: 20,\n render: subject => html`<ox-entity360-section .heading=${i18next.t('text.invoice-section-files')} .state=${'ready'}><invoice-files .invoiceId=${subject.id}></invoice-files></ox-entity360-section>`\n })\n}\n\n@customElement('invoice-overview-section')\nexport class InvoiceOverviewSection extends LitElement {\n static styles = [\n DocumentFormStyles,\n css`\n :host {\n font-size: var(--ui-t-body);\n line-height: 1.5;\n }\n dl {\n margin: 0 0 var(--spacing-large);\n display: grid;\n grid-template-columns: max-content 1fr;\n gap: var(--spacing-small) var(--spacing-large);\n }\n dt {\n color: var(--ui-muted);\n }\n dd {\n margin: 0;\n overflow-wrap: anywhere;\n font-variant-numeric: tabular-nums;\n }\n `\n ]\n\n @property({ attribute: false }) subject?: Entity360Subject\n @state() answer?: Entity360DoorAnswer<any>\n\n updated(changed: Map<string, unknown>) {\n if (changed.has('subject')) this.read()\n }\n\n private async read() {\n const id = this.subject?.id\n this.answer = undefined\n if (!id) return\n let response: any\n try {\n response = await client.query({\n query: gql(`\n query ($id: String!) {\n invoice: ${invoice360Query()}(id: $id) {\n id number status direction currency issueDate dueDate counterpartyId supplierName buyerName purchaseOrder\n supplyAmount taxAmount totalAmount taxGroups { taxKind taxRate supplyAmount taxAmount }\n }\n }\n `),\n variables: { id },\n fetchPolicy: 'no-cache',\n errorPolicy: 'all'\n } as any)\n } catch (e: any) {\n response = { data: null, errors: e?.graphQLErrors?.length ? e.graphQLErrors : [{ message: e?.message ?? String(e) }] }\n }\n if (this.subject?.id !== id) return\n this.answer = readEntity360Door(response, data => data?.invoice)\n }\n\n render() {\n const one = this.answer?.data\n return html`<ox-entity360-section .heading=${i18next.t('title.invoice')} .state=${this.answer?.state ?? 'loading'} .message=${this.answer?.message ?? ''}>\n ${one\n ? html`<dl>\n <dt>${i18next.t('field.invoice-number')}</dt>\n <dd>${one.number} · ${invoiceStatusWord(one.status)}</dd>\n <dt>${i18next.t('field.counterparty')}</dt>\n <dd>${one.counterpartyId ? counterpartCell(one) : '—'}</dd>\n <dt>${i18next.t('field.invoice-supplier-name')}</dt>\n <dd>${one.supplierName}</dd>\n <dt>${i18next.t('field.invoice-buyer-name')}</dt>\n <dd>${one.buyerName}</dd>\n <dt>${i18next.t('field.invoice-issue-date')}</dt>\n <dd>${one.issueDate ?? '—'}</dd>\n <dt>${i18next.t('field.invoice-due-date')}</dt>\n <dd>${one.dueDate ?? '—'}</dd>\n </dl>\n ${renderDocumentTotals(one)}`\n : ''}\n </ox-entity360-section>`\n }\n}\n"]}
1
+ {"version":3,"file":"invoice-360.js","sourceRoot":"","sources":["../../client/entity360/invoice-360.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { QueryController } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { entity360Answer, entity360Name, registerEntity360Kind, registerEntity360Section, type Entity360Subject } from '@operato/layout'\n\nimport { DocumentFormStyles, renderDocumentTotals } from '../document/document-form'\nimport { invoice360Query } from '../invoice-attach'\nimport '../invoice-files'\n\n/** The other party: the buyer of a sale, the supplier of a purchase. */\nexport const counterpartOf = (value: { direction?: string; supplierName?: string; buyerName?: string }) =>\n (value.direction === 'PURCHASE' ? value.supplierName : value.buyerName) || ''\n\n/** The other party as printed - a link to its counterparty's 360 when the invoice names one, else the printed name. */\nexport const counterpartCell = (value: { counterpartyId?: string | null; direction?: string; supplierName?: string; buyerName?: string }) =>\n value.counterpartyId ? entity360Name({ __typename: 'Counterparty', id: value.counterpartyId, name: counterpartOf(value) }, counterpartOf(value)) : counterpartOf(value)\n\nexport const invoiceStatusWord = (status?: string) =>\n status === 'ISSUED' ? i18next.t('text.invoice-status-issued') : status === 'VOID' ? i18next.t('text.invoice-status-void') : i18next.t('text.invoice-status-draft')\n\n/** An invoice's 360 (ADR-0067). The module draws the invoice; an application hangs its own sections on 'invoice'. */\nexport function registerInvoiceKind() {\n registerEntity360Kind({\n kind: 'invoice',\n typenames: ['Invoice'],\n assistantSubject: true,\n title: ({ value }) => `${i18next.t('title.invoice')} · ${counterpartOf(value) || value.number || ''}`,\n context: ({ value }) => [value.number, value.issueDate, value.status ? invoiceStatusWord(value.status) : ''].filter(Boolean).join(' · ')\n })\n registerEntity360Section('invoice', {\n name: 'overview',\n order: 10,\n render: subject => html`<invoice-overview-section .subject=${subject}></invoice-overview-section>`\n })\n registerEntity360Section('invoice', {\n name: 'files',\n order: 20,\n render: subject => html`<ox-entity360-section .heading=${i18next.t('text.invoice-section-files')} .state=${'ready'}><invoice-files .invoiceId=${subject.id}></invoice-files></ox-entity360-section>`\n })\n}\n\n@customElement('invoice-overview-section')\nexport class InvoiceOverviewSection extends LitElement {\n static styles = [\n DocumentFormStyles,\n css`\n :host {\n font-size: var(--ui-t-body);\n line-height: 1.5;\n }\n dl {\n margin: 0 0 var(--spacing-large);\n display: grid;\n grid-template-columns: max-content 1fr;\n gap: var(--spacing-small) var(--spacing-large);\n }\n dt {\n color: var(--ui-muted);\n }\n dd {\n margin: 0;\n overflow-wrap: anywhere;\n font-variant-numeric: tabular-nums;\n }\n `\n ]\n\n @property({ attribute: false }) subject?: Entity360Subject\n /* The invoice of the subject shown (ADR-0190). */\n private invoice = new QueryController(\n this,\n gql(`\n query ($id: String!) {\n invoice: ${invoice360Query()}(id: $id) {\n id number status direction currency issueDate dueDate counterpartyId supplierName buyerName purchaseOrder\n supplyAmount taxAmount totalAmount taxGroups { taxKind taxRate supplyAmount taxAmount }\n }\n }\n `),\n { variables: () => (this.subject?.id ? { id: this.subject.id } : undefined) }\n )\n\n get answer() {\n return entity360Answer(this.invoice, data => data?.invoice)\n }\n\n render() {\n const one = this.answer?.data\n return html`<ox-entity360-section .heading=${i18next.t('title.invoice')} .state=${this.answer?.state ?? 'loading'} .message=${this.answer?.message ?? ''}>\n ${one\n ? html`<dl>\n <dt>${i18next.t('field.invoice-number')}</dt>\n <dd>${one.number} · ${invoiceStatusWord(one.status)}</dd>\n <dt>${i18next.t('field.counterparty')}</dt>\n <dd>${one.counterpartyId ? counterpartCell(one) : '—'}</dd>\n <dt>${i18next.t('field.invoice-supplier-name')}</dt>\n <dd>${one.supplierName}</dd>\n <dt>${i18next.t('field.invoice-buyer-name')}</dt>\n <dd>${one.buyerName}</dd>\n <dt>${i18next.t('field.invoice-issue-date')}</dt>\n <dd>${one.issueDate ?? '—'}</dd>\n <dt>${i18next.t('field.invoice-due-date')}</dt>\n <dd>${one.dueDate ?? '—'}</dd>\n </dl>\n ${renderDocumentTotals(one)}`\n : ''}\n </ox-entity360-section>`\n }\n}\n"]}
@@ -7,7 +7,7 @@ export { defaultTaxRate } from '@things-factory/invoice/dist-shared/document-amo
7
7
  export { printDocument, PRINT_LANGUAGES, type PrintLanguage } from './document/document-print.js';
8
8
  export { DocumentPreview, openDocumentPreview, type DocumentFile, type DocumentFileFormat, type DocumentFileLoader } from './document/document-preview.js';
9
9
  export { DocumentPartySelect, partyOfName, type DocumentParty } from './document/document-party.js';
10
- export { documentDefaults, headFromDefaults, OUR_SIDE_FIELDS, oursFromLast, type DocumentDefaults } from './document/document-defaults.js';
10
+ export { DOCUMENT_DEFAULTS, DOCUMENT_DEFAULTS_READER, headFromDefaults, OUR_SIDE_FIELDS, oursFromLast, type DocumentDefaults } from './document/document-defaults.js';
11
11
  export { daysAfter, nextInvoiceNumber, partyNamed, sameName } from '@things-factory/invoice/dist-shared/document-start.js';
12
12
  export { issuePeriodOf } from '@things-factory/invoice/dist-shared/invoice-standing.js';
13
13
  export * from './viewparts/document-defaults-setting-let.js';
@@ -7,7 +7,7 @@ export { defaultTaxRate } from '@things-factory/invoice/dist-shared/document-amo
7
7
  export { printDocument, PRINT_LANGUAGES } from './document/document-print.js';
8
8
  export { DocumentPreview, openDocumentPreview } from './document/document-preview.js';
9
9
  export { DocumentPartySelect, partyOfName } from './document/document-party.js';
10
- export { documentDefaults, headFromDefaults, OUR_SIDE_FIELDS, oursFromLast } from './document/document-defaults.js';
10
+ export { DOCUMENT_DEFAULTS, DOCUMENT_DEFAULTS_READER, headFromDefaults, OUR_SIDE_FIELDS, oursFromLast } from './document/document-defaults.js';
11
11
  export { daysAfter, nextInvoiceNumber, partyNamed, sameName } from '@things-factory/invoice/dist-shared/document-start.js';
12
12
  export { issuePeriodOf } from '@things-factory/invoice/dist-shared/invoice-standing.js';
13
13
  export * from './viewparts/document-defaults-setting-let.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,wBAAwB,EAA2B,MAAM,qBAAqB,CAAA;AACpH,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAC/G,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,kBAAkB,EAAE,oBAAoB,EAAsB,MAAM,6BAA6B,CAAA;AAC3I,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAClH,OAAO,EAAE,cAAc,EAAE,MAAM,yDAAyD,CAAA;AACxF,OAAO,EAAE,aAAa,EAAE,eAAe,EAAsB,MAAM,8BAA8B,CAAA;AACjG,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAuE,MAAM,gCAAgC,CAAA;AAC1J,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAsB,MAAM,8BAA8B,CAAA;AACnG,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAyB,MAAM,iCAAiC,CAAA;AAC1I,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,uDAAuD,CAAA;AAC1H,OAAO,EAAE,aAAa,EAAE,MAAM,yDAAyD,CAAA;AACvF,cAAc,8CAA8C,CAAA","sourcesContent":["export { configureInvoiceLinkSection, configureInvoice360Query, type InvoiceLinkSection } from './invoice-attach.js'\nexport { counterpartOf, invoiceStatusWord } from './entity360/invoice-360.js'\nexport { currencyChoices, currencyDigits, documentAmount, documentNumber } from './document/document-amount.js'\nexport { DocumentFormStyles, HEAD_FIELDS, renderDocumentHead, renderDocumentTotals, type DocumentValue } from './document/document-form.js'\nexport { documentLinesConfig, linesOf, onLineChange, reckonLines, settleLine } from './document/document-lines.js'\nexport { defaultTaxRate } from '@things-factory/invoice/dist-shared/document-amounts.js'\nexport { printDocument, PRINT_LANGUAGES, type PrintLanguage } from './document/document-print.js'\nexport { DocumentPreview, openDocumentPreview, type DocumentFile, type DocumentFileFormat, type DocumentFileLoader } from './document/document-preview.js'\nexport { DocumentPartySelect, partyOfName, type DocumentParty } from './document/document-party.js'\nexport { documentDefaults, headFromDefaults, OUR_SIDE_FIELDS, oursFromLast, type DocumentDefaults } from './document/document-defaults.js'\nexport { daysAfter, nextInvoiceNumber, partyNamed, sameName } from '@things-factory/invoice/dist-shared/document-start.js'\nexport { issuePeriodOf } from '@things-factory/invoice/dist-shared/invoice-standing.js'\nexport * from './viewparts/document-defaults-setting-let.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,wBAAwB,EAA2B,MAAM,qBAAqB,CAAA;AACpH,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAC/G,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,kBAAkB,EAAE,oBAAoB,EAAsB,MAAM,6BAA6B,CAAA;AAC3I,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAClH,OAAO,EAAE,cAAc,EAAE,MAAM,yDAAyD,CAAA;AACxF,OAAO,EAAE,aAAa,EAAE,eAAe,EAAsB,MAAM,8BAA8B,CAAA;AACjG,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAuE,MAAM,gCAAgC,CAAA;AAC1J,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAsB,MAAM,8BAA8B,CAAA;AACnG,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAyB,MAAM,iCAAiC,CAAA;AACrK,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,uDAAuD,CAAA;AAC1H,OAAO,EAAE,aAAa,EAAE,MAAM,yDAAyD,CAAA;AACvF,cAAc,8CAA8C,CAAA","sourcesContent":["export { configureInvoiceLinkSection, configureInvoice360Query, type InvoiceLinkSection } from './invoice-attach.js'\nexport { counterpartOf, invoiceStatusWord } from './entity360/invoice-360.js'\nexport { currencyChoices, currencyDigits, documentAmount, documentNumber } from './document/document-amount.js'\nexport { DocumentFormStyles, HEAD_FIELDS, renderDocumentHead, renderDocumentTotals, type DocumentValue } from './document/document-form.js'\nexport { documentLinesConfig, linesOf, onLineChange, reckonLines, settleLine } from './document/document-lines.js'\nexport { defaultTaxRate } from '@things-factory/invoice/dist-shared/document-amounts.js'\nexport { printDocument, PRINT_LANGUAGES, type PrintLanguage } from './document/document-print.js'\nexport { DocumentPreview, openDocumentPreview, type DocumentFile, type DocumentFileFormat, type DocumentFileLoader } from './document/document-preview.js'\nexport { DocumentPartySelect, partyOfName, type DocumentParty } from './document/document-party.js'\nexport { DOCUMENT_DEFAULTS, DOCUMENT_DEFAULTS_READER, headFromDefaults, OUR_SIDE_FIELDS, oursFromLast, type DocumentDefaults } from './document/document-defaults.js'\nexport { daysAfter, nextInvoiceNumber, partyNamed, sameName } from '@things-factory/invoice/dist-shared/document-start.js'\nexport { issuePeriodOf } from '@things-factory/invoice/dist-shared/invoice-standing.js'\nexport * from './viewparts/document-defaults-setting-let.js'\n"]}
@@ -2,12 +2,6 @@ import '@material/web/icon/icon.js';
2
2
  import '@operato/attachment';
3
3
  import '@operato/input/ox-input-file.js';
4
4
  import { LitElement } from 'lit';
5
- type InvoiceFile = {
6
- id: string;
7
- name: string;
8
- mimetype?: string;
9
- fullpath: string;
10
- };
11
5
  declare const InvoiceFiles_base: (new (...args: any[]) => LitElement) & typeof LitElement;
12
6
  /**
13
7
  * The files an invoice keeps - the signed copy, the order, the delivery note. Each opens in its own tab. Whoever may
@@ -16,15 +10,15 @@ declare const InvoiceFiles_base: (new (...args: any[]) => LitElement) & typeof L
16
10
  export declare class InvoiceFiles extends InvoiceFiles_base {
17
11
  static styles: import("lit").CSSResult[];
18
12
  invoiceId?: string;
19
- files: InvoiceFile[];
20
13
  mayChange: boolean;
21
- busy: boolean;
22
14
  progress?: number;
15
+ private filesRead;
16
+ private changing;
17
+ private get files();
18
+ private get busy();
23
19
  connectedCallback(): void;
24
- updated(changed: Map<string, unknown>): void;
25
20
  render(): import("lit-html").TemplateResult<1>;
26
21
  private tile;
27
- private load;
28
22
  private pick;
29
23
  private takeOff;
30
24
  private change;
@@ -6,9 +6,8 @@ import '@operato/input/ox-input-file.js';
6
6
  import gql from 'graphql-tag';
7
7
  import { css, html, LitElement, nothing } from 'lit';
8
8
  import { customElement, property, state } from 'lit/decorators.js';
9
- import { client, uploadContext } from '@operato/graphql';
9
+ import { MutationController, QueryController, uploadContext } from '@operato/graphql';
10
10
  import { i18next, localize } from '@operato/i18n';
11
- import { notify } from '@operato/layout';
12
11
  import { OxPrompt } from '@operato/popup/ox-prompt.js';
13
12
  import { hasPrivilege } from '@things-factory/auth-base/dist-client/index.js';
14
13
  import { invoice360Query } from './invoice-attach';
@@ -21,9 +20,17 @@ const touch = () => window.matchMedia('(pointer: coarse)').matches;
21
20
  let InvoiceFiles = class InvoiceFiles extends localize(i18next)(LitElement) {
22
21
  constructor() {
23
22
  super(...arguments);
24
- this.files = [];
25
23
  this.mayChange = false;
26
- this.busy = false;
24
+ /* The files of the invoice named (ADR-0190). */
25
+ this.filesRead = new QueryController(this, gql(`query ($id: String!) { invoice: ${invoice360Query()}(id: $id) { id files { id name mimetype fullpath } } }`), { variables: () => (this.invoiceId ? { id: this.invoiceId } : undefined) });
26
+ /* Attaching or taking off reads the files again. */
27
+ this.changing = new MutationController(this, gql `
28
+ mutation ($id: String!, $attach: [Upload!], $remove: [String!]) {
29
+ changeInvoiceFiles(id: $id, attach: $attach, remove: $remove) {
30
+ id
31
+ }
32
+ }
33
+ `, { refetch: () => [this.filesRead] });
27
34
  }
28
35
  static { this.styles = [
29
36
  css `
@@ -99,14 +106,16 @@ let InvoiceFiles = class InvoiceFiles extends localize(i18next)(LitElement) {
99
106
  }
100
107
  `
101
108
  ]; }
109
+ get files() {
110
+ return this.filesRead.data?.invoice?.files ?? [];
111
+ }
112
+ get busy() {
113
+ return this.changing.pending;
114
+ }
102
115
  connectedCallback() {
103
116
  super.connectedCallback();
104
117
  hasPrivilege({ privilege: 'mutation', category: 'invoice', domainOwnerGranted: true }).then(may => (this.mayChange = !!may));
105
118
  }
106
- updated(changed) {
107
- if (changed.has('invoiceId'))
108
- this.load();
109
- }
110
119
  render() {
111
120
  const editable = this.mayChange && !this.busy;
112
121
  return html `
@@ -157,24 +166,6 @@ let InvoiceFiles = class InvoiceFiles extends localize(i18next)(LitElement) {
157
166
  : nothing}
158
167
  </span>`;
159
168
  }
160
- async load() {
161
- const id = this.invoiceId;
162
- this.files = [];
163
- if (!id)
164
- return;
165
- try {
166
- const response = await client.query({
167
- query: gql(`query ($id: String!) { invoice: ${invoice360Query()}(id: $id) { id files { id name mimetype fullpath } } }`),
168
- variables: { id },
169
- fetchPolicy: 'no-cache'
170
- });
171
- if (this.invoiceId === id)
172
- this.files = response.data?.invoice?.files ?? [];
173
- }
174
- catch (error) {
175
- notify({ level: 'error', message: error?.graphQLErrors?.[0]?.message ?? error?.message ?? String(error) });
176
- }
177
- }
178
169
  async pick(e) {
179
170
  const picked = [...(e.detail ?? [])];
180
171
  /* The picker's own reset says `change` again, with nothing - that one is let go. */
@@ -196,48 +187,18 @@ let InvoiceFiles = class InvoiceFiles extends localize(i18next)(LitElement) {
196
187
  async change({ attach = [], remove = [] }) {
197
188
  if (!this.invoiceId || this.busy)
198
189
  return;
199
- this.busy = true;
200
- try {
201
- const response = await client.mutate({
202
- mutation: gql `
203
- mutation ($id: String!, $attach: [Upload!], $remove: [String!]) {
204
- changeInvoiceFiles(id: $id, attach: $attach, remove: $remove) {
205
- id
206
- }
207
- }
208
- `,
209
- variables: { id: this.invoiceId, attach, remove },
210
- context: attach.length ? uploadContext(fraction => (this.progress = fraction)) : {}
211
- });
212
- if (response.errors?.length)
213
- throw new Error(response.errors.map(one => one.message).join(' · '));
214
- await this.load();
215
- }
216
- catch (error) {
217
- notify({ level: 'error', message: error?.graphQLErrors?.[0]?.message ?? error?.message ?? String(error) });
218
- }
219
- finally {
220
- this.busy = false;
221
- this.progress = undefined;
222
- }
190
+ await this.changing.run({ id: this.invoiceId, attach, remove }, { context: attach.length ? uploadContext(fraction => (this.progress = fraction)) : {} });
191
+ this.progress = undefined;
223
192
  }
224
193
  };
225
194
  __decorate([
226
195
  property(),
227
196
  __metadata("design:type", String)
228
197
  ], InvoiceFiles.prototype, "invoiceId", void 0);
229
- __decorate([
230
- state(),
231
- __metadata("design:type", Array)
232
- ], InvoiceFiles.prototype, "files", void 0);
233
198
  __decorate([
234
199
  state(),
235
200
  __metadata("design:type", Object)
236
201
  ], InvoiceFiles.prototype, "mayChange", void 0);
237
- __decorate([
238
- state(),
239
- __metadata("design:type", Object)
240
- ], InvoiceFiles.prototype, "busy", void 0);
241
202
  __decorate([
242
203
  state(),
243
204
  __metadata("design:type", Number)