@things-factory/sales 10.1.244 → 10.1.246

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 (41) hide show
  1. package/dist-client/close-months.d.ts +5 -0
  2. package/dist-client/close-months.js +20 -0
  3. package/dist-client/close-months.js.map +1 -0
  4. package/dist-client/headroom-choice.d.ts +10 -0
  5. package/dist-client/headroom-choice.js +22 -0
  6. package/dist-client/headroom-choice.js.map +1 -0
  7. package/dist-client/pages/opportunity-list.d.ts +18 -3
  8. package/dist-client/pages/opportunity-list.js +93 -9
  9. package/dist-client/pages/opportunity-list.js.map +1 -1
  10. package/dist-client/pages/quotation-list.d.ts +11 -0
  11. package/dist-client/pages/quotation-list.js +71 -5
  12. package/dist-client/pages/quotation-list.js.map +1 -1
  13. package/dist-client/pages/sales-product-list.d.ts +6 -1
  14. package/dist-client/pages/sales-product-list.js +42 -2
  15. package/dist-client/pages/sales-product-list.js.map +1 -1
  16. package/dist-client/tsconfig.tsbuildinfo +1 -1
  17. package/dist-server/service/opportunity/opportunity-query.d.ts +6 -0
  18. package/dist-server/service/opportunity/opportunity-query.js +14 -1
  19. package/dist-server/service/opportunity/opportunity-query.js.map +1 -1
  20. package/dist-server/service/opportunity/opportunity-service.d.ts +13 -1
  21. package/dist-server/service/opportunity/opportunity-service.js +13 -0
  22. package/dist-server/service/opportunity/opportunity-service.js.map +1 -1
  23. package/dist-server/service/opportunity/opportunity-type.d.ts +5 -0
  24. package/dist-server/service/opportunity/opportunity-type.js +19 -1
  25. package/dist-server/service/opportunity/opportunity-type.js.map +1 -1
  26. package/dist-server/service/quotation/quotation-query.d.ts +4 -0
  27. package/dist-server/service/quotation/quotation-query.js +13 -1
  28. package/dist-server/service/quotation/quotation-query.js.map +1 -1
  29. package/dist-server/service/quotation/quotation-service.d.ts +9 -2
  30. package/dist-server/service/quotation/quotation-service.js +9 -0
  31. package/dist-server/service/quotation/quotation-service.js.map +1 -1
  32. package/dist-server/service/sales-product/sales-product-query.d.ts +4 -0
  33. package/dist-server/service/sales-product/sales-product-query.js +14 -1
  34. package/dist-server/service/sales-product/sales-product-query.js.map +1 -1
  35. package/dist-server/service/sales-product/sales-product-service.d.ts +11 -1
  36. package/dist-server/service/sales-product/sales-product-service.js +16 -0
  37. package/dist-server/service/sales-product/sales-product-service.js.map +1 -1
  38. package/dist-server/tsconfig.tsbuildinfo +1 -1
  39. package/package.json +8 -7
  40. package/translations/en.json +8 -0
  41. package/translations/ko.json +8 -0
@@ -1,6 +1,7 @@
1
1
  import { __decorate, __metadata } from "tslib";
2
2
  import '@operato/data-grist/ox-grist.js';
3
3
  import '@operato/data-grist/ox-filters-form.js';
4
+ import '@operato/input/ox-input-select-buttons.js';
4
5
  import gql from 'graphql-tag';
5
6
  import { html } from 'lit';
6
7
  import { customElement, query, state } from 'lit/decorators.js';
@@ -20,9 +21,16 @@ const FIELDS = ['code', 'name', 'kind', 'grade', 'spec', 'unit', 'unitPrice', 'c
20
21
  /**
21
22
  * 상품 — what the domain sells and the price it offers it at: goods, a service, or labor by the grade of the people
22
23
  * (ADR-0171). Typed like a spreadsheet and saved together. A quotation line chosen from a product copies it at that
23
- * moment; changing a price here changes no written quotation.
24
+ * moment; changing a price here changes no written quotation. The headroom narrows it to the products in use or out of
25
+ * use, each chip with how many it holds under the other conditions.
24
26
  */
25
27
  let SalesProductList = class SalesProductList extends localize(i18next)(PageView) {
28
+ constructor() {
29
+ super(...arguments);
30
+ /* In use or out of use - none chosen is every product. */
31
+ this.inUse = '';
32
+ this.activeCounts = new Map();
33
+ }
26
34
  static { this.styles = [WorkSurfacePageStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles]; }
27
35
  get context() {
28
36
  return {
@@ -57,6 +65,11 @@ let SalesProductList = class SalesProductList extends localize(i18next)(PageView
57
65
  <div slot="headroom" class="header">
58
66
  <div class="filters">
59
67
  <ox-filters-form without-search autofocus></ox-filters-form>
68
+ <ox-input-select-buttons
69
+ .options=${['active', 'inactive'].map(value => ({ value, display: i18next.t(`text.sales-product-${value}`), count: this.activeCounts.get(value) ?? 0 }))}
70
+ .value=${this.inUse || undefined}
71
+ @change=${(e) => ((this.inUse = e.detail || ''), this.grist.fetch())}
72
+ ></ox-input-select-buttons>
60
73
  </div>
61
74
  </div>
62
75
  </ox-grist>`;
@@ -115,6 +128,10 @@ let SalesProductList = class SalesProductList extends localize(i18next)(PageView
115
128
  };
116
129
  }
117
130
  async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [], search }) {
131
+ search = search?.trim() || undefined;
132
+ this.countActive(filters, search);
133
+ if (this.inUse)
134
+ filters = [...filters, { name: 'active', operator: this.inUse === 'active' ? 'is_true' : 'is_not_true', value: null }];
118
135
  const response = await client.query({
119
136
  query: gql `
120
137
  query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $search: String) {
@@ -124,13 +141,28 @@ let SalesProductList = class SalesProductList extends localize(i18next)(PageView
124
141
  }
125
142
  }
126
143
  `,
127
- variables: { filters, pagination: { page, limit }, sortings, search: search?.trim() || undefined },
144
+ variables: { filters, pagination: { page, limit }, sortings, search },
128
145
  fetchPolicy: 'network-only'
129
146
  });
130
147
  if (response.errors?.length)
131
148
  throw response;
132
149
  return { total: response.data.responses.total, records: response.data.responses.items };
133
150
  }
151
+ /* The in-use chips' numbers, on the list's filters before the chip is added. */
152
+ async countActive(filters, search) {
153
+ const response = await client.query({
154
+ query: gql `
155
+ query ($filters: [Filter!], $search: String) {
156
+ salesProductActiveCounts(filters: $filters, search: $search) { value count }
157
+ }
158
+ `,
159
+ variables: { filters, search },
160
+ fetchPolicy: 'no-cache'
161
+ });
162
+ if (response.errors?.length)
163
+ return console.error(response.errors);
164
+ this.activeCounts = new Map(response.data.salesProductActiveCounts.map((row) => [row.value, row.count]));
165
+ }
134
166
  /** New, changed and deleted rows together; a refusal is said in the server's words and nothing is kept. */
135
167
  async save() {
136
168
  const patches = this.grist.dirtyRecords.map((record) => {
@@ -191,6 +223,14 @@ __decorate([
191
223
  state(),
192
224
  __metadata("design:type", Object)
193
225
  ], SalesProductList.prototype, "gristConfig", void 0);
226
+ __decorate([
227
+ state(),
228
+ __metadata("design:type", Object)
229
+ ], SalesProductList.prototype, "inUse", void 0);
230
+ __decorate([
231
+ state(),
232
+ __metadata("design:type", Object)
233
+ ], SalesProductList.prototype, "activeCounts", void 0);
194
234
  __decorate([
195
235
  query('ox-grist'),
196
236
  __metadata("design:type", DataGrist)
@@ -1 +1 @@
1
- {"version":3,"file":"sales-product-list.js","sourceRoot":"","sources":["../../client/pages/sales-product-list.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist/ox-grist.js'\nimport '@operato/data-grist/ox-filters-form.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 { notify } from '@operato/layout'\nimport { OxPrompt } from '@operato/popup/ox-prompt.js'\nimport { PageView } from '@operato/shell'\nimport { CommonButtonStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\nimport { documentNumber } from '@things-factory/invoice/dist-client'\n\nimport { salesProductKindWord } from '../sales-product-words'\n\nconst KINDS = ['GOODS', 'SERVICE', 'LABOR']\n\n/** The fields a row writes - all of them for a new row, the changed ones otherwise. */\nconst FIELDS = ['code', 'name', 'kind', 'grade', 'spec', 'unit', 'unitPrice', 'currency', 'taxKind', 'active', 'description']\n\n/**\n * 상품 — what the domain sells and the price it offers it at: goods, a service, or labor by the grade of the people\n * (ADR-0171). Typed like a spreadsheet and saved together. A quotation line chosen from a product copies it at that\n * moment; changing a price here changes no written quotation.\n */\n@customElement('sales-product-list')\nexport class SalesProductList extends localize(i18next)(PageView) {\n static styles = [WorkSurfacePageStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles]\n\n @state() gristConfig: any\n @query('ox-grist') private grist!: DataGrist\n\n get context() {\n return {\n title: i18next.t('title.sales-product-list'),\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n },\n filter: {\n handler: () => {\n this.grist.toggleHeadroom()\n }\n },\n actions: [\n { title: i18next.t('button.add'), icon: 'add', action: () => this.grist.addRecordToTop({ kind: 'GOODS', currency: 'KRW', taxKind: 'TAXABLE', active: true }) },\n { title: i18next.t('button.delete'), action: () => this.delete(), ...CommonButtonStyles.delete },\n { title: i18next.t('button.save'), action: () => this.save(), ...CommonButtonStyles.save }\n ],\n exportable: { name: i18next.t('title.sales-product-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 >\n <div slot=\"headroom\" class=\"header\">\n <div class=\"filters\">\n <ox-filters-form without-search autofocus></ox-filters-form>\n </div>\n </div>\n </ox-grist>`\n }\n\n async pageInitialized() {\n const text = (name: string, header: string, width: number, extra: any = {}) => ({ type: 'string', name, header, width, sortable: true, ...extra, record: { editable: true, ...extra.record } })\n this.gristConfig = {\n rows: { appendable: true, selectable: { multiple: true } },\n pagination: { limit: 100, pages: [50, 100, 500] },\n emptyNote: { title: i18next.t('text.sales-product-empty'), description: i18next.t('text.sales-product-empty-description') },\n list: { fields: ['name', 'code'], details: ['kind', 'unit', 'unitPrice'] },\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n { type: 'gutter', gutterName: 'row-selector', multiple: true },\n text('code', i18next.t('field.sales-product-code'), 110, { record: { mandatory: true } }),\n text('name', i18next.t('field.sales-product-name'), 200, { record: { mandatory: true } }),\n {\n type: 'select',\n name: 'kind',\n header: i18next.t('field.sales-product-kind'),\n width: 80,\n sortable: true,\n record: { editable: true, options: KINDS.map(kind => ({ value: kind, display: salesProductKindWord(kind) })) },\n filter: { type: 'select', operator: 'eq', options: [{ display: '', value: '' }, ...KINDS.map(kind => ({ display: salesProductKindWord(kind), value: kind }))] }\n },\n text('grade', i18next.t('field.sales-product-grade'), 110),\n text('spec', i18next.t('field.sales-product-spec'), 160),\n text('unit', i18next.t('field.sales-product-unit'), 70, { record: { align: 'center' } }),\n {\n type: 'float',\n name: 'unitPrice',\n header: i18next.t('field.sales-product-unit-price'),\n width: 130,\n sortable: true,\n record: { editable: true, align: 'right', renderer: (value: number, _c: any, record: any) => documentNumber(value, record?.currency || 'KRW') }\n },\n text('currency', i18next.t('field.sales-product-currency'), 70, { record: { align: 'center' } }),\n {\n type: 'select',\n name: 'taxKind',\n header: i18next.t('field.sales-product-tax-kind'),\n width: 80,\n record: {\n editable: true,\n options: [\n { value: 'TAXABLE', display: i18next.t('text.tax-kind-taxable') },\n { value: 'ZERO_RATED', display: i18next.t('text.tax-kind-zero-rated') },\n { value: 'EXEMPT', display: i18next.t('text.tax-kind-exempt') }\n ]\n }\n },\n { type: 'checkbox', name: 'active', header: i18next.t('field.sales-product-active'), width: 60, sortable: true, record: { editable: true } },\n text('description', i18next.t('field.sales-product-description'), 220)\n ],\n sorters: [{ name: 'code' }]\n }\n }\n\n async fetchHandler({ page = 1, limit = 100, 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: salesProducts(filters: $filters, pagination: $pagination, sortings: $sortings, search: $search) {\n items { id code name kind grade spec unit unitPrice currency taxKind active description }\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 /** New, changed and deleted rows together; a refusal is said in the server's words and nothing is kept. */\n private async save() {\n const patches = this.grist.dirtyRecords.map((record: any) => {\n const changed = record.__dirty__ === '+' ? FIELDS.filter(field => record[field] !== undefined) : Object.keys(record.__dirtyfields__ ?? {}).filter(field => FIELDS.includes(field))\n return { ...(record.id ? { id: record.id } : {}), cuFlag: record.__dirty__, ...Object.fromEntries(changed.map(field => [field, record[field] === '' ? null : record[field]])) }\n })\n if (!patches.length) return\n try {\n const response = await client.mutate({\n mutation: gql`\n mutation ($patches: [SalesProductPatch!]!) {\n updateMultipleSalesProduct(patches: $patches) { id }\n }\n `,\n variables: { patches }\n })\n if (response.errors?.length) throw response\n notify({ level: 'info', message: i18next.t('text.sales-product-saved') })\n this.grist.fetch()\n } catch (error: any) {\n notify({ level: 'error', message: error?.graphQLErrors?.[0]?.message ?? error?.errors?.[0]?.message ?? error?.message ?? String(error) })\n }\n }\n\n private async delete() {\n const ids = this.grist.selected.map((record: any) => record.id).filter(Boolean)\n if (!ids.length) return\n const confirmed = await OxPrompt.open({\n title: i18next.t('button.delete'),\n text: i18next.t('text.sales-product-delete-confirm', { count: ids.length }),\n confirmButton: { text: i18next.t('button.delete'), destructive: true },\n cancelButton: { text: i18next.t('button.cancel') }\n })\n if (!confirmed) return\n try {\n const response = await client.mutate({\n mutation: gql`\n mutation ($ids: [String!]!) {\n deleteSalesProducts(ids: $ids)\n }\n `,\n variables: { ids }\n })\n if (response.errors?.length) throw response\n this.grist.fetch()\n } catch (error: any) {\n notify({ level: 'error', message: error?.graphQLErrors?.[0]?.message ?? error?.errors?.[0]?.message ?? error?.message ?? String(error) })\n }\n }\n}\n"]}
1
+ {"version":3,"file":"sales-product-list.js","sourceRoot":"","sources":["../../client/pages/sales-product-list.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist/ox-grist.js'\nimport '@operato/data-grist/ox-filters-form.js'\nimport '@operato/input/ox-input-select-buttons.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 { notify } from '@operato/layout'\nimport { OxPrompt } from '@operato/popup/ox-prompt.js'\nimport { PageView } from '@operato/shell'\nimport { CommonButtonStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\nimport { documentNumber } from '@things-factory/invoice/dist-client'\n\nimport { salesProductKindWord } from '../sales-product-words'\n\nconst KINDS = ['GOODS', 'SERVICE', 'LABOR']\n\n/** The fields a row writes - all of them for a new row, the changed ones otherwise. */\nconst FIELDS = ['code', 'name', 'kind', 'grade', 'spec', 'unit', 'unitPrice', 'currency', 'taxKind', 'active', 'description']\n\n/**\n * 상품 — what the domain sells and the price it offers it at: goods, a service, or labor by the grade of the people\n * (ADR-0171). Typed like a spreadsheet and saved together. A quotation line chosen from a product copies it at that\n * moment; changing a price here changes no written quotation. The headroom narrows it to the products in use or out of\n * use, each chip with how many it holds under the other conditions.\n */\n@customElement('sales-product-list')\nexport class SalesProductList extends localize(i18next)(PageView) {\n static styles = [WorkSurfacePageStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles]\n\n @state() gristConfig: any\n /* In use or out of use - none chosen is every product. */\n @state() private inUse = ''\n @state() private activeCounts = new Map<string, number>()\n @query('ox-grist') private grist!: DataGrist\n\n get context() {\n return {\n title: i18next.t('title.sales-product-list'),\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n },\n filter: {\n handler: () => {\n this.grist.toggleHeadroom()\n }\n },\n actions: [\n { title: i18next.t('button.add'), icon: 'add', action: () => this.grist.addRecordToTop({ kind: 'GOODS', currency: 'KRW', taxKind: 'TAXABLE', active: true }) },\n { title: i18next.t('button.delete'), action: () => this.delete(), ...CommonButtonStyles.delete },\n { title: i18next.t('button.save'), action: () => this.save(), ...CommonButtonStyles.save }\n ],\n exportable: { name: i18next.t('title.sales-product-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 >\n <div slot=\"headroom\" class=\"header\">\n <div class=\"filters\">\n <ox-filters-form without-search autofocus></ox-filters-form>\n <ox-input-select-buttons\n .options=${['active', 'inactive'].map(value => ({ value, display: i18next.t(`text.sales-product-${value}`), count: this.activeCounts.get(value) ?? 0 }))}\n .value=${this.inUse || undefined}\n @change=${(e: CustomEvent) => ((this.inUse = (e.detail as string) || ''), this.grist.fetch())}\n ></ox-input-select-buttons>\n </div>\n </div>\n </ox-grist>`\n }\n\n async pageInitialized() {\n const text = (name: string, header: string, width: number, extra: any = {}) => ({ type: 'string', name, header, width, sortable: true, ...extra, record: { editable: true, ...extra.record } })\n this.gristConfig = {\n rows: { appendable: true, selectable: { multiple: true } },\n pagination: { limit: 100, pages: [50, 100, 500] },\n emptyNote: { title: i18next.t('text.sales-product-empty'), description: i18next.t('text.sales-product-empty-description') },\n list: { fields: ['name', 'code'], details: ['kind', 'unit', 'unitPrice'] },\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n { type: 'gutter', gutterName: 'row-selector', multiple: true },\n text('code', i18next.t('field.sales-product-code'), 110, { record: { mandatory: true } }),\n text('name', i18next.t('field.sales-product-name'), 200, { record: { mandatory: true } }),\n {\n type: 'select',\n name: 'kind',\n header: i18next.t('field.sales-product-kind'),\n width: 80,\n sortable: true,\n record: { editable: true, options: KINDS.map(kind => ({ value: kind, display: salesProductKindWord(kind) })) },\n filter: { type: 'select', operator: 'eq', options: [{ display: '', value: '' }, ...KINDS.map(kind => ({ display: salesProductKindWord(kind), value: kind }))] }\n },\n text('grade', i18next.t('field.sales-product-grade'), 110),\n text('spec', i18next.t('field.sales-product-spec'), 160),\n text('unit', i18next.t('field.sales-product-unit'), 70, { record: { align: 'center' } }),\n {\n type: 'float',\n name: 'unitPrice',\n header: i18next.t('field.sales-product-unit-price'),\n width: 130,\n sortable: true,\n record: { editable: true, align: 'right', renderer: (value: number, _c: any, record: any) => documentNumber(value, record?.currency || 'KRW') }\n },\n text('currency', i18next.t('field.sales-product-currency'), 70, { record: { align: 'center' } }),\n {\n type: 'select',\n name: 'taxKind',\n header: i18next.t('field.sales-product-tax-kind'),\n width: 80,\n record: {\n editable: true,\n options: [\n { value: 'TAXABLE', display: i18next.t('text.tax-kind-taxable') },\n { value: 'ZERO_RATED', display: i18next.t('text.tax-kind-zero-rated') },\n { value: 'EXEMPT', display: i18next.t('text.tax-kind-exempt') }\n ]\n }\n },\n { type: 'checkbox', name: 'active', header: i18next.t('field.sales-product-active'), width: 60, sortable: true, record: { editable: true } },\n text('description', i18next.t('field.sales-product-description'), 220)\n ],\n sorters: [{ name: 'code' }]\n }\n }\n\n async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [], search }: FetchOption) {\n search = search?.trim() || undefined\n this.countActive(filters, search)\n if (this.inUse) filters = [...filters, { name: 'active', operator: this.inUse === 'active' ? 'is_true' : 'is_not_true', value: null }]\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $search: String) {\n responses: salesProducts(filters: $filters, pagination: $pagination, sortings: $sortings, search: $search) {\n items { id code name kind grade spec unit unitPrice currency taxKind active description }\n total\n }\n }\n `,\n variables: { filters, pagination: { page, limit }, sortings, search },\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 /* The in-use chips' numbers, on the list's filters before the chip is added. */\n private async countActive(filters: any[], search?: string) {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $search: String) {\n salesProductActiveCounts(filters: $filters, search: $search) { value count }\n }\n `,\n variables: { filters, search },\n fetchPolicy: 'no-cache'\n })\n if (response.errors?.length) return console.error(response.errors)\n this.activeCounts = new Map(response.data.salesProductActiveCounts.map((row: { value: string; count: number }) => [row.value, row.count]))\n }\n\n /** New, changed and deleted rows together; a refusal is said in the server's words and nothing is kept. */\n private async save() {\n const patches = this.grist.dirtyRecords.map((record: any) => {\n const changed = record.__dirty__ === '+' ? FIELDS.filter(field => record[field] !== undefined) : Object.keys(record.__dirtyfields__ ?? {}).filter(field => FIELDS.includes(field))\n return { ...(record.id ? { id: record.id } : {}), cuFlag: record.__dirty__, ...Object.fromEntries(changed.map(field => [field, record[field] === '' ? null : record[field]])) }\n })\n if (!patches.length) return\n try {\n const response = await client.mutate({\n mutation: gql`\n mutation ($patches: [SalesProductPatch!]!) {\n updateMultipleSalesProduct(patches: $patches) { id }\n }\n `,\n variables: { patches }\n })\n if (response.errors?.length) throw response\n notify({ level: 'info', message: i18next.t('text.sales-product-saved') })\n this.grist.fetch()\n } catch (error: any) {\n notify({ level: 'error', message: error?.graphQLErrors?.[0]?.message ?? error?.errors?.[0]?.message ?? error?.message ?? String(error) })\n }\n }\n\n private async delete() {\n const ids = this.grist.selected.map((record: any) => record.id).filter(Boolean)\n if (!ids.length) return\n const confirmed = await OxPrompt.open({\n title: i18next.t('button.delete'),\n text: i18next.t('text.sales-product-delete-confirm', { count: ids.length }),\n confirmButton: { text: i18next.t('button.delete'), destructive: true },\n cancelButton: { text: i18next.t('button.cancel') }\n })\n if (!confirmed) return\n try {\n const response = await client.mutate({\n mutation: gql`\n mutation ($ids: [String!]!) {\n deleteSalesProducts(ids: $ids)\n }\n `,\n variables: { ids }\n })\n if (response.errors?.length) throw response\n this.grist.fetch()\n } catch (error: any) {\n notify({ level: 'error', message: error?.graphQLErrors?.[0]?.message ?? error?.errors?.[0]?.message ?? error?.message ?? String(error) })\n }\n }\n}\n"]}