@forklaunch/implementation-billing-stripe 0.4.4 → 0.5.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.
@@ -120,13 +120,13 @@ export class StripeBillingPortalService<
120
120
  });
121
121
  const session = await this.stripeClient.billingPortal.sessions.create({
122
122
  ...billingPortalDto.stripeFields,
123
- customer: existingSession.customerId
123
+ customer: billingPortalDto.customerId || existingSession.customerId
124
124
  });
125
125
 
126
126
  return await this.baseBillingPortalService.updateBillingPortalSession(
127
127
  {
128
128
  ...billingPortalDto,
129
- id: session.id,
129
+ id: existingSession.id, // Use the original database ID, not the new Stripe session ID
130
130
  uri: session.url,
131
131
  expiresAt: new Date(
132
132
  Date.now() + this.billingPortalSessionExpiryDurationMs
@@ -97,6 +97,7 @@ export class StripeCheckoutSessionService<
97
97
  ): Promise<Dto['CheckoutSessionMapper']> {
98
98
  const session = await this.stripeClient.checkout.sessions.create({
99
99
  ...checkoutSessionDto.stripeFields,
100
+ mode: 'subscription',
100
101
  payment_method_types: checkoutSessionDto.paymentMethods,
101
102
  currency: checkoutSessionDto.currency as string,
102
103
  success_url: checkoutSessionDto.successRedirectUri,
@@ -109,10 +109,11 @@ export class StripePaymentLinkService<
109
109
  ...paymentLinkDto,
110
110
  id: session.id,
111
111
  amount:
112
+ paymentLinkDto.amount ??
112
113
  session.line_items?.data.reduce<number>(
113
114
  (total, item) => total + item.amount_total,
114
115
  0
115
- ) ?? 0
116
+ )
116
117
  },
117
118
  this.em,
118
119
  session,
@@ -197,6 +198,7 @@ export class StripePaymentLinkService<
197
198
  }
198
199
 
199
200
  async listPaymentLinks(idsDto?: IdsDto): Promise<Dto['PaymentLinkMapper'][]> {
201
+ this.openTelemetryCollector.log('info', idsDto ?? 'idsDto is undefined');
200
202
  const stripePaymentLinks = await this.stripeClient.paymentLinks.list({
201
203
  active: true
202
204
  });
@@ -204,19 +206,17 @@ export class StripePaymentLinkService<
204
206
  const databasePaymentLinks =
205
207
  await this.basePaymentLinkService.listPaymentLinks(idsDto);
206
208
 
207
- return await Promise.all(
208
- databasePaymentLinks.map(async (paymentLink) => {
209
+ return databasePaymentLinks
210
+ .map((paymentLink) => {
209
211
  const stripePaymentLink = stripePaymentLinks.data.find(
210
212
  (sp) => sp.id === paymentLink.id
211
213
  );
212
214
  if (!stripePaymentLink) {
213
- throw new Error(
214
- `Stripe payment link not found for id: ${paymentLink.id}`
215
- );
215
+ return null;
216
216
  }
217
217
  paymentLink.stripeFields = stripePaymentLink;
218
218
  return paymentLink;
219
219
  })
220
- );
220
+ .filter((paymentLink) => paymentLink !== null);
221
221
  }
222
222
  }
@@ -91,6 +91,7 @@ export class StripePlanService<
91
91
  ): Promise<Dto['PlanMapper']> {
92
92
  const stripePlan = await this.stripeClient.plans.create({
93
93
  ...planDto.stripeFields,
94
+ amount: planDto.price,
94
95
  interval: planDto.cadence,
95
96
  product: planDto.name,
96
97
  currency: planDto.currency as string
@@ -110,17 +111,11 @@ export class StripePlanService<
110
111
  }
111
112
 
112
113
  async getPlan(idDto: IdDto, em?: EntityManager): Promise<Dto['PlanMapper']> {
113
- const plan = await this.stripeClient.plans.retrieve(idDto.id);
114
- const id = (
115
- await em?.findOne<{ id: string; externalId: string }>(
116
- this.options?.databaseTableName ?? 'plan',
117
- { externalId: idDto.id }
118
- )
119
- )?.id;
120
- if (!id) {
114
+ const planEntity = await this.basePlanService.getPlan(idDto, em);
115
+ if (!planEntity.externalId) {
121
116
  throw new Error('Plan not found');
122
117
  }
123
- const planEntity = await this.basePlanService.getPlan({ id }, em);
118
+ const plan = await this.stripeClient.plans.retrieve(planEntity.externalId);
124
119
  planEntity.stripeFields = plan;
125
120
  return planEntity;
126
121
  }
@@ -129,35 +124,58 @@ export class StripePlanService<
129
124
  planDto: StripeUpdatePlanDto,
130
125
  em?: EntityManager
131
126
  ): Promise<Dto['PlanMapper']> {
132
- const existingPlan = await this.stripeClient.plans.retrieve(planDto.id);
133
- const plan = await this.stripeClient.plans.del(planDto.id).then(() =>
134
- this.stripeClient.plans.create({
135
- ...planDto.stripeFields,
136
- interval: planDto.cadence ?? existingPlan.interval,
137
- product: planDto.name,
138
- currency: planDto.currency ?? existingPlan.currency
139
- })
127
+ const planEntity = await this.basePlanService.getPlan(
128
+ {
129
+ id: planDto.id
130
+ },
131
+ em
140
132
  );
141
133
 
142
- const planEntity = await this.basePlanService.updatePlan(
143
- await this.mappers.UpdatePlanMapper.toEntity(
144
- {
145
- ...planDto,
146
- externalId: plan.id,
147
- billingProvider: 'stripe'
148
- },
149
- em ?? this.em,
150
- plan
151
- ),
152
- em
134
+ const existingPlan = await this.stripeClient.plans.retrieve(
135
+ planEntity.externalId
153
136
  );
154
- planEntity.stripeFields = plan;
155
137
 
156
- return planEntity;
138
+ const existingProduct = existingPlan.product;
139
+ if (!existingProduct) {
140
+ throw new Error('Plan product not found');
141
+ }
142
+
143
+ const productId =
144
+ typeof existingProduct === 'string'
145
+ ? existingProduct
146
+ : existingProduct.id;
147
+
148
+ await this.stripeClient.plans.del(planEntity.externalId);
149
+ const updatedPlan = await this.stripeClient.plans.create({
150
+ ...planDto.stripeFields,
151
+ interval: planDto.cadence ?? existingPlan.interval,
152
+ currency: planDto.currency ?? existingPlan.currency,
153
+ amount: planDto.price ?? existingPlan.amount ?? undefined,
154
+ product: productId
155
+ });
156
+
157
+ const updatedPlanEntity = await this.basePlanService.updatePlan(
158
+ {
159
+ ...planDto,
160
+ externalId: updatedPlan.id,
161
+ name: planDto.name,
162
+ billingProvider: 'stripe'
163
+ },
164
+ em,
165
+ updatedPlan
166
+ );
167
+
168
+ updatedPlanEntity.stripeFields = updatedPlan;
169
+
170
+ return updatedPlanEntity;
157
171
  }
158
172
 
159
- async deletePlan(idDto: { id: string }, em?: EntityManager): Promise<void> {
160
- await this.stripeClient.plans.del(idDto.id);
173
+ async deletePlan(idDto: IdDto, em?: EntityManager): Promise<void> {
174
+ const plan = await this.basePlanService.getPlan(idDto, em);
175
+ if (!plan.externalId) {
176
+ throw new Error('Plan not found');
177
+ }
178
+ await this.stripeClient.plans.del(plan.externalId);
161
179
  await this.basePlanService.deletePlan(idDto, em);
162
180
  }
163
181
 
@@ -165,30 +183,27 @@ export class StripePlanService<
165
183
  idsDto?: IdsDto,
166
184
  em?: EntityManager
167
185
  ): Promise<Dto['PlanMapper'][]> {
168
- const plans = await this.stripeClient.plans.list({
169
- active: true
170
- });
171
- const planIds = (
172
- await em?.findAll<{ id: string; externalId: string }>(
173
- this.options?.databaseTableName ?? 'plan',
174
- { where: { externalId: { $in: plans.data.map((plan) => plan.id) } } }
175
- )
176
- )
177
- ?.filter((s) => idsDto?.ids?.includes(s.id))
178
- ?.map((s) => s.id);
179
-
180
- if (!planIds) {
181
- throw new Error('Plans not found');
186
+ const plans = await this.basePlanService.listPlans(idsDto, em);
187
+
188
+ if (!plans || plans.length === 0) {
189
+ return [];
182
190
  }
183
- return await Promise.all(
184
- (await this.basePlanService.listPlans({ ids: planIds }, em)).map(
185
- async (plan) => ({
186
- ...plan,
187
- stripeFields: plans.data.find(
188
- (stripePlan) => stripePlan.id === plan.externalId
189
- )
190
- })
191
- )
191
+
192
+ const stripePlans = await Promise.all(
193
+ plans.map(async (plan) => {
194
+ try {
195
+ return await this.stripeClient.plans.retrieve(plan.externalId);
196
+ } catch {
197
+ return null;
198
+ }
199
+ })
192
200
  );
201
+
202
+ return plans
203
+ .map((plan, index) => ({
204
+ ...plan,
205
+ stripeFields: stripePlans[index]
206
+ }))
207
+ .filter((plan) => plan.stripeFields !== null);
193
208
  }
194
209
  }
@@ -117,8 +117,11 @@ export class StripeSubscriptionService<
117
117
  ): Promise<Dto['SubscriptionMapper']> {
118
118
  const subscriptionEntity =
119
119
  await this.baseSubscriptionService.getSubscription(idDto, em);
120
+ if (!subscriptionEntity.externalId) {
121
+ throw new Error('Subscription not found');
122
+ }
120
123
  const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
121
- idDto.id
124
+ subscriptionEntity.externalId
122
125
  );
123
126
  subscriptionEntity.stripeFields = stripeSubscription;
124
127
  return subscriptionEntity;
@@ -130,8 +133,11 @@ export class StripeSubscriptionService<
130
133
  ): Promise<Dto['SubscriptionMapper']> {
131
134
  const subscriptionEntity =
132
135
  await this.baseSubscriptionService.getUserSubscription(idDto, em);
136
+ if (!subscriptionEntity.externalId) {
137
+ throw new Error('Subscription not found');
138
+ }
133
139
  const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
134
- idDto.id
140
+ subscriptionEntity.externalId
135
141
  );
136
142
  subscriptionEntity.stripeFields = stripeSubscription;
137
143
  return subscriptionEntity;
@@ -141,104 +147,130 @@ export class StripeSubscriptionService<
141
147
  idDto: IdDto,
142
148
  em?: EntityManager
143
149
  ): Promise<Dto['SubscriptionMapper']> {
144
- const id = (
145
- await em?.findOne<{ id: string; externalId: string }>(
146
- this.options?.databaseTableName ?? 'subscription',
147
- { externalId: idDto.id }
148
- )
149
- )?.id;
150
- if (!id) {
150
+ const subscriptionEntity =
151
+ await this.baseSubscriptionService.getOrganizationSubscription(idDto, em);
152
+ if (!subscriptionEntity.externalId) {
151
153
  throw new Error('Subscription not found');
152
154
  }
153
- const subscriptionEntity =
154
- await this.baseSubscriptionService.getOrganizationSubscription(
155
- { id },
156
- em
157
- );
158
155
  const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
159
- idDto.id
156
+ subscriptionEntity.externalId
160
157
  );
161
158
  subscriptionEntity.stripeFields = stripeSubscription;
162
159
  return subscriptionEntity;
163
160
  }
164
161
 
165
162
  async updateSubscription(
166
- subscriptionDto: StripeUpdateSubscriptionDto<PartyType>,
163
+ subscriptionDto: StripeUpdateSubscriptionDto<PartyType> & IdDto,
167
164
  em?: EntityManager
168
165
  ): Promise<Dto['SubscriptionMapper']> {
169
- const subscription = await this.stripeClient.subscriptions.update(
170
- subscriptionDto.id,
166
+ const subscriptionEntity =
167
+ await this.baseSubscriptionService.getSubscription(
168
+ {
169
+ id: subscriptionDto.id
170
+ },
171
+ em
172
+ );
173
+ if (!subscriptionEntity.externalId) {
174
+ throw new Error('Subscription not found');
175
+ }
176
+
177
+ const existingStripeSubscription =
178
+ await this.stripeClient.subscriptions.retrieve(
179
+ subscriptionEntity.externalId
180
+ );
181
+
182
+ const updatedSubscription = await this.stripeClient.subscriptions.update(
183
+ subscriptionEntity.externalId,
171
184
  {
172
185
  ...subscriptionDto.stripeFields,
173
- items: [
174
- {
175
- plan: subscriptionDto.productId
176
- }
177
- ]
186
+ items: existingStripeSubscription.items.data.map((item) => ({
187
+ id: item.id,
188
+ plan: subscriptionDto.productId || item.plan?.id
189
+ }))
178
190
  }
179
191
  );
180
192
 
181
- return await this.baseSubscriptionService.updateSubscription(
182
- {
183
- ...subscriptionDto,
184
- externalId: subscription.id,
185
- billingProvider: 'stripe',
186
- providerFields: subscription
187
- },
188
- em ?? this.em,
189
- subscription
190
- );
193
+ const updatedSubscriptionEntity =
194
+ await this.baseSubscriptionService.updateSubscription(
195
+ {
196
+ ...subscriptionDto,
197
+ externalId: updatedSubscription.id,
198
+ billingProvider: 'stripe'
199
+ },
200
+ em ?? this.em,
201
+ updatedSubscription
202
+ );
203
+
204
+ updatedSubscriptionEntity.stripeFields = updatedSubscription;
205
+ return updatedSubscriptionEntity;
191
206
  }
192
207
 
193
- async deleteSubscription(
194
- idDto: { id: string },
195
- em?: EntityManager
196
- ): Promise<void> {
197
- await this.stripeClient.subscriptions.cancel(idDto.id);
208
+ async deleteSubscription(idDto: IdDto, em?: EntityManager): Promise<void> {
209
+ const subscription = await this.baseSubscriptionService.getSubscription(
210
+ idDto,
211
+ em
212
+ );
213
+ if (!subscription.externalId) {
214
+ throw new Error('Subscription not found');
215
+ }
216
+ await this.stripeClient.subscriptions.cancel(subscription.externalId);
198
217
  await this.baseSubscriptionService.deleteSubscription(idDto, em);
199
218
  }
200
219
 
201
220
  async listSubscriptions(
202
- idsDto: IdsDto,
221
+ idsDto?: IdsDto,
203
222
  em?: EntityManager
204
223
  ): Promise<Dto['SubscriptionMapper'][]> {
205
- const subscriptions = (
206
- await this.stripeClient.subscriptions.list({
207
- status: 'active'
208
- })
209
- ).data.filter((s) => idsDto.ids?.includes(s.id));
210
-
211
- const ids = (
212
- await em?.findAll<{ id: string; externalId: string }>(
213
- this.options?.databaseTableName ?? 'subscription',
214
- { where: { externalId: { $in: subscriptions.map((s) => s.id) } } }
215
- )
216
- )?.map((s) => s.id);
224
+ const subscriptions = await this.baseSubscriptionService.listSubscriptions(
225
+ idsDto,
226
+ em
227
+ );
217
228
 
218
- if (!ids) {
219
- throw new Error('Subscriptions not found');
229
+ if (!subscriptions || subscriptions.length === 0) {
230
+ return [];
220
231
  }
221
232
 
222
- return await Promise.all(
223
- (await this.baseSubscriptionService.listSubscriptions({ ids }, em)).map(
224
- async (subscription) => {
225
- const stripeSubscription = subscriptions.find(
226
- (s) => s.id === subscription.externalId
227
- )!;
228
- subscription.stripeFields = stripeSubscription;
229
- return subscription;
233
+ const stripeSubscriptions = await Promise.all(
234
+ subscriptions.map(async (subscription) => {
235
+ try {
236
+ return await this.stripeClient.subscriptions.retrieve(
237
+ subscription.externalId
238
+ );
239
+ } catch {
240
+ return null;
230
241
  }
231
- )
242
+ })
232
243
  );
244
+
245
+ return subscriptions
246
+ .map((subscription, index) => ({
247
+ ...subscription,
248
+ stripeFields: stripeSubscriptions[index]
249
+ }))
250
+ .filter((subscription) => subscription.stripeFields !== null);
233
251
  }
234
252
 
235
253
  async cancelSubscription(idDto: IdDto, em?: EntityManager): Promise<void> {
236
- await this.stripeClient.subscriptions.cancel(idDto.id);
254
+ const subscription = await this.baseSubscriptionService.getSubscription(
255
+ idDto,
256
+ em
257
+ );
258
+ if (!subscription.externalId) {
259
+ throw new Error('Subscription not found');
260
+ }
261
+ await this.stripeClient.subscriptions.cancel(subscription.externalId);
237
262
  await this.baseSubscriptionService.cancelSubscription(idDto, em);
238
263
  }
239
264
 
240
265
  async resumeSubscription(idDto: IdDto, em?: EntityManager): Promise<void> {
241
- await this.stripeClient.subscriptions.resume(idDto.id);
266
+ const subscription = await this.baseSubscriptionService.getSubscription(
267
+ idDto,
268
+ em
269
+ );
270
+ if (!subscription.externalId) {
271
+ throw new Error('Subscription not found');
272
+ }
273
+ await this.stripeClient.subscriptions.resume(subscription.externalId);
242
274
  await this.baseSubscriptionService.resumeSubscription(idDto, em);
243
275
  }
244
276
  }
@@ -121,9 +121,7 @@ declare class StripePlanService<SchemaValidator extends AnySchemaValidator, Enti
121
121
  createPlan(planDto: StripeCreatePlanDto, em?: EntityManager): Promise<Dto['PlanMapper']>;
122
122
  getPlan(idDto: IdDto, em?: EntityManager): Promise<Dto['PlanMapper']>;
123
123
  updatePlan(planDto: StripeUpdatePlanDto, em?: EntityManager): Promise<Dto['PlanMapper']>;
124
- deletePlan(idDto: {
125
- id: string;
126
- }, em?: EntityManager): Promise<void>;
124
+ deletePlan(idDto: IdDto, em?: EntityManager): Promise<void>;
127
125
  listPlans(idsDto?: IdsDto, em?: EntityManager): Promise<Dto['PlanMapper'][]>;
128
126
  }
129
127
 
@@ -152,11 +150,9 @@ declare class StripeSubscriptionService<SchemaValidator extends AnySchemaValidat
152
150
  getSubscription(idDto: IdDto, em?: EntityManager): Promise<Dto['SubscriptionMapper']>;
153
151
  getUserSubscription(idDto: IdDto, em?: EntityManager): Promise<Dto['SubscriptionMapper']>;
154
152
  getOrganizationSubscription(idDto: IdDto, em?: EntityManager): Promise<Dto['SubscriptionMapper']>;
155
- updateSubscription(subscriptionDto: StripeUpdateSubscriptionDto<PartyType>, em?: EntityManager): Promise<Dto['SubscriptionMapper']>;
156
- deleteSubscription(idDto: {
157
- id: string;
158
- }, em?: EntityManager): Promise<void>;
159
- listSubscriptions(idsDto: IdsDto, em?: EntityManager): Promise<Dto['SubscriptionMapper'][]>;
153
+ updateSubscription(subscriptionDto: StripeUpdateSubscriptionDto<PartyType> & IdDto, em?: EntityManager): Promise<Dto['SubscriptionMapper']>;
154
+ deleteSubscription(idDto: IdDto, em?: EntityManager): Promise<void>;
155
+ listSubscriptions(idsDto?: IdsDto, em?: EntityManager): Promise<Dto['SubscriptionMapper'][]>;
160
156
  cancelSubscription(idDto: IdDto, em?: EntityManager): Promise<void>;
161
157
  resumeSubscription(idDto: IdDto, em?: EntityManager): Promise<void>;
162
158
  }
@@ -121,9 +121,7 @@ declare class StripePlanService<SchemaValidator extends AnySchemaValidator, Enti
121
121
  createPlan(planDto: StripeCreatePlanDto, em?: EntityManager): Promise<Dto['PlanMapper']>;
122
122
  getPlan(idDto: IdDto, em?: EntityManager): Promise<Dto['PlanMapper']>;
123
123
  updatePlan(planDto: StripeUpdatePlanDto, em?: EntityManager): Promise<Dto['PlanMapper']>;
124
- deletePlan(idDto: {
125
- id: string;
126
- }, em?: EntityManager): Promise<void>;
124
+ deletePlan(idDto: IdDto, em?: EntityManager): Promise<void>;
127
125
  listPlans(idsDto?: IdsDto, em?: EntityManager): Promise<Dto['PlanMapper'][]>;
128
126
  }
129
127
 
@@ -152,11 +150,9 @@ declare class StripeSubscriptionService<SchemaValidator extends AnySchemaValidat
152
150
  getSubscription(idDto: IdDto, em?: EntityManager): Promise<Dto['SubscriptionMapper']>;
153
151
  getUserSubscription(idDto: IdDto, em?: EntityManager): Promise<Dto['SubscriptionMapper']>;
154
152
  getOrganizationSubscription(idDto: IdDto, em?: EntityManager): Promise<Dto['SubscriptionMapper']>;
155
- updateSubscription(subscriptionDto: StripeUpdateSubscriptionDto<PartyType>, em?: EntityManager): Promise<Dto['SubscriptionMapper']>;
156
- deleteSubscription(idDto: {
157
- id: string;
158
- }, em?: EntityManager): Promise<void>;
159
- listSubscriptions(idsDto: IdsDto, em?: EntityManager): Promise<Dto['SubscriptionMapper'][]>;
153
+ updateSubscription(subscriptionDto: StripeUpdateSubscriptionDto<PartyType> & IdDto, em?: EntityManager): Promise<Dto['SubscriptionMapper']>;
154
+ deleteSubscription(idDto: IdDto, em?: EntityManager): Promise<void>;
155
+ listSubscriptions(idsDto?: IdsDto, em?: EntityManager): Promise<Dto['SubscriptionMapper'][]>;
160
156
  cancelSubscription(idDto: IdDto, em?: EntityManager): Promise<void>;
161
157
  resumeSubscription(idDto: IdDto, em?: EntityManager): Promise<void>;
162
158
  }
@@ -89,12 +89,13 @@ var StripeBillingPortalService = class {
89
89
  });
90
90
  const session = await this.stripeClient.billingPortal.sessions.create({
91
91
  ...billingPortalDto.stripeFields,
92
- customer: existingSession.customerId
92
+ customer: billingPortalDto.customerId || existingSession.customerId
93
93
  });
94
94
  return await this.baseBillingPortalService.updateBillingPortalSession(
95
95
  {
96
96
  ...billingPortalDto,
97
- id: session.id,
97
+ id: existingSession.id,
98
+ // Use the original database ID, not the new Stripe session ID
98
99
  uri: session.url,
99
100
  expiresAt: new Date(
100
101
  Date.now() + this.billingPortalSessionExpiryDurationMs
@@ -137,6 +138,7 @@ var StripeCheckoutSessionService = class {
137
138
  async createCheckoutSession(checkoutSessionDto, ...args) {
138
139
  const session = await this.stripeClient.checkout.sessions.create({
139
140
  ...checkoutSessionDto.stripeFields,
141
+ mode: "subscription",
140
142
  payment_method_types: checkoutSessionDto.paymentMethods,
141
143
  currency: checkoutSessionDto.currency,
142
144
  success_url: checkoutSessionDto.successRedirectUri,
@@ -222,10 +224,10 @@ var StripePaymentLinkService = class {
222
224
  {
223
225
  ...paymentLinkDto,
224
226
  id: session.id,
225
- amount: session.line_items?.data.reduce(
227
+ amount: paymentLinkDto.amount ?? session.line_items?.data.reduce(
226
228
  (total, item) => total + item.amount_total,
227
229
  0
228
- ) ?? 0
230
+ )
229
231
  },
230
232
  this.em,
231
233
  session,
@@ -291,24 +293,21 @@ var StripePaymentLinkService = class {
291
293
  await this.basePaymentLinkService.handlePaymentFailure({ id });
292
294
  }
293
295
  async listPaymentLinks(idsDto) {
296
+ this.openTelemetryCollector.log("info", idsDto ?? "idsDto is undefined");
294
297
  const stripePaymentLinks = await this.stripeClient.paymentLinks.list({
295
298
  active: true
296
299
  });
297
300
  const databasePaymentLinks = await this.basePaymentLinkService.listPaymentLinks(idsDto);
298
- return await Promise.all(
299
- databasePaymentLinks.map(async (paymentLink) => {
300
- const stripePaymentLink = stripePaymentLinks.data.find(
301
- (sp) => sp.id === paymentLink.id
302
- );
303
- if (!stripePaymentLink) {
304
- throw new Error(
305
- `Stripe payment link not found for id: ${paymentLink.id}`
306
- );
307
- }
308
- paymentLink.stripeFields = stripePaymentLink;
309
- return paymentLink;
310
- })
311
- );
301
+ return databasePaymentLinks.map((paymentLink) => {
302
+ const stripePaymentLink = stripePaymentLinks.data.find(
303
+ (sp) => sp.id === paymentLink.id
304
+ );
305
+ if (!stripePaymentLink) {
306
+ return null;
307
+ }
308
+ paymentLink.stripeFields = stripePaymentLink;
309
+ return paymentLink;
310
+ }).filter((paymentLink) => paymentLink !== null);
312
311
  }
313
312
  };
314
313
 
@@ -339,6 +338,7 @@ var StripePlanService = class {
339
338
  async createPlan(planDto, em) {
340
339
  const stripePlan = await this.stripeClient.plans.create({
341
340
  ...planDto.stripeFields,
341
+ amount: planDto.price,
342
342
  interval: planDto.cadence,
343
343
  product: planDto.name,
344
344
  currency: planDto.currency
@@ -355,68 +355,76 @@ var StripePlanService = class {
355
355
  return plan;
356
356
  }
357
357
  async getPlan(idDto, em) {
358
- const plan = await this.stripeClient.plans.retrieve(idDto.id);
359
- const id = (await em?.findOne(
360
- this.options?.databaseTableName ?? "plan",
361
- { externalId: idDto.id }
362
- ))?.id;
363
- if (!id) {
358
+ const planEntity = await this.basePlanService.getPlan(idDto, em);
359
+ if (!planEntity.externalId) {
364
360
  throw new Error("Plan not found");
365
361
  }
366
- const planEntity = await this.basePlanService.getPlan({ id }, em);
362
+ const plan = await this.stripeClient.plans.retrieve(planEntity.externalId);
367
363
  planEntity.stripeFields = plan;
368
364
  return planEntity;
369
365
  }
370
366
  async updatePlan(planDto, em) {
371
- const existingPlan = await this.stripeClient.plans.retrieve(planDto.id);
372
- const plan = await this.stripeClient.plans.del(planDto.id).then(
373
- () => this.stripeClient.plans.create({
374
- ...planDto.stripeFields,
375
- interval: planDto.cadence ?? existingPlan.interval,
376
- product: planDto.name,
377
- currency: planDto.currency ?? existingPlan.currency
378
- })
379
- );
380
- const planEntity = await this.basePlanService.updatePlan(
381
- await this.mappers.UpdatePlanMapper.toEntity(
382
- {
383
- ...planDto,
384
- externalId: plan.id,
385
- billingProvider: "stripe"
386
- },
387
- em ?? this.em,
388
- plan
389
- ),
367
+ const planEntity = await this.basePlanService.getPlan(
368
+ {
369
+ id: planDto.id
370
+ },
390
371
  em
391
372
  );
392
- planEntity.stripeFields = plan;
393
- return planEntity;
373
+ const existingPlan = await this.stripeClient.plans.retrieve(
374
+ planEntity.externalId
375
+ );
376
+ const existingProduct = existingPlan.product;
377
+ if (!existingProduct) {
378
+ throw new Error("Plan product not found");
379
+ }
380
+ const productId = typeof existingProduct === "string" ? existingProduct : existingProduct.id;
381
+ await this.stripeClient.plans.del(planEntity.externalId);
382
+ const updatedPlan = await this.stripeClient.plans.create({
383
+ ...planDto.stripeFields,
384
+ interval: planDto.cadence ?? existingPlan.interval,
385
+ currency: planDto.currency ?? existingPlan.currency,
386
+ amount: planDto.price ?? existingPlan.amount ?? void 0,
387
+ product: productId
388
+ });
389
+ const updatedPlanEntity = await this.basePlanService.updatePlan(
390
+ {
391
+ ...planDto,
392
+ externalId: updatedPlan.id,
393
+ name: planDto.name,
394
+ billingProvider: "stripe"
395
+ },
396
+ em,
397
+ updatedPlan
398
+ );
399
+ updatedPlanEntity.stripeFields = updatedPlan;
400
+ return updatedPlanEntity;
394
401
  }
395
402
  async deletePlan(idDto, em) {
396
- await this.stripeClient.plans.del(idDto.id);
403
+ const plan = await this.basePlanService.getPlan(idDto, em);
404
+ if (!plan.externalId) {
405
+ throw new Error("Plan not found");
406
+ }
407
+ await this.stripeClient.plans.del(plan.externalId);
397
408
  await this.basePlanService.deletePlan(idDto, em);
398
409
  }
399
410
  async listPlans(idsDto, em) {
400
- const plans = await this.stripeClient.plans.list({
401
- active: true
402
- });
403
- const planIds = (await em?.findAll(
404
- this.options?.databaseTableName ?? "plan",
405
- { where: { externalId: { $in: plans.data.map((plan) => plan.id) } } }
406
- ))?.filter((s) => idsDto?.ids?.includes(s.id))?.map((s) => s.id);
407
- if (!planIds) {
408
- throw new Error("Plans not found");
411
+ const plans = await this.basePlanService.listPlans(idsDto, em);
412
+ if (!plans || plans.length === 0) {
413
+ return [];
409
414
  }
410
- return await Promise.all(
411
- (await this.basePlanService.listPlans({ ids: planIds }, em)).map(
412
- async (plan) => ({
413
- ...plan,
414
- stripeFields: plans.data.find(
415
- (stripePlan) => stripePlan.id === plan.externalId
416
- )
417
- })
418
- )
415
+ const stripePlans = await Promise.all(
416
+ plans.map(async (plan) => {
417
+ try {
418
+ return await this.stripeClient.plans.retrieve(plan.externalId);
419
+ } catch {
420
+ return null;
421
+ }
422
+ })
419
423
  );
424
+ return plans.map((plan, index) => ({
425
+ ...plan,
426
+ stripeFields: stripePlans[index]
427
+ })).filter((plan) => plan.stripeFields !== null);
420
428
  }
421
429
  };
422
430
 
@@ -466,94 +474,127 @@ var StripeSubscriptionService = class {
466
474
  }
467
475
  async getSubscription(idDto, em) {
468
476
  const subscriptionEntity = await this.baseSubscriptionService.getSubscription(idDto, em);
477
+ if (!subscriptionEntity.externalId) {
478
+ throw new Error("Subscription not found");
479
+ }
469
480
  const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
470
- idDto.id
481
+ subscriptionEntity.externalId
471
482
  );
472
483
  subscriptionEntity.stripeFields = stripeSubscription;
473
484
  return subscriptionEntity;
474
485
  }
475
486
  async getUserSubscription(idDto, em) {
476
487
  const subscriptionEntity = await this.baseSubscriptionService.getUserSubscription(idDto, em);
488
+ if (!subscriptionEntity.externalId) {
489
+ throw new Error("Subscription not found");
490
+ }
477
491
  const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
478
- idDto.id
492
+ subscriptionEntity.externalId
479
493
  );
480
494
  subscriptionEntity.stripeFields = stripeSubscription;
481
495
  return subscriptionEntity;
482
496
  }
483
497
  async getOrganizationSubscription(idDto, em) {
484
- const id = (await em?.findOne(
485
- this.options?.databaseTableName ?? "subscription",
486
- { externalId: idDto.id }
487
- ))?.id;
488
- if (!id) {
498
+ const subscriptionEntity = await this.baseSubscriptionService.getOrganizationSubscription(idDto, em);
499
+ if (!subscriptionEntity.externalId) {
489
500
  throw new Error("Subscription not found");
490
501
  }
491
- const subscriptionEntity = await this.baseSubscriptionService.getOrganizationSubscription(
492
- { id },
493
- em
494
- );
495
502
  const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
496
- idDto.id
503
+ subscriptionEntity.externalId
497
504
  );
498
505
  subscriptionEntity.stripeFields = stripeSubscription;
499
506
  return subscriptionEntity;
500
507
  }
501
508
  async updateSubscription(subscriptionDto, em) {
502
- const subscription = await this.stripeClient.subscriptions.update(
503
- subscriptionDto.id,
509
+ const subscriptionEntity = await this.baseSubscriptionService.getSubscription(
510
+ {
511
+ id: subscriptionDto.id
512
+ },
513
+ em
514
+ );
515
+ if (!subscriptionEntity.externalId) {
516
+ throw new Error("Subscription not found");
517
+ }
518
+ const existingStripeSubscription = await this.stripeClient.subscriptions.retrieve(
519
+ subscriptionEntity.externalId
520
+ );
521
+ const updatedSubscription = await this.stripeClient.subscriptions.update(
522
+ subscriptionEntity.externalId,
504
523
  {
505
524
  ...subscriptionDto.stripeFields,
506
- items: [
507
- {
508
- plan: subscriptionDto.productId
509
- }
510
- ]
525
+ items: existingStripeSubscription.items.data.map((item) => ({
526
+ id: item.id,
527
+ plan: subscriptionDto.productId || item.plan?.id
528
+ }))
511
529
  }
512
530
  );
513
- return await this.baseSubscriptionService.updateSubscription(
531
+ const updatedSubscriptionEntity = await this.baseSubscriptionService.updateSubscription(
514
532
  {
515
533
  ...subscriptionDto,
516
- externalId: subscription.id,
517
- billingProvider: "stripe",
518
- providerFields: subscription
534
+ externalId: updatedSubscription.id,
535
+ billingProvider: "stripe"
519
536
  },
520
537
  em ?? this.em,
521
- subscription
538
+ updatedSubscription
522
539
  );
540
+ updatedSubscriptionEntity.stripeFields = updatedSubscription;
541
+ return updatedSubscriptionEntity;
523
542
  }
524
543
  async deleteSubscription(idDto, em) {
525
- await this.stripeClient.subscriptions.cancel(idDto.id);
544
+ const subscription = await this.baseSubscriptionService.getSubscription(
545
+ idDto,
546
+ em
547
+ );
548
+ if (!subscription.externalId) {
549
+ throw new Error("Subscription not found");
550
+ }
551
+ await this.stripeClient.subscriptions.cancel(subscription.externalId);
526
552
  await this.baseSubscriptionService.deleteSubscription(idDto, em);
527
553
  }
528
554
  async listSubscriptions(idsDto, em) {
529
- const subscriptions = (await this.stripeClient.subscriptions.list({
530
- status: "active"
531
- })).data.filter((s) => idsDto.ids?.includes(s.id));
532
- const ids = (await em?.findAll(
533
- this.options?.databaseTableName ?? "subscription",
534
- { where: { externalId: { $in: subscriptions.map((s) => s.id) } } }
535
- ))?.map((s) => s.id);
536
- if (!ids) {
537
- throw new Error("Subscriptions not found");
555
+ const subscriptions = await this.baseSubscriptionService.listSubscriptions(
556
+ idsDto,
557
+ em
558
+ );
559
+ if (!subscriptions || subscriptions.length === 0) {
560
+ return [];
538
561
  }
539
- return await Promise.all(
540
- (await this.baseSubscriptionService.listSubscriptions({ ids }, em)).map(
541
- async (subscription) => {
542
- const stripeSubscription = subscriptions.find(
543
- (s) => s.id === subscription.externalId
562
+ const stripeSubscriptions = await Promise.all(
563
+ subscriptions.map(async (subscription) => {
564
+ try {
565
+ return await this.stripeClient.subscriptions.retrieve(
566
+ subscription.externalId
544
567
  );
545
- subscription.stripeFields = stripeSubscription;
546
- return subscription;
568
+ } catch {
569
+ return null;
547
570
  }
548
- )
571
+ })
549
572
  );
573
+ return subscriptions.map((subscription, index) => ({
574
+ ...subscription,
575
+ stripeFields: stripeSubscriptions[index]
576
+ })).filter((subscription) => subscription.stripeFields !== null);
550
577
  }
551
578
  async cancelSubscription(idDto, em) {
552
- await this.stripeClient.subscriptions.cancel(idDto.id);
579
+ const subscription = await this.baseSubscriptionService.getSubscription(
580
+ idDto,
581
+ em
582
+ );
583
+ if (!subscription.externalId) {
584
+ throw new Error("Subscription not found");
585
+ }
586
+ await this.stripeClient.subscriptions.cancel(subscription.externalId);
553
587
  await this.baseSubscriptionService.cancelSubscription(idDto, em);
554
588
  }
555
589
  async resumeSubscription(idDto, em) {
556
- await this.stripeClient.subscriptions.resume(idDto.id);
590
+ const subscription = await this.baseSubscriptionService.getSubscription(
591
+ idDto,
592
+ em
593
+ );
594
+ if (!subscription.externalId) {
595
+ throw new Error("Subscription not found");
596
+ }
597
+ await this.stripeClient.subscriptions.resume(subscription.externalId);
557
598
  await this.baseSubscriptionService.resumeSubscription(idDto, em);
558
599
  }
559
600
  };
@@ -57,12 +57,13 @@ var StripeBillingPortalService = class {
57
57
  });
58
58
  const session = await this.stripeClient.billingPortal.sessions.create({
59
59
  ...billingPortalDto.stripeFields,
60
- customer: existingSession.customerId
60
+ customer: billingPortalDto.customerId || existingSession.customerId
61
61
  });
62
62
  return await this.baseBillingPortalService.updateBillingPortalSession(
63
63
  {
64
64
  ...billingPortalDto,
65
- id: session.id,
65
+ id: existingSession.id,
66
+ // Use the original database ID, not the new Stripe session ID
66
67
  uri: session.url,
67
68
  expiresAt: new Date(
68
69
  Date.now() + this.billingPortalSessionExpiryDurationMs
@@ -105,6 +106,7 @@ var StripeCheckoutSessionService = class {
105
106
  async createCheckoutSession(checkoutSessionDto, ...args) {
106
107
  const session = await this.stripeClient.checkout.sessions.create({
107
108
  ...checkoutSessionDto.stripeFields,
109
+ mode: "subscription",
108
110
  payment_method_types: checkoutSessionDto.paymentMethods,
109
111
  currency: checkoutSessionDto.currency,
110
112
  success_url: checkoutSessionDto.successRedirectUri,
@@ -190,10 +192,10 @@ var StripePaymentLinkService = class {
190
192
  {
191
193
  ...paymentLinkDto,
192
194
  id: session.id,
193
- amount: session.line_items?.data.reduce(
195
+ amount: paymentLinkDto.amount ?? session.line_items?.data.reduce(
194
196
  (total, item) => total + item.amount_total,
195
197
  0
196
- ) ?? 0
198
+ )
197
199
  },
198
200
  this.em,
199
201
  session,
@@ -259,24 +261,21 @@ var StripePaymentLinkService = class {
259
261
  await this.basePaymentLinkService.handlePaymentFailure({ id });
260
262
  }
261
263
  async listPaymentLinks(idsDto) {
264
+ this.openTelemetryCollector.log("info", idsDto ?? "idsDto is undefined");
262
265
  const stripePaymentLinks = await this.stripeClient.paymentLinks.list({
263
266
  active: true
264
267
  });
265
268
  const databasePaymentLinks = await this.basePaymentLinkService.listPaymentLinks(idsDto);
266
- return await Promise.all(
267
- databasePaymentLinks.map(async (paymentLink) => {
268
- const stripePaymentLink = stripePaymentLinks.data.find(
269
- (sp) => sp.id === paymentLink.id
270
- );
271
- if (!stripePaymentLink) {
272
- throw new Error(
273
- `Stripe payment link not found for id: ${paymentLink.id}`
274
- );
275
- }
276
- paymentLink.stripeFields = stripePaymentLink;
277
- return paymentLink;
278
- })
279
- );
269
+ return databasePaymentLinks.map((paymentLink) => {
270
+ const stripePaymentLink = stripePaymentLinks.data.find(
271
+ (sp) => sp.id === paymentLink.id
272
+ );
273
+ if (!stripePaymentLink) {
274
+ return null;
275
+ }
276
+ paymentLink.stripeFields = stripePaymentLink;
277
+ return paymentLink;
278
+ }).filter((paymentLink) => paymentLink !== null);
280
279
  }
281
280
  };
282
281
 
@@ -307,6 +306,7 @@ var StripePlanService = class {
307
306
  async createPlan(planDto, em) {
308
307
  const stripePlan = await this.stripeClient.plans.create({
309
308
  ...planDto.stripeFields,
309
+ amount: planDto.price,
310
310
  interval: planDto.cadence,
311
311
  product: planDto.name,
312
312
  currency: planDto.currency
@@ -323,68 +323,76 @@ var StripePlanService = class {
323
323
  return plan;
324
324
  }
325
325
  async getPlan(idDto, em) {
326
- const plan = await this.stripeClient.plans.retrieve(idDto.id);
327
- const id = (await em?.findOne(
328
- this.options?.databaseTableName ?? "plan",
329
- { externalId: idDto.id }
330
- ))?.id;
331
- if (!id) {
326
+ const planEntity = await this.basePlanService.getPlan(idDto, em);
327
+ if (!planEntity.externalId) {
332
328
  throw new Error("Plan not found");
333
329
  }
334
- const planEntity = await this.basePlanService.getPlan({ id }, em);
330
+ const plan = await this.stripeClient.plans.retrieve(planEntity.externalId);
335
331
  planEntity.stripeFields = plan;
336
332
  return planEntity;
337
333
  }
338
334
  async updatePlan(planDto, em) {
339
- const existingPlan = await this.stripeClient.plans.retrieve(planDto.id);
340
- const plan = await this.stripeClient.plans.del(planDto.id).then(
341
- () => this.stripeClient.plans.create({
342
- ...planDto.stripeFields,
343
- interval: planDto.cadence ?? existingPlan.interval,
344
- product: planDto.name,
345
- currency: planDto.currency ?? existingPlan.currency
346
- })
347
- );
348
- const planEntity = await this.basePlanService.updatePlan(
349
- await this.mappers.UpdatePlanMapper.toEntity(
350
- {
351
- ...planDto,
352
- externalId: plan.id,
353
- billingProvider: "stripe"
354
- },
355
- em ?? this.em,
356
- plan
357
- ),
335
+ const planEntity = await this.basePlanService.getPlan(
336
+ {
337
+ id: planDto.id
338
+ },
358
339
  em
359
340
  );
360
- planEntity.stripeFields = plan;
361
- return planEntity;
341
+ const existingPlan = await this.stripeClient.plans.retrieve(
342
+ planEntity.externalId
343
+ );
344
+ const existingProduct = existingPlan.product;
345
+ if (!existingProduct) {
346
+ throw new Error("Plan product not found");
347
+ }
348
+ const productId = typeof existingProduct === "string" ? existingProduct : existingProduct.id;
349
+ await this.stripeClient.plans.del(planEntity.externalId);
350
+ const updatedPlan = await this.stripeClient.plans.create({
351
+ ...planDto.stripeFields,
352
+ interval: planDto.cadence ?? existingPlan.interval,
353
+ currency: planDto.currency ?? existingPlan.currency,
354
+ amount: planDto.price ?? existingPlan.amount ?? void 0,
355
+ product: productId
356
+ });
357
+ const updatedPlanEntity = await this.basePlanService.updatePlan(
358
+ {
359
+ ...planDto,
360
+ externalId: updatedPlan.id,
361
+ name: planDto.name,
362
+ billingProvider: "stripe"
363
+ },
364
+ em,
365
+ updatedPlan
366
+ );
367
+ updatedPlanEntity.stripeFields = updatedPlan;
368
+ return updatedPlanEntity;
362
369
  }
363
370
  async deletePlan(idDto, em) {
364
- await this.stripeClient.plans.del(idDto.id);
371
+ const plan = await this.basePlanService.getPlan(idDto, em);
372
+ if (!plan.externalId) {
373
+ throw new Error("Plan not found");
374
+ }
375
+ await this.stripeClient.plans.del(plan.externalId);
365
376
  await this.basePlanService.deletePlan(idDto, em);
366
377
  }
367
378
  async listPlans(idsDto, em) {
368
- const plans = await this.stripeClient.plans.list({
369
- active: true
370
- });
371
- const planIds = (await em?.findAll(
372
- this.options?.databaseTableName ?? "plan",
373
- { where: { externalId: { $in: plans.data.map((plan) => plan.id) } } }
374
- ))?.filter((s) => idsDto?.ids?.includes(s.id))?.map((s) => s.id);
375
- if (!planIds) {
376
- throw new Error("Plans not found");
379
+ const plans = await this.basePlanService.listPlans(idsDto, em);
380
+ if (!plans || plans.length === 0) {
381
+ return [];
377
382
  }
378
- return await Promise.all(
379
- (await this.basePlanService.listPlans({ ids: planIds }, em)).map(
380
- async (plan) => ({
381
- ...plan,
382
- stripeFields: plans.data.find(
383
- (stripePlan) => stripePlan.id === plan.externalId
384
- )
385
- })
386
- )
383
+ const stripePlans = await Promise.all(
384
+ plans.map(async (plan) => {
385
+ try {
386
+ return await this.stripeClient.plans.retrieve(plan.externalId);
387
+ } catch {
388
+ return null;
389
+ }
390
+ })
387
391
  );
392
+ return plans.map((plan, index) => ({
393
+ ...plan,
394
+ stripeFields: stripePlans[index]
395
+ })).filter((plan) => plan.stripeFields !== null);
388
396
  }
389
397
  };
390
398
 
@@ -434,94 +442,127 @@ var StripeSubscriptionService = class {
434
442
  }
435
443
  async getSubscription(idDto, em) {
436
444
  const subscriptionEntity = await this.baseSubscriptionService.getSubscription(idDto, em);
445
+ if (!subscriptionEntity.externalId) {
446
+ throw new Error("Subscription not found");
447
+ }
437
448
  const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
438
- idDto.id
449
+ subscriptionEntity.externalId
439
450
  );
440
451
  subscriptionEntity.stripeFields = stripeSubscription;
441
452
  return subscriptionEntity;
442
453
  }
443
454
  async getUserSubscription(idDto, em) {
444
455
  const subscriptionEntity = await this.baseSubscriptionService.getUserSubscription(idDto, em);
456
+ if (!subscriptionEntity.externalId) {
457
+ throw new Error("Subscription not found");
458
+ }
445
459
  const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
446
- idDto.id
460
+ subscriptionEntity.externalId
447
461
  );
448
462
  subscriptionEntity.stripeFields = stripeSubscription;
449
463
  return subscriptionEntity;
450
464
  }
451
465
  async getOrganizationSubscription(idDto, em) {
452
- const id = (await em?.findOne(
453
- this.options?.databaseTableName ?? "subscription",
454
- { externalId: idDto.id }
455
- ))?.id;
456
- if (!id) {
466
+ const subscriptionEntity = await this.baseSubscriptionService.getOrganizationSubscription(idDto, em);
467
+ if (!subscriptionEntity.externalId) {
457
468
  throw new Error("Subscription not found");
458
469
  }
459
- const subscriptionEntity = await this.baseSubscriptionService.getOrganizationSubscription(
460
- { id },
461
- em
462
- );
463
470
  const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
464
- idDto.id
471
+ subscriptionEntity.externalId
465
472
  );
466
473
  subscriptionEntity.stripeFields = stripeSubscription;
467
474
  return subscriptionEntity;
468
475
  }
469
476
  async updateSubscription(subscriptionDto, em) {
470
- const subscription = await this.stripeClient.subscriptions.update(
471
- subscriptionDto.id,
477
+ const subscriptionEntity = await this.baseSubscriptionService.getSubscription(
478
+ {
479
+ id: subscriptionDto.id
480
+ },
481
+ em
482
+ );
483
+ if (!subscriptionEntity.externalId) {
484
+ throw new Error("Subscription not found");
485
+ }
486
+ const existingStripeSubscription = await this.stripeClient.subscriptions.retrieve(
487
+ subscriptionEntity.externalId
488
+ );
489
+ const updatedSubscription = await this.stripeClient.subscriptions.update(
490
+ subscriptionEntity.externalId,
472
491
  {
473
492
  ...subscriptionDto.stripeFields,
474
- items: [
475
- {
476
- plan: subscriptionDto.productId
477
- }
478
- ]
493
+ items: existingStripeSubscription.items.data.map((item) => ({
494
+ id: item.id,
495
+ plan: subscriptionDto.productId || item.plan?.id
496
+ }))
479
497
  }
480
498
  );
481
- return await this.baseSubscriptionService.updateSubscription(
499
+ const updatedSubscriptionEntity = await this.baseSubscriptionService.updateSubscription(
482
500
  {
483
501
  ...subscriptionDto,
484
- externalId: subscription.id,
485
- billingProvider: "stripe",
486
- providerFields: subscription
502
+ externalId: updatedSubscription.id,
503
+ billingProvider: "stripe"
487
504
  },
488
505
  em ?? this.em,
489
- subscription
506
+ updatedSubscription
490
507
  );
508
+ updatedSubscriptionEntity.stripeFields = updatedSubscription;
509
+ return updatedSubscriptionEntity;
491
510
  }
492
511
  async deleteSubscription(idDto, em) {
493
- await this.stripeClient.subscriptions.cancel(idDto.id);
512
+ const subscription = await this.baseSubscriptionService.getSubscription(
513
+ idDto,
514
+ em
515
+ );
516
+ if (!subscription.externalId) {
517
+ throw new Error("Subscription not found");
518
+ }
519
+ await this.stripeClient.subscriptions.cancel(subscription.externalId);
494
520
  await this.baseSubscriptionService.deleteSubscription(idDto, em);
495
521
  }
496
522
  async listSubscriptions(idsDto, em) {
497
- const subscriptions = (await this.stripeClient.subscriptions.list({
498
- status: "active"
499
- })).data.filter((s) => idsDto.ids?.includes(s.id));
500
- const ids = (await em?.findAll(
501
- this.options?.databaseTableName ?? "subscription",
502
- { where: { externalId: { $in: subscriptions.map((s) => s.id) } } }
503
- ))?.map((s) => s.id);
504
- if (!ids) {
505
- throw new Error("Subscriptions not found");
523
+ const subscriptions = await this.baseSubscriptionService.listSubscriptions(
524
+ idsDto,
525
+ em
526
+ );
527
+ if (!subscriptions || subscriptions.length === 0) {
528
+ return [];
506
529
  }
507
- return await Promise.all(
508
- (await this.baseSubscriptionService.listSubscriptions({ ids }, em)).map(
509
- async (subscription) => {
510
- const stripeSubscription = subscriptions.find(
511
- (s) => s.id === subscription.externalId
530
+ const stripeSubscriptions = await Promise.all(
531
+ subscriptions.map(async (subscription) => {
532
+ try {
533
+ return await this.stripeClient.subscriptions.retrieve(
534
+ subscription.externalId
512
535
  );
513
- subscription.stripeFields = stripeSubscription;
514
- return subscription;
536
+ } catch {
537
+ return null;
515
538
  }
516
- )
539
+ })
517
540
  );
541
+ return subscriptions.map((subscription, index) => ({
542
+ ...subscription,
543
+ stripeFields: stripeSubscriptions[index]
544
+ })).filter((subscription) => subscription.stripeFields !== null);
518
545
  }
519
546
  async cancelSubscription(idDto, em) {
520
- await this.stripeClient.subscriptions.cancel(idDto.id);
547
+ const subscription = await this.baseSubscriptionService.getSubscription(
548
+ idDto,
549
+ em
550
+ );
551
+ if (!subscription.externalId) {
552
+ throw new Error("Subscription not found");
553
+ }
554
+ await this.stripeClient.subscriptions.cancel(subscription.externalId);
521
555
  await this.baseSubscriptionService.cancelSubscription(idDto, em);
522
556
  }
523
557
  async resumeSubscription(idDto, em) {
524
- await this.stripeClient.subscriptions.resume(idDto.id);
558
+ const subscription = await this.baseSubscriptionService.getSubscription(
559
+ idDto,
560
+ em
561
+ );
562
+ if (!subscription.externalId) {
563
+ throw new Error("Subscription not found");
564
+ }
565
+ await this.stripeClient.subscriptions.resume(subscription.externalId);
525
566
  await this.baseSubscriptionService.resumeSubscription(idDto, em);
526
567
  }
527
568
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forklaunch/implementation-billing-stripe",
3
- "version": "0.4.4",
3
+ "version": "0.5.1",
4
4
  "description": "Stripe implementation for forklaunch billing",
5
5
  "homepage": "https://github.com/forklaunch/forklaunch-js#readme",
6
6
  "bugs": {
@@ -42,20 +42,20 @@
42
42
  "lib/**"
43
43
  ],
44
44
  "dependencies": {
45
- "@forklaunch/common": "^0.6.14",
46
- "@forklaunch/core": "^0.15.3",
47
- "@forklaunch/internal": "^0.3.14",
48
- "@forklaunch/validator": "^0.10.14",
49
- "@mikro-orm/core": "^6.5.6",
45
+ "@forklaunch/common": "^0.6.18",
46
+ "@forklaunch/core": "^0.15.7",
47
+ "@forklaunch/internal": "^0.3.18",
48
+ "@forklaunch/validator": "^0.10.18",
49
+ "@mikro-orm/core": "^6.5.7",
50
50
  "@sinclair/typebox": "^0.34.41",
51
51
  "ajv": "^8.17.1",
52
- "stripe": "^18.5.0",
53
- "zod": "^4.1.11",
54
- "@forklaunch/implementation-billing-base": "0.7.4",
55
- "@forklaunch/interfaces-billing": "0.7.3"
52
+ "stripe": "^19.1.0",
53
+ "zod": "^4.1.12",
54
+ "@forklaunch/implementation-billing-base": "0.8.1",
55
+ "@forklaunch/interfaces-billing": "0.8.1"
56
56
  },
57
57
  "devDependencies": {
58
- "@typescript/native-preview": "7.0.0-dev.20250930.1",
58
+ "@typescript/native-preview": "7.0.0-dev.20251008.1",
59
59
  "depcheck": "^1.4.7",
60
60
  "prettier": "^3.6.2",
61
61
  "typedoc": "^0.28.13"