feat: Improvements to payment module and Stripe provider (#10980)
* fix: Correctly parse Stripe error, remove unused method * fix: Isolate the payment provider error check function * fix: Allow passing few extra parameters to Stripe --------- Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
co-authored by
Oli Juhl
parent
44cd0224af
commit
f5235862c0
@@ -1,5 +1,3 @@
|
||||
import { EOL } from "os"
|
||||
|
||||
import Stripe from "stripe"
|
||||
|
||||
import {
|
||||
@@ -13,9 +11,7 @@ import {
|
||||
import {
|
||||
AbstractPaymentProvider,
|
||||
isDefined,
|
||||
isPaymentProviderError,
|
||||
isPresent,
|
||||
MedusaError,
|
||||
PaymentActions,
|
||||
PaymentSessionStatus,
|
||||
} from "@medusajs/framework/utils"
|
||||
@@ -60,23 +56,37 @@ abstract class StripeBase extends AbstractPaymentProvider<StripeOptions> {
|
||||
return this.options_
|
||||
}
|
||||
|
||||
getPaymentIntentOptions(): PaymentIntentOptions {
|
||||
const options: PaymentIntentOptions = {}
|
||||
normalizePaymentIntentParameters(
|
||||
extra?: Record<string, unknown>
|
||||
): Partial<Stripe.PaymentIntentCreateParams> {
|
||||
const res = {} as Partial<Stripe.PaymentIntentCreateParams>
|
||||
|
||||
if (this?.paymentIntentOptions?.capture_method) {
|
||||
options.capture_method = this.paymentIntentOptions.capture_method
|
||||
}
|
||||
res.description = (extra?.payment_description ??
|
||||
this.options_?.paymentDescription) as string
|
||||
|
||||
if (this?.paymentIntentOptions?.setup_future_usage) {
|
||||
options.setup_future_usage = this.paymentIntentOptions.setup_future_usage
|
||||
}
|
||||
res.capture_method =
|
||||
(extra?.capture_method as "automatic" | "manual") ??
|
||||
this.paymentIntentOptions.capture_method ??
|
||||
(this.options_.capture ? "automatic" : "manual")
|
||||
|
||||
if (this?.paymentIntentOptions?.payment_method_types) {
|
||||
options.payment_method_types =
|
||||
this.paymentIntentOptions.payment_method_types
|
||||
}
|
||||
res.setup_future_usage =
|
||||
(extra?.setup_future_usage as "off_session" | "on_session" | undefined) ??
|
||||
this.paymentIntentOptions.setup_future_usage
|
||||
|
||||
return options
|
||||
res.payment_method_types = this.paymentIntentOptions
|
||||
.payment_method_types as string[]
|
||||
|
||||
res.automatic_payment_methods =
|
||||
(extra?.automatic_payment_methods as { enabled: true } | undefined) ??
|
||||
(this.options_?.automaticPaymentMethods ? { enabled: true } : undefined)
|
||||
|
||||
res.off_session = extra?.off_session as boolean | undefined
|
||||
|
||||
res.confirm = extra?.confirm as boolean | undefined
|
||||
|
||||
res.payment_method = extra?.payment_method as string | undefined
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
async getPaymentStatus(
|
||||
@@ -106,24 +116,16 @@ abstract class StripeBase extends AbstractPaymentProvider<StripeOptions> {
|
||||
async initiatePayment(
|
||||
input: CreatePaymentProviderSession
|
||||
): Promise<PaymentProviderError | PaymentProviderSessionResponse> {
|
||||
const intentRequestData = this.getPaymentIntentOptions()
|
||||
const { email, extra, session_id, customer } = input.context
|
||||
const { currency_code, amount } = input
|
||||
|
||||
const description = (extra?.payment_description ??
|
||||
this.options_?.paymentDescription) as string
|
||||
const additionalParameters = this.normalizePaymentIntentParameters(extra)
|
||||
|
||||
const intentRequest: Stripe.PaymentIntentCreateParams = {
|
||||
description,
|
||||
amount: getSmallestUnit(amount, currency_code),
|
||||
currency: currency_code,
|
||||
metadata: { session_id: session_id! },
|
||||
capture_method: this.options_.capture ? "automatic" : "manual",
|
||||
...intentRequestData,
|
||||
}
|
||||
|
||||
if (this.options_?.automaticPaymentMethods) {
|
||||
intentRequest.automatic_payment_methods = { enabled: true }
|
||||
...additionalParameters,
|
||||
}
|
||||
|
||||
if (customer?.metadata?.stripe_id) {
|
||||
@@ -273,15 +275,7 @@ abstract class StripeBase extends AbstractPaymentProvider<StripeOptions> {
|
||||
const stripeId = context.customer?.metadata?.stripe_id
|
||||
|
||||
if (stripeId !== data.customer) {
|
||||
const result = await this.initiatePayment(input)
|
||||
if (isPaymentProviderError(result)) {
|
||||
return this.buildError(
|
||||
"An error occurred in updatePayment during the initiate of the new payment for the new customer",
|
||||
result
|
||||
)
|
||||
}
|
||||
|
||||
return result
|
||||
return await this.initiatePayment(input)
|
||||
} else {
|
||||
if (isPresent(amount) && data.amount === amountNumeric) {
|
||||
return { data }
|
||||
@@ -300,25 +294,6 @@ abstract class StripeBase extends AbstractPaymentProvider<StripeOptions> {
|
||||
}
|
||||
}
|
||||
|
||||
async updatePaymentData(sessionId: string, data: Record<string, unknown>) {
|
||||
try {
|
||||
// Prevent from updating the amount from here as it should go through
|
||||
// the updatePayment method to perform the correct logic
|
||||
if (isPresent(data.amount)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Cannot update amount, use updatePayment instead"
|
||||
)
|
||||
}
|
||||
|
||||
return (await this.stripe_.paymentIntents.update(sessionId, {
|
||||
...data,
|
||||
})) as unknown as PaymentProviderSessionResponse["data"]
|
||||
} catch (e) {
|
||||
return this.buildError("An error occurred in updatePaymentData", e)
|
||||
}
|
||||
}
|
||||
|
||||
async getWebhookActionAndData(
|
||||
webhookData: ProviderWebhookPayload["payload"]
|
||||
): Promise<WebhookActionResult> {
|
||||
@@ -374,18 +349,17 @@ abstract class StripeBase extends AbstractPaymentProvider<StripeOptions> {
|
||||
this.options_.webhookSecret
|
||||
)
|
||||
}
|
||||
protected buildError(
|
||||
message: string,
|
||||
error: Stripe.StripeRawError | PaymentProviderError | Error
|
||||
): PaymentProviderError {
|
||||
protected buildError(message: string, error: Error): PaymentProviderError {
|
||||
const errorDetails =
|
||||
"raw" in error ? (error.raw as Stripe.StripeRawError) : error
|
||||
|
||||
return {
|
||||
error: message,
|
||||
code: "code" in error ? error.code : "unknown",
|
||||
detail: isPaymentProviderError(error)
|
||||
? `${error.error}${EOL}${error.detail ?? ""}`
|
||||
: "detail" in error
|
||||
? error.detail
|
||||
: error.message ?? "",
|
||||
error: `${message}: ${error.message}`,
|
||||
code: "code" in errorDetails ? errorDetails.code : "unknown",
|
||||
detail:
|
||||
"detail" in errorDetails
|
||||
? `${error.message}: ${errorDetails.detail}`
|
||||
: error.message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user