@vrplatform/hyperline-client 1.0.10 → 1.0.12

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.
@@ -2,3 +2,4 @@ export * from './const';
2
2
  export * from './types';
3
3
  export * from './client';
4
4
  export * from './hooks';
5
+ export * from './utils';
@@ -2,4 +2,5 @@ export * from './const';
2
2
  export * from './types';
3
3
  export * from './client';
4
4
  export * from './hooks';
5
+ export * from './utils';
5
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"src/","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC","sourcesContent":["export * from './const';\nexport * from './types';\nexport * from './client';\nexport * from './hooks';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"src/","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC","sourcesContent":["export * from './const';\nexport * from './types';\nexport * from './client';\nexport * from './hooks';\nexport * from './utils';\n"]}
@@ -1 +1 @@
1
- {"root":["../../src/_types.generated.ts","../../src/client.ts","../../src/const.ts","../../src/hooks.ts","../../src/index.ts","../../src/types.ts","../../src/utils.ts"],"version":"5.7.3"}
1
+ {"root":["../../src/_types.generated.ts","../../src/client.ts","../../src/const.ts","../../src/hooks.ts","../../src/index.ts","../../src/types.ts","../../src/utils/arraybuffertobase64.ts","../../src/utils/getmrrdiffreasons.ts","../../src/utils/index.ts"],"version":"5.7.3"}
@@ -0,0 +1 @@
1
+ export declare function arrayBufferToBase64(arrayBuffer: ArrayBuffer): string;
@@ -0,0 +1,6 @@
1
+ export function arrayBufferToBase64(arrayBuffer) {
2
+ const uint8Array = new Uint8Array(arrayBuffer);
3
+ const binaryString = String.fromCharCode.apply(null, uint8Array);
4
+ return btoa(binaryString);
5
+ }
6
+ //# sourceMappingURL=arrayBufferToBase64.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arrayBufferToBase64.js","sourceRoot":"src/","sources":["utils/arrayBufferToBase64.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,mBAAmB,CAAC,WAAwB;IAC1D,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,UAAiB,CAAC,CAAC;IACxE,OAAO,IAAI,CAAC,YAAY,CAAC,CAAC;AAC5B,CAAC","sourcesContent":["export function arrayBufferToBase64(arrayBuffer: ArrayBuffer) {\n const uint8Array = new Uint8Array(arrayBuffer);\n const binaryString = String.fromCharCode.apply(null, uint8Array as any);\n return btoa(binaryString);\n}\n"]}
@@ -0,0 +1,20 @@
1
+ export declare function getMrrDiffReasons(firstDate: string, lastDate: string, client?: {
2
+ readonly client: GQtyClient<import("@finalytic/graphql").GeneratedSchema>;
3
+ subscriptionsClient: import("gqty").SubscriptionsClient;
4
+ mutate<T = unknown>(resolved: (sub: import("@finalytic/graphql").Mutation) => T, options?: import("@finalytic/graphql").ResolveOptionsWithSession<T>): Promise<T>;
5
+ query<T = unknown>(resolved: (sub: import("@finalytic/graphql").Query) => T, options?: import("@finalytic/graphql").ResolveOptionsWithSession<T>): Promise<T>;
6
+ subscribe<T = unknown>(resolved: (sub: import("@finalytic/graphql").Subscription) => T, onData: (data: T, unsubscribeFn: () => Promise<void>) => void, onError?: (err: Error, unsubscribeFn: () => Promise<void>) => void): () => Promise<void>;
7
+ }): Promise<{
8
+ messages: string[];
9
+ result: {
10
+ mrrDiff: number;
11
+ listingsDiff: number;
12
+ hasCancelled: boolean;
13
+ id: string;
14
+ name?: string;
15
+ plan?: string;
16
+ activePartnerTeamsDiff: number;
17
+ createdAt: string;
18
+ isNew: boolean;
19
+ }[];
20
+ }>;
@@ -0,0 +1,214 @@
1
+ import { useHasuraClient } from '@finalytic/graphql';
2
+ import { groupBy, utc } from '@finalytic/utils';
3
+ import { VRP_TENANT_ID, XIMPLIFI_TENANT_ID, } from '@vrplatform/hyperline-client';
4
+ function printFinancialNumber(number, showPlusMinus = true) {
5
+ return `${showPlusMinus ? (number >= 0 ? '+' : '-') : ''}$${Math.abs(number)
6
+ .toFixed(2)
7
+ .toString()
8
+ .replace(/\B(?=(\d{3})+(?!\d))/g, ',')}`;
9
+ }
10
+ function printPlusMinus(number) {
11
+ return `${number >= 0 ? '+' : '-'}${Math.abs(number)}`;
12
+ }
13
+ const hasura = useHasuraClient({
14
+ secret: process.env.HASURA_GRAPHQL_ADMIN_SECRET,
15
+ });
16
+ export async function getMrrDiffReasons(firstDate, lastDate, client = hasura) {
17
+ const messages = [];
18
+ messages.push(`MRR Diff Reasons from ${utc(firstDate).yyyymmdd()} to ${utc(lastDate).yyyymmdd()}`);
19
+ messages.push('--------------------------------');
20
+ const { mrrEvents, listingsEvents } = await client.query((q) => ({
21
+ mrrEvents: q
22
+ .tracking_event({
23
+ where: {
24
+ name: { _eq: 'mrr_reported' },
25
+ _or: [
26
+ {
27
+ createdAt: {
28
+ _gte: utc(firstDate).yyyymmdd(),
29
+ _lte: utc(firstDate).add(1, 'day').yyyymmdd(),
30
+ },
31
+ },
32
+ {
33
+ createdAt: {
34
+ _gte: utc(lastDate).yyyymmdd(),
35
+ _lte: utc(lastDate).add(1, 'day').yyyymmdd(),
36
+ },
37
+ },
38
+ ],
39
+ },
40
+ })
41
+ .map((e) => ({
42
+ tenantId: e.tenant?.id,
43
+ tenantName: e.tenant?.name,
44
+ tenantCreatedAt: e.tenant?.createdAt,
45
+ tenantPlan: e.tenant?.billingPlan,
46
+ partnerTeamsCreatedFirstDate: e.tenant
47
+ ?.clients({
48
+ where: {
49
+ createdAt: {
50
+ _lte: utc(firstDate).yyyymmdd(),
51
+ },
52
+ },
53
+ })
54
+ .map((c) => c.id).length,
55
+ partnerTeamsCreatedLastDate: e.tenant
56
+ ?.clients({
57
+ where: {
58
+ createdAt: {
59
+ _lte: utc(lastDate).yyyymmdd(),
60
+ },
61
+ },
62
+ })
63
+ .map((c) => c.id).length,
64
+ partnerTeamsCancelledFirstDate: e.tenant
65
+ ?.clients({
66
+ where: {
67
+ cancelledAt: {
68
+ _lte: utc(firstDate).yyyymmdd(),
69
+ },
70
+ },
71
+ })
72
+ .map((c) => c.id).length,
73
+ partnerTeamsCancelledLastDate: e.tenant
74
+ ?.clients({
75
+ where: {
76
+ cancelledAt: {
77
+ _lte: utc(lastDate).yyyymmdd(),
78
+ },
79
+ },
80
+ })
81
+ .map((c) => c.id).length,
82
+ mrr: e.props()?.mrr,
83
+ createdAt: utc(e.createdAt).yyyymmdd(),
84
+ })),
85
+ listingsEvents: q
86
+ .tracking_event({
87
+ where: {
88
+ name: { _eq: 'listings_reported' },
89
+ _or: [
90
+ {
91
+ createdAt: {
92
+ _gte: utc(firstDate).yyyymmdd(),
93
+ _lte: utc(firstDate).add(1, 'day').yyyymmdd(),
94
+ },
95
+ },
96
+ {
97
+ createdAt: {
98
+ _gte: utc(lastDate).yyyymmdd(),
99
+ _lte: utc(lastDate).add(1, 'day').yyyymmdd(),
100
+ },
101
+ },
102
+ ],
103
+ },
104
+ })
105
+ .map((e) => ({
106
+ tenantId: e.tenant?.id,
107
+ billingPartnerId: e.tenant?.calculatedBillingPartnerId,
108
+ listings: e.props()?.activeListings,
109
+ createdAt: utc(e.createdAt).yyyymmdd(),
110
+ })),
111
+ }));
112
+ messages.push(`Found ${mrrEvents.length} mrr events`);
113
+ // join mrr and listings events
114
+ const trackingEvents = mrrEvents.map((e) => {
115
+ const filteredEvents = listingsEvents.filter((l) => {
116
+ const tenantId = [VRP_TENANT_ID, XIMPLIFI_TENANT_ID].includes(l.billingPartnerId)
117
+ ? l.tenantId
118
+ : l.billingPartnerId;
119
+ return tenantId === e.tenantId && l.createdAt === e.createdAt;
120
+ });
121
+ return {
122
+ ...e,
123
+ listings: filteredEvents.reduce((acc, l) => acc + (l.listings ?? 0), 0),
124
+ };
125
+ });
126
+ // get list of tenants
127
+ const tenants = {};
128
+ for (const event of trackingEvents) {
129
+ if (!tenants[event.tenantId]) {
130
+ const partnerTeamsCreatedDiff = (event.partnerTeamsCreatedLastDate || 0) -
131
+ (event.partnerTeamsCreatedFirstDate || 0);
132
+ const partnerTeamsCancelledDiff = (event.partnerTeamsCancelledLastDate || 0) -
133
+ (event.partnerTeamsCancelledFirstDate || 0);
134
+ tenants[event.tenantId] = {
135
+ id: event.tenantId,
136
+ name: event.tenantName,
137
+ plan: event.tenantPlan,
138
+ activePartnerTeamsDiff: partnerTeamsCreatedDiff - partnerTeamsCancelledDiff,
139
+ mrrFirstDate: undefined,
140
+ mrrLastDate: undefined,
141
+ mrrDiff: 0,
142
+ listingsFirstDate: undefined,
143
+ listingsLastDate: undefined,
144
+ listingsDiff: 0,
145
+ createdAt: utc(event.tenantCreatedAt).yyyymmdd(),
146
+ isNew: utc(event.tenantCreatedAt).isBetween(utc(firstDate), utc(lastDate)),
147
+ };
148
+ }
149
+ if (event.createdAt === firstDate) {
150
+ tenants[event.tenantId].mrrFirstDate = event.mrr;
151
+ tenants[event.tenantId].listingsFirstDate = event.listings;
152
+ }
153
+ if (event.createdAt === lastDate) {
154
+ tenants[event.tenantId].mrrLastDate = event.mrr;
155
+ tenants[event.tenantId].listingsLastDate = event.listings;
156
+ }
157
+ }
158
+ const result = Object.values(tenants)
159
+ .map(({ mrrFirstDate, mrrLastDate, listingsFirstDate, listingsLastDate, ...t }) => ({
160
+ ...t,
161
+ mrrDiff: (mrrLastDate ?? 0) - (mrrFirstDate ?? 0),
162
+ listingsDiff: (listingsLastDate ?? 0) - (listingsFirstDate ?? 0),
163
+ hasCancelled: mrrFirstDate !== undefined && mrrLastDate === undefined,
164
+ }))
165
+ .filter((t) => t.mrrDiff)
166
+ .sort((a, b) => b.mrrDiff - a.mrrDiff)
167
+ .reverse();
168
+ // calculate summ of mrr per day
169
+ const groupedEvents = groupBy(trackingEvents, (e) => e.createdAt);
170
+ const summedMrrPerDay = Object.entries(groupedEvents)
171
+ .map(([date, events]) => {
172
+ const mrr = events.reduce((acc, e) => acc + (e.mrr ?? 0), 0);
173
+ const listings = events.reduce((acc, e) => acc + (e.listings ?? 0), 0);
174
+ return {
175
+ date,
176
+ mrr,
177
+ count: events.length,
178
+ listings,
179
+ };
180
+ })
181
+ .sort((a, b) => utc(b.date).diff(utc(a.date)));
182
+ messages.push(`MRR sum changed from ${printFinancialNumber(summedMrrPerDay[1].mrr, false)} to ${printFinancialNumber(summedMrrPerDay[0].mrr, false)} (${printFinancialNumber(summedMrrPerDay[0].mrr - summedMrrPerDay[1].mrr)})`);
183
+ messages.push(`MRR Reports changed from ${summedMrrPerDay[1].count.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} to ${summedMrrPerDay[0].count.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} (${printPlusMinus(summedMrrPerDay[0].count - summedMrrPerDay[1].count)})`);
184
+ messages.push(`Active Listings changed from ${summedMrrPerDay[1].listings.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} to ${summedMrrPerDay[0].listings.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} (${printPlusMinus(summedMrrPerDay[0].listings - summedMrrPerDay[1].listings)})`);
185
+ messages.push(`Active Partner Teams changed by ${printPlusMinus(result.reduce((acc, t) => acc + t.activePartnerTeamsDiff, 0))}`);
186
+ messages.push();
187
+ const cancelledTenants = result.filter((t) => t.hasCancelled);
188
+ const legacyTenants = result.filter((t) => t.plan?.includes('Legacy') &&
189
+ !cancelledTenants.map((t) => t.id).includes(t.id));
190
+ const newTenants = result.filter((t) => t.isNew &&
191
+ !cancelledTenants.map((t) => t.id).includes(t.id) &&
192
+ !legacyTenants.map((t) => t.id).includes(t.id));
193
+ const activeListings = result.filter((t) => t.listingsDiff &&
194
+ !newTenants.map((t) => t.id).includes(t.id) &&
195
+ !cancelledTenants.map((t) => t.id).includes(t.id) &&
196
+ !legacyTenants.map((t) => t.id).includes(t.id));
197
+ const otherTenants = result.filter((t) => !newTenants.map((t) => t.id).includes(t.id) &&
198
+ !cancelledTenants.map((t) => t.id).includes(t.id) &&
199
+ !legacyTenants.map((t) => t.id).includes(t.id) &&
200
+ !activeListings.map((t) => t.id).includes(t.id));
201
+ const total = newTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +
202
+ cancelledTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +
203
+ legacyTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +
204
+ activeListings.reduce((acc, t) => acc + t.mrrDiff, 0) +
205
+ otherTenants.reduce((acc, t) => acc + t.mrrDiff, 0);
206
+ messages.push(`MRR from ${newTenants.length} new tenants: ${printFinancialNumber(newTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`);
207
+ messages.push(`MRR from ${cancelledTenants.length} cancelled tenants: ${printFinancialNumber(cancelledTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`);
208
+ messages.push(`MRR from ${legacyTenants.length} tenants with Legacy plans: ${printFinancialNumber(legacyTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`);
209
+ messages.push(`MRR from ${activeListings.length} tenants with active listings changes: ${printFinancialNumber(activeListings.reduce((acc, t) => acc + t.mrrDiff, 0))}`);
210
+ messages.push(`MRR from ${otherTenants.length} other tenants: ${printFinancialNumber(otherTenants.reduce((acc, t) => acc + t.mrrDiff, 0))} (${otherTenants.map((t) => `${t.name} (${printFinancialNumber(t.mrrDiff)})`).join(', ')})`);
211
+ messages.push(`= ${printFinancialNumber(total)}`);
212
+ return { messages, result };
213
+ }
214
+ //# sourceMappingURL=getMrrDiffReasons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getMrrDiffReasons.js","sourceRoot":"src/","sources":["utils/getMrrDiffReasons.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EACL,aAAa,EACb,kBAAkB,GACnB,MAAM,8BAA8B,CAAC;AAEtC,SAAS,oBAAoB,CAAC,MAAc,EAAE,aAAa,GAAG,IAAI;IAChE,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;SACzE,OAAO,CAAC,CAAC,CAAC;SACV,QAAQ,EAAE;SACV,OAAO,CAAC,uBAAuB,EAAE,GAAG,CAAC,EAAE,CAAC;AAC7C,CAAC;AACD,SAAS,cAAc,CAAC,MAAc;IACpC,OAAO,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;AACzD,CAAC;AAED,MAAM,MAAM,GAAG,eAAe,CAAC;IAC7B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B;CAChD,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,SAAiB,EACjB,QAAgB,EAChB,MAAM,GAAG,MAAM;IAEf,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,QAAQ,CAAC,IAAI,CACX,yBAAyB,GAAG,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,EAAE,CACpF,CAAC;IACF,QAAQ,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IAElD,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/D,SAAS,EAAE,CAAC;aACT,cAAc,CAAC;YACd,KAAK,EAAE;gBACL,IAAI,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE;gBAC7B,GAAG,EAAE;oBACH;wBACE,SAAS,EAAE;4BACT,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;4BAC/B,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,QAAQ,EAAE;yBAC9C;qBACF;oBACD;wBACE,SAAS,EAAE;4BACT,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE;4BAC9B,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,QAAQ,EAAE;yBAC7C;qBACF;iBACF;aACF;SACF,CAAC;aACD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACX,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,EAAG;YACvB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI;YAC1B,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,SAAS;YACpC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,WAAW;YACjC,4BAA4B,EAAE,CAAC,CAAC,MAAM;gBACpC,EAAE,OAAO,CAAC;gBACR,KAAK,EAAE;oBACL,SAAS,EAAE;wBACT,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;qBAChC;iBACF;aACF,CAAC;iBACD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM;YAC1B,2BAA2B,EAAE,CAAC,CAAC,MAAM;gBACnC,EAAE,OAAO,CAAC;gBACR,KAAK,EAAE;oBACL,SAAS,EAAE;wBACT,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE;qBAC/B;iBACF;aACF,CAAC;iBACD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM;YAC1B,8BAA8B,EAAE,CAAC,CAAC,MAAM;gBACtC,EAAE,OAAO,CAAC;gBACR,KAAK,EAAE;oBACL,WAAW,EAAE;wBACX,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;qBAChC;iBACF;aACF,CAAC;iBACD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM;YAC1B,6BAA6B,EAAE,CAAC,CAAC,MAAM;gBACrC,EAAE,OAAO,CAAC;gBACR,KAAK,EAAE;oBACL,WAAW,EAAE;wBACX,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE;qBAC/B;iBACF;aACF,CAAC;iBACD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM;YAC1B,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,GAAG;YACnB,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;SACvC,CAAC,CAAC;QACL,cAAc,EAAE,CAAC;aACd,cAAc,CAAC;YACd,KAAK,EAAE;gBACL,IAAI,EAAE,EAAE,GAAG,EAAE,mBAAmB,EAAE;gBAClC,GAAG,EAAE;oBACH;wBACE,SAAS,EAAE;4BACT,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;4BAC/B,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,QAAQ,EAAE;yBAC9C;qBACF;oBACD;wBACE,SAAS,EAAE;4BACT,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE;4BAC9B,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,QAAQ,EAAE;yBAC7C;qBACF;iBACF;aACF;SACF,CAAC;aACD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACX,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,EAAG;YACvB,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,0BAA2B;YACvD,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,cAAc;YACnC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;SACvC,CAAC,CAAC;KACN,CAAC,CAAC,CAAC;IACJ,QAAQ,CAAC,IAAI,CAAC,SAAS,SAAS,CAAC,MAAM,aAAa,CAAC,CAAC;IAEtD,+BAA+B;IAC/B,MAAM,cAAc,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACzC,MAAM,cAAc,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YACjD,MAAM,QAAQ,GAAG,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC,QAAQ,CAC3D,CAAC,CAAC,gBAAiB,CACpB;gBACC,CAAC,CAAC,CAAC,CAAC,QAAS;gBACb,CAAC,CAAC,CAAC,CAAC,gBAAiB,CAAC;YAExB,OAAO,QAAQ,KAAK,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,CAAC;QAChE,CAAC,CAAC,CAAC;QAEH,OAAO;YACL,GAAG,CAAC;YACJ,QAAQ,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;SACxE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,sBAAsB;IACtB,MAAM,OAAO,GAiBT,EAAE,CAAC;IACP,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,MAAM,uBAAuB,GAC3B,CAAC,KAAK,CAAC,2BAA2B,IAAI,CAAC,CAAC;gBACxC,CAAC,KAAK,CAAC,4BAA4B,IAAI,CAAC,CAAC,CAAC;YAC5C,MAAM,yBAAyB,GAC7B,CAAC,KAAK,CAAC,6BAA6B,IAAI,CAAC,CAAC;gBAC1C,CAAC,KAAK,CAAC,8BAA8B,IAAI,CAAC,CAAC,CAAC;YAE9C,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG;gBACxB,EAAE,EAAE,KAAK,CAAC,QAAQ;gBAClB,IAAI,EAAE,KAAK,CAAC,UAAU;gBACtB,IAAI,EAAE,KAAK,CAAC,UAAU;gBACtB,sBAAsB,EACpB,uBAAuB,GAAG,yBAAyB;gBACrD,YAAY,EAAE,SAAS;gBACvB,WAAW,EAAE,SAAS;gBACtB,OAAO,EAAE,CAAC;gBACV,iBAAiB,EAAE,SAAS;gBAC5B,gBAAgB,EAAE,SAAS;gBAC3B,YAAY,EAAE,CAAC;gBACf,SAAS,EAAE,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;gBAChD,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,SAAS,CACzC,GAAG,CAAC,SAAS,CAAC,EACd,GAAG,CAAC,QAAQ,CAAC,CACd;aACF,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YAClC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC;YACjD,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,iBAAiB,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC7D,CAAC;QACD,IAAI,KAAK,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;YACjC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC;YAChD,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,gBAAgB,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;SAClC,GAAG,CACF,CAAC,EACC,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,GAAG,CAAC,EACL,EAAE,EAAE,CAAC,CAAC;QACL,GAAG,CAAC;QACJ,OAAO,EAAE,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,CAAC;QACjD,YAAY,EAAE,CAAC,gBAAgB,IAAI,CAAC,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,CAAC;QAChE,YAAY,EAAE,YAAY,KAAK,SAAS,IAAI,WAAW,KAAK,SAAS;KACtE,CAAC,CACH;SACA,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;SACxB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;SACrC,OAAO,EAAE,CAAC;IAEb,gCAAgC;IAChC,MAAM,aAAa,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAClE,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;SAClD,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE;QACtB,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAEvE,OAAO;YACL,IAAI;YACJ,GAAG;YACH,KAAK,EAAE,MAAM,CAAC,MAAM;YACpB,QAAQ;SACT,CAAC;IACJ,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjD,QAAQ,CAAC,IAAI,CACX,wBAAwB,oBAAoB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,oBAAoB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,oBAAoB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CACnN,CAAC;IACF,QAAQ,CAAC,IAAI,CACX,4BAA4B,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,uBAAuB,EAAE,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,uBAAuB,EAAE,GAAG,CAAC,KAAK,cAAc,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CACjQ,CAAC;IACF,QAAQ,CAAC,IAAI,CACX,gCAAgC,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,uBAAuB,EAAE,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,uBAAuB,EAAE,GAAG,CAAC,KAAK,cAAc,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CACjR,CAAC;IACF,QAAQ,CAAC,IAAI,CACX,mCAAmC,cAAc,CAC/C,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,sBAAsB,EAAE,CAAC,CAAC,CAC7D,EAAE,CACJ,CAAC;IACF,QAAQ,CAAC,IAAI,EAAE,CAAC;IAEhB,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IAC9D,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CACjC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC;QAC1B,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CACpD,CAAC;IACF,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAC9B,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,KAAK;QACP,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CACjD,CAAC;IACF,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAClC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,YAAY;QACd,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CACjD,CAAC;IACF,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAChC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9C,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAClD,CAAC;IACF,MAAM,KAAK,GACT,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACjD,gBAAgB,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACvD,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACpD,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACrD,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,IAAI,CACX,YAAY,UAAU,CAAC,MAAM,iBAAiB,oBAAoB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CACxH,CAAC;IACF,QAAQ,CAAC,IAAI,CACX,YAAY,gBAAgB,CAAC,MAAM,uBAAuB,oBAAoB,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAC1I,CAAC;IACF,QAAQ,CAAC,IAAI,CACX,YAAY,aAAa,CAAC,MAAM,+BAA+B,oBAAoB,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAC5I,CAAC;IACF,QAAQ,CAAC,IAAI,CACX,YAAY,cAAc,CAAC,MAAM,0CAA0C,oBAAoB,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CACzJ,CAAC;IACF,QAAQ,CAAC,IAAI,CACX,YAAY,YAAY,CAAC,MAAM,mBAAmB,oBAAoB,CACpE,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CACpD,KAAK,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC9F,CAAC;IACF,QAAQ,CAAC,IAAI,CAAC,KAAK,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAElD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC9B,CAAC","sourcesContent":["import { useHasuraClient } from '@finalytic/graphql';\nimport { groupBy, utc } from '@finalytic/utils';\nimport {\n VRP_TENANT_ID,\n XIMPLIFI_TENANT_ID,\n} from '@vrplatform/hyperline-client';\n\nfunction printFinancialNumber(number: number, showPlusMinus = true) {\n return `${showPlusMinus ? (number >= 0 ? '+' : '-') : ''}$${Math.abs(number)\n .toFixed(2)\n .toString()\n .replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')}`;\n}\nfunction printPlusMinus(number: number) {\n return `${number >= 0 ? '+' : '-'}${Math.abs(number)}`;\n}\n\nconst hasura = useHasuraClient({\n secret: process.env.HASURA_GRAPHQL_ADMIN_SECRET,\n});\n\nexport async function getMrrDiffReasons(\n firstDate: string,\n lastDate: string,\n client = hasura\n) {\n const messages: string[] = [];\n messages.push(\n `MRR Diff Reasons from ${utc(firstDate).yyyymmdd()} to ${utc(lastDate).yyyymmdd()}`\n );\n messages.push('--------------------------------');\n\n const { mrrEvents, listingsEvents } = await client.query((q) => ({\n mrrEvents: q\n .tracking_event({\n where: {\n name: { _eq: 'mrr_reported' },\n _or: [\n {\n createdAt: {\n _gte: utc(firstDate).yyyymmdd(),\n _lte: utc(firstDate).add(1, 'day').yyyymmdd(),\n },\n },\n {\n createdAt: {\n _gte: utc(lastDate).yyyymmdd(),\n _lte: utc(lastDate).add(1, 'day').yyyymmdd(),\n },\n },\n ],\n },\n })\n .map((e) => ({\n tenantId: e.tenant?.id!,\n tenantName: e.tenant?.name,\n tenantCreatedAt: e.tenant?.createdAt,\n tenantPlan: e.tenant?.billingPlan,\n partnerTeamsCreatedFirstDate: e.tenant\n ?.clients({\n where: {\n createdAt: {\n _lte: utc(firstDate).yyyymmdd(),\n },\n },\n })\n .map((c) => c.id).length,\n partnerTeamsCreatedLastDate: e.tenant\n ?.clients({\n where: {\n createdAt: {\n _lte: utc(lastDate).yyyymmdd(),\n },\n },\n })\n .map((c) => c.id).length,\n partnerTeamsCancelledFirstDate: e.tenant\n ?.clients({\n where: {\n cancelledAt: {\n _lte: utc(firstDate).yyyymmdd(),\n },\n },\n })\n .map((c) => c.id).length,\n partnerTeamsCancelledLastDate: e.tenant\n ?.clients({\n where: {\n cancelledAt: {\n _lte: utc(lastDate).yyyymmdd(),\n },\n },\n })\n .map((c) => c.id).length,\n mrr: e.props()?.mrr,\n createdAt: utc(e.createdAt).yyyymmdd(),\n })),\n listingsEvents: q\n .tracking_event({\n where: {\n name: { _eq: 'listings_reported' },\n _or: [\n {\n createdAt: {\n _gte: utc(firstDate).yyyymmdd(),\n _lte: utc(firstDate).add(1, 'day').yyyymmdd(),\n },\n },\n {\n createdAt: {\n _gte: utc(lastDate).yyyymmdd(),\n _lte: utc(lastDate).add(1, 'day').yyyymmdd(),\n },\n },\n ],\n },\n })\n .map((e) => ({\n tenantId: e.tenant?.id!,\n billingPartnerId: e.tenant?.calculatedBillingPartnerId!,\n listings: e.props()?.activeListings,\n createdAt: utc(e.createdAt).yyyymmdd(),\n })),\n }));\n messages.push(`Found ${mrrEvents.length} mrr events`);\n\n // join mrr and listings events\n const trackingEvents = mrrEvents.map((e) => {\n const filteredEvents = listingsEvents.filter((l) => {\n const tenantId = [VRP_TENANT_ID, XIMPLIFI_TENANT_ID].includes(\n l.billingPartnerId!\n )\n ? l.tenantId!\n : l.billingPartnerId!;\n\n return tenantId === e.tenantId && l.createdAt === e.createdAt;\n });\n\n return {\n ...e,\n listings: filteredEvents.reduce((acc, l) => acc + (l.listings ?? 0), 0),\n };\n });\n\n // get list of tenants\n const tenants: Record<\n string,\n {\n id: string;\n name?: string;\n plan?: string;\n activePartnerTeamsDiff: number;\n mrrFirstDate?: number;\n mrrLastDate?: number;\n mrrDiff: number;\n listingsFirstDate?: number;\n listingsLastDate?: number;\n listingsDiff: number;\n createdAt: string;\n isNew: boolean;\n hasCancelled?: boolean;\n }\n > = {};\n for (const event of trackingEvents) {\n if (!tenants[event.tenantId]) {\n const partnerTeamsCreatedDiff =\n (event.partnerTeamsCreatedLastDate || 0) -\n (event.partnerTeamsCreatedFirstDate || 0);\n const partnerTeamsCancelledDiff =\n (event.partnerTeamsCancelledLastDate || 0) -\n (event.partnerTeamsCancelledFirstDate || 0);\n\n tenants[event.tenantId] = {\n id: event.tenantId,\n name: event.tenantName,\n plan: event.tenantPlan,\n activePartnerTeamsDiff:\n partnerTeamsCreatedDiff - partnerTeamsCancelledDiff,\n mrrFirstDate: undefined,\n mrrLastDate: undefined,\n mrrDiff: 0,\n listingsFirstDate: undefined,\n listingsLastDate: undefined,\n listingsDiff: 0,\n createdAt: utc(event.tenantCreatedAt).yyyymmdd(),\n isNew: utc(event.tenantCreatedAt).isBetween(\n utc(firstDate),\n utc(lastDate)\n ),\n };\n }\n\n if (event.createdAt === firstDate) {\n tenants[event.tenantId].mrrFirstDate = event.mrr;\n tenants[event.tenantId].listingsFirstDate = event.listings;\n }\n if (event.createdAt === lastDate) {\n tenants[event.tenantId].mrrLastDate = event.mrr;\n tenants[event.tenantId].listingsLastDate = event.listings;\n }\n }\n\n const result = Object.values(tenants)\n .map(\n ({\n mrrFirstDate,\n mrrLastDate,\n listingsFirstDate,\n listingsLastDate,\n ...t\n }) => ({\n ...t,\n mrrDiff: (mrrLastDate ?? 0) - (mrrFirstDate ?? 0),\n listingsDiff: (listingsLastDate ?? 0) - (listingsFirstDate ?? 0),\n hasCancelled: mrrFirstDate !== undefined && mrrLastDate === undefined,\n })\n )\n .filter((t) => t.mrrDiff)\n .sort((a, b) => b.mrrDiff - a.mrrDiff)\n .reverse();\n\n // calculate summ of mrr per day\n const groupedEvents = groupBy(trackingEvents, (e) => e.createdAt);\n const summedMrrPerDay = Object.entries(groupedEvents)\n .map(([date, events]) => {\n const mrr = events.reduce((acc, e) => acc + (e.mrr ?? 0), 0);\n const listings = events.reduce((acc, e) => acc + (e.listings ?? 0), 0);\n\n return {\n date,\n mrr,\n count: events.length,\n listings,\n };\n })\n .sort((a, b) => utc(b.date).diff(utc(a.date)));\n messages.push(\n `MRR sum changed from ${printFinancialNumber(summedMrrPerDay[1].mrr, false)} to ${printFinancialNumber(summedMrrPerDay[0].mrr, false)} (${printFinancialNumber(summedMrrPerDay[0].mrr - summedMrrPerDay[1].mrr)})`\n );\n messages.push(\n `MRR Reports changed from ${summedMrrPerDay[1].count.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')} to ${summedMrrPerDay[0].count.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')} (${printPlusMinus(summedMrrPerDay[0].count - summedMrrPerDay[1].count)})`\n );\n messages.push(\n `Active Listings changed from ${summedMrrPerDay[1].listings.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')} to ${summedMrrPerDay[0].listings.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')} (${printPlusMinus(summedMrrPerDay[0].listings - summedMrrPerDay[1].listings)})`\n );\n messages.push(\n `Active Partner Teams changed by ${printPlusMinus(\n result.reduce((acc, t) => acc + t.activePartnerTeamsDiff, 0)\n )}`\n );\n messages.push();\n\n const cancelledTenants = result.filter((t) => t.hasCancelled);\n const legacyTenants = result.filter(\n (t) =>\n t.plan?.includes('Legacy') &&\n !cancelledTenants.map((t) => t.id).includes(t.id)\n );\n const newTenants = result.filter(\n (t) =>\n t.isNew &&\n !cancelledTenants.map((t) => t.id).includes(t.id) &&\n !legacyTenants.map((t) => t.id).includes(t.id)\n );\n const activeListings = result.filter(\n (t) =>\n t.listingsDiff &&\n !newTenants.map((t) => t.id).includes(t.id) &&\n !cancelledTenants.map((t) => t.id).includes(t.id) &&\n !legacyTenants.map((t) => t.id).includes(t.id)\n );\n const otherTenants = result.filter(\n (t) =>\n !newTenants.map((t) => t.id).includes(t.id) &&\n !cancelledTenants.map((t) => t.id).includes(t.id) &&\n !legacyTenants.map((t) => t.id).includes(t.id) &&\n !activeListings.map((t) => t.id).includes(t.id)\n );\n const total =\n newTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +\n cancelledTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +\n legacyTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +\n activeListings.reduce((acc, t) => acc + t.mrrDiff, 0) +\n otherTenants.reduce((acc, t) => acc + t.mrrDiff, 0);\n messages.push(\n `MRR from ${newTenants.length} new tenants: ${printFinancialNumber(newTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`\n );\n messages.push(\n `MRR from ${cancelledTenants.length} cancelled tenants: ${printFinancialNumber(cancelledTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`\n );\n messages.push(\n `MRR from ${legacyTenants.length} tenants with Legacy plans: ${printFinancialNumber(legacyTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`\n );\n messages.push(\n `MRR from ${activeListings.length} tenants with active listings changes: ${printFinancialNumber(activeListings.reduce((acc, t) => acc + t.mrrDiff, 0))}`\n );\n messages.push(\n `MRR from ${otherTenants.length} other tenants: ${printFinancialNumber(\n otherTenants.reduce((acc, t) => acc + t.mrrDiff, 0)\n )} (${otherTenants.map((t) => `${t.name} (${printFinancialNumber(t.mrrDiff)})`).join(', ')})`\n );\n messages.push(`= ${printFinancialNumber(total)}`);\n\n return { messages, result };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './getMrrDiffReasons';
2
+ export * from './arrayBufferToBase64';
@@ -0,0 +1,3 @@
1
+ export * from './getMrrDiffReasons';
2
+ export * from './arrayBufferToBase64';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"src/","sources":["utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC","sourcesContent":["export * from './getMrrDiffReasons';\nexport * from './arrayBufferToBase64';\n"]}
@@ -2,3 +2,4 @@ export * from './const';
2
2
  export * from './types';
3
3
  export * from './client';
4
4
  export * from './hooks';
5
+ export * from './utils';
@@ -2,4 +2,5 @@ export * from './const';
2
2
  export * from './types';
3
3
  export * from './client';
4
4
  export * from './hooks';
5
+ export * from './utils';
5
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"src/","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC","sourcesContent":["export * from './const';\nexport * from './types';\nexport * from './client';\nexport * from './hooks';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"src/","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC","sourcesContent":["export * from './const';\nexport * from './types';\nexport * from './client';\nexport * from './hooks';\nexport * from './utils';\n"]}
@@ -1 +1 @@
1
- {"root":["../../src/_types.generated.ts","../../src/client.ts","../../src/const.ts","../../src/hooks.ts","../../src/index.ts","../../src/types.ts","../../src/utils.ts"],"version":"5.7.3"}
1
+ {"root":["../../src/_types.generated.ts","../../src/client.ts","../../src/const.ts","../../src/hooks.ts","../../src/index.ts","../../src/types.ts","../../src/utils/arraybuffertobase64.ts","../../src/utils/getmrrdiffreasons.ts","../../src/utils/index.ts"],"version":"5.7.3"}
@@ -0,0 +1 @@
1
+ export declare function arrayBufferToBase64(arrayBuffer: ArrayBuffer): string;
@@ -0,0 +1,6 @@
1
+ export function arrayBufferToBase64(arrayBuffer) {
2
+ const uint8Array = new Uint8Array(arrayBuffer);
3
+ const binaryString = String.fromCharCode.apply(null, uint8Array);
4
+ return btoa(binaryString);
5
+ }
6
+ //# sourceMappingURL=arrayBufferToBase64.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arrayBufferToBase64.js","sourceRoot":"src/","sources":["utils/arrayBufferToBase64.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,mBAAmB,CAAC,WAAwB;IAC1D,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,UAAiB,CAAC,CAAC;IACxE,OAAO,IAAI,CAAC,YAAY,CAAC,CAAC;AAC5B,CAAC","sourcesContent":["export function arrayBufferToBase64(arrayBuffer: ArrayBuffer) {\n const uint8Array = new Uint8Array(arrayBuffer);\n const binaryString = String.fromCharCode.apply(null, uint8Array as any);\n return btoa(binaryString);\n}\n"]}
@@ -0,0 +1,20 @@
1
+ export declare function getMrrDiffReasons(firstDate: string, lastDate: string, client?: {
2
+ readonly client: GQtyClient<import("@finalytic/graphql").GeneratedSchema>;
3
+ subscriptionsClient: import("gqty").SubscriptionsClient;
4
+ mutate<T = unknown>(resolved: (sub: import("@finalytic/graphql").Mutation) => T, options?: import("@finalytic/graphql").ResolveOptionsWithSession<T>): Promise<T>;
5
+ query<T = unknown>(resolved: (sub: import("@finalytic/graphql").Query) => T, options?: import("@finalytic/graphql").ResolveOptionsWithSession<T>): Promise<T>;
6
+ subscribe<T = unknown>(resolved: (sub: import("@finalytic/graphql").Subscription) => T, onData: (data: T, unsubscribeFn: () => Promise<void>) => void, onError?: (err: Error, unsubscribeFn: () => Promise<void>) => void): () => Promise<void>;
7
+ }): Promise<{
8
+ messages: string[];
9
+ result: {
10
+ mrrDiff: number;
11
+ listingsDiff: number;
12
+ hasCancelled: boolean;
13
+ id: string;
14
+ name?: string;
15
+ plan?: string;
16
+ activePartnerTeamsDiff: number;
17
+ createdAt: string;
18
+ isNew: boolean;
19
+ }[];
20
+ }>;
@@ -0,0 +1,214 @@
1
+ import { useHasuraClient } from '@finalytic/graphql';
2
+ import { groupBy, utc } from '@finalytic/utils';
3
+ import { VRP_TENANT_ID, XIMPLIFI_TENANT_ID, } from '@vrplatform/hyperline-client';
4
+ function printFinancialNumber(number, showPlusMinus = true) {
5
+ return `${showPlusMinus ? (number >= 0 ? '+' : '-') : ''}$${Math.abs(number)
6
+ .toFixed(2)
7
+ .toString()
8
+ .replace(/\B(?=(\d{3})+(?!\d))/g, ',')}`;
9
+ }
10
+ function printPlusMinus(number) {
11
+ return `${number >= 0 ? '+' : '-'}${Math.abs(number)}`;
12
+ }
13
+ const hasura = useHasuraClient({
14
+ secret: process.env.HASURA_GRAPHQL_ADMIN_SECRET,
15
+ });
16
+ export async function getMrrDiffReasons(firstDate, lastDate, client = hasura) {
17
+ const messages = [];
18
+ messages.push(`MRR Diff Reasons from ${utc(firstDate).yyyymmdd()} to ${utc(lastDate).yyyymmdd()}`);
19
+ messages.push('--------------------------------');
20
+ const { mrrEvents, listingsEvents } = await client.query((q) => ({
21
+ mrrEvents: q
22
+ .tracking_event({
23
+ where: {
24
+ name: { _eq: 'mrr_reported' },
25
+ _or: [
26
+ {
27
+ createdAt: {
28
+ _gte: utc(firstDate).yyyymmdd(),
29
+ _lte: utc(firstDate).add(1, 'day').yyyymmdd(),
30
+ },
31
+ },
32
+ {
33
+ createdAt: {
34
+ _gte: utc(lastDate).yyyymmdd(),
35
+ _lte: utc(lastDate).add(1, 'day').yyyymmdd(),
36
+ },
37
+ },
38
+ ],
39
+ },
40
+ })
41
+ .map((e) => ({
42
+ tenantId: e.tenant?.id,
43
+ tenantName: e.tenant?.name,
44
+ tenantCreatedAt: e.tenant?.createdAt,
45
+ tenantPlan: e.tenant?.billingPlan,
46
+ partnerTeamsCreatedFirstDate: e.tenant
47
+ ?.clients({
48
+ where: {
49
+ createdAt: {
50
+ _lte: utc(firstDate).yyyymmdd(),
51
+ },
52
+ },
53
+ })
54
+ .map((c) => c.id).length,
55
+ partnerTeamsCreatedLastDate: e.tenant
56
+ ?.clients({
57
+ where: {
58
+ createdAt: {
59
+ _lte: utc(lastDate).yyyymmdd(),
60
+ },
61
+ },
62
+ })
63
+ .map((c) => c.id).length,
64
+ partnerTeamsCancelledFirstDate: e.tenant
65
+ ?.clients({
66
+ where: {
67
+ cancelledAt: {
68
+ _lte: utc(firstDate).yyyymmdd(),
69
+ },
70
+ },
71
+ })
72
+ .map((c) => c.id).length,
73
+ partnerTeamsCancelledLastDate: e.tenant
74
+ ?.clients({
75
+ where: {
76
+ cancelledAt: {
77
+ _lte: utc(lastDate).yyyymmdd(),
78
+ },
79
+ },
80
+ })
81
+ .map((c) => c.id).length,
82
+ mrr: e.props()?.mrr,
83
+ createdAt: utc(e.createdAt).yyyymmdd(),
84
+ })),
85
+ listingsEvents: q
86
+ .tracking_event({
87
+ where: {
88
+ name: { _eq: 'listings_reported' },
89
+ _or: [
90
+ {
91
+ createdAt: {
92
+ _gte: utc(firstDate).yyyymmdd(),
93
+ _lte: utc(firstDate).add(1, 'day').yyyymmdd(),
94
+ },
95
+ },
96
+ {
97
+ createdAt: {
98
+ _gte: utc(lastDate).yyyymmdd(),
99
+ _lte: utc(lastDate).add(1, 'day').yyyymmdd(),
100
+ },
101
+ },
102
+ ],
103
+ },
104
+ })
105
+ .map((e) => ({
106
+ tenantId: e.tenant?.id,
107
+ billingPartnerId: e.tenant?.calculatedBillingPartnerId,
108
+ listings: e.props()?.activeListings,
109
+ createdAt: utc(e.createdAt).yyyymmdd(),
110
+ })),
111
+ }));
112
+ messages.push(`Found ${mrrEvents.length} mrr events`);
113
+ // join mrr and listings events
114
+ const trackingEvents = mrrEvents.map((e) => {
115
+ const filteredEvents = listingsEvents.filter((l) => {
116
+ const tenantId = [VRP_TENANT_ID, XIMPLIFI_TENANT_ID].includes(l.billingPartnerId)
117
+ ? l.tenantId
118
+ : l.billingPartnerId;
119
+ return tenantId === e.tenantId && l.createdAt === e.createdAt;
120
+ });
121
+ return {
122
+ ...e,
123
+ listings: filteredEvents.reduce((acc, l) => acc + (l.listings ?? 0), 0),
124
+ };
125
+ });
126
+ // get list of tenants
127
+ const tenants = {};
128
+ for (const event of trackingEvents) {
129
+ if (!tenants[event.tenantId]) {
130
+ const partnerTeamsCreatedDiff = (event.partnerTeamsCreatedLastDate || 0) -
131
+ (event.partnerTeamsCreatedFirstDate || 0);
132
+ const partnerTeamsCancelledDiff = (event.partnerTeamsCancelledLastDate || 0) -
133
+ (event.partnerTeamsCancelledFirstDate || 0);
134
+ tenants[event.tenantId] = {
135
+ id: event.tenantId,
136
+ name: event.tenantName,
137
+ plan: event.tenantPlan,
138
+ activePartnerTeamsDiff: partnerTeamsCreatedDiff - partnerTeamsCancelledDiff,
139
+ mrrFirstDate: undefined,
140
+ mrrLastDate: undefined,
141
+ mrrDiff: 0,
142
+ listingsFirstDate: undefined,
143
+ listingsLastDate: undefined,
144
+ listingsDiff: 0,
145
+ createdAt: utc(event.tenantCreatedAt).yyyymmdd(),
146
+ isNew: utc(event.tenantCreatedAt).isBetween(utc(firstDate), utc(lastDate)),
147
+ };
148
+ }
149
+ if (event.createdAt === firstDate) {
150
+ tenants[event.tenantId].mrrFirstDate = event.mrr;
151
+ tenants[event.tenantId].listingsFirstDate = event.listings;
152
+ }
153
+ if (event.createdAt === lastDate) {
154
+ tenants[event.tenantId].mrrLastDate = event.mrr;
155
+ tenants[event.tenantId].listingsLastDate = event.listings;
156
+ }
157
+ }
158
+ const result = Object.values(tenants)
159
+ .map(({ mrrFirstDate, mrrLastDate, listingsFirstDate, listingsLastDate, ...t }) => ({
160
+ ...t,
161
+ mrrDiff: (mrrLastDate ?? 0) - (mrrFirstDate ?? 0),
162
+ listingsDiff: (listingsLastDate ?? 0) - (listingsFirstDate ?? 0),
163
+ hasCancelled: mrrFirstDate !== undefined && mrrLastDate === undefined,
164
+ }))
165
+ .filter((t) => t.mrrDiff)
166
+ .sort((a, b) => b.mrrDiff - a.mrrDiff)
167
+ .reverse();
168
+ // calculate summ of mrr per day
169
+ const groupedEvents = groupBy(trackingEvents, (e) => e.createdAt);
170
+ const summedMrrPerDay = Object.entries(groupedEvents)
171
+ .map(([date, events]) => {
172
+ const mrr = events.reduce((acc, e) => acc + (e.mrr ?? 0), 0);
173
+ const listings = events.reduce((acc, e) => acc + (e.listings ?? 0), 0);
174
+ return {
175
+ date,
176
+ mrr,
177
+ count: events.length,
178
+ listings,
179
+ };
180
+ })
181
+ .sort((a, b) => utc(b.date).diff(utc(a.date)));
182
+ messages.push(`MRR sum changed from ${printFinancialNumber(summedMrrPerDay[1].mrr, false)} to ${printFinancialNumber(summedMrrPerDay[0].mrr, false)} (${printFinancialNumber(summedMrrPerDay[0].mrr - summedMrrPerDay[1].mrr)})`);
183
+ messages.push(`MRR Reports changed from ${summedMrrPerDay[1].count.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} to ${summedMrrPerDay[0].count.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} (${printPlusMinus(summedMrrPerDay[0].count - summedMrrPerDay[1].count)})`);
184
+ messages.push(`Active Listings changed from ${summedMrrPerDay[1].listings.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} to ${summedMrrPerDay[0].listings.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} (${printPlusMinus(summedMrrPerDay[0].listings - summedMrrPerDay[1].listings)})`);
185
+ messages.push(`Active Partner Teams changed by ${printPlusMinus(result.reduce((acc, t) => acc + t.activePartnerTeamsDiff, 0))}`);
186
+ messages.push();
187
+ const cancelledTenants = result.filter((t) => t.hasCancelled);
188
+ const legacyTenants = result.filter((t) => t.plan?.includes('Legacy') &&
189
+ !cancelledTenants.map((t) => t.id).includes(t.id));
190
+ const newTenants = result.filter((t) => t.isNew &&
191
+ !cancelledTenants.map((t) => t.id).includes(t.id) &&
192
+ !legacyTenants.map((t) => t.id).includes(t.id));
193
+ const activeListings = result.filter((t) => t.listingsDiff &&
194
+ !newTenants.map((t) => t.id).includes(t.id) &&
195
+ !cancelledTenants.map((t) => t.id).includes(t.id) &&
196
+ !legacyTenants.map((t) => t.id).includes(t.id));
197
+ const otherTenants = result.filter((t) => !newTenants.map((t) => t.id).includes(t.id) &&
198
+ !cancelledTenants.map((t) => t.id).includes(t.id) &&
199
+ !legacyTenants.map((t) => t.id).includes(t.id) &&
200
+ !activeListings.map((t) => t.id).includes(t.id));
201
+ const total = newTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +
202
+ cancelledTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +
203
+ legacyTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +
204
+ activeListings.reduce((acc, t) => acc + t.mrrDiff, 0) +
205
+ otherTenants.reduce((acc, t) => acc + t.mrrDiff, 0);
206
+ messages.push(`MRR from ${newTenants.length} new tenants: ${printFinancialNumber(newTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`);
207
+ messages.push(`MRR from ${cancelledTenants.length} cancelled tenants: ${printFinancialNumber(cancelledTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`);
208
+ messages.push(`MRR from ${legacyTenants.length} tenants with Legacy plans: ${printFinancialNumber(legacyTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`);
209
+ messages.push(`MRR from ${activeListings.length} tenants with active listings changes: ${printFinancialNumber(activeListings.reduce((acc, t) => acc + t.mrrDiff, 0))}`);
210
+ messages.push(`MRR from ${otherTenants.length} other tenants: ${printFinancialNumber(otherTenants.reduce((acc, t) => acc + t.mrrDiff, 0))} (${otherTenants.map((t) => `${t.name} (${printFinancialNumber(t.mrrDiff)})`).join(', ')})`);
211
+ messages.push(`= ${printFinancialNumber(total)}`);
212
+ return { messages, result };
213
+ }
214
+ //# sourceMappingURL=getMrrDiffReasons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getMrrDiffReasons.js","sourceRoot":"src/","sources":["utils/getMrrDiffReasons.ts"],"names":[],"mappings":"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","sourcesContent":["import { useHasuraClient } from '@finalytic/graphql';\nimport { groupBy, utc } from '@finalytic/utils';\nimport {\n VRP_TENANT_ID,\n XIMPLIFI_TENANT_ID,\n} from '@vrplatform/hyperline-client';\n\nfunction printFinancialNumber(number: number, showPlusMinus = true) {\n return `${showPlusMinus ? (number >= 0 ? '+' : '-') : ''}$${Math.abs(number)\n .toFixed(2)\n .toString()\n .replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')}`;\n}\nfunction printPlusMinus(number: number) {\n return `${number >= 0 ? '+' : '-'}${Math.abs(number)}`;\n}\n\nconst hasura = useHasuraClient({\n secret: process.env.HASURA_GRAPHQL_ADMIN_SECRET,\n});\n\nexport async function getMrrDiffReasons(\n firstDate: string,\n lastDate: string,\n client = hasura\n) {\n const messages: string[] = [];\n messages.push(\n `MRR Diff Reasons from ${utc(firstDate).yyyymmdd()} to ${utc(lastDate).yyyymmdd()}`\n );\n messages.push('--------------------------------');\n\n const { mrrEvents, listingsEvents } = await client.query((q) => ({\n mrrEvents: q\n .tracking_event({\n where: {\n name: { _eq: 'mrr_reported' },\n _or: [\n {\n createdAt: {\n _gte: utc(firstDate).yyyymmdd(),\n _lte: utc(firstDate).add(1, 'day').yyyymmdd(),\n },\n },\n {\n createdAt: {\n _gte: utc(lastDate).yyyymmdd(),\n _lte: utc(lastDate).add(1, 'day').yyyymmdd(),\n },\n },\n ],\n },\n })\n .map((e) => ({\n tenantId: e.tenant?.id!,\n tenantName: e.tenant?.name,\n tenantCreatedAt: e.tenant?.createdAt,\n tenantPlan: e.tenant?.billingPlan,\n partnerTeamsCreatedFirstDate: e.tenant\n ?.clients({\n where: {\n createdAt: {\n _lte: utc(firstDate).yyyymmdd(),\n },\n },\n })\n .map((c) => c.id).length,\n partnerTeamsCreatedLastDate: e.tenant\n ?.clients({\n where: {\n createdAt: {\n _lte: utc(lastDate).yyyymmdd(),\n },\n },\n })\n .map((c) => c.id).length,\n partnerTeamsCancelledFirstDate: e.tenant\n ?.clients({\n where: {\n cancelledAt: {\n _lte: utc(firstDate).yyyymmdd(),\n },\n },\n })\n .map((c) => c.id).length,\n partnerTeamsCancelledLastDate: e.tenant\n ?.clients({\n where: {\n cancelledAt: {\n _lte: utc(lastDate).yyyymmdd(),\n },\n },\n })\n .map((c) => c.id).length,\n mrr: e.props()?.mrr,\n createdAt: utc(e.createdAt).yyyymmdd(),\n })),\n listingsEvents: q\n .tracking_event({\n where: {\n name: { _eq: 'listings_reported' },\n _or: [\n {\n createdAt: {\n _gte: utc(firstDate).yyyymmdd(),\n _lte: utc(firstDate).add(1, 'day').yyyymmdd(),\n },\n },\n {\n createdAt: {\n _gte: utc(lastDate).yyyymmdd(),\n _lte: utc(lastDate).add(1, 'day').yyyymmdd(),\n },\n },\n ],\n },\n })\n .map((e) => ({\n tenantId: e.tenant?.id!,\n billingPartnerId: e.tenant?.calculatedBillingPartnerId!,\n listings: e.props()?.activeListings,\n createdAt: utc(e.createdAt).yyyymmdd(),\n })),\n }));\n messages.push(`Found ${mrrEvents.length} mrr events`);\n\n // join mrr and listings events\n const trackingEvents = mrrEvents.map((e) => {\n const filteredEvents = listingsEvents.filter((l) => {\n const tenantId = [VRP_TENANT_ID, XIMPLIFI_TENANT_ID].includes(\n l.billingPartnerId!\n )\n ? l.tenantId!\n : l.billingPartnerId!;\n\n return tenantId === e.tenantId && l.createdAt === e.createdAt;\n });\n\n return {\n ...e,\n listings: filteredEvents.reduce((acc, l) => acc + (l.listings ?? 0), 0),\n };\n });\n\n // get list of tenants\n const tenants: Record<\n string,\n {\n id: string;\n name?: string;\n plan?: string;\n activePartnerTeamsDiff: number;\n mrrFirstDate?: number;\n mrrLastDate?: number;\n mrrDiff: number;\n listingsFirstDate?: number;\n listingsLastDate?: number;\n listingsDiff: number;\n createdAt: string;\n isNew: boolean;\n hasCancelled?: boolean;\n }\n > = {};\n for (const event of trackingEvents) {\n if (!tenants[event.tenantId]) {\n const partnerTeamsCreatedDiff =\n (event.partnerTeamsCreatedLastDate || 0) -\n (event.partnerTeamsCreatedFirstDate || 0);\n const partnerTeamsCancelledDiff =\n (event.partnerTeamsCancelledLastDate || 0) -\n (event.partnerTeamsCancelledFirstDate || 0);\n\n tenants[event.tenantId] = {\n id: event.tenantId,\n name: event.tenantName,\n plan: event.tenantPlan,\n activePartnerTeamsDiff:\n partnerTeamsCreatedDiff - partnerTeamsCancelledDiff,\n mrrFirstDate: undefined,\n mrrLastDate: undefined,\n mrrDiff: 0,\n listingsFirstDate: undefined,\n listingsLastDate: undefined,\n listingsDiff: 0,\n createdAt: utc(event.tenantCreatedAt).yyyymmdd(),\n isNew: utc(event.tenantCreatedAt).isBetween(\n utc(firstDate),\n utc(lastDate)\n ),\n };\n }\n\n if (event.createdAt === firstDate) {\n tenants[event.tenantId].mrrFirstDate = event.mrr;\n tenants[event.tenantId].listingsFirstDate = event.listings;\n }\n if (event.createdAt === lastDate) {\n tenants[event.tenantId].mrrLastDate = event.mrr;\n tenants[event.tenantId].listingsLastDate = event.listings;\n }\n }\n\n const result = Object.values(tenants)\n .map(\n ({\n mrrFirstDate,\n mrrLastDate,\n listingsFirstDate,\n listingsLastDate,\n ...t\n }) => ({\n ...t,\n mrrDiff: (mrrLastDate ?? 0) - (mrrFirstDate ?? 0),\n listingsDiff: (listingsLastDate ?? 0) - (listingsFirstDate ?? 0),\n hasCancelled: mrrFirstDate !== undefined && mrrLastDate === undefined,\n })\n )\n .filter((t) => t.mrrDiff)\n .sort((a, b) => b.mrrDiff - a.mrrDiff)\n .reverse();\n\n // calculate summ of mrr per day\n const groupedEvents = groupBy(trackingEvents, (e) => e.createdAt);\n const summedMrrPerDay = Object.entries(groupedEvents)\n .map(([date, events]) => {\n const mrr = events.reduce((acc, e) => acc + (e.mrr ?? 0), 0);\n const listings = events.reduce((acc, e) => acc + (e.listings ?? 0), 0);\n\n return {\n date,\n mrr,\n count: events.length,\n listings,\n };\n })\n .sort((a, b) => utc(b.date).diff(utc(a.date)));\n messages.push(\n `MRR sum changed from ${printFinancialNumber(summedMrrPerDay[1].mrr, false)} to ${printFinancialNumber(summedMrrPerDay[0].mrr, false)} (${printFinancialNumber(summedMrrPerDay[0].mrr - summedMrrPerDay[1].mrr)})`\n );\n messages.push(\n `MRR Reports changed from ${summedMrrPerDay[1].count.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')} to ${summedMrrPerDay[0].count.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')} (${printPlusMinus(summedMrrPerDay[0].count - summedMrrPerDay[1].count)})`\n );\n messages.push(\n `Active Listings changed from ${summedMrrPerDay[1].listings.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')} to ${summedMrrPerDay[0].listings.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')} (${printPlusMinus(summedMrrPerDay[0].listings - summedMrrPerDay[1].listings)})`\n );\n messages.push(\n `Active Partner Teams changed by ${printPlusMinus(\n result.reduce((acc, t) => acc + t.activePartnerTeamsDiff, 0)\n )}`\n );\n messages.push();\n\n const cancelledTenants = result.filter((t) => t.hasCancelled);\n const legacyTenants = result.filter(\n (t) =>\n t.plan?.includes('Legacy') &&\n !cancelledTenants.map((t) => t.id).includes(t.id)\n );\n const newTenants = result.filter(\n (t) =>\n t.isNew &&\n !cancelledTenants.map((t) => t.id).includes(t.id) &&\n !legacyTenants.map((t) => t.id).includes(t.id)\n );\n const activeListings = result.filter(\n (t) =>\n t.listingsDiff &&\n !newTenants.map((t) => t.id).includes(t.id) &&\n !cancelledTenants.map((t) => t.id).includes(t.id) &&\n !legacyTenants.map((t) => t.id).includes(t.id)\n );\n const otherTenants = result.filter(\n (t) =>\n !newTenants.map((t) => t.id).includes(t.id) &&\n !cancelledTenants.map((t) => t.id).includes(t.id) &&\n !legacyTenants.map((t) => t.id).includes(t.id) &&\n !activeListings.map((t) => t.id).includes(t.id)\n );\n const total =\n newTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +\n cancelledTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +\n legacyTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +\n activeListings.reduce((acc, t) => acc + t.mrrDiff, 0) +\n otherTenants.reduce((acc, t) => acc + t.mrrDiff, 0);\n messages.push(\n `MRR from ${newTenants.length} new tenants: ${printFinancialNumber(newTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`\n );\n messages.push(\n `MRR from ${cancelledTenants.length} cancelled tenants: ${printFinancialNumber(cancelledTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`\n );\n messages.push(\n `MRR from ${legacyTenants.length} tenants with Legacy plans: ${printFinancialNumber(legacyTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`\n );\n messages.push(\n `MRR from ${activeListings.length} tenants with active listings changes: ${printFinancialNumber(activeListings.reduce((acc, t) => acc + t.mrrDiff, 0))}`\n );\n messages.push(\n `MRR from ${otherTenants.length} other tenants: ${printFinancialNumber(\n otherTenants.reduce((acc, t) => acc + t.mrrDiff, 0)\n )} (${otherTenants.map((t) => `${t.name} (${printFinancialNumber(t.mrrDiff)})`).join(', ')})`\n );\n messages.push(`= ${printFinancialNumber(total)}`);\n\n return { messages, result };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './getMrrDiffReasons';
2
+ export * from './arrayBufferToBase64';
@@ -0,0 +1,3 @@
1
+ export * from './getMrrDiffReasons';
2
+ export * from './arrayBufferToBase64';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"src/","sources":["utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC","sourcesContent":["export * from './getMrrDiffReasons';\nexport * from './arrayBufferToBase64';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vrplatform/hyperline-client",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "main": "build/main/index.js",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -18,6 +18,9 @@
18
18
  "engines": {
19
19
  "node": ">=14"
20
20
  },
21
+ "dependencies": {
22
+ "@finalytic/graphql": "*"
23
+ },
21
24
  "devDependencies": {
22
25
  "@vrplatform/log": "*",
23
26
  "openapi-typescript": "^7.6.1"
package/src/index.ts CHANGED
@@ -2,3 +2,4 @@ export * from './const';
2
2
  export * from './types';
3
3
  export * from './client';
4
4
  export * from './hooks';
5
+ export * from './utils';
@@ -0,0 +1,305 @@
1
+ import { useHasuraClient } from '@finalytic/graphql';
2
+ import { groupBy, utc } from '@finalytic/utils';
3
+ import {
4
+ VRP_TENANT_ID,
5
+ XIMPLIFI_TENANT_ID,
6
+ } from '@vrplatform/hyperline-client';
7
+
8
+ function printFinancialNumber(number: number, showPlusMinus = true) {
9
+ return `${showPlusMinus ? (number >= 0 ? '+' : '-') : ''}$${Math.abs(number)
10
+ .toFixed(2)
11
+ .toString()
12
+ .replace(/\B(?=(\d{3})+(?!\d))/g, ',')}`;
13
+ }
14
+ function printPlusMinus(number: number) {
15
+ return `${number >= 0 ? '+' : '-'}${Math.abs(number)}`;
16
+ }
17
+
18
+ const hasura = useHasuraClient({
19
+ secret: process.env.HASURA_GRAPHQL_ADMIN_SECRET,
20
+ });
21
+
22
+ export async function getMrrDiffReasons(
23
+ firstDate: string,
24
+ lastDate: string,
25
+ client = hasura
26
+ ) {
27
+ const messages: string[] = [];
28
+ messages.push(
29
+ `MRR Diff Reasons from ${utc(firstDate).yyyymmdd()} to ${utc(lastDate).yyyymmdd()}`
30
+ );
31
+ messages.push('--------------------------------');
32
+
33
+ const { mrrEvents, listingsEvents } = await client.query((q) => ({
34
+ mrrEvents: q
35
+ .tracking_event({
36
+ where: {
37
+ name: { _eq: 'mrr_reported' },
38
+ _or: [
39
+ {
40
+ createdAt: {
41
+ _gte: utc(firstDate).yyyymmdd(),
42
+ _lte: utc(firstDate).add(1, 'day').yyyymmdd(),
43
+ },
44
+ },
45
+ {
46
+ createdAt: {
47
+ _gte: utc(lastDate).yyyymmdd(),
48
+ _lte: utc(lastDate).add(1, 'day').yyyymmdd(),
49
+ },
50
+ },
51
+ ],
52
+ },
53
+ })
54
+ .map((e) => ({
55
+ tenantId: e.tenant?.id!,
56
+ tenantName: e.tenant?.name,
57
+ tenantCreatedAt: e.tenant?.createdAt,
58
+ tenantPlan: e.tenant?.billingPlan,
59
+ partnerTeamsCreatedFirstDate: e.tenant
60
+ ?.clients({
61
+ where: {
62
+ createdAt: {
63
+ _lte: utc(firstDate).yyyymmdd(),
64
+ },
65
+ },
66
+ })
67
+ .map((c) => c.id).length,
68
+ partnerTeamsCreatedLastDate: e.tenant
69
+ ?.clients({
70
+ where: {
71
+ createdAt: {
72
+ _lte: utc(lastDate).yyyymmdd(),
73
+ },
74
+ },
75
+ })
76
+ .map((c) => c.id).length,
77
+ partnerTeamsCancelledFirstDate: e.tenant
78
+ ?.clients({
79
+ where: {
80
+ cancelledAt: {
81
+ _lte: utc(firstDate).yyyymmdd(),
82
+ },
83
+ },
84
+ })
85
+ .map((c) => c.id).length,
86
+ partnerTeamsCancelledLastDate: e.tenant
87
+ ?.clients({
88
+ where: {
89
+ cancelledAt: {
90
+ _lte: utc(lastDate).yyyymmdd(),
91
+ },
92
+ },
93
+ })
94
+ .map((c) => c.id).length,
95
+ mrr: e.props()?.mrr,
96
+ createdAt: utc(e.createdAt).yyyymmdd(),
97
+ })),
98
+ listingsEvents: q
99
+ .tracking_event({
100
+ where: {
101
+ name: { _eq: 'listings_reported' },
102
+ _or: [
103
+ {
104
+ createdAt: {
105
+ _gte: utc(firstDate).yyyymmdd(),
106
+ _lte: utc(firstDate).add(1, 'day').yyyymmdd(),
107
+ },
108
+ },
109
+ {
110
+ createdAt: {
111
+ _gte: utc(lastDate).yyyymmdd(),
112
+ _lte: utc(lastDate).add(1, 'day').yyyymmdd(),
113
+ },
114
+ },
115
+ ],
116
+ },
117
+ })
118
+ .map((e) => ({
119
+ tenantId: e.tenant?.id!,
120
+ billingPartnerId: e.tenant?.calculatedBillingPartnerId!,
121
+ listings: e.props()?.activeListings,
122
+ createdAt: utc(e.createdAt).yyyymmdd(),
123
+ })),
124
+ }));
125
+ messages.push(`Found ${mrrEvents.length} mrr events`);
126
+
127
+ // join mrr and listings events
128
+ const trackingEvents = mrrEvents.map((e) => {
129
+ const filteredEvents = listingsEvents.filter((l) => {
130
+ const tenantId = [VRP_TENANT_ID, XIMPLIFI_TENANT_ID].includes(
131
+ l.billingPartnerId!
132
+ )
133
+ ? l.tenantId!
134
+ : l.billingPartnerId!;
135
+
136
+ return tenantId === e.tenantId && l.createdAt === e.createdAt;
137
+ });
138
+
139
+ return {
140
+ ...e,
141
+ listings: filteredEvents.reduce((acc, l) => acc + (l.listings ?? 0), 0),
142
+ };
143
+ });
144
+
145
+ // get list of tenants
146
+ const tenants: Record<
147
+ string,
148
+ {
149
+ id: string;
150
+ name?: string;
151
+ plan?: string;
152
+ activePartnerTeamsDiff: number;
153
+ mrrFirstDate?: number;
154
+ mrrLastDate?: number;
155
+ mrrDiff: number;
156
+ listingsFirstDate?: number;
157
+ listingsLastDate?: number;
158
+ listingsDiff: number;
159
+ createdAt: string;
160
+ isNew: boolean;
161
+ hasCancelled?: boolean;
162
+ }
163
+ > = {};
164
+ for (const event of trackingEvents) {
165
+ if (!tenants[event.tenantId]) {
166
+ const partnerTeamsCreatedDiff =
167
+ (event.partnerTeamsCreatedLastDate || 0) -
168
+ (event.partnerTeamsCreatedFirstDate || 0);
169
+ const partnerTeamsCancelledDiff =
170
+ (event.partnerTeamsCancelledLastDate || 0) -
171
+ (event.partnerTeamsCancelledFirstDate || 0);
172
+
173
+ tenants[event.tenantId] = {
174
+ id: event.tenantId,
175
+ name: event.tenantName,
176
+ plan: event.tenantPlan,
177
+ activePartnerTeamsDiff:
178
+ partnerTeamsCreatedDiff - partnerTeamsCancelledDiff,
179
+ mrrFirstDate: undefined,
180
+ mrrLastDate: undefined,
181
+ mrrDiff: 0,
182
+ listingsFirstDate: undefined,
183
+ listingsLastDate: undefined,
184
+ listingsDiff: 0,
185
+ createdAt: utc(event.tenantCreatedAt).yyyymmdd(),
186
+ isNew: utc(event.tenantCreatedAt).isBetween(
187
+ utc(firstDate),
188
+ utc(lastDate)
189
+ ),
190
+ };
191
+ }
192
+
193
+ if (event.createdAt === firstDate) {
194
+ tenants[event.tenantId].mrrFirstDate = event.mrr;
195
+ tenants[event.tenantId].listingsFirstDate = event.listings;
196
+ }
197
+ if (event.createdAt === lastDate) {
198
+ tenants[event.tenantId].mrrLastDate = event.mrr;
199
+ tenants[event.tenantId].listingsLastDate = event.listings;
200
+ }
201
+ }
202
+
203
+ const result = Object.values(tenants)
204
+ .map(
205
+ ({
206
+ mrrFirstDate,
207
+ mrrLastDate,
208
+ listingsFirstDate,
209
+ listingsLastDate,
210
+ ...t
211
+ }) => ({
212
+ ...t,
213
+ mrrDiff: (mrrLastDate ?? 0) - (mrrFirstDate ?? 0),
214
+ listingsDiff: (listingsLastDate ?? 0) - (listingsFirstDate ?? 0),
215
+ hasCancelled: mrrFirstDate !== undefined && mrrLastDate === undefined,
216
+ })
217
+ )
218
+ .filter((t) => t.mrrDiff)
219
+ .sort((a, b) => b.mrrDiff - a.mrrDiff)
220
+ .reverse();
221
+
222
+ // calculate summ of mrr per day
223
+ const groupedEvents = groupBy(trackingEvents, (e) => e.createdAt);
224
+ const summedMrrPerDay = Object.entries(groupedEvents)
225
+ .map(([date, events]) => {
226
+ const mrr = events.reduce((acc, e) => acc + (e.mrr ?? 0), 0);
227
+ const listings = events.reduce((acc, e) => acc + (e.listings ?? 0), 0);
228
+
229
+ return {
230
+ date,
231
+ mrr,
232
+ count: events.length,
233
+ listings,
234
+ };
235
+ })
236
+ .sort((a, b) => utc(b.date).diff(utc(a.date)));
237
+ messages.push(
238
+ `MRR sum changed from ${printFinancialNumber(summedMrrPerDay[1].mrr, false)} to ${printFinancialNumber(summedMrrPerDay[0].mrr, false)} (${printFinancialNumber(summedMrrPerDay[0].mrr - summedMrrPerDay[1].mrr)})`
239
+ );
240
+ messages.push(
241
+ `MRR Reports changed from ${summedMrrPerDay[1].count.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} to ${summedMrrPerDay[0].count.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} (${printPlusMinus(summedMrrPerDay[0].count - summedMrrPerDay[1].count)})`
242
+ );
243
+ messages.push(
244
+ `Active Listings changed from ${summedMrrPerDay[1].listings.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} to ${summedMrrPerDay[0].listings.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')} (${printPlusMinus(summedMrrPerDay[0].listings - summedMrrPerDay[1].listings)})`
245
+ );
246
+ messages.push(
247
+ `Active Partner Teams changed by ${printPlusMinus(
248
+ result.reduce((acc, t) => acc + t.activePartnerTeamsDiff, 0)
249
+ )}`
250
+ );
251
+ messages.push();
252
+
253
+ const cancelledTenants = result.filter((t) => t.hasCancelled);
254
+ const legacyTenants = result.filter(
255
+ (t) =>
256
+ t.plan?.includes('Legacy') &&
257
+ !cancelledTenants.map((t) => t.id).includes(t.id)
258
+ );
259
+ const newTenants = result.filter(
260
+ (t) =>
261
+ t.isNew &&
262
+ !cancelledTenants.map((t) => t.id).includes(t.id) &&
263
+ !legacyTenants.map((t) => t.id).includes(t.id)
264
+ );
265
+ const activeListings = result.filter(
266
+ (t) =>
267
+ t.listingsDiff &&
268
+ !newTenants.map((t) => t.id).includes(t.id) &&
269
+ !cancelledTenants.map((t) => t.id).includes(t.id) &&
270
+ !legacyTenants.map((t) => t.id).includes(t.id)
271
+ );
272
+ const otherTenants = result.filter(
273
+ (t) =>
274
+ !newTenants.map((t) => t.id).includes(t.id) &&
275
+ !cancelledTenants.map((t) => t.id).includes(t.id) &&
276
+ !legacyTenants.map((t) => t.id).includes(t.id) &&
277
+ !activeListings.map((t) => t.id).includes(t.id)
278
+ );
279
+ const total =
280
+ newTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +
281
+ cancelledTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +
282
+ legacyTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +
283
+ activeListings.reduce((acc, t) => acc + t.mrrDiff, 0) +
284
+ otherTenants.reduce((acc, t) => acc + t.mrrDiff, 0);
285
+ messages.push(
286
+ `MRR from ${newTenants.length} new tenants: ${printFinancialNumber(newTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`
287
+ );
288
+ messages.push(
289
+ `MRR from ${cancelledTenants.length} cancelled tenants: ${printFinancialNumber(cancelledTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`
290
+ );
291
+ messages.push(
292
+ `MRR from ${legacyTenants.length} tenants with Legacy plans: ${printFinancialNumber(legacyTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`
293
+ );
294
+ messages.push(
295
+ `MRR from ${activeListings.length} tenants with active listings changes: ${printFinancialNumber(activeListings.reduce((acc, t) => acc + t.mrrDiff, 0))}`
296
+ );
297
+ messages.push(
298
+ `MRR from ${otherTenants.length} other tenants: ${printFinancialNumber(
299
+ otherTenants.reduce((acc, t) => acc + t.mrrDiff, 0)
300
+ )} (${otherTenants.map((t) => `${t.name} (${printFinancialNumber(t.mrrDiff)})`).join(', ')})`
301
+ );
302
+ messages.push(`= ${printFinancialNumber(total)}`);
303
+
304
+ return { messages, result };
305
+ }
@@ -0,0 +1,2 @@
1
+ export * from './getMrrDiffReasons';
2
+ export * from './arrayBufferToBase64';
File without changes