fix(medusa): Add free shipping functionality (#241)
This commit is contained in:
1 parent
348d1c4997
commit
fb0613d3cb
7 files changed
+210
-41
No files matched your search
@@ -65,7 +65,7 @@ describe("POST /store/carts/:id", () => {
|
||||
expect(CartServiceMock.retrieve).toHaveBeenCalledWith(
|
||||
IdMap.getId("emptyCart"),
|
||||
{
|
||||
relations: ["payment_sessions"],
|
||||
relations: ["payment_sessions", "shipping_methods"],
|
||||
}
|
||||
)
|
||||
expect(CartServiceMock.retrieve).toHaveBeenCalledWith(
|
||||
|
||||
@@ -104,7 +104,7 @@ export default async (req, res) => {
|
||||
|
||||
// If the cart has payment sessions update these
|
||||
const updated = await cartService.retrieve(id, {
|
||||
relations: ["payment_sessions"],
|
||||
relations: ["payment_sessions", "shipping_methods"],
|
||||
})
|
||||
|
||||
if (updated.payment_sessions?.length && !value.region_id) {
|
||||
|
||||
@@ -1281,6 +1281,7 @@ describe("CartService", () => {
|
||||
profile_id: IdMap.getId(m.profile),
|
||||
},
|
||||
})),
|
||||
discounts: [],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import _ from "lodash"
|
||||
import { Validator, MedusaError } from "medusa-core-utils"
|
||||
import { BaseService } from "medusa-interfaces"
|
||||
import { defaultFields, defaultRelations } from "../api/routes/store/carts"
|
||||
|
||||
/**
|
||||
* Provides layer to manipulate carts.
|
||||
@@ -574,6 +573,49 @@ class CartService extends BaseService {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures shipping total on cart is correct in regards to a potential free
|
||||
* shipping discount
|
||||
* If a free shipping is present, we set shipping methods price to 0
|
||||
* if a free shipping was present, we set shipping methods to original amount
|
||||
* @param {Cart} cart - the the cart to adjust free shipping for
|
||||
* @param {boolean} shouldAdd - flag to indicate, if we should add or remove
|
||||
*/
|
||||
async adjustFreeShipping_(cart, shouldAdd) {
|
||||
if (cart.shipping_methods?.length) {
|
||||
// if any free shipping discounts, we ensure to update shipping method amount
|
||||
if (shouldAdd) {
|
||||
await Promise.all(
|
||||
cart.shipping_methods.map(async sm => {
|
||||
const smRepo = this.manager_.getCustomRepository(
|
||||
this.shippingMethodRepository_
|
||||
)
|
||||
|
||||
const method = await smRepo.findOne({ where: { id: sm.id } })
|
||||
|
||||
if (method) {
|
||||
method.price = 0
|
||||
await smRepo.save(method)
|
||||
}
|
||||
})
|
||||
)
|
||||
} else {
|
||||
await Promise.all(
|
||||
cart.shipping_methods.map(async sm => {
|
||||
const smRepo = this.manager_.getCustomRepository(
|
||||
this.shippingMethodRepository_
|
||||
)
|
||||
|
||||
// if free shipping discount is removed, we adjust the shipping
|
||||
// back to its original amount
|
||||
sm.price = sm.shipping_option.amount
|
||||
await smRepo.save(sm)
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async update(cartId, update) {
|
||||
return this.atomicPhase_(async manager => {
|
||||
const cartRepo = manager.getCustomRepository(this.cartRepository_)
|
||||
@@ -627,10 +669,29 @@ class CartService extends BaseService {
|
||||
}
|
||||
|
||||
if ("discounts" in update) {
|
||||
const previousDiscounts = cart.discounts
|
||||
cart.discounts = []
|
||||
|
||||
for (const { code } of update.discounts) {
|
||||
await this.applyDiscount_(cart, code)
|
||||
}
|
||||
|
||||
const hasFreeShipping = cart.discounts.some(
|
||||
({ rule }) => rule.type === "free_shipping"
|
||||
)
|
||||
|
||||
// if we previously had a free shipping discount and then removed it,
|
||||
// we need to update shipping methods to original price
|
||||
if (
|
||||
previousDiscounts.some(({ rule }) => rule.type === "free_shipping") &&
|
||||
!hasFreeShipping
|
||||
) {
|
||||
await this.adjustFreeShipping_(cart, false)
|
||||
}
|
||||
|
||||
if (hasFreeShipping) {
|
||||
await this.adjustFreeShipping_(cart, true)
|
||||
}
|
||||
}
|
||||
|
||||
if ("gift_cards" in update) {
|
||||
@@ -890,8 +951,13 @@ class CartService extends BaseService {
|
||||
async removeDiscount(cartId, discountCode) {
|
||||
return this.atomicPhase_(async manager => {
|
||||
const cart = await this.retrieve(cartId, {
|
||||
relations: ["discounts", "payment_sessions"],
|
||||
relations: ["discounts", "payment_sessions", "shipping_methods"],
|
||||
})
|
||||
|
||||
if (cart.discounts.some(({ rule }) => rule.type === "free_shipping")) {
|
||||
await this.adjustFreeShipping_(cart, false)
|
||||
}
|
||||
|
||||
cart.discounts = cart.discounts.filter(d => d.code !== discountCode)
|
||||
|
||||
const cartRepo = manager.getCustomRepository(this.cartRepository_)
|
||||
@@ -1232,6 +1298,7 @@ class CartService extends BaseService {
|
||||
select: ["subtotal"],
|
||||
relations: [
|
||||
"shipping_methods",
|
||||
"discounts",
|
||||
"shipping_methods.shipping_option",
|
||||
"items",
|
||||
"items.variant",
|
||||
@@ -1267,7 +1334,15 @@ class CartService extends BaseService {
|
||||
})
|
||||
}
|
||||
|
||||
const result = await this.retrieve(cartId)
|
||||
const result = await this.retrieve(cartId, {
|
||||
relations: ["discounts", "shipping_methods"],
|
||||
})
|
||||
|
||||
// if cart has freeshipping, adjust price
|
||||
if (result.discounts.some(({ rule }) => rule.type === "free_shipping")) {
|
||||
await this.adjustFreeShipping_(result, true)
|
||||
}
|
||||
|
||||
await this.eventBus_
|
||||
.withTransaction(manager)
|
||||
.emit(CartService.Events.UPDATED, result)
|
||||
|
||||
@@ -400,8 +400,13 @@ class SwapService extends BaseService {
|
||||
|
||||
const order = swap.order
|
||||
|
||||
// filter out free shipping discounts
|
||||
const discounts =
|
||||
order?.discounts?.filter(({ rule }) => rule.type !== "free_shipping") ||
|
||||
undefined
|
||||
|
||||
const cart = await this.cartService_.withTransaction(manager).create({
|
||||
discounts: order.discounts,
|
||||
discounts,
|
||||
email: order.email,
|
||||
billing_address_id: order.billing_address_id,
|
||||
shipping_address_id: order.shipping_address_id,
|
||||
|
||||
Reference in new issue
Block a user