diff --git a/packages/vendure-plugin-stripe-subscription/README.md b/packages/vendure-plugin-stripe-subscription/README.md index 77193c1a..2d12f9e6 100644 --- a/packages/vendure-plugin-stripe-subscription/README.md +++ b/packages/vendure-plugin-stripe-subscription/README.md @@ -66,8 +66,7 @@ plugins: [ 6. Start the Vendure server and login to the admin UI 7. Go to `Settings > Subscriptions` and create a Schedule. 8. Create a variant and select a schedule in the variant detail screen in the admin UI. -9. Create a payment method with the code `stripe-subscription-payment` and select `stripe-subscription` as handler. ** - Your payment method MUST have 'stripe-subscription' in the code field** +9. Create a payment method with the code `stripe-subscription-payment` and select `stripe-subscription` as handler. You can (and should) have only 1 payment method with the Stripe Subscription handler per channel. 10. Set your API key from Stripe in the apiKey field. 11. Get the webhook secret from you Stripe dashboard and save it on the payment method. diff --git a/packages/vendure-plugin-stripe-subscription/src/api/stripe-subscription.controller.ts b/packages/vendure-plugin-stripe-subscription/src/api/stripe-subscription.controller.ts index f38ee3e2..7a53b1e6 100644 --- a/packages/vendure-plugin-stripe-subscription/src/api/stripe-subscription.controller.ts +++ b/packages/vendure-plugin-stripe-subscription/src/api/stripe-subscription.controller.ts @@ -256,7 +256,7 @@ export class StripeSubscriptionController { } // Validate signature const { stripeClient } = - await this.stripeSubscriptionService.getStripeHandler(ctx, order.id); + await this.stripeSubscriptionService.getStripeContext(ctx); if (!this.options?.disableWebhookSignatureChecking) { stripeClient.validateWebhookSignature(request.rawBody, signature); } diff --git a/packages/vendure-plugin-stripe-subscription/src/api/stripe-subscription.handler.ts b/packages/vendure-plugin-stripe-subscription/src/api/stripe-subscription.handler.ts index 071a7c2e..6bc2ae23 100644 --- a/packages/vendure-plugin-stripe-subscription/src/api/stripe-subscription.handler.ts +++ b/packages/vendure-plugin-stripe-subscription/src/api/stripe-subscription.handler.ts @@ -6,22 +6,10 @@ import { Logger, PaymentMethodHandler, SettlePaymentResult, - UserInputError, } from '@vendure/core'; -import { RequestContext } from '@vendure/core/dist/api/common/request-context'; -import { Order, Payment, PaymentMethod } from '@vendure/core/dist/entity'; -import { - CancelPaymentErrorResult, - CancelPaymentResult, -} from '@vendure/core/dist/config/payment/payment-method-handler'; -import { - OrderLineWithSubscriptionFields, - OrderWithSubscriptionFields, -} from './subscription-custom-fields'; -import { StripeSubscriptionService } from './stripe-subscription.service'; -import { StripeClient } from './stripe.client'; import { loggerCtx } from '../constants'; import { printMoney } from './pricing.helper'; +import { StripeSubscriptionService } from './stripe-subscription.service'; let service: StripeSubscriptionService; export const stripeSubscriptionHandler = new PaymentMethodHandler({ @@ -111,7 +99,7 @@ export const stripeSubscriptionHandler = new PaymentMethodHandler({ payment, args ): Promise { - const { stripeClient } = await service.getStripeHandler(ctx, order.id); + const { stripeClient } = await service.getStripeContext(ctx); const refund = await stripeClient.refunds.create({ payment_intent: payment.transactionId, amount, diff --git a/packages/vendure-plugin-stripe-subscription/src/api/stripe-subscription.service.ts b/packages/vendure-plugin-stripe-subscription/src/api/stripe-subscription.service.ts index 8d46ac16..f516594d 100644 --- a/packages/vendure-plugin-stripe-subscription/src/api/stripe-subscription.service.ts +++ b/packages/vendure-plugin-stripe-subscription/src/api/stripe-subscription.service.ts @@ -23,6 +23,7 @@ import { OrderService, OrderStateTransitionError, PaginatedList, + PaymentMethod, PaymentMethodService, ProductVariantService, RequestContext, @@ -63,10 +64,9 @@ import { StripeSubscriptionPayment } from './stripe-subscription-payment.entity' import { StripeInvoice } from './types/stripe-invoice'; import { StripePaymentIntent } from './types/stripe-payment-intent'; -export interface StripeHandlerConfig { - paymentMethodCode: string; +export interface StripeContext { + paymentMethod: PaymentMethod; stripeClient: StripeClient; - webhookSecret: string; } interface CreateSubscriptionsJob { @@ -212,7 +212,7 @@ export class StripeSubscriptionService { ); } await this.entityHydrator.hydrate(ctx, line, { relations: ['order'] }); - const { stripeClient } = await this.getStripeHandler(ctx, line.order.id); + const { stripeClient } = await this.getStripeContext(ctx); for (const subscriptionId of line.customFields.subscriptionIds) { try { await stripeClient.subscriptions.update(subscriptionId, { @@ -245,11 +245,9 @@ export class StripeSubscriptionService { } /** - * + * */ - async getSubscriptions(ctx: RequestContext) { - - } + async getSubscriptions(ctx: RequestContext) {} async createPaymentIntent(ctx: RequestContext): Promise { let order = (await this.activeOrderService.getActiveOrder( @@ -283,8 +281,10 @@ export class StripeSubscriptionService { 'Cannot create payment intent for order without shippingMethod' ); } - const { stripeClient } = await this.getStripeHandler(ctx, order.id); - const stripeCustomer = await stripeClient.getOrCreateClient(order.customer); + const { stripeClient } = await this.getStripeContext(ctx); + const stripeCustomer = await stripeClient.getOrCreateCustomer( + order.customer + ); this.customerService .update(ctx, { id: order.customer.id, @@ -505,7 +505,9 @@ export class StripeSubscriptionService { object: StripePaymentIntent, order: Order ): Promise { - const { paymentMethodCode } = await this.getStripeHandler(ctx, order.id); + const { + paymentMethod: { code: paymentMethodCode }, + } = await this.getStripeContext(ctx); if (!object.customer) { await this.logHistoryEntry( ctx, @@ -592,7 +594,7 @@ export class StripeSubscriptionService { `Not creating subscriptions for order ${order.code}, because it doesn't have any subscription products` ); } - const { stripeClient } = await this.getStripeHandler(ctx, order.id); + const { stripeClient } = await this.getStripeContext(ctx); const customer = await stripeClient.customers.retrieve(stripeCustomerId); if (!customer) { throw Error( @@ -775,32 +777,25 @@ export class StripeSubscriptionService { } /** - * Get the paymentMethod with the stripe handler, should be only 1! + * Get the Stripe context for the current channel. + * The Stripe context consists of the Stripe client and the Vendure payment method connected to the Stripe account */ - async getStripeHandler( - ctx: RequestContext, - orderId: ID - ): Promise { - const paymentMethodQuotes = - await this.orderService.getEligiblePaymentMethods(ctx, orderId); - const paymentMethodQuote = paymentMethodQuotes - .filter((quote) => quote.isEligible) - .find((pm) => pm.code.indexOf('stripe-subscription') > -1); - if (!paymentMethodQuote) { + async getStripeContext(ctx: RequestContext): Promise { + const paymentMethods = await this.paymentMethodService.findAll(ctx, { + filter: { enabled: { eq: true } }, + }); + const stripePaymentMethods = paymentMethods.items.filter( + (pm) => pm.handler.code === stripeSubscriptionHandler.code + ); + if (stripePaymentMethods.length > 1) { throw new UserInputError( - `No eligible payment method found with code 'stripe-subscription'` + `Multiple payment methods found with handler 'stripe-subscription', there should only be 1 per channel!` ); } - const paymentMethod = await this.paymentMethodService.findOne( - ctx, - paymentMethodQuote.id - ); - if ( - !paymentMethod || - paymentMethod.handler.code !== stripeSubscriptionHandler.code - ) { + const paymentMethod = stripePaymentMethods[0]; + if (!paymentMethod) { throw new UserInputError( - `Payment method '${paymentMethodQuote.code}' doesn't have handler '${stripeSubscriptionHandler.code}' configured.` + `No enabled payment method found with handler 'stripe-subscription'` ); } const apiKey = paymentMethod.handler.args.find( @@ -819,11 +814,10 @@ export class StripeSubscriptionService { ); } return { - paymentMethodCode: paymentMethod.code, + paymentMethod: paymentMethod, stripeClient: new StripeClient(webhookSecret, apiKey, { apiVersion: null as any, // Null uses accounts default version }), - webhookSecret, }; } diff --git a/packages/vendure-plugin-stripe-subscription/src/api/stripe.client.ts b/packages/vendure-plugin-stripe-subscription/src/api/stripe.client.ts index 4bd0cc15..625b93c5 100644 --- a/packages/vendure-plugin-stripe-subscription/src/api/stripe.client.ts +++ b/packages/vendure-plugin-stripe-subscription/src/api/stripe.client.ts @@ -21,14 +21,14 @@ interface SubscriptionInput { */ export class StripeClient extends Stripe { constructor( - private webhookSecret: string, + public webhookSecret: string, apiKey: string, config: Stripe.StripeConfig ) { super(apiKey, config); } - async getOrCreateClient( + async getOrCreateCustomer( customer: CustomerWithSubscriptionFields ): Promise { if (customer.customFields?.stripeSubscriptionCustomerId) {