Skip to content

Commit

Permalink
Merge branch 'develop' into feat/api-v2-invite-endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Feb 14, 2024
2 parents be8384f + 1ed5f91 commit cd24411
Show file tree
Hide file tree
Showing 17 changed files with 377 additions and 48 deletions.
5 changes: 5 additions & 0 deletions .changeset/rude-shirts-act.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@medusajs/types": patch
---

feat(cart): `POST /store/carts/:id`
63 changes: 63 additions & 0 deletions integration-tests/plugins/__tests__/cart/store/update-cart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
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/:id", () => {
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 cart = await cartModuleService.create({
currency_code: "usd",
})

const response = await api.post(`/store/carts/${cart.id}`, {
email: "tony@stark.com",
})

expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: cart.id,
currency_code: "usd",
email: "tony@stark.com",
})
)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,56 @@ describe("Cart Module Service", () => {
})
)
})

it("should update a cart with selector successfully", async () => {
const [createdCart] = await service.create([
{
currency_code: "eur",
},
])

const [updatedCart] = await service.update(
{ id: createdCart.id },
{
email: "test@email.com",
}
)

const [cart] = await service.list({ id: [createdCart.id] })

expect(cart).toEqual(
expect.objectContaining({
id: createdCart.id,
currency_code: "eur",
email: updatedCart.email,
})
)
})

it("should update a cart with id successfully", async () => {
const [createdCart] = await service.create([
{
currency_code: "eur",
},
])

const updatedCart = await service.update(
createdCart.id,
{
email: "test@email.com",
}
)

const [cart] = await service.list({ id: [createdCart.id] })

expect(cart).toEqual(
expect.objectContaining({
id: createdCart.id,
currency_code: "eur",
email: updatedCart.email,
})
)
})
})

describe("delete", () => {
Expand Down
71 changes: 51 additions & 20 deletions packages/cart/src/services/cart-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,43 +190,74 @@ export default class CartModuleService<
return createdCarts
}

async update(data: CartTypes.UpdateCartDTO[]): Promise<CartTypes.CartDTO[]>
async update(
data: CartTypes.UpdateCartDTO[],
cartId: string,
data: CartTypes.UpdateCartDataDTO,
sharedContext?: Context
): Promise<CartTypes.CartDTO[]>

): Promise<CartTypes.CartDTO>
async update(
data: CartTypes.UpdateCartDTO,
selector: Partial<CartTypes.CartDTO>,
data: CartTypes.UpdateCartDataDTO,
sharedContext?: Context
): Promise<CartTypes.CartDTO>
): Promise<CartTypes.CartDTO[]>

@InjectManager("baseRepository_")
async update(
data: CartTypes.UpdateCartDTO[] | CartTypes.UpdateCartDTO,
dataOrIdOrSelector:
| CartTypes.UpdateCartDTO[]
| string
| Partial<CartTypes.CartDTO>,
data?: CartTypes.UpdateCartDataDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<CartTypes.CartDTO[] | CartTypes.CartDTO> {
const input = Array.isArray(data) ? data : [data]
const carts = await this.update_(input, sharedContext)
const result = await this.update_(dataOrIdOrSelector, data, sharedContext)

const result = await this.list(
{ id: carts.map((p) => p!.id) },
{
relations: ["shipping_address", "billing_address"],
},
sharedContext
)
const serializedResult = await this.baseRepository_.serialize<
CartTypes.CartDTO[]
>(result, {
populate: true,
})

return (Array.isArray(data) ? result : result[0]) as
| CartTypes.CartDTO
| CartTypes.CartDTO[]
return isString(dataOrIdOrSelector) ? serializedResult[0] : serializedResult
}

@InjectTransactionManager("baseRepository_")
protected async update_(
data: CartTypes.UpdateCartDTO[],
dataOrIdOrSelector:
| CartTypes.UpdateCartDTO[]
| string
| Partial<CartTypes.CartDTO>,
data?: CartTypes.UpdateCartDataDTO,
@MedusaContext() sharedContext: Context = {}
) {
return await this.cartService_.update(data, sharedContext)
let toUpdate: CartTypes.UpdateCartDTO[] = []
if (isString(dataOrIdOrSelector)) {
toUpdate = [
{
id: dataOrIdOrSelector,
...data,
},
]
} else if (Array.isArray(dataOrIdOrSelector)) {
toUpdate = dataOrIdOrSelector
} else {
const carts = await this.cartService_.list(
{ ...dataOrIdOrSelector },
{ select: ["id"] },
sharedContext
)

toUpdate = carts.map((cart) => {
return {
...data,
id: cart.id,
}
})
}

const result = await this.cartService_.update(toUpdate, sharedContext)
return result
}

addLineItems(
Expand Down
12 changes: 6 additions & 6 deletions packages/cart/src/types/cart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ export interface CreateCartDTO {

export interface UpdateCartDTO {
id: string
region_id?: string
customer_id?: string
sales_channel_id?: string
email?: string
currency_code?: string
metadata?: Record<string, unknown>
region_id?: string | null
customer_id?: string | null
sales_channel_id?: string | null
email?: string | null
currency_code?: string | null
metadata?: Record<string, unknown> | null

adjustments?: (CreateLineItemAdjustmentDTO | UpdateLineItemAdjustmentDTO)[]
}
3 changes: 2 additions & 1 deletion packages/core-flows/src/definition/cart/steps/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./create-carts";
export * from "./create-carts"
export * from "./update-carts"

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

type UpdateCartsStepInput = {
selector: FilterableCartProps
update: UpdateCartDataDTO
}

export const updateCartsStepId = "update-carts"
export const updateCartsStep = createStep(
updateCartsStepId,
async (data: UpdateCartsStepInput, { container }) => {
const service = container.resolve<ICartModuleService>(
ModuleRegistrationName.CART
)

const { selects, relations } = getSelectsAndRelationsFromObjectArray([
data.update,
])

const prevCarts = await service.list(data.selector, {
select: selects,
relations,
})

const updatedCarts = await service.update(
data.selector as Partial<CartDTO>,
data.update
)

return new StepResponse(updatedCarts, prevCarts)
},
async (previousCarts, { container }) => {
if (!previousCarts?.length) {
return
}

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

const toRestore = previousCarts.map((c) => ({
id: c.id,
region_id: c.region_id,
customer_id: c.customer_id,
sales_channel_id: c.sales_channel_id,
email: c.email,
currency_code: c.currency_code,
metadata: c.metadata,
}))

await service.update(toRestore)
}
)
3 changes: 2 additions & 1 deletion packages/core-flows/src/definition/cart/workflows/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./create-carts";
export * from "./create-carts"
export * from "./update-carts"

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

type WorkflowInput = {
selector: FilterableCartProps
update: UpdateCartDataDTO
}

export const updateCartsWorkflowId = "update-carts"
export const updateCartsWorkflow = createWorkflow(
updateCartsWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<CartDTO[]> => {
return updateCartsStep(input)
}
)
1 change: 1 addition & 0 deletions packages/medusa/src/api-v2/middlewares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const config: MiddlewaresConfig = {
...adminCustomerRoutesMiddlewares,
...adminPromotionRoutesMiddlewares,
...adminCampaignRoutesMiddlewares,
...storeCartRoutesMiddlewares,
...storeCustomerRoutesMiddlewares,
...storeCartRoutesMiddlewares,
...authRoutesMiddlewares,
Expand Down
23 changes: 23 additions & 0 deletions packages/medusa/src/api-v2/store/carts/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { updateCartsWorkflow } from "@medusajs/core-flows"
import { UpdateCartDataDTO } from "@medusajs/types"
import { MedusaRequest, MedusaResponse } from "../../../../types/routing"

import { defaultStoreCartRemoteQueryObject } from "../query-config"

export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
Expand All @@ -17,3 +20,23 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => {

res.json({ cart })
}

export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
const updateCartWorkflow = updateCartsWorkflow(req.scope)

const workflowInput = {
selector: { id: req.params.id },
update: req.validatedBody as UpdateCartDataDTO,
}

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

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

res.status(200).json({ cart: result[0] })
}
11 changes: 10 additions & 1 deletion packages/medusa/src/api-v2/store/carts/middlewares.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { transformBody, transformQuery } from "../../../api/middlewares"
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
import * as QueryConfig from "./query-config"
import { StoreGetCartsCartParams, StorePostCartReq } from "./validators"
import {
StoreGetCartsCartParams,
StorePostCartReq,
StorePostCartsCartReq,
} from "./validators"

export const storeCartRoutesMiddlewares: MiddlewareRoute[] = [
{
Expand All @@ -19,4 +23,9 @@ export const storeCartRoutesMiddlewares: MiddlewareRoute[] = [
matcher: "/store/carts",
middlewares: [transformBody(StorePostCartReq)],
},
{
method: ["POST"],
matcher: "/store/carts/:id",
middlewares: [transformBody(StorePostCartsCartReq)],
},
]
Loading

0 comments on commit cd24411

Please sign in to comment.