Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: CartRegion link, definition + workflow #6392

Merged
merged 15 commits into from
Feb 16, 2024
166 changes: 166 additions & 0 deletions integration-tests/plugins/__tests__/cart/store/create-cart.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICartModuleService, IRegionModuleService } 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
let regionModuleService: IRegionModuleService

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)
regionModuleService = appContainer.resolve(ModuleRegistrationName.REGION)
})

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

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

// @ts-ignore
await regionModuleService.createDefaultCountriesAndCurrencies()
})

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

it("should create a cart", async () => {
const region = await regionModuleService.create({
name: "US",
currency_code: "usd",
})

const api = useApi() as any
const response = await api.post(`/store/carts`, {
email: "[email protected]",
currency_code: "usd",
region_id: region.id,
})

expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: response.data.cart.id,
currency_code: "usd",
email: "[email protected]",
region: expect.objectContaining({
id: region.id,
currency_code: "usd",
}),
})
)
})

it("should use any region", async () => {
olivermrbl marked this conversation as resolved.
Show resolved Hide resolved
await regionModuleService.create({
name: "US",
currency_code: "usd",
})

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]",
region: expect.objectContaining({
id: expect.any(String),
}),
})
)
})

it("should use region currency code", async () => {
await regionModuleService.create({
name: "US",
currency_code: "usd",
})

const api = useApi() as any
const response = await api.post(`/store/carts`, {
email: "[email protected]",
})

expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: response.data.cart.id,
currency_code: "usd",
email: "[email protected]",
region: expect.objectContaining({
id: expect.any(String),
}),
})
)
})

it("should throw when no regions exist", async () => {
const api = useApi() as any

await expect(
api.post(`/store/carts`, {
email: "[email protected]",
currency_code: "usd",
})
).rejects.toThrow()
})

it("should create a cart", async () => {
const region = await regionModuleService.create({
name: "US",
currency_code: "usd",
})

await regionModuleService.create({
name: "Europe",
currency_code: "eur",
})

const api = useApi() as any
const response = await api.post(`/store/carts`, {
email: "[email protected]",
currency_code: "usd",
region_id: region.id,
})

expect(response.status).toEqual(200)
expect(response.data.cart).toEqual(
expect.objectContaining({
id: response.data.cart.id,
currency_code: "usd",
email: "[email protected]",
region: expect.objectContaining({
id: region.id,
currency_code: "usd",
}),
})
)
})
})
59 changes: 0 additions & 59 deletions integration-tests/plugins/__tests__/cart/store/create-cart.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IRegionModuleService } from "@medusajs/types"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"

export const findOneOrAnyRegionStepId = "find-one-or-any-region"
export const findOneOrAnyRegionStep = createStep(
findOneOrAnyRegionStepId,
async (data: { regionId?: string }, { container }) => {
const service = container.resolve<IRegionModuleService>(
ModuleRegistrationName.REGION
)

if (!data.regionId) {
const regions = await service.list({})
olivermrbl marked this conversation as resolved.
Show resolved Hide resolved

if (!regions?.length) {
throw Error("No regions found")
}

return new StepResponse(regions[0])
}

const region = await service.retrieve(data.regionId)

return new StepResponse(region)
}
)
1 change: 1 addition & 0 deletions packages/core-flows/src/definition/cart/steps/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./create-carts"
export * from "./find-one-or-any-region"
export * from "./update-carts"

Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
import { CartDTO, CreateCartDTO } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { createCartsStep } from "../steps"
import { CartDTO, CreateCartWorkflowInputDTO } from "@medusajs/types"
import {
WorkflowData,
createWorkflow,
transform,
} from "@medusajs/workflows-sdk"
import { createCartsStep, findOneOrAnyRegionStep } from "../steps"

type WorkflowInput = { cartData: CreateCartDTO[] }
type WorkflowInput = CreateCartWorkflowInputDTO

export const createCartsWorkflowId = "create-carts"
export const createCartsWorkflow = createWorkflow(
createCartsWorkflowId,
export const createCartWorkflowId = "create-cart"
export const createCartWorkflow = createWorkflow(
createCartWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<CartDTO[]> => {
return createCartsStep(input.cartData)
const region = findOneOrAnyRegionStep({
regionId: input.region_id,
})

const cartInput = transform({ input, region }, (data) => {
return {
...data.input,
currency_code: data?.input.currency_code || data.region.currency_code,
region_id: data.region.id,
}
})

const cart = createCartsStep([cartInput])

return cart
}
)
28 changes: 28 additions & 0 deletions packages/link-modules/src/definitions/cart-region.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Modules } from "@medusajs/modules-sdk"
import { ModuleJoinerConfig } from "@medusajs/types"

export const CartRegion: ModuleJoinerConfig = {
olivermrbl marked this conversation as resolved.
Show resolved Hide resolved
isLink: true,
isReadOnlyLink: true,
extends: [
{
serviceName: Modules.CART,
relationship: {
serviceName: Modules.REGION,
primaryKey: "id",
foreignKey: "region_id",
alias: "region",
},
},
{
serviceName: Modules.REGION,
relationship: {
serviceName: Modules.CART,
primaryKey: "id",
foreignKey: "cart_id",
alias: "carts",
isList: true,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
serviceName: Modules.REGION,
relationship: {
serviceName: Modules.CART,
primaryKey: "id",
foreignKey: "cart_id",
alias: "carts",
isList: true,
},
serviceName: Modules.REGION,
relationship: {
serviceName: Modules.CART,
primaryKey: "region_id",
foreignKey: "id",
alias: "carts",
isList: true,
},

Copy link
Contributor

@carlos-r-l-rodrigues carlos-r-l-rodrigues Feb 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can cover these configs on the tests, querying these new properties.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like this: 2225f15

},
],
}
10 changes: 6 additions & 4 deletions packages/link-modules/src/definitions/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
export * from "./cart-region"
export * from "./cart-sales-channel"
export * from "./inventory-level-stock-location"
export * from "./order-sales-channel"
export * from "./product-sales-channel"
export * from "./product-shipping-profile"
export * from "./product-variant-inventory-item"
export * from "./product-variant-price-set"
export * from "./product-shipping-profile"
export * from "./product-sales-channel"
export * from "./cart-sales-channel"
export * from "./order-sales-channel"
export * from "./publishable-api-key-sales-channel"

3 changes: 1 addition & 2 deletions packages/medusa/src/api-v2/store/carts/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => {

const query = {
cart: {
__args: variables,
...defaultStoreCartRemoteQueryObject,
},
}

const [cart] = await remoteQuery(query)
const [cart] = await remoteQuery(query, { cart: variables })

res.json({ cart })
}
Expand Down
4 changes: 4 additions & 0 deletions packages/medusa/src/api-v2/store/carts/query-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const defaultStoreCartFields = [

export const defaultStoreCartRelations = [
"items",
"region",
"shipping_address",
"billing_address",
"shipping_methods",
Expand Down Expand Up @@ -61,4 +62,7 @@ export const defaultStoreCartRemoteQueryObject = {
"phone",
],
},
region: {
fields: ["id", "name", "currency_code"],
},
}
Loading
Loading