From df62e618bcc365ef376b96705d63b465b48b0191 Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Tue, 4 Oct 2022 10:49:43 +0200 Subject: [PATCH] feat(medusa,medusa-payment-stripe): Migrate Stripe to Abstract payment service (#1790) --- .changeset/nine-trainers-protect.md | 6 + .../src/__mocks__/cart.js | 3 + .../src/__mocks__/customer.js | 3 + .../src/__mocks__/totals.js | 3 + .../src/api/middlewares/await-middleware.js | 4 +- .../src/api/routes/hooks/stripe.js | 24 ++- .../src/services/__mocks__/stripe-provider.js | 3 + .../src/services/__tests__/stripe-provider.js | 3 + .../src/services/stripe-bancontact.js | 141 ++++++++++------- .../src/services/stripe-blik.js | 137 +++++++++------- .../src/services/stripe-giropay.js | 147 ++++++++++-------- .../src/services/stripe-ideal.js | 122 +++++++++------ .../src/services/stripe-provider.js | 107 +++++++------ .../src/services/stripe-przelewy24.js | 118 ++++++++------ .../src/subscribers/cart.js | 72 +++++---- .../medusa/src/interfaces/payment-service.ts | 7 +- packages/medusa/src/loaders/defaults.ts | 16 +- packages/medusa/src/services/cart.ts | 9 +- .../medusa/src/services/payment-provider.ts | 8 +- 19 files changed, 546 insertions(+), 387 deletions(-) create mode 100644 .changeset/nine-trainers-protect.md diff --git a/.changeset/nine-trainers-protect.md b/.changeset/nine-trainers-protect.md new file mode 100644 index 0000000000..4c1f473886 --- /dev/null +++ b/.changeset/nine-trainers-protect.md @@ -0,0 +1,6 @@ +--- +"medusa-payment-stripe": patch +"@medusajs/medusa": patch +--- + +Migrate Stripe providers to the new AbstractPaymentService diff --git a/packages/medusa-payment-stripe/src/__mocks__/cart.js b/packages/medusa-payment-stripe/src/__mocks__/cart.js index 062dc1003b..c3a5bd01d0 100644 --- a/packages/medusa-payment-stripe/src/__mocks__/cart.js +++ b/packages/medusa-payment-stripe/src/__mocks__/cart.js @@ -185,6 +185,9 @@ export const carts = { } export const CartServiceMock = { + withTransaction: function () { + return this + }, retrieve: jest.fn().mockImplementation((cartId) => { if (cartId === IdMap.getId("fr-cart")) { return Promise.resolve(carts.frCart) diff --git a/packages/medusa-payment-stripe/src/__mocks__/customer.js b/packages/medusa-payment-stripe/src/__mocks__/customer.js index 8d197e14d7..421f661e88 100644 --- a/packages/medusa-payment-stripe/src/__mocks__/customer.js +++ b/packages/medusa-payment-stripe/src/__mocks__/customer.js @@ -1,6 +1,9 @@ import { IdMap } from "medusa-test-utils" export const CustomerServiceMock = { + withTransaction: function () { + return this + }, retrieve: jest.fn().mockImplementation((id) => { if (id === IdMap.getId("lebron")) { return Promise.resolve({ diff --git a/packages/medusa-payment-stripe/src/__mocks__/totals.js b/packages/medusa-payment-stripe/src/__mocks__/totals.js index e4b1f117e3..5163d4ee66 100644 --- a/packages/medusa-payment-stripe/src/__mocks__/totals.js +++ b/packages/medusa-payment-stripe/src/__mocks__/totals.js @@ -1,4 +1,7 @@ export const TotalsServiceMock = { + withTransaction: function () { + return this + }, getTotal: jest.fn(), } diff --git a/packages/medusa-payment-stripe/src/api/middlewares/await-middleware.js b/packages/medusa-payment-stripe/src/api/middlewares/await-middleware.js index 1c3692b377..ca4821e6af 100644 --- a/packages/medusa-payment-stripe/src/api/middlewares/await-middleware.js +++ b/packages/medusa-payment-stripe/src/api/middlewares/await-middleware.js @@ -1 +1,3 @@ -export default (fn) => (...args) => fn(...args).catch(args[2]) +export default (fn) => + (...args) => + fn(...args).catch(args[2]) diff --git a/packages/medusa-payment-stripe/src/api/routes/hooks/stripe.js b/packages/medusa-payment-stripe/src/api/routes/hooks/stripe.js index 65538328ae..f83ebac942 100644 --- a/packages/medusa-payment-stripe/src/api/routes/hooks/stripe.js +++ b/packages/medusa-payment-stripe/src/api/routes/hooks/stripe.js @@ -12,6 +12,7 @@ export default async (req, res) => { const paymentIntent = event.data.object + const manager = req.scope.resolve("manager") const cartService = req.scope.resolve("cartService") const orderService = req.scope.resolve("orderService") @@ -24,24 +25,19 @@ export default async (req, res) => { switch (event.type) { case "payment_intent.succeeded": if (order && order.payment_status !== "captured") { - await orderService.capturePayment(order.id) + await manager.transaction(async (manager) => { + await orderService.withTransaction(manager).capturePayment(order.id) + }) } break - //case "payment_intent.canceled": - // if (order) { - // await orderService.update(order._id, { - // status: "canceled", - // }) - // } - // break - case "payment_intent.payment_failed": - // TODO: Not implemented yet - break case "payment_intent.amount_capturable_updated": if (!order) { - await cartService.setPaymentSession(cartId, "stripe") - await cartService.authorizePayment(cartId) - await orderService.createFromCart(cartId) + await manager.transaction(async (manager) => { + const cartServiceTx = cartService.withTransaction(manager) + await cartServiceTx.setPaymentSession(cartId, "stripe") + await cartServiceTx.authorizePayment(cartId) + await orderService.withTransaction(manager).createFromCart(cartId) + }) } break default: diff --git a/packages/medusa-payment-stripe/src/services/__mocks__/stripe-provider.js b/packages/medusa-payment-stripe/src/services/__mocks__/stripe-provider.js index 89fcacb139..e49467719e 100644 --- a/packages/medusa-payment-stripe/src/services/__mocks__/stripe-provider.js +++ b/packages/medusa-payment-stripe/src/services/__mocks__/stripe-provider.js @@ -1,6 +1,9 @@ import { IdMap } from "medusa-test-utils" export const StripeProviderServiceMock = { + withTransaction: function () { + return this + }, retrievePayment: jest.fn().mockImplementation((payData) => { if (payData.id === "pi_123456789") { return Promise.resolve({ diff --git a/packages/medusa-payment-stripe/src/services/__tests__/stripe-provider.js b/packages/medusa-payment-stripe/src/services/__tests__/stripe-provider.js index 2626623b69..b6eed7d2e2 100644 --- a/packages/medusa-payment-stripe/src/services/__tests__/stripe-provider.js +++ b/packages/medusa-payment-stripe/src/services/__tests__/stripe-provider.js @@ -5,6 +5,9 @@ import { carts } from "../../__mocks__/cart" import { TotalsServiceMock } from "../../__mocks__/totals" const RegionServiceMock = { + withTransaction: function () { + return this + }, retrieve: jest.fn().mockReturnValue(Promise.resolve({})), } diff --git a/packages/medusa-payment-stripe/src/services/stripe-bancontact.js b/packages/medusa-payment-stripe/src/services/stripe-bancontact.js index e6d07f48bc..3516023252 100644 --- a/packages/medusa-payment-stripe/src/services/stripe-bancontact.js +++ b/packages/medusa-payment-stripe/src/services/stripe-bancontact.js @@ -1,15 +1,29 @@ -import _ from "lodash" import Stripe from "stripe" -import { PaymentService } from "medusa-interfaces" +import { AbstractPaymentService, PaymentSessionData } from "@medusajs/medusa" -class BancontactProviderService extends PaymentService { +class BancontactProviderService extends AbstractPaymentService { static identifier = "stripe-bancontact" constructor( - { stripeProviderService, customerService, totalsService, regionService }, + { + stripeProviderService, + customerService, + totalsService, + regionService, + manager, + }, options ) { - super() + super( + { + stripeProviderService, + customerService, + totalsService, + regionService, + manager, + }, + options + ) /** * Required Stripe options: @@ -36,22 +50,25 @@ class BancontactProviderService extends PaymentService { /** @private @const {TotalsService} */ this.totalsService_ = totalsService + + /** @private @const {EntityManager} */ + this.manager_ = manager } /** * Fetches Stripe payment intent. Check its status and returns the * corresponding Medusa status. - * @param {object} paymentData - payment method data from cart - * @returns {string} the status of the payment intent + * @param {PaymentSessionData} paymentSessionData - payment method data from cart + * @return {Promise} the status of the payment intent */ - async getStatus(paymentData) { - return await this.stripeProviderService_.getStatus(paymentData) + async getStatus(paymentSessionData) { + return await this.stripeProviderService_.getStatus(paymentSessionData) } /** * Fetches a customers saved payment methods if registered in Stripe. * @param {object} customer - customer to fetch saved cards for - * @returns {Promise>} saved payments methods + * @return {Promise} saved payments methods */ async retrieveSavedMethods(customer) { return Promise.resolve([]) @@ -60,7 +77,7 @@ class BancontactProviderService extends PaymentService { /** * Fetches a Stripe customer * @param {string} customerId - Stripe customer id - * @returns {Promise} Stripe customer + * @return {Promise} Stripe customer */ async retrieveCustomer(customerId) { return await this.stripeProviderService_.retrieveCustomer(customerId) @@ -69,28 +86,35 @@ class BancontactProviderService extends PaymentService { /** * Creates a Stripe customer using a Medusa customer. * @param {object} customer - Customer data from Medusa - * @returns {Promise} Stripe customer + * @return {Promise} Stripe customer */ async createCustomer(customer) { - return await this.stripeProviderService_.createCustomer(customer) + return await this.stripeProviderService_ + .withTransaction(this.manager_) + .createCustomer(customer) } /** * Creates a Stripe payment intent. * If customer is not registered in Stripe, we do so. - * @param {object} cart - cart to create a payment for - * @returns {object} Stripe payment intent + * @param {Cart} cart - cart to create a payment for + * @return {Promise} Stripe payment intent */ async createPayment(cart) { const { customer_id, region_id, email } = cart - const region = await this.regionService_.retrieve(region_id) + const region = await this.regionService_ + .withTransaction(this.manager_) + .retrieve(region_id) const { currency_code } = region - const amount = await this.totalsService_.getTotal(cart) + const amount = await this.totalsService_ + .withTransaction(this.manager_) + .getTotal(cart) const intentRequest = { amount: Math.round(amount), - description: cart?.context?.payment_description ?? this.options_?.payment_description, + description: + cart?.context?.payment_description ?? this.options?.payment_description, currency: currency_code, payment_method_types: ["bancontact"], capture_method: "automatic", @@ -98,7 +122,9 @@ class BancontactProviderService extends PaymentService { } if (customer_id) { - const customer = await this.customerService_.retrieve(customer_id) + const customer = await this.customerService_ + .withTransaction(this.manager_) + .retrieve(customer_id) if (customer.metadata?.stripe_id) { intentRequest.customer = customer.metadata.stripe_id @@ -118,70 +144,69 @@ class BancontactProviderService extends PaymentService { intentRequest.customer = stripeCustomer.id } - const paymentIntent = await this.stripe_.paymentIntents.create( - intentRequest - ) - - return paymentIntent + return await this.stripe_.paymentIntents.create(intentRequest) } /** * Retrieves Stripe payment intent. - * @param {object} data - the data of the payment to retrieve - * @returns {Promise} Stripe payment intent + * @param {PaymentData} paymentData - the data of the payment to retrieve + * @return {Promise} Stripe payment intent */ - async retrievePayment(data) { - return await this.stripeProviderService_.retrievePayment(data) + async retrievePayment(paymentData) { + return await this.stripeProviderService_.retrievePayment(paymentData) } /** * Gets a Stripe payment intent and returns it. - * @param {object} sessionData - the data of the payment to retrieve - * @returns {Promise} Stripe payment intent + * @param {PaymentSession} paymentSession - the data of the payment to retrieve + * @return {Promise} Stripe payment intent */ - async getPaymentData(sessionData) { - return await this.stripeProviderService_.getPaymentData(sessionData) + async getPaymentData(paymentSession) { + return await this.stripeProviderService_.getPaymentData(paymentSession) } /** * Authorizes Stripe payment intent by simply returning * the status for the payment intent in use. - * @param {object} sessionData - payment session data + * @param {PaymentSession} paymentSession - payment session data * @param {object} context - properties relevant to current context - * @returns {Promise<{ status: string, data: object }>} result with data and status + * @return {Promise<{data: PaymentSessionData; status: PaymentSessionStatus}>} result with data and status */ - async authorizePayment(sessionData, context = {}) { + async authorizePayment(paymentSession, context = {}) { return await this.stripeProviderService_.authorizePayment( - sessionData, + paymentSession, context ) } - async updatePaymentData(sessionData, update) { + async updatePaymentData(paymentSessionData, data) { return await this.stripeProviderService_.updatePaymentData( - sessionData, - update + paymentSessionData, + data ) } /** * Updates Stripe payment intent. - * @param {object} sessionData - payment session data. - * @param {object} update - objec to update intent with - * @returns {object} Stripe payment intent + * @param {PaymentSessionData} paymentSessionData - payment session data. + * @param {Cart} cart + * @return {Promise} Stripe payment intent */ - async updatePayment(sessionData, cart) { + async updatePayment(paymentSessionData, cart) { try { const stripeId = cart.customer?.metadata?.stripe_id || undefined - if (stripeId !== sessionData.customer) { + if (stripeId !== paymentSessionData.customer) { return this.createPayment(cart) } else { - if (cart.total && sessionData.amount === Math.round(cart.total)) { + if ( + cart.total && + paymentSessionData.amount === Math.round(cart.total) + ) { return sessionData } - return this.stripe_.paymentIntents.update(sessionData.id, { + return this.stripe_.paymentIntents.update(paymentSessionData.id, { amount: Math.round(cart.total), }) } @@ -190,15 +215,15 @@ class BancontactProviderService extends PaymentService { } } - async deletePayment(payment) { - return await this.stripeProviderService_.deletePayment(payment) + async deletePayment(paymentSession) { + return await this.stripeProviderService_.deletePayment(paymentSession) } /** * Updates customer of Stripe payment intent. * @param {string} paymentIntentId - id of payment intent to update * @param {string} customerId - id of new Stripe customer - * @returns {object} Stripe payment intent + * @return {object} Stripe payment intent */ async updatePaymentIntentCustomer(paymentIntentId, customerId) { return await this.stripeProviderService_.updatePaymentIntentCustomer( @@ -209,8 +234,8 @@ class BancontactProviderService extends PaymentService { /** * Captures payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @returns {object} Stripe payment intent + * @param {Payment} payment - payment method data from cart + * @return {Promise} Stripe payment intent */ async capturePayment(payment) { return await this.stripeProviderService_.capturePayment(payment) @@ -218,21 +243,21 @@ class BancontactProviderService extends PaymentService { /** * Refunds payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @param {number} amountToRefund - amount to refund - * @returns {string} refunded payment intent + * @param {Payment} payment - payment method data from cart + * @param {number} refundAmount - amount to refund + * @return {Promise} refunded payment intent */ - async refundPayment(payment, amountToRefund) { + async refundPayment(payment, refundAmount) { return await this.stripeProviderService_.refundPayment( payment, - amountToRefund + refundAmount ) } /** * Cancels payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @returns {object} canceled payment intent + * @param {Payment} payment - payment method data from cart + * @return {Promise} canceled payment intent */ async cancelPayment(payment) { return await this.stripeProviderService_.cancelPayment(payment) diff --git a/packages/medusa-payment-stripe/src/services/stripe-blik.js b/packages/medusa-payment-stripe/src/services/stripe-blik.js index fc7e07845a..d7d5c4bb71 100644 --- a/packages/medusa-payment-stripe/src/services/stripe-blik.js +++ b/packages/medusa-payment-stripe/src/services/stripe-blik.js @@ -1,15 +1,29 @@ -import _ from "lodash" import Stripe from "stripe" -import { PaymentService } from "medusa-interfaces" +import { AbstractPaymentService, PaymentSessionStatus } from "@medusajs/medusa" -class BlikProviderService extends PaymentService { +class BlikProviderService extends AbstractPaymentService { static identifier = "stripe-blik" constructor( - { stripeProviderService, customerService, totalsService, regionService }, + { + stripeProviderService, + customerService, + totalsService, + regionService, + manager, + }, options ) { - super() + super( + { + stripeProviderService, + customerService, + totalsService, + regionService, + manager, + }, + options + ) /** * Required Stripe options: @@ -36,22 +50,24 @@ class BlikProviderService extends PaymentService { /** @private @const {TotalsService} */ this.totalsService_ = totalsService + + this.manager_ = manager } /** * Fetches Stripe payment intent. Check its status and returns the * corresponding Medusa status. - * @param {object} paymentData - payment method data from cart - * @returns {string} the status of the payment intent + * @param {PaymentSessionData} paymentSessionData - payment method data from cart + * @return {Promise} the status of the payment intent */ - async getStatus(paymentData) { - return await this.stripeProviderService_.getStatus(paymentData) + async getStatus(paymentSessionData) { + return await this.stripeProviderService_.getStatus(paymentSessionData) } /** * Fetches a customers saved payment methods if registered in Stripe. * @param {object} customer - customer to fetch saved cards for - * @returns {Promise>} saved payments methods + * @return {Promise} saved payments methods */ async retrieveSavedMethods(customer) { return Promise.resolve([]) @@ -60,7 +76,7 @@ class BlikProviderService extends PaymentService { /** * Fetches a Stripe customer * @param {string} customerId - Stripe customer id - * @returns {Promise} Stripe customer + * @return {Promise} Stripe customer */ async retrieveCustomer(customerId) { return await this.stripeProviderService_.retrieveCustomer(customerId) @@ -69,24 +85,30 @@ class BlikProviderService extends PaymentService { /** * Creates a Stripe customer using a Medusa customer. * @param {object} customer - Customer data from Medusa - * @returns {Promise} Stripe customer + * @return {Promise} Stripe customer */ async createCustomer(customer) { - return await this.stripeProviderService_.createCustomer(customer) + return await this.stripeProviderService_ + .withTransaction(this.manager_) + .createCustomer(customer) } /** * Creates a Stripe payment intent. * If customer is not registered in Stripe, we do so. - * @param {object} cart - cart to create a payment for - * @returns {object} Stripe payment intent + * @param {Cart} cart - cart to create a payment for + * @returns {PaymentSessionData} Stripe payment intent */ async createPayment(cart) { const { customer_id, region_id, email } = cart - const region = await this.regionService_.retrieve(region_id) + const region = await this.regionService_ + .withTransaction(this.manager_) + .retrieve(region_id) const { currency_code } = region - const amount = await this.totalsService_.getTotal(cart) + const amount = await this.totalsService_ + .withTransaction(this.manager_) + .getTotal(cart) const intentRequest = { amount: Math.round(amount), @@ -97,7 +119,9 @@ class BlikProviderService extends PaymentService { } if (customer_id) { - const customer = await this.customerService_.retrieve(customer_id) + const customer = await this.customerService_ + .withTransaction(this.manager_) + .retrieve(customer_id) if (customer.metadata?.stripe_id) { intentRequest.customer = customer.metadata.stripe_id @@ -117,70 +141,69 @@ class BlikProviderService extends PaymentService { intentRequest.customer = stripeCustomer.id } - const paymentIntent = await this.stripe_.paymentIntents.create( - intentRequest - ) - - return paymentIntent + return await this.stripe_.paymentIntents.create(intentRequest) } /** * Retrieves Stripe payment intent. - * @param {object} data - the data of the payment to retrieve - * @returns {Promise} Stripe payment intent + * @param {PaymentData} paymentData - the data of the payment to retrieve + * @return {Promise} Stripe payment intent */ - async retrievePayment(data) { - return await this.stripeProviderService_.retrievePayment(data) + async retrievePayment(paymentData) { + return await this.stripeProviderService_.retrievePayment(paymentData) } /** * Gets a Stripe payment intent and returns it. - * @param {object} sessionData - the data of the payment to retrieve - * @returns {Promise} Stripe payment intent + * @param {PaymentSession} paymentSession - the data of the payment to retrieve + * @return {Promise} Stripe payment intent */ - async getPaymentData(sessionData) { - return await this.stripeProviderService_.getPaymentData(sessionData) + async getPaymentData(paymentSession) { + return await this.stripeProviderService_.getPaymentData(paymentSession) } /** * Authorizes Stripe payment intent by simply returning * the status for the payment intent in use. - * @param {object} sessionData - payment session data + * @param {PaymentSession} paymentSession - payment session data * @param {object} context - properties relevant to current context - * @returns {Promise<{ status: string, data: object }>} result with data and status + * @return {Promise<{data: PaymentSessionData; status: PaymentSessionStatus}>} result with data and status */ - async authorizePayment(sessionData, context = {}) { + async authorizePayment(paymentSession, context = {}) { return await this.stripeProviderService_.authorizePayment( - sessionData, + paymentSession, context ) } - async updatePaymentData(sessionData, update) { + async updatePaymentData(paymentSessionData, data) { return await this.stripeProviderService_.updatePaymentData( - sessionData, - update + paymentSessionData, + data ) } /** * Updates Stripe payment intent. - * @param {object} sessionData - payment session data. - * @param {object} update - objec to update intent with - * @returns {object} Stripe payment intent + * @param {PaymentSessionData} paymentSessionData - payment session data. + * @param {Cart} cart + * @return {Promise} Stripe payment intent */ - async updatePayment(sessionData, cart) { + async updatePayment(paymentSessionData, cart) { try { const stripeId = cart.customer?.metadata?.stripe_id || undefined - if (stripeId !== sessionData.customer) { + if (stripeId !== paymentSessionData.customer) { return this.createPayment(cart) } else { - if (cart.total && sessionData.amount === Math.round(cart.total)) { + if ( + cart.total && + paymentSessionData.amount === Math.round(cart.total) + ) { return sessionData } - return this.stripe_.paymentIntents.update(sessionData.id, { + return this.stripe_.paymentIntents.update(paymentSessionData.id, { amount: Math.round(cart.total), }) } @@ -189,15 +212,15 @@ class BlikProviderService extends PaymentService { } } - async deletePayment(payment) { - return await this.stripeProviderService_.deletePayment(payment) + async deletePayment(paymentSession) { + return await this.stripeProviderService_.deletePayment(paymentSession) } /** * Updates customer of Stripe payment intent. * @param {string} paymentIntentId - id of payment intent to update * @param {string} customerId - id of new Stripe customer - * @returns {object} Stripe payment intent + * @return {object} Stripe payment intent */ async updatePaymentIntentCustomer(paymentIntentId, customerId) { return await this.stripeProviderService_.updatePaymentIntentCustomer( @@ -208,8 +231,8 @@ class BlikProviderService extends PaymentService { /** * Captures payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @returns {object} Stripe payment intent + * @param {Payment} payment - payment method data from cart + * @return {Promise} Stripe payment intent */ async capturePayment(payment) { return await this.stripeProviderService_.capturePayment(payment) @@ -217,21 +240,21 @@ class BlikProviderService extends PaymentService { /** * Refunds payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @param {number} amountToRefund - amount to refund - * @returns {string} refunded payment intent + * @param {Payment} payment - payment method data from cart + * @param {number} refundAmount - amount to refund + * @return {Promise} refunded payment intent */ - async refundPayment(payment, amountToRefund) { + async refundPayment(payment, refundAmount) { return await this.stripeProviderService_.refundPayment( payment, - amountToRefund + refundAmount ) } /** * Cancels payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @returns {object} canceled payment intent + * @param {Payment} payment - payment method data from cart + * @return {Promise} canceled payment intent */ async cancelPayment(payment) { return await this.stripeProviderService_.cancelPayment(payment) diff --git a/packages/medusa-payment-stripe/src/services/stripe-giropay.js b/packages/medusa-payment-stripe/src/services/stripe-giropay.js index 89409d6160..1f61f1b9ea 100644 --- a/packages/medusa-payment-stripe/src/services/stripe-giropay.js +++ b/packages/medusa-payment-stripe/src/services/stripe-giropay.js @@ -1,15 +1,29 @@ -import _ from "lodash" import Stripe from "stripe" -import { PaymentService } from "medusa-interfaces" +import { AbstractPaymentService, PaymentSessionStatus } from "@medusajs/medusa" -class GiropayProviderService extends PaymentService { +class GiropayProviderService extends AbstractPaymentService { static identifier = "stripe-giropay" constructor( - { stripeProviderService, customerService, totalsService, regionService }, + { + stripeProviderService, + customerService, + totalsService, + regionService, + manager, + }, options ) { - super() + super( + { + stripeProviderService, + customerService, + totalsService, + regionService, + manager, + }, + options + ) /** * Required Stripe options: @@ -36,22 +50,25 @@ class GiropayProviderService extends PaymentService { /** @private @const {TotalsService} */ this.totalsService_ = totalsService + + /** @private @const {EntityManager} */ + this.manager_ = manager } /** * Fetches Stripe payment intent. Check its status and returns the * corresponding Medusa status. - * @param {object} paymentData - payment method data from cart - * @returns {string} the status of the payment intent + * @param {PaymentSessionData} paymentSessionData - payment method data from cart + * @return {Promise} the status of the payment intent */ - async getStatus(paymentData) { - return await this.stripeProviderService_.getStatus(paymentData) + async getStatus(paymentSessionData) { + return await this.stripeProviderService_.getStatus(paymentSessionData) } /** * Fetches a customers saved payment methods if registered in Stripe. - * @param {object} customer - customer to fetch saved cards for - * @returns {Promise>} saved payments methods + * @param {Customer} customer - customer to fetch saved cards for + * @return {Promise} saved payments methods */ async retrieveSavedMethods(customer) { return Promise.resolve([]) @@ -60,7 +77,7 @@ class GiropayProviderService extends PaymentService { /** * Fetches a Stripe customer * @param {string} customerId - Stripe customer id - * @returns {Promise} Stripe customer + * @return {Promise} Stripe customer */ async retrieveCustomer(customerId) { return await this.stripeProviderService_.retrieveCustomer(customerId) @@ -69,28 +86,35 @@ class GiropayProviderService extends PaymentService { /** * Creates a Stripe customer using a Medusa customer. * @param {object} customer - Customer data from Medusa - * @returns {Promise} Stripe customer + * @return {Promise} Stripe customer */ async createCustomer(customer) { - return await this.stripeProviderService_.createCustomer(customer) + return await this.stripeProviderService_ + .withTransaction(this.manager_) + .createCustomer(customer) } /** * Creates a Stripe payment intent. * If customer is not registered in Stripe, we do so. - * @param {object} cart - cart to create a payment for - * @returns {object} Stripe payment intent + * @param {Cart} cart - cart to create a payment for + * @return {Promise} Stripe payment intent */ async createPayment(cart) { const { customer_id, region_id, email } = cart - const region = await this.regionService_.retrieve(region_id) + const region = await this.regionService_ + .withTransaction(this.manager_) + .retrieve(region_id) const { currency_code } = region - const amount = await this.totalsService_.getTotal(cart) + const amount = await this.totalsService_ + .withTransaction(this.manager_) + .getTotal(cart) const intentRequest = { amount: Math.round(amount), - description: cart?.context?.payment_description ?? this.options_?.payment_description, + description: + cart?.context?.payment_description ?? this.options?.payment_description, currency: currency_code, payment_method_types: ["giropay"], capture_method: "automatic", @@ -98,7 +122,9 @@ class GiropayProviderService extends PaymentService { } if (customer_id) { - const customer = await this.customerService_.retrieve(customer_id) + const customer = await this.customerService_ + .withTransaction(this.manager_) + .retrieve(customer_id) if (customer.metadata?.stripe_id) { intentRequest.customer = customer.metadata.stripe_id @@ -118,70 +144,69 @@ class GiropayProviderService extends PaymentService { intentRequest.customer = stripeCustomer.id } - const paymentIntent = await this.stripe_.paymentIntents.create( - intentRequest - ) - - return paymentIntent + return await this.stripe_.paymentIntents.create(intentRequest) } /** * Retrieves Stripe payment intent. - * @param {object} data - the data of the payment to retrieve - * @returns {Promise} Stripe payment intent + * @param {PaymentData} paymentData - the data of the payment to retrieve + * @return {Promise} Stripe payment intent */ - async retrievePayment(data) { - return await this.stripeProviderService_.retrievePayment(data) + async retrievePayment(paymentData) { + return await this.stripeProviderService_.retrievePayment(paymentData) } /** * Gets a Stripe payment intent and returns it. - * @param {object} sessionData - the data of the payment to retrieve - * @returns {Promise} Stripe payment intent + * @param {PaymentSession} paymentSession - the data of the payment to retrieve + * @return {Promise} Stripe payment intent */ - async getPaymentData(sessionData) { - return await this.stripeProviderService_.getPaymentData(sessionData) + async getPaymentData(paymentSession) { + return await this.stripeProviderService_.getPaymentData(paymentSession) } /** * Authorizes Stripe payment intent by simply returning * the status for the payment intent in use. - * @param {object} sessionData - payment session data - * @param {object} context - properties relevant to current context - * @returns {Promise<{ status: string, data: object }>} result with data and status + * @param {PaymentSession} paymentSession - payment session data + * @param {Data} context - properties relevant to current context + * @return {Promise<{data: PaymentSessionData; status: PaymentSessionStatus}>} result with data and status */ - async authorizePayment(sessionData, context = {}) { + async authorizePayment(paymentSession, context = {}) { return await this.stripeProviderService_.authorizePayment( - sessionData, + paymentSession, context ) } - async updatePaymentData(sessionData, update) { + async updatePaymentData(paymentSessionData, data) { return await this.stripeProviderService_.updatePaymentData( - sessionData, - update + paymentSessionData, + data ) } /** * Updates Stripe payment intent. - * @param {object} sessionData - payment session data. - * @param {object} update - objec to update intent with - * @returns {object} Stripe payment intent + * @param {PaymentSessionData} paymentSessionData - payment session data. + * @param {Cart} cart + * @return {Promise} Stripe payment intent */ - async updatePayment(sessionData, cart) { + async updatePayment(paymentSessionData, cart) { try { const stripeId = cart.customer?.metadata?.stripe_id || undefined - if (stripeId !== sessionData.customer) { + if (stripeId !== paymentSessionData.customer) { return this.createPayment(cart) } else { - if (cart.total && sessionData.amount === Math.round(cart.total)) { - return sessionData + if ( + cart.total && + paymentSessionData.amount === Math.round(cart.total) + ) { + return paymentSessionData } - return this.stripe_.paymentIntents.update(sessionData.id, { + return this.stripe_.paymentIntents.update(paymentSessionData.id, { amount: Math.round(cart.total), }) } @@ -190,15 +215,15 @@ class GiropayProviderService extends PaymentService { } } - async deletePayment(payment) { - return await this.stripeProviderService_.deletePayment(payment) + async deletePayment(paymentSession) { + return await this.stripeProviderService_.deletePayment(paymentSession) } /** * Updates customer of Stripe payment intent. * @param {string} paymentIntentId - id of payment intent to update * @param {string} customerId - id of new Stripe customer - * @returns {object} Stripe payment intent + * @return {object} Stripe payment intent */ async updatePaymentIntentCustomer(paymentIntentId, customerId) { return await this.stripeProviderService_.updatePaymentIntentCustomer( @@ -209,8 +234,8 @@ class GiropayProviderService extends PaymentService { /** * Captures payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @returns {object} Stripe payment intent + * @param {Payment} payment - payment method data from cart + * @return {Promise} Stripe payment intent */ async capturePayment(payment) { return await this.stripeProviderService_.capturePayment(payment) @@ -218,21 +243,21 @@ class GiropayProviderService extends PaymentService { /** * Refunds payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @param {number} amountToRefund - amount to refund - * @returns {string} refunded payment intent + * @param {Payment} payment - payment method data from cart + * @param {number} refundAmount - amount to refund + * @return {Promise} refunded payment intent */ - async refundPayment(payment, amountToRefund) { + async refundPayment(payment, refundAmount) { return await this.stripeProviderService_.refundPayment( payment, - amountToRefund + refundAmount ) } /** * Cancels payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @returns {object} canceled payment intent + * @param {Payment} payment - payment method data from cart + * @return {Promise} canceled payment intent */ async cancelPayment(payment) { return await this.stripeProviderService_.cancelPayment(payment) diff --git a/packages/medusa-payment-stripe/src/services/stripe-ideal.js b/packages/medusa-payment-stripe/src/services/stripe-ideal.js index 73e0d1f57f..2ed1712335 100644 --- a/packages/medusa-payment-stripe/src/services/stripe-ideal.js +++ b/packages/medusa-payment-stripe/src/services/stripe-ideal.js @@ -1,4 +1,3 @@ -import _ from "lodash" import Stripe from "stripe" import { PaymentService } from "medusa-interfaces" @@ -6,10 +5,25 @@ class IdealProviderService extends PaymentService { static identifier = "stripe-ideal" constructor( - { stripeProviderService, customerService, totalsService, regionService }, + { + stripeProviderService, + customerService, + totalsService, + regionService, + manager, + }, options ) { - super() + super( + { + stripeProviderService, + customerService, + totalsService, + regionService, + manager, + }, + options + ) /** * Required Stripe options: @@ -36,13 +50,15 @@ class IdealProviderService extends PaymentService { /** @private @const {TotalsService} */ this.totalsService_ = totalsService + + this.manager_ = manager } /** * Fetches Stripe payment intent. Check its status and returns the * corresponding Medusa status. - * @param {object} paymentData - payment method data from cart - * @returns {string} the status of the payment intent + * @param {PaymentSessionData} paymentSessionData - payment method data from cart + * @return {Promise} the status of the payment intent */ async getStatus(paymentData) { return await this.stripeProviderService_.getStatus(paymentData) @@ -51,7 +67,7 @@ class IdealProviderService extends PaymentService { /** * Fetches a customers saved payment methods if registered in Stripe. * @param {object} customer - customer to fetch saved cards for - * @returns {Promise>} saved payments methods + * @return {Promise} saved payments methods */ async retrieveSavedMethods(customer) { return Promise.resolve([]) @@ -60,7 +76,7 @@ class IdealProviderService extends PaymentService { /** * Fetches a Stripe customer * @param {string} customerId - Stripe customer id - * @returns {Promise} Stripe customer + * @return {Promise} Stripe customer */ async retrieveCustomer(customerId) { return await this.stripeProviderService_.retrieveCustomer(customerId) @@ -69,28 +85,36 @@ class IdealProviderService extends PaymentService { /** * Creates a Stripe customer using a Medusa customer. * @param {object} customer - Customer data from Medusa - * @returns {Promise} Stripe customer + * @return {Promise} Stripe customer */ async createCustomer(customer) { - return await this.stripeProviderService_.createCustomer(customer) + return await this.stripeProviderService_ + .withTransaction(this.manager_) + .createCustomer(customer) } /** * Creates a Stripe payment intent. * If customer is not registered in Stripe, we do so. - * @param {object} cart - cart to create a payment for - * @returns {object} Stripe payment intent + * @param {Cart} cart - cart to create a payment for + * @return {Promise} Stripe payment intent */ async createPayment(cart) { const { customer_id, region_id, email } = cart - const region = await this.regionService_.retrieve(region_id) + const region = await this.regionService_ + .withTransaction(this.manager_) + .retrieve(region_id) const { currency_code } = region - const amount = await this.totalsService_.getTotal(cart) + const amount = await this.totalsService_ + .withTransaction(this.manager_) + .getTotal(cart) const intentRequest = { amount: Math.round(amount), - description: cart?.context?.payment_description ?? this.options_?.payment_description, + description: + cart?.context?.payment_description ?? + this.options_?.payment_description, currency: currency_code, payment_method_types: ["ideal"], capture_method: "automatic", @@ -98,7 +122,9 @@ class IdealProviderService extends PaymentService { } if (customer_id) { - const customer = await this.customerService_.retrieve(customer_id) + const customer = await this.customerService_ + .withTransaction(this.manager_) + .retrieve(customer_id) if (customer.metadata?.stripe_id) { intentRequest.customer = customer.metadata.stripe_id @@ -118,57 +144,53 @@ class IdealProviderService extends PaymentService { intentRequest.customer = stripeCustomer.id } - const paymentIntent = await this.stripe_.paymentIntents.create( - intentRequest - ) - - return paymentIntent + return await this.stripe_.paymentIntents.create(intentRequest) } /** * Retrieves Stripe payment intent. - * @param {object} data - the data of the payment to retrieve - * @returns {Promise} Stripe payment intent + * @param {PaymentData} paymentData - the data of the payment to retrieve + * @return {Promise} Stripe payment intent */ - async retrievePayment(data) { - return await this.stripeProviderService_.retrievePayment(data) + async retrievePayment(paymentData) { + return await this.stripeProviderService_.retrievePayment(paymentData) } /** * Gets a Stripe payment intent and returns it. - * @param {object} sessionData - the data of the payment to retrieve - * @returns {Promise} Stripe payment intent + * @param {PaymentSession} paymentSession - the data of the payment to retrieve + * @return {Promise} Stripe payment intent */ - async getPaymentData(sessionData) { - return await this.stripeProviderService_.getPaymentData(sessionData) + async getPaymentData(paymentSession) { + return await this.stripeProviderService_.getPaymentData(paymentSession) } /** * Authorizes Stripe payment intent by simply returning * the status for the payment intent in use. - * @param {object} sessionData - payment session data + * @param {PaymentSession} paymentSession - payment session data * @param {object} context - properties relevant to current context - * @returns {Promise<{ status: string, data: object }>} result with data and status + * @return {Promise<{data: PaymentSessionData; status: PaymentSessionStatus}>} result with data and status */ - async authorizePayment(sessionData, context = {}) { + async authorizePayment(paymentSession, context = {}) { return await this.stripeProviderService_.authorizePayment( - sessionData, + paymentSession, context ) } - async updatePaymentData(sessionData, update) { + async updatePaymentData(paymentSessionData, data) { return await this.stripeProviderService_.updatePaymentData( - sessionData, - update + paymentSessionData, + data ) } /** * Updates Stripe payment intent. - * @param {object} sessionData - payment session data. - * @param {object} update - objec to update intent with - * @returns {object} Stripe payment intent + * @param {PaymentSessionData} paymentSessionData - payment session data. + * @param {Cart} cart + * @return {Promise} Stripe payment intent */ async updatePayment(sessionData, cart) { try { @@ -190,15 +212,15 @@ class IdealProviderService extends PaymentService { } } - async deletePayment(payment) { - return await this.stripeProviderService_.deletePayment(payment) + async deletePayment(paymentSession) { + return await this.stripeProviderService_.deletePayment(paymentSession) } /** * Updates customer of Stripe payment intent. * @param {string} paymentIntentId - id of payment intent to update * @param {string} customerId - id of new Stripe customer - * @returns {object} Stripe payment intent + * @return {object} Stripe payment intent */ async updatePaymentIntentCustomer(paymentIntentId, customerId) { return await this.stripeProviderService_.updatePaymentIntentCustomer( @@ -209,8 +231,8 @@ class IdealProviderService extends PaymentService { /** * Captures payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @returns {object} Stripe payment intent + * @param {Payment} payment - payment method data from cart + * @return {Promise} Stripe payment intent */ async capturePayment(payment) { return await this.stripeProviderService_.capturePayment(payment) @@ -218,21 +240,21 @@ class IdealProviderService extends PaymentService { /** * Refunds payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @param {number} amountToRefund - amount to refund - * @returns {string} refunded payment intent + * @param {Payment} payment - payment method data from cart + * @param {number} refundAmount - amount to refund + * @return {Promise} refunded payment intent */ - async refundPayment(payment, amountToRefund) { + async refundPayment(payment, refundAmount) { return await this.stripeProviderService_.refundPayment( payment, - amountToRefund + refundAmount ) } /** * Cancels payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @returns {object} canceled payment intent + * @param {Payment} payment - payment method data from cart + * @return {Promise} canceled payment intent */ async cancelPayment(payment) { return await this.stripeProviderService_.cancelPayment(payment) diff --git a/packages/medusa-payment-stripe/src/services/stripe-provider.js b/packages/medusa-payment-stripe/src/services/stripe-provider.js index 14d02d9ca3..fde19d86eb 100644 --- a/packages/medusa-payment-stripe/src/services/stripe-provider.js +++ b/packages/medusa-payment-stripe/src/services/stripe-provider.js @@ -1,12 +1,18 @@ import Stripe from "stripe" -import { PaymentService } from "medusa-interfaces" -import { PaymentSessionStatus } from '@medusajs/medusa/dist' +import { + AbstractPaymentService, + PaymentSessionData, + PaymentSessionStatus, +} from "@medusajs/medusa" -class StripeProviderService extends PaymentService { +class StripeProviderService extends AbstractPaymentService { static identifier = "stripe" - constructor({ customerService, totalsService, regionService }, options) { - super() + constructor( + { customerService, totalsService, regionService, manager }, + options + ) { + super({ customerService, totalsService, regionService, manager }, options) /** * Required Stripe options: @@ -30,13 +36,16 @@ class StripeProviderService extends PaymentService { /** @private @const {TotalsService} */ this.totalsService_ = totalsService + + /** @private @const {EntityManager} */ + this.manager_ = manager } /** - * Fetches Stripe payment intent. Check its status and returns the - * corresponding Medusa status. - * @param {object} paymentData - payment method data from cart - * @returns {string} the status of the payment intent + * Get payment session status + * statuses. + * @param {PaymentSessionData} paymentData - the data stored with the payment session + * @return {Promise} the status of the order */ async getStatus(paymentData) { const { id } = paymentData @@ -61,8 +70,8 @@ class StripeProviderService extends PaymentService { /** * Fetches a customers saved payment methods if registered in Stripe. - * @param {object} customer - customer to fetch saved cards for - * @returns {Promise>} saved payments methods + * @param {Customer} customer - customer to fetch saved cards for + * @return {Promise} saved payments methods */ async retrieveSavedMethods(customer) { if (customer.metadata && customer.metadata.stripe_id) { @@ -101,9 +110,11 @@ class StripeProviderService extends PaymentService { }) if (customer.id) { - await this.customerService_.update(customer.id, { - metadata: { stripe_id: stripeCustomer.id }, - }) + await this.customerService_ + .withTransaction(this.manager_) + .update(customer.id, { + metadata: { stripe_id: stripeCustomer.id }, + }) } return stripeCustomer @@ -115,17 +126,23 @@ class StripeProviderService extends PaymentService { /** * Creates a Stripe payment intent. * If customer is not registered in Stripe, we do so. - * @param {object} cart - cart to create a payment for - * @returns {object} Stripe payment intent + * @param {Cart} cart - cart to create a payment for + * @return {Promise} Stripe payment intent */ async createPayment(cart) { const { customer_id, region_id, email } = cart - const { currency_code } = await this.regionService_.retrieve(region_id) + const { currency_code } = await this.regionService_ + .withTransaction(this.manager_) + .retrieve(region_id) - const amount = await this.totalsService_.getTotal(cart) + const amount = await this.totalsService_ + .withTransaction(this.manager_) + .getTotal(cart) const intentRequest = { - description: cart?.context?.payment_description ?? this.options_?.payment_description, + description: + cart?.context?.payment_description ?? + this.options_?.payment_description, amount: Math.round(amount), currency: currency_code, setup_future_usage: "on_session", @@ -134,7 +151,9 @@ class StripeProviderService extends PaymentService { } if (customer_id) { - const customer = await this.customerService_.retrieve(customer_id) + const customer = await this.customerService_ + .withTransaction(this.manager_) + .retrieve(customer_id) if (customer.metadata?.stripe_id) { intentRequest.customer = customer.metadata.stripe_id @@ -154,15 +173,13 @@ class StripeProviderService extends PaymentService { intentRequest.customer = stripeCustomer.id } - return await this.stripe_.paymentIntents.create( - intentRequest - ) + return await this.stripe_.paymentIntents.create(intentRequest) } /** * Retrieves Stripe payment intent. - * @param {object} data - the data of the payment to retrieve - * @returns {Promise} Stripe payment intent + * @param {PaymentData} paymentData - the data of the payment to retrieve + * @return {Promise} Stripe payment intent */ async retrievePayment(data) { try { @@ -174,12 +191,12 @@ class StripeProviderService extends PaymentService { /** * Gets a Stripe payment intent and returns it. - * @param {object} sessionData - the data of the payment to retrieve - * @returns {Promise} Stripe payment intent + * @param {PaymentSession} paymentSession - the data of the payment to retrieve + * @return {Promise} Stripe payment intent */ - async getPaymentData(sessionData) { + async getPaymentData(paymentSession) { try { - return this.stripe_.paymentIntents.retrieve(sessionData.data.id) + return this.stripe_.paymentIntents.retrieve(paymentSession.data.id) } catch (error) { throw error } @@ -188,15 +205,15 @@ class StripeProviderService extends PaymentService { /** * Authorizes Stripe payment intent by simply returning * the status for the payment intent in use. - * @param {object} sessionData - payment session data - * @param {object} context - properties relevant to current context - * @returns {Promise<{ status: string, data: object }>} result with data and status + * @param {PaymentSession} paymentSession - payment session data + * @param {Data} context - properties relevant to current context + * @return {Promise<{ data: PaymentSessionData; status: PaymentSessionStatus }>} result with data and status */ - async authorizePayment(sessionData, context = {}) { - const stat = await this.getStatus(sessionData.data) + async authorizePayment(paymentSession, context = {}) { + const stat = await this.getStatus(paymentSession.data) try { - return { data: sessionData.data, status: stat } + return { data: paymentSession.data, status: stat } } catch (error) { throw error } @@ -214,9 +231,9 @@ class StripeProviderService extends PaymentService { /** * Updates Stripe payment intent. - * @param {object} sessionData - payment session data. - * @param {object} update - objec to update intent with - * @returns {object} Stripe payment intent + * @param {PaymentSessionData} paymentSessionData - payment session data. + * @param {Cart} cart + * @return {Promise} Stripe payment intent */ async updatePayment(sessionData, cart) { try { @@ -270,8 +287,8 @@ class StripeProviderService extends PaymentService { /** * Captures payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @returns {object} Stripe payment intent + * @param {Payment} payment - payment method data from cart + * @return {Promise} Stripe payment intent */ async capturePayment(payment) { const { id } = payment.data @@ -290,9 +307,9 @@ class StripeProviderService extends PaymentService { /** * Refunds payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @param {number} amountToRefund - amount to refund - * @returns {string} refunded payment intent + * @param {Payment} payment - payment method data from cart + * @param {number} refundAmount - amount to refund + * @return {Promise} refunded payment intent */ async refundPayment(payment, amountToRefund) { const { id } = payment.data @@ -310,8 +327,8 @@ class StripeProviderService extends PaymentService { /** * Cancels payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @returns {object} canceled payment intent + * @param {Payment} payment - payment method data from cart + * @return {Promise} canceled payment intent */ async cancelPayment(payment) { const { id } = payment.data diff --git a/packages/medusa-payment-stripe/src/services/stripe-przelewy24.js b/packages/medusa-payment-stripe/src/services/stripe-przelewy24.js index 82f7f2a534..c635357690 100644 --- a/packages/medusa-payment-stripe/src/services/stripe-przelewy24.js +++ b/packages/medusa-payment-stripe/src/services/stripe-przelewy24.js @@ -1,15 +1,29 @@ -import _ from "lodash" import Stripe from "stripe" -import { PaymentService } from "medusa-interfaces" +import { AbstractPaymentService, PaymentSessionStatus } from "@medusajs/medusa" -class Przelewy24ProviderService extends PaymentService { +class Przelewy24ProviderService extends AbstractPaymentService { static identifier = "stripe-przelewy24" constructor( - { stripeProviderService, customerService, totalsService, regionService }, + { + stripeProviderService, + customerService, + totalsService, + regionService, + manager, + }, options ) { - super() + super( + { + stripeProviderService, + customerService, + totalsService, + regionService, + manager, + }, + options + ) /** * Required Stripe options: @@ -36,13 +50,15 @@ class Przelewy24ProviderService extends PaymentService { /** @private @const {TotalsService} */ this.totalsService_ = totalsService + + this.manager_ = manager } /** * Fetches Stripe payment intent. Check its status and returns the * corresponding Medusa status. - * @param {object} paymentData - payment method data from cart - * @returns {string} the status of the payment intent + * @param {PaymentSessionData} paymentSessionData - payment method data from cart + * @return {Promise} the status of the payment intent */ async getStatus(paymentData) { return await this.stripeProviderService_.getStatus(paymentData) @@ -51,7 +67,7 @@ class Przelewy24ProviderService extends PaymentService { /** * Fetches a customers saved payment methods if registered in Stripe. * @param {object} customer - customer to fetch saved cards for - * @returns {Promise>} saved payments methods + * @return {Promise} saved payments methods */ async retrieveSavedMethods(customer) { return Promise.resolve([]) @@ -60,7 +76,7 @@ class Przelewy24ProviderService extends PaymentService { /** * Fetches a Stripe customer * @param {string} customerId - Stripe customer id - * @returns {Promise} Stripe customer + * @return {Promise} Stripe customer */ async retrieveCustomer(customerId) { return await this.stripeProviderService_.retrieveCustomer(customerId) @@ -69,10 +85,12 @@ class Przelewy24ProviderService extends PaymentService { /** * Creates a Stripe customer using a Medusa customer. * @param {object} customer - Customer data from Medusa - * @returns {Promise} Stripe customer + * @return {Promise} Stripe customer */ async createCustomer(customer) { - return await this.stripeProviderService_.createCustomer(customer) + return await this.stripeProviderService_ + .withTransaction(this.manager_) + .createCustomer(customer) } /** @@ -83,10 +101,14 @@ class Przelewy24ProviderService extends PaymentService { */ async createPayment(cart) { const { customer_id, region_id, email } = cart - const region = await this.regionService_.retrieve(region_id) + const region = await this.regionService_ + .withTransaction(this.manager_) + .retrieve(region_id) const { currency_code } = region - const amount = await this.totalsService_.getTotal(cart) + const amount = await this.totalsService_ + .withTransaction(this.manager_) + .getTotal(cart) const intentRequest = { amount: Math.round(amount), @@ -97,7 +119,9 @@ class Przelewy24ProviderService extends PaymentService { } if (customer_id) { - const customer = await this.customerService_.retrieve(customer_id) + const customer = await this.customerService_ + .withTransaction(this.manager_) + .retrieve(customer_id) if (customer.metadata?.stripe_id) { intentRequest.customer = customer.metadata.stripe_id @@ -117,57 +141,53 @@ class Przelewy24ProviderService extends PaymentService { intentRequest.customer = stripeCustomer.id } - const paymentIntent = await this.stripe_.paymentIntents.create( - intentRequest - ) - - return paymentIntent + return await this.stripe_.paymentIntents.create(intentRequest) } /** * Retrieves Stripe payment intent. - * @param {object} data - the data of the payment to retrieve - * @returns {Promise} Stripe payment intent + * @param {PaymentData} paymentData - the data of the payment to retrieve + * @return {Promise} Stripe payment intent */ - async retrievePayment(data) { - return await this.stripeProviderService_.retrievePayment(data) + async retrievePayment(paymentData) { + return await this.stripeProviderService_.retrievePayment(paymentData) } /** * Gets a Stripe payment intent and returns it. - * @param {object} sessionData - the data of the payment to retrieve - * @returns {Promise} Stripe payment intent + * @param {PaymentSession} paymentSession - the data of the payment to retrieve + * @return {Promise} Stripe payment intent */ - async getPaymentData(sessionData) { - return await this.stripeProviderService_.getPaymentData(sessionData) + async getPaymentData(paymentSession) { + return await this.stripeProviderService_.getPaymentData(paymentSession) } /** * Authorizes Stripe payment intent by simply returning * the status for the payment intent in use. - * @param {object} sessionData - payment session data + * @param {PaymentSession} paymentSession - payment session data * @param {object} context - properties relevant to current context - * @returns {Promise<{ status: string, data: object }>} result with data and status + * @return {Promise<{data: PaymentSessionData; status: PaymentSessionStatus}>} result with data and status */ - async authorizePayment(sessionData, context = {}) { + async authorizePayment(paymentSession, context = {}) { return await this.stripeProviderService_.authorizePayment( - sessionData, + paymentSession, context ) } - async updatePaymentData(sessionData, update) { + async updatePaymentData(paymentSessionData, data) { return await this.stripeProviderService_.updatePaymentData( - sessionData, - update + paymentSessionData, + data ) } /** * Updates Stripe payment intent. - * @param {object} sessionData - payment session data. - * @param {object} update - objec to update intent with - * @returns {object} Stripe payment intent + * @param {PaymentSessionData} paymentSessionData - payment session data. + * @param {Cart} cart + * @return {Promise} Stripe payment intent */ async updatePayment(sessionData, cart) { try { @@ -189,15 +209,15 @@ class Przelewy24ProviderService extends PaymentService { } } - async deletePayment(payment) { - return await this.stripeProviderService_.deletePayment(payment) + async deletePayment(paymentSession) { + return await this.stripeProviderService_.deletePayment(paymentSession) } /** * Updates customer of Stripe payment intent. * @param {string} paymentIntentId - id of payment intent to update * @param {string} customerId - id of new Stripe customer - * @returns {object} Stripe payment intent + * @return {object} Stripe payment intent */ async updatePaymentIntentCustomer(paymentIntentId, customerId) { return await this.stripeProviderService_.updatePaymentIntentCustomer( @@ -208,8 +228,8 @@ class Przelewy24ProviderService extends PaymentService { /** * Captures payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @returns {object} Stripe payment intent + * @param {Payment} payment - payment method data from cart + * @return {Promise} Stripe payment intent */ async capturePayment(payment) { return await this.stripeProviderService_.capturePayment(payment) @@ -217,21 +237,21 @@ class Przelewy24ProviderService extends PaymentService { /** * Refunds payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @param {number} amountToRefund - amount to refund - * @returns {string} refunded payment intent + * @param {Payment} payment - payment method data from cart + * @param {number} refundAmount - amount to refund + * @return {Promise} refunded payment intent */ - async refundPayment(payment, amountToRefund) { + async refundPayment(payment, refundAmount) { return await this.stripeProviderService_.refundPayment( payment, - amountToRefund + refundAmount ) } /** * Cancels payment for Stripe payment intent. - * @param {object} paymentData - payment method data from cart - * @returns {object} canceled payment intent + * @param {Payment} payment - payment method data from cart + * @return {Promise} canceled payment intent */ async cancelPayment(payment) { return await this.stripeProviderService_.cancelPayment(payment) diff --git a/packages/medusa-payment-stripe/src/subscribers/cart.js b/packages/medusa-payment-stripe/src/subscribers/cart.js index e6a2fac15c..7def274536 100644 --- a/packages/medusa-payment-stripe/src/subscribers/cart.js +++ b/packages/medusa-payment-stripe/src/subscribers/cart.js @@ -1,14 +1,14 @@ class CartSubscriber { constructor({ + manager, cartService, - customerService, paymentProviderService, eventBusService, }) { this.cartService_ = cartService - this.customerService_ = customerService this.paymentProviderService_ = paymentProviderService this.eventBus_ = eventBusService + this.manager_ = manager this.eventBus_.subscribe("cart.customer_updated", async (cart) => { await this.onCustomerUpdated(cart) @@ -16,38 +16,44 @@ class CartSubscriber { } async onCustomerUpdated(cartId) { - const cart = await this.cartService_.retrieve(cartId, { - select: [ - "subtotal", - "tax_total", - "shipping_total", - "discount_total", - "total", - ], - relations: [ - "items", - "billing_address", - "shipping_address", - "region", - "region.payment_providers", - "items", - "items.adjustments", - "payment_sessions", - "customer", - ], + await this.manager_.transaction(async (transactionManager) => { + const cart = await this.cartService_ + .withTransaction(transactionManager) + .retrieve(cartId, { + select: [ + "subtotal", + "tax_total", + "shipping_total", + "discount_total", + "gift_card_total", + "total", + ], + relations: [ + "billing_address", + "shipping_address", + "region", + "region.payment_providers", + "items", + "items.adjustments", + "payment_sessions", + "customer", + ], + }) + + if (!cart.payment_sessions?.length) { + return Promise.resolve() + } + + const session = cart.payment_sessions.find( + (ps) => ps.provider_id === "stripe" + ) + + if (session) { + return await this.paymentProviderService_ + .withTransaction(transactionManager) + .updateSession(session, cart) + } }) - - if (!cart.payment_sessions?.length) { - return Promise.resolve() - } - - const session = cart.payment_sessions.find( - (ps) => ps.provider_id === "stripe" - ) - - if (session) { - return await this.paymentProviderService_.updateSession(session, cart) - } } } diff --git a/packages/medusa/src/interfaces/payment-service.ts b/packages/medusa/src/interfaces/payment-service.ts index e201be6363..64c1b24b8a 100644 --- a/packages/medusa/src/interfaces/payment-service.ts +++ b/packages/medusa/src/interfaces/payment-service.ts @@ -12,8 +12,7 @@ export type Data = Record export type PaymentData = Data export type PaymentSessionData = Data -export interface PaymentService - extends TransactionBaseService { +export interface PaymentService extends TransactionBaseService { getIdentifier(): string getPaymentData(paymentSession: PaymentSession): Promise @@ -50,9 +49,9 @@ export interface PaymentService getStatus(data: Data): Promise } -export abstract class AbstractPaymentService +export abstract class AbstractPaymentService extends TransactionBaseService - implements PaymentService + implements PaymentService { protected constructor(container: unknown, config?: Record) { super(container, config) diff --git a/packages/medusa/src/loaders/defaults.ts b/packages/medusa/src/loaders/defaults.ts index e4a2588f3c..29268e061a 100644 --- a/packages/medusa/src/loaders/defaults.ts +++ b/packages/medusa/src/loaders/defaults.ts @@ -1,6 +1,6 @@ import { - BaseNotificationService, BaseFulfillmentService, + BaseNotificationService, BasePaymentService, } from "medusa-interfaces" import { currencies } from "../utils/currencies" @@ -82,7 +82,8 @@ export default async ({ const hasCountries = await countryRepo.findOne() if (!hasCountries) { for (const c of countries) { - const query = `INSERT INTO "country" ("iso_2", "iso_3", "num_code", "name", "display_name") VALUES ($1, $2, $3, $4, $5)` + const query = `INSERT INTO "country" ("iso_2", "iso_3", "num_code", "name", "display_name") + VALUES ($1, $2, $3, $4, $5)` const iso2 = c.alpha2.toLowerCase() const iso3 = c.alpha3.toLowerCase() @@ -106,7 +107,8 @@ export default async ({ const hasCurrencies = await currencyRepo.findOne() if (!hasCurrencies) { for (const [, c] of Object.entries(currencies)) { - const query = `INSERT INTO "currency" ("code", "symbol", "symbol_native", "name") VALUES ($1, $2, $3, $4)` + const query = `INSERT INTO "currency" ("code", "symbol", "symbol_native", "name") + VALUES ($1, $2, $3, $4)` const code = c.code.toLowerCase() const sym = c.symbol @@ -122,9 +124,11 @@ export default async ({ await storeService.withTransaction(manager).create() const payProviders = - silentResolution< - (typeof BasePaymentService | AbstractPaymentService)[] - >(container, "paymentProviders", logger) || [] + silentResolution<(typeof BasePaymentService | AbstractPaymentService)[]>( + container, + "paymentProviders", + logger + ) || [] const payIds = payProviders.map((p) => p.getIdentifier()) const pProviderService = container.resolve( diff --git a/packages/medusa/src/services/cart.ts b/packages/medusa/src/services/cart.ts index 114bacc802..ac64b53185 100644 --- a/packages/medusa/src/services/cart.ts +++ b/packages/medusa/src/services/cart.ts @@ -1,9 +1,7 @@ import { isEmpty, isEqual } from "lodash" import { MedusaError } from "medusa-core-utils" import { DeepPartial, EntityManager, In } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { IPriceSelectionStrategy } from "../interfaces/price-selection-strategy" -import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels" +import { IPriceSelectionStrategy, TransactionBaseService } from "../interfaces" import { Address, Cart, @@ -36,7 +34,6 @@ import CustomerService from "./customer" import DiscountService from "./discount" import EventBusService from "./event-bus" import GiftCardService from "./gift-card" -import { SalesChannelService } from "./index" import InventoryService from "./inventory" import LineItemService from "./line-item" import LineItemAdjustmentService from "./line-item-adjustment" @@ -45,9 +42,11 @@ import ProductService from "./product" import ProductVariantService from "./product-variant" import RegionService from "./region" import ShippingOptionService from "./shipping-option" -import StoreService from "./store" import TaxProviderService from "./tax-provider" import TotalsService from "./totals" +import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels" +import StoreService from "./store" +import { SalesChannelService } from "./index" type InjectedDependencies = { manager: EntityManager diff --git a/packages/medusa/src/services/payment-provider.ts b/packages/medusa/src/services/payment-provider.ts index 106897ae65..dd85dcc994 100644 --- a/packages/medusa/src/services/payment-provider.ts +++ b/packages/medusa/src/services/payment-provider.ts @@ -26,7 +26,7 @@ type InjectedDependencies = { refundRepository: typeof RefundRepository } & { [key in `${PaymentProviderKey}`]: - | AbstractPaymentService + | AbstractPaymentService | typeof BasePaymentService } @@ -275,11 +275,11 @@ export default class PaymentProviderService extends TransactionBaseService { * @return {PaymentService} the payment provider */ retrieveProvider< - TProvider extends AbstractPaymentService | typeof BasePaymentService + TProvider extends AbstractPaymentService | typeof BasePaymentService >( providerId: string - ): TProvider extends AbstractPaymentService - ? AbstractPaymentService + ): TProvider extends AbstractPaymentService + ? AbstractPaymentService : typeof BasePaymentService { try { let provider