Skip to content

Commit

Permalink
feat(cart): POST /store/carts (#6273)
Browse files Browse the repository at this point in the history
Depends on #6262
  • Loading branch information
olivermrbl authored Feb 5, 2024
1 parent 884428a commit ede221d
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 3 deletions.
59 changes: 59 additions & 0 deletions integration-tests/plugins/__tests__/cart/store/create-cart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICartModuleService } from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import adminSeeder from "../../../../helpers/admin-seeder"

jest.setTimeout(50000)

const env = { MEDUSA_FF_MEDUSA_V2: true }

describe("POST /store/carts", () => {
let dbConnection
let appContainer
let shutdownServer
let cartModuleService: ICartModuleService

beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
cartModuleService = appContainer.resolve(ModuleRegistrationName.CART)
})

afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})

beforeEach(async () => {
await adminSeeder(dbConnection)
})

afterEach(async () => {
const db = useDb()
await db.teardown()
})

it("should create a cart", async () => {
const api = useApi() as any
const response = await api.post(`/store/carts`, {
email: "[email protected]",
currency_code: "usd",
})

expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: response.data.cart.id,
currency_code: "usd",
email: "[email protected]",
})
)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import adminSeeder from "../../../../helpers/admin-seeder"

jest.setTimeout(50000)

const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import adminSeeder from "../../../../helpers/admin-seeder"

jest.setTimeout(50000)

const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import adminSeeder from "../../../../helpers/admin-seeder"

jest.setTimeout(50000)

const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { initModules } from "medusa-test-utils"
import { MikroOrmWrapper } from "../../../utils"
import { getInitModuleConfig } from "../../../utils/get-init-module-config"

jest.setTimeout(30000)
jest.setTimeout(50000)

describe("Cart Module Service", () => {
let service: ICartModuleService
Expand Down
3 changes: 3 additions & 0 deletions packages/core-flows/src/definition/cart/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export * from "./create-cart"
export * from "./steps"
export * from "./workflows"

31 changes: 31 additions & 0 deletions packages/core-flows/src/definition/cart/steps/create-carts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { CreateCartDTO, ICartModuleService } from "@medusajs/types"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"

export const createCartsStepId = "create-carts"
export const createCartsStep = createStep(
createCartsStepId,
async (data: CreateCartDTO[], { container }) => {
const service = container.resolve<ICartModuleService>(
ModuleRegistrationName.CART
)

const createdCarts = await service.create(data)

return new StepResponse(
createdCarts,
createdCarts.map((cart) => cart.id)
)
},
async (createdCartsIds, { container }) => {
if (!createdCartsIds?.length) {
return
}

const service = container.resolve<ICartModuleService>(
ModuleRegistrationName.CART
)

await service.delete(createdCartsIds)
}
)
2 changes: 2 additions & 0 deletions packages/core-flows/src/definition/cart/steps/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./create-carts";

13 changes: 13 additions & 0 deletions packages/core-flows/src/definition/cart/workflows/create-carts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { CartDTO, CreateCartDTO } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { createCartsStep } from "../steps"

type WorkflowInput = { cartData: CreateCartDTO[] }

export const createCartsWorkflowId = "create-carts"
export const createCartsWorkflow = createWorkflow(
createCartsWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<CartDTO[]> => {
return createCartsStep(input.cartData)
}
)
2 changes: 2 additions & 0 deletions packages/core-flows/src/definition/cart/workflows/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./create-carts";

9 changes: 7 additions & 2 deletions packages/medusa/src/api-v2/store/carts/middlewares.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { transformQuery } from "../../../api/middlewares"
import { transformBody, transformQuery } from "../../../api/middlewares"
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
import * as QueryConfig from "./query-config"
import { StoreGetCartsCartParams } from "./validators"
import { StoreGetCartsCartParams, StorePostCartReq } from "./validators"

export const storeCartRoutesMiddlewares: MiddlewareRoute[] = [
{
Expand All @@ -14,4 +14,9 @@ export const storeCartRoutesMiddlewares: MiddlewareRoute[] = [
),
],
},
{
method: ["POST"],
matcher: "/store/carts",
middlewares: [transformBody(StorePostCartReq)],
},
]
23 changes: 23 additions & 0 deletions packages/medusa/src/api-v2/store/carts/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createCartsWorkflow } from "@medusajs/core-flows"
import { CreateCartDTO } from "@medusajs/types"
import { MedusaRequest, MedusaResponse } from "../../../types/routing"

export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
const createCartWorkflow = createCartsWorkflow(req.scope)
const cartData = [
{
...(req.validatedBody as CreateCartDTO),
},
]

const { result, errors } = await createCartWorkflow.run({
input: { cartData },
throwOnError: false,
})

if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}

res.status(200).json({ cart: result[0] })
}
52 changes: 52 additions & 0 deletions packages/medusa/src/api-v2/store/carts/validators.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,55 @@
import { Type } from "class-transformer"
import {
IsArray,
IsInt,
IsNotEmpty,
IsObject,
IsOptional,
IsString,
ValidateNested,
} from "class-validator"
import { FindParams } from "../../../types/common"

export class StoreGetCartsCartParams extends FindParams {}

export class Item {
@IsNotEmpty()
@IsString()
variant_id: string

@IsNotEmpty()
@IsInt()
quantity: number
}

export class StorePostCartReq {
@IsOptional()
@IsString()
region_id?: string

@IsOptional()
@IsString()
customer_id?: string

@IsOptional()
@IsString()
email?: string

@IsOptional()
@IsString()
currency_code?: string

@IsOptional()
@IsArray()
@ValidateNested({ each: true })
@Type(() => Item)
items?: Item[]

@IsString()
@IsOptional()
sales_channel_id?: string

@IsObject()
@IsOptional()
metadata?: Record<string, unknown>
}

0 comments on commit ede221d

Please sign in to comment.