Skip to content

Commit

Permalink
feat(cart): Shipping methods (#6101)
Browse files Browse the repository at this point in the history
  • Loading branch information
olivermrbl committed Jan 18, 2024
1 parent 5cfb662 commit 7f7cb2a
Show file tree
Hide file tree
Showing 19 changed files with 431 additions and 31 deletions.
5 changes: 5 additions & 0 deletions .changeset/olive-ads-brake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@medusajs/types": patch
---

feat(cart): Shipping methods
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ICartModuleService } from "@medusajs/types"
import { CheckConstraintViolationException } from "@mikro-orm/core"
import { initialize } from "../../../../src/initialize"
import { DB_URL, MikroOrmWrapper } from "../../../utils"

Expand Down Expand Up @@ -466,12 +467,9 @@ describe("Cart Module Service", () => {

expect(item.title).toBe("test")

const updatedItem = await service.updateLineItems(
item.id,
{
title: "test2",
}
)
const updatedItem = await service.updateLineItems(item.id, {
title: "test2",
})

expect(updatedItem.title).toBe("test2")
})
Expand Down Expand Up @@ -519,13 +517,13 @@ describe("Cart Module Service", () => {
selector: { cart_id: createdCart.id },
data: {
title: "changed-test",
}
},
},
{
selector: { id: itemTwo!.id },
data: {
title: "changed-other-test",
}
},
},
])

Expand Down Expand Up @@ -603,4 +601,117 @@ describe("Cart Module Service", () => {
expect(cart.items?.length).toBe(0)
})
})

describe("addShippingMethods", () => {
it("should add a shipping method to cart succesfully", async () => {
const [createdCart] = await service.create([
{
currency_code: "eur",
},
])

const [method] = await service.addShippingMethods(createdCart.id, [
{
amount: 100,
name: "Test",
},
])

const cart = await service.retrieve(createdCart.id, {
relations: ["shipping_methods"],
})

expect(method.id).toBe(cart.shipping_methods![0].id)
})

it("should throw when amount is negative", async () => {
const [createdCart] = await service.create([
{
currency_code: "eur",
},
])

const error = await service
.addShippingMethods(createdCart.id, [
{
amount: -100,
name: "Test",
},
])
.catch((e) => e)

expect(error.name).toBe(CheckConstraintViolationException.name)
})

it("should add multiple shipping methods to multiple carts succesfully", async () => {
let [eurCart] = await service.create([
{
currency_code: "eur",
},
])

let [usdCart] = await service.create([
{
currency_code: "usd",
},
])

const methods = await service.addShippingMethods([
{
cart_id: eurCart.id,
amount: 100,
name: "Test One",
},
{
cart_id: usdCart.id,
amount: 100,
name: "Test One",
},
])

const carts = await service.list(
{ id: [eurCart.id, usdCart.id] },
{ relations: ["shipping_methods"] }
)

eurCart = carts.find((c) => c.currency_code === "eur")!
usdCart = carts.find((c) => c.currency_code === "usd")!

const eurMethods = methods.filter((m) => m.cart_id === eurCart.id)
const usdMethods = methods.filter((m) => m.cart_id === usdCart.id)

expect(eurCart.shipping_methods![0].id).toBe(eurMethods[0].id)
expect(usdCart.shipping_methods![0].id).toBe(usdMethods[0].id)

expect(eurCart.shipping_methods?.length).toBe(1)
expect(usdCart.shipping_methods?.length).toBe(1)
})
})

describe("removeShippingMethods", () => {
it("should remove a line item succesfully", async () => {
const [createdCart] = await service.create([
{
currency_code: "eur",
},
])

const [method] = await service.addShippingMethods(createdCart.id, [
{
amount: 100,
name: "test",
},
])

expect(method.id).not.toBe(null)

await service.removeShippingMethods(method.id)

const cart = await service.retrieve(createdCart.id, {
relations: ["shipping_methods"],
})

expect(cart.shipping_methods?.length).toBe(0)
})
})
})
14 changes: 12 additions & 2 deletions packages/cart/src/loaders/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export default async ({
container.register({
cartService: asClass(defaultServices.CartService).singleton(),
addressService: asClass(defaultServices.AddressService).singleton(),
shippingMethodService: asClass(
defaultServices.ShippingMethodService
).singleton(),
lineItemService: asClass(defaultServices.LineItemService).singleton(),
})

Expand All @@ -38,7 +41,14 @@ function loadDefaultRepositories({ container }) {
container.register({
baseRepository: asClass(defaultRepositories.BaseRepository).singleton(),
cartRepository: asClass(defaultRepositories.CartRepository).singleton(),
addressRepository: asClass(defaultRepositories.AddressRepository).singleton(),
lineItemRepository: asClass(defaultRepositories.LineItemRepository).singleton(),
addressRepository: asClass(
defaultRepositories.AddressRepository
).singleton(),
lineItemRepository: asClass(
defaultRepositories.LineItemRepository
).singleton(),
shippingMethodRepository: asClass(
defaultRepositories.ShippingMethodRepository
).singleton(),
})
}
6 changes: 3 additions & 3 deletions packages/cart/src/models/line-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,13 @@ export default class LineItem {
@Property({ columnType: "jsonb", nullable: true })
variant_option_values?: Record<string, unknown> | null

@Property({ columnType: "boolean", default: true })
@Property({ columnType: "boolean" })
requires_shipping = true

@Property({ columnType: "boolean", default: true })
@Property({ columnType: "boolean" })
is_discountable = true

@Property({ columnType: "boolean", default: false })
@Property({ columnType: "boolean" })
is_tax_inclusive = false

@Property({ columnType: "numeric", nullable: true })
Expand Down
9 changes: 6 additions & 3 deletions packages/cart/src/models/shipping-method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,20 @@ import ShippingMethodAdjustmentLine from "./shipping-method-adjustment-line"
import ShippingMethodTaxLine from "./shipping-method-tax-line"

@Entity({ tableName: "cart_shipping_method" })
@Check<ShippingMethod>({ expression: (columns) => `${columns.amount} >= 0` })
export default class ShippingMethod {
@PrimaryKey({ columnType: "text" })
id: string

@Property({ columnType: "text" })
cart_id: string

@ManyToOne(() => Cart, {
onDelete: "cascade",
index: "IDX_shipping_method_cart_id",
fieldName: "cart_id",
nullable: true,
})
cart: Cart
cart?: Cart | null

@Property({ columnType: "text" })
name: string
Expand All @@ -34,7 +38,6 @@ export default class ShippingMethod {
description?: string | null

@Property({ columnType: "numeric", serializer: Number })
@Check({ expression: "amount >= 0" }) // TODO: Validate that numeric types work with the expression
amount: number

@Property({ columnType: "boolean" })
Expand Down
7 changes: 6 additions & 1 deletion packages/cart/src/repositories/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ export class AddressRepository extends DALUtils.mikroOrmBaseRepositoryFactory<
create: CreateAddressDTO
update: UpdateAddressDTO
}
>(Address) {}
>(Address) {
constructor(...args: any[]) {
// @ts-ignore
super(...arguments)
}
}
1 change: 1 addition & 0 deletions packages/cart/src/repositories/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export { MikroOrmBaseRepository as BaseRepository } from "@medusajs/utils"
export * from "./address"
export * from "./cart"
export * from "./line-item"
export * from "./shipping-method"

7 changes: 6 additions & 1 deletion packages/cart/src/repositories/line-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ export class LineItemRepository extends DALUtils.mikroOrmBaseRepositoryFactory<
create: CreateLineItemDTO
update: UpdateLineItemDTO
}
>(LineItem) {}
>(LineItem) {
constructor(...args: any[]) {
// @ts-ignore
super(...arguments)
}
}
16 changes: 16 additions & 0 deletions packages/cart/src/repositories/shipping-method.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { DALUtils } from "@medusajs/utils"
import { ShippingMethod } from "@models"
import { CreateShippingMethodDTO, UpdateShippingMethodDTO } from "@types"

export class ShippingMethodRepository extends DALUtils.mikroOrmBaseRepositoryFactory<
ShippingMethod,
{
create: CreateShippingMethodDTO
update: UpdateShippingMethodDTO
}
>(ShippingMethod) {
constructor(...args: any[]) {
// @ts-ignore
super(...arguments)
}
}
Loading

1 comment on commit 7f7cb2a

@vercel
Copy link

@vercel vercel bot commented on 7f7cb2a Jan 18, 2024

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

medusa-dashboard – ./packages/admin-next/dashboard

medusa-dashboard-medusajs.vercel.app
medusa-dashboard-git-develop-medusajs.vercel.app
admin-preview.medusajs.com
medusa-dashboard.vercel.app

Please sign in to comment.