feat(medusa): Respond with order when cart is already completed (#5766)
This commit is contained in:
5
.changeset/heavy-moles-check.md
Normal file
5
.changeset/heavy-moles-check.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@medusajs/medusa": minor
|
||||
---
|
||||
|
||||
feat(medusa): Respond with order when cart is already completed
|
||||
@@ -24,14 +24,6 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`/store/carts POST /store/carts/:id returns early, if cart is already completed 1`] = `
|
||||
Object {
|
||||
"code": "cart_incompatible_state",
|
||||
"message": "Cart has already been completed",
|
||||
"type": "not_allowed",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`/store/carts shipping address + region updates updates region only - single to multiple countries 1`] = `
|
||||
Object {
|
||||
"address_1": null,
|
||||
|
||||
@@ -2234,24 +2234,27 @@ describe("/store/carts", () => {
|
||||
expect(createdOrder.status).toEqual(200)
|
||||
})
|
||||
|
||||
it("returns early, if cart is already completed", async () => {
|
||||
const manager = dbConnection.manager
|
||||
it("should return early, if cart is already completed", async () => {
|
||||
const api = useApi()
|
||||
await manager.query(
|
||||
`UPDATE "cart"
|
||||
SET completed_at=current_timestamp
|
||||
WHERE id = 'test-cart-2'`
|
||||
|
||||
const completedCart = await api.post(
|
||||
`/store/carts/test-cart-2/complete-cart`
|
||||
)
|
||||
try {
|
||||
await api.post(`/store/carts/test-cart-2/complete-cart`)
|
||||
} catch (error) {
|
||||
expect(error.response.data).toMatchSnapshot({
|
||||
type: "not_allowed",
|
||||
message: "Cart has already been completed",
|
||||
code: "cart_incompatible_state",
|
||||
|
||||
expect(completedCart.status).toEqual(200)
|
||||
|
||||
const alreadyCompletedCart = await api.post(
|
||||
`/store/carts/test-cart-2/complete-cart`
|
||||
)
|
||||
|
||||
expect(alreadyCompletedCart.data.data).toEqual(
|
||||
expect.objectContaining({
|
||||
cart_id: "test-cart-2",
|
||||
id: expect.any(String),
|
||||
})
|
||||
expect(error.response.status).toEqual(409)
|
||||
}
|
||||
)
|
||||
expect(alreadyCompletedCart.data.type).toEqual("order")
|
||||
expect(alreadyCompletedCart.status).toEqual(200)
|
||||
})
|
||||
|
||||
it("fails to complete cart with items inventory not/partially covered", async () => {
|
||||
@@ -2354,6 +2357,32 @@ describe("/store/carts", () => {
|
||||
expect(res.data.cart.completed_at).not.toBe(null)
|
||||
})
|
||||
|
||||
it("should return the swap when cart is already completed", async () => {
|
||||
const manager = dbConnection.manager
|
||||
await manager.query(
|
||||
"UPDATE swap SET cart_id='swap-cart' where id='test-swap'"
|
||||
)
|
||||
|
||||
await manager.query("DELETE FROM payment where swap_id='test-swap'")
|
||||
|
||||
const api = useApi()
|
||||
|
||||
await api.post(`/store/carts/swap-cart/complete-cart`)
|
||||
|
||||
const alreadyCompletedCart = await api.post(
|
||||
`/store/carts/swap-cart/complete-cart`
|
||||
)
|
||||
|
||||
expect(alreadyCompletedCart.data.data).toEqual(
|
||||
expect.objectContaining({
|
||||
cart_id: "swap-cart",
|
||||
id: expect.any(String),
|
||||
})
|
||||
)
|
||||
expect(alreadyCompletedCart.data.type).toEqual("swap")
|
||||
expect(alreadyCompletedCart.status).toEqual(200)
|
||||
})
|
||||
|
||||
it("completes cart with a non-customer and for a customer with the same email created later the order doesn't show up", async () => {
|
||||
const api = useApi()
|
||||
const customerEmail = "test-email-for-non-existent-customer@test.com"
|
||||
|
||||
@@ -456,7 +456,7 @@ describe("/store/carts", () => {
|
||||
await db.teardown()
|
||||
})
|
||||
|
||||
it("should fails on cart already completed", async () => {
|
||||
it("should return an order on cart already completed", async () => {
|
||||
const api = useApi()
|
||||
const manager = dbConnection.manager
|
||||
|
||||
@@ -501,17 +501,16 @@ describe("/store/carts", () => {
|
||||
})
|
||||
)
|
||||
|
||||
const responseFail = await api
|
||||
.post(`/store/carts/${cartId}/complete`)
|
||||
.catch((err) => {
|
||||
return err.response
|
||||
})
|
||||
const successRes = await api.post(`/store/carts/${cartId}/complete`)
|
||||
|
||||
expect(responseFail.status).toEqual(409)
|
||||
expect(responseFail.data.code).toEqual("cart_incompatible_state")
|
||||
expect(responseFail.data.message).toEqual(
|
||||
"Cart has already been completed"
|
||||
expect(successRes.status).toEqual(200)
|
||||
expect(successRes.data.data).toEqual(
|
||||
expect.objectContaining({
|
||||
cart_id: cartId,
|
||||
id: expect.any(String),
|
||||
})
|
||||
)
|
||||
expect(successRes.data.type).toEqual("order")
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ const toTest = [
|
||||
},
|
||||
],
|
||||
[
|
||||
"returns 409",
|
||||
"succeeds",
|
||||
{
|
||||
cart: {
|
||||
id: "test-cart",
|
||||
@@ -104,12 +104,15 @@ const toTest = [
|
||||
idempotency_key: "ikey",
|
||||
recovery_point: "started",
|
||||
},
|
||||
validate: function (value) {
|
||||
expect(value.response_code).toEqual(409)
|
||||
expect(value.response_body).toEqual({
|
||||
code: "cart_incompatible_state",
|
||||
message: "Cart has already been completed",
|
||||
type: "not_allowed",
|
||||
validate: function (value, { orderServiceMock }) {
|
||||
expect(value.response_code).toEqual(200)
|
||||
expect(
|
||||
orderServiceMock.retrieveByCartIdWithTotals
|
||||
).toHaveBeenCalledTimes(1)
|
||||
expect(
|
||||
orderServiceMock.retrieveByCartIdWithTotals
|
||||
).toHaveBeenCalledWith("test-cart", {
|
||||
relations: ["shipping_address", "items", "payments"],
|
||||
})
|
||||
},
|
||||
},
|
||||
@@ -204,6 +207,7 @@ describe("CartCompletionStrategy", () => {
|
||||
createFromCart: jest.fn(() => Promise.resolve(cart)),
|
||||
retrieve: jest.fn(() => Promise.resolve({})),
|
||||
retrieveWithTotals: jest.fn(() => Promise.resolve({})),
|
||||
retrieveByCartIdWithTotals: jest.fn(() => Promise.resolve({})),
|
||||
newTotalsService: newTotalsServiceMock,
|
||||
}
|
||||
const swapServiceMock = {
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import {
|
||||
AbstractCartCompletionStrategy,
|
||||
CartCompletionResponse,
|
||||
} from "../interfaces"
|
||||
import {
|
||||
IEventBusService,
|
||||
IInventoryService,
|
||||
ReservationItemDTO,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
AbstractCartCompletionStrategy,
|
||||
CartCompletionResponse,
|
||||
} from "../interfaces"
|
||||
import { IdempotencyKey, Order } from "../models"
|
||||
import OrderService, {
|
||||
ORDER_CART_ALREADY_EXISTS_ERROR,
|
||||
} from "../services/order"
|
||||
import {
|
||||
PaymentProviderService,
|
||||
ProductVariantInventoryService,
|
||||
} from "../services"
|
||||
import OrderService, {
|
||||
ORDER_CART_ALREADY_EXISTS_ERROR,
|
||||
} from "../services/order"
|
||||
|
||||
import CartService from "../services/cart"
|
||||
import { EntityManager } from "typeorm"
|
||||
import IdempotencyKeyService from "../services/idempotency-key"
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
import { RequestContext } from "../types/request"
|
||||
import SwapService from "../services/swap"
|
||||
import { promiseAll } from "@medusajs/utils"
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
import { EntityManager } from "typeorm"
|
||||
import CartService from "../services/cart"
|
||||
import IdempotencyKeyService from "../services/idempotency-key"
|
||||
import SwapService from "../services/swap"
|
||||
import { RequestContext } from "../types/request"
|
||||
|
||||
type InjectedDependencies = {
|
||||
productVariantInventoryService: ProductVariantInventoryService
|
||||
@@ -201,13 +201,29 @@ class CartCompletionStrategy extends AbstractCartCompletionStrategy {
|
||||
})
|
||||
|
||||
if (cart.completed_at) {
|
||||
if (cart.type === "swap") {
|
||||
const swapId = cart.metadata?.swap_id as string
|
||||
const swapServiceTx = this.swapService_.withTransaction(manager)
|
||||
|
||||
const swap = await swapServiceTx.retrieve(swapId, {
|
||||
relations: ["shipping_address"],
|
||||
})
|
||||
|
||||
return {
|
||||
response_code: 200,
|
||||
response_body: { data: swap, type: "swap" },
|
||||
}
|
||||
}
|
||||
|
||||
const order = await this.orderService_
|
||||
.withTransaction(manager)
|
||||
.retrieveByCartIdWithTotals(id, {
|
||||
relations: ["shipping_address", "items", "payments"],
|
||||
})
|
||||
|
||||
return {
|
||||
response_code: 409,
|
||||
response_body: {
|
||||
code: MedusaError.Codes.CART_INCOMPATIBLE_STATE,
|
||||
message: "Cart has already been completed",
|
||||
type: MedusaError.Types.NOT_ALLOWED,
|
||||
},
|
||||
response_code: 200,
|
||||
response_body: { data: order, type: "order" },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,8 +465,8 @@ class CartCompletionStrategy extends AbstractCartCompletionStrategy {
|
||||
await this.removeReservations(reservations)
|
||||
|
||||
if (error && error.message === ORDER_CART_ALREADY_EXISTS_ERROR) {
|
||||
order = await orderServiceTx.retrieveByCartId(id, {
|
||||
relations: ["shipping_address", "payments"],
|
||||
order = await orderServiceTx.retrieveByCartIdWithTotals(id, {
|
||||
relations: ["shipping_address", "items", "payments"],
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user