@forklaunch/implementation-billing-stripe 0.0.1 → 0.0.3
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/domain/enum/index.d.mts +194 -0
- package/lib/domain/enum/index.d.ts +194 -0
- package/lib/domain/enum/index.js +236 -0
- package/lib/domain/enum/index.mjs +201 -0
- package/lib/domain/schemas/index.d.mts +4142 -0
- package/lib/domain/schemas/index.d.ts +4142 -0
- package/lib/{schemas → domain/schemas}/index.js +351 -275
- package/lib/{schemas → domain/schemas}/index.mjs +224 -223
- package/lib/domain/types/index.d.mts +280 -0
- package/lib/domain/types/index.d.ts +280 -0
- package/lib/{types → domain/types}/index.js +9 -5
- package/lib/eject/domain/enum/billingProvider.enum.ts +3 -0
- package/lib/eject/domain/enum/currency.enum.ts +137 -0
- package/lib/eject/domain/enum/index.ts +4 -0
- package/lib/eject/domain/enum/paymentMethod.enum.ts +39 -0
- package/lib/eject/domain/enum/planCadence.enum.ts +5 -0
- package/lib/eject/domain/schemas/checkoutSession.schema.ts +2 -2
- package/lib/eject/domain/schemas/paymentLink.schema.ts +2 -2
- package/lib/eject/domain/schemas/plan.schema.ts +3 -3
- package/lib/eject/domain/schemas/subscription.schema.ts +1 -1
- package/lib/eject/{types → domain/types}/stripe.dto.types.ts +4 -4
- package/lib/eject/{types → domain/types}/stripe.entity.types.ts +4 -4
- package/lib/eject/services/billingPortal.service.ts +2 -2
- package/lib/eject/services/checkoutSession.service.ts +4 -4
- package/lib/eject/services/paymentLink.service.ts +4 -4
- package/lib/eject/services/plan.service.ts +5 -5
- package/lib/eject/services/subscription.service.ts +3 -3
- package/lib/eject/services/webhook.service.ts +5 -5
- package/lib/services/index.d.mts +709 -194
- package/lib/services/index.d.ts +709 -194
- package/lib/services/index.js +359 -244
- package/lib/services/index.mjs +298 -205
- package/package.json +16 -16
- package/lib/domain/index.d.mts +0 -189
- package/lib/domain/index.d.ts +0 -189
- package/lib/domain/index.js +0 -231
- package/lib/domain/index.mjs +0 -201
- package/lib/schemas/index.d.mts +0 -376
- package/lib/schemas/index.d.ts +0 -376
- package/lib/types/index.d.mts +0 -121
- package/lib/types/index.d.ts +0 -121
- /package/lib/{types → domain/types}/index.mjs +0 -0
- /package/lib/eject/{types → domain/types}/index.ts +0 -0
package/lib/services/index.mjs
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
// services/billingPortal.service.ts
|
|
2
|
-
import { BaseBillingPortalService } from
|
|
2
|
+
import { BaseBillingPortalService } from '@forklaunch/implementation-billing-base/services';
|
|
3
3
|
import {
|
|
4
4
|
IdentityRequestMapper,
|
|
5
5
|
IdentityResponseMapper,
|
|
6
6
|
transformIntoInternalMapper
|
|
7
|
-
} from
|
|
7
|
+
} from '@forklaunch/internal';
|
|
8
8
|
var StripeBillingPortalService = class {
|
|
9
|
-
constructor(
|
|
9
|
+
constructor(
|
|
10
|
+
stripeClient,
|
|
11
|
+
em,
|
|
12
|
+
cache,
|
|
13
|
+
openTelemetryCollector,
|
|
14
|
+
schemaValidator,
|
|
15
|
+
mappers,
|
|
16
|
+
options
|
|
17
|
+
) {
|
|
10
18
|
this.stripeClient = stripeClient;
|
|
11
19
|
this.em = em;
|
|
12
20
|
this.cache = cache;
|
|
@@ -36,26 +44,28 @@ var StripeBillingPortalService = class {
|
|
|
36
44
|
...billingPortalDto.stripeFields,
|
|
37
45
|
customer: billingPortalDto.customerId
|
|
38
46
|
});
|
|
39
|
-
const billingPortalEntity =
|
|
40
|
-
await this.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
Date
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
const billingPortalEntity =
|
|
48
|
+
await this.baseBillingPortalService.createBillingPortalSession(
|
|
49
|
+
await this._mappers.CreateBillingPortalMapper.deserializeDtoToEntity(
|
|
50
|
+
{
|
|
51
|
+
...billingPortalDto,
|
|
52
|
+
id: session.id,
|
|
53
|
+
uri: session.url,
|
|
54
|
+
expiresAt: new Date(
|
|
55
|
+
Date.now() + this.billingPortalSessionExpiryDurationMs
|
|
56
|
+
)
|
|
57
|
+
},
|
|
58
|
+
this.em,
|
|
59
|
+
session
|
|
60
|
+
)
|
|
61
|
+
);
|
|
53
62
|
return this._mappers.BillingPortalMapper.serializeEntityToDto(
|
|
54
63
|
billingPortalEntity
|
|
55
64
|
);
|
|
56
65
|
}
|
|
57
66
|
async getBillingPortalSession(idDto) {
|
|
58
|
-
const billingPortalEntity =
|
|
67
|
+
const billingPortalEntity =
|
|
68
|
+
await this.baseBillingPortalService.getBillingPortalSession(idDto);
|
|
59
69
|
return this._mappers.BillingPortalMapper.serializeEntityToDto(
|
|
60
70
|
billingPortalEntity
|
|
61
71
|
);
|
|
@@ -64,27 +74,29 @@ var StripeBillingPortalService = class {
|
|
|
64
74
|
return this.baseBillingPortalService.expireBillingPortalSession(idDto);
|
|
65
75
|
}
|
|
66
76
|
async updateBillingPortalSession(billingPortalDto) {
|
|
67
|
-
const existingSession =
|
|
68
|
-
|
|
69
|
-
|
|
77
|
+
const existingSession =
|
|
78
|
+
await this.baseBillingPortalService.getBillingPortalSession({
|
|
79
|
+
id: billingPortalDto.id
|
|
80
|
+
});
|
|
70
81
|
const session = await this.stripeClient.billingPortal.sessions.create({
|
|
71
82
|
...billingPortalDto.stripeFields,
|
|
72
83
|
customer: existingSession.customerId
|
|
73
84
|
});
|
|
74
|
-
const baseBillingPortalDto =
|
|
75
|
-
await this.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
Date
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
const baseBillingPortalDto =
|
|
86
|
+
await this.baseBillingPortalService.updateBillingPortalSession(
|
|
87
|
+
await this._mappers.UpdateBillingPortalMapper.deserializeDtoToEntity(
|
|
88
|
+
{
|
|
89
|
+
...billingPortalDto,
|
|
90
|
+
id: session.id,
|
|
91
|
+
uri: session.url,
|
|
92
|
+
expiresAt: new Date(
|
|
93
|
+
Date.now() + this.billingPortalSessionExpiryDurationMs
|
|
94
|
+
)
|
|
95
|
+
},
|
|
96
|
+
this.em,
|
|
97
|
+
session
|
|
98
|
+
)
|
|
99
|
+
);
|
|
88
100
|
return this._mappers.BillingPortalMapper.serializeEntityToDto(
|
|
89
101
|
baseBillingPortalDto
|
|
90
102
|
);
|
|
@@ -92,14 +104,22 @@ var StripeBillingPortalService = class {
|
|
|
92
104
|
};
|
|
93
105
|
|
|
94
106
|
// services/checkoutSession.service.ts
|
|
95
|
-
import { BaseCheckoutSessionService } from
|
|
107
|
+
import { BaseCheckoutSessionService } from '@forklaunch/implementation-billing-base/services';
|
|
96
108
|
import {
|
|
97
109
|
IdentityRequestMapper as IdentityRequestMapper2,
|
|
98
110
|
IdentityResponseMapper as IdentityResponseMapper2,
|
|
99
111
|
transformIntoInternalMapper as transformIntoInternalMapper2
|
|
100
|
-
} from
|
|
112
|
+
} from '@forklaunch/internal';
|
|
101
113
|
var StripeCheckoutSessionService = class {
|
|
102
|
-
constructor(
|
|
114
|
+
constructor(
|
|
115
|
+
stripeClient,
|
|
116
|
+
em,
|
|
117
|
+
cache,
|
|
118
|
+
openTelemetryCollector,
|
|
119
|
+
schemaValidator,
|
|
120
|
+
mappers,
|
|
121
|
+
options
|
|
122
|
+
) {
|
|
103
123
|
this.stripeClient = stripeClient;
|
|
104
124
|
this.em = em;
|
|
105
125
|
this.cache = cache;
|
|
@@ -131,27 +151,27 @@ var StripeCheckoutSessionService = class {
|
|
|
131
151
|
success_url: checkoutSessionDto.successRedirectUri,
|
|
132
152
|
cancel_url: checkoutSessionDto.cancelRedirectUri
|
|
133
153
|
});
|
|
134
|
-
const checkoutSessionEntity =
|
|
135
|
-
await this.
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
154
|
+
const checkoutSessionEntity =
|
|
155
|
+
await this.baseCheckoutSessionService.createCheckoutSession(
|
|
156
|
+
await this._mappers.CreateCheckoutSessionMapper.deserializeDtoToEntity(
|
|
157
|
+
{
|
|
158
|
+
...checkoutSessionDto,
|
|
159
|
+
id: session.id,
|
|
160
|
+
uri: session.url,
|
|
161
|
+
expiresAt: new Date(Date.now() + 5 * 60 * 1e3),
|
|
162
|
+
providerFields: session
|
|
163
|
+
},
|
|
164
|
+
this.em,
|
|
165
|
+
session
|
|
166
|
+
)
|
|
167
|
+
);
|
|
147
168
|
return this._mappers.CheckoutSessionMapper.serializeEntityToDto(
|
|
148
169
|
checkoutSessionEntity
|
|
149
170
|
);
|
|
150
171
|
}
|
|
151
|
-
async getCheckoutSession({
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const databaseCheckoutSession = await this.baseCheckoutSessionService.getCheckoutSession({ id });
|
|
172
|
+
async getCheckoutSession({ id }) {
|
|
173
|
+
const databaseCheckoutSession =
|
|
174
|
+
await this.baseCheckoutSessionService.getCheckoutSession({ id });
|
|
155
175
|
return {
|
|
156
176
|
...this._mappers.CheckoutSessionMapper.serializeEntityToDto(
|
|
157
177
|
databaseCheckoutSession
|
|
@@ -166,7 +186,7 @@ var StripeCheckoutSessionService = class {
|
|
|
166
186
|
async handleCheckoutSuccess({ id }) {
|
|
167
187
|
await this.stripeClient.checkout.sessions.update(id, {
|
|
168
188
|
metadata: {
|
|
169
|
-
status:
|
|
189
|
+
status: 'SUCCESS'
|
|
170
190
|
}
|
|
171
191
|
});
|
|
172
192
|
await this.baseCheckoutSessionService.handleCheckoutSuccess({ id });
|
|
@@ -174,7 +194,7 @@ var StripeCheckoutSessionService = class {
|
|
|
174
194
|
async handleCheckoutFailure({ id }) {
|
|
175
195
|
await this.stripeClient.checkout.sessions.update(id, {
|
|
176
196
|
metadata: {
|
|
177
|
-
status:
|
|
197
|
+
status: 'FAILED'
|
|
178
198
|
}
|
|
179
199
|
});
|
|
180
200
|
await this.baseCheckoutSessionService.handleCheckoutFailure({ id });
|
|
@@ -182,14 +202,22 @@ var StripeCheckoutSessionService = class {
|
|
|
182
202
|
};
|
|
183
203
|
|
|
184
204
|
// services/paymentLink.service.ts
|
|
185
|
-
import { BasePaymentLinkService } from
|
|
205
|
+
import { BasePaymentLinkService } from '@forklaunch/implementation-billing-base/services';
|
|
186
206
|
import {
|
|
187
207
|
IdentityRequestMapper as IdentityRequestMapper3,
|
|
188
208
|
IdentityResponseMapper as IdentityResponseMapper3,
|
|
189
209
|
transformIntoInternalMapper as transformIntoInternalMapper3
|
|
190
|
-
} from
|
|
210
|
+
} from '@forklaunch/internal';
|
|
191
211
|
var StripePaymentLinkService = class {
|
|
192
|
-
constructor(
|
|
212
|
+
constructor(
|
|
213
|
+
stripeClient,
|
|
214
|
+
em,
|
|
215
|
+
cache,
|
|
216
|
+
openTelemetryCollector,
|
|
217
|
+
schemaValidator,
|
|
218
|
+
mappers,
|
|
219
|
+
options
|
|
220
|
+
) {
|
|
193
221
|
this.stripeClient = stripeClient;
|
|
194
222
|
this.em = em;
|
|
195
223
|
this.cache = cache;
|
|
@@ -219,20 +247,22 @@ var StripePaymentLinkService = class {
|
|
|
219
247
|
payment_method_types: paymentLinkDto.paymentMethods,
|
|
220
248
|
currency: paymentLinkDto.currency
|
|
221
249
|
});
|
|
222
|
-
const paymentLinkEntity =
|
|
223
|
-
await this.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
250
|
+
const paymentLinkEntity =
|
|
251
|
+
await this.basePaymentLinkService.createPaymentLink(
|
|
252
|
+
await this._mappers.CreatePaymentLinkMapper.deserializeDtoToEntity(
|
|
253
|
+
{
|
|
254
|
+
...paymentLinkDto,
|
|
255
|
+
id: session.id,
|
|
256
|
+
amount:
|
|
257
|
+
session.line_items?.data.reduce(
|
|
258
|
+
(total, item) => total + item.amount_total,
|
|
259
|
+
0
|
|
260
|
+
) ?? 0
|
|
261
|
+
},
|
|
262
|
+
this.em,
|
|
263
|
+
session
|
|
264
|
+
)
|
|
265
|
+
);
|
|
236
266
|
return this._mappers.PaymentLinkMapper.serializeEntityToDto(
|
|
237
267
|
paymentLinkEntity
|
|
238
268
|
);
|
|
@@ -245,26 +275,29 @@ var StripePaymentLinkService = class {
|
|
|
245
275
|
payment_method_types: paymentLinkDto.paymentMethods
|
|
246
276
|
}
|
|
247
277
|
);
|
|
248
|
-
const paymentLinkEntity =
|
|
249
|
-
await this.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
278
|
+
const paymentLinkEntity =
|
|
279
|
+
await this.basePaymentLinkService.updatePaymentLink(
|
|
280
|
+
await this._mappers.UpdatePaymentLinkMapper.deserializeDtoToEntity(
|
|
281
|
+
{
|
|
282
|
+
...paymentLinkDto,
|
|
283
|
+
id: session.id,
|
|
284
|
+
amount:
|
|
285
|
+
session.line_items?.data.reduce(
|
|
286
|
+
(total, item) => total + item.amount_total,
|
|
287
|
+
0
|
|
288
|
+
) ?? 0
|
|
289
|
+
},
|
|
290
|
+
this.em,
|
|
291
|
+
session
|
|
292
|
+
)
|
|
293
|
+
);
|
|
262
294
|
return this._mappers.PaymentLinkMapper.serializeEntityToDto(
|
|
263
295
|
paymentLinkEntity
|
|
264
296
|
);
|
|
265
297
|
}
|
|
266
298
|
async getPaymentLink({ id }) {
|
|
267
|
-
const databasePaymentLink =
|
|
299
|
+
const databasePaymentLink =
|
|
300
|
+
await this.basePaymentLinkService.getPaymentLink({ id });
|
|
268
301
|
return {
|
|
269
302
|
...this._mappers.PaymentLinkMapper.serializeEntityToDto(
|
|
270
303
|
databasePaymentLink
|
|
@@ -275,7 +308,7 @@ var StripePaymentLinkService = class {
|
|
|
275
308
|
async expirePaymentLink({ id }) {
|
|
276
309
|
await this.stripeClient.paymentLinks.update(id, {
|
|
277
310
|
metadata: {
|
|
278
|
-
status:
|
|
311
|
+
status: 'EXPIRED'
|
|
279
312
|
}
|
|
280
313
|
});
|
|
281
314
|
await this.basePaymentLinkService.expirePaymentLink({ id });
|
|
@@ -283,7 +316,7 @@ var StripePaymentLinkService = class {
|
|
|
283
316
|
async handlePaymentSuccess({ id }) {
|
|
284
317
|
await this.stripeClient.paymentLinks.update(id, {
|
|
285
318
|
metadata: {
|
|
286
|
-
status:
|
|
319
|
+
status: 'COMPLETED'
|
|
287
320
|
}
|
|
288
321
|
});
|
|
289
322
|
await this.basePaymentLinkService.handlePaymentSuccess({ id });
|
|
@@ -291,7 +324,7 @@ var StripePaymentLinkService = class {
|
|
|
291
324
|
async handlePaymentFailure({ id }) {
|
|
292
325
|
await this.stripeClient.paymentLinks.update(id, {
|
|
293
326
|
metadata: {
|
|
294
|
-
status:
|
|
327
|
+
status: 'FAILED'
|
|
295
328
|
}
|
|
296
329
|
});
|
|
297
330
|
await this.basePaymentLinkService.handlePaymentFailure({ id });
|
|
@@ -303,9 +336,9 @@ var StripePaymentLinkService = class {
|
|
|
303
336
|
return await Promise.all(
|
|
304
337
|
(await this.basePaymentLinkService.listPaymentLinks(idsDto)).map(
|
|
305
338
|
async (paymentLink) => ({
|
|
306
|
-
...await this._mappers.PaymentLinkMapper.serializeEntityToDto(
|
|
339
|
+
...(await this._mappers.PaymentLinkMapper.serializeEntityToDto(
|
|
307
340
|
paymentLink
|
|
308
|
-
),
|
|
341
|
+
)),
|
|
309
342
|
stripeFields: paymentLinks.data.find(
|
|
310
343
|
(paymentLink2) => paymentLink2.id === paymentLink2.id
|
|
311
344
|
)
|
|
@@ -316,14 +349,21 @@ var StripePaymentLinkService = class {
|
|
|
316
349
|
};
|
|
317
350
|
|
|
318
351
|
// services/plan.service.ts
|
|
319
|
-
import { BasePlanService } from
|
|
352
|
+
import { BasePlanService } from '@forklaunch/implementation-billing-base/services';
|
|
320
353
|
import {
|
|
321
354
|
IdentityRequestMapper as IdentityRequestMapper4,
|
|
322
355
|
IdentityResponseMapper as IdentityResponseMapper4,
|
|
323
356
|
transformIntoInternalMapper as transformIntoInternalMapper4
|
|
324
|
-
} from
|
|
357
|
+
} from '@forklaunch/internal';
|
|
325
358
|
var StripePlanService = class {
|
|
326
|
-
constructor(
|
|
359
|
+
constructor(
|
|
360
|
+
stripeClient,
|
|
361
|
+
em,
|
|
362
|
+
openTelemetryCollector,
|
|
363
|
+
schemaValidator,
|
|
364
|
+
mappers,
|
|
365
|
+
options
|
|
366
|
+
) {
|
|
327
367
|
this.stripeClient = stripeClient;
|
|
328
368
|
this.em = em;
|
|
329
369
|
this.openTelemetryCollector = openTelemetryCollector;
|
|
@@ -357,7 +397,7 @@ var StripePlanService = class {
|
|
|
357
397
|
{
|
|
358
398
|
...planDto,
|
|
359
399
|
externalId: plan.id,
|
|
360
|
-
billingProvider:
|
|
400
|
+
billingProvider: 'stripe'
|
|
361
401
|
},
|
|
362
402
|
em ?? this.em,
|
|
363
403
|
plan
|
|
@@ -368,24 +408,25 @@ var StripePlanService = class {
|
|
|
368
408
|
}
|
|
369
409
|
async getPlan(idDto, em) {
|
|
370
410
|
const plan = await this.stripeClient.plans.retrieve(idDto.id);
|
|
371
|
-
const id = (
|
|
372
|
-
this.options?.databaseTableName ??
|
|
373
|
-
|
|
374
|
-
|
|
411
|
+
const id = (
|
|
412
|
+
await em?.findOne(this.options?.databaseTableName ?? 'plan', {
|
|
413
|
+
externalId: idDto.id
|
|
414
|
+
})
|
|
415
|
+
)?.id;
|
|
375
416
|
if (!id) {
|
|
376
|
-
throw new Error(
|
|
417
|
+
throw new Error('Plan not found');
|
|
377
418
|
}
|
|
378
419
|
return {
|
|
379
|
-
...await this._mappers.PlanMapper.serializeEntityToDto(
|
|
420
|
+
...(await this._mappers.PlanMapper.serializeEntityToDto(
|
|
380
421
|
await this.basePlanService.getPlan({ id }, em)
|
|
381
|
-
),
|
|
422
|
+
)),
|
|
382
423
|
stripeFields: plan
|
|
383
424
|
};
|
|
384
425
|
}
|
|
385
426
|
async updatePlan(planDto, em) {
|
|
386
427
|
const existingPlan = await this.stripeClient.plans.retrieve(planDto.id);
|
|
387
|
-
const plan = await this.stripeClient.plans.del(planDto.id).then(
|
|
388
|
-
|
|
428
|
+
const plan = await this.stripeClient.plans.del(planDto.id).then(() =>
|
|
429
|
+
this.stripeClient.plans.create({
|
|
389
430
|
...planDto.stripeFields,
|
|
390
431
|
interval: planDto.cadence ?? existingPlan.interval,
|
|
391
432
|
product: planDto.name,
|
|
@@ -397,7 +438,7 @@ var StripePlanService = class {
|
|
|
397
438
|
{
|
|
398
439
|
...planDto,
|
|
399
440
|
externalId: plan.id,
|
|
400
|
-
billingProvider:
|
|
441
|
+
billingProvider: 'stripe'
|
|
401
442
|
},
|
|
402
443
|
em ?? this.em,
|
|
403
444
|
plan
|
|
@@ -414,16 +455,19 @@ var StripePlanService = class {
|
|
|
414
455
|
const plans = await this.stripeClient.plans.list({
|
|
415
456
|
active: true
|
|
416
457
|
});
|
|
417
|
-
const ids = (
|
|
418
|
-
this.options?.databaseTableName ??
|
|
419
|
-
|
|
420
|
-
|
|
458
|
+
const ids = (
|
|
459
|
+
await em?.findAll(this.options?.databaseTableName ?? 'plan', {
|
|
460
|
+
where: { externalId: { $in: plans.data.map((plan) => plan.id) } }
|
|
461
|
+
})
|
|
462
|
+
)
|
|
463
|
+
?.filter((s) => idsDto?.ids?.includes(s.id))
|
|
464
|
+
?.map((s) => s.id);
|
|
421
465
|
if (!ids) {
|
|
422
|
-
throw new Error(
|
|
466
|
+
throw new Error('Plans not found');
|
|
423
467
|
}
|
|
424
468
|
return await Promise.all(
|
|
425
469
|
(await this.basePlanService.listPlans({ ids }, em)).map(async (plan) => ({
|
|
426
|
-
...await this._mappers.PlanMapper.serializeEntityToDto(plan),
|
|
470
|
+
...(await this._mappers.PlanMapper.serializeEntityToDto(plan)),
|
|
427
471
|
stripeFields: plans.data.find(
|
|
428
472
|
(stripePlan) => stripePlan.id === plan.externalId
|
|
429
473
|
)
|
|
@@ -433,14 +477,21 @@ var StripePlanService = class {
|
|
|
433
477
|
};
|
|
434
478
|
|
|
435
479
|
// services/subscription.service.ts
|
|
436
|
-
import { BaseSubscriptionService } from
|
|
480
|
+
import { BaseSubscriptionService } from '@forklaunch/implementation-billing-base/services';
|
|
437
481
|
import {
|
|
438
482
|
IdentityRequestMapper as IdentityRequestMapper5,
|
|
439
483
|
IdentityResponseMapper as IdentityResponseMapper5,
|
|
440
484
|
transformIntoInternalMapper as transformIntoInternalMapper5
|
|
441
|
-
} from
|
|
485
|
+
} from '@forklaunch/internal';
|
|
442
486
|
var StripeSubscriptionService = class {
|
|
443
|
-
constructor(
|
|
487
|
+
constructor(
|
|
488
|
+
stripe,
|
|
489
|
+
em,
|
|
490
|
+
openTelemetryCollector,
|
|
491
|
+
schemaValidator,
|
|
492
|
+
mappers,
|
|
493
|
+
options
|
|
494
|
+
) {
|
|
444
495
|
this.stripe = stripe;
|
|
445
496
|
this.em = em;
|
|
446
497
|
this.openTelemetryCollector = openTelemetryCollector;
|
|
@@ -472,53 +523,55 @@ var StripeSubscriptionService = class {
|
|
|
472
523
|
}
|
|
473
524
|
]
|
|
474
525
|
});
|
|
475
|
-
const subscriptionEntity =
|
|
476
|
-
await this.
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
526
|
+
const subscriptionEntity =
|
|
527
|
+
await this.baseSubscriptionService.createSubscription(
|
|
528
|
+
await this._mappers.CreateSubscriptionMapper.deserializeDtoToEntity(
|
|
529
|
+
{
|
|
530
|
+
...subscriptionDto,
|
|
531
|
+
externalId: subscription.id,
|
|
532
|
+
billingProvider: 'stripe'
|
|
533
|
+
},
|
|
534
|
+
em ?? this.em,
|
|
535
|
+
subscription
|
|
536
|
+
),
|
|
537
|
+
em
|
|
538
|
+
);
|
|
487
539
|
return this._mappers.SubscriptionMapper.serializeEntityToDto(
|
|
488
540
|
subscriptionEntity
|
|
489
541
|
);
|
|
490
542
|
}
|
|
491
543
|
async getSubscription(idDto, em) {
|
|
492
544
|
return {
|
|
493
|
-
...await this._mappers.SubscriptionMapper.serializeEntityToDto(
|
|
545
|
+
...(await this._mappers.SubscriptionMapper.serializeEntityToDto(
|
|
494
546
|
await this.baseSubscriptionService.getSubscription(idDto, em)
|
|
495
|
-
),
|
|
547
|
+
)),
|
|
496
548
|
stripeFields: await this.stripe.subscriptions.retrieve(idDto.id)
|
|
497
549
|
};
|
|
498
550
|
}
|
|
499
551
|
async getUserSubscription(idDto, em) {
|
|
500
552
|
return {
|
|
501
|
-
...await this._mappers.SubscriptionMapper.serializeEntityToDto(
|
|
553
|
+
...(await this._mappers.SubscriptionMapper.serializeEntityToDto(
|
|
502
554
|
await this.baseSubscriptionService.getUserSubscription(idDto, em)
|
|
503
|
-
),
|
|
555
|
+
)),
|
|
504
556
|
stripeFields: await this.stripe.subscriptions.retrieve(idDto.id)
|
|
505
557
|
};
|
|
506
558
|
}
|
|
507
559
|
async getOrganizationSubscription(idDto, em) {
|
|
508
|
-
const id = (
|
|
509
|
-
this.options?.databaseTableName ??
|
|
510
|
-
|
|
511
|
-
|
|
560
|
+
const id = (
|
|
561
|
+
await em?.findOne(this.options?.databaseTableName ?? 'subscription', {
|
|
562
|
+
externalId: idDto.id
|
|
563
|
+
})
|
|
564
|
+
)?.id;
|
|
512
565
|
if (!id) {
|
|
513
|
-
throw new Error(
|
|
566
|
+
throw new Error('Subscription not found');
|
|
514
567
|
}
|
|
515
568
|
return {
|
|
516
|
-
...await this._mappers.SubscriptionMapper.serializeEntityToDto(
|
|
569
|
+
...(await this._mappers.SubscriptionMapper.serializeEntityToDto(
|
|
517
570
|
await this.baseSubscriptionService.getOrganizationSubscription(
|
|
518
571
|
{ id },
|
|
519
572
|
em
|
|
520
573
|
)
|
|
521
|
-
),
|
|
574
|
+
)),
|
|
522
575
|
stripeFields: await this.stripe.subscriptions.retrieve(idDto.id)
|
|
523
576
|
};
|
|
524
577
|
}
|
|
@@ -534,19 +587,20 @@ var StripeSubscriptionService = class {
|
|
|
534
587
|
]
|
|
535
588
|
}
|
|
536
589
|
);
|
|
537
|
-
const subscriptionEntity =
|
|
538
|
-
await this.
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
590
|
+
const subscriptionEntity =
|
|
591
|
+
await this.baseSubscriptionService.updateSubscription(
|
|
592
|
+
await this._mappers.UpdateSubscriptionMapper.deserializeDtoToEntity(
|
|
593
|
+
{
|
|
594
|
+
...subscriptionDto,
|
|
595
|
+
externalId: subscription.id,
|
|
596
|
+
billingProvider: 'stripe',
|
|
597
|
+
providerFields: subscription
|
|
598
|
+
},
|
|
599
|
+
em ?? this.em,
|
|
600
|
+
subscription
|
|
601
|
+
),
|
|
602
|
+
em
|
|
603
|
+
);
|
|
550
604
|
return this._mappers.SubscriptionMapper.serializeEntityToDto(
|
|
551
605
|
subscriptionEntity
|
|
552
606
|
);
|
|
@@ -556,23 +610,26 @@ var StripeSubscriptionService = class {
|
|
|
556
610
|
await this.baseSubscriptionService.deleteSubscription(idDto, em);
|
|
557
611
|
}
|
|
558
612
|
async listSubscriptions(idsDto, em) {
|
|
559
|
-
const subscriptions = (
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
613
|
+
const subscriptions = (
|
|
614
|
+
await this.stripe.subscriptions.list({
|
|
615
|
+
status: 'active'
|
|
616
|
+
})
|
|
617
|
+
).data.filter((s) => idsDto.ids?.includes(s.id));
|
|
618
|
+
const ids = (
|
|
619
|
+
await em?.findAll(this.options?.databaseTableName ?? 'subscription', {
|
|
620
|
+
where: { externalId: { $in: subscriptions.map((s) => s.id) } }
|
|
621
|
+
})
|
|
622
|
+
)?.map((s) => s.id);
|
|
566
623
|
if (!ids) {
|
|
567
|
-
throw new Error(
|
|
624
|
+
throw new Error('Subscriptions not found');
|
|
568
625
|
}
|
|
569
626
|
return await Promise.all(
|
|
570
627
|
(await this.baseSubscriptionService.listSubscriptions({ ids }, em)).map(
|
|
571
628
|
async (subscription) => {
|
|
572
629
|
return {
|
|
573
|
-
...await this._mappers.SubscriptionMapper.serializeEntityToDto(
|
|
630
|
+
...(await this._mappers.SubscriptionMapper.serializeEntityToDto(
|
|
574
631
|
subscription
|
|
575
|
-
),
|
|
632
|
+
)),
|
|
576
633
|
stripeFields: subscriptions.find(
|
|
577
634
|
(s) => s.id === subscription.externalId
|
|
578
635
|
)
|
|
@@ -593,7 +650,17 @@ var StripeSubscriptionService = class {
|
|
|
593
650
|
|
|
594
651
|
// services/webhook.service.ts
|
|
595
652
|
var StripeWebhookService = class {
|
|
596
|
-
constructor(
|
|
653
|
+
constructor(
|
|
654
|
+
stripeClient,
|
|
655
|
+
em,
|
|
656
|
+
schemaValidator,
|
|
657
|
+
openTelemetryCollector,
|
|
658
|
+
billingPortalService,
|
|
659
|
+
checkoutSessionService,
|
|
660
|
+
paymentLinkService,
|
|
661
|
+
planService,
|
|
662
|
+
subscriptionService
|
|
663
|
+
) {
|
|
597
664
|
this.stripeClient = stripeClient;
|
|
598
665
|
this.em = em;
|
|
599
666
|
this.schemaValidator = schemaValidator;
|
|
@@ -606,11 +673,11 @@ var StripeWebhookService = class {
|
|
|
606
673
|
}
|
|
607
674
|
async handleWebhookEvent(event) {
|
|
608
675
|
if (this.openTelemetryCollector) {
|
|
609
|
-
this.openTelemetryCollector.info(
|
|
676
|
+
this.openTelemetryCollector.info('Handling webhook event', event);
|
|
610
677
|
}
|
|
611
678
|
const eventType = event.type;
|
|
612
679
|
switch (eventType) {
|
|
613
|
-
case
|
|
680
|
+
case 'billing_portal.session.created': {
|
|
614
681
|
this.billingPortalService.baseBillingPortalService.createBillingPortalSession(
|
|
615
682
|
{
|
|
616
683
|
id: event.data.object.id,
|
|
@@ -622,136 +689,162 @@ var StripeWebhookService = class {
|
|
|
622
689
|
);
|
|
623
690
|
break;
|
|
624
691
|
}
|
|
625
|
-
case
|
|
692
|
+
case 'checkout.session.expired': {
|
|
626
693
|
this.checkoutSessionService.handleCheckoutFailure({
|
|
627
694
|
id: event.data.object.id
|
|
628
695
|
});
|
|
629
696
|
break;
|
|
630
697
|
}
|
|
631
|
-
case
|
|
698
|
+
case 'checkout.session.completed': {
|
|
632
699
|
this.checkoutSessionService.handleCheckoutSuccess({
|
|
633
700
|
id: event.data.object.id
|
|
634
701
|
});
|
|
635
702
|
break;
|
|
636
703
|
}
|
|
637
|
-
case
|
|
704
|
+
case 'payment_link.created':
|
|
638
705
|
{
|
|
639
706
|
this.paymentLinkService.basePaymentLinkService.createPaymentLink({
|
|
640
707
|
id: event.data.object.id,
|
|
641
|
-
amount:
|
|
642
|
-
(
|
|
643
|
-
|
|
644
|
-
|
|
708
|
+
amount:
|
|
709
|
+
event.data.object.line_items?.data.reduce(
|
|
710
|
+
(total, item) => total + item.amount_total,
|
|
711
|
+
0
|
|
712
|
+
) ?? 0,
|
|
645
713
|
paymentMethods: event.data.object.payment_method_types,
|
|
646
|
-
status:
|
|
714
|
+
status: 'CREATED',
|
|
647
715
|
currency: event.data.object.currency,
|
|
648
716
|
providerFields: event.data.object
|
|
649
717
|
});
|
|
650
718
|
}
|
|
651
719
|
break;
|
|
652
|
-
case
|
|
720
|
+
case 'payment_link.updated': {
|
|
653
721
|
this.paymentLinkService.basePaymentLinkService.updatePaymentLink({
|
|
654
722
|
id: event.data.object.id,
|
|
655
|
-
amount:
|
|
656
|
-
(
|
|
657
|
-
|
|
658
|
-
|
|
723
|
+
amount:
|
|
724
|
+
event.data.object.line_items?.data.reduce(
|
|
725
|
+
(total, item) => total + item.amount_total,
|
|
726
|
+
0
|
|
727
|
+
) ?? 0,
|
|
659
728
|
paymentMethods: event.data.object.payment_method_types,
|
|
660
|
-
status:
|
|
729
|
+
status: 'UPDATED',
|
|
661
730
|
currency: event.data.object.currency,
|
|
662
731
|
providerFields: event.data.object
|
|
663
732
|
});
|
|
664
733
|
break;
|
|
665
734
|
}
|
|
666
|
-
case
|
|
667
|
-
if (
|
|
735
|
+
case 'plan.created': {
|
|
736
|
+
if (
|
|
737
|
+
typeof event.data.object.product === 'object' &&
|
|
738
|
+
event.data.object.product != null &&
|
|
739
|
+
event.data.object.amount != null
|
|
740
|
+
) {
|
|
668
741
|
this.planService.basePlanService.createPlan({
|
|
669
742
|
id: event.data.object.id,
|
|
670
|
-
billingProvider:
|
|
743
|
+
billingProvider: 'stripe' /* STRIPE */,
|
|
671
744
|
cadence: event.data.object.interval,
|
|
672
745
|
currency: event.data.object.currency,
|
|
673
746
|
active: true,
|
|
674
|
-
name:
|
|
747
|
+
name:
|
|
748
|
+
typeof event.data.object.product === 'string'
|
|
749
|
+
? event.data.object.product
|
|
750
|
+
: event.data.object.product?.id,
|
|
675
751
|
price: event.data.object.amount,
|
|
676
752
|
externalId: event.data.object.id,
|
|
677
753
|
providerFields: event.data.object
|
|
678
754
|
});
|
|
679
755
|
} else {
|
|
680
|
-
throw new Error(
|
|
756
|
+
throw new Error('Invalid plan');
|
|
681
757
|
}
|
|
682
758
|
break;
|
|
683
759
|
}
|
|
684
|
-
case
|
|
685
|
-
if (
|
|
760
|
+
case 'plan.updated': {
|
|
761
|
+
if (
|
|
762
|
+
typeof event.data.object.product === 'object' &&
|
|
763
|
+
event.data.object.product != null &&
|
|
764
|
+
event.data.object.amount != null
|
|
765
|
+
) {
|
|
686
766
|
this.planService.basePlanService.updatePlan({
|
|
687
767
|
id: event.data.object.id,
|
|
688
|
-
billingProvider:
|
|
768
|
+
billingProvider: 'stripe' /* STRIPE */,
|
|
689
769
|
cadence: event.data.object.interval,
|
|
690
770
|
currency: event.data.object.currency,
|
|
691
771
|
active: true,
|
|
692
|
-
name:
|
|
772
|
+
name:
|
|
773
|
+
typeof event.data.object.product === 'string'
|
|
774
|
+
? event.data.object.product
|
|
775
|
+
: event.data.object.product?.id,
|
|
693
776
|
price: event.data.object.amount,
|
|
694
777
|
externalId: event.data.object.id,
|
|
695
778
|
providerFields: event.data.object
|
|
696
779
|
});
|
|
697
780
|
} else {
|
|
698
|
-
throw new Error(
|
|
781
|
+
throw new Error('Invalid plan');
|
|
699
782
|
}
|
|
700
783
|
break;
|
|
701
784
|
}
|
|
702
|
-
case
|
|
785
|
+
case 'plan.deleted': {
|
|
703
786
|
this.planService.deletePlan({
|
|
704
787
|
id: event.data.object.id
|
|
705
788
|
});
|
|
706
789
|
break;
|
|
707
790
|
}
|
|
708
|
-
case
|
|
791
|
+
case 'customer.subscription.created': {
|
|
709
792
|
this.subscriptionService.baseSubscriptionService.createSubscription({
|
|
710
793
|
id: event.data.object.id,
|
|
711
|
-
partyId:
|
|
712
|
-
|
|
794
|
+
partyId:
|
|
795
|
+
typeof event.data.object.customer === 'string'
|
|
796
|
+
? event.data.object.customer
|
|
797
|
+
: event.data.object.customer.id,
|
|
798
|
+
partyType: 'USER',
|
|
713
799
|
description: event.data.object.description ?? void 0,
|
|
714
800
|
active: true,
|
|
715
801
|
productId: event.data.object.items.data[0].plan.id,
|
|
716
802
|
providerFields: event.data.object,
|
|
717
803
|
externalId: event.data.object.id,
|
|
718
|
-
billingProvider:
|
|
804
|
+
billingProvider: 'stripe' /* STRIPE */,
|
|
719
805
|
startDate: new Date(event.data.object.created),
|
|
720
|
-
endDate: event.data.object.cancel_at
|
|
806
|
+
endDate: event.data.object.cancel_at
|
|
807
|
+
? new Date(event.data.object.cancel_at)
|
|
808
|
+
: /* @__PURE__ */ new Date(Infinity),
|
|
721
809
|
status: event.data.object.status
|
|
722
810
|
});
|
|
723
811
|
break;
|
|
724
812
|
}
|
|
725
|
-
case
|
|
813
|
+
case 'customer.subscription.updated': {
|
|
726
814
|
this.subscriptionService.baseSubscriptionService.updateSubscription({
|
|
727
815
|
id: event.data.object.id,
|
|
728
|
-
partyId:
|
|
729
|
-
|
|
816
|
+
partyId:
|
|
817
|
+
typeof event.data.object.customer === 'string'
|
|
818
|
+
? event.data.object.customer
|
|
819
|
+
: event.data.object.customer.id,
|
|
820
|
+
partyType: 'USER',
|
|
730
821
|
description: event.data.object.description ?? void 0,
|
|
731
822
|
active: true,
|
|
732
823
|
providerFields: event.data.object,
|
|
733
824
|
externalId: event.data.object.id,
|
|
734
|
-
billingProvider:
|
|
825
|
+
billingProvider: 'stripe' /* STRIPE */,
|
|
735
826
|
startDate: new Date(event.data.object.created),
|
|
736
|
-
endDate: event.data.object.cancel_at
|
|
827
|
+
endDate: event.data.object.cancel_at
|
|
828
|
+
? new Date(event.data.object.cancel_at)
|
|
829
|
+
: /* @__PURE__ */ new Date(Infinity),
|
|
737
830
|
productId: event.data.object.items.data[0].plan.id,
|
|
738
831
|
status: event.data.object.status
|
|
739
832
|
});
|
|
740
833
|
break;
|
|
741
834
|
}
|
|
742
|
-
case
|
|
835
|
+
case 'customer.subscription.deleted': {
|
|
743
836
|
this.subscriptionService.deleteSubscription({
|
|
744
837
|
id: event.data.object.id
|
|
745
838
|
});
|
|
746
839
|
break;
|
|
747
840
|
}
|
|
748
|
-
case
|
|
841
|
+
case 'customer.subscription.paused': {
|
|
749
842
|
this.subscriptionService.cancelSubscription({
|
|
750
843
|
id: event.data.object.id
|
|
751
844
|
});
|
|
752
845
|
break;
|
|
753
846
|
}
|
|
754
|
-
case
|
|
847
|
+
case 'customer.subscription.resumed': {
|
|
755
848
|
this.subscriptionService.resumeSubscription({
|
|
756
849
|
id: event.data.object.id
|
|
757
850
|
});
|
|
@@ -759,7 +852,7 @@ var StripeWebhookService = class {
|
|
|
759
852
|
}
|
|
760
853
|
default:
|
|
761
854
|
this.openTelemetryCollector.info(
|
|
762
|
-
|
|
855
|
+
'Unprocessed stripe event type',
|
|
763
856
|
eventType
|
|
764
857
|
);
|
|
765
858
|
break;
|