feat(medusa): Respond with order when cart is already completed (#5766)
This commit is contained in:
1 parent
c808317044
commit
428331a653
6 files changed
+106
-61
No files matched your search
@@ -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`] = `
|
exports[`/store/carts shipping address + region updates updates region only - single to multiple countries 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"address_1": null,
|
"address_1": null,
|
||||||
|
|||||||
@@ -2234,24 +2234,27 @@ describe("/store/carts", () => {
|
|||||||
expect(createdOrder.status).toEqual(200)
|
expect(createdOrder.status).toEqual(200)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("returns early, if cart is already completed", async () => {
|
it("should return early, if cart is already completed", async () => {
|
||||||
const manager = dbConnection.manager
|
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
await manager.query(
|
|
||||||
`UPDATE "cart"
|
const completedCart = await api.post(
|
||||||
SET completed_at=current_timestamp
|
`/store/carts/test-cart-2/complete-cart`
|
||||||
WHERE id = 'test-cart-2'`
|
|
||||||
)
|
)
|
||||||
try {
|
|
||||||
await api.post(`/store/carts/test-cart-2/complete-cart`)
|
expect(completedCart.status).toEqual(200)
|
||||||
} catch (error) {
|
|
||||||
expect(error.response.data).toMatchSnapshot({
|
const alreadyCompletedCart = await api.post(
|
||||||
type: "not_allowed",
|
`/store/carts/test-cart-2/complete-cart`
|
||||||
message: "Cart has already been completed",
|
)
|
||||||
code: "cart_incompatible_state",
|
|
||||||
|
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 () => {
|
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)
|
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 () => {
|
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 api = useApi()
|
||||||
const customerEmail = "test-email-for-non-existent-customer@test.com"
|
const customerEmail = "test-email-for-non-existent-customer@test.com"
|
||||||
|
|||||||
@@ -456,7 +456,7 @@ describe("/store/carts", () => {
|
|||||||
await db.teardown()
|
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 api = useApi()
|
||||||
const manager = dbConnection.manager
|
const manager = dbConnection.manager
|
||||||
|
|
||||||
@@ -501,17 +501,16 @@ describe("/store/carts", () => {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
const responseFail = await api
|
const successRes = await api.post(`/store/carts/${cartId}/complete`)
|
||||||
.post(`/store/carts/${cartId}/complete`)
|
|
||||||
.catch((err) => {
|
|
||||||
return err.response
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(responseFail.status).toEqual(409)
|
expect(successRes.status).toEqual(200)
|
||||||
expect(responseFail.data.code).toEqual("cart_incompatible_state")
|
expect(successRes.data.data).toEqual(
|
||||||
expect(responseFail.data.message).toEqual(
|
expect.objectContaining({
|
||||||
"Cart has already been completed"
|
cart_id: cartId,
|
||||||
|
id: expect.any(String),
|
||||||
|
})
|
||||||
)
|
)
|
||||||
|
expect(successRes.data.type).toEqual("order")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ const toTest = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"returns 409",
|
"succeeds",
|
||||||
{
|
{
|
||||||
cart: {
|
cart: {
|
||||||
id: "test-cart",
|
id: "test-cart",
|
||||||
@@ -104,12 +104,15 @@ const toTest = [
|
|||||||
idempotency_key: "ikey",
|
idempotency_key: "ikey",
|
||||||
recovery_point: "started",
|
recovery_point: "started",
|
||||||
},
|
},
|
||||||
validate: function (value) {
|
validate: function (value, { orderServiceMock }) {
|
||||||
expect(value.response_code).toEqual(409)
|
expect(value.response_code).toEqual(200)
|
||||||
expect(value.response_body).toEqual({
|
expect(
|
||||||
code: "cart_incompatible_state",
|
orderServiceMock.retrieveByCartIdWithTotals
|
||||||
message: "Cart has already been completed",
|
).toHaveBeenCalledTimes(1)
|
||||||
type: "not_allowed",
|
expect(
|
||||||
|
orderServiceMock.retrieveByCartIdWithTotals
|
||||||
|
).toHaveBeenCalledWith("test-cart", {
|
||||||
|
relations: ["shipping_address", "items", "payments"],
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -204,6 +207,7 @@ describe("CartCompletionStrategy", () => {
|
|||||||
createFromCart: jest.fn(() => Promise.resolve(cart)),
|
createFromCart: jest.fn(() => Promise.resolve(cart)),
|
||||||
retrieve: jest.fn(() => Promise.resolve({})),
|
retrieve: jest.fn(() => Promise.resolve({})),
|
||||||
retrieveWithTotals: jest.fn(() => Promise.resolve({})),
|
retrieveWithTotals: jest.fn(() => Promise.resolve({})),
|
||||||
|
retrieveByCartIdWithTotals: jest.fn(() => Promise.resolve({})),
|
||||||
newTotalsService: newTotalsServiceMock,
|
newTotalsService: newTotalsServiceMock,
|
||||||
}
|
}
|
||||||
const swapServiceMock = {
|
const swapServiceMock = {
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
import {
|
|
||||||
AbstractCartCompletionStrategy,
|
|
||||||
CartCompletionResponse,
|
|
||||||
} from "../interfaces"
|
|
||||||
import {
|
import {
|
||||||
IEventBusService,
|
IEventBusService,
|
||||||
IInventoryService,
|
IInventoryService,
|
||||||
ReservationItemDTO,
|
ReservationItemDTO,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
AbstractCartCompletionStrategy,
|
||||||
|
CartCompletionResponse,
|
||||||
|
} from "../interfaces"
|
||||||
import { IdempotencyKey, Order } from "../models"
|
import { IdempotencyKey, Order } from "../models"
|
||||||
import OrderService, {
|
|
||||||
ORDER_CART_ALREADY_EXISTS_ERROR,
|
|
||||||
} from "../services/order"
|
|
||||||
import {
|
import {
|
||||||
PaymentProviderService,
|
PaymentProviderService,
|
||||||
ProductVariantInventoryService,
|
ProductVariantInventoryService,
|
||||||
} from "../services"
|
} 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 { 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 = {
|
type InjectedDependencies = {
|
||||||
productVariantInventoryService: ProductVariantInventoryService
|
productVariantInventoryService: ProductVariantInventoryService
|
||||||
@@ -201,13 +201,29 @@ class CartCompletionStrategy extends AbstractCartCompletionStrategy {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (cart.completed_at) {
|
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 {
|
return {
|
||||||
response_code: 409,
|
response_code: 200,
|
||||||
response_body: {
|
response_body: { data: order, type: "order" },
|
||||||
code: MedusaError.Codes.CART_INCOMPATIBLE_STATE,
|
|
||||||
message: "Cart has already been completed",
|
|
||||||
type: MedusaError.Types.NOT_ALLOWED,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,8 +465,8 @@ class CartCompletionStrategy extends AbstractCartCompletionStrategy {
|
|||||||
await this.removeReservations(reservations)
|
await this.removeReservations(reservations)
|
||||||
|
|
||||||
if (error && error.message === ORDER_CART_ALREADY_EXISTS_ERROR) {
|
if (error && error.message === ORDER_CART_ALREADY_EXISTS_ERROR) {
|
||||||
order = await orderServiceTx.retrieveByCartId(id, {
|
order = await orderServiceTx.retrieveByCartIdWithTotals(id, {
|
||||||
relations: ["shipping_address", "payments"],
|
relations: ["shipping_address", "items", "payments"],
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in new issue
Block a user