feat(medusa,medusa-payment-stripe): Migrate Stripe to Abstract payment service (#1790)

This commit is contained in:
Adrien de Peretti authored and GitHub committed 2022-10-04 10:49:43 +02:00
1 parent 00959f79bc
commit df62e618bc
19 files changed
+516 -357

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
---
"medusa-payment-stripe": patch
"@medusajs/medusa": patch
---
Migrate Stripe providers to the new AbstractPaymentService
@@ -185,6 +185,9 @@ export const carts = {
} }
export const CartServiceMock = { export const CartServiceMock = {
withTransaction: function () {
return this
},
retrieve: jest.fn().mockImplementation((cartId) => { retrieve: jest.fn().mockImplementation((cartId) => {
if (cartId === IdMap.getId("fr-cart")) { if (cartId === IdMap.getId("fr-cart")) {
return Promise.resolve(carts.frCart) return Promise.resolve(carts.frCart)
@@ -1,6 +1,9 @@
import { IdMap } from "medusa-test-utils" import { IdMap } from "medusa-test-utils"
export const CustomerServiceMock = { export const CustomerServiceMock = {
withTransaction: function () {
return this
},
retrieve: jest.fn().mockImplementation((id) => { retrieve: jest.fn().mockImplementation((id) => {
if (id === IdMap.getId("lebron")) { if (id === IdMap.getId("lebron")) {
return Promise.resolve({ return Promise.resolve({
@@ -1,4 +1,7 @@
export const TotalsServiceMock = { export const TotalsServiceMock = {
withTransaction: function () {
return this
},
getTotal: jest.fn(), getTotal: jest.fn(),
} }
@@ -1 +1,3 @@
export default (fn) => (...args) => fn(...args).catch(args[2]) export default (fn) =>
(...args) =>
fn(...args).catch(args[2])
@@ -12,6 +12,7 @@ export default async (req, res) => {
const paymentIntent = event.data.object const paymentIntent = event.data.object
const manager = req.scope.resolve("manager")
const cartService = req.scope.resolve("cartService") const cartService = req.scope.resolve("cartService")
const orderService = req.scope.resolve("orderService") const orderService = req.scope.resolve("orderService")
@@ -24,24 +25,19 @@ export default async (req, res) => {
switch (event.type) { switch (event.type) {
case "payment_intent.succeeded": case "payment_intent.succeeded":
if (order && order.payment_status !== "captured") { if (order && order.payment_status !== "captured") {
await orderService.capturePayment(order.id) await manager.transaction(async (manager) => {
await orderService.withTransaction(manager).capturePayment(order.id)
})
} }
break 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": case "payment_intent.amount_capturable_updated":
if (!order) { if (!order) {
await cartService.setPaymentSession(cartId, "stripe") await manager.transaction(async (manager) => {
await cartService.authorizePayment(cartId) const cartServiceTx = cartService.withTransaction(manager)
await orderService.createFromCart(cartId) await cartServiceTx.setPaymentSession(cartId, "stripe")
await cartServiceTx.authorizePayment(cartId)
await orderService.withTransaction(manager).createFromCart(cartId)
})
} }
break break
default: default:
@@ -1,6 +1,9 @@
import { IdMap } from "medusa-test-utils" import { IdMap } from "medusa-test-utils"
export const StripeProviderServiceMock = { export const StripeProviderServiceMock = {
withTransaction: function () {
return this
},
retrievePayment: jest.fn().mockImplementation((payData) => { retrievePayment: jest.fn().mockImplementation((payData) => {
if (payData.id === "pi_123456789") { if (payData.id === "pi_123456789") {
return Promise.resolve({ return Promise.resolve({
@@ -5,6 +5,9 @@ import { carts } from "../../__mocks__/cart"
import { TotalsServiceMock } from "../../__mocks__/totals" import { TotalsServiceMock } from "../../__mocks__/totals"
const RegionServiceMock = { const RegionServiceMock = {
withTransaction: function () {
return this
},
retrieve: jest.fn().mockReturnValue(Promise.resolve({})), retrieve: jest.fn().mockReturnValue(Promise.resolve({})),
} }
@@ -1,15 +1,29 @@
import _ from "lodash"
import Stripe from "stripe" 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" static identifier = "stripe-bancontact"
constructor( constructor(
{ stripeProviderService, customerService, totalsService, regionService }, {
stripeProviderService,
customerService,
totalsService,
regionService,
manager,
},
options options
) { ) {
super() super(
{
stripeProviderService,
customerService,
totalsService,
regionService,
manager,
},
options
)
/** /**
* Required Stripe options: * Required Stripe options:
@@ -36,22 +50,25 @@ class BancontactProviderService extends PaymentService {
/** @private @const {TotalsService} */ /** @private @const {TotalsService} */
this.totalsService_ = totalsService this.totalsService_ = totalsService
/** @private @const {EntityManager} */
this.manager_ = manager
} }
/** /**
* Fetches Stripe payment intent. Check its status and returns the * Fetches Stripe payment intent. Check its status and returns the
* corresponding Medusa status. * corresponding Medusa status.
* @param {object} paymentData - payment method data from cart * @param {PaymentSessionData} paymentSessionData - payment method data from cart
* @returns {string} the status of the payment intent * @return {Promise<PaymentSessionStatus>} the status of the payment intent
*/ */
async getStatus(paymentData) { async getStatus(paymentSessionData) {
return await this.stripeProviderService_.getStatus(paymentData) return await this.stripeProviderService_.getStatus(paymentSessionData)
} }
/** /**
* Fetches a customers saved payment methods if registered in Stripe. * Fetches a customers saved payment methods if registered in Stripe.
* @param {object} customer - customer to fetch saved cards for * @param {object} customer - customer to fetch saved cards for
* @returns {Promise<Array<object>>} saved payments methods * @return {Promise<Data[]>} saved payments methods
*/ */
async retrieveSavedMethods(customer) { async retrieveSavedMethods(customer) {
return Promise.resolve([]) return Promise.resolve([])
@@ -60,7 +77,7 @@ class BancontactProviderService extends PaymentService {
/** /**
* Fetches a Stripe customer * Fetches a Stripe customer
* @param {string} customerId - Stripe customer id * @param {string} customerId - Stripe customer id
* @returns {Promise<object>} Stripe customer * @return {Promise<object>} Stripe customer
*/ */
async retrieveCustomer(customerId) { async retrieveCustomer(customerId) {
return await this.stripeProviderService_.retrieveCustomer(customerId) return await this.stripeProviderService_.retrieveCustomer(customerId)
@@ -69,28 +86,35 @@ class BancontactProviderService extends PaymentService {
/** /**
* Creates a Stripe customer using a Medusa customer. * Creates a Stripe customer using a Medusa customer.
* @param {object} customer - Customer data from Medusa * @param {object} customer - Customer data from Medusa
* @returns {Promise<object>} Stripe customer * @return {Promise<object>} Stripe customer
*/ */
async createCustomer(customer) { async createCustomer(customer) {
return await this.stripeProviderService_.createCustomer(customer) return await this.stripeProviderService_
.withTransaction(this.manager_)
.createCustomer(customer)
} }
/** /**
* Creates a Stripe payment intent. * Creates a Stripe payment intent.
* If customer is not registered in Stripe, we do so. * If customer is not registered in Stripe, we do so.
* @param {object} cart - cart to create a payment for * @param {Cart} cart - cart to create a payment for
* @returns {object} Stripe payment intent * @return {Promise<PaymentSessionData>} Stripe payment intent
*/ */
async createPayment(cart) { async createPayment(cart) {
const { customer_id, region_id, email } = 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 { currency_code } = region
const amount = await this.totalsService_.getTotal(cart) const amount = await this.totalsService_
.withTransaction(this.manager_)
.getTotal(cart)
const intentRequest = { const intentRequest = {
amount: Math.round(amount), 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, currency: currency_code,
payment_method_types: ["bancontact"], payment_method_types: ["bancontact"],
capture_method: "automatic", capture_method: "automatic",
@@ -98,7 +122,9 @@ class BancontactProviderService extends PaymentService {
} }
if (customer_id) { 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) { if (customer.metadata?.stripe_id) {
intentRequest.customer = customer.metadata.stripe_id intentRequest.customer = customer.metadata.stripe_id
@@ -118,70 +144,69 @@ class BancontactProviderService extends PaymentService {
intentRequest.customer = stripeCustomer.id intentRequest.customer = stripeCustomer.id
} }
const paymentIntent = await this.stripe_.paymentIntents.create( return await this.stripe_.paymentIntents.create(intentRequest)
intentRequest
)
return paymentIntent
} }
/** /**
* Retrieves Stripe payment intent. * Retrieves Stripe payment intent.
* @param {object} data - the data of the payment to retrieve * @param {PaymentData} paymentData - the data of the payment to retrieve
* @returns {Promise<object>} Stripe payment intent * @return {Promise<Data>} Stripe payment intent
*/ */
async retrievePayment(data) { async retrievePayment(paymentData) {
return await this.stripeProviderService_.retrievePayment(data) return await this.stripeProviderService_.retrievePayment(paymentData)
} }
/** /**
* Gets a Stripe payment intent and returns it. * Gets a Stripe payment intent and returns it.
* @param {object} sessionData - the data of the payment to retrieve * @param {PaymentSession} paymentSession - the data of the payment to retrieve
* @returns {Promise<object>} Stripe payment intent * @return {Promise<PaymentData>} Stripe payment intent
*/ */
async getPaymentData(sessionData) { async getPaymentData(paymentSession) {
return await this.stripeProviderService_.getPaymentData(sessionData) return await this.stripeProviderService_.getPaymentData(paymentSession)
} }
/** /**
* Authorizes Stripe payment intent by simply returning * Authorizes Stripe payment intent by simply returning
* the status for the payment intent in use. * 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 * @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( return await this.stripeProviderService_.authorizePayment(
sessionData, paymentSession,
context context
) )
} }
async updatePaymentData(sessionData, update) { async updatePaymentData(paymentSessionData, data) {
return await this.stripeProviderService_.updatePaymentData( return await this.stripeProviderService_.updatePaymentData(
sessionData, paymentSessionData,
update data
) )
} }
/** /**
* Updates Stripe payment intent. * Updates Stripe payment intent.
* @param {object} sessionData - payment session data. * @param {PaymentSessionData} paymentSessionData - payment session data.
* @param {object} update - objec to update intent with * @param {Cart} cart
* @returns {object} Stripe payment intent * @return {Promise<PaymentSessionData>} Stripe payment intent
*/ */
async updatePayment(sessionData, cart) { async updatePayment(paymentSessionData, cart) {
try { try {
const stripeId = cart.customer?.metadata?.stripe_id || undefined const stripeId = cart.customer?.metadata?.stripe_id || undefined
if (stripeId !== sessionData.customer) { if (stripeId !== paymentSessionData.customer) {
return this.createPayment(cart) return this.createPayment(cart)
} else { } else {
if (cart.total && sessionData.amount === Math.round(cart.total)) { if (
cart.total &&
paymentSessionData.amount === Math.round(cart.total)
) {
return sessionData return sessionData
} }
return this.stripe_.paymentIntents.update(sessionData.id, { return this.stripe_.paymentIntents.update(paymentSessionData.id, {
amount: Math.round(cart.total), amount: Math.round(cart.total),
}) })
} }
@@ -190,15 +215,15 @@ class BancontactProviderService extends PaymentService {
} }
} }
async deletePayment(payment) { async deletePayment(paymentSession) {
return await this.stripeProviderService_.deletePayment(payment) return await this.stripeProviderService_.deletePayment(paymentSession)
} }
/** /**
* Updates customer of Stripe payment intent. * Updates customer of Stripe payment intent.
* @param {string} paymentIntentId - id of payment intent to update * @param {string} paymentIntentId - id of payment intent to update
* @param {string} customerId - id of new Stripe customer * @param {string} customerId - id of new Stripe customer
* @returns {object} Stripe payment intent * @return {object} Stripe payment intent
*/ */
async updatePaymentIntentCustomer(paymentIntentId, customerId) { async updatePaymentIntentCustomer(paymentIntentId, customerId) {
return await this.stripeProviderService_.updatePaymentIntentCustomer( return await this.stripeProviderService_.updatePaymentIntentCustomer(
@@ -209,8 +234,8 @@ class BancontactProviderService extends PaymentService {
/** /**
* Captures payment for Stripe payment intent. * Captures payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @returns {object} Stripe payment intent * @return {Promise<PaymentData>} Stripe payment intent
*/ */
async capturePayment(payment) { async capturePayment(payment) {
return await this.stripeProviderService_.capturePayment(payment) return await this.stripeProviderService_.capturePayment(payment)
@@ -218,21 +243,21 @@ class BancontactProviderService extends PaymentService {
/** /**
* Refunds payment for Stripe payment intent. * Refunds payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @param {number} amountToRefund - amount to refund * @param {number} refundAmount - amount to refund
* @returns {string} refunded payment intent * @return {Promise<PaymentData>} refunded payment intent
*/ */
async refundPayment(payment, amountToRefund) { async refundPayment(payment, refundAmount) {
return await this.stripeProviderService_.refundPayment( return await this.stripeProviderService_.refundPayment(
payment, payment,
amountToRefund refundAmount
) )
} }
/** /**
* Cancels payment for Stripe payment intent. * Cancels payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @returns {object} canceled payment intent * @return {Promise<PaymentData>} canceled payment intent
*/ */
async cancelPayment(payment) { async cancelPayment(payment) {
return await this.stripeProviderService_.cancelPayment(payment) return await this.stripeProviderService_.cancelPayment(payment)
@@ -1,15 +1,29 @@
import _ from "lodash"
import Stripe from "stripe" 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" static identifier = "stripe-blik"
constructor( constructor(
{ stripeProviderService, customerService, totalsService, regionService }, {
stripeProviderService,
customerService,
totalsService,
regionService,
manager,
},
options options
) { ) {
super() super(
{
stripeProviderService,
customerService,
totalsService,
regionService,
manager,
},
options
)
/** /**
* Required Stripe options: * Required Stripe options:
@@ -36,22 +50,24 @@ class BlikProviderService extends PaymentService {
/** @private @const {TotalsService} */ /** @private @const {TotalsService} */
this.totalsService_ = totalsService this.totalsService_ = totalsService
this.manager_ = manager
} }
/** /**
* Fetches Stripe payment intent. Check its status and returns the * Fetches Stripe payment intent. Check its status and returns the
* corresponding Medusa status. * corresponding Medusa status.
* @param {object} paymentData - payment method data from cart * @param {PaymentSessionData} paymentSessionData - payment method data from cart
* @returns {string} the status of the payment intent * @return {Promise<PaymentSessionStatus>} the status of the payment intent
*/ */
async getStatus(paymentData) { async getStatus(paymentSessionData) {
return await this.stripeProviderService_.getStatus(paymentData) return await this.stripeProviderService_.getStatus(paymentSessionData)
} }
/** /**
* Fetches a customers saved payment methods if registered in Stripe. * Fetches a customers saved payment methods if registered in Stripe.
* @param {object} customer - customer to fetch saved cards for * @param {object} customer - customer to fetch saved cards for
* @returns {Promise<Array<object>>} saved payments methods * @return {Promise<Data[]>} saved payments methods
*/ */
async retrieveSavedMethods(customer) { async retrieveSavedMethods(customer) {
return Promise.resolve([]) return Promise.resolve([])
@@ -60,7 +76,7 @@ class BlikProviderService extends PaymentService {
/** /**
* Fetches a Stripe customer * Fetches a Stripe customer
* @param {string} customerId - Stripe customer id * @param {string} customerId - Stripe customer id
* @returns {Promise<object>} Stripe customer * @return {Promise<object>} Stripe customer
*/ */
async retrieveCustomer(customerId) { async retrieveCustomer(customerId) {
return await this.stripeProviderService_.retrieveCustomer(customerId) return await this.stripeProviderService_.retrieveCustomer(customerId)
@@ -69,24 +85,30 @@ class BlikProviderService extends PaymentService {
/** /**
* Creates a Stripe customer using a Medusa customer. * Creates a Stripe customer using a Medusa customer.
* @param {object} customer - Customer data from Medusa * @param {object} customer - Customer data from Medusa
* @returns {Promise<object>} Stripe customer * @return {Promise<object>} Stripe customer
*/ */
async createCustomer(customer) { async createCustomer(customer) {
return await this.stripeProviderService_.createCustomer(customer) return await this.stripeProviderService_
.withTransaction(this.manager_)
.createCustomer(customer)
} }
/** /**
* Creates a Stripe payment intent. * Creates a Stripe payment intent.
* If customer is not registered in Stripe, we do so. * If customer is not registered in Stripe, we do so.
* @param {object} cart - cart to create a payment for * @param {Cart} cart - cart to create a payment for
* @returns {object} Stripe payment intent * @returns {PaymentSessionData} Stripe payment intent
*/ */
async createPayment(cart) { async createPayment(cart) {
const { customer_id, region_id, email } = 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 { currency_code } = region
const amount = await this.totalsService_.getTotal(cart) const amount = await this.totalsService_
.withTransaction(this.manager_)
.getTotal(cart)
const intentRequest = { const intentRequest = {
amount: Math.round(amount), amount: Math.round(amount),
@@ -97,7 +119,9 @@ class BlikProviderService extends PaymentService {
} }
if (customer_id) { 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) { if (customer.metadata?.stripe_id) {
intentRequest.customer = customer.metadata.stripe_id intentRequest.customer = customer.metadata.stripe_id
@@ -117,70 +141,69 @@ class BlikProviderService extends PaymentService {
intentRequest.customer = stripeCustomer.id intentRequest.customer = stripeCustomer.id
} }
const paymentIntent = await this.stripe_.paymentIntents.create( return await this.stripe_.paymentIntents.create(intentRequest)
intentRequest
)
return paymentIntent
} }
/** /**
* Retrieves Stripe payment intent. * Retrieves Stripe payment intent.
* @param {object} data - the data of the payment to retrieve * @param {PaymentData} paymentData - the data of the payment to retrieve
* @returns {Promise<object>} Stripe payment intent * @return {Promise<Data>} Stripe payment intent
*/ */
async retrievePayment(data) { async retrievePayment(paymentData) {
return await this.stripeProviderService_.retrievePayment(data) return await this.stripeProviderService_.retrievePayment(paymentData)
} }
/** /**
* Gets a Stripe payment intent and returns it. * Gets a Stripe payment intent and returns it.
* @param {object} sessionData - the data of the payment to retrieve * @param {PaymentSession} paymentSession - the data of the payment to retrieve
* @returns {Promise<object>} Stripe payment intent * @return {Promise<PaymentData>} Stripe payment intent
*/ */
async getPaymentData(sessionData) { async getPaymentData(paymentSession) {
return await this.stripeProviderService_.getPaymentData(sessionData) return await this.stripeProviderService_.getPaymentData(paymentSession)
} }
/** /**
* Authorizes Stripe payment intent by simply returning * Authorizes Stripe payment intent by simply returning
* the status for the payment intent in use. * 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 * @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( return await this.stripeProviderService_.authorizePayment(
sessionData, paymentSession,
context context
) )
} }
async updatePaymentData(sessionData, update) { async updatePaymentData(paymentSessionData, data) {
return await this.stripeProviderService_.updatePaymentData( return await this.stripeProviderService_.updatePaymentData(
sessionData, paymentSessionData,
update data
) )
} }
/** /**
* Updates Stripe payment intent. * Updates Stripe payment intent.
* @param {object} sessionData - payment session data. * @param {PaymentSessionData} paymentSessionData - payment session data.
* @param {object} update - objec to update intent with * @param {Cart} cart
* @returns {object} Stripe payment intent * @return {Promise<PaymentSessionData>} Stripe payment intent
*/ */
async updatePayment(sessionData, cart) { async updatePayment(paymentSessionData, cart) {
try { try {
const stripeId = cart.customer?.metadata?.stripe_id || undefined const stripeId = cart.customer?.metadata?.stripe_id || undefined
if (stripeId !== sessionData.customer) { if (stripeId !== paymentSessionData.customer) {
return this.createPayment(cart) return this.createPayment(cart)
} else { } else {
if (cart.total && sessionData.amount === Math.round(cart.total)) { if (
cart.total &&
paymentSessionData.amount === Math.round(cart.total)
) {
return sessionData return sessionData
} }
return this.stripe_.paymentIntents.update(sessionData.id, { return this.stripe_.paymentIntents.update(paymentSessionData.id, {
amount: Math.round(cart.total), amount: Math.round(cart.total),
}) })
} }
@@ -189,15 +212,15 @@ class BlikProviderService extends PaymentService {
} }
} }
async deletePayment(payment) { async deletePayment(paymentSession) {
return await this.stripeProviderService_.deletePayment(payment) return await this.stripeProviderService_.deletePayment(paymentSession)
} }
/** /**
* Updates customer of Stripe payment intent. * Updates customer of Stripe payment intent.
* @param {string} paymentIntentId - id of payment intent to update * @param {string} paymentIntentId - id of payment intent to update
* @param {string} customerId - id of new Stripe customer * @param {string} customerId - id of new Stripe customer
* @returns {object} Stripe payment intent * @return {object} Stripe payment intent
*/ */
async updatePaymentIntentCustomer(paymentIntentId, customerId) { async updatePaymentIntentCustomer(paymentIntentId, customerId) {
return await this.stripeProviderService_.updatePaymentIntentCustomer( return await this.stripeProviderService_.updatePaymentIntentCustomer(
@@ -208,8 +231,8 @@ class BlikProviderService extends PaymentService {
/** /**
* Captures payment for Stripe payment intent. * Captures payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @returns {object} Stripe payment intent * @return {Promise<PaymentData>} Stripe payment intent
*/ */
async capturePayment(payment) { async capturePayment(payment) {
return await this.stripeProviderService_.capturePayment(payment) return await this.stripeProviderService_.capturePayment(payment)
@@ -217,21 +240,21 @@ class BlikProviderService extends PaymentService {
/** /**
* Refunds payment for Stripe payment intent. * Refunds payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @param {number} amountToRefund - amount to refund * @param {number} refundAmount - amount to refund
* @returns {string} refunded payment intent * @return {Promise<PaymentData>} refunded payment intent
*/ */
async refundPayment(payment, amountToRefund) { async refundPayment(payment, refundAmount) {
return await this.stripeProviderService_.refundPayment( return await this.stripeProviderService_.refundPayment(
payment, payment,
amountToRefund refundAmount
) )
} }
/** /**
* Cancels payment for Stripe payment intent. * Cancels payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @returns {object} canceled payment intent * @return {Promise<PaymentData>} canceled payment intent
*/ */
async cancelPayment(payment) { async cancelPayment(payment) {
return await this.stripeProviderService_.cancelPayment(payment) return await this.stripeProviderService_.cancelPayment(payment)
@@ -1,15 +1,29 @@
import _ from "lodash"
import Stripe from "stripe" 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" static identifier = "stripe-giropay"
constructor( constructor(
{ stripeProviderService, customerService, totalsService, regionService }, {
stripeProviderService,
customerService,
totalsService,
regionService,
manager,
},
options options
) { ) {
super() super(
{
stripeProviderService,
customerService,
totalsService,
regionService,
manager,
},
options
)
/** /**
* Required Stripe options: * Required Stripe options:
@@ -36,22 +50,25 @@ class GiropayProviderService extends PaymentService {
/** @private @const {TotalsService} */ /** @private @const {TotalsService} */
this.totalsService_ = totalsService this.totalsService_ = totalsService
/** @private @const {EntityManager} */
this.manager_ = manager
} }
/** /**
* Fetches Stripe payment intent. Check its status and returns the * Fetches Stripe payment intent. Check its status and returns the
* corresponding Medusa status. * corresponding Medusa status.
* @param {object} paymentData - payment method data from cart * @param {PaymentSessionData} paymentSessionData - payment method data from cart
* @returns {string} the status of the payment intent * @return {Promise<PaymentSessionStatus>} the status of the payment intent
*/ */
async getStatus(paymentData) { async getStatus(paymentSessionData) {
return await this.stripeProviderService_.getStatus(paymentData) return await this.stripeProviderService_.getStatus(paymentSessionData)
} }
/** /**
* Fetches a customers saved payment methods if registered in Stripe. * Fetches a customers saved payment methods if registered in Stripe.
* @param {object} customer - customer to fetch saved cards for * @param {Customer} customer - customer to fetch saved cards for
* @returns {Promise<Array<object>>} saved payments methods * @return {Promise<Data[]>} saved payments methods
*/ */
async retrieveSavedMethods(customer) { async retrieveSavedMethods(customer) {
return Promise.resolve([]) return Promise.resolve([])
@@ -60,7 +77,7 @@ class GiropayProviderService extends PaymentService {
/** /**
* Fetches a Stripe customer * Fetches a Stripe customer
* @param {string} customerId - Stripe customer id * @param {string} customerId - Stripe customer id
* @returns {Promise<object>} Stripe customer * @return {Promise<object>} Stripe customer
*/ */
async retrieveCustomer(customerId) { async retrieveCustomer(customerId) {
return await this.stripeProviderService_.retrieveCustomer(customerId) return await this.stripeProviderService_.retrieveCustomer(customerId)
@@ -69,28 +86,35 @@ class GiropayProviderService extends PaymentService {
/** /**
* Creates a Stripe customer using a Medusa customer. * Creates a Stripe customer using a Medusa customer.
* @param {object} customer - Customer data from Medusa * @param {object} customer - Customer data from Medusa
* @returns {Promise<object>} Stripe customer * @return {Promise<object>} Stripe customer
*/ */
async createCustomer(customer) { async createCustomer(customer) {
return await this.stripeProviderService_.createCustomer(customer) return await this.stripeProviderService_
.withTransaction(this.manager_)
.createCustomer(customer)
} }
/** /**
* Creates a Stripe payment intent. * Creates a Stripe payment intent.
* If customer is not registered in Stripe, we do so. * If customer is not registered in Stripe, we do so.
* @param {object} cart - cart to create a payment for * @param {Cart} cart - cart to create a payment for
* @returns {object} Stripe payment intent * @return {Promise<PaymentSessionData>} Stripe payment intent
*/ */
async createPayment(cart) { async createPayment(cart) {
const { customer_id, region_id, email } = 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 { currency_code } = region
const amount = await this.totalsService_.getTotal(cart) const amount = await this.totalsService_
.withTransaction(this.manager_)
.getTotal(cart)
const intentRequest = { const intentRequest = {
amount: Math.round(amount), 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, currency: currency_code,
payment_method_types: ["giropay"], payment_method_types: ["giropay"],
capture_method: "automatic", capture_method: "automatic",
@@ -98,7 +122,9 @@ class GiropayProviderService extends PaymentService {
} }
if (customer_id) { 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) { if (customer.metadata?.stripe_id) {
intentRequest.customer = customer.metadata.stripe_id intentRequest.customer = customer.metadata.stripe_id
@@ -118,70 +144,69 @@ class GiropayProviderService extends PaymentService {
intentRequest.customer = stripeCustomer.id intentRequest.customer = stripeCustomer.id
} }
const paymentIntent = await this.stripe_.paymentIntents.create( return await this.stripe_.paymentIntents.create(intentRequest)
intentRequest
)
return paymentIntent
} }
/** /**
* Retrieves Stripe payment intent. * Retrieves Stripe payment intent.
* @param {object} data - the data of the payment to retrieve * @param {PaymentData} paymentData - the data of the payment to retrieve
* @returns {Promise<object>} Stripe payment intent * @return {Promise<Data>} Stripe payment intent
*/ */
async retrievePayment(data) { async retrievePayment(paymentData) {
return await this.stripeProviderService_.retrievePayment(data) return await this.stripeProviderService_.retrievePayment(paymentData)
} }
/** /**
* Gets a Stripe payment intent and returns it. * Gets a Stripe payment intent and returns it.
* @param {object} sessionData - the data of the payment to retrieve * @param {PaymentSession} paymentSession - the data of the payment to retrieve
* @returns {Promise<object>} Stripe payment intent * @return {Promise<PaymentData>} Stripe payment intent
*/ */
async getPaymentData(sessionData) { async getPaymentData(paymentSession) {
return await this.stripeProviderService_.getPaymentData(sessionData) return await this.stripeProviderService_.getPaymentData(paymentSession)
} }
/** /**
* Authorizes Stripe payment intent by simply returning * Authorizes Stripe payment intent by simply returning
* the status for the payment intent in use. * 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 * @param {Data} 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( return await this.stripeProviderService_.authorizePayment(
sessionData, paymentSession,
context context
) )
} }
async updatePaymentData(sessionData, update) { async updatePaymentData(paymentSessionData, data) {
return await this.stripeProviderService_.updatePaymentData( return await this.stripeProviderService_.updatePaymentData(
sessionData, paymentSessionData,
update data
) )
} }
/** /**
* Updates Stripe payment intent. * Updates Stripe payment intent.
* @param {object} sessionData - payment session data. * @param {PaymentSessionData} paymentSessionData - payment session data.
* @param {object} update - objec to update intent with * @param {Cart} cart
* @returns {object} Stripe payment intent * @return {Promise<PaymentSessionData>} Stripe payment intent
*/ */
async updatePayment(sessionData, cart) { async updatePayment(paymentSessionData, cart) {
try { try {
const stripeId = cart.customer?.metadata?.stripe_id || undefined const stripeId = cart.customer?.metadata?.stripe_id || undefined
if (stripeId !== sessionData.customer) { if (stripeId !== paymentSessionData.customer) {
return this.createPayment(cart) return this.createPayment(cart)
} else { } else {
if (cart.total && sessionData.amount === Math.round(cart.total)) { if (
return sessionData 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), amount: Math.round(cart.total),
}) })
} }
@@ -190,15 +215,15 @@ class GiropayProviderService extends PaymentService {
} }
} }
async deletePayment(payment) { async deletePayment(paymentSession) {
return await this.stripeProviderService_.deletePayment(payment) return await this.stripeProviderService_.deletePayment(paymentSession)
} }
/** /**
* Updates customer of Stripe payment intent. * Updates customer of Stripe payment intent.
* @param {string} paymentIntentId - id of payment intent to update * @param {string} paymentIntentId - id of payment intent to update
* @param {string} customerId - id of new Stripe customer * @param {string} customerId - id of new Stripe customer
* @returns {object} Stripe payment intent * @return {object} Stripe payment intent
*/ */
async updatePaymentIntentCustomer(paymentIntentId, customerId) { async updatePaymentIntentCustomer(paymentIntentId, customerId) {
return await this.stripeProviderService_.updatePaymentIntentCustomer( return await this.stripeProviderService_.updatePaymentIntentCustomer(
@@ -209,8 +234,8 @@ class GiropayProviderService extends PaymentService {
/** /**
* Captures payment for Stripe payment intent. * Captures payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @returns {object} Stripe payment intent * @return {Promise<PaymentData>} Stripe payment intent
*/ */
async capturePayment(payment) { async capturePayment(payment) {
return await this.stripeProviderService_.capturePayment(payment) return await this.stripeProviderService_.capturePayment(payment)
@@ -218,21 +243,21 @@ class GiropayProviderService extends PaymentService {
/** /**
* Refunds payment for Stripe payment intent. * Refunds payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @param {number} amountToRefund - amount to refund * @param {number} refundAmount - amount to refund
* @returns {string} refunded payment intent * @return {Promise<PaymentData>} refunded payment intent
*/ */
async refundPayment(payment, amountToRefund) { async refundPayment(payment, refundAmount) {
return await this.stripeProviderService_.refundPayment( return await this.stripeProviderService_.refundPayment(
payment, payment,
amountToRefund refundAmount
) )
} }
/** /**
* Cancels payment for Stripe payment intent. * Cancels payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @returns {object} canceled payment intent * @return {Promise<PaymentData>} canceled payment intent
*/ */
async cancelPayment(payment) { async cancelPayment(payment) {
return await this.stripeProviderService_.cancelPayment(payment) return await this.stripeProviderService_.cancelPayment(payment)
@@ -1,4 +1,3 @@
import _ from "lodash"
import Stripe from "stripe" import Stripe from "stripe"
import { PaymentService } from "medusa-interfaces" import { PaymentService } from "medusa-interfaces"
@@ -6,10 +5,25 @@ class IdealProviderService extends PaymentService {
static identifier = "stripe-ideal" static identifier = "stripe-ideal"
constructor( constructor(
{ stripeProviderService, customerService, totalsService, regionService }, {
stripeProviderService,
customerService,
totalsService,
regionService,
manager,
},
options options
) { ) {
super() super(
{
stripeProviderService,
customerService,
totalsService,
regionService,
manager,
},
options
)
/** /**
* Required Stripe options: * Required Stripe options:
@@ -36,13 +50,15 @@ class IdealProviderService extends PaymentService {
/** @private @const {TotalsService} */ /** @private @const {TotalsService} */
this.totalsService_ = totalsService this.totalsService_ = totalsService
this.manager_ = manager
} }
/** /**
* Fetches Stripe payment intent. Check its status and returns the * Fetches Stripe payment intent. Check its status and returns the
* corresponding Medusa status. * corresponding Medusa status.
* @param {object} paymentData - payment method data from cart * @param {PaymentSessionData} paymentSessionData - payment method data from cart
* @returns {string} the status of the payment intent * @return {Promise<PaymentSessionStatus>} the status of the payment intent
*/ */
async getStatus(paymentData) { async getStatus(paymentData) {
return await this.stripeProviderService_.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. * Fetches a customers saved payment methods if registered in Stripe.
* @param {object} customer - customer to fetch saved cards for * @param {object} customer - customer to fetch saved cards for
* @returns {Promise<Array<object>>} saved payments methods * @return {Promise<Data[]>} saved payments methods
*/ */
async retrieveSavedMethods(customer) { async retrieveSavedMethods(customer) {
return Promise.resolve([]) return Promise.resolve([])
@@ -60,7 +76,7 @@ class IdealProviderService extends PaymentService {
/** /**
* Fetches a Stripe customer * Fetches a Stripe customer
* @param {string} customerId - Stripe customer id * @param {string} customerId - Stripe customer id
* @returns {Promise<object>} Stripe customer * @return {Promise<object>} Stripe customer
*/ */
async retrieveCustomer(customerId) { async retrieveCustomer(customerId) {
return await this.stripeProviderService_.retrieveCustomer(customerId) return await this.stripeProviderService_.retrieveCustomer(customerId)
@@ -69,28 +85,36 @@ class IdealProviderService extends PaymentService {
/** /**
* Creates a Stripe customer using a Medusa customer. * Creates a Stripe customer using a Medusa customer.
* @param {object} customer - Customer data from Medusa * @param {object} customer - Customer data from Medusa
* @returns {Promise<object>} Stripe customer * @return {Promise<object>} Stripe customer
*/ */
async createCustomer(customer) { async createCustomer(customer) {
return await this.stripeProviderService_.createCustomer(customer) return await this.stripeProviderService_
.withTransaction(this.manager_)
.createCustomer(customer)
} }
/** /**
* Creates a Stripe payment intent. * Creates a Stripe payment intent.
* If customer is not registered in Stripe, we do so. * If customer is not registered in Stripe, we do so.
* @param {object} cart - cart to create a payment for * @param {Cart} cart - cart to create a payment for
* @returns {object} Stripe payment intent * @return {Promise<PaymentSessionData>} Stripe payment intent
*/ */
async createPayment(cart) { async createPayment(cart) {
const { customer_id, region_id, email } = 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 { currency_code } = region
const amount = await this.totalsService_.getTotal(cart) const amount = await this.totalsService_
.withTransaction(this.manager_)
.getTotal(cart)
const intentRequest = { const intentRequest = {
amount: Math.round(amount), 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, currency: currency_code,
payment_method_types: ["ideal"], payment_method_types: ["ideal"],
capture_method: "automatic", capture_method: "automatic",
@@ -98,7 +122,9 @@ class IdealProviderService extends PaymentService {
} }
if (customer_id) { 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) { if (customer.metadata?.stripe_id) {
intentRequest.customer = customer.metadata.stripe_id intentRequest.customer = customer.metadata.stripe_id
@@ -118,57 +144,53 @@ class IdealProviderService extends PaymentService {
intentRequest.customer = stripeCustomer.id intentRequest.customer = stripeCustomer.id
} }
const paymentIntent = await this.stripe_.paymentIntents.create( return await this.stripe_.paymentIntents.create(intentRequest)
intentRequest
)
return paymentIntent
} }
/** /**
* Retrieves Stripe payment intent. * Retrieves Stripe payment intent.
* @param {object} data - the data of the payment to retrieve * @param {PaymentData} paymentData - the data of the payment to retrieve
* @returns {Promise<object>} Stripe payment intent * @return {Promise<Data>} Stripe payment intent
*/ */
async retrievePayment(data) { async retrievePayment(paymentData) {
return await this.stripeProviderService_.retrievePayment(data) return await this.stripeProviderService_.retrievePayment(paymentData)
} }
/** /**
* Gets a Stripe payment intent and returns it. * Gets a Stripe payment intent and returns it.
* @param {object} sessionData - the data of the payment to retrieve * @param {PaymentSession} paymentSession - the data of the payment to retrieve
* @returns {Promise<object>} Stripe payment intent * @return {Promise<PaymentData>} Stripe payment intent
*/ */
async getPaymentData(sessionData) { async getPaymentData(paymentSession) {
return await this.stripeProviderService_.getPaymentData(sessionData) return await this.stripeProviderService_.getPaymentData(paymentSession)
} }
/** /**
* Authorizes Stripe payment intent by simply returning * Authorizes Stripe payment intent by simply returning
* the status for the payment intent in use. * 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 * @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( return await this.stripeProviderService_.authorizePayment(
sessionData, paymentSession,
context context
) )
} }
async updatePaymentData(sessionData, update) { async updatePaymentData(paymentSessionData, data) {
return await this.stripeProviderService_.updatePaymentData( return await this.stripeProviderService_.updatePaymentData(
sessionData, paymentSessionData,
update data
) )
} }
/** /**
* Updates Stripe payment intent. * Updates Stripe payment intent.
* @param {object} sessionData - payment session data. * @param {PaymentSessionData} paymentSessionData - payment session data.
* @param {object} update - objec to update intent with * @param {Cart} cart
* @returns {object} Stripe payment intent * @return {Promise<PaymentSessionData>} Stripe payment intent
*/ */
async updatePayment(sessionData, cart) { async updatePayment(sessionData, cart) {
try { try {
@@ -190,15 +212,15 @@ class IdealProviderService extends PaymentService {
} }
} }
async deletePayment(payment) { async deletePayment(paymentSession) {
return await this.stripeProviderService_.deletePayment(payment) return await this.stripeProviderService_.deletePayment(paymentSession)
} }
/** /**
* Updates customer of Stripe payment intent. * Updates customer of Stripe payment intent.
* @param {string} paymentIntentId - id of payment intent to update * @param {string} paymentIntentId - id of payment intent to update
* @param {string} customerId - id of new Stripe customer * @param {string} customerId - id of new Stripe customer
* @returns {object} Stripe payment intent * @return {object} Stripe payment intent
*/ */
async updatePaymentIntentCustomer(paymentIntentId, customerId) { async updatePaymentIntentCustomer(paymentIntentId, customerId) {
return await this.stripeProviderService_.updatePaymentIntentCustomer( return await this.stripeProviderService_.updatePaymentIntentCustomer(
@@ -209,8 +231,8 @@ class IdealProviderService extends PaymentService {
/** /**
* Captures payment for Stripe payment intent. * Captures payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @returns {object} Stripe payment intent * @return {Promise<PaymentData>} Stripe payment intent
*/ */
async capturePayment(payment) { async capturePayment(payment) {
return await this.stripeProviderService_.capturePayment(payment) return await this.stripeProviderService_.capturePayment(payment)
@@ -218,21 +240,21 @@ class IdealProviderService extends PaymentService {
/** /**
* Refunds payment for Stripe payment intent. * Refunds payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @param {number} amountToRefund - amount to refund * @param {number} refundAmount - amount to refund
* @returns {string} refunded payment intent * @return {Promise<PaymentData>} refunded payment intent
*/ */
async refundPayment(payment, amountToRefund) { async refundPayment(payment, refundAmount) {
return await this.stripeProviderService_.refundPayment( return await this.stripeProviderService_.refundPayment(
payment, payment,
amountToRefund refundAmount
) )
} }
/** /**
* Cancels payment for Stripe payment intent. * Cancels payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @returns {object} canceled payment intent * @return {Promise<PaymentData>} canceled payment intent
*/ */
async cancelPayment(payment) { async cancelPayment(payment) {
return await this.stripeProviderService_.cancelPayment(payment) return await this.stripeProviderService_.cancelPayment(payment)
@@ -1,12 +1,18 @@
import Stripe from "stripe" import Stripe from "stripe"
import { PaymentService } from "medusa-interfaces" import {
import { PaymentSessionStatus } from '@medusajs/medusa/dist' AbstractPaymentService,
PaymentSessionData,
PaymentSessionStatus,
} from "@medusajs/medusa"
class StripeProviderService extends PaymentService { class StripeProviderService extends AbstractPaymentService {
static identifier = "stripe" static identifier = "stripe"
constructor({ customerService, totalsService, regionService }, options) { constructor(
super() { customerService, totalsService, regionService, manager },
options
) {
super({ customerService, totalsService, regionService, manager }, options)
/** /**
* Required Stripe options: * Required Stripe options:
@@ -30,13 +36,16 @@ class StripeProviderService extends PaymentService {
/** @private @const {TotalsService} */ /** @private @const {TotalsService} */
this.totalsService_ = totalsService this.totalsService_ = totalsService
/** @private @const {EntityManager} */
this.manager_ = manager
} }
/** /**
* Fetches Stripe payment intent. Check its status and returns the * Get payment session status
* corresponding Medusa status. * statuses.
* @param {object} paymentData - payment method data from cart * @param {PaymentSessionData} paymentData - the data stored with the payment session
* @returns {string} the status of the payment intent * @return {Promise<PaymentSessionStatus>} the status of the order
*/ */
async getStatus(paymentData) { async getStatus(paymentData) {
const { id } = paymentData const { id } = paymentData
@@ -61,8 +70,8 @@ class StripeProviderService extends PaymentService {
/** /**
* Fetches a customers saved payment methods if registered in Stripe. * Fetches a customers saved payment methods if registered in Stripe.
* @param {object} customer - customer to fetch saved cards for * @param {Customer} customer - customer to fetch saved cards for
* @returns {Promise<Array<object>>} saved payments methods * @return {Promise<Data[]>} saved payments methods
*/ */
async retrieveSavedMethods(customer) { async retrieveSavedMethods(customer) {
if (customer.metadata && customer.metadata.stripe_id) { if (customer.metadata && customer.metadata.stripe_id) {
@@ -101,7 +110,9 @@ class StripeProviderService extends PaymentService {
}) })
if (customer.id) { if (customer.id) {
await this.customerService_.update(customer.id, { await this.customerService_
.withTransaction(this.manager_)
.update(customer.id, {
metadata: { stripe_id: stripeCustomer.id }, metadata: { stripe_id: stripeCustomer.id },
}) })
} }
@@ -115,17 +126,23 @@ class StripeProviderService extends PaymentService {
/** /**
* Creates a Stripe payment intent. * Creates a Stripe payment intent.
* If customer is not registered in Stripe, we do so. * If customer is not registered in Stripe, we do so.
* @param {object} cart - cart to create a payment for * @param {Cart} cart - cart to create a payment for
* @returns {object} Stripe payment intent * @return {Promise<PaymentSessionData>} Stripe payment intent
*/ */
async createPayment(cart) { async createPayment(cart) {
const { customer_id, region_id, email } = 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 = { const intentRequest = {
description: cart?.context?.payment_description ?? this.options_?.payment_description, description:
cart?.context?.payment_description ??
this.options_?.payment_description,
amount: Math.round(amount), amount: Math.round(amount),
currency: currency_code, currency: currency_code,
setup_future_usage: "on_session", setup_future_usage: "on_session",
@@ -134,7 +151,9 @@ class StripeProviderService extends PaymentService {
} }
if (customer_id) { 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) { if (customer.metadata?.stripe_id) {
intentRequest.customer = customer.metadata.stripe_id intentRequest.customer = customer.metadata.stripe_id
@@ -154,15 +173,13 @@ class StripeProviderService extends PaymentService {
intentRequest.customer = stripeCustomer.id intentRequest.customer = stripeCustomer.id
} }
return await this.stripe_.paymentIntents.create( return await this.stripe_.paymentIntents.create(intentRequest)
intentRequest
)
} }
/** /**
* Retrieves Stripe payment intent. * Retrieves Stripe payment intent.
* @param {object} data - the data of the payment to retrieve * @param {PaymentData} paymentData - the data of the payment to retrieve
* @returns {Promise<object>} Stripe payment intent * @return {Promise<Data>} Stripe payment intent
*/ */
async retrievePayment(data) { async retrievePayment(data) {
try { try {
@@ -174,12 +191,12 @@ class StripeProviderService extends PaymentService {
/** /**
* Gets a Stripe payment intent and returns it. * Gets a Stripe payment intent and returns it.
* @param {object} sessionData - the data of the payment to retrieve * @param {PaymentSession} paymentSession - the data of the payment to retrieve
* @returns {Promise<object>} Stripe payment intent * @return {Promise<PaymentData>} Stripe payment intent
*/ */
async getPaymentData(sessionData) { async getPaymentData(paymentSession) {
try { try {
return this.stripe_.paymentIntents.retrieve(sessionData.data.id) return this.stripe_.paymentIntents.retrieve(paymentSession.data.id)
} catch (error) { } catch (error) {
throw error throw error
} }
@@ -188,15 +205,15 @@ class StripeProviderService extends PaymentService {
/** /**
* Authorizes Stripe payment intent by simply returning * Authorizes Stripe payment intent by simply returning
* the status for the payment intent in use. * 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 * @param {Data} 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 = {}) {
const stat = await this.getStatus(sessionData.data) const stat = await this.getStatus(paymentSession.data)
try { try {
return { data: sessionData.data, status: stat } return { data: paymentSession.data, status: stat }
} catch (error) { } catch (error) {
throw error throw error
} }
@@ -214,9 +231,9 @@ class StripeProviderService extends PaymentService {
/** /**
* Updates Stripe payment intent. * Updates Stripe payment intent.
* @param {object} sessionData - payment session data. * @param {PaymentSessionData} paymentSessionData - payment session data.
* @param {object} update - objec to update intent with * @param {Cart} cart
* @returns {object} Stripe payment intent * @return {Promise<PaymentSessionData>} Stripe payment intent
*/ */
async updatePayment(sessionData, cart) { async updatePayment(sessionData, cart) {
try { try {
@@ -270,8 +287,8 @@ class StripeProviderService extends PaymentService {
/** /**
* Captures payment for Stripe payment intent. * Captures payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @returns {object} Stripe payment intent * @return {Promise<PaymentData>} Stripe payment intent
*/ */
async capturePayment(payment) { async capturePayment(payment) {
const { id } = payment.data const { id } = payment.data
@@ -290,9 +307,9 @@ class StripeProviderService extends PaymentService {
/** /**
* Refunds payment for Stripe payment intent. * Refunds payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @param {number} amountToRefund - amount to refund * @param {number} refundAmount - amount to refund
* @returns {string} refunded payment intent * @return {Promise<PaymentData>} refunded payment intent
*/ */
async refundPayment(payment, amountToRefund) { async refundPayment(payment, amountToRefund) {
const { id } = payment.data const { id } = payment.data
@@ -310,8 +327,8 @@ class StripeProviderService extends PaymentService {
/** /**
* Cancels payment for Stripe payment intent. * Cancels payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @returns {object} canceled payment intent * @return {Promise<PaymentData>} canceled payment intent
*/ */
async cancelPayment(payment) { async cancelPayment(payment) {
const { id } = payment.data const { id } = payment.data
@@ -1,15 +1,29 @@
import _ from "lodash"
import Stripe from "stripe" 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" static identifier = "stripe-przelewy24"
constructor( constructor(
{ stripeProviderService, customerService, totalsService, regionService }, {
stripeProviderService,
customerService,
totalsService,
regionService,
manager,
},
options options
) { ) {
super() super(
{
stripeProviderService,
customerService,
totalsService,
regionService,
manager,
},
options
)
/** /**
* Required Stripe options: * Required Stripe options:
@@ -36,13 +50,15 @@ class Przelewy24ProviderService extends PaymentService {
/** @private @const {TotalsService} */ /** @private @const {TotalsService} */
this.totalsService_ = totalsService this.totalsService_ = totalsService
this.manager_ = manager
} }
/** /**
* Fetches Stripe payment intent. Check its status and returns the * Fetches Stripe payment intent. Check its status and returns the
* corresponding Medusa status. * corresponding Medusa status.
* @param {object} paymentData - payment method data from cart * @param {PaymentSessionData} paymentSessionData - payment method data from cart
* @returns {string} the status of the payment intent * @return {Promise<PaymentSessionStatus>} the status of the payment intent
*/ */
async getStatus(paymentData) { async getStatus(paymentData) {
return await this.stripeProviderService_.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. * Fetches a customers saved payment methods if registered in Stripe.
* @param {object} customer - customer to fetch saved cards for * @param {object} customer - customer to fetch saved cards for
* @returns {Promise<Array<object>>} saved payments methods * @return {Promise<Data[]>} saved payments methods
*/ */
async retrieveSavedMethods(customer) { async retrieveSavedMethods(customer) {
return Promise.resolve([]) return Promise.resolve([])
@@ -60,7 +76,7 @@ class Przelewy24ProviderService extends PaymentService {
/** /**
* Fetches a Stripe customer * Fetches a Stripe customer
* @param {string} customerId - Stripe customer id * @param {string} customerId - Stripe customer id
* @returns {Promise<object>} Stripe customer * @return {Promise<object>} Stripe customer
*/ */
async retrieveCustomer(customerId) { async retrieveCustomer(customerId) {
return await this.stripeProviderService_.retrieveCustomer(customerId) return await this.stripeProviderService_.retrieveCustomer(customerId)
@@ -69,10 +85,12 @@ class Przelewy24ProviderService extends PaymentService {
/** /**
* Creates a Stripe customer using a Medusa customer. * Creates a Stripe customer using a Medusa customer.
* @param {object} customer - Customer data from Medusa * @param {object} customer - Customer data from Medusa
* @returns {Promise<object>} Stripe customer * @return {Promise<object>} Stripe customer
*/ */
async createCustomer(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) { async createPayment(cart) {
const { customer_id, region_id, email } = 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 { currency_code } = region
const amount = await this.totalsService_.getTotal(cart) const amount = await this.totalsService_
.withTransaction(this.manager_)
.getTotal(cart)
const intentRequest = { const intentRequest = {
amount: Math.round(amount), amount: Math.round(amount),
@@ -97,7 +119,9 @@ class Przelewy24ProviderService extends PaymentService {
} }
if (customer_id) { 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) { if (customer.metadata?.stripe_id) {
intentRequest.customer = customer.metadata.stripe_id intentRequest.customer = customer.metadata.stripe_id
@@ -117,57 +141,53 @@ class Przelewy24ProviderService extends PaymentService {
intentRequest.customer = stripeCustomer.id intentRequest.customer = stripeCustomer.id
} }
const paymentIntent = await this.stripe_.paymentIntents.create( return await this.stripe_.paymentIntents.create(intentRequest)
intentRequest
)
return paymentIntent
} }
/** /**
* Retrieves Stripe payment intent. * Retrieves Stripe payment intent.
* @param {object} data - the data of the payment to retrieve * @param {PaymentData} paymentData - the data of the payment to retrieve
* @returns {Promise<object>} Stripe payment intent * @return {Promise<Data>} Stripe payment intent
*/ */
async retrievePayment(data) { async retrievePayment(paymentData) {
return await this.stripeProviderService_.retrievePayment(data) return await this.stripeProviderService_.retrievePayment(paymentData)
} }
/** /**
* Gets a Stripe payment intent and returns it. * Gets a Stripe payment intent and returns it.
* @param {object} sessionData - the data of the payment to retrieve * @param {PaymentSession} paymentSession - the data of the payment to retrieve
* @returns {Promise<object>} Stripe payment intent * @return {Promise<PaymentData>} Stripe payment intent
*/ */
async getPaymentData(sessionData) { async getPaymentData(paymentSession) {
return await this.stripeProviderService_.getPaymentData(sessionData) return await this.stripeProviderService_.getPaymentData(paymentSession)
} }
/** /**
* Authorizes Stripe payment intent by simply returning * Authorizes Stripe payment intent by simply returning
* the status for the payment intent in use. * 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 * @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( return await this.stripeProviderService_.authorizePayment(
sessionData, paymentSession,
context context
) )
} }
async updatePaymentData(sessionData, update) { async updatePaymentData(paymentSessionData, data) {
return await this.stripeProviderService_.updatePaymentData( return await this.stripeProviderService_.updatePaymentData(
sessionData, paymentSessionData,
update data
) )
} }
/** /**
* Updates Stripe payment intent. * Updates Stripe payment intent.
* @param {object} sessionData - payment session data. * @param {PaymentSessionData} paymentSessionData - payment session data.
* @param {object} update - objec to update intent with * @param {Cart} cart
* @returns {object} Stripe payment intent * @return {Promise<PaymentSessionData>} Stripe payment intent
*/ */
async updatePayment(sessionData, cart) { async updatePayment(sessionData, cart) {
try { try {
@@ -189,15 +209,15 @@ class Przelewy24ProviderService extends PaymentService {
} }
} }
async deletePayment(payment) { async deletePayment(paymentSession) {
return await this.stripeProviderService_.deletePayment(payment) return await this.stripeProviderService_.deletePayment(paymentSession)
} }
/** /**
* Updates customer of Stripe payment intent. * Updates customer of Stripe payment intent.
* @param {string} paymentIntentId - id of payment intent to update * @param {string} paymentIntentId - id of payment intent to update
* @param {string} customerId - id of new Stripe customer * @param {string} customerId - id of new Stripe customer
* @returns {object} Stripe payment intent * @return {object} Stripe payment intent
*/ */
async updatePaymentIntentCustomer(paymentIntentId, customerId) { async updatePaymentIntentCustomer(paymentIntentId, customerId) {
return await this.stripeProviderService_.updatePaymentIntentCustomer( return await this.stripeProviderService_.updatePaymentIntentCustomer(
@@ -208,8 +228,8 @@ class Przelewy24ProviderService extends PaymentService {
/** /**
* Captures payment for Stripe payment intent. * Captures payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @returns {object} Stripe payment intent * @return {Promise<PaymentData>} Stripe payment intent
*/ */
async capturePayment(payment) { async capturePayment(payment) {
return await this.stripeProviderService_.capturePayment(payment) return await this.stripeProviderService_.capturePayment(payment)
@@ -217,21 +237,21 @@ class Przelewy24ProviderService extends PaymentService {
/** /**
* Refunds payment for Stripe payment intent. * Refunds payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @param {number} amountToRefund - amount to refund * @param {number} refundAmount - amount to refund
* @returns {string} refunded payment intent * @return {Promise<PaymentData>} refunded payment intent
*/ */
async refundPayment(payment, amountToRefund) { async refundPayment(payment, refundAmount) {
return await this.stripeProviderService_.refundPayment( return await this.stripeProviderService_.refundPayment(
payment, payment,
amountToRefund refundAmount
) )
} }
/** /**
* Cancels payment for Stripe payment intent. * Cancels payment for Stripe payment intent.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment method data from cart
* @returns {object} canceled payment intent * @return {Promise<PaymentData>} canceled payment intent
*/ */
async cancelPayment(payment) { async cancelPayment(payment) {
return await this.stripeProviderService_.cancelPayment(payment) return await this.stripeProviderService_.cancelPayment(payment)
@@ -1,14 +1,14 @@
class CartSubscriber { class CartSubscriber {
constructor({ constructor({
manager,
cartService, cartService,
customerService,
paymentProviderService, paymentProviderService,
eventBusService, eventBusService,
}) { }) {
this.cartService_ = cartService this.cartService_ = cartService
this.customerService_ = customerService
this.paymentProviderService_ = paymentProviderService this.paymentProviderService_ = paymentProviderService
this.eventBus_ = eventBusService this.eventBus_ = eventBusService
this.manager_ = manager
this.eventBus_.subscribe("cart.customer_updated", async (cart) => { this.eventBus_.subscribe("cart.customer_updated", async (cart) => {
await this.onCustomerUpdated(cart) await this.onCustomerUpdated(cart)
@@ -16,16 +16,19 @@ class CartSubscriber {
} }
async onCustomerUpdated(cartId) { async onCustomerUpdated(cartId) {
const cart = await this.cartService_.retrieve(cartId, { await this.manager_.transaction(async (transactionManager) => {
const cart = await this.cartService_
.withTransaction(transactionManager)
.retrieve(cartId, {
select: [ select: [
"subtotal", "subtotal",
"tax_total", "tax_total",
"shipping_total", "shipping_total",
"discount_total", "discount_total",
"gift_card_total",
"total", "total",
], ],
relations: [ relations: [
"items",
"billing_address", "billing_address",
"shipping_address", "shipping_address",
"region", "region",
@@ -46,8 +49,11 @@ class CartSubscriber {
) )
if (session) { if (session) {
return await this.paymentProviderService_.updateSession(session, cart) return await this.paymentProviderService_
.withTransaction(transactionManager)
.updateSession(session, cart)
} }
})
} }
} }
@@ -12,8 +12,7 @@ export type Data = Record<string, unknown>
export type PaymentData = Data export type PaymentData = Data
export type PaymentSessionData = Data export type PaymentSessionData = Data
export interface PaymentService<T extends TransactionBaseService> export interface PaymentService extends TransactionBaseService {
extends TransactionBaseService {
getIdentifier(): string getIdentifier(): string
getPaymentData(paymentSession: PaymentSession): Promise<PaymentData> getPaymentData(paymentSession: PaymentSession): Promise<PaymentData>
@@ -50,9 +49,9 @@ export interface PaymentService<T extends TransactionBaseService>
getStatus(data: Data): Promise<PaymentSessionStatus> getStatus(data: Data): Promise<PaymentSessionStatus>
} }
export abstract class AbstractPaymentService<T extends TransactionBaseService> export abstract class AbstractPaymentService
extends TransactionBaseService extends TransactionBaseService
implements PaymentService<T> implements PaymentService
{ {
protected constructor(container: unknown, config?: Record<string, unknown>) { protected constructor(container: unknown, config?: Record<string, unknown>) {
super(container, config) super(container, config)
+10 -6
View File
@@ -1,6 +1,6 @@
import { import {
BaseNotificationService,
BaseFulfillmentService, BaseFulfillmentService,
BaseNotificationService,
BasePaymentService, BasePaymentService,
} from "medusa-interfaces" } from "medusa-interfaces"
import { currencies } from "../utils/currencies" import { currencies } from "../utils/currencies"
@@ -82,7 +82,8 @@ export default async ({
const hasCountries = await countryRepo.findOne() const hasCountries = await countryRepo.findOne()
if (!hasCountries) { if (!hasCountries) {
for (const c of countries) { 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 iso2 = c.alpha2.toLowerCase()
const iso3 = c.alpha3.toLowerCase() const iso3 = c.alpha3.toLowerCase()
@@ -106,7 +107,8 @@ export default async ({
const hasCurrencies = await currencyRepo.findOne() const hasCurrencies = await currencyRepo.findOne()
if (!hasCurrencies) { if (!hasCurrencies) {
for (const [, c] of Object.entries(currencies)) { 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 code = c.code.toLowerCase()
const sym = c.symbol const sym = c.symbol
@@ -122,9 +124,11 @@ export default async ({
await storeService.withTransaction(manager).create() await storeService.withTransaction(manager).create()
const payProviders = const payProviders =
silentResolution< silentResolution<(typeof BasePaymentService | AbstractPaymentService)[]>(
(typeof BasePaymentService | AbstractPaymentService<never>)[] container,
>(container, "paymentProviders", logger) || [] "paymentProviders",
logger
) || []
const payIds = payProviders.map((p) => p.getIdentifier()) const payIds = payProviders.map((p) => p.getIdentifier())
const pProviderService = container.resolve<PaymentProviderService>( const pProviderService = container.resolve<PaymentProviderService>(
+4 -5
View File
@@ -1,9 +1,7 @@
import { isEmpty, isEqual } from "lodash" import { isEmpty, isEqual } from "lodash"
import { MedusaError } from "medusa-core-utils" import { MedusaError } from "medusa-core-utils"
import { DeepPartial, EntityManager, In } from "typeorm" import { DeepPartial, EntityManager, In } from "typeorm"
import { TransactionBaseService } from "../interfaces" import { IPriceSelectionStrategy, TransactionBaseService } from "../interfaces"
import { IPriceSelectionStrategy } from "../interfaces/price-selection-strategy"
import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels"
import { import {
Address, Address,
Cart, Cart,
@@ -36,7 +34,6 @@ import CustomerService from "./customer"
import DiscountService from "./discount" import DiscountService from "./discount"
import EventBusService from "./event-bus" import EventBusService from "./event-bus"
import GiftCardService from "./gift-card" import GiftCardService from "./gift-card"
import { SalesChannelService } from "./index"
import InventoryService from "./inventory" import InventoryService from "./inventory"
import LineItemService from "./line-item" import LineItemService from "./line-item"
import LineItemAdjustmentService from "./line-item-adjustment" import LineItemAdjustmentService from "./line-item-adjustment"
@@ -45,9 +42,11 @@ import ProductService from "./product"
import ProductVariantService from "./product-variant" import ProductVariantService from "./product-variant"
import RegionService from "./region" import RegionService from "./region"
import ShippingOptionService from "./shipping-option" import ShippingOptionService from "./shipping-option"
import StoreService from "./store"
import TaxProviderService from "./tax-provider" import TaxProviderService from "./tax-provider"
import TotalsService from "./totals" import TotalsService from "./totals"
import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels"
import StoreService from "./store"
import { SalesChannelService } from "./index"
type InjectedDependencies = { type InjectedDependencies = {
manager: EntityManager manager: EntityManager
@@ -26,7 +26,7 @@ type InjectedDependencies = {
refundRepository: typeof RefundRepository refundRepository: typeof RefundRepository
} & { } & {
[key in `${PaymentProviderKey}`]: [key in `${PaymentProviderKey}`]:
| AbstractPaymentService<never> | AbstractPaymentService
| typeof BasePaymentService | typeof BasePaymentService
} }
@@ -275,11 +275,11 @@ export default class PaymentProviderService extends TransactionBaseService {
* @return {PaymentService} the payment provider * @return {PaymentService} the payment provider
*/ */
retrieveProvider< retrieveProvider<
TProvider extends AbstractPaymentService<never> | typeof BasePaymentService TProvider extends AbstractPaymentService | typeof BasePaymentService
>( >(
providerId: string providerId: string
): TProvider extends AbstractPaymentService<never> ): TProvider extends AbstractPaymentService
? AbstractPaymentService<never> ? AbstractPaymentService
: typeof BasePaymentService { : typeof BasePaymentService {
try { try {
let provider let provider