@things-factory/saas 10.1.240 → 10.1.241
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -11
- package/dist-client/entity360/saas-account-360.d.ts +0 -1
- package/dist-client/entity360/saas-account-360.js +18 -71
- package/dist-client/entity360/saas-account-360.js.map +1 -1
- package/dist-client/index.d.ts +0 -3
- package/dist-client/index.js +0 -3
- package/dist-client/index.js.map +1 -1
- package/dist-client/pages/saas-account-list.d.ts +1 -1
- package/dist-client/pages/saas-account-list.js +5 -14
- package/dist-client/pages/saas-account-list.js.map +1 -1
- package/dist-client/pages/saas-account-page.d.ts +3 -5
- package/dist-client/pages/saas-account-page.js +30 -55
- package/dist-client/pages/saas-account-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +0 -3
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/words.d.ts +0 -13
- package/dist-client/words.js +0 -17
- package/dist-client/words.js.map +1 -1
- package/dist-server/service/checks.d.ts +1 -9
- package/dist-server/service/checks.js +2 -18
- package/dist-server/service/checks.js.map +1 -1
- package/dist-server/service/index.d.ts +1 -6
- package/dist-server/service/index.js +1 -9
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/saas-account.d.ts +0 -4
- package/dist-server/service/saas-account.js +1 -16
- package/dist-server/service/saas-account.js.map +1 -1
- package/dist-server/service/saas-mutation.d.ts +1 -10
- package/dist-server/service/saas-mutation.js +1 -86
- package/dist-server/service/saas-mutation.js.map +1 -1
- package/dist-server/service/saas-query.d.ts +2 -51
- package/dist-server/service/saas-query.js +2 -65
- package/dist-server/service/saas-query.js.map +1 -1
- package/dist-server/service/saas-rules.d.ts +3 -141
- package/dist-server/service/saas-rules.js +10 -213
- package/dist-server/service/saas-rules.js.map +1 -1
- package/dist-server/service/saas-service.d.ts +2 -125
- package/dist-server/service/saas-service.js +50 -438
- package/dist-server/service/saas-service.js.map +1 -1
- package/dist-server/service/saas-subscription.d.ts +4 -5
- package/dist-server/service/saas-subscription.js +11 -21
- package/dist-server/service/saas-subscription.js.map +1 -1
- package/dist-server/service/saas-sync.d.ts +0 -35
- package/dist-server/service/saas-sync.js +0 -60
- package/dist-server/service/saas-sync.js.map +1 -1
- package/dist-server/service/saas-type.d.ts +0 -93
- package/dist-server/service/saas-type.js +3 -351
- package/dist-server/service/saas-type.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/translations/en.json +3 -81
- package/translations/es.json +3 -81
- package/translations/ja.json +3 -81
- package/translations/ko.json +3 -81
- package/translations/ms.json +3 -81
- package/translations/zh.json +3 -81
- package/dist-client/components/saas-bill-editor.d.ts +0 -59
- package/dist-client/components/saas-bill-editor.js +0 -211
- package/dist-client/components/saas-bill-editor.js.map +0 -1
- package/dist-client/components/saas-candidates.d.ts +0 -33
- package/dist-client/components/saas-candidates.js +0 -157
- package/dist-client/components/saas-candidates.js.map +0 -1
- package/dist-client/pages/saas-cost-trend.d.ts +0 -23
- package/dist-client/pages/saas-cost-trend.js +0 -219
- package/dist-client/pages/saas-cost-trend.js.map +0 -1
- package/dist-server/service/saas-bill.d.ts +0 -42
- package/dist-server/service/saas-bill.js +0 -165
- package/dist-server/service/saas-bill.js.map +0 -1
- package/dist-server/service/saas-hidden-vendor.d.ts +0 -19
- package/dist-server/service/saas-hidden-vendor.js +0 -53
- package/dist-server/service/saas-hidden-vendor.js.map +0 -1
- package/dist-server/service/saas-trend-type.d.ts +0 -9
- package/dist-server/service/saas-trend-type.js +0 -37
- package/dist-server/service/saas-trend-type.js.map +0 -1
package/README.md
CHANGED
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
What the company subscribes to online and pays for again and again — not only SaaS: cloud (AWS, Azure, GCP), domains and
|
|
4
4
|
certificates too — and the software licenses it owns (ADR-0177 in operato-application).
|
|
5
5
|
|
|
6
|
-
- **Account** — one account we hold with a vendor
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
- **Account** — one account we hold with a vendor (an AWS organization's payer account, a Microsoft 365 tenant, an Adobe
|
|
7
|
+
Admin Console, a registrar). An account under another (an AWS member account) names its purpose and admins only. No
|
|
8
|
+
password, key or recovery code is kept — only where it is kept.
|
|
9
9
|
- **Subscription** — one thing under an account we decide on and can cancel: a plan with seats, a fixed fee, metered
|
|
10
|
-
usage
|
|
11
|
-
|
|
12
|
-
- **Seat** — who holds one place of a subscription.
|
|
13
|
-
|
|
14
|
-
the bills, never stored.
|
|
10
|
+
usage, a commitment, or a license we own (which points at the asset register). Its quantity and unit price are a
|
|
11
|
+
reference only.
|
|
12
|
+
- **Seat** — who holds one place of a subscription. A Microsoft 365 or Google Workspace tenant keeps them in step
|
|
13
|
+
(`syncSaasLicenses`).
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
recurring cash
|
|
15
|
+
No money is kept here (ADR-0177 amendment 7): what a subscription costs month by month, and what is still to come, is a
|
|
16
|
+
recurring cash item's (`@things-factory/accounting`), compared by a person with the reference the quantities and unit
|
|
17
|
+
prices make.
|
|
18
18
|
|
|
19
19
|
Who may do what: `saas.keeping` keeps everything, `saas.reading` reads it, and an account's admins — whatever their
|
|
20
|
-
seat — keep their own accounts' subscriptions
|
|
20
|
+
seat — keep their own accounts' subscriptions and seats (`saas.administering`).
|
|
@@ -5,7 +5,6 @@ export declare class SaasAccount360 extends LitElement {
|
|
|
5
5
|
static styles: import("lit").CSSResult;
|
|
6
6
|
subject?: Entity360Subject;
|
|
7
7
|
answer?: Entity360DoorAnswer<any>;
|
|
8
|
-
payments?: any[] | null;
|
|
9
8
|
updated(changed: Map<string, unknown>): void;
|
|
10
9
|
private read;
|
|
11
10
|
render(): import("lit-html").TemplateResult<1>;
|
|
@@ -8,9 +8,10 @@ import { entity360Name, readEntity360Door, registerEntity360Kind, registerEntity
|
|
|
8
8
|
import { navigate } from '@operato/shell';
|
|
9
9
|
import { amountText, wordOf } from '../words.js';
|
|
10
10
|
/*
|
|
11
|
-
* A subscription account's 360 (ADR-0177 decision 11) - one account read deep: what it is and how it is paid,
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* A subscription account's 360 (ADR-0177 decision 11) - one account read deep: what it is and how it is paid, what is
|
|
12
|
+
* subscribed under it with the reference its quantities and unit prices make, and what moved on it. No months and no
|
|
13
|
+
* bank lines - the money is a recurring item's (개정 7). Reading first; the account's screen opens from a quiet button
|
|
14
|
+
* beside the heading.
|
|
14
15
|
*/
|
|
15
16
|
export function registerSaasAccount360() {
|
|
16
17
|
registerEntity360Kind({
|
|
@@ -26,12 +27,10 @@ export function registerSaasAccount360() {
|
|
|
26
27
|
const ACCOUNT = gql `
|
|
27
28
|
query ($id: String!) {
|
|
28
29
|
saasAccount(id: $id) {
|
|
29
|
-
id name identifier purpose currency
|
|
30
|
+
id name identifier purpose currency status closedOn
|
|
30
31
|
counterparty { id name } paymentAccount { id name } parent { id name } admins { id name }
|
|
31
|
-
trend { months values sources nextMonths expected currency }
|
|
32
32
|
}
|
|
33
|
-
saasSubscriptions(accountId: $id) { id name billing quantity unitPrice
|
|
34
|
-
saasBills(accountId: $id) { id month billedOn total lines { subscription { id name } label amount } }
|
|
33
|
+
saasSubscriptions(accountId: $id) { id name billing quantity unitPrice referenceAmount renewalOn autoRenew status seatsHeld }
|
|
35
34
|
saasChanges(accountId: $id) { subject field fromValue toValue at changedBy }
|
|
36
35
|
}
|
|
37
36
|
`;
|
|
@@ -75,13 +74,6 @@ let SaasAccount360 = class SaasAccount360 extends LitElement {
|
|
|
75
74
|
td:first-child {
|
|
76
75
|
text-align: left;
|
|
77
76
|
}
|
|
78
|
-
td.expected {
|
|
79
|
-
color: var(--ui-muted);
|
|
80
|
-
font-style: italic;
|
|
81
|
-
}
|
|
82
|
-
ox-grist-sparkline-renderer {
|
|
83
|
-
height: 48px;
|
|
84
|
-
}
|
|
85
77
|
.quiet {
|
|
86
78
|
border: none;
|
|
87
79
|
background: none;
|
|
@@ -110,21 +102,6 @@ let SaasAccount360 = class SaasAccount360 extends LitElement {
|
|
|
110
102
|
if (this.subject?.id !== id)
|
|
111
103
|
return;
|
|
112
104
|
this.answer = readEntity360Door(response, data => (data?.saasAccount ? data : null));
|
|
113
|
-
this.payments = undefined;
|
|
114
|
-
try {
|
|
115
|
-
const paid = await client.query({
|
|
116
|
-
query: gql `query ($id: String!) { saasPayments(accountId: $id) { id transactionDate amount currency description } }`,
|
|
117
|
-
variables: { id },
|
|
118
|
-
fetchPolicy: 'no-cache',
|
|
119
|
-
errorPolicy: 'all'
|
|
120
|
-
});
|
|
121
|
-
if (this.subject?.id === id)
|
|
122
|
-
this.payments = paid.errors?.length ? null : paid.data?.saasPayments ?? [];
|
|
123
|
-
}
|
|
124
|
-
catch {
|
|
125
|
-
if (this.subject?.id === id)
|
|
126
|
-
this.payments = null;
|
|
127
|
-
}
|
|
128
105
|
}
|
|
129
106
|
render() {
|
|
130
107
|
const state = this.answer?.state ?? 'loading';
|
|
@@ -133,9 +110,9 @@ let SaasAccount360 = class SaasAccount360 extends LitElement {
|
|
|
133
110
|
const section = (heading, body, action) => html `<ox-entity360-section .heading=${heading} .state=${state} .message=${this.answer?.message ?? ''}>${action ? html `<span slot="actions">${action}</span>` : nothing}${one ? body : nothing}</ox-entity360-section>`;
|
|
134
111
|
if (!one)
|
|
135
112
|
return section(i18next.t('title.saas-account-page'), nothing);
|
|
136
|
-
const trend = one.trend;
|
|
137
113
|
const subs = data.saasSubscriptions ?? [];
|
|
138
|
-
const
|
|
114
|
+
const live = subs.filter(sub => sub.status !== 'CANCELLED');
|
|
115
|
+
const reference = live.map(sub => sub.referenceAmount).filter((value) => value !== null && value !== undefined);
|
|
139
116
|
const changes = data.saasChanges ?? [];
|
|
140
117
|
const nextRenewal = subs
|
|
141
118
|
.filter(sub => sub.status === 'ACTIVE' && sub.renewalOn)
|
|
@@ -150,7 +127,7 @@ let SaasAccount360 = class SaasAccount360 extends LitElement {
|
|
|
150
127
|
<dt>${i18next.t('field.saas-account-payment-account')}</dt>
|
|
151
128
|
<dd>${one.paymentAccount?.name ?? '—'}</dd>
|
|
152
129
|
<dt>${i18next.t('field.saas-account-currency')}</dt>
|
|
153
|
-
<dd>${one.currency}
|
|
130
|
+
<dd>${one.currency}</dd>
|
|
154
131
|
<dt>${i18next.t('text.saas-360-next-renewal')}</dt>
|
|
155
132
|
<dd>${nextRenewal ?? '—'}</dd>
|
|
156
133
|
<dt>${i18next.t('field.saas-account-admins')}</dt>
|
|
@@ -158,46 +135,20 @@ let SaasAccount360 = class SaasAccount360 extends LitElement {
|
|
|
158
135
|
<dt>${i18next.t('field.saas-account-status')}</dt>
|
|
159
136
|
<dd>${wordOf('saas-account-status', one.status)}${one.closedOn ? ` · ${one.closedOn}` : ''}</dd>
|
|
160
137
|
</dl>`, open)}
|
|
161
|
-
${trend
|
|
162
|
-
? section(i18next.t('text.saas-360-months'), html `${[...trend.values, ...trend.expected].some((value) => value !== null)
|
|
163
|
-
? html `<ox-grist-sparkline-renderer .value=${trend} .column=${{ type: 'sparkline', name: 'trend', record: {} }}></ox-grist-sparkline-renderer>`
|
|
164
|
-
: nothing}
|
|
165
|
-
<table>
|
|
166
|
-
<tr><th>${i18next.t('field.saas-bill-month')}</th><th>${trend.currency}</th></tr>
|
|
167
|
-
${trend.months.map((month, i) => html `<tr>
|
|
168
|
-
<td>${month} ${trend.sources?.[i] ? html `<span class="muted">${i18next.t(`text.saas-360-source-${trend.sources[i]}`)}</span>` : nothing}</td>
|
|
169
|
-
<td>${trend.values[i] === null ? '—' : amountText(trend.values[i])}</td>
|
|
170
|
-
</tr>`)}
|
|
171
|
-
${trend.nextMonths.map((month, i) => html `<tr><td>${month}</td><td class="expected">${trend.expected[i] === null ? '' : amountText(trend.expected[i])}</td></tr>`)}
|
|
172
|
-
</table>`)
|
|
173
|
-
: nothing}
|
|
174
|
-
${this.payments
|
|
175
|
-
? section(i18next.t('text.saas-360-payments', { vendor: one.counterparty?.name ?? '' }), this.payments.length
|
|
176
|
-
? html `<table>
|
|
177
|
-
${this.payments.map(line => html `<tr>
|
|
178
|
-
<td>${entity360Name({ __typename: 'Transaction', id: line.id, transactionDate: line.transactionDate, direction: 'EXPENSE' }, line.transactionDate)}</td>
|
|
179
|
-
<td class="muted">${line.description ?? ''}</td>
|
|
180
|
-
<td>${amountText(line.amount)} ${line.currency !== one.currency ? line.currency : ''}</td>
|
|
181
|
-
</tr>`)}
|
|
182
|
-
</table>`
|
|
183
|
-
: html `<div class="muted">${i18next.t(one.counterparty ? 'text.saas-360-payments-empty' : 'text.saas-360-payments-no-vendor')}</div>`)
|
|
184
|
-
: nothing}
|
|
185
|
-
${section(i18next.t('text.saas-tab-bills'), bills.length
|
|
186
|
-
? html `<table>
|
|
187
|
-
${bills.map(bill => html `<tr>
|
|
188
|
-
<td>${bill.month}${bill.billedOn ? html ` <span class="muted">${bill.billedOn}</span>` : nothing}</td>
|
|
189
|
-
<td class="muted">${(bill.lines ?? []).map((line) => `${line.subscription?.name ?? line.label ?? ''} ${amountText(line.amount)}`).join(' · ')}</td>
|
|
190
|
-
<td>${amountText(bill.total)}</td>
|
|
191
|
-
</tr>`)}
|
|
192
|
-
</table>`
|
|
193
|
-
: html `<div class="muted">${i18next.t('text.saas-bills-empty')}</div>`)}
|
|
194
138
|
${section(i18next.t('text.saas-tab-subscriptions'), subs.length
|
|
195
139
|
? html `<table>
|
|
196
140
|
${subs.map(sub => html `<tr>
|
|
197
141
|
<td>${sub.name} <span class="muted">${wordOf('saas-billing', sub.billing)} · ${wordOf('saas-subscription-status', sub.status)}</span></td>
|
|
198
|
-
<td class="muted">${sub.billing === 'SEAT' ? i18next.t('text.saas-360-seats', { held: sub.seatsHeld ?? 0, quantity: sub.quantity ?? 0 }) :
|
|
199
|
-
<td>${
|
|
142
|
+
<td class="muted">${sub.billing === 'SEAT' ? i18next.t('text.saas-360-seats', { held: sub.seatsHeld ?? 0, quantity: sub.quantity ?? 0 }) : ''}</td>
|
|
143
|
+
<td>${amountText(sub.referenceAmount)}</td>
|
|
200
144
|
</tr>`)}
|
|
145
|
+
${reference.length
|
|
146
|
+
? html `<tr>
|
|
147
|
+
<td class="muted">${i18next.t('text.saas-360-reference')}</td>
|
|
148
|
+
<td></td>
|
|
149
|
+
<td>${amountText(reference.reduce((sum, value) => sum + value, 0))} ${one.currency}</td>
|
|
150
|
+
</tr>`
|
|
151
|
+
: nothing}
|
|
201
152
|
</table>`
|
|
202
153
|
: html `<div class="muted">${i18next.t('text.saas-subscriptions-empty')}</div>`)}
|
|
203
154
|
${section(i18next.t('text.saas-360-changes'), changes.length
|
|
@@ -220,10 +171,6 @@ __decorate([
|
|
|
220
171
|
state(),
|
|
221
172
|
__metadata("design:type", Object)
|
|
222
173
|
], SaasAccount360.prototype, "answer", void 0);
|
|
223
|
-
__decorate([
|
|
224
|
-
state(),
|
|
225
|
-
__metadata("design:type", Object)
|
|
226
|
-
], SaasAccount360.prototype, "payments", void 0);
|
|
227
174
|
SaasAccount360 = __decorate([
|
|
228
175
|
customElement('saas-account-360')
|
|
229
176
|
], SaasAccount360);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"saas-account-360.js","sourceRoot":"","sources":["../../client/entity360/saas-account-360.ts"],"names":[],"mappings":"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","sourcesContent":["import 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 } from '@operato/i18n'\nimport { entity360Name, readEntity360Door, registerEntity360Kind, registerEntity360Section, type Entity360DoorAnswer, type Entity360Subject } from '@operato/layout'\nimport { navigate } from '@operato/shell'\n\nimport { amountText, wordOf } from '../words.js'\n\n/*\n * A subscription account's 360 (ADR-0177 decision 11) - one account read deep: what it is and how it is paid, its last\n * twelve months against the next three expected, its bills month by month, what is subscribed under it and what moved on\n * it. Reading first; the account's screen opens from a quiet button beside the heading.\n */\nexport function registerSaasAccount360() {\n registerEntity360Kind({\n kind: 'saas-account',\n typenames: ['SaasAccount'],\n /* Not yet a record the assistant's conversation follows - the module registers no subject describer for it. */\n assistantSubject: false,\n title: ({ value }) => `${i18next.t('title.saas-account-page')} · ${value.name || ''}`,\n context: ({ value }) => [value.identifier, value.currency].filter(Boolean).join(' · ')\n })\n registerEntity360Section('saas-account', { name: 'overview', order: 10, render: subject => html`<saas-account-360 .subject=${subject}></saas-account-360>` })\n}\n\nconst ACCOUNT = gql`\n query ($id: String!) {\n saasAccount(id: $id) {\n id name identifier purpose currency billingDay status closedOn\n counterparty { id name } paymentAccount { id name } parent { id name } admins { id name }\n trend { months values sources nextMonths expected currency }\n }\n saasSubscriptions(accountId: $id) { id name billing quantity unitPrice amount budget everyMonths renewalOn autoRenew status seatsHeld }\n saasBills(accountId: $id) { id month billedOn total lines { subscription { id name } label amount } }\n saasChanges(accountId: $id) { subject field fromValue toValue at changedBy }\n }\n`\n\n@customElement('saas-account-360')\nexport class SaasAccount360 extends LitElement {\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-large, 12px);\n font-size: var(--ui-t-body, 13px);\n line-height: 1.5;\n }\n dl {\n margin: 0;\n display: grid;\n grid-template-columns: max-content 1fr;\n gap: var(--spacing-small, 4px) var(--spacing-large, 12px);\n }\n dt,\n th,\n .muted {\n color: var(--ui-muted);\n }\n dd {\n margin: 0;\n overflow-wrap: anywhere;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n font-variant-numeric: tabular-nums;\n }\n th,\n td {\n padding: 4px 6px;\n border-bottom: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n text-align: right;\n font-weight: normal;\n }\n th:first-child,\n td:first-child {\n text-align: left;\n }\n td.expected {\n color: var(--ui-muted);\n font-style: italic;\n }\n ox-grist-sparkline-renderer {\n height: 48px;\n }\n .quiet {\n border: none;\n background: none;\n padding: 0;\n color: var(--md-sys-color-primary);\n font: inherit;\n cursor: pointer;\n }\n `\n\n @property({ attribute: false }) subject?: Entity360Subject\n @state() answer?: Entity360DoorAnswer<any>\n /* What left the bank for the vendor - the bank's door, read apart so a reader without it still sees the rest. */\n @state() payments?: any[] | null\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({ query: ACCOUNT, variables: { id }, fetchPolicy: 'no-cache', errorPolicy: 'all' } 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?.saasAccount ? data : null))\n this.payments = undefined\n try {\n const paid: any = await client.query({\n query: gql`query ($id: String!) { saasPayments(accountId: $id) { id transactionDate amount currency description } }`,\n variables: { id },\n fetchPolicy: 'no-cache',\n errorPolicy: 'all'\n } as any)\n if (this.subject?.id === id) this.payments = paid.errors?.length ? null : paid.data?.saasPayments ?? []\n } catch {\n if (this.subject?.id === id) this.payments = null\n }\n }\n\n render() {\n const state = this.answer?.state ?? 'loading'\n const data = this.answer?.data\n const one = data?.saasAccount\n const section = (heading: string, body: unknown, action?: unknown) =>\n html`<ox-entity360-section .heading=${heading} .state=${state} .message=${this.answer?.message ?? ''}>${action ? html`<span slot=\"actions\">${action}</span>` : nothing}${one ? body : nothing}</ox-entity360-section>`\n if (!one) return section(i18next.t('title.saas-account-page'), nothing)\n\n const trend = one.trend\n const subs: any[] = data.saasSubscriptions ?? []\n const bills: any[] = data.saasBills ?? []\n const changes: any[] = data.saasChanges ?? []\n const nextRenewal = subs\n .filter(sub => sub.status === 'ACTIVE' && sub.renewalOn)\n .map(sub => sub.renewalOn)\n .sort()[0]\n const open = html`<button class=\"quiet\" @click=${() => navigate(`saas-account-page?id=${one.id}`)}>${i18next.t('button.saas-open-account')}</button>`\n const party = (value?: { id: string; name: string }) => (value ? entity360Name({ __typename: 'Counterparty', ...value }, value.name) : '—')\n\n return html`\n ${section(\n one.name,\n html`<dl>\n <dt>${i18next.t('field.saas-account-counterparty')}</dt>\n <dd>${party(one.counterparty)}</dd>\n <dt>${i18next.t('field.saas-account-payment-account')}</dt>\n <dd>${one.paymentAccount?.name ?? '—'}</dd>\n <dt>${i18next.t('field.saas-account-currency')}</dt>\n <dd>${one.currency}${one.billingDay ? ` · ${i18next.t('text.saas-account-billing-day', { day: one.billingDay })}` : ''}</dd>\n <dt>${i18next.t('text.saas-360-next-renewal')}</dt>\n <dd>${nextRenewal ?? '—'}</dd>\n <dt>${i18next.t('field.saas-account-admins')}</dt>\n <dd>${(one.admins ?? []).map((admin: any) => admin.name).join(', ') || '—'}</dd>\n <dt>${i18next.t('field.saas-account-status')}</dt>\n <dd>${wordOf('saas-account-status', one.status)}${one.closedOn ? ` · ${one.closedOn}` : ''}</dd>\n </dl>`,\n open\n )}\n ${trend\n ? section(\n i18next.t('text.saas-360-months'),\n html`${[...trend.values, ...trend.expected].some((value: number | null) => value !== null)\n ? html`<ox-grist-sparkline-renderer .value=${trend} .column=${{ type: 'sparkline', name: 'trend', record: {} }}></ox-grist-sparkline-renderer>`\n : nothing}\n <table>\n <tr><th>${i18next.t('field.saas-bill-month')}</th><th>${trend.currency}</th></tr>\n ${trend.months.map(\n (month: string, i: number) =>\n html`<tr>\n <td>${month} ${trend.sources?.[i] ? html`<span class=\"muted\">${i18next.t(`text.saas-360-source-${trend.sources[i]}`)}</span>` : nothing}</td>\n <td>${trend.values[i] === null ? '—' : amountText(trend.values[i])}</td>\n </tr>`\n )}\n ${trend.nextMonths.map((month: string, i: number) => html`<tr><td>${month}</td><td class=\"expected\">${trend.expected[i] === null ? '' : amountText(trend.expected[i])}</td></tr>`)}\n </table>`\n )\n : nothing}\n ${this.payments\n ? section(\n i18next.t('text.saas-360-payments', { vendor: one.counterparty?.name ?? '' }),\n this.payments.length\n ? html`<table>\n ${this.payments.map(\n line => html`<tr>\n <td>${entity360Name({ __typename: 'Transaction', id: line.id, transactionDate: line.transactionDate, direction: 'EXPENSE' }, line.transactionDate)}</td>\n <td class=\"muted\">${line.description ?? ''}</td>\n <td>${amountText(line.amount)} ${line.currency !== one.currency ? line.currency : ''}</td>\n </tr>`\n )}\n </table>`\n : html`<div class=\"muted\">${i18next.t(one.counterparty ? 'text.saas-360-payments-empty' : 'text.saas-360-payments-no-vendor')}</div>`\n )\n : nothing}\n ${section(\n i18next.t('text.saas-tab-bills'),\n bills.length\n ? html`<table>\n ${bills.map(\n bill => html`<tr>\n <td>${bill.month}${bill.billedOn ? html` <span class=\"muted\">${bill.billedOn}</span>` : nothing}</td>\n <td class=\"muted\">${(bill.lines ?? []).map((line: any) => `${line.subscription?.name ?? line.label ?? ''} ${amountText(line.amount)}`).join(' · ')}</td>\n <td>${amountText(bill.total)}</td>\n </tr>`\n )}\n </table>`\n : html`<div class=\"muted\">${i18next.t('text.saas-bills-empty')}</div>`\n )}\n ${section(\n i18next.t('text.saas-tab-subscriptions'),\n subs.length\n ? html`<table>\n ${subs.map(\n sub => html`<tr>\n <td>${sub.name} <span class=\"muted\">${wordOf('saas-billing', sub.billing)} · ${wordOf('saas-subscription-status', sub.status)}</span></td>\n <td class=\"muted\">${sub.billing === 'SEAT' ? i18next.t('text.saas-360-seats', { held: sub.seatsHeld ?? 0, quantity: sub.quantity ?? 0 }) : sub.billing === 'USAGE' ? i18next.t('text.saas-360-budget', { budget: amountText(sub.budget) }) : ''}</td>\n <td>${sub.billing === 'SEAT' ? amountText((sub.quantity ?? 0) * (sub.unitPrice ?? 0)) : amountText(sub.amount)}</td>\n </tr>`\n )}\n </table>`\n : html`<div class=\"muted\">${i18next.t('text.saas-subscriptions-empty')}</div>`\n )}\n ${section(\n i18next.t('text.saas-360-changes'),\n changes.length\n ? html`<table>\n ${changes.map(\n change => html`<tr>\n <td>${String(change.at).slice(0, 10)} <span class=\"muted\">${change.changedBy ?? ''}</span></td>\n <td>${change.subject} · ${i18next.t(`text.saas-change-field-${change.field}`, { defaultValue: change.field })}</td>\n <td>${change.fromValue ?? '—'} → ${change.toValue ?? '—'}</td>\n </tr>`\n )}\n </table>`\n : html`<div class=\"muted\">${i18next.t('text.saas-360-changes-empty')}</div>`\n )}\n `\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"saas-account-360.js","sourceRoot":"","sources":["../../client/entity360/saas-account-360.ts"],"names":[],"mappings":"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","sourcesContent":["import 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 } from '@operato/i18n'\nimport { entity360Name, readEntity360Door, registerEntity360Kind, registerEntity360Section, type Entity360DoorAnswer, type Entity360Subject } from '@operato/layout'\nimport { navigate } from '@operato/shell'\n\nimport { amountText, wordOf } from '../words.js'\n\n/*\n * A subscription account's 360 (ADR-0177 decision 11) - one account read deep: what it is and how it is paid, what is\n * subscribed under it with the reference its quantities and unit prices make, and what moved on it. No months and no\n * bank lines - the money is a recurring item's (개정 7). Reading first; the account's screen opens from a quiet button\n * beside the heading.\n */\nexport function registerSaasAccount360() {\n registerEntity360Kind({\n kind: 'saas-account',\n typenames: ['SaasAccount'],\n /* Not yet a record the assistant's conversation follows - the module registers no subject describer for it. */\n assistantSubject: false,\n title: ({ value }) => `${i18next.t('title.saas-account-page')} · ${value.name || ''}`,\n context: ({ value }) => [value.identifier, value.currency].filter(Boolean).join(' · ')\n })\n registerEntity360Section('saas-account', { name: 'overview', order: 10, render: subject => html`<saas-account-360 .subject=${subject}></saas-account-360>` })\n}\n\nconst ACCOUNT = gql`\n query ($id: String!) {\n saasAccount(id: $id) {\n id name identifier purpose currency status closedOn\n counterparty { id name } paymentAccount { id name } parent { id name } admins { id name }\n }\n saasSubscriptions(accountId: $id) { id name billing quantity unitPrice referenceAmount renewalOn autoRenew status seatsHeld }\n saasChanges(accountId: $id) { subject field fromValue toValue at changedBy }\n }\n`\n\n@customElement('saas-account-360')\nexport class SaasAccount360 extends LitElement {\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-large, 12px);\n font-size: var(--ui-t-body, 13px);\n line-height: 1.5;\n }\n dl {\n margin: 0;\n display: grid;\n grid-template-columns: max-content 1fr;\n gap: var(--spacing-small, 4px) var(--spacing-large, 12px);\n }\n dt,\n th,\n .muted {\n color: var(--ui-muted);\n }\n dd {\n margin: 0;\n overflow-wrap: anywhere;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n font-variant-numeric: tabular-nums;\n }\n th,\n td {\n padding: 4px 6px;\n border-bottom: 1px solid var(--ui-line, var(--md-sys-color-outline-variant));\n text-align: right;\n font-weight: normal;\n }\n th:first-child,\n td:first-child {\n text-align: left;\n }\n .quiet {\n border: none;\n background: none;\n padding: 0;\n color: var(--md-sys-color-primary);\n font: inherit;\n cursor: pointer;\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({ query: ACCOUNT, variables: { id }, fetchPolicy: 'no-cache', errorPolicy: 'all' } 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?.saasAccount ? data : null))\n }\n\n render() {\n const state = this.answer?.state ?? 'loading'\n const data = this.answer?.data\n const one = data?.saasAccount\n const section = (heading: string, body: unknown, action?: unknown) =>\n html`<ox-entity360-section .heading=${heading} .state=${state} .message=${this.answer?.message ?? ''}>${action ? html`<span slot=\"actions\">${action}</span>` : nothing}${one ? body : nothing}</ox-entity360-section>`\n if (!one) return section(i18next.t('title.saas-account-page'), nothing)\n\n const subs: any[] = data.saasSubscriptions ?? []\n const live = subs.filter(sub => sub.status !== 'CANCELLED')\n const reference = live.map(sub => sub.referenceAmount).filter((value): value is number => value !== null && value !== undefined)\n const changes: any[] = data.saasChanges ?? []\n const nextRenewal = subs\n .filter(sub => sub.status === 'ACTIVE' && sub.renewalOn)\n .map(sub => sub.renewalOn)\n .sort()[0]\n const open = html`<button class=\"quiet\" @click=${() => navigate(`saas-account-page?id=${one.id}`)}>${i18next.t('button.saas-open-account')}</button>`\n const party = (value?: { id: string; name: string }) => (value ? entity360Name({ __typename: 'Counterparty', ...value }, value.name) : '—')\n\n return html`\n ${section(\n one.name,\n html`<dl>\n <dt>${i18next.t('field.saas-account-counterparty')}</dt>\n <dd>${party(one.counterparty)}</dd>\n <dt>${i18next.t('field.saas-account-payment-account')}</dt>\n <dd>${one.paymentAccount?.name ?? '—'}</dd>\n <dt>${i18next.t('field.saas-account-currency')}</dt>\n <dd>${one.currency}</dd>\n <dt>${i18next.t('text.saas-360-next-renewal')}</dt>\n <dd>${nextRenewal ?? '—'}</dd>\n <dt>${i18next.t('field.saas-account-admins')}</dt>\n <dd>${(one.admins ?? []).map((admin: any) => admin.name).join(', ') || '—'}</dd>\n <dt>${i18next.t('field.saas-account-status')}</dt>\n <dd>${wordOf('saas-account-status', one.status)}${one.closedOn ? ` · ${one.closedOn}` : ''}</dd>\n </dl>`,\n open\n )}\n ${section(\n i18next.t('text.saas-tab-subscriptions'),\n subs.length\n ? html`<table>\n ${subs.map(\n sub => html`<tr>\n <td>${sub.name} <span class=\"muted\">${wordOf('saas-billing', sub.billing)} · ${wordOf('saas-subscription-status', sub.status)}</span></td>\n <td class=\"muted\">${sub.billing === 'SEAT' ? i18next.t('text.saas-360-seats', { held: sub.seatsHeld ?? 0, quantity: sub.quantity ?? 0 }) : ''}</td>\n <td>${amountText(sub.referenceAmount)}</td>\n </tr>`\n )}\n ${reference.length\n ? html`<tr>\n <td class=\"muted\">${i18next.t('text.saas-360-reference')}</td>\n <td></td>\n <td>${amountText(reference.reduce((sum, value) => sum + value, 0))} ${one.currency}</td>\n </tr>`\n : nothing}\n </table>`\n : html`<div class=\"muted\">${i18next.t('text.saas-subscriptions-empty')}</div>`\n )}\n ${section(\n i18next.t('text.saas-360-changes'),\n changes.length\n ? html`<table>\n ${changes.map(\n change => html`<tr>\n <td>${String(change.at).slice(0, 10)} <span class=\"muted\">${change.changedBy ?? ''}</span></td>\n <td>${change.subject} · ${i18next.t(`text.saas-change-field-${change.field}`, { defaultValue: change.field })}</td>\n <td>${change.fromValue ?? '—'} → ${change.toValue ?? '—'}</td>\n </tr>`\n )}\n </table>`\n : html`<div class=\"muted\">${i18next.t('text.saas-360-changes-empty')}</div>`\n )}\n `\n }\n}\n"]}
|
package/dist-client/index.d.ts
CHANGED
package/dist-client/index.js
CHANGED
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
export { SaasBillEditor } from './components/saas-bill-editor.js';
|
|
2
|
-
export { SaasCandidates } from './components/saas-candidates.js';
|
|
3
1
|
export { registerSaasAccount360 } from './entity360/saas-account-360.js';
|
|
4
|
-
export { trendTitle } from './words.js';
|
|
5
2
|
//# sourceMappingURL=index.js.map
|
package/dist-client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA","sourcesContent":["export { registerSaasAccount360 } from './entity360/saas-account-360.js'\n"]}
|
|
@@ -5,7 +5,7 @@ import { PageView } from '@operato/shell';
|
|
|
5
5
|
declare const SaasAccountList_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
|
|
6
6
|
/**
|
|
7
7
|
* 구독 서비스 — the accounts the domain holds with vendors (ADR-0177 decision 2), typed like a spreadsheet and saved together.
|
|
8
|
-
* An account opens to its subscriptions, their seats
|
|
8
|
+
* An account opens to its subscriptions, their seats and its admins. Its money is a recurring item's (개정 7).
|
|
9
9
|
*/
|
|
10
10
|
export declare class SaasAccountList extends SaasAccountList_base {
|
|
11
11
|
static styles: import("lit").CSSResult[];
|
|
@@ -12,18 +12,16 @@ import { navigate, PageView } from '@operato/shell';
|
|
|
12
12
|
import { CommonButtonStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
|
|
13
13
|
import { isMobileDevice } from '@operato/utils';
|
|
14
14
|
/* The register grids' save, the asset module's - this module saves its grids the same way. */
|
|
15
|
-
import { saveGrid } from '@things-factory/asset/dist-client
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
const FIELDS = ['name', 'counterparty', 'identifier', 'parent', 'purpose', 'billingEmail', 'paymentAccount', 'currency', 'billingDay', 'secretLocation', 'increaseAlertRate', 'status', 'closedOn', 'description'];
|
|
15
|
+
import { saveGrid } from '@things-factory/asset/dist-client';
|
|
16
|
+
import { ACCOUNT_STATUSES, fieldWord, filterOptionsOf, optionsOf, picker } from '../words.js';
|
|
17
|
+
const FIELDS = ['name', 'counterparty', 'identifier', 'parent', 'purpose', 'billingEmail', 'paymentAccount', 'currency', 'secretLocation', 'status', 'closedOn', 'description'];
|
|
19
18
|
const ACCOUNT_FIELDS = `
|
|
20
19
|
id name counterparty { id name } identifier parent { id name } purpose admins { id name } billingEmail
|
|
21
|
-
paymentAccount { id name } currency
|
|
22
|
-
trend { months values nextMonths expected currency }
|
|
20
|
+
paymentAccount { id name } currency secretLocation status closedOn description
|
|
23
21
|
`;
|
|
24
22
|
/**
|
|
25
23
|
* 구독 서비스 — the accounts the domain holds with vendors (ADR-0177 decision 2), typed like a spreadsheet and saved together.
|
|
26
|
-
* An account opens to its subscriptions, their seats
|
|
24
|
+
* An account opens to its subscriptions, their seats and its admins. Its money is a recurring item's (개정 7).
|
|
27
25
|
*/
|
|
28
26
|
let SaasAccountList = class SaasAccountList extends localize(i18next)(PageView) {
|
|
29
27
|
constructor() {
|
|
@@ -41,9 +39,6 @@ let SaasAccountList = class SaasAccountList extends localize(i18next)(PageView)
|
|
|
41
39
|
actions: this.mine
|
|
42
40
|
? []
|
|
43
41
|
: [
|
|
44
|
-
{ title: i18next.t('button.saas-cost-trend'), icon: 'monitoring', action: () => navigate('saas-cost-trend') },
|
|
45
|
-
/* What the bank and card lines already say is subscribed to (ADR-0177 개정 1). */
|
|
46
|
-
{ title: i18next.t('button.saas-candidates'), icon: 'manage_search', action: () => SaasCandidates.open({ made: () => this.grist.fetch() }) },
|
|
47
42
|
{ title: i18next.t('button.add'), icon: 'add', action: () => this.grist.addRecordToTop({ currency: 'KRW', status: 'ACTIVE' }) },
|
|
48
43
|
{ title: i18next.t('button.delete'), action: () => this.save(true), ...CommonButtonStyles.delete },
|
|
49
44
|
{ title: i18next.t('button.save'), action: () => this.save(), ...CommonButtonStyles.save }
|
|
@@ -83,8 +78,6 @@ let SaasAccountList = class SaasAccountList extends localize(i18next)(PageView)
|
|
|
83
78
|
{ type: 'gutter', gutterName: 'button', icon: 'open_in_new', handlers: { click: (_c, _d, _col, record) => open(record) } },
|
|
84
79
|
/* The name opens the account's 360 (ADR-0067); a new row is typed into. */
|
|
85
80
|
text('name', 180, { record: { mandatory: true, renderer: (value, _c, record) => (record?.id ? entity360Name({ __typename: 'SaasAccount', ...record }, value) : value ?? '') } }),
|
|
86
|
-
/* The last twelve months billed, the next three expected dashed (ADR-0177 decision 10). */
|
|
87
|
-
{ type: 'sparkline', name: 'trend', header: fieldWord('saas-account', 'trend'), width: 120, record: { options: { title: (value) => trendTitle(value) } } },
|
|
88
81
|
object('counterparty', 150, 'counterpartyChoices', [{ name: 'name', header: fieldWord('saas-account', 'counterparty') }]),
|
|
89
82
|
text('identifier', 150),
|
|
90
83
|
object('parent', 140, 'saasAccounts', [{ name: 'name', header: fieldWord('saas-account', 'parent') }]),
|
|
@@ -98,8 +91,6 @@ let SaasAccountList = class SaasAccountList extends localize(i18next)(PageView)
|
|
|
98
91
|
},
|
|
99
92
|
object('paymentAccount', 150, 'bankAccounts', [{ name: 'name', header: fieldWord('saas-account', 'paymentAccount') }]),
|
|
100
93
|
text('currency', 60, { record: { align: 'center' } }),
|
|
101
|
-
{ type: 'integer', name: 'billingDay', header: fieldWord('saas-account', 'billingDay'), width: 70, record: { ...editable, align: 'right' } },
|
|
102
|
-
{ type: 'float', name: 'increaseAlertRate', header: fieldWord('saas-account', 'increaseAlertRate'), width: 80, hidden: true, record: { ...editable, align: 'right' } },
|
|
103
94
|
text('billingEmail', 160, { hidden: true }),
|
|
104
95
|
text('secretLocation', 160),
|
|
105
96
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"saas-account-list.js","sourceRoot":"","sources":["../../client/pages/saas-account-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, getEditor } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { entity360Name } from '@operato/layout'\nimport { navigate, PageView } from '@operato/shell'\nimport { CommonButtonStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n/* The register grids' save, the asset module's - this module saves its grids the same way. */\nimport { saveGrid } from '@things-factory/asset/dist-client/grid.js'\n\nimport { SaasCandidates } from '../components/saas-candidates.js'\nimport { ACCOUNT_STATUSES, fieldWord, filterOptionsOf, optionsOf, picker, trendTitle } from '../words.js'\n\nconst FIELDS = ['name', 'counterparty', 'identifier', 'parent', 'purpose', 'billingEmail', 'paymentAccount', 'currency', 'billingDay', 'secretLocation', 'increaseAlertRate', 'status', 'closedOn', 'description']\nconst ACCOUNT_FIELDS = `\n id name counterparty { id name } identifier parent { id name } purpose admins { id name } billingEmail\n paymentAccount { id name } currency billingDay secretLocation increaseAlertRate status closedOn description\n trend { months values nextMonths expected currency }\n`\n\n/**\n * 구독 서비스 — the accounts the domain holds with vendors (ADR-0177 decision 2), typed like a spreadsheet and saved together.\n * An account opens to its subscriptions, their seats, its admins and its bills.\n */\n@customElement('saas-account-list')\nexport class SaasAccountList extends localize(i18next)(PageView) {\n static styles = [WorkSurfacePageStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles]\n\n /** Only the accounts the signed-in person administers, opened and not kept here. */\n protected mine = false\n\n @state() gristConfig: any\n @query('ox-grist') private grist!: DataGrist\n\n get context() {\n const title = i18next.t(this.mine ? 'title.my-saas-account-list' : 'title.saas-account-list')\n return {\n title,\n search: { handler: (search: string) => (this.grist.searchText = search), value: this.grist?.searchText || '' },\n filter: { handler: () => this.grist.toggleHeadroom() },\n actions: this.mine\n ? []\n : [\n { title: i18next.t('button.saas-cost-trend'), icon: 'monitoring', action: () => navigate('saas-cost-trend') },\n /* What the bank and card lines already say is subscribed to (ADR-0177 개정 1). */\n { title: i18next.t('button.saas-candidates'), icon: 'manage_search', action: () => SaasCandidates.open({ made: () => this.grist.fetch() }) },\n { title: i18next.t('button.add'), icon: 'add', action: () => this.grist.addRecordToTop({ currency: 'KRW', status: 'ACTIVE' }) },\n { title: i18next.t('button.delete'), action: () => this.save(true), ...CommonButtonStyles.delete },\n { title: i18next.t('button.save'), action: () => this.save(), ...CommonButtonStyles.save }\n ],\n exportable: { name: title, data: () => this.grist.exportRecords() }\n }\n }\n\n render() {\n return html`<ox-grist class=\"page-fill\" search-mode=\"term\" .mode=${isMobileDevice() ? 'CARD' : 'GRID'} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>\n <div slot=\"headroom\" class=\"header\">\n <div class=\"filters\"><ox-filters-form without-search autofocus></ox-filters-form></div>\n </div>\n </ox-grist>`\n }\n\n async pageInitialized() {\n const editable = { editable: !this.mine }\n const text = (name: string, width: number, extra: any = {}) => ({ type: 'string', name, header: fieldWord('saas-account', name), width, sortable: true, ...extra, record: { ...editable, ...extra.record } })\n const object = (name: string, width: number, queryName: string, columns: { name: string; header?: string }[]) => ({\n type: 'object',\n name,\n header: fieldWord('saas-account', name),\n width,\n record: { ...editable, editor: getEditor('resource-object'), options: picker(queryName, columns) }\n })\n const open = (record: any) => record?.id && navigate(`saas-account-page?id=${record.id}`)\n this.gristConfig = {\n rows: { appendable: !this.mine, selectable: { multiple: !this.mine } },\n pagination: { limit: 100, pages: [50, 100] },\n emptyNote: {\n title: i18next.t(this.mine ? 'text.my-saas-account-empty' : 'text.saas-account-empty'),\n description: i18next.t(this.mine ? 'text.my-saas-account-empty-description' : 'text.saas-account-empty-description')\n },\n list: { fields: ['name', 'identifier'], details: ['purpose', 'admins'] },\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n ...(this.mine ? [] : [{ type: 'gutter', gutterName: 'row-selector', multiple: true }]),\n { type: 'gutter', gutterName: 'button', icon: 'open_in_new', handlers: { click: (_c: any, _d: any, _col: any, record: any) => open(record) } },\n /* The name opens the account's 360 (ADR-0067); a new row is typed into. */\n text('name', 180, { record: { mandatory: true, renderer: (value: string, _c: any, record: any) => (record?.id ? entity360Name({ __typename: 'SaasAccount', ...record }, value) : value ?? '') } }),\n /* The last twelve months billed, the next three expected dashed (ADR-0177 decision 10). */\n { type: 'sparkline', name: 'trend', header: fieldWord('saas-account', 'trend'), width: 120, record: { options: { title: (value: any) => trendTitle(value) } } },\n object('counterparty', 150, 'counterpartyChoices', [{ name: 'name', header: fieldWord('saas-account', 'counterparty') }]),\n text('identifier', 150),\n object('parent', 140, 'saasAccounts', [{ name: 'name', header: fieldWord('saas-account', 'parent') }]),\n text('purpose', 120),\n {\n type: 'string',\n name: 'admins',\n header: fieldWord('saas-account', 'admins'),\n width: 160,\n record: { renderer: (value: any[]) => (value ?? []).map(one => one.name).join(', ') }\n },\n object('paymentAccount', 150, 'bankAccounts', [{ name: 'name', header: fieldWord('saas-account', 'paymentAccount') }]),\n text('currency', 60, { record: { align: 'center' } }),\n { type: 'integer', name: 'billingDay', header: fieldWord('saas-account', 'billingDay'), width: 70, record: { ...editable, align: 'right' } },\n { type: 'float', name: 'increaseAlertRate', header: fieldWord('saas-account', 'increaseAlertRate'), width: 80, hidden: true, record: { ...editable, align: 'right' } },\n text('billingEmail', 160, { hidden: true }),\n text('secretLocation', 160),\n {\n type: 'select',\n name: 'status',\n header: fieldWord('saas-account', 'status'),\n width: 80,\n sortable: true,\n record: { ...editable, options: optionsOf('saas-account-status', ACCOUNT_STATUSES) },\n filter: { type: 'select', operator: 'eq', options: filterOptionsOf('saas-account-status', ACCOUNT_STATUSES) }\n },\n text('closedOn', 100, { record: { align: 'center' } }),\n text('description', 200)\n ],\n sorters: [{ name: 'name' }]\n }\n }\n\n async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [], search }: FetchOption) {\n if (this.mine) {\n const response = await client.query({ query: gql`query { rows: mySaasAccounts { ${ACCOUNT_FIELDS} } }`, fetchPolicy: 'network-only' })\n if (response.errors?.length) throw response\n return { total: response.data.rows.length, records: response.data.rows }\n }\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $search: String) {\n responses: saasAccounts(filters: $filters, pagination: $pagination, sortings: $sortings, search: $search) {\n items { ${ACCOUNT_FIELDS} }\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 private async save(deleting = false) {\n /* A picked row goes as its id. */\n const shape = ({ counterparty, parent, paymentAccount, ...patch }: any) => ({\n ...patch,\n ...(counterparty === undefined ? {} : { counterpartyId: counterparty?.id ?? null }),\n ...(parent === undefined ? {} : { parentId: parent?.id ?? null }),\n ...(paymentAccount === undefined ? {} : { paymentAccountId: paymentAccount?.id ?? null })\n })\n if (await saveGrid(this.grist, FIELDS, 'updateMultipleSaasAccount', 'SaasAccountPatch', {}, deleting, shape)) this.grist.fetch()\n }\n}\n\n/** 내가 관리하는 구독 서비스 — the accounts the signed-in person is named an admin of, whatever their seat (ADR-0177 Q4). */\n@customElement('my-saas-account-list')\nexport class MySaasAccountList extends SaasAccountList {\n protected mine = true\n}\n"]}
|
|
1
|
+
{"version":3,"file":"saas-account-list.js","sourceRoot":"","sources":["../../client/pages/saas-account-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, getEditor } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { entity360Name } from '@operato/layout'\nimport { navigate, PageView } from '@operato/shell'\nimport { CommonButtonStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { isMobileDevice } from '@operato/utils'\n/* The register grids' save, the asset module's - this module saves its grids the same way. */\nimport { saveGrid } from '@things-factory/asset/dist-client'\n\nimport { ACCOUNT_STATUSES, fieldWord, filterOptionsOf, optionsOf, picker } from '../words.js'\n\nconst FIELDS = ['name', 'counterparty', 'identifier', 'parent', 'purpose', 'billingEmail', 'paymentAccount', 'currency', 'secretLocation', 'status', 'closedOn', 'description']\nconst ACCOUNT_FIELDS = `\n id name counterparty { id name } identifier parent { id name } purpose admins { id name } billingEmail\n paymentAccount { id name } currency secretLocation status closedOn description\n`\n\n/**\n * 구독 서비스 — the accounts the domain holds with vendors (ADR-0177 decision 2), typed like a spreadsheet and saved together.\n * An account opens to its subscriptions, their seats and its admins. Its money is a recurring item's (개정 7).\n */\n@customElement('saas-account-list')\nexport class SaasAccountList extends localize(i18next)(PageView) {\n static styles = [WorkSurfacePageStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles]\n\n /** Only the accounts the signed-in person administers, opened and not kept here. */\n protected mine = false\n\n @state() gristConfig: any\n @query('ox-grist') private grist!: DataGrist\n\n get context() {\n const title = i18next.t(this.mine ? 'title.my-saas-account-list' : 'title.saas-account-list')\n return {\n title,\n search: { handler: (search: string) => (this.grist.searchText = search), value: this.grist?.searchText || '' },\n filter: { handler: () => this.grist.toggleHeadroom() },\n actions: this.mine\n ? []\n : [\n { title: i18next.t('button.add'), icon: 'add', action: () => this.grist.addRecordToTop({ currency: 'KRW', status: 'ACTIVE' }) },\n { title: i18next.t('button.delete'), action: () => this.save(true), ...CommonButtonStyles.delete },\n { title: i18next.t('button.save'), action: () => this.save(), ...CommonButtonStyles.save }\n ],\n exportable: { name: title, data: () => this.grist.exportRecords() }\n }\n }\n\n render() {\n return html`<ox-grist class=\"page-fill\" search-mode=\"term\" .mode=${isMobileDevice() ? 'CARD' : 'GRID'} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>\n <div slot=\"headroom\" class=\"header\">\n <div class=\"filters\"><ox-filters-form without-search autofocus></ox-filters-form></div>\n </div>\n </ox-grist>`\n }\n\n async pageInitialized() {\n const editable = { editable: !this.mine }\n const text = (name: string, width: number, extra: any = {}) => ({ type: 'string', name, header: fieldWord('saas-account', name), width, sortable: true, ...extra, record: { ...editable, ...extra.record } })\n const object = (name: string, width: number, queryName: string, columns: { name: string; header?: string }[]) => ({\n type: 'object',\n name,\n header: fieldWord('saas-account', name),\n width,\n record: { ...editable, editor: getEditor('resource-object'), options: picker(queryName, columns) }\n })\n const open = (record: any) => record?.id && navigate(`saas-account-page?id=${record.id}`)\n this.gristConfig = {\n rows: { appendable: !this.mine, selectable: { multiple: !this.mine } },\n pagination: { limit: 100, pages: [50, 100] },\n emptyNote: {\n title: i18next.t(this.mine ? 'text.my-saas-account-empty' : 'text.saas-account-empty'),\n description: i18next.t(this.mine ? 'text.my-saas-account-empty-description' : 'text.saas-account-empty-description')\n },\n list: { fields: ['name', 'identifier'], details: ['purpose', 'admins'] },\n columns: [\n { type: 'gutter', gutterName: 'sequence' },\n ...(this.mine ? [] : [{ type: 'gutter', gutterName: 'row-selector', multiple: true }]),\n { type: 'gutter', gutterName: 'button', icon: 'open_in_new', handlers: { click: (_c: any, _d: any, _col: any, record: any) => open(record) } },\n /* The name opens the account's 360 (ADR-0067); a new row is typed into. */\n text('name', 180, { record: { mandatory: true, renderer: (value: string, _c: any, record: any) => (record?.id ? entity360Name({ __typename: 'SaasAccount', ...record }, value) : value ?? '') } }),\n object('counterparty', 150, 'counterpartyChoices', [{ name: 'name', header: fieldWord('saas-account', 'counterparty') }]),\n text('identifier', 150),\n object('parent', 140, 'saasAccounts', [{ name: 'name', header: fieldWord('saas-account', 'parent') }]),\n text('purpose', 120),\n {\n type: 'string',\n name: 'admins',\n header: fieldWord('saas-account', 'admins'),\n width: 160,\n record: { renderer: (value: any[]) => (value ?? []).map(one => one.name).join(', ') }\n },\n object('paymentAccount', 150, 'bankAccounts', [{ name: 'name', header: fieldWord('saas-account', 'paymentAccount') }]),\n text('currency', 60, { record: { align: 'center' } }),\n text('billingEmail', 160, { hidden: true }),\n text('secretLocation', 160),\n {\n type: 'select',\n name: 'status',\n header: fieldWord('saas-account', 'status'),\n width: 80,\n sortable: true,\n record: { ...editable, options: optionsOf('saas-account-status', ACCOUNT_STATUSES) },\n filter: { type: 'select', operator: 'eq', options: filterOptionsOf('saas-account-status', ACCOUNT_STATUSES) }\n },\n text('closedOn', 100, { record: { align: 'center' } }),\n text('description', 200)\n ],\n sorters: [{ name: 'name' }]\n }\n }\n\n async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [], search }: FetchOption) {\n if (this.mine) {\n const response = await client.query({ query: gql`query { rows: mySaasAccounts { ${ACCOUNT_FIELDS} } }`, fetchPolicy: 'network-only' })\n if (response.errors?.length) throw response\n return { total: response.data.rows.length, records: response.data.rows }\n }\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $search: String) {\n responses: saasAccounts(filters: $filters, pagination: $pagination, sortings: $sortings, search: $search) {\n items { ${ACCOUNT_FIELDS} }\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 private async save(deleting = false) {\n /* A picked row goes as its id. */\n const shape = ({ counterparty, parent, paymentAccount, ...patch }: any) => ({\n ...patch,\n ...(counterparty === undefined ? {} : { counterpartyId: counterparty?.id ?? null }),\n ...(parent === undefined ? {} : { parentId: parent?.id ?? null }),\n ...(paymentAccount === undefined ? {} : { paymentAccountId: paymentAccount?.id ?? null })\n })\n if (await saveGrid(this.grist, FIELDS, 'updateMultipleSaasAccount', 'SaasAccountPatch', {}, deleting, shape)) this.grist.fetch()\n }\n}\n\n/** 내가 관리하는 구독 서비스 — the accounts the signed-in person is named an admin of, whatever their seat (ADR-0177 Q4). */\n@customElement('my-saas-account-list')\nexport class MySaasAccountList extends SaasAccountList {\n protected mine = true\n}\n"]}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import '@operato/data-grist/ox-grist.js';
|
|
2
|
-
import '../components/saas-bill-editor.js';
|
|
3
2
|
import { PageView } from '@operato/shell';
|
|
4
|
-
type Tab = 'subscriptions' | 'seats' | '
|
|
3
|
+
type Tab = 'subscriptions' | 'seats' | 'admins';
|
|
5
4
|
declare const SaasAccountPage_base: (new (...args: any[]) => import("lit").LitElement) & typeof PageView;
|
|
6
5
|
/**
|
|
7
|
-
* 구독 서비스 한 계정 — tab by tab its subscriptions, the seats of one of them
|
|
8
|
-
*
|
|
6
|
+
* 구독 서비스 한 계정 — tab by tab its subscriptions, the seats of one of them and who administers it (ADR-0177 decisions
|
|
7
|
+
* 2-6; its money is a recurring item's, 개정 7). The keepers keep all of it; an admin keeps what is under their own account, not the account
|
|
9
8
|
* or its admins.
|
|
10
9
|
*/
|
|
11
10
|
export declare class SaasAccountPage extends SaasAccountPage_base {
|
|
@@ -46,7 +45,6 @@ export declare class SaasAccountPage extends SaasAccountPage_base {
|
|
|
46
45
|
total: any;
|
|
47
46
|
records: any;
|
|
48
47
|
}>;
|
|
49
|
-
private openBill;
|
|
50
48
|
private save;
|
|
51
49
|
/** The admins are a field of the account - the grid's rows, less the deleted, saved as its list. */
|
|
52
50
|
private saveAdmins;
|