@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.
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,67 +1,18 @@
1
- import { BankAccount, Transaction } from '@things-factory/accounting';
1
+ import { BankAccount } from '@things-factory/accounting';
2
2
  import { User } from '@things-factory/auth-base';
3
3
  import { Counterparty } from '@things-factory/biz-base';
4
4
  import { Domain, ListParam } from '@things-factory/shell';
5
5
  import { SaasAccount } from './saas-account';
6
- import { SaasBill } from './saas-bill';
7
6
  import { SaasSeat } from './saas-seat';
8
7
  import { SaasSubscription } from './saas-subscription';
9
- import { SaasAccountList, SaasCandidate, SaasChange } from './saas-type';
8
+ import { SaasAccountList, SaasChange } from './saas-type';
10
9
  export declare class SaasAccountQuery {
11
10
  saasAccounts(params: ListParam, context: ResolverContext): Promise<SaasAccountList>;
12
11
  mySaasAccounts(context: ResolverContext): Promise<SaasAccount[]>;
13
12
  saasAccount(id: string, context: ResolverContext): Promise<SaasAccount>;
14
13
  saasSubscriptions(accountId: string, context: ResolverContext): Promise<SaasSubscription[]>;
15
14
  saasSeats(subscriptionId: string, context: ResolverContext): Promise<SaasSeat[]>;
16
- saasBills(accountId: string, context: ResolverContext): Promise<SaasBill[]>;
17
15
  saasChanges(accountId: string, context: ResolverContext): Promise<SaasChange[]>;
18
- saasPayments(accountId: string, context: ResolverContext): Promise<Transaction[]>;
19
- saasCandidates(hidden: boolean, context: ResolverContext): Promise<SaasCandidate[]>;
20
- saasCostTrend(from: string, to: string, context: ResolverContext): Promise<{
21
- months: string[];
22
- all: import("./saas-rules").TrendSeries[];
23
- accounts: {
24
- name: string;
25
- key: string;
26
- accountId?: string | null;
27
- subscriptionId?: string | null;
28
- currency: string;
29
- amounts: number[];
30
- total: number;
31
- monthOverMonth: number | null;
32
- yearOverYear: number | null;
33
- }[];
34
- subscriptions: {
35
- name: string;
36
- accountName: string;
37
- key: string;
38
- accountId?: string | null;
39
- subscriptionId?: string | null;
40
- currency: string;
41
- amounts: number[];
42
- total: number;
43
- monthOverMonth: number | null;
44
- yearOverYear: number | null;
45
- }[];
46
- departments: {
47
- total: number;
48
- key: string;
49
- departmentId: string | null;
50
- name: string | null;
51
- currency: string;
52
- amounts: number[];
53
- }[];
54
- alerts: {
55
- accountName: string;
56
- subscriptionName: string;
57
- accountId: string;
58
- month: string;
59
- kind: import("./saas-rules").SaasAlertKind;
60
- subscriptionId?: string;
61
- amount: number;
62
- limit: number;
63
- }[];
64
- }>;
65
16
  counterparty(row: SaasAccount): Counterparty | Promise<Counterparty>;
66
17
  parent(row: SaasAccount): SaasAccount | Promise<SaasAccount>;
67
18
  paymentAccount(row: SaasAccount): BankAccount | Promise<BankAccount>;
@@ -10,25 +10,18 @@ const type_graphql_1 = require("type-graphql");
10
10
  const typeorm_1 = require("typeorm");
11
11
  const saas_access_1 = require("./saas-access");
12
12
  const saas_account_1 = require("./saas-account");
13
- const saas_bill_1 = require("./saas-bill");
14
13
  const saas_service_1 = require("./saas-service");
15
14
  const saas_seat_1 = require("./saas-seat");
16
15
  const saas_subscription_1 = require("./saas-subscription");
17
16
  const saas_type_1 = require("./saas-type");
18
17
  const today = () => new Date().toISOString().slice(0, 10);
19
- /** The accounts with their admins and their months (decision 10) - the list's relations in one read each. */
18
+ /** The accounts with their admins - the list's relation in one read. */
20
19
  async function withAdmins(tx, state, items) {
21
20
  if (!items.length)
22
21
  return items;
23
- const { domain, user, unsafeIP, prohibitedPrivileges } = state;
24
22
  const rows = await tx.getRepository(saas_account_1.SaasAccount).find({ where: { id: (0, typeorm_1.In)(items.map(one => one.id)) }, relations: ['admins'] });
25
- /* What left the bank is the bank's fact (ADR-0139) - read into the months only for whoever reads bank lines. */
26
- const withBank = await (0, auth_base_1.checkPermission)({ category: 'bank', privilege: 'query', owner: false }, user, domain, unsafeIP, prohibitedPrivileges);
27
- const trends = await (0, saas_service_1.saasTrendsOf)(tx, domain, items, today(), withBank);
28
- for (const one of items) {
23
+ for (const one of items)
29
24
  one.admins = rows.find(row => row.id === one.id)?.admins ?? [];
30
- one.trend = trends.get(one.id);
31
- }
32
25
  return items;
33
26
  }
34
27
  let SaasAccountQuery = class SaasAccountQuery {
@@ -58,30 +51,11 @@ let SaasAccountQuery = class SaasAccountQuery {
58
51
  const manager = (0, shell_1.getRepository)(saas_account_1.SaasAccount).manager;
59
52
  return (0, saas_service_1.saasSeatsOf)(manager, context.state.domain, await (0, saas_access_1.scopeOf)(context.state, 'query', manager), subscriptionId);
60
53
  }
61
- async saasBills(accountId, context) {
62
- const manager = (0, shell_1.getRepository)(saas_account_1.SaasAccount).manager;
63
- return (0, saas_service_1.saasBillsOf)(manager, context.state.domain, await (0, saas_access_1.scopeOf)(context.state, 'query', manager), accountId);
64
- }
65
54
  async saasChanges(accountId, context) {
66
55
  const manager = (0, shell_1.getRepository)(saas_account_1.SaasAccount).manager;
67
56
  const rows = await (0, saas_service_1.saasChangesOf)(manager, context.state.domain, await (0, saas_access_1.scopeOf)(context.state, 'query', manager), accountId);
68
57
  return rows.map((one) => ({ subject: one.subject, factKind: one.factKind, field: one.field, fromValue: one.fromValue, toValue: one.toValue, at: one.at, changedBy: one.changedBy?.name }));
69
58
  }
70
- /* The bank lines are the bank's facts (ADR-0139): this door asks the bank's privilege, the account's scope on top. */
71
- async saasPayments(accountId, context) {
72
- const manager = (0, shell_1.getRepository)(saas_account_1.SaasAccount).manager;
73
- return (0, saas_service_1.saasPaymentsOf)(manager, context.state.domain, await (0, saas_access_1.scopeOf)(context.state, 'query', manager), accountId);
74
- }
75
- /* Read from the bank and card lines (ADR-0139): the bank's door; the candidates are the keepers' (`saas`) on top. */
76
- async saasCandidates(hidden, context) {
77
- const manager = (0, shell_1.getRepository)(saas_account_1.SaasAccount).manager;
78
- if ((await (0, saas_access_1.scopeOf)(context.state, 'query', manager)) !== 'all')
79
- return [];
80
- return (0, saas_service_1.saasCandidatesOf)(manager, context.state.domain, today(), !!hidden);
81
- }
82
- saasCostTrend(from, to, context) {
83
- return (0, saas_service_1.saasCostTrend)((0, shell_1.getRepository)(saas_account_1.SaasAccount).manager, context.state.domain, from, to);
84
- }
85
59
  counterparty(row) {
86
60
  return row.counterparty ?? (row.counterpartyId ? (0, shell_1.getRepository)(biz_base_1.Counterparty).findOneBy({ id: row.counterpartyId }) : undefined);
87
61
  }
@@ -143,15 +117,6 @@ tslib_1.__decorate([
143
117
  tslib_1.__metadata("design:paramtypes", [String, Object]),
144
118
  tslib_1.__metadata("design:returntype", Promise)
145
119
  ], SaasAccountQuery.prototype, "saasSeats", null);
146
- tslib_1.__decorate([
147
- (0, type_graphql_1.Directive)('@privilege(category: "saas-self", privilege: "query", domainOwnerGranted: true)'),
148
- (0, type_graphql_1.Query)(type => [saas_bill_1.SaasBill], { description: 'The bills of an account, latest first, with their lines' }),
149
- tslib_1.__param(0, (0, type_graphql_1.Arg)('accountId')),
150
- tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
151
- tslib_1.__metadata("design:type", Function),
152
- tslib_1.__metadata("design:paramtypes", [String, Object]),
153
- tslib_1.__metadata("design:returntype", Promise)
154
- ], SaasAccountQuery.prototype, "saasBills", null);
155
120
  tslib_1.__decorate([
156
121
  (0, type_graphql_1.Directive)('@privilege(category: "saas-self", privilege: "query", domainOwnerGranted: true)'),
157
122
  (0, type_graphql_1.Query)(type => [saas_type_1.SaasChange], { description: 'What moved on an account and its subscriptions, newest first' }),
@@ -161,34 +126,6 @@ tslib_1.__decorate([
161
126
  tslib_1.__metadata("design:paramtypes", [String, Object]),
162
127
  tslib_1.__metadata("design:returntype", Promise)
163
128
  ], SaasAccountQuery.prototype, "saasChanges", null);
164
- tslib_1.__decorate([
165
- (0, type_graphql_1.Directive)('@privilege(category: "bank", privilege: "query", domainOwnerGranted: false)'),
166
- (0, type_graphql_1.Query)(type => [accounting_1.Transaction], { description: "The bank lines that paid an account's vendor, newest first" }),
167
- tslib_1.__param(0, (0, type_graphql_1.Arg)('accountId')),
168
- tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
169
- tslib_1.__metadata("design:type", Function),
170
- tslib_1.__metadata("design:paramtypes", [String, Object]),
171
- tslib_1.__metadata("design:returntype", Promise)
172
- ], SaasAccountQuery.prototype, "saasPayments", null);
173
- tslib_1.__decorate([
174
- (0, type_graphql_1.Directive)('@privilege(category: "bank", privilege: "query", domainOwnerGranted: false)'),
175
- (0, type_graphql_1.Query)(type => [saas_type_1.SaasCandidate], { description: 'The vendors the bank and card lines show paid month after month that are no account or recurring item yet; with hidden, the ones hidden' }),
176
- tslib_1.__param(0, (0, type_graphql_1.Arg)('hidden', { nullable: true })),
177
- tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
178
- tslib_1.__metadata("design:type", Function),
179
- tslib_1.__metadata("design:paramtypes", [Boolean, Object]),
180
- tslib_1.__metadata("design:returntype", Promise)
181
- ], SaasAccountQuery.prototype, "saasCandidates", null);
182
- tslib_1.__decorate([
183
- (0, type_graphql_1.Directive)('@privilege(category: "saas", privilege: "query", domainOwnerGranted: true)'),
184
- (0, type_graphql_1.Query)(type => saas_type_1.SaasCostTrend, { description: 'The cost trend from the bills, month by month from one month to another (YYYY-MM)' }),
185
- tslib_1.__param(0, (0, type_graphql_1.Arg)('from')),
186
- tslib_1.__param(1, (0, type_graphql_1.Arg)('to')),
187
- tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
188
- tslib_1.__metadata("design:type", Function),
189
- tslib_1.__metadata("design:paramtypes", [String, String, Object]),
190
- tslib_1.__metadata("design:returntype", void 0)
191
- ], SaasAccountQuery.prototype, "saasCostTrend", null);
192
129
  tslib_1.__decorate([
193
130
  (0, type_graphql_1.FieldResolver)(type => biz_base_1.Counterparty, { nullable: true }),
194
131
  tslib_1.__param(0, (0, type_graphql_1.Root)()),
@@ -1 +1 @@
1
- {"version":3,"file":"saas-query.js","sourceRoot":"","sources":["../../server/service/saas-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { BankAccount, Transaction } from '@things-factory/accounting'\nimport { checkPermission, User } from '@things-factory/auth-base'\nimport { Counterparty } from '@things-factory/biz-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam, SpeakRefusals } from '@things-factory/shell'\nimport { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { accountIn, administeredBy, scopeOf } from './saas-access'\nimport { SaasAccount } from './saas-account'\nimport { SaasBill } from './saas-bill'\nimport { saasBillsOf, saasCandidatesOf, saasChangesOf, saasCostTrend, saasPaymentsOf, saasSeatsOf, saasSubscriptionsOf, saasTrendsOf } from './saas-service'\nimport { SaasSeat } from './saas-seat'\nimport { SaasSubscription } from './saas-subscription'\nimport { SaasAccountList, SaasCandidate, SaasChange, SaasCostTrend } from './saas-type'\n\nconst today = () => new Date().toISOString().slice(0, 10)\n\n/** The accounts with their admins and their months (decision 10) - the list's relations in one read each. */\nasync function withAdmins(tx: any, state: any, items: SaasAccount[]) {\n if (!items.length) return items\n const { domain, user, unsafeIP, prohibitedPrivileges } = state\n const rows = await tx.getRepository(SaasAccount).find({ where: { id: In(items.map(one => one.id)) }, relations: ['admins'] })\n /* What left the bank is the bank's fact (ADR-0139) - read into the months only for whoever reads bank lines. */\n const withBank = await checkPermission({ category: 'bank', privilege: 'query', owner: false } as any, user, domain, unsafeIP, prohibitedPrivileges)\n const trends = await saasTrendsOf(tx, domain, items, today(), withBank)\n for (const one of items) {\n one.admins = rows.find(row => row.id === one.id)?.admins ?? []\n one.trend = trends.get(one.id)\n }\n return items\n}\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(SaasAccount)\nexport class SaasAccountQuery {\n @Directive('@privilege(category: \"saas\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => SaasAccountList, { description: 'To fetch a page of the accounts the domain holds with vendors' })\n async saasAccounts(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<SaasAccountList> {\n const query = getQueryBuilderFromListParams({ domain: context.state.domain, params, repository: getRepository(SaasAccount), searchables: ['name', 'identifier', 'purpose', 'billingEmail', 'description'] })\n const [items, total] = await query.getManyAndCount()\n return { items: await withAdmins(getRepository(SaasAccount).manager, context.state, items), total }\n }\n\n @Directive('@privilege(category: \"saas-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => [SaasAccount], { description: 'The accounts the signed-in person is named an admin of' })\n async mySaasAccounts(@Ctx() context: ResolverContext): Promise<SaasAccount[]> {\n const { domain, user } = context.state\n const manager = getRepository(SaasAccount).manager\n const ids = await administeredBy(manager, domain, user?.id)\n if (!ids.length) return []\n return withAdmins(manager, context.state, await getRepository(SaasAccount).find({ where: { domain: { id: domain.id }, id: In(ids) } as any, order: { name: 'ASC' } as any }))\n }\n\n @Directive('@privilege(category: \"saas-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => SaasAccount, { description: 'To fetch an account - a reader’s any, an admin’s own' })\n async saasAccount(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<SaasAccount> {\n const manager = getRepository(SaasAccount).manager\n const account = await accountIn(manager, context.state.domain, await scopeOf(context.state, 'query', manager), id)\n return (await withAdmins(manager, context.state, [account]))[0]\n }\n\n @Directive('@privilege(category: \"saas-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => [SaasSubscription], { description: 'The subscriptions of an account, with the seats held today' })\n async saasSubscriptions(@Arg('accountId') accountId: string, @Ctx() context: ResolverContext): Promise<SaasSubscription[]> {\n const manager = getRepository(SaasAccount).manager\n return saasSubscriptionsOf(manager, context.state.domain, await scopeOf(context.state, 'query', manager), accountId, today())\n }\n\n @Directive('@privilege(category: \"saas-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => [SaasSeat], { description: 'The seats of a subscription' })\n async saasSeats(@Arg('subscriptionId') subscriptionId: string, @Ctx() context: ResolverContext): Promise<SaasSeat[]> {\n const manager = getRepository(SaasAccount).manager\n return saasSeatsOf(manager, context.state.domain, await scopeOf(context.state, 'query', manager), subscriptionId)\n }\n\n @Directive('@privilege(category: \"saas-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => [SaasBill], { description: 'The bills of an account, latest first, with their lines' })\n async saasBills(@Arg('accountId') accountId: string, @Ctx() context: ResolverContext): Promise<SaasBill[]> {\n const manager = getRepository(SaasAccount).manager\n return saasBillsOf(manager, context.state.domain, await scopeOf(context.state, 'query', manager), accountId)\n }\n\n @Directive('@privilege(category: \"saas-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => [SaasChange], { description: 'What moved on an account and its subscriptions, newest first' })\n async saasChanges(@Arg('accountId') accountId: string, @Ctx() context: ResolverContext): Promise<SaasChange[]> {\n const manager = getRepository(SaasAccount).manager\n const rows = await saasChangesOf(manager, context.state.domain, await scopeOf(context.state, 'query', manager), accountId)\n return rows.map((one: any) => ({ subject: one.subject, factKind: one.factKind, field: one.field, fromValue: one.fromValue, toValue: one.toValue, at: one.at, changedBy: one.changedBy?.name }))\n }\n\n /* The bank lines are the bank's facts (ADR-0139): this door asks the bank's privilege, the account's scope on top. */\n @Directive('@privilege(category: \"bank\", privilege: \"query\", domainOwnerGranted: false)')\n @Query(type => [Transaction], { description: \"The bank lines that paid an account's vendor, newest first\" })\n async saasPayments(@Arg('accountId') accountId: string, @Ctx() context: ResolverContext): Promise<Transaction[]> {\n const manager = getRepository(SaasAccount).manager\n return saasPaymentsOf(manager, context.state.domain, await scopeOf(context.state, 'query', manager), accountId)\n }\n\n /* Read from the bank and card lines (ADR-0139): the bank's door; the candidates are the keepers' (`saas`) on top. */\n @Directive('@privilege(category: \"bank\", privilege: \"query\", domainOwnerGranted: false)')\n @Query(type => [SaasCandidate], { description: 'The vendors the bank and card lines show paid month after month that are no account or recurring item yet; with hidden, the ones hidden' })\n async saasCandidates(@Arg('hidden', { nullable: true }) hidden: boolean, @Ctx() context: ResolverContext): Promise<SaasCandidate[]> {\n const manager = getRepository(SaasAccount).manager\n if ((await scopeOf(context.state, 'query', manager)) !== 'all') return []\n return saasCandidatesOf(manager, context.state.domain, today(), !!hidden) as any\n }\n\n @Directive('@privilege(category: \"saas\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => SaasCostTrend, { description: 'The cost trend from the bills, month by month from one month to another (YYYY-MM)' })\n saasCostTrend(@Arg('from') from: string, @Arg('to') to: string, @Ctx() context: ResolverContext) {\n return saasCostTrend(getRepository(SaasAccount).manager, context.state.domain, from, to)\n }\n\n @FieldResolver(type => Counterparty, { nullable: true })\n counterparty(@Root() row: SaasAccount) {\n return row.counterparty ?? (row.counterpartyId ? getRepository(Counterparty).findOneBy({ id: row.counterpartyId }) : undefined)\n }\n\n @FieldResolver(type => SaasAccount, { nullable: true })\n parent(@Root() row: SaasAccount) {\n return row.parent ?? (row.parentId ? getRepository(SaasAccount).findOneBy({ id: row.parentId }) : undefined)\n }\n\n @FieldResolver(type => BankAccount, { nullable: true })\n paymentAccount(@Root() row: SaasAccount) {\n return row.paymentAccount ?? (row.paymentAccountId ? getRepository(BankAccount).findOneBy({ id: row.paymentAccountId }) : undefined)\n }\n\n @FieldResolver(type => Domain, { nullable: true })\n domain(@Root() row: SaasAccount) {\n return row.domain ?? (row.domainId ? getRepository(Domain).findOneBy({ id: row.domainId }) : undefined)\n }\n\n @FieldResolver(type => User, { nullable: true })\n updater(@Root() row: SaasAccount) {\n return row.updater ?? (row.updaterId ? getRepository(User).findOneBy({ id: row.updaterId }) : undefined)\n }\n}\n"]}
1
+ {"version":3,"file":"saas-query.js","sourceRoot":"","sources":["../../server/service/saas-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { BankAccount } from '@things-factory/accounting'\nimport { User } from '@things-factory/auth-base'\nimport { Counterparty } from '@things-factory/biz-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam, SpeakRefusals } from '@things-factory/shell'\nimport { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { accountIn, administeredBy, scopeOf } from './saas-access'\nimport { SaasAccount } from './saas-account'\nimport { saasChangesOf, saasSeatsOf, saasSubscriptionsOf } from './saas-service'\nimport { SaasSeat } from './saas-seat'\nimport { SaasSubscription } from './saas-subscription'\nimport { SaasAccountList, SaasChange } from './saas-type'\n\nconst today = () => new Date().toISOString().slice(0, 10)\n\n/** The accounts with their admins - the list's relation in one read. */\nasync function withAdmins(tx: any, state: any, items: SaasAccount[]) {\n if (!items.length) return items\n const rows = await tx.getRepository(SaasAccount).find({ where: { id: In(items.map(one => one.id)) }, relations: ['admins'] })\n for (const one of items) one.admins = rows.find(row => row.id === one.id)?.admins ?? []\n return items\n}\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(SaasAccount)\nexport class SaasAccountQuery {\n @Directive('@privilege(category: \"saas\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => SaasAccountList, { description: 'To fetch a page of the accounts the domain holds with vendors' })\n async saasAccounts(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<SaasAccountList> {\n const query = getQueryBuilderFromListParams({ domain: context.state.domain, params, repository: getRepository(SaasAccount), searchables: ['name', 'identifier', 'purpose', 'billingEmail', 'description'] })\n const [items, total] = await query.getManyAndCount()\n return { items: await withAdmins(getRepository(SaasAccount).manager, context.state, items), total }\n }\n\n @Directive('@privilege(category: \"saas-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => [SaasAccount], { description: 'The accounts the signed-in person is named an admin of' })\n async mySaasAccounts(@Ctx() context: ResolverContext): Promise<SaasAccount[]> {\n const { domain, user } = context.state\n const manager = getRepository(SaasAccount).manager\n const ids = await administeredBy(manager, domain, user?.id)\n if (!ids.length) return []\n return withAdmins(manager, context.state, await getRepository(SaasAccount).find({ where: { domain: { id: domain.id }, id: In(ids) } as any, order: { name: 'ASC' } as any }))\n }\n\n @Directive('@privilege(category: \"saas-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => SaasAccount, { description: 'To fetch an account - a reader’s any, an admin’s own' })\n async saasAccount(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<SaasAccount> {\n const manager = getRepository(SaasAccount).manager\n const account = await accountIn(manager, context.state.domain, await scopeOf(context.state, 'query', manager), id)\n return (await withAdmins(manager, context.state, [account]))[0]\n }\n\n @Directive('@privilege(category: \"saas-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => [SaasSubscription], { description: 'The subscriptions of an account, with the seats held today' })\n async saasSubscriptions(@Arg('accountId') accountId: string, @Ctx() context: ResolverContext): Promise<SaasSubscription[]> {\n const manager = getRepository(SaasAccount).manager\n return saasSubscriptionsOf(manager, context.state.domain, await scopeOf(context.state, 'query', manager), accountId, today())\n }\n\n @Directive('@privilege(category: \"saas-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => [SaasSeat], { description: 'The seats of a subscription' })\n async saasSeats(@Arg('subscriptionId') subscriptionId: string, @Ctx() context: ResolverContext): Promise<SaasSeat[]> {\n const manager = getRepository(SaasAccount).manager\n return saasSeatsOf(manager, context.state.domain, await scopeOf(context.state, 'query', manager), subscriptionId)\n }\n\n @Directive('@privilege(category: \"saas-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => [SaasChange], { description: 'What moved on an account and its subscriptions, newest first' })\n async saasChanges(@Arg('accountId') accountId: string, @Ctx() context: ResolverContext): Promise<SaasChange[]> {\n const manager = getRepository(SaasAccount).manager\n const rows = await saasChangesOf(manager, context.state.domain, await scopeOf(context.state, 'query', manager), accountId)\n return rows.map((one: any) => ({ subject: one.subject, factKind: one.factKind, field: one.field, fromValue: one.fromValue, toValue: one.toValue, at: one.at, changedBy: one.changedBy?.name }))\n }\n\n @FieldResolver(type => Counterparty, { nullable: true })\n counterparty(@Root() row: SaasAccount) {\n return row.counterparty ?? (row.counterpartyId ? getRepository(Counterparty).findOneBy({ id: row.counterpartyId }) : undefined)\n }\n\n @FieldResolver(type => SaasAccount, { nullable: true })\n parent(@Root() row: SaasAccount) {\n return row.parent ?? (row.parentId ? getRepository(SaasAccount).findOneBy({ id: row.parentId }) : undefined)\n }\n\n @FieldResolver(type => BankAccount, { nullable: true })\n paymentAccount(@Root() row: SaasAccount) {\n return row.paymentAccount ?? (row.paymentAccountId ? getRepository(BankAccount).findOneBy({ id: row.paymentAccountId }) : undefined)\n }\n\n @FieldResolver(type => Domain, { nullable: true })\n domain(@Root() row: SaasAccount) {\n return row.domain ?? (row.domainId ? getRepository(Domain).findOneBy({ id: row.domainId }) : undefined)\n }\n\n @FieldResolver(type => User, { nullable: true })\n updater(@Root() row: SaasAccount) {\n return row.updater ?? (row.updaterId ? getRepository(User).findOneBy({ id: row.updaterId }) : undefined)\n }\n}\n"]}
@@ -15,118 +15,21 @@ export declare enum SaasSubscriptionStatus {
15
15
  CANCELLED = "CANCELLED"
16
16
  }
17
17
  export declare const DATE: RegExp;
18
- export declare const MONTH: RegExp;
19
- /** An account's bill rising more than this over the month before is told, unless the account names its own rate. */
20
- export declare const DEFAULT_INCREASE_ALERT_RATE = 0.2;
21
- /** Metered usage is expected at the average of so many latest bills. */
22
- export declare const USAGE_AVERAGE_MONTHS = 3;
23
18
  export interface SubscriptionFacts {
24
19
  id: string;
25
20
  billing: SaasBilling | string;
26
21
  quantity?: number | null;
27
22
  unitPrice?: number | null;
28
- amount?: number | null;
29
- budget?: number | null;
30
- everyMonths?: number | null;
31
23
  startOn: string;
32
24
  renewalOn?: string | null;
33
25
  endedOn?: string | null;
34
26
  status: SaasSubscriptionStatus | string;
35
27
  }
36
- export interface BillFacts {
37
- accountId: string;
38
- month: string;
39
- currency: string;
40
- lines: {
41
- subscriptionId?: string | null;
42
- amount: number;
43
- }[];
44
- }
45
- export declare const monthKey: (year: number, month: number) => string;
46
- /** The month a number of months from a `YYYY-MM`. */
47
- export declare function shiftMonth(key: string, by: number): string;
48
- /** The months from one `YYYY-MM` to another, both in. */
49
- export declare function monthsFrom(from: string, to: string): string[];
50
- /**
51
- * The last month it is billed in: a cancelled one in the month it ended, when the bill of that month falls on or before
52
- * the day it ended, else the month before; one not to be renewed in the month before its renewal day. Open otherwise.
53
- */
54
- export declare function lastBilledMonth(sub: SubscriptionFacts, billingDay?: number | null): string | null;
55
- /** Whether it is billed in a month - from the month it started, every so many months, to its last. An owned license never is. */
56
- export declare function billedIn(sub: SubscriptionFacts, year: number, month: number, billingDay?: number | null): boolean;
57
- /** What one billing of it costs, as the subscription says: seats times the unit price, the fee. Usage says nothing - null. */
58
- export declare function cycleAmountOf(sub: SubscriptionFacts): number | null;
59
- /** Metered usage expected for a month: the average of its latest billed months (decision Q3), else its budget, else nothing. */
60
- export declare function usageEstimate(sub: SubscriptionFacts, billed: {
61
- month: string;
62
- amount: number;
63
- }[]): number | null;
64
- /**
65
- * What an account is expected to be billed in a month (decision 4): the subscriptions billed in it, each at what it says
66
- * or, for usage, at its estimate - on the account's billing day. Nothing for a closed account, a sub-account or a month
67
- * nothing falls in.
68
- */
69
- export declare function expectedOfMonth(account: {
70
- status: string;
71
- parentId?: string | null;
72
- billingDay?: number | null;
73
- }, subs: SubscriptionFacts[], billedBySubscription: Map<string, {
74
- month: string;
75
- amount: number;
76
- }[]>, year: number, month: number): {
77
- amount: number;
78
- day: string | null;
79
- parts: {
80
- subscriptionId: string;
81
- amount: number;
82
- }[];
83
- } | null;
84
- /** A bill's total - the sum of its lines, credits below zero. */
85
- export declare const billTotal: (lines: {
86
- amount: number;
87
- }[]) => number;
88
- /** How a series moved: the last month over the one before, and over the same month a year before - null when nothing to compare. */
89
- export declare function changesOf(amounts: number[]): {
90
- monthOverMonth: number | null;
91
- yearOverYear: number | null;
92
- };
93
- export interface TrendSeries {
94
- key: string;
95
- accountId?: string | null;
96
- subscriptionId?: string | null;
97
- currency: string;
98
- amounts: number[];
99
- total: number;
100
- monthOverMonth: number | null;
101
- yearOverYear: number | null;
102
- }
103
- /**
104
- * The cost trend from the bills (decision 9), month by month from `from` to `to`, in each bill's own currency: one series
105
- * an account, one a subscription (lines on no subscription - tax, credits - in `rest` of the account), one a currency in
106
- * all. Computed, never stored.
107
- */
108
- export declare function trendOf(bills: BillFacts[], from: string, to: string): {
109
- months: string[];
110
- all: TrendSeries[];
111
- accounts: TrendSeries[];
112
- subscriptions: TrendSeries[];
113
- };
114
- export type SaasAlertKind = 'usage-over-budget' | 'bill-increased' | 'seat-bill-differs';
115
28
  /**
116
- * What a month's bill of an account is worth telling (decision 9): usage over its budget, the bill up more than the
117
- * account's rate over the month before, a seat plan billed other than its seats times its price (a price rise, a seat
118
- * added by the vendor).
29
+ * What its quantity and unit price make - a reference a person compares with the recurring item's actual (개정 7-3):
30
+ * seats or units times the price, a fee with no quantity once. Null when no price is written; an owned license none.
119
31
  */
120
- export declare function alertsOf(account: {
121
- id: string;
122
- increaseAlertRate?: number | null;
123
- billingDay?: number | null;
124
- }, subs: SubscriptionFacts[], bill: BillFacts, previous?: BillFacts | null): {
125
- kind: SaasAlertKind;
126
- subscriptionId?: string;
127
- amount: number;
128
- limit: number;
129
- }[];
32
+ export declare function referenceAmountOf(sub: SubscriptionFacts): number | null;
130
33
  /** Whether its renewal is near: from so many days before its renewal day (none - the day itself) to the day, while in use. */
131
34
  export declare function renewalDue(sub: SubscriptionFacts & {
132
35
  noticeDays?: number | null;
@@ -136,44 +39,3 @@ export declare const seatHeld: (seat: {
136
39
  fromOn?: string | null;
137
40
  untilOn?: string | null;
138
41
  }, today: string) => boolean;
139
- /**
140
- * A line of money out - a bank withdrawal or a card's charge - and whom it paid: its counterparty, or for a line no
141
- * counterparty is linked to, the name written on it (`key` is the counterparty id, else `name:` and the name's key).
142
- */
143
- export interface VendorLine {
144
- key: string;
145
- counterpartyId?: string | null;
146
- name?: string | null;
147
- transactionDate: string;
148
- amount: number;
149
- currency?: string | null;
150
- bankAccountId?: string | null;
151
- }
152
- export interface CandidateFacts {
153
- key: string;
154
- /** The counterparty paid; none when the lines only name it - a new account registers it. */
155
- counterpartyId: string | null;
156
- /** The name written most on the lines. */
157
- name: string | null;
158
- /** The months money went out in, of the window. */
159
- months: number;
160
- /** What went out a month, on average over those months. */
161
- average: number;
162
- /** The first line of the window - the subscription is known to have started by then. */
163
- firstDate: string;
164
- lastDate: string;
165
- lastAmount: number;
166
- currency: string;
167
- /** The account or card it went out of most. */
168
- paymentAccountId: string | null;
169
- /** The day of the month it went out on most; a month's last day is 31. */
170
- billingDay: number | null;
171
- }
172
- /** At least this many months of the window paid one vendor before it looks like a subscription. */
173
- export declare const CANDIDATE_MIN_MONTHS = 3;
174
- /**
175
- * Whom the lines say is paid month after month - in at least `CANDIDATE_MIN_MONTHS` months, in the currency paid most -
176
- * each with what a new account and its subscription would start from. Those whose key is in `skip` (already an
177
- * account, a recurring item, hidden) are not candidates. Largest first.
178
- */
179
- export declare function candidatesOf(lines: readonly VendorLine[], skip: ReadonlySet<string>): CandidateFacts[];