@forklaunch/implementation-billing-base 0.1.17 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/__test__/schemaEquality.test.js +35 -14
- package/lib/eject/domain/schemas/checkoutSession.schema.ts +24 -4
- package/lib/eject/domain/schemas/paymentLink.schema.ts +24 -4
- package/lib/eject/services/billingPortal.service.ts +104 -32
- package/lib/eject/services/checkoutSession.service.ts +115 -32
- package/lib/eject/services/paymentLink.service.ts +116 -41
- package/lib/eject/services/plan.service.ts +60 -22
- package/lib/eject/services/subscription.service.ts +83 -26
- package/lib/schemas/checkoutSession.schema.d.ts +97 -11
- package/lib/schemas/checkoutSession.schema.d.ts.map +1 -1
- package/lib/schemas/paymentLink.schema.d.ts +101 -12
- package/lib/schemas/paymentLink.schema.d.ts.map +1 -1
- package/lib/schemas/typebox/checkoutSession.schema.d.ts +130 -10
- package/lib/schemas/typebox/checkoutSession.schema.d.ts.map +1 -1
- package/lib/schemas/typebox/checkoutSession.schema.js +9 -3
- package/lib/schemas/typebox/paymentLink.schema.d.ts +144 -12
- package/lib/schemas/typebox/paymentLink.schema.d.ts.map +1 -1
- package/lib/schemas/typebox/paymentLink.schema.js +9 -3
- package/lib/schemas/zod/checkoutSession.schema.d.ts +66 -12
- package/lib/schemas/zod/checkoutSession.schema.d.ts.map +1 -1
- package/lib/schemas/zod/checkoutSession.schema.js +9 -3
- package/lib/schemas/zod/paymentLink.schema.d.ts +66 -12
- package/lib/schemas/zod/paymentLink.schema.d.ts.map +1 -1
- package/lib/schemas/zod/paymentLink.schema.js +9 -3
- package/lib/services/billingPortal.service.d.ts +25 -7
- package/lib/services/billingPortal.service.d.ts.map +1 -1
- package/lib/services/billingPortal.service.js +87 -29
- package/lib/services/checkoutSession.service.d.ts +63 -20
- package/lib/services/checkoutSession.service.d.ts.map +1 -1
- package/lib/services/checkoutSession.service.js +67 -16
- package/lib/services/paymentLink.service.d.ts +39 -20
- package/lib/services/paymentLink.service.d.ts.map +1 -1
- package/lib/services/paymentLink.service.js +88 -24
- package/lib/services/plan.service.d.ts +19 -7
- package/lib/services/plan.service.d.ts.map +1 -1
- package/lib/services/plan.service.js +49 -17
- package/lib/services/subscription.service.d.ts +21 -7
- package/lib/services/subscription.service.d.ts.map +1 -1
- package/lib/services/subscription.service.js +72 -20
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
|
@@ -60,35 +60,48 @@ const zodBillingPortalSchema = ZodBillingPortalSchema({ uuidId: false });
|
|
|
60
60
|
const typeboxBillingPortalSchema = TypeboxBillingPortalSchema({
|
|
61
61
|
uuidId: false
|
|
62
62
|
});
|
|
63
|
-
const zodCreateCheckoutSessionSchema =
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
const zodCreateCheckoutSessionSchema = ZodCreateCheckoutSessionSchema(
|
|
64
|
+
DummyEnum,
|
|
65
|
+
DummyEnum
|
|
66
|
+
);
|
|
67
|
+
const typeboxCreateCheckoutSessionSchema = TypeboxCreateCheckoutSessionSchema(
|
|
68
|
+
DummyEnum,
|
|
69
|
+
DummyEnum
|
|
70
|
+
);
|
|
67
71
|
const zodUpdateCheckoutSessionSchema = ZodUpdateCheckoutSessionSchema({
|
|
68
72
|
uuidId: false
|
|
69
|
-
})(DummyEnum);
|
|
73
|
+
})(DummyEnum, DummyEnum);
|
|
70
74
|
const typeboxUpdateCheckoutSessionSchema = TypeboxUpdateCheckoutSessionSchema({
|
|
71
75
|
uuidId: false
|
|
72
|
-
})(DummyEnum);
|
|
76
|
+
})(DummyEnum, DummyEnum);
|
|
73
77
|
const zodCheckoutSessionSchema = ZodCheckoutSessionSchema({ uuidId: true })(
|
|
78
|
+
DummyEnum,
|
|
74
79
|
DummyEnum
|
|
75
80
|
);
|
|
76
81
|
const typeboxCheckoutSessionSchema = TypeboxCheckoutSessionSchema({
|
|
77
82
|
uuidId: true
|
|
78
|
-
})(DummyEnum);
|
|
79
|
-
const zodCreatePaymentLinkSchema = ZodCreatePaymentLinkSchema(
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
})(DummyEnum, DummyEnum);
|
|
84
|
+
const zodCreatePaymentLinkSchema = ZodCreatePaymentLinkSchema(
|
|
85
|
+
DummyEnum,
|
|
86
|
+
DummyEnum
|
|
87
|
+
);
|
|
88
|
+
const typeboxCreatePaymentLinkSchema = TypeboxCreatePaymentLinkSchema(
|
|
89
|
+
DummyEnum,
|
|
90
|
+
DummyEnum
|
|
91
|
+
);
|
|
82
92
|
const zodUpdatePaymentLinkSchema = ZodUpdatePaymentLinkSchema({
|
|
83
93
|
uuidId: false
|
|
84
|
-
})(DummyEnum);
|
|
94
|
+
})(DummyEnum, DummyEnum);
|
|
85
95
|
const typeboxUpdatePaymentLinkSchema = TypeboxUpdatePaymentLinkSchema({
|
|
86
96
|
uuidId: false
|
|
87
|
-
})(DummyEnum);
|
|
88
|
-
const zodPaymentLinkSchema = ZodPaymentLinkSchema({ uuidId: true })(
|
|
97
|
+
})(DummyEnum, DummyEnum);
|
|
98
|
+
const zodPaymentLinkSchema = ZodPaymentLinkSchema({ uuidId: true })(
|
|
99
|
+
DummyEnum,
|
|
100
|
+
DummyEnum
|
|
101
|
+
);
|
|
89
102
|
const typeboxPaymentLinkSchema = TypeboxPaymentLinkSchema({
|
|
90
103
|
uuidId: false
|
|
91
|
-
})(DummyEnum);
|
|
104
|
+
})(DummyEnum, DummyEnum);
|
|
92
105
|
const zodCreatePlanSchema = ZodCreatePlanSchema(DummyEnum, DummyEnum);
|
|
93
106
|
const typeboxCreatePlanSchema = TypeboxCreatePlanSchema(DummyEnum, DummyEnum);
|
|
94
107
|
const zodUpdatePlanSchema = ZodUpdatePlanSchema({ uuidId: false })(
|
|
@@ -178,6 +191,8 @@ describe('schema equality', () => {
|
|
|
178
191
|
paymentMethods: [DummyEnum.A, DummyEnum.B],
|
|
179
192
|
successRedirectUri: 'https://example.com',
|
|
180
193
|
cancelRedirectUri: 'https://example.com',
|
|
194
|
+
expiresAt: new Date(),
|
|
195
|
+
status: DummyEnum.A,
|
|
181
196
|
extraFields: {
|
|
182
197
|
test: 'test'
|
|
183
198
|
}
|
|
@@ -214,6 +229,8 @@ describe('schema equality', () => {
|
|
|
214
229
|
paymentMethods: [DummyEnum.A, DummyEnum.B],
|
|
215
230
|
successRedirectUri: 'https://example.com',
|
|
216
231
|
cancelRedirectUri: 'https://example.com',
|
|
232
|
+
expiresAt: new Date(),
|
|
233
|
+
status: DummyEnum.A,
|
|
217
234
|
extraFields: {
|
|
218
235
|
test: 'test'
|
|
219
236
|
}
|
|
@@ -237,6 +254,8 @@ describe('schema equality', () => {
|
|
|
237
254
|
metadata: {
|
|
238
255
|
test: 'test'
|
|
239
256
|
},
|
|
257
|
+
expiresAt: new Date(),
|
|
258
|
+
status: DummyEnum.A,
|
|
240
259
|
extraFields: {
|
|
241
260
|
test: 'test'
|
|
242
261
|
}
|
|
@@ -278,6 +297,8 @@ describe('schema equality', () => {
|
|
|
278
297
|
metadata: {
|
|
279
298
|
test: 'test'
|
|
280
299
|
},
|
|
300
|
+
expiresAt: new Date(),
|
|
301
|
+
status: DummyEnum.A,
|
|
281
302
|
extraFields: {
|
|
282
303
|
test: 'test'
|
|
283
304
|
}
|
|
@@ -10,37 +10,57 @@ import {
|
|
|
10
10
|
} from '@{{app_name}}/core';
|
|
11
11
|
|
|
12
12
|
export const CreateCheckoutSessionSchema = <
|
|
13
|
-
T extends Record<string, LiteralSchema
|
|
13
|
+
T extends Record<string, LiteralSchema>,
|
|
14
|
+
U extends Record<string, LiteralSchema>
|
|
14
15
|
>(
|
|
15
|
-
PaymentMethodEnum: T
|
|
16
|
+
PaymentMethodEnum: T,
|
|
17
|
+
StatusEnum: U
|
|
16
18
|
) => ({
|
|
17
19
|
customerId: string,
|
|
18
20
|
paymentMethods: array(enum_(PaymentMethodEnum)),
|
|
19
21
|
successRedirectUri: string,
|
|
20
22
|
cancelRedirectUri: string,
|
|
23
|
+
expiresAt: date,
|
|
24
|
+
status: enum_(StatusEnum),
|
|
21
25
|
extraFields: optional(unknown)
|
|
22
26
|
});
|
|
23
27
|
|
|
24
28
|
export const UpdateCheckoutSessionSchema =
|
|
25
29
|
({ uuidId }: { uuidId: boolean }) =>
|
|
26
|
-
<
|
|
30
|
+
<
|
|
31
|
+
T extends Record<string, LiteralSchema>,
|
|
32
|
+
U extends Record<string, LiteralSchema>
|
|
33
|
+
>(
|
|
34
|
+
PaymentMethodEnum: T,
|
|
35
|
+
StatusEnum: U
|
|
36
|
+
) => ({
|
|
27
37
|
id: uuidId ? uuid : string,
|
|
28
38
|
customerId: optional(string),
|
|
29
39
|
paymentMethods: optional(array(enum_(PaymentMethodEnum))),
|
|
30
40
|
successRedirectUri: optional(string),
|
|
31
41
|
cancelRedirectUri: optional(string),
|
|
42
|
+
expiresAt: optional(date),
|
|
43
|
+
status: optional(enum_(StatusEnum)),
|
|
32
44
|
extraFields: optional(unknown)
|
|
33
45
|
});
|
|
34
46
|
|
|
35
47
|
export const CheckoutSessionSchema =
|
|
36
48
|
({ uuidId }: { uuidId: boolean }) =>
|
|
37
|
-
<
|
|
49
|
+
<
|
|
50
|
+
T extends Record<string, LiteralSchema>,
|
|
51
|
+
U extends Record<string, LiteralSchema>
|
|
52
|
+
>(
|
|
53
|
+
PaymentMethodEnum: T,
|
|
54
|
+
StatusEnum: U
|
|
55
|
+
) => ({
|
|
38
56
|
id: uuidId ? uuid : string,
|
|
39
57
|
customerId: string,
|
|
40
58
|
metadata: optional(unknown),
|
|
41
59
|
paymentMethods: array(enum_(PaymentMethodEnum)),
|
|
42
60
|
successRedirectUri: string,
|
|
43
61
|
cancelRedirectUri: string,
|
|
62
|
+
expiresAt: date,
|
|
63
|
+
status: enum_(StatusEnum),
|
|
44
64
|
extraFields: optional(unknown),
|
|
45
65
|
createdAt: optional(date),
|
|
46
66
|
updatedAt: optional(date)
|
|
@@ -10,9 +10,11 @@ import {
|
|
|
10
10
|
} from '@{{app_name}}/core';
|
|
11
11
|
|
|
12
12
|
export const CreatePaymentLinkSchema = <
|
|
13
|
-
T extends Record<string, LiteralSchema
|
|
13
|
+
T extends Record<string, LiteralSchema>,
|
|
14
|
+
U extends Record<string, LiteralSchema>
|
|
14
15
|
>(
|
|
15
|
-
CurrencyEnum: T
|
|
16
|
+
CurrencyEnum: T,
|
|
17
|
+
StatusEnum: U
|
|
16
18
|
) => ({
|
|
17
19
|
amount: number,
|
|
18
20
|
currency: enum_(CurrencyEnum),
|
|
@@ -20,12 +22,20 @@ export const CreatePaymentLinkSchema = <
|
|
|
20
22
|
metadata: optional(unknown),
|
|
21
23
|
successRedirectUri: string,
|
|
22
24
|
cancelRedirectUri: string,
|
|
25
|
+
expiresAt: date,
|
|
26
|
+
status: enum_(StatusEnum),
|
|
23
27
|
extraFields: optional(unknown)
|
|
24
28
|
});
|
|
25
29
|
|
|
26
30
|
export const UpdatePaymentLinkSchema =
|
|
27
31
|
({ uuidId }: { uuidId: boolean }) =>
|
|
28
|
-
<
|
|
32
|
+
<
|
|
33
|
+
T extends Record<string, LiteralSchema>,
|
|
34
|
+
U extends Record<string, LiteralSchema>
|
|
35
|
+
>(
|
|
36
|
+
CurrencyEnum: T,
|
|
37
|
+
StatusEnum: U
|
|
38
|
+
) => ({
|
|
29
39
|
id: uuidId ? uuid : string,
|
|
30
40
|
amount: optional(number),
|
|
31
41
|
currency: optional(enum_(CurrencyEnum)),
|
|
@@ -33,12 +43,20 @@ export const UpdatePaymentLinkSchema =
|
|
|
33
43
|
metadata: optional(unknown),
|
|
34
44
|
successRedirectUri: optional(string),
|
|
35
45
|
cancelRedirectUri: optional(string),
|
|
46
|
+
expiresAt: optional(date),
|
|
47
|
+
status: optional(enum_(StatusEnum)),
|
|
36
48
|
extraFields: optional(unknown)
|
|
37
49
|
});
|
|
38
50
|
|
|
39
51
|
export const PaymentLinkSchema =
|
|
40
52
|
({ uuidId }: { uuidId: boolean }) =>
|
|
41
|
-
<
|
|
53
|
+
<
|
|
54
|
+
T extends Record<string, LiteralSchema>,
|
|
55
|
+
U extends Record<string, LiteralSchema>
|
|
56
|
+
>(
|
|
57
|
+
CurrencyEnum: T,
|
|
58
|
+
StatusEnum: U
|
|
59
|
+
) => ({
|
|
42
60
|
id: uuidId ? uuid : string,
|
|
43
61
|
amount: number,
|
|
44
62
|
currency: enum_(CurrencyEnum),
|
|
@@ -46,6 +64,8 @@ export const PaymentLinkSchema =
|
|
|
46
64
|
metadata: optional(unknown),
|
|
47
65
|
successRedirectUri: string,
|
|
48
66
|
cancelRedirectUri: string,
|
|
67
|
+
expiresAt: date,
|
|
68
|
+
status: enum_(StatusEnum),
|
|
49
69
|
extraFields: optional(unknown),
|
|
50
70
|
createdAt: optional(date),
|
|
51
71
|
updatedAt: optional(date)
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { IdDto, InstanceTypeRecord } from '@forklaunch/common';
|
|
2
2
|
import { createCacheKey, TtlCache } from '@forklaunch/core/cache';
|
|
3
|
+
import {
|
|
4
|
+
evaluateTelemetryOptions,
|
|
5
|
+
MetricsDefinition,
|
|
6
|
+
OpenTelemetryCollector,
|
|
7
|
+
TelemetryOptions
|
|
8
|
+
} from '@forklaunch/core/http';
|
|
3
9
|
import {
|
|
4
10
|
InternalDtoMapper,
|
|
5
11
|
RequestDtoMapperConstructor,
|
|
6
12
|
ResponseDtoMapperConstructor,
|
|
7
13
|
transformIntoInternalDtoMapper
|
|
8
14
|
} from '@forklaunch/core/mappers';
|
|
9
|
-
import {
|
|
10
|
-
MetricsDefinition,
|
|
11
|
-
OpenTelemetryCollector
|
|
12
|
-
} from '@forklaunch/core/http';
|
|
13
15
|
import { BillingPortalService } from '@forklaunch/interfaces-billing/interfaces';
|
|
14
16
|
import {
|
|
15
17
|
BillingPortalDto,
|
|
@@ -17,6 +19,7 @@ import {
|
|
|
17
19
|
UpdateBillingPortalDto
|
|
18
20
|
} from '@forklaunch/interfaces-billing/types';
|
|
19
21
|
import { AnySchemaValidator } from '@forklaunch/validator';
|
|
22
|
+
import { EntityManager } from '@mikro-orm/core';
|
|
20
23
|
|
|
21
24
|
export class BaseBillingPortalService<
|
|
22
25
|
SchemaValidator extends AnySchemaValidator,
|
|
@@ -41,17 +44,24 @@ export class BaseBillingPortalService<
|
|
|
41
44
|
}
|
|
42
45
|
> implements BillingPortalService
|
|
43
46
|
{
|
|
44
|
-
#
|
|
45
|
-
InstanceTypeRecord<typeof this.
|
|
47
|
+
#mappers: InternalDtoMapper<
|
|
48
|
+
InstanceTypeRecord<typeof this.mappers>,
|
|
46
49
|
Entities,
|
|
47
50
|
Dto
|
|
48
51
|
>;
|
|
52
|
+
private evaluatedTelemetryOptions: {
|
|
53
|
+
logging?: boolean;
|
|
54
|
+
metrics?: boolean;
|
|
55
|
+
tracing?: boolean;
|
|
56
|
+
};
|
|
57
|
+
private enableDatabaseBackup: boolean;
|
|
49
58
|
|
|
50
59
|
constructor(
|
|
60
|
+
protected em: EntityManager,
|
|
51
61
|
protected cache: TtlCache,
|
|
52
62
|
protected openTelemetryCollector: OpenTelemetryCollector<Metrics>,
|
|
53
63
|
protected schemaValidator: SchemaValidator,
|
|
54
|
-
protected
|
|
64
|
+
protected mappers: {
|
|
55
65
|
BillingPortalDtoMapper: ResponseDtoMapperConstructor<
|
|
56
66
|
SchemaValidator,
|
|
57
67
|
Dto['BillingPortalDtoMapper'],
|
|
@@ -67,9 +77,21 @@ export class BaseBillingPortalService<
|
|
|
67
77
|
Dto['UpdateBillingPortalDtoMapper'],
|
|
68
78
|
Entities['UpdateBillingPortalDtoMapper']
|
|
69
79
|
>;
|
|
80
|
+
},
|
|
81
|
+
readonly options?: {
|
|
82
|
+
telemetry?: TelemetryOptions;
|
|
83
|
+
enableDatabaseBackup?: boolean;
|
|
70
84
|
}
|
|
71
85
|
) {
|
|
72
|
-
this.#
|
|
86
|
+
this.#mappers = transformIntoInternalDtoMapper(mappers, schemaValidator);
|
|
87
|
+
this.enableDatabaseBackup = options?.enableDatabaseBackup ?? false;
|
|
88
|
+
this.evaluatedTelemetryOptions = options?.telemetry
|
|
89
|
+
? evaluateTelemetryOptions(options.telemetry).enabled
|
|
90
|
+
: {
|
|
91
|
+
logging: false,
|
|
92
|
+
metrics: false,
|
|
93
|
+
tracing: false
|
|
94
|
+
};
|
|
73
95
|
}
|
|
74
96
|
|
|
75
97
|
protected createCacheKey = createCacheKey('billing_portal_session');
|
|
@@ -77,65 +99,115 @@ export class BaseBillingPortalService<
|
|
|
77
99
|
async createBillingPortalSession(
|
|
78
100
|
billingPortalDto: Dto['CreateBillingPortalDtoMapper']
|
|
79
101
|
): Promise<Dto['BillingPortalDtoMapper']> {
|
|
80
|
-
|
|
81
|
-
this
|
|
102
|
+
if (this.evaluatedTelemetryOptions.logging) {
|
|
103
|
+
this.openTelemetryCollector.info(
|
|
104
|
+
'Creating billing portal session',
|
|
82
105
|
billingPortalDto
|
|
83
106
|
);
|
|
107
|
+
}
|
|
84
108
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
109
|
+
const billingPortal =
|
|
110
|
+
await this.#mappers.CreateBillingPortalDtoMapper.deserializeDtoToEntity(
|
|
111
|
+
billingPortalDto,
|
|
112
|
+
this.em
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if (this.enableDatabaseBackup) {
|
|
116
|
+
await this.em.persistAndFlush(billingPortal);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const createdBillingPortalDto =
|
|
120
|
+
await this.#mappers.BillingPortalDtoMapper.serializeEntityToDto(
|
|
121
|
+
billingPortal
|
|
122
|
+
);
|
|
89
123
|
|
|
90
124
|
await this.cache.putRecord({
|
|
91
|
-
key: this.createCacheKey(
|
|
92
|
-
value:
|
|
125
|
+
key: this.createCacheKey(createdBillingPortalDto.id),
|
|
126
|
+
value: createdBillingPortalDto,
|
|
93
127
|
ttlMilliseconds: this.cache.getTtlMilliseconds()
|
|
94
128
|
});
|
|
95
129
|
|
|
96
|
-
return
|
|
97
|
-
billingPortalSession
|
|
98
|
-
);
|
|
130
|
+
return createdBillingPortalDto;
|
|
99
131
|
}
|
|
100
132
|
|
|
101
133
|
async getBillingPortalSession(
|
|
102
134
|
idDto: IdDto
|
|
103
135
|
): Promise<Dto['BillingPortalDtoMapper']> {
|
|
104
|
-
|
|
136
|
+
if (this.evaluatedTelemetryOptions.logging) {
|
|
137
|
+
this.openTelemetryCollector.info('Getting billing portal session', idDto);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const billingPortalDetails = await this.cache.readRecord<
|
|
105
141
|
Entities['BillingPortalDtoMapper']
|
|
106
142
|
>(this.createCacheKey(idDto.id));
|
|
107
|
-
|
|
143
|
+
|
|
144
|
+
if (!billingPortalDetails) {
|
|
108
145
|
throw new Error('Session not found');
|
|
109
146
|
}
|
|
110
147
|
|
|
111
|
-
return
|
|
112
|
-
billingPortalSessionDetails.value
|
|
113
|
-
);
|
|
148
|
+
return billingPortalDetails.value;
|
|
114
149
|
}
|
|
115
150
|
|
|
116
151
|
async updateBillingPortalSession(
|
|
117
152
|
billingPortalDto: UpdateBillingPortalDto
|
|
118
153
|
): Promise<Dto['BillingPortalDtoMapper']> {
|
|
119
|
-
|
|
120
|
-
this
|
|
154
|
+
if (this.evaluatedTelemetryOptions.logging) {
|
|
155
|
+
this.openTelemetryCollector.info(
|
|
156
|
+
'Updating billing portal session',
|
|
121
157
|
billingPortalDto
|
|
122
158
|
);
|
|
123
|
-
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const existingBillingPortal = (
|
|
162
|
+
await this.cache.readRecord<Entities['BillingPortalDtoMapper']>(
|
|
163
|
+
this.createCacheKey(billingPortalDto.id)
|
|
164
|
+
)
|
|
165
|
+
)?.value;
|
|
166
|
+
|
|
167
|
+
if (!existingBillingPortal) {
|
|
168
|
+
throw new Error('Session not found');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const billingPortal =
|
|
172
|
+
await this.#mappers.UpdateBillingPortalDtoMapper.deserializeDtoToEntity(
|
|
173
|
+
billingPortalDto,
|
|
174
|
+
this.em
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
if (this.enableDatabaseBackup) {
|
|
178
|
+
await this.em.persistAndFlush({
|
|
179
|
+
billingPortal
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const updatedBillingPortalDto = {
|
|
184
|
+
...existingBillingPortal,
|
|
185
|
+
...(await this.#mappers.BillingPortalDtoMapper.serializeEntityToDto(
|
|
186
|
+
billingPortal
|
|
187
|
+
))
|
|
188
|
+
};
|
|
189
|
+
|
|
124
190
|
await this.cache.putRecord({
|
|
125
|
-
key: this.createCacheKey(
|
|
126
|
-
value:
|
|
191
|
+
key: this.createCacheKey(updatedBillingPortalDto.id),
|
|
192
|
+
value: updatedBillingPortalDto,
|
|
127
193
|
ttlMilliseconds: this.cache.getTtlMilliseconds()
|
|
128
194
|
});
|
|
129
195
|
|
|
130
|
-
return
|
|
131
|
-
billingPortalSession
|
|
132
|
-
);
|
|
196
|
+
return updatedBillingPortalDto;
|
|
133
197
|
}
|
|
134
198
|
|
|
135
199
|
async expireBillingPortalSession(idDto: IdDto): Promise<void> {
|
|
200
|
+
if (this.evaluatedTelemetryOptions.logging) {
|
|
201
|
+
this.openTelemetryCollector.info(
|
|
202
|
+
'Expiring billing portal session',
|
|
203
|
+
idDto
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
136
207
|
const sessionExists = await this.cache.readRecord(
|
|
137
208
|
this.createCacheKey(idDto.id)
|
|
138
209
|
);
|
|
210
|
+
|
|
139
211
|
if (!sessionExists) {
|
|
140
212
|
throw new Error('Session not found');
|
|
141
213
|
}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { IdDto, InstanceTypeRecord } from '@forklaunch/common';
|
|
2
2
|
import { createCacheKey, TtlCache } from '@forklaunch/core/cache';
|
|
3
|
+
import {
|
|
4
|
+
evaluateTelemetryOptions,
|
|
5
|
+
MetricsDefinition,
|
|
6
|
+
OpenTelemetryCollector,
|
|
7
|
+
TelemetryOptions
|
|
8
|
+
} from '@forklaunch/core/http';
|
|
3
9
|
import {
|
|
4
10
|
InternalDtoMapper,
|
|
5
11
|
RequestDtoMapperConstructor,
|
|
6
12
|
ResponseDtoMapperConstructor,
|
|
7
13
|
transformIntoInternalDtoMapper
|
|
8
14
|
} from '@forklaunch/core/mappers';
|
|
9
|
-
import {
|
|
10
|
-
MetricsDefinition,
|
|
11
|
-
OpenTelemetryCollector
|
|
12
|
-
} from '@forklaunch/core/http';
|
|
13
15
|
import { CheckoutSessionService } from '@forklaunch/interfaces-billing/interfaces';
|
|
14
16
|
import {
|
|
15
17
|
CheckoutSessionDto,
|
|
@@ -17,42 +19,75 @@ import {
|
|
|
17
19
|
UpdateCheckoutSessionDto
|
|
18
20
|
} from '@forklaunch/interfaces-billing/types';
|
|
19
21
|
import { AnySchemaValidator } from '@forklaunch/validator';
|
|
22
|
+
import { EntityManager } from '@mikro-orm/core';
|
|
20
23
|
|
|
21
24
|
export class BaseCheckoutSessionService<
|
|
22
25
|
SchemaValidator extends AnySchemaValidator,
|
|
23
26
|
PaymentMethodEnum,
|
|
27
|
+
StatusEnum,
|
|
24
28
|
Metrics extends MetricsDefinition = MetricsDefinition,
|
|
25
29
|
Dto extends {
|
|
26
|
-
CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum>;
|
|
27
|
-
CreateCheckoutSessionDtoMapper: CreateCheckoutSessionDto<
|
|
28
|
-
|
|
30
|
+
CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum, StatusEnum>;
|
|
31
|
+
CreateCheckoutSessionDtoMapper: CreateCheckoutSessionDto<
|
|
32
|
+
PaymentMethodEnum,
|
|
33
|
+
StatusEnum
|
|
34
|
+
>;
|
|
35
|
+
UpdateCheckoutSessionDtoMapper: UpdateCheckoutSessionDto<
|
|
36
|
+
PaymentMethodEnum,
|
|
37
|
+
StatusEnum
|
|
38
|
+
>;
|
|
29
39
|
} = {
|
|
30
|
-
CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum>;
|
|
31
|
-
CreateCheckoutSessionDtoMapper: CreateCheckoutSessionDto<
|
|
32
|
-
|
|
40
|
+
CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum, StatusEnum>;
|
|
41
|
+
CreateCheckoutSessionDtoMapper: CreateCheckoutSessionDto<
|
|
42
|
+
PaymentMethodEnum,
|
|
43
|
+
StatusEnum
|
|
44
|
+
>;
|
|
45
|
+
UpdateCheckoutSessionDtoMapper: UpdateCheckoutSessionDto<
|
|
46
|
+
PaymentMethodEnum,
|
|
47
|
+
StatusEnum
|
|
48
|
+
>;
|
|
33
49
|
},
|
|
34
50
|
Entities extends {
|
|
35
|
-
CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum>;
|
|
36
|
-
CreateCheckoutSessionDtoMapper: CheckoutSessionDto<
|
|
37
|
-
|
|
51
|
+
CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum, StatusEnum>;
|
|
52
|
+
CreateCheckoutSessionDtoMapper: CheckoutSessionDto<
|
|
53
|
+
PaymentMethodEnum,
|
|
54
|
+
StatusEnum
|
|
55
|
+
>;
|
|
56
|
+
UpdateCheckoutSessionDtoMapper: CheckoutSessionDto<
|
|
57
|
+
PaymentMethodEnum,
|
|
58
|
+
StatusEnum
|
|
59
|
+
>;
|
|
38
60
|
} = {
|
|
39
|
-
CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum>;
|
|
40
|
-
CreateCheckoutSessionDtoMapper: CheckoutSessionDto<
|
|
41
|
-
|
|
61
|
+
CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum, StatusEnum>;
|
|
62
|
+
CreateCheckoutSessionDtoMapper: CheckoutSessionDto<
|
|
63
|
+
PaymentMethodEnum,
|
|
64
|
+
StatusEnum
|
|
65
|
+
>;
|
|
66
|
+
UpdateCheckoutSessionDtoMapper: CheckoutSessionDto<
|
|
67
|
+
PaymentMethodEnum,
|
|
68
|
+
StatusEnum
|
|
69
|
+
>;
|
|
42
70
|
}
|
|
43
|
-
> implements CheckoutSessionService<PaymentMethodEnum>
|
|
71
|
+
> implements CheckoutSessionService<PaymentMethodEnum, StatusEnum>
|
|
44
72
|
{
|
|
45
|
-
#
|
|
46
|
-
InstanceTypeRecord<typeof this.
|
|
73
|
+
#mappers: InternalDtoMapper<
|
|
74
|
+
InstanceTypeRecord<typeof this.mappers>,
|
|
47
75
|
Entities,
|
|
48
76
|
Dto
|
|
49
77
|
>;
|
|
78
|
+
private evaluatedTelemetryOptions: {
|
|
79
|
+
logging?: boolean;
|
|
80
|
+
metrics?: boolean;
|
|
81
|
+
tracing?: boolean;
|
|
82
|
+
};
|
|
83
|
+
private enableDatabaseBackup: boolean;
|
|
50
84
|
|
|
51
85
|
constructor(
|
|
86
|
+
protected readonly em: EntityManager,
|
|
52
87
|
protected readonly cache: TtlCache,
|
|
53
88
|
protected readonly openTelemetryCollector: OpenTelemetryCollector<Metrics>,
|
|
54
89
|
protected readonly schemaValidator: SchemaValidator,
|
|
55
|
-
protected readonly
|
|
90
|
+
protected readonly mappers: {
|
|
56
91
|
CheckoutSessionDtoMapper: ResponseDtoMapperConstructor<
|
|
57
92
|
SchemaValidator,
|
|
58
93
|
Dto['CheckoutSessionDtoMapper'],
|
|
@@ -68,9 +103,21 @@ export class BaseCheckoutSessionService<
|
|
|
68
103
|
Dto['UpdateCheckoutSessionDtoMapper'],
|
|
69
104
|
Entities['UpdateCheckoutSessionDtoMapper']
|
|
70
105
|
>;
|
|
106
|
+
},
|
|
107
|
+
readonly options?: {
|
|
108
|
+
enableDatabaseBackup?: boolean;
|
|
109
|
+
telemetry?: TelemetryOptions;
|
|
71
110
|
}
|
|
72
111
|
) {
|
|
73
|
-
this.#
|
|
112
|
+
this.#mappers = transformIntoInternalDtoMapper(mappers, schemaValidator);
|
|
113
|
+
this.enableDatabaseBackup = options?.enableDatabaseBackup ?? false;
|
|
114
|
+
this.evaluatedTelemetryOptions = options?.telemetry
|
|
115
|
+
? evaluateTelemetryOptions(options.telemetry).enabled
|
|
116
|
+
: {
|
|
117
|
+
logging: false,
|
|
118
|
+
metrics: false,
|
|
119
|
+
tracing: false
|
|
120
|
+
};
|
|
74
121
|
}
|
|
75
122
|
|
|
76
123
|
protected createCacheKey = createCacheKey('checkout_session');
|
|
@@ -78,21 +125,35 @@ export class BaseCheckoutSessionService<
|
|
|
78
125
|
async createCheckoutSession(
|
|
79
126
|
checkoutSessionDto: Dto['CreateCheckoutSessionDtoMapper']
|
|
80
127
|
): Promise<Dto['CheckoutSessionDtoMapper']> {
|
|
81
|
-
|
|
82
|
-
this
|
|
128
|
+
if (this.evaluatedTelemetryOptions.logging) {
|
|
129
|
+
this.openTelemetryCollector.info(
|
|
130
|
+
'Creating checkout session',
|
|
83
131
|
checkoutSessionDto
|
|
84
132
|
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const checkoutSession =
|
|
136
|
+
await this.#mappers.CreateCheckoutSessionDtoMapper.deserializeDtoToEntity(
|
|
137
|
+
checkoutSessionDto,
|
|
138
|
+
this.em
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const createdCheckoutSessionDto =
|
|
142
|
+
await this.#mappers.CheckoutSessionDtoMapper.serializeEntityToDto(
|
|
143
|
+
checkoutSession
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
if (this.enableDatabaseBackup) {
|
|
147
|
+
await this.em.persistAndFlush(checkoutSession);
|
|
148
|
+
}
|
|
85
149
|
|
|
86
|
-
// Store the checkoutSession details in the cache
|
|
87
150
|
await this.cache.putRecord({
|
|
88
|
-
key: this.createCacheKey(
|
|
89
|
-
value:
|
|
151
|
+
key: this.createCacheKey(createdCheckoutSessionDto.id),
|
|
152
|
+
value: createdCheckoutSessionDto,
|
|
90
153
|
ttlMilliseconds: this.cache.getTtlMilliseconds()
|
|
91
154
|
});
|
|
92
155
|
|
|
93
|
-
return
|
|
94
|
-
checkoutSession
|
|
95
|
-
);
|
|
156
|
+
return createdCheckoutSessionDto;
|
|
96
157
|
}
|
|
97
158
|
|
|
98
159
|
async getCheckoutSession({
|
|
@@ -105,7 +166,7 @@ export class BaseCheckoutSessionService<
|
|
|
105
166
|
throw new Error('Session not found');
|
|
106
167
|
}
|
|
107
168
|
|
|
108
|
-
return this.#
|
|
169
|
+
return this.#mappers.CheckoutSessionDtoMapper.serializeEntityToDto(
|
|
109
170
|
checkoutSessionDetails.value
|
|
110
171
|
);
|
|
111
172
|
}
|
|
@@ -121,12 +182,34 @@ export class BaseCheckoutSessionService<
|
|
|
121
182
|
}
|
|
122
183
|
|
|
123
184
|
async handleCheckoutSuccess({ id }: IdDto): Promise<void> {
|
|
124
|
-
this.
|
|
185
|
+
if (this.evaluatedTelemetryOptions.logging) {
|
|
186
|
+
this.openTelemetryCollector.info('Checkout success', { id });
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (this.enableDatabaseBackup) {
|
|
190
|
+
const checkoutSession = await this.em.upsert('CheckoutSession', {
|
|
191
|
+
id,
|
|
192
|
+
status: 'SUCCESS'
|
|
193
|
+
});
|
|
194
|
+
await this.em.persistAndFlush(checkoutSession);
|
|
195
|
+
}
|
|
196
|
+
|
|
125
197
|
await this.cache.deleteRecord(this.createCacheKey(id));
|
|
126
198
|
}
|
|
127
199
|
|
|
128
200
|
async handleCheckoutFailure({ id }: IdDto): Promise<void> {
|
|
129
|
-
this.
|
|
201
|
+
if (this.evaluatedTelemetryOptions.logging) {
|
|
202
|
+
this.openTelemetryCollector.info('Checkout failure', { id });
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (this.enableDatabaseBackup) {
|
|
206
|
+
const checkoutSession = await this.em.upsert('CheckoutSession', {
|
|
207
|
+
id,
|
|
208
|
+
status: 'FAILED'
|
|
209
|
+
});
|
|
210
|
+
await this.em.persistAndFlush(checkoutSession);
|
|
211
|
+
}
|
|
212
|
+
|
|
130
213
|
await this.cache.deleteRecord(this.createCacheKey(id));
|
|
131
214
|
}
|
|
132
215
|
}
|