@vrplatform/hyperline-client 1.0.25 → 1.0.27

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 (46) hide show
  1. package/build/main/client.d.ts +2 -2
  2. package/build/main/client.js.map +1 -1
  3. package/build/main/const.d.ts +1 -7
  4. package/build/main/const.js +1 -7
  5. package/build/main/const.js.map +1 -1
  6. package/build/main/types.d.ts +0 -43
  7. package/build/main/types.js.map +1 -1
  8. package/build/main/utils/calculateMrr.d.ts +45 -0
  9. package/build/main/utils/calculateMrr.js +107 -0
  10. package/build/main/utils/calculateMrr.js.map +1 -0
  11. package/build/main/utils/index.d.ts +2 -1
  12. package/build/main/utils/index.js +2 -1
  13. package/build/main/utils/index.js.map +1 -1
  14. package/build/main/utils/isTestingTeam.d.ts +5 -0
  15. package/build/main/utils/isTestingTeam.js +4 -0
  16. package/build/main/utils/isTestingTeam.js.map +1 -0
  17. package/build/module/client.d.ts +2 -2
  18. package/build/module/client.js.map +1 -1
  19. package/build/module/const.d.ts +1 -7
  20. package/build/module/const.js +1 -7
  21. package/build/module/const.js.map +1 -1
  22. package/build/module/types.d.ts +0 -43
  23. package/build/module/types.js.map +1 -1
  24. package/build/module/utils/calculateMrr.d.ts +45 -0
  25. package/build/module/utils/calculateMrr.js +107 -0
  26. package/build/module/utils/calculateMrr.js.map +1 -0
  27. package/build/module/utils/index.d.ts +2 -1
  28. package/build/module/utils/index.js +2 -1
  29. package/build/module/utils/index.js.map +1 -1
  30. package/build/module/utils/isTestingTeam.d.ts +5 -0
  31. package/build/module/utils/isTestingTeam.js +4 -0
  32. package/build/module/utils/isTestingTeam.js.map +1 -0
  33. package/package.json +3 -5
  34. package/src/client.ts +6 -6
  35. package/src/const.ts +1 -14
  36. package/src/types.ts +0 -55
  37. package/src/utils/calculateMrr.ts +206 -0
  38. package/src/utils/index.ts +2 -1
  39. package/src/utils/isTestingTeam.ts +11 -0
  40. package/build/main/utils/getMrrDiffReasons.d.ts +0 -15
  41. package/build/main/utils/getMrrDiffReasons.js +0 -217
  42. package/build/main/utils/getMrrDiffReasons.js.map +0 -1
  43. package/build/module/utils/getMrrDiffReasons.d.ts +0 -15
  44. package/build/module/utils/getMrrDiffReasons.js +0 -217
  45. package/build/module/utils/getMrrDiffReasons.js.map +0 -1
  46. package/src/utils/getMrrDiffReasons.ts +0 -306
package/src/const.ts CHANGED
@@ -7,6 +7,7 @@ export const VRP_TENANT_ID = '7bfec41f-aa3f-4602-95d2-f7996e4f0e59';
7
7
  export const DEMO_TEST_PARTNER_TENANT_ID =
8
8
  '0b6a7bd6-56cc-46b5-b2ab-1bd7d1e994fa';
9
9
  export const XIMPLIFI_TENANT_ID = 'd6ab2bbe-e0fc-48d9-89a3-c3c05f4e79b5';
10
+ export const TEST_TENANT_ID = 'fa4d1a20-2f47-4021-9c72-c5a809be9c48';
10
11
 
11
12
  // Customers
12
13
  export const XIMPLIFI_CUSTOMER_ID = 'cus_HDUZawnaJbPa9p';
@@ -56,20 +57,6 @@ export const HYPERLINE_PARTNER_DEV_PLAN_ID = 'plan_8qtj8T4j0W3oiS';
56
57
  export const HYPERLINE_PARTNER_PLAN_NAME = 'VRP Subscription - Partners';
57
58
  export const HYPERLINE_PARTNER_PRODUCT_ID = 'itm_AJBM0_jPsrqizl';
58
59
 
59
- export const HYPERLINE_PARTNER_CLIENT_SHADOW_TEMPLATE_ID =
60
- 'subt_Ny9vQJcTga4LJs';
61
- export const HYPERLINE_PARTNER_CLIENT_SHADOW_DEV_TEMPLATE_ID =
62
- 'subt_yQxDuboHpmXNxW';
63
- export const HYPERLINE_PARTNER_CLIENT_SHADOW_TEMPLATE_CONFIGURATION_ID =
64
- 'subtc_ELFdZAOA8fHh7o';
65
- export const HYPERLINE_PARTNER_CLIENT_SHADOW_DEV_TEMPLATE_CONFIGURATION_ID =
66
- 'subtc_eeflfPiaYWaHSD';
67
- export const HYPERLINE_PARTNER_CLIENT_SHADOW_PRODUCT_ID = 'itm_7zZNcdWyUf3VWx';
68
- export const HYPERLINE_PARTNER_CLIENT_SHADOW_DEV_PRODUCT_ID =
69
- 'itm_WBqFApJRVuVbYx';
70
- export const HYPERLINE_PARTNER_CLIENT_SHADOW_TEMPLATE_NAME =
71
- 'VRP Partner Client Shadow Subscription';
72
-
73
60
  export const GL_HYPERLINE_DEFAULT_PLAN_ID = 'plan_JXviWSpU5yuokD';
74
61
  export const GL_HYPERLINE_DEFAULT_DEV_PLAN_ID = 'plan_Nnozk8_TfYqTkj';
75
62
  export const GL_HYPERLINE_DEFAULT_PLAN_NAME = 'VRTrust Subscription';
package/src/types.ts CHANGED
@@ -14,61 +14,6 @@ export type HyperlinePayload<T extends HyperlineWebhook> = {
14
14
  data: Record<string, any>;
15
15
  };
16
16
 
17
- export type HyperlineCreateSubscriptionPayload = {
18
- customer_id: string;
19
- invoicing_entity_id?: string | null;
20
- activation_strategy?: 'start_date' | 'manually' | 'checkout';
21
- starts_at?: string;
22
- plan_id?: string;
23
- template_id?: string;
24
- template_configuration_id?: string;
25
- trial?: {
26
- end_strategy: 'manual' | 'end_date' | 'duration';
27
- starts_at?: string;
28
- ends_at?: string;
29
- duration?: {
30
- period: 'days' | 'weeks' | 'months' | 'years';
31
- count: number;
32
- };
33
- };
34
- cancellation_strategy?:
35
- | 'refund_prorata'
36
- | 'refund_custom'
37
- | 'charge_prorata'
38
- | 'charge_custom'
39
- | 'end_of_period'
40
- | 'do_nothing';
41
- generate_draft_invoices?: boolean;
42
- renew_automatically?: boolean;
43
- contract_terms?: {
44
- activation_strategy:
45
- | 'start_date'
46
- | 'immediately'
47
- | 'manual'
48
- | 'quote_signature'
49
- | 'checkout';
50
- end_strategy: 'end_date' | 'duration' | 'manual';
51
- starts_at?: string;
52
- duration?: {
53
- period: 'days' | 'weeks' | 'months' | 'years';
54
- count: number;
55
- };
56
- renew_automatically?: boolean;
57
- renew_for_duration?: {
58
- period: 'days' | 'weeks' | 'months' | 'years';
59
- count: number;
60
- };
61
- };
62
- billing_cycle_alignment?: 'calendar_period' | 'anniversary';
63
- coupons?: {
64
- id: string;
65
- repeat: 'once' | 'forever' | 'custom';
66
- expires_at?: string;
67
- apply_at?: string;
68
- product_ids?: string[];
69
- }[];
70
- };
71
-
72
17
  export type BillableEvent = {
73
18
  record: {
74
19
  id: '202408_cus_w_Q7M9bXcHMKB6';
@@ -0,0 +1,206 @@
1
+ import {
2
+ GL_HYPERLINE_DEFAULT_DEV_PLAN_ID,
3
+ GL_HYPERLINE_DEFAULT_MIN_AMOUNT,
4
+ GL_HYPERLINE_DEFAULT_PLAN_ID,
5
+ HYPERLINE_DEFAULT_DEV_PLAN_ID,
6
+ HYPERLINE_DEFAULT_MIN_AMOUNT,
7
+ HYPERLINE_DEFAULT_PLAN_ID,
8
+ } from '../const';
9
+ import { useHyperlineByToken } from '../hooks';
10
+
11
+ export async function calculateMrr(
12
+ subscriptionId: string,
13
+ estimated = false,
14
+ _activeListings?: number,
15
+ hyperline: {
16
+ getSubscription(
17
+ id: string,
18
+ liveBilling?: boolean
19
+ ): Promise<{
20
+ customer_id: string;
21
+ plan_id: string | null;
22
+ products?: unknown[];
23
+ coupons?: (
24
+ | {
25
+ type: 'amount';
26
+ repeat: 'once' | 'forever' | 'custom';
27
+ discount_amount: number;
28
+ }
29
+ | {
30
+ type: 'percent';
31
+ repeat: 'once' | 'forever' | 'custom';
32
+ discount_percent: number;
33
+ }
34
+ )[];
35
+ phases?: {
36
+ type: 'setup' | 'trial' | 'standard';
37
+ status: 'pending' | 'active' | 'finished';
38
+ products: {
39
+ min_amount?: number | null;
40
+ max_amount?: number | null;
41
+ prices: (
42
+ | {
43
+ type: 'volume';
44
+ amount: number;
45
+ from: number;
46
+ to: number | null;
47
+ unit_count: number;
48
+ }
49
+ | {
50
+ type:
51
+ | 'bps'
52
+ | 'bulk'
53
+ | 'bundle'
54
+ | 'fee'
55
+ | 'flat_fee'
56
+ | 'packaged';
57
+ }
58
+ )[];
59
+ }[];
60
+ }[];
61
+ live_billing?: { total_amount: number };
62
+ } | null>;
63
+ getInvoicesByCustomerId(id: string): Promise<{
64
+ data: {
65
+ emitted_at: string;
66
+ total_amount: number;
67
+ }[];
68
+ } | null>;
69
+ } = useHyperlineByToken(process.env.HYPERLINE_TOKEN!),
70
+ includeLiveBilling = false
71
+ ) {
72
+ const _subscription = await hyperline.getSubscription(
73
+ subscriptionId,
74
+ includeLiveBilling
75
+ );
76
+ if (!_subscription) throw new Error('Subscription not found');
77
+
78
+ const { products, phases, ...subscription } = _subscription;
79
+
80
+ let mrr = 0;
81
+ const activeListings = _activeListings || 0;
82
+ const phase = phases?.filter((x) =>
83
+ estimated
84
+ ? x.type === 'standard'
85
+ : (x.type === 'trial' && x.status === 'active') || x.type === 'standard'
86
+ )?.[0];
87
+ const product = phase?.products?.[0];
88
+ const type = product?.prices?.[0].type;
89
+ if (type === 'volume') {
90
+ const volumePrices: Array<{
91
+ amount: number;
92
+ from: number;
93
+ to: number | null;
94
+ unit_count: number;
95
+ }> = [];
96
+
97
+ product?.prices?.forEach((price) => {
98
+ if (
99
+ price.type !== 'volume' ||
100
+ !('amount' in price) ||
101
+ !('from' in price) ||
102
+ !('to' in price) ||
103
+ !('unit_count' in price)
104
+ )
105
+ return;
106
+
107
+ volumePrices.push({
108
+ amount: price.amount,
109
+ from: price.from,
110
+ to: price.to,
111
+ unit_count: price.unit_count,
112
+ });
113
+ });
114
+ volumePrices.sort((a, b) => a.from - b.from);
115
+
116
+ mrr =
117
+ volumePrices.reduce((acc, price) => {
118
+ const listings =
119
+ price.to && activeListings >= price.to
120
+ ? price.to - price.from
121
+ : activeListings >= price.from
122
+ ? activeListings - price.from
123
+ : 0;
124
+
125
+ acc += (price.amount / 100) * (listings / price.unit_count);
126
+
127
+ return acc;
128
+ }, 0) || 0;
129
+
130
+ const firstTier = volumePrices[0];
131
+ const secondTier = volumePrices[1];
132
+ const product_min_amount =
133
+ product &&
134
+ 'min_amount' in product &&
135
+ typeof product.min_amount === 'number'
136
+ ? product.min_amount
137
+ : null;
138
+ const product_max_amount =
139
+ product &&
140
+ 'max_amount' in product &&
141
+ typeof product.max_amount === 'number'
142
+ ? product.max_amount
143
+ : null;
144
+ const inferred_min_amount =
145
+ firstTier &&
146
+ secondTier &&
147
+ firstTier.from === 0 &&
148
+ firstTier.to != null &&
149
+ secondTier.from === firstTier.to &&
150
+ firstTier.amount === secondTier.amount &&
151
+ firstTier.unit_count === secondTier.unit_count
152
+ ? firstTier.amount *
153
+ ((firstTier.to - firstTier.from) / firstTier.unit_count)
154
+ : 0;
155
+ const plan_min_amount = [
156
+ GL_HYPERLINE_DEFAULT_PLAN_ID,
157
+ GL_HYPERLINE_DEFAULT_DEV_PLAN_ID,
158
+ ].includes(subscription.plan_id!)
159
+ ? GL_HYPERLINE_DEFAULT_MIN_AMOUNT
160
+ : [HYPERLINE_DEFAULT_PLAN_ID, HYPERLINE_DEFAULT_DEV_PLAN_ID].includes(
161
+ subscription.plan_id!
162
+ )
163
+ ? HYPERLINE_DEFAULT_MIN_AMOUNT
164
+ : 0;
165
+
166
+ const min_amount =
167
+ ((product_min_amount || plan_min_amount || inferred_min_amount) ?? 0) /
168
+ 100;
169
+ mrr = Math.max(mrr, min_amount);
170
+
171
+ const max_amount = ((product_max_amount || 0) ?? 0) / 100;
172
+ mrr = max_amount > 0 ? Math.min(mrr, max_amount) : mrr;
173
+
174
+ // apply discounts (only these who repeat forever if estimated is true)
175
+ (subscription.coupons || [])
176
+ .filter((coupon) => (estimated ? coupon.repeat === 'forever' : true))
177
+ .forEach((x) => {
178
+ if ('discount_amount' in x && x.discount_amount)
179
+ mrr -= x.discount_amount / 100;
180
+ else if ('discount_percent' in x && x.discount_percent)
181
+ mrr -= (x.discount_percent / 100) * mrr;
182
+ });
183
+ } else if (type === 'bps') {
184
+ const { data } = subscription?.customer_id
185
+ ? (await hyperline.getInvoicesByCustomerId(subscription.customer_id)) || {
186
+ data: [],
187
+ }
188
+ : { data: [] };
189
+
190
+ // sort invoices by date
191
+ const invoices = data
192
+ ?.sort((a, b) => a.emitted_at.localeCompare(b.emitted_at))
193
+ .reverse();
194
+
195
+ // get the last invoice
196
+ mrr = (invoices[0]?.total_amount || 0) / 100;
197
+ }
198
+
199
+ return {
200
+ mrr,
201
+ mrrAlt:
202
+ subscription.live_billing?.total_amount == null
203
+ ? null
204
+ : subscription.live_billing.total_amount / 100,
205
+ };
206
+ }
@@ -1,2 +1,3 @@
1
1
  export * from './arrayBufferToBase64';
2
- export * from './getMrrDiffReasons';
2
+ export * from './calculateMrr';
3
+ export * from './isTestingTeam';
@@ -0,0 +1,11 @@
1
+ import { DEMO_TEST_PARTNER_TENANT_ID, TEST_TENANT_ID } from '../const';
2
+
3
+ export const isTestingTeam = (tenant: {
4
+ id?: string;
5
+ partnerId?: string | null;
6
+ billingPartnerId?: string | null;
7
+ }) =>
8
+ tenant.id === TEST_TENANT_ID ||
9
+ [tenant.id, tenant.partnerId, tenant.billingPartnerId].includes(
10
+ DEMO_TEST_PARTNER_TENANT_ID
11
+ );
@@ -1,15 +0,0 @@
1
- import { HasuraClient } from '@vrplatform/graphql';
2
- export declare function getMrrDiffReasons(firstDate: string, lastDate: string, client: HasuraClient): Promise<{
3
- messages: string[];
4
- result: {
5
- mrrDiff: number;
6
- listingsDiff: number;
7
- hasCancelled: boolean;
8
- id: string;
9
- name?: string;
10
- plan?: string;
11
- activePartnerTeamsDiff: number;
12
- createdAt: string;
13
- isNew: boolean;
14
- }[];
15
- }>;
@@ -1,217 +0,0 @@
1
- import { groupBy, utc } from '@vrplatform/utils';
2
- import { VRP_TENANT_ID, XIMPLIFI_TENANT_ID } from '../const';
3
- function printFinancialNumber(number, showPlusMinus = true) {
4
- return `${showPlusMinus ? (number >= 0 ? '+' : '-') : ''}$${Math.abs(number)
5
- .toFixed(2)
6
- .toString()
7
- .replace(/\B(?=(\d{3})+(?!\d))/g, ',')}`;
8
- }
9
- function printPlusMinus(number) {
10
- return `${number >= 0 ? '+' : '-'}${Math.abs(number)}`;
11
- }
12
- export async function getMrrDiffReasons(firstDate, lastDate, client) {
13
- const messages = [];
14
- messages.push(`MRR Diff Reasons from ${utc(firstDate).yyyymmdd()} to ${utc(lastDate).yyyymmdd()}`);
15
- messages.push('--------------------------------');
16
- const { mrrEvents, listingsEvents } = await client.query((q) => ({
17
- mrrEvents: q
18
- .tracking_event({
19
- where: {
20
- name: { _eq: 'mrr_reported' },
21
- _or: [
22
- {
23
- createdAt: {
24
- _gte: utc(firstDate).yyyymmdd(),
25
- _lte: utc(firstDate).add(1, 'day').yyyymmdd(),
26
- },
27
- },
28
- {
29
- createdAt: {
30
- _gte: utc(lastDate).yyyymmdd(),
31
- _lte: utc(lastDate).add(1, 'day').yyyymmdd(),
32
- },
33
- },
34
- ],
35
- },
36
- })
37
- .map((e) => ({
38
- tenantId: e.tenant?.id,
39
- tenantName: e.tenant?.name,
40
- tenantCreatedAt: e.tenant?.createdAt,
41
- tenantPlan: e.tenant?.billingPlan,
42
- partnerTeamsCreatedFirstDate: e.tenant
43
- ?.clients({
44
- where: {
45
- createdAt: {
46
- _lte: utc(firstDate).yyyymmdd(),
47
- },
48
- },
49
- })
50
- .map((c) => c.id).length,
51
- partnerTeamsCreatedLastDate: e.tenant
52
- ?.clients({
53
- where: {
54
- createdAt: {
55
- _lte: utc(lastDate).yyyymmdd(),
56
- },
57
- },
58
- })
59
- .map((c) => c.id).length,
60
- partnerTeamsCancelledFirstDate: e.tenant
61
- ?.clients({
62
- where: {
63
- cancelledAt: {
64
- _lte: utc(firstDate).yyyymmdd(),
65
- },
66
- },
67
- })
68
- .map((c) => c.id).length,
69
- partnerTeamsCancelledLastDate: e.tenant
70
- ?.clients({
71
- where: {
72
- cancelledAt: {
73
- _lte: utc(lastDate).yyyymmdd(),
74
- },
75
- },
76
- })
77
- .map((c) => c.id).length,
78
- mrr: e.props()?.mrr,
79
- createdAt: utc(e.createdAt).yyyymmdd(),
80
- })),
81
- listingsEvents: q
82
- .tracking_event({
83
- where: {
84
- name: { _eq: 'listings_reported' },
85
- _or: [
86
- {
87
- createdAt: {
88
- _gte: utc(firstDate).yyyymmdd(),
89
- _lte: utc(firstDate).add(1, 'day').yyyymmdd(),
90
- },
91
- },
92
- {
93
- createdAt: {
94
- _gte: utc(lastDate).yyyymmdd(),
95
- _lte: utc(lastDate).add(1, 'day').yyyymmdd(),
96
- },
97
- },
98
- ],
99
- },
100
- })
101
- .map((e) => ({
102
- tenantId: e.tenant?.id,
103
- billingPartnerId: e.tenant?.calculatedBillingPartnerId,
104
- listings: e.props()?.activeListings,
105
- createdAt: utc(e.createdAt).yyyymmdd(),
106
- })),
107
- }));
108
- messages.push(`Found ${mrrEvents.length} mrr events`);
109
- // join mrr and listings events
110
- const trackingEvents = mrrEvents
111
- .filter((e) => e.tenantId)
112
- .map((e) => {
113
- const filteredEvents = listingsEvents.filter((l) => {
114
- if (!l.billingPartnerId || !l.tenantId)
115
- return false;
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 (!event.tenantId)
130
- continue;
131
- if (!tenants[event.tenantId]) {
132
- const partnerTeamsCreatedDiff = (event.partnerTeamsCreatedLastDate || 0) -
133
- (event.partnerTeamsCreatedFirstDate || 0);
134
- const partnerTeamsCancelledDiff = (event.partnerTeamsCancelledLastDate || 0) -
135
- (event.partnerTeamsCancelledFirstDate || 0);
136
- tenants[event.tenantId] = {
137
- id: event.tenantId,
138
- name: event.tenantName,
139
- plan: event.tenantPlan,
140
- activePartnerTeamsDiff: partnerTeamsCreatedDiff - partnerTeamsCancelledDiff,
141
- mrrFirstDate: undefined,
142
- mrrLastDate: undefined,
143
- mrrDiff: 0,
144
- listingsFirstDate: undefined,
145
- listingsLastDate: undefined,
146
- listingsDiff: 0,
147
- createdAt: utc(event.tenantCreatedAt).yyyymmdd(),
148
- isNew: utc(event.tenantCreatedAt).isBetween(utc(firstDate), utc(lastDate)),
149
- };
150
- }
151
- if (event.createdAt === firstDate) {
152
- tenants[event.tenantId].mrrFirstDate = event.mrr;
153
- tenants[event.tenantId].listingsFirstDate = event.listings;
154
- }
155
- if (event.createdAt === lastDate) {
156
- tenants[event.tenantId].mrrLastDate = event.mrr;
157
- tenants[event.tenantId].listingsLastDate = event.listings;
158
- }
159
- }
160
- const result = Object.values(tenants)
161
- .map(({ mrrFirstDate, mrrLastDate, listingsFirstDate, listingsLastDate, ...t }) => ({
162
- ...t,
163
- mrrDiff: (mrrLastDate ?? 0) - (mrrFirstDate ?? 0),
164
- listingsDiff: (listingsLastDate ?? 0) - (listingsFirstDate ?? 0),
165
- hasCancelled: mrrFirstDate !== undefined && mrrLastDate === undefined,
166
- }))
167
- .filter((t) => t.mrrDiff)
168
- .sort((a, b) => b.mrrDiff - a.mrrDiff)
169
- .reverse();
170
- // calculate summ of mrr per day
171
- const groupedEvents = groupBy(trackingEvents, (e) => e.createdAt);
172
- const summedMrrPerDay = Object.entries(groupedEvents)
173
- .map(([date, events]) => {
174
- const typedEvents = events;
175
- const mrr = typedEvents.reduce((acc, e) => acc + (e.mrr ?? 0), 0);
176
- const listings = typedEvents.reduce((acc, e) => acc + (e.listings ?? 0), 0);
177
- return {
178
- date,
179
- mrr,
180
- count: typedEvents.length,
181
- listings,
182
- };
183
- })
184
- .sort((a, b) => utc(b.date).diff(utc(a.date)));
185
- messages.push(`MRR sum changed from ${printFinancialNumber(summedMrrPerDay[1].mrr, false)} to ${printFinancialNumber(summedMrrPerDay[0].mrr, false)} (${printFinancialNumber(summedMrrPerDay[0].mrr - summedMrrPerDay[1].mrr)})`);
186
- 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)})`);
187
- 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)})`);
188
- messages.push(`Active Partner Teams changed by ${printPlusMinus(result.reduce((acc, t) => acc + t.activePartnerTeamsDiff, 0))}`);
189
- messages.push();
190
- const cancelledTenants = result.filter((t) => t.hasCancelled);
191
- const legacyTenants = result.filter((t) => t.plan?.includes('Legacy') &&
192
- !cancelledTenants.map((t) => t.id).includes(t.id));
193
- const newTenants = result.filter((t) => t.isNew &&
194
- !cancelledTenants.map((t) => t.id).includes(t.id) &&
195
- !legacyTenants.map((t) => t.id).includes(t.id));
196
- const activeListings = result.filter((t) => t.listingsDiff &&
197
- !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
- const otherTenants = result.filter((t) => !newTenants.map((t) => t.id).includes(t.id) &&
201
- !cancelledTenants.map((t) => t.id).includes(t.id) &&
202
- !legacyTenants.map((t) => t.id).includes(t.id) &&
203
- !activeListings.map((t) => t.id).includes(t.id));
204
- const total = newTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +
205
- cancelledTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +
206
- legacyTenants.reduce((acc, t) => acc + t.mrrDiff, 0) +
207
- activeListings.reduce((acc, t) => acc + t.mrrDiff, 0) +
208
- otherTenants.reduce((acc, t) => acc + t.mrrDiff, 0);
209
- messages.push(`MRR from ${newTenants.length} new tenants: ${printFinancialNumber(newTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`);
210
- messages.push(`MRR from ${cancelledTenants.length} cancelled tenants: ${printFinancialNumber(cancelledTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`);
211
- messages.push(`MRR from ${legacyTenants.length} tenants with Legacy plans: ${printFinancialNumber(legacyTenants.reduce((acc, t) => acc + t.mrrDiff, 0))}`);
212
- messages.push(`MRR from ${activeListings.length} tenants with active listings changes: ${printFinancialNumber(activeListings.reduce((acc, t) => acc + t.mrrDiff, 0))}`);
213
- 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(', ')})`);
214
- messages.push(`= ${printFinancialNumber(total)}`);
215
- return { messages, result };
216
- }
217
- //# sourceMappingURL=getMrrDiffReasons.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"getMrrDiffReasons.js","sourceRoot":"src/","sources":["utils/getMrrDiffReasons.ts"],"names":[],"mappings":"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","sourcesContent":["import { HasuraClient } from '@vrplatform/graphql';\nimport { groupBy, utc } from '@vrplatform/utils';\nimport { VRP_TENANT_ID, XIMPLIFI_TENANT_ID } from '../const';\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\nexport async function getMrrDiffReasons(\n firstDate: string,\n lastDate: string,\n client: HasuraClient\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\n .filter((e) => e.tenantId)\n .map((e) => {\n const filteredEvents = listingsEvents.filter((l) => {\n if (!l.billingPartnerId || !l.tenantId) return false;\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 (!event.tenantId) continue;\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 typedEvents = events as typeof trackingEvents;\n const mrr = typedEvents.reduce((acc, e) => acc + (e.mrr ?? 0), 0);\n const listings = typedEvents.reduce(\n (acc, e) => acc + (e.listings ?? 0),\n 0\n );\n\n return {\n date,\n mrr,\n count: typedEvents.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"]}
@@ -1,15 +0,0 @@
1
- import { HasuraClient } from '@vrplatform/graphql';
2
- export declare function getMrrDiffReasons(firstDate: string, lastDate: string, client: HasuraClient): Promise<{
3
- messages: string[];
4
- result: {
5
- mrrDiff: number;
6
- listingsDiff: number;
7
- hasCancelled: boolean;
8
- id: string;
9
- name?: string;
10
- plan?: string;
11
- activePartnerTeamsDiff: number;
12
- createdAt: string;
13
- isNew: boolean;
14
- }[];
15
- }>;