fix: Idempotent cart completion (#9231)
What - Store result of cart-completion workflow for three days by default - This enables the built-in idempotency mechanism to kick-in, provided the same transaction ID is used on workflow executions - Return order from cart-completion workflow if the cart has already been completed - In case transaction ID is not used on workflow executions, we still only want to complete a cart once
This commit is contained in:
@@ -27,6 +27,7 @@ import {
|
||||
UpdatePaymentDTO,
|
||||
UpdatePaymentSessionDTO,
|
||||
UpsertPaymentCollectionDTO,
|
||||
WebhookActionResult,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
BigNumber,
|
||||
@@ -37,7 +38,6 @@ import {
|
||||
MedusaContext,
|
||||
MedusaError,
|
||||
ModulesSdkUtils,
|
||||
PaymentActions,
|
||||
PaymentCollectionStatus,
|
||||
PaymentSessionStatus,
|
||||
promiseAll,
|
||||
@@ -425,20 +425,19 @@ export default class PaymentModuleService
|
||||
"amount",
|
||||
"raw_amount",
|
||||
"currency_code",
|
||||
"authorized_at",
|
||||
"payment_collection_id",
|
||||
],
|
||||
relations: ["payment", "payment_collection"],
|
||||
},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
// this method needs to be idempotent
|
||||
if (session.authorized_at) {
|
||||
const payment = await this.paymentService_.retrieve(
|
||||
{ session_id: session.id },
|
||||
{ relations: ["payment_collection"] },
|
||||
sharedContext
|
||||
)
|
||||
return await this.baseRepository_.serialize(payment, { populate: true })
|
||||
if (session.payment && session.authorized_at) {
|
||||
return await this.baseRepository_.serialize(session.payment, {
|
||||
populate: true,
|
||||
})
|
||||
}
|
||||
|
||||
let { data, status } = await this.paymentProviderService_.authorizePayment(
|
||||
@@ -849,45 +848,16 @@ export default class PaymentModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
async processEvent(
|
||||
async getWebhookActionAndData(
|
||||
eventData: ProviderWebhookPayload,
|
||||
@MedusaContext() sharedContext?: Context
|
||||
): Promise<void> {
|
||||
): Promise<WebhookActionResult> {
|
||||
const providerId = `pp_${eventData.provider}`
|
||||
|
||||
const event = await this.paymentProviderService_.getWebhookActionAndData(
|
||||
return await this.paymentProviderService_.getWebhookActionAndData(
|
||||
providerId,
|
||||
eventData.payload
|
||||
)
|
||||
|
||||
if (event.action === PaymentActions.NOT_SUPPORTED) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (event.action) {
|
||||
case PaymentActions.SUCCESSFUL: {
|
||||
const [payment] = await this.listPayments(
|
||||
{
|
||||
payment_session_id: event.data.session_id,
|
||||
},
|
||||
{},
|
||||
sharedContext
|
||||
)
|
||||
if (payment && !payment.captured_at) {
|
||||
await this.capturePayment(
|
||||
{ payment_id: payment.id, amount: event.data.amount },
|
||||
sharedContext
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
case PaymentActions.AUTHORIZED:
|
||||
await this.authorizePaymentSession(
|
||||
event.data.session_id,
|
||||
{},
|
||||
sharedContext
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
|
||||
Reference in New Issue
Block a user