fix(core-flows): refresh payment collection inside updateCartPromotionsWorkflow (#13963)

* Refresh payment collection after cart promotion update

* Add missing test

* Add changeset

* Update changeset

* Add force_refresh_payment_collection to updateCartPromotionsWorkflow to conditionally refresh payment collection

* Prevent refreshing payment collection multiple times

* Fix test

* Formatting and unused vars

---------

Co-authored-by: Adrien de Peretti <adrien.deperetti@gmail.com>
This commit is contained in:
Nicolas Gorga
2025-12-05 15:27:21 -03:00
committed by GitHub
co-authored by Adrien de Peretti
parent 144f0f4e2e
commit 842c0f5007
5 changed files with 88 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@medusajs/core-flows": patch
---
fix(core-flows): refresh payment collection inside updateCartPromotionsWorkflow
@@ -5299,6 +5299,72 @@ medusaIntegrationTestRunner({
})
})
describe("DELETE /store/carts/:id/promotions", () => {
it("should remove promotions and recalculate payment_collection amount", async () => {
cart = (
await api.post(
`/store/carts`,
{
currency_code: "usd",
sales_channel_id: salesChannel.id,
region_id: region.id,
shipping_address: shippingAddressData,
items: [{ variant_id: product.variants[0].id, quantity: 1 }],
promo_codes: [promotion.code],
},
storeHeaders
)
).data.cart
await api.post(
`/store/payment-collections`,
{ cart_id: cart.id },
storeHeaders
)
cart = (await api.get(`/store/carts/${cart.id}`, storeHeaders)).data
.cart
expect(cart).toEqual(
expect.objectContaining({
id: cart.id,
items: expect.arrayContaining([
expect.objectContaining({
adjustments: expect.arrayContaining([
expect.objectContaining({
code: "PROMOTION_APPLIED",
promotion_id: promotion.id,
amount: 100,
}),
]),
}),
]),
})
)
const cartAfterDeletion = await api
.delete(`/store/carts/${cart.id}/promotions`, {
data: { promo_codes: [promotion.code] },
...storeHeaders,
})
.then((response) => response.data.cart)
expect(cartAfterDeletion).toEqual(
expect.objectContaining({
id: cart.id,
items: expect.arrayContaining([
expect.objectContaining({
adjustments: [],
}),
]),
})
)
expect(cartAfterDeletion.total).toEqual(1500)
expect(cartAfterDeletion.discount_total).toEqual(0)
})
})
describe("POST /store/carts/:id/customer", () => {
beforeEach(async () => {
cart = (
@@ -234,6 +234,7 @@ export const createCartWorkflow = createWorkflow(
input: {
cart_id: cart.id,
promo_codes: input.promo_codes,
force_refresh_payment_collection: false,
},
})
@@ -230,6 +230,7 @@ export const refreshCartItemsWorkflow = createWorkflow(
cart: refetchedCart, // Pass cart to avoid refetch in updateCartPromotionsWorkflow
promo_codes: cartPromoCodes,
action: PromotionActions.REPLACE,
force_refresh_payment_collection: false,
},
})
@@ -22,6 +22,7 @@ import {
} from "../steps"
import { updateCartPromotionsStep } from "../steps/update-cart-promotions"
import { cartFieldsForRefreshSteps } from "../utils/fields"
import { refreshPaymentCollectionForCartWorkflow } from "./refresh-payment-collection"
/**
* The details of the promotion updates on a cart.
@@ -47,6 +48,11 @@ export type UpdateCartPromotionsWorkflowInput = {
| PromotionActions.ADD
| PromotionActions.REMOVE
| PromotionActions.REPLACE
/**
* Wether to force the refresh of the cart payment collection. If the caller doesn't refresh it explicitly,
* you should probably set this property to true.
*/
force_refresh_payment_collection?: boolean
}
export const updateCartPromotionsWorkflowId = "update-cart-promotions"
@@ -153,6 +159,15 @@ export const updateCartPromotionsWorkflow = createWorkflow(
})
)
when(
{ input },
({ input }) => input.force_refresh_payment_collection === true
).then(() => {
refreshPaymentCollectionForCartWorkflow.runAsStep({
input: { cart },
})
})
releaseLockStep({
key: cart.id,
})