fix(core-flows, medusa): Prevent cart addresses duplication on update (#13841)

* Allow id field in addresses properties for cart update validator

* Update cart addresses in update step where id is provided, both reference and nested fields

* Add tests

* Add changeset

* Remove unnecessary map step

* Review changes
This commit is contained in:
Nicolas Gorga
2025-12-09 21:49:16 -03:00
committed by GitHub
parent 4dbf46f2cb
commit fdc2b722d9
4 changed files with 337 additions and 5 deletions

View File

@@ -1,5 +1,6 @@
import {
ICartModuleService,
UpdateAddressDTO,
UpdateCartDTO,
UpdateCartWorkflowInputDTO,
} from "@medusajs/framework/types"
@@ -46,17 +47,53 @@ export const updateCartsStep = createStep(
{ select: selects, relations }
)
// Since service factory udpate method will correctly keep the reference to the addresses,
// but won't update its fields, we do this separately
const addressesInput = data
.flatMap((cart) => [cart.shipping_address, cart.billing_address])
.filter((address) => !!address)
let addressesToUpdateIds: string[] = []
const addressesToUpdate = addressesInput.filter(
(address): address is UpdateAddressDTO => {
if ("id" in address && !!address.id) {
addressesToUpdateIds.push(address.id as string)
return true
}
return false
}
)
const addressesBeforeUpdate = await cartModule.listAddresses({
id: addressesToUpdate.map((address) => address.id),
})
if (addressesToUpdate.length) {
await cartModule.updateAddresses(addressesToUpdate)
}
const updatedCart = await cartModule.updateCarts(data)
return new StepResponse(updatedCart, cartsBeforeUpdate)
return new StepResponse(updatedCart, {
cartsBeforeUpdate,
addressesBeforeUpdate,
})
},
async (cartsBeforeUpdate, { container }) => {
if (!cartsBeforeUpdate) {
async (dataToCompensate, { container }) => {
if (!dataToCompensate) {
return
}
const { cartsBeforeUpdate, addressesBeforeUpdate } = dataToCompensate
const cartModule = container.resolve<ICartModuleService>(Modules.CART)
const addressesToUpdate: UpdateAddressDTO[] = []
for (const address of addressesBeforeUpdate) {
addressesToUpdate.push({
...address,
metadata: address.metadata ?? undefined
})
}
await cartModule.updateAddresses(addressesToUpdate)
const dataToUpdate: UpdateCartDTO[] = []
for (const cart of cartsBeforeUpdate) {