@things-factory/saas 10.1.240 → 10.1.242

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 (76) hide show
  1. package/README.md +11 -11
  2. package/dist-client/entity360/saas-account-360.d.ts +0 -1
  3. package/dist-client/entity360/saas-account-360.js +18 -71
  4. package/dist-client/entity360/saas-account-360.js.map +1 -1
  5. package/dist-client/index.d.ts +0 -3
  6. package/dist-client/index.js +0 -3
  7. package/dist-client/index.js.map +1 -1
  8. package/dist-client/pages/saas-account-list.d.ts +1 -1
  9. package/dist-client/pages/saas-account-list.js +5 -14
  10. package/dist-client/pages/saas-account-list.js.map +1 -1
  11. package/dist-client/pages/saas-account-page.d.ts +3 -5
  12. package/dist-client/pages/saas-account-page.js +30 -55
  13. package/dist-client/pages/saas-account-page.js.map +1 -1
  14. package/dist-client/route.d.ts +1 -1
  15. package/dist-client/route.js +0 -3
  16. package/dist-client/route.js.map +1 -1
  17. package/dist-client/tsconfig.tsbuildinfo +1 -1
  18. package/dist-client/words.d.ts +0 -13
  19. package/dist-client/words.js +0 -17
  20. package/dist-client/words.js.map +1 -1
  21. package/dist-server/service/checks.d.ts +1 -9
  22. package/dist-server/service/checks.js +2 -18
  23. package/dist-server/service/checks.js.map +1 -1
  24. package/dist-server/service/index.d.ts +1 -6
  25. package/dist-server/service/index.js +1 -9
  26. package/dist-server/service/index.js.map +1 -1
  27. package/dist-server/service/saas-account.d.ts +0 -4
  28. package/dist-server/service/saas-account.js +1 -16
  29. package/dist-server/service/saas-account.js.map +1 -1
  30. package/dist-server/service/saas-mutation.d.ts +1 -10
  31. package/dist-server/service/saas-mutation.js +1 -86
  32. package/dist-server/service/saas-mutation.js.map +1 -1
  33. package/dist-server/service/saas-query.d.ts +2 -51
  34. package/dist-server/service/saas-query.js +2 -65
  35. package/dist-server/service/saas-query.js.map +1 -1
  36. package/dist-server/service/saas-rules.d.ts +3 -141
  37. package/dist-server/service/saas-rules.js +10 -213
  38. package/dist-server/service/saas-rules.js.map +1 -1
  39. package/dist-server/service/saas-service.d.ts +2 -125
  40. package/dist-server/service/saas-service.js +50 -438
  41. package/dist-server/service/saas-service.js.map +1 -1
  42. package/dist-server/service/saas-subscription.d.ts +4 -5
  43. package/dist-server/service/saas-subscription.js +11 -21
  44. package/dist-server/service/saas-subscription.js.map +1 -1
  45. package/dist-server/service/saas-sync.d.ts +0 -35
  46. package/dist-server/service/saas-sync.js +0 -60
  47. package/dist-server/service/saas-sync.js.map +1 -1
  48. package/dist-server/service/saas-type.d.ts +0 -93
  49. package/dist-server/service/saas-type.js +3 -351
  50. package/dist-server/service/saas-type.js.map +1 -1
  51. package/dist-server/tsconfig.tsbuildinfo +1 -1
  52. package/package.json +10 -10
  53. package/translations/en.json +3 -81
  54. package/translations/es.json +3 -81
  55. package/translations/ja.json +3 -81
  56. package/translations/ko.json +3 -81
  57. package/translations/ms.json +3 -81
  58. package/translations/zh.json +3 -81
  59. package/dist-client/components/saas-bill-editor.d.ts +0 -59
  60. package/dist-client/components/saas-bill-editor.js +0 -211
  61. package/dist-client/components/saas-bill-editor.js.map +0 -1
  62. package/dist-client/components/saas-candidates.d.ts +0 -33
  63. package/dist-client/components/saas-candidates.js +0 -157
  64. package/dist-client/components/saas-candidates.js.map +0 -1
  65. package/dist-client/pages/saas-cost-trend.d.ts +0 -23
  66. package/dist-client/pages/saas-cost-trend.js +0 -219
  67. package/dist-client/pages/saas-cost-trend.js.map +0 -1
  68. package/dist-server/service/saas-bill.d.ts +0 -42
  69. package/dist-server/service/saas-bill.js +0 -165
  70. package/dist-server/service/saas-bill.js.map +0 -1
  71. package/dist-server/service/saas-hidden-vendor.d.ts +0 -19
  72. package/dist-server/service/saas-hidden-vendor.js +0 -53
  73. package/dist-server/service/saas-hidden-vendor.js.map +0 -1
  74. package/dist-server/service/saas-trend-type.d.ts +0 -9
  75. package/dist-server/service/saas-trend-type.js +0 -37
  76. package/dist-server/service/saas-trend-type.js.map +0 -1
@@ -1,211 +0,0 @@
1
- import { __decorate, __metadata } from "tslib";
2
- import '@material/web/button/filled-button.js';
3
- import '@material/web/button/text-button.js';
4
- import '@operato/data-grist/ox-grist.js';
5
- import '@operato/popup/ox-popup-actions.js';
6
- import gql from 'graphql-tag';
7
- import { css, html, LitElement } from 'lit';
8
- import { customElement, property, query, state } from 'lit/decorators.js';
9
- import { DataGrist } from '@operato/data-grist';
10
- import { client } from '@operato/graphql';
11
- import { i18next, localize } from '@operato/i18n';
12
- import { notify, openPopup } from '@operato/layout';
13
- import { closePopup } from '@operato/popup';
14
- import { CommonPopupStyles } from '@operato/styles';
15
- import { failureOf } from '@things-factory/asset/dist-client/grid.js';
16
- import { amountText, fieldWord, shiftMonth, thisMonth } from '../words.js';
17
- /**
18
- * One bill of an account for a month (ADR-0177 decisions 5, 9): a line a subscription - a new bill starts with one for each
19
- * in use - and lines on none for tax and credits. Saved whole; the cost trend is read from these.
20
- */
21
- let SaasBillEditor = class SaasBillEditor extends localize(i18next)(LitElement) {
22
- constructor() {
23
- super(...arguments);
24
- this.accountId = '';
25
- this.currency = '';
26
- this.subscriptions = [];
27
- this.month = shiftMonth(thisMonth(), -1);
28
- this.billedOn = '';
29
- this.description = '';
30
- this.total = 0;
31
- /* The lines it opens with - set once, so a re-render does not put them back over what was typed. */
32
- this.initial = { records: [], total: 0 };
33
- }
34
- static { this.styles = [
35
- CommonPopupStyles,
36
- css `
37
- :host {
38
- display: flex;
39
- flex-direction: column;
40
- background-color: var(--md-sys-color-surface);
41
- min-height: 420px;
42
- }
43
- .fields {
44
- display: flex;
45
- flex-wrap: wrap;
46
- gap: var(--spacing-medium, 8px) var(--spacing-large, 12px);
47
- padding: var(--spacing-large, 12px);
48
- }
49
- label {
50
- display: flex;
51
- flex-direction: column;
52
- gap: 4px;
53
- font-size: var(--ui-t-caption, 12px);
54
- color: var(--md-sys-color-on-surface-variant);
55
- }
56
- label.wide {
57
- flex: 1;
58
- min-width: 200px;
59
- }
60
- input {
61
- height: 32px;
62
- padding: 0 8px;
63
- border: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));
64
- border-radius: var(--md-sys-shape-corner-small, 4px);
65
- background: var(--md-sys-color-surface);
66
- color: var(--md-sys-color-on-surface);
67
- font: inherit;
68
- font-size: var(--ui-t-body, 14px);
69
- }
70
- .total {
71
- padding: 0 var(--spacing-large, 12px) var(--spacing-medium, 8px);
72
- text-align: right;
73
- font-size: var(--ui-t-body, 14px);
74
- }
75
- ox-grist {
76
- flex: 1;
77
- overflow-y: auto;
78
- }
79
- `
80
- ]; }
81
- static open(options) {
82
- const title = options.bill ? i18next.t('title.saas-bill-edit', { month: options.bill.month }) : i18next.t('title.saas-bill-new');
83
- return openPopup(html `<saas-bill-editor .accountId=${options.accountId} .currency=${options.currency} .subscriptions=${options.subscriptions} .bill=${options.bill} .saved=${options.saved}></saas-bill-editor>`, { backdrop: true, size: 'large', title });
84
- }
85
- connectedCallback() {
86
- super.connectedCallback();
87
- if (this.bill) {
88
- this.month = this.bill.month;
89
- this.billedOn = this.bill.billedOn ?? '';
90
- this.description = this.bill.description ?? '';
91
- }
92
- const records = this.lines;
93
- this.initial = { records, total: records.length };
94
- const options = [{ value: '', display: i18next.t('text.saas-bill-line-none') }, ...this.subscriptions.map(one => ({ value: one.id, display: one.name }))];
95
- this.gristConfig = {
96
- rows: { appendable: true, selectable: { multiple: true } },
97
- pagination: { infinite: true },
98
- columns: [
99
- { type: 'gutter', gutterName: 'sequence' },
100
- { type: 'gutter', gutterName: 'row-selector', multiple: true },
101
- { type: 'select', name: 'subscriptionId', header: fieldWord('saas-bill-line', 'subscription'), width: 240, record: { editable: true, options } },
102
- { type: 'string', name: 'label', header: fieldWord('saas-bill-line', 'label'), width: 160, record: { editable: true } },
103
- { type: 'float', name: 'amount', header: fieldWord('saas-bill-line', 'amount') + ` (${this.currency})`, width: 140, record: { editable: true, align: 'right', renderer: (value) => amountText(value) } }
104
- ]
105
- };
106
- }
107
- get lines() {
108
- return this.bill
109
- ? this.bill.lines.map(line => ({ subscriptionId: line.subscription?.id ?? '', label: line.label ?? '', amount: line.amount }))
110
- : this.subscriptions.filter(one => one.status !== 'CANCELLED' && one.billing !== 'OWNED').map(one => ({ subscriptionId: one.id, label: '', amount: null }));
111
- }
112
- render() {
113
- return html `
114
- <div class="fields">
115
- <label>${fieldWord('saas-bill', 'month')} (YYYY-MM)<input type="month" .value=${this.month} @change=${(e) => (this.month = e.target.value)} /></label>
116
- <label>${fieldWord('saas-bill', 'billedOn')}<input type="date" .value=${this.billedOn} @change=${(e) => (this.billedOn = e.target.value)} /></label>
117
- <label class="wide">${fieldWord('saas-bill', 'description')}<input .value=${this.description} @change=${(e) => (this.description = e.target.value)} /></label>
118
- </div>
119
- <ox-grist .mode=${'GRID'} .config=${this.gristConfig} .data=${this.initial} @field-change=${() => this.sum()}></ox-grist>
120
- <div class="total">${i18next.t('text.saas-bill-total', { total: amountText(this.total), currency: this.currency })}</div>
121
- <ox-popup-actions>
122
- <md-text-button slot="start" @click=${() => this.grist.addRecord({ subscriptionId: '', label: '', amount: null })}>${i18next.t('button.saas-bill-add-line')}</md-text-button>
123
- <md-text-button slot="cancel" @click=${() => closePopup(this)}>${i18next.t('button.cancel')}</md-text-button>
124
- <md-filled-button slot="confirm" @click=${() => this.save()}>${i18next.t('button.save')}</md-filled-button>
125
- </ox-popup-actions>
126
- `;
127
- }
128
- firstUpdated() {
129
- this.sum();
130
- }
131
- records() {
132
- return (this.grist?.dirtyData?.records ?? this.grist?.data?.records ?? []);
133
- }
134
- sum() {
135
- this.total = this.records()
136
- .filter(one => one.__dirty__ !== '-')
137
- .reduce((sum, one) => sum + (Number(one.amount) || 0), 0);
138
- }
139
- async save() {
140
- const lines = this.records()
141
- .filter(one => one.__dirty__ !== '-' && (one.subscriptionId || one.label || Number(one.amount)))
142
- .map(one => ({ subscriptionId: one.subscriptionId || null, label: one.label || null, amount: Number(one.amount) || 0 }));
143
- try {
144
- const response = await client.mutate({
145
- mutation: gql `
146
- mutation ($accountId: String!, $bill: SaasBillInput!) {
147
- saveSaasBill(accountId: $accountId, bill: $bill) { id }
148
- }
149
- `,
150
- variables: { accountId: this.accountId, bill: { id: this.bill?.id, month: this.month, billedOn: this.billedOn || null, description: this.description || null, lines } }
151
- });
152
- if (response.errors?.length)
153
- throw response;
154
- notify({ level: 'info', message: i18next.t('text.saas-bill-saved', { month: this.month }) });
155
- this.saved?.();
156
- closePopup(this);
157
- }
158
- catch (error) {
159
- notify({ level: 'error', message: failureOf(error) });
160
- }
161
- }
162
- };
163
- __decorate([
164
- property(),
165
- __metadata("design:type", Object)
166
- ], SaasBillEditor.prototype, "accountId", void 0);
167
- __decorate([
168
- property(),
169
- __metadata("design:type", Object)
170
- ], SaasBillEditor.prototype, "currency", void 0);
171
- __decorate([
172
- property({ type: Array }),
173
- __metadata("design:type", Array)
174
- ], SaasBillEditor.prototype, "subscriptions", void 0);
175
- __decorate([
176
- property({ type: Object }),
177
- __metadata("design:type", Object)
178
- ], SaasBillEditor.prototype, "bill", void 0);
179
- __decorate([
180
- property({ type: Object }),
181
- __metadata("design:type", Function)
182
- ], SaasBillEditor.prototype, "saved", void 0);
183
- __decorate([
184
- state(),
185
- __metadata("design:type", Object)
186
- ], SaasBillEditor.prototype, "month", void 0);
187
- __decorate([
188
- state(),
189
- __metadata("design:type", Object)
190
- ], SaasBillEditor.prototype, "billedOn", void 0);
191
- __decorate([
192
- state(),
193
- __metadata("design:type", Object)
194
- ], SaasBillEditor.prototype, "description", void 0);
195
- __decorate([
196
- state(),
197
- __metadata("design:type", Object)
198
- ], SaasBillEditor.prototype, "total", void 0);
199
- __decorate([
200
- state(),
201
- __metadata("design:type", Object)
202
- ], SaasBillEditor.prototype, "gristConfig", void 0);
203
- __decorate([
204
- query('ox-grist'),
205
- __metadata("design:type", DataGrist)
206
- ], SaasBillEditor.prototype, "grist", void 0);
207
- SaasBillEditor = __decorate([
208
- customElement('saas-bill-editor')
209
- ], SaasBillEditor);
210
- export { SaasBillEditor };
211
- //# sourceMappingURL=saas-bill-editor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"saas-bill-editor.js","sourceRoot":"","sources":["../../client/components/saas-bill-editor.ts"],"names":[],"mappings":";AAAA,OAAO,uCAAuC,CAAA;AAC9C,OAAO,qCAAqC,CAAA;AAC5C,OAAO,iCAAiC,CAAA;AACxC,OAAO,oCAAoC,CAAA;AAE3C,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAEzE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,2CAA2C,CAAA;AAErE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAK1E;;;GAGG;AAEI,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAA1D;;QAiDO,cAAS,GAAG,EAAE,CAAA;QACd,aAAQ,GAAG,EAAE,CAAA;QACE,kBAAa,GAAmB,EAAE,CAAA;QAIpD,UAAK,GAAG,UAAU,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;QACnC,aAAQ,GAAG,EAAE,CAAA;QACb,gBAAW,GAAG,EAAE,CAAA;QAChB,UAAK,GAAG,CAAC,CAAA;QAElB,oGAAoG;QAC5F,YAAO,GAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAA;IA4FlD,CAAC;aAxJQ,WAAM,GAAG;QACd,iBAAiB;QACjB,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2CF;KACF,AA9CY,CA8CZ;IAiBD,MAAM,CAAC,IAAI,CAAC,OAAgH;QAC1H,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAA;QAChI,OAAO,SAAS,CACd,IAAI,CAAA,gCAAgC,OAAO,CAAC,SAAS,cAAc,OAAO,CAAC,QAAQ,mBAAmB,OAAO,CAAC,aAAa,UAAU,OAAO,CAAC,IAAI,WAAW,OAAO,CAAC,KAAK,sBAAsB,EAC/L,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CACzC,CAAA;IACH,CAAC;IAED,iBAAiB;QACf,KAAK,CAAC,iBAAiB,EAAE,CAAA;QACzB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAA;YAC5B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAA;YACxC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAA;QAChD,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAA;QAC1B,IAAI,CAAC,OAAO,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,CAAA;QACjD,MAAM,OAAO,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QACzJ,IAAI,CAAC,WAAW,GAAG;YACjB,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;YAC1D,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;YAC9B,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE;gBAC1C,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC9D,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,CAAC,gBAAgB,EAAE,cAAc,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;gBAChJ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,gBAAgB,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;gBACvH,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,gBAAgB,EAAE,QAAQ,CAAC,GAAG,KAAK,IAAI,CAAC,QAAQ,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,EAAE;aACjN;SACF,CAAA;IACH,CAAC;IAED,IAAY,KAAK;QACf,OAAO,IAAI,CAAC,IAAI;YACd,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YAC9H,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,WAAW,IAAI,GAAG,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAC/J,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAA;;iBAEE,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,wCAAwC,IAAI,CAAC,KAAK,YAAY,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;iBACtI,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC,6BAA6B,IAAI,CAAC,QAAQ,YAAY,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;8BACvH,SAAS,CAAC,WAAW,EAAE,aAAa,CAAC,iBAAiB,IAAI,CAAC,WAAW,YAAY,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;;wBAEvI,MAAM,YAAY,IAAI,CAAC,WAAW,UAAU,IAAI,CAAC,OAAO,kBAAkB,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;2BACvF,OAAO,CAAC,CAAC,CAAC,sBAAsB,EAAE,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;;8CAE1E,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC;+CACpH,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;kDACjD,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;;KAE1F,CAAA;IACH,CAAC;IAED,YAAY;QACV,IAAI,CAAC,GAAG,EAAE,CAAA;IACZ,CAAC;IAEO,OAAO;QACb,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,IAAI,EAAE,CAAU,CAAA;IACrF,CAAC;IAEO,GAAG;QACT,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE;aACxB,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,GAAG,CAAC;aACpC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC7D,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE;aACzB,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,KAAK,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;aAC/F,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;QAC1H,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC;gBACnC,QAAQ,EAAE,GAAG,CAAA;;;;SAIZ;gBACD,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI,EAAE,KAAK,EAAE,EAAE;aACxK,CAAC,CAAA;YACF,IAAK,QAAgB,CAAC,MAAM,EAAE,MAAM;gBAAE,MAAM,QAAQ,CAAA;YACpD,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,sBAAsB,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA;YAC5F,IAAI,CAAC,KAAK,EAAE,EAAE,CAAA;YACd,UAAU,CAAC,IAAI,CAAC,CAAA;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACvD,CAAC;IACH,CAAC;;AAvGW;IAAX,QAAQ,EAAE;;iDAAe;AACd;IAAX,QAAQ,EAAE;;gDAAc;AACE;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;;qDAAmC;AACjC;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;4CAAY;AACX;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;6CAAmB;AAErC;IAAR,KAAK,EAAE;;6CAAoC;AACnC;IAAR,KAAK,EAAE;;gDAAc;AACb;IAAR,KAAK,EAAE;;mDAAiB;AAChB;IAAR,KAAK,EAAE;;6CAAU;AACT;IAAR,KAAK,EAAE;;mDAAiB;AAGE;IAA1B,KAAK,CAAC,UAAU,CAAC;8BAAiB,SAAS;6CAAA;AA9DjC,cAAc;IAD1B,aAAa,CAAC,kBAAkB,CAAC;GACrB,cAAc,CAyJ1B","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@operato/data-grist/ox-grist.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, 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, openPopup } from '@operato/layout'\nimport { closePopup } from '@operato/popup'\nimport { CommonPopupStyles } from '@operato/styles'\nimport { failureOf } from '@things-factory/asset/dist-client/grid.js'\n\nimport { amountText, fieldWord, shiftMonth, thisMonth } from '../words.js'\n\ntype Subscription = { id: string; name: string; billing: string; status: string }\ntype Bill = { id?: string; month: string; billedOn?: string | null; description?: string | null; lines: { subscription?: { id: string } | null; label?: string | null; amount: number }[] }\n\n/**\n * One bill of an account for a month (ADR-0177 decisions 5, 9): a line a subscription - a new bill starts with one for each\n * in use - and lines on none for tax and credits. Saved whole; the cost trend is read from these.\n */\n@customElement('saas-bill-editor')\nexport class SaasBillEditor extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n background-color: var(--md-sys-color-surface);\n min-height: 420px;\n }\n .fields {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-medium, 8px) var(--spacing-large, 12px);\n padding: var(--spacing-large, 12px);\n }\n label {\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: var(--ui-t-caption, 12px);\n color: var(--md-sys-color-on-surface-variant);\n }\n label.wide {\n flex: 1;\n min-width: 200px;\n }\n input {\n height: 32px;\n padding: 0 8px;\n border: 1px solid var(--ui-line-soft, var(--md-sys-color-outline-variant));\n border-radius: var(--md-sys-shape-corner-small, 4px);\n background: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n font: inherit;\n font-size: var(--ui-t-body, 14px);\n }\n .total {\n padding: 0 var(--spacing-large, 12px) var(--spacing-medium, 8px);\n text-align: right;\n font-size: var(--ui-t-body, 14px);\n }\n ox-grist {\n flex: 1;\n overflow-y: auto;\n }\n `\n ]\n\n @property() accountId = ''\n @property() currency = ''\n @property({ type: Array }) subscriptions: Subscription[] = []\n @property({ type: Object }) bill?: Bill\n @property({ type: Object }) saved?: () => void\n\n @state() month = shiftMonth(thisMonth(), -1)\n @state() billedOn = ''\n @state() description = ''\n @state() total = 0\n @state() gristConfig: any\n /* The lines it opens with - set once, so a re-render does not put them back over what was typed. */\n private initial: any = { records: [], total: 0 }\n @query('ox-grist') private grist!: DataGrist\n\n static open(options: { accountId: string; currency: string; subscriptions: Subscription[]; bill?: Bill; saved?: () => void }) {\n const title = options.bill ? i18next.t('title.saas-bill-edit', { month: options.bill.month }) : i18next.t('title.saas-bill-new')\n return openPopup(\n html`<saas-bill-editor .accountId=${options.accountId} .currency=${options.currency} .subscriptions=${options.subscriptions} .bill=${options.bill} .saved=${options.saved}></saas-bill-editor>`,\n { backdrop: true, size: 'large', title }\n )\n }\n\n connectedCallback() {\n super.connectedCallback()\n if (this.bill) {\n this.month = this.bill.month\n this.billedOn = this.bill.billedOn ?? ''\n this.description = this.bill.description ?? ''\n }\n const records = this.lines\n this.initial = { records, total: records.length }\n const options = [{ value: '', display: i18next.t('text.saas-bill-line-none') }, ...this.subscriptions.map(one => ({ value: one.id, display: one.name }))]\n this.gristConfig = {\n rows: { appendable: true, selectable: { multiple: true } },\n pagination: { infinite: true },\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n { type: 'gutter', gutterName: 'row-selector', multiple: true },\n { type: 'select', name: 'subscriptionId', header: fieldWord('saas-bill-line', 'subscription'), width: 240, record: { editable: true, options } },\n { type: 'string', name: 'label', header: fieldWord('saas-bill-line', 'label'), width: 160, record: { editable: true } },\n { type: 'float', name: 'amount', header: fieldWord('saas-bill-line', 'amount') + ` (${this.currency})`, width: 140, record: { editable: true, align: 'right', renderer: (value: number) => amountText(value) } }\n ]\n }\n }\n\n private get lines() {\n return this.bill\n ? this.bill.lines.map(line => ({ subscriptionId: line.subscription?.id ?? '', label: line.label ?? '', amount: line.amount }))\n : this.subscriptions.filter(one => one.status !== 'CANCELLED' && one.billing !== 'OWNED').map(one => ({ subscriptionId: one.id, label: '', amount: null }))\n }\n\n render() {\n return html`\n <div class=\"fields\">\n <label>${fieldWord('saas-bill', 'month')} (YYYY-MM)<input type=\"month\" .value=${this.month} @change=${(e: any) => (this.month = e.target.value)} /></label>\n <label>${fieldWord('saas-bill', 'billedOn')}<input type=\"date\" .value=${this.billedOn} @change=${(e: any) => (this.billedOn = e.target.value)} /></label>\n <label class=\"wide\">${fieldWord('saas-bill', 'description')}<input .value=${this.description} @change=${(e: any) => (this.description = e.target.value)} /></label>\n </div>\n <ox-grist .mode=${'GRID'} .config=${this.gristConfig} .data=${this.initial} @field-change=${() => this.sum()}></ox-grist>\n <div class=\"total\">${i18next.t('text.saas-bill-total', { total: amountText(this.total), currency: this.currency })}</div>\n <ox-popup-actions>\n <md-text-button slot=\"start\" @click=${() => this.grist.addRecord({ subscriptionId: '', label: '', amount: null })}>${i18next.t('button.saas-bill-add-line')}</md-text-button>\n <md-text-button slot=\"cancel\" @click=${() => closePopup(this)}>${i18next.t('button.cancel')}</md-text-button>\n <md-filled-button slot=\"confirm\" @click=${() => this.save()}>${i18next.t('button.save')}</md-filled-button>\n </ox-popup-actions>\n `\n }\n\n firstUpdated() {\n this.sum()\n }\n\n private records(): any[] {\n return (this.grist?.dirtyData?.records ?? this.grist?.data?.records ?? []) as any[]\n }\n\n private sum() {\n this.total = this.records()\n .filter(one => one.__dirty__ !== '-')\n .reduce((sum, one) => sum + (Number(one.amount) || 0), 0)\n }\n\n private async save() {\n const lines = this.records()\n .filter(one => one.__dirty__ !== '-' && (one.subscriptionId || one.label || Number(one.amount)))\n .map(one => ({ subscriptionId: one.subscriptionId || null, label: one.label || null, amount: Number(one.amount) || 0 }))\n try {\n const response = await client.mutate({\n mutation: gql`\n mutation ($accountId: String!, $bill: SaasBillInput!) {\n saveSaasBill(accountId: $accountId, bill: $bill) { id }\n }\n `,\n variables: { accountId: this.accountId, bill: { id: this.bill?.id, month: this.month, billedOn: this.billedOn || null, description: this.description || null, lines } }\n })\n if ((response as any).errors?.length) throw response\n notify({ level: 'info', message: i18next.t('text.saas-bill-saved', { month: this.month }) })\n this.saved?.()\n closePopup(this)\n } catch (error) {\n notify({ level: 'error', message: failureOf(error) })\n }\n }\n}\n"]}
@@ -1,33 +0,0 @@
1
- import '@material/web/button/filled-button.js';
2
- import '@material/web/button/text-button.js';
3
- import '@operato/data-grist/ox-grist.js';
4
- import '@operato/popup/ox-popup-actions.js';
5
- import { LitElement } from 'lit';
6
- declare const SaasCandidates_base: (new (...args: any[]) => LitElement) & typeof LitElement;
7
- /**
8
- * 장부에서 찾기 (ADR-0177 개정 1) - whom the bank and card lines show paid month after month that is no account or
9
- * recurring item yet, a registered counterparty or a name the lines carry. Picked ones become accounts with a usage
10
- * subscription at their monthly average (a name is registered as a counterparty); ones that are no subscription are
11
- * hidden, and can be shown again.
12
- */
13
- export declare class SaasCandidates extends SaasCandidates_base {
14
- static styles: import("lit").CSSResult[];
15
- made?: () => void;
16
- /** The hidden ones instead of the candidates. */
17
- hidden: boolean;
18
- data: any;
19
- private grist;
20
- private gristConfig;
21
- static open(options?: {
22
- made?: () => void;
23
- }): import("@operato/layout").PopupHandle<unknown>;
24
- connectedCallback(): void;
25
- render(): import("lit-html").TemplateResult<1>;
26
- private flip;
27
- private read;
28
- private picked;
29
- private run;
30
- private create;
31
- private hide;
32
- }
33
- export {};
@@ -1,157 +0,0 @@
1
- import { __decorate, __metadata } from "tslib";
2
- import '@material/web/button/filled-button.js';
3
- import '@material/web/button/text-button.js';
4
- import '@operato/data-grist/ox-grist.js';
5
- import '@operato/popup/ox-popup-actions.js';
6
- import gql from 'graphql-tag';
7
- import { css, html, LitElement } from 'lit';
8
- import { customElement, property, query, state } from 'lit/decorators.js';
9
- import { DataGrist } from '@operato/data-grist';
10
- import { client } from '@operato/graphql';
11
- import { i18next, localize } from '@operato/i18n';
12
- import { notify, openPopup } from '@operato/layout';
13
- import { closePopup } from '@operato/popup';
14
- import { CommonPopupStyles } from '@operato/styles';
15
- import { failureOf } from '@things-factory/asset/dist-client/grid.js';
16
- import { amountText, fieldWord } from '../words.js';
17
- const CANDIDATES = gql `
18
- query ($hidden: Boolean) {
19
- saasCandidates(hidden: $hidden) { key counterpartyId counterpartyName months average firstDate lastDate lastAmount currency billingDay }
20
- }
21
- `;
22
- /**
23
- * 장부에서 찾기 (ADR-0177 개정 1) - whom the bank and card lines show paid month after month that is no account or
24
- * recurring item yet, a registered counterparty or a name the lines carry. Picked ones become accounts with a usage
25
- * subscription at their monthly average (a name is registered as a counterparty); ones that are no subscription are
26
- * hidden, and can be shown again.
27
- */
28
- let SaasCandidates = class SaasCandidates extends localize(i18next)(LitElement) {
29
- constructor() {
30
- super(...arguments);
31
- /** The hidden ones instead of the candidates. */
32
- this.hidden = false;
33
- this.data = { records: [], total: 0 };
34
- this.gristConfig = {
35
- rows: { appendable: false, selectable: { multiple: true } },
36
- pagination: { infinite: true },
37
- columns: [
38
- { type: 'gutter', gutterName: 'sequence' },
39
- { type: 'gutter', gutterName: 'row-selector', multiple: true },
40
- { type: 'string', name: 'counterpartyName', header: fieldWord('saas-candidate', 'counterparty'), width: 200 },
41
- { type: 'integer', name: 'months', header: fieldWord('saas-candidate', 'months'), width: 90, record: { align: 'right' } },
42
- { type: 'float', name: 'average', header: fieldWord('saas-candidate', 'average'), width: 130, record: { align: 'right', renderer: (value, _c, record) => `${amountText(value)} ${record?.currency ?? ''}` } },
43
- { type: 'string', name: 'lastDate', header: fieldWord('saas-candidate', 'last'), width: 200, record: { renderer: (value, _c, record) => `${value} · ${amountText(record?.lastAmount)}` } },
44
- { type: 'integer', name: 'billingDay', header: fieldWord('saas-account', 'billingDay'), width: 80, record: { align: 'right', renderer: (value) => (value === 31 ? i18next.t('text.saas-candidate-month-end') : value ?? '') } }
45
- ]
46
- };
47
- }
48
- static { this.styles = [
49
- CommonPopupStyles,
50
- css `
51
- :host {
52
- display: flex;
53
- flex-direction: column;
54
- background-color: var(--md-sys-color-surface);
55
- min-height: 420px;
56
- }
57
- .note {
58
- padding: var(--spacing-medium, 8px) var(--spacing-large, 12px);
59
- font-size: var(--ui-t-caption, 12px);
60
- color: var(--md-sys-color-on-surface-variant);
61
- }
62
- ox-grist {
63
- flex: 1;
64
- overflow-y: auto;
65
- }
66
- `
67
- ]; }
68
- static open(options = {}) {
69
- return openPopup(html `<saas-candidates .made=${options.made}></saas-candidates>`, { backdrop: true, size: 'large', title: i18next.t('title.saas-candidates') });
70
- }
71
- connectedCallback() {
72
- super.connectedCallback();
73
- this.read();
74
- }
75
- render() {
76
- return html `
77
- <div class="note">${i18next.t(this.hidden ? 'text.saas-candidates-hidden-note' : 'text.saas-candidates-note')}</div>
78
- <ox-grist .mode=${'GRID'} .config=${this.gristConfig} .data=${this.data}></ox-grist>
79
- <ox-popup-actions>
80
- <md-text-button slot="start" @click=${() => this.flip()}>${i18next.t(this.hidden ? 'button.saas-candidates-show' : 'button.saas-candidates-hidden')}</md-text-button>
81
- <md-text-button slot="cancel" @click=${() => closePopup(this)}>${i18next.t('button.close')}</md-text-button>
82
- ${this.hidden
83
- ? html `<md-filled-button slot="confirm" @click=${() => this.hide(false)}>${i18next.t('button.saas-candidates-unhide')}</md-filled-button>`
84
- : html `<md-text-button slot="cancel" @click=${() => this.hide(true)}>${i18next.t('button.saas-candidates-hide')}</md-text-button>
85
- <md-filled-button slot="confirm" @click=${() => this.create()}>${i18next.t('button.saas-candidates-create')}</md-filled-button>`}
86
- </ox-popup-actions>
87
- `;
88
- }
89
- async flip() {
90
- this.hidden = !this.hidden;
91
- await this.read();
92
- }
93
- async read() {
94
- try {
95
- const response = await client.query({ query: CANDIDATES, variables: { hidden: this.hidden }, fetchPolicy: 'no-cache' });
96
- if (response.errors?.length)
97
- throw response;
98
- const records = response.data.saasCandidates;
99
- this.data = { records, total: records.length };
100
- }
101
- catch (error) {
102
- notify({ level: 'error', message: failureOf(error) });
103
- }
104
- }
105
- picked() {
106
- return (this.grist?.selected ?? []).map(one => one.key);
107
- }
108
- async run(mutation, variables) {
109
- const ids = this.picked();
110
- if (!ids.length) {
111
- notify({ level: 'warn', message: i18next.t('text.saas-candidates-pick') });
112
- return false;
113
- }
114
- try {
115
- const response = await client.mutate({ mutation, variables: { ...variables, keys: ids } });
116
- if (response.errors?.length)
117
- throw response;
118
- await this.read();
119
- return true;
120
- }
121
- catch (error) {
122
- notify({ level: 'error', message: failureOf(error) });
123
- return false;
124
- }
125
- }
126
- async create() {
127
- const count = this.picked().length;
128
- if (await this.run(gql `mutation ($keys: [String!]!) { createSaasAccountsFromCandidates(keys: $keys) { id } }`, {})) {
129
- notify({ level: 'info', message: i18next.t('text.saas-candidates-made', { count }) });
130
- this.made?.();
131
- }
132
- }
133
- async hide(hide) {
134
- await this.run(gql `mutation ($keys: [String!]!, $hide: Boolean!) { hideSaasCandidates(keys: $keys, hide: $hide) }`, { hide });
135
- }
136
- };
137
- __decorate([
138
- property({ type: Object }),
139
- __metadata("design:type", Function)
140
- ], SaasCandidates.prototype, "made", void 0);
141
- __decorate([
142
- state(),
143
- __metadata("design:type", Object)
144
- ], SaasCandidates.prototype, "hidden", void 0);
145
- __decorate([
146
- state(),
147
- __metadata("design:type", Object)
148
- ], SaasCandidates.prototype, "data", void 0);
149
- __decorate([
150
- query('ox-grist'),
151
- __metadata("design:type", DataGrist)
152
- ], SaasCandidates.prototype, "grist", void 0);
153
- SaasCandidates = __decorate([
154
- customElement('saas-candidates')
155
- ], SaasCandidates);
156
- export { SaasCandidates };
157
- //# sourceMappingURL=saas-candidates.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"saas-candidates.js","sourceRoot":"","sources":["../../client/components/saas-candidates.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@operato/data-grist/ox-grist.js'\nimport '@operato/popup/ox-popup-actions.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, 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, openPopup } from '@operato/layout'\nimport { closePopup } from '@operato/popup'\nimport { CommonPopupStyles } from '@operato/styles'\nimport { failureOf } from '@things-factory/asset/dist-client/grid.js'\n\nimport { amountText, fieldWord } from '../words.js'\n\nconst CANDIDATES = gql`\n query ($hidden: Boolean) {\n saasCandidates(hidden: $hidden) { key counterpartyId counterpartyName months average firstDate lastDate lastAmount currency billingDay }\n }\n`\n\n/**\n * 장부에서 찾기 (ADR-0177 개정 1) - whom the bank and card lines show paid month after month that is no account or\n * recurring item yet, a registered counterparty or a name the lines carry. Picked ones become accounts with a usage\n * subscription at their monthly average (a name is registered as a counterparty); ones that are no subscription are\n * hidden, and can be shown again.\n */\n@customElement('saas-candidates')\nexport class SaasCandidates extends localize(i18next)(LitElement) {\n static styles = [\n CommonPopupStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n background-color: var(--md-sys-color-surface);\n min-height: 420px;\n }\n .note {\n padding: var(--spacing-medium, 8px) var(--spacing-large, 12px);\n font-size: var(--ui-t-caption, 12px);\n color: var(--md-sys-color-on-surface-variant);\n }\n ox-grist {\n flex: 1;\n overflow-y: auto;\n }\n `\n ]\n\n @property({ type: Object }) made?: () => void\n\n /** The hidden ones instead of the candidates. */\n @state() hidden = false\n @state() data: any = { records: [], total: 0 }\n @query('ox-grist') private grist!: DataGrist\n\n private gristConfig = {\n rows: { appendable: false, selectable: { multiple: true } },\n pagination: { infinite: true },\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n { type: 'gutter', gutterName: 'row-selector', multiple: true },\n { type: 'string', name: 'counterpartyName', header: fieldWord('saas-candidate', 'counterparty'), width: 200 },\n { type: 'integer', name: 'months', header: fieldWord('saas-candidate', 'months'), width: 90, record: { align: 'right' } },\n { type: 'float', name: 'average', header: fieldWord('saas-candidate', 'average'), width: 130, record: { align: 'right', renderer: (value: number, _c: any, record: any) => `${amountText(value)} ${record?.currency ?? ''}` } },\n { type: 'string', name: 'lastDate', header: fieldWord('saas-candidate', 'last'), width: 200, record: { renderer: (value: string, _c: any, record: any) => `${value} · ${amountText(record?.lastAmount)}` } },\n { type: 'integer', name: 'billingDay', header: fieldWord('saas-account', 'billingDay'), width: 80, record: { align: 'right', renderer: (value: number) => (value === 31 ? i18next.t('text.saas-candidate-month-end') : value ?? '') } }\n ]\n }\n\n static open(options: { made?: () => void } = {}) {\n return openPopup(html`<saas-candidates .made=${options.made}></saas-candidates>`, { backdrop: true, size: 'large', title: i18next.t('title.saas-candidates') })\n }\n\n connectedCallback() {\n super.connectedCallback()\n this.read()\n }\n\n render() {\n return html`\n <div class=\"note\">${i18next.t(this.hidden ? 'text.saas-candidates-hidden-note' : 'text.saas-candidates-note')}</div>\n <ox-grist .mode=${'GRID'} .config=${this.gristConfig} .data=${this.data}></ox-grist>\n <ox-popup-actions>\n <md-text-button slot=\"start\" @click=${() => this.flip()}>${i18next.t(this.hidden ? 'button.saas-candidates-show' : 'button.saas-candidates-hidden')}</md-text-button>\n <md-text-button slot=\"cancel\" @click=${() => closePopup(this)}>${i18next.t('button.close')}</md-text-button>\n ${this.hidden\n ? html`<md-filled-button slot=\"confirm\" @click=${() => this.hide(false)}>${i18next.t('button.saas-candidates-unhide')}</md-filled-button>`\n : html`<md-text-button slot=\"cancel\" @click=${() => this.hide(true)}>${i18next.t('button.saas-candidates-hide')}</md-text-button>\n <md-filled-button slot=\"confirm\" @click=${() => this.create()}>${i18next.t('button.saas-candidates-create')}</md-filled-button>`}\n </ox-popup-actions>\n `\n }\n\n private async flip() {\n this.hidden = !this.hidden\n await this.read()\n }\n\n private async read() {\n try {\n const response: any = await client.query({ query: CANDIDATES, variables: { hidden: this.hidden }, fetchPolicy: 'no-cache' })\n if (response.errors?.length) throw response\n const records = response.data.saasCandidates\n this.data = { records, total: records.length }\n } catch (error) {\n notify({ level: 'error', message: failureOf(error) })\n }\n }\n\n private picked(): string[] {\n return ((this.grist?.selected ?? []) as any[]).map(one => one.key)\n }\n\n private async run(mutation: any, variables: any) {\n const ids = this.picked()\n if (!ids.length) {\n notify({ level: 'warn', message: i18next.t('text.saas-candidates-pick') })\n return false\n }\n try {\n const response: any = await client.mutate({ mutation, variables: { ...variables, keys: ids } })\n if (response.errors?.length) throw response\n await this.read()\n return true\n } catch (error) {\n notify({ level: 'error', message: failureOf(error) })\n return false\n }\n }\n\n private async create() {\n const count = this.picked().length\n if (await this.run(gql`mutation ($keys: [String!]!) { createSaasAccountsFromCandidates(keys: $keys) { id } }`, {})) {\n notify({ level: 'info', message: i18next.t('text.saas-candidates-made', { count }) })\n this.made?.()\n }\n }\n\n private async hide(hide: boolean) {\n await this.run(gql`mutation ($keys: [String!]!, $hide: Boolean!) { hideSaasCandidates(keys: $keys, hide: $hide) }`, { hide })\n }\n}\n"]}
@@ -1,23 +0,0 @@
1
- import { PageView } from '@operato/shell';
2
- declare const SaasCostTrend_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
3
- /**
4
- * 비용 추이 — what the subscriptions cost month by month, from their bills (ADR-0177 decision 9): everything, each account
5
- * with its subscriptions under it, each department, in each bill's own currency. What the latest bills are worth telling
6
- * comes first. Nothing here is stored; it is read from the bills each time.
7
- */
8
- export declare class SaasCostTrend extends SaasCostTrend_base {
9
- static styles: import("lit").CSSResult[];
10
- from: string;
11
- to: string;
12
- trend?: any;
13
- get context(): {
14
- title: string;
15
- };
16
- pageUpdated(changes: any): Promise<void>;
17
- private read;
18
- private change;
19
- private row;
20
- private head;
21
- render(): import("lit-html").TemplateResult<1>;
22
- }
23
- export {};