fix(medusa): Update cart sales channel should not remove all line items (#5980)
This commit is contained in:
committed by
GitHub
parent
42cc8ae3f8
commit
278b7fb203
5
.changeset/rude-boats-ring.md
Normal file
5
.changeset/rude-boats-ring.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@medusajs/medusa": patch
|
||||
---
|
||||
|
||||
fix(medusa): Update cart sales channel should not remove all line items
|
||||
@@ -42,6 +42,11 @@ describe("[MEDUSA_FF_SALES_CHANNELS] /store/carts", () => {
|
||||
|
||||
describe("POST /store/carts/:id", () => {
|
||||
let product
|
||||
let product2
|
||||
let product3
|
||||
|
||||
const salesChannelId = "sales-channel"
|
||||
const defaultSalesChannelId = "default-sales-channel"
|
||||
|
||||
beforeEach(async () => {
|
||||
await simpleRegionFactory(dbConnection, {
|
||||
@@ -55,13 +60,13 @@ describe("[MEDUSA_FF_SALES_CHANNELS] /store/carts", () => {
|
||||
product = await simpleProductFactory(dbConnection, {
|
||||
sales_channels: [
|
||||
{
|
||||
id: "sales-channel",
|
||||
id: salesChannelId,
|
||||
name: "Sales channel",
|
||||
description: "Sales channel",
|
||||
is_disabled: false,
|
||||
},
|
||||
{
|
||||
id: "default-sales-channel",
|
||||
id: defaultSalesChannelId,
|
||||
name: "Main sales channel",
|
||||
description: "Main sales channel",
|
||||
is_default: true,
|
||||
@@ -69,6 +74,10 @@ describe("[MEDUSA_FF_SALES_CHANNELS] /store/carts", () => {
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
product2 = await simpleProductFactory(dbConnection)
|
||||
|
||||
product3 = await simpleProductFactory(dbConnection)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -91,7 +100,7 @@ describe("[MEDUSA_FF_SALES_CHANNELS] /store/carts", () => {
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
sales_channel_id: "sales-channel",
|
||||
sales_channel_id: salesChannelId,
|
||||
})
|
||||
|
||||
const cart = createCartRes.data.cart
|
||||
@@ -110,7 +119,7 @@ describe("[MEDUSA_FF_SALES_CHANNELS] /store/carts", () => {
|
||||
expect(createdOrder.status).toEqual(200)
|
||||
expect(createdOrder.data.data).toEqual(
|
||||
expect.objectContaining({
|
||||
sales_channel_id: "sales-channel",
|
||||
sales_channel_id: salesChannelId,
|
||||
})
|
||||
)
|
||||
})
|
||||
@@ -152,5 +161,40 @@ describe("[MEDUSA_FF_SALES_CHANNELS] /store/carts", () => {
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should remove the line items that does not belong to the new sales channel", async () => {
|
||||
const api = useApi()
|
||||
|
||||
let createCartRes = await api.post("/store/carts", {
|
||||
region_id: "test-region",
|
||||
items: [
|
||||
{
|
||||
variant_id: product.variants[0].id,
|
||||
quantity: 1,
|
||||
},
|
||||
{
|
||||
variant_id: product2.variants[0].id,
|
||||
quantity: 1,
|
||||
},
|
||||
{
|
||||
variant_id: product3.variants[0].id,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
sales_channel_id: defaultSalesChannelId,
|
||||
})
|
||||
|
||||
let items = createCartRes.data.cart.items
|
||||
expect(items).toHaveLength(3)
|
||||
|
||||
const cartId = createCartRes.data.cart.id
|
||||
createCartRes = await api.post(`/store/carts/${cartId}`, {
|
||||
sales_channel_id: salesChannelId,
|
||||
})
|
||||
|
||||
items = createCartRes.data.cart.items
|
||||
expect(items).toHaveLength(1)
|
||||
expect(items.map((i) => i.variant.id)).toEqual([product.variants[0].id])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -744,9 +744,9 @@ describe("CartService", () => {
|
||||
)
|
||||
|
||||
expect(lineItemService.delete).toHaveBeenCalledTimes(1)
|
||||
expect(lineItemService.delete).toHaveBeenCalledWith(
|
||||
IdMap.getId("itemToRemove")
|
||||
)
|
||||
expect(lineItemService.delete).toHaveBeenCalledWith([
|
||||
IdMap.getId("itemToRemove"),
|
||||
])
|
||||
|
||||
expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1)
|
||||
expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({
|
||||
|
||||
@@ -267,21 +267,23 @@ const unknownVariantId = "unknown-variant"
|
||||
})
|
||||
describe("delete", () => {
|
||||
const lineItemRepository = MockRepository({
|
||||
findOne: () =>
|
||||
Promise.resolve({
|
||||
id: IdMap.getId("test-line-item"),
|
||||
variant_id: IdMap.getId("test-variant"),
|
||||
variant: {
|
||||
id: IdMap.getId("test-variant"),
|
||||
title: "Test variant",
|
||||
find: () =>
|
||||
Promise.resolve([
|
||||
{
|
||||
id: IdMap.getId("test-line-item"),
|
||||
variant_id: IdMap.getId("test-variant"),
|
||||
variant: {
|
||||
id: IdMap.getId("test-variant"),
|
||||
title: "Test variant",
|
||||
},
|
||||
cart_id: IdMap.getId("test-cart"),
|
||||
title: "Test product",
|
||||
description: "Test variant",
|
||||
thumbnail: "",
|
||||
unit_price: 50,
|
||||
quantity: 1,
|
||||
},
|
||||
cart_id: IdMap.getId("test-cart"),
|
||||
title: "Test product",
|
||||
description: "Test variant",
|
||||
thumbnail: "",
|
||||
unit_price: 50,
|
||||
quantity: 1,
|
||||
}),
|
||||
]),
|
||||
})
|
||||
|
||||
const lineItemService = new LineItemService({
|
||||
@@ -297,20 +299,22 @@ const unknownVariantId = "unknown-variant"
|
||||
await lineItemService.delete(IdMap.getId("test-line-item"))
|
||||
|
||||
expect(lineItemRepository.remove).toHaveBeenCalledTimes(1)
|
||||
expect(lineItemRepository.remove).toHaveBeenCalledWith({
|
||||
id: IdMap.getId("test-line-item"),
|
||||
variant_id: IdMap.getId("test-variant"),
|
||||
variant: {
|
||||
id: IdMap.getId("test-variant"),
|
||||
title: "Test variant",
|
||||
expect(lineItemRepository.remove).toHaveBeenCalledWith([
|
||||
{
|
||||
id: IdMap.getId("test-line-item"),
|
||||
variant_id: IdMap.getId("test-variant"),
|
||||
variant: {
|
||||
id: IdMap.getId("test-variant"),
|
||||
title: "Test variant",
|
||||
},
|
||||
cart_id: IdMap.getId("test-cart"),
|
||||
title: "Test product",
|
||||
description: "Test variant",
|
||||
thumbnail: "",
|
||||
unit_price: 50,
|
||||
quantity: 1,
|
||||
},
|
||||
cart_id: IdMap.getId("test-cart"),
|
||||
title: "Test product",
|
||||
description: "Test variant",
|
||||
thumbnail: "",
|
||||
unit_price: 50,
|
||||
quantity: 1,
|
||||
})
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -560,23 +560,29 @@ class CartService extends TransactionBaseService {
|
||||
/**
|
||||
* Removes a line item from the cart.
|
||||
* @param cartId - the id of the cart that we will remove from
|
||||
* @param lineItemId - the line item to remove.
|
||||
* @param lineItemId - the line item(s) to remove.
|
||||
* @return the result of the update operation
|
||||
*/
|
||||
async removeLineItem(cartId: string, lineItemId: string): Promise<Cart> {
|
||||
async removeLineItem(
|
||||
cartId: string,
|
||||
lineItemId: string | string[]
|
||||
): Promise<void> {
|
||||
return await this.atomicPhase_(
|
||||
async (transactionManager: EntityManager) => {
|
||||
const cart = await this.retrieve(cartId, {
|
||||
relations: [
|
||||
"items.variant.product.profiles",
|
||||
"payment_sessions",
|
||||
"shipping_methods",
|
||||
],
|
||||
relations: ["items.variant.product.profiles", "shipping_methods"],
|
||||
})
|
||||
|
||||
const lineItem = cart.items.find((item) => item.id === lineItemId)
|
||||
if (!lineItem) {
|
||||
return cart
|
||||
const lineItemIdsToRemove = new Set(
|
||||
Array.isArray(lineItemId) ? lineItemId : [lineItemId]
|
||||
)
|
||||
|
||||
const lineItems = cart.items.filter((item) =>
|
||||
lineItemIdsToRemove.has(item.id)
|
||||
)
|
||||
|
||||
if (!lineItems.length) {
|
||||
return
|
||||
}
|
||||
|
||||
if (cart.shipping_methods?.length) {
|
||||
@@ -599,12 +605,11 @@ class CartService extends TransactionBaseService {
|
||||
|
||||
await this.lineItemService_
|
||||
.withTransaction(transactionManager)
|
||||
.delete(lineItem.id)
|
||||
.delete([...lineItemIdsToRemove])
|
||||
|
||||
const result = await this.retrieve(cartId, {
|
||||
relations: [
|
||||
"items.variant.product.profiles",
|
||||
"discounts",
|
||||
"discounts.rule",
|
||||
"region",
|
||||
],
|
||||
@@ -618,8 +623,6 @@ class CartService extends TransactionBaseService {
|
||||
.emit(CartService.Events.UPDATED, {
|
||||
id: cart.id,
|
||||
})
|
||||
|
||||
return this.retrieve(cartId)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -1423,14 +1426,13 @@ class CartService extends TransactionBaseService {
|
||||
return !productIdsToKeep.has(item.variant.product_id)
|
||||
})
|
||||
|
||||
if (itemsToRemove.length) {
|
||||
const results = await promiseAll(
|
||||
itemsToRemove.map(async (item) => {
|
||||
return this.removeLineItem(cart.id, item.id)
|
||||
})
|
||||
)
|
||||
cart.items = results.pop()?.items ?? []
|
||||
if (!itemsToRemove.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const itemIdsToRemove = new Set(itemsToRemove.map((item) => item.id))
|
||||
await this.removeLineItem(cart.id, [...itemIdsToRemove])
|
||||
cart.items = cart.items.filter((item) => !itemIdsToRemove.has(item.id))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
import {MedusaError} from "medusa-core-utils"
|
||||
import {EntityManager, In} from "typeorm"
|
||||
import {DeepPartial} from "typeorm/common/DeepPartial"
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
import { EntityManager, In } from "typeorm"
|
||||
import { DeepPartial } from "typeorm/common/DeepPartial"
|
||||
|
||||
import {
|
||||
FlagRouter,
|
||||
MedusaV2Flag,
|
||||
selectorConstraintsToString
|
||||
selectorConstraintsToString,
|
||||
} from "@medusajs/utils"
|
||||
import {TransactionBaseService} from "../interfaces"
|
||||
import TaxInclusivePricingFeatureFlag
|
||||
from "../loaders/feature-flags/tax-inclusive-pricing"
|
||||
import { TransactionBaseService } from "../interfaces"
|
||||
import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing"
|
||||
import {
|
||||
LineItem,
|
||||
LineItemAdjustment,
|
||||
LineItemTaxLine,
|
||||
ProductVariant,
|
||||
} from "../models"
|
||||
import {CartRepository} from "../repositories/cart"
|
||||
import {LineItemRepository} from "../repositories/line-item"
|
||||
import {LineItemTaxLineRepository} from "../repositories/line-item-tax-line"
|
||||
import {FindConfig, Selector} from "../types/common"
|
||||
import {GenerateInputData, GenerateLineItemContext} from "../types/line-item"
|
||||
import {ProductVariantPricing} from "../types/pricing"
|
||||
import {buildQuery, isString, setMetadata} from "../utils"
|
||||
import { CartRepository } from "../repositories/cart"
|
||||
import { LineItemRepository } from "../repositories/line-item"
|
||||
import { LineItemTaxLineRepository } from "../repositories/line-item-tax-line"
|
||||
import { FindConfig, Selector } from "../types/common"
|
||||
import { GenerateInputData, GenerateLineItemContext } from "../types/line-item"
|
||||
import { ProductVariantPricing } from "../types/pricing"
|
||||
import { buildQuery, isString, setMetadata } from "../utils"
|
||||
import {
|
||||
PricingService,
|
||||
ProductService,
|
||||
@@ -484,23 +483,33 @@ class LineItemService extends TransactionBaseService {
|
||||
)
|
||||
}
|
||||
|
||||
async delete(ids: string[]): Promise<LineItem[]>
|
||||
async delete(id: string): Promise<LineItem | void>
|
||||
|
||||
/**
|
||||
* Deletes a line item.
|
||||
* @param id - the id of the line item to delete
|
||||
* @return the result of the delete operation
|
||||
*/
|
||||
async delete(id: string): Promise<LineItem | undefined | null> {
|
||||
async delete(id: string | string[]): Promise<LineItem[] | LineItem | void> {
|
||||
const ids = Array.isArray(id) ? id : [id]
|
||||
|
||||
return await this.atomicPhase_(
|
||||
async (transactionManager: EntityManager) => {
|
||||
const lineItemRepository = transactionManager.withRepository(
|
||||
this.lineItemRepository_
|
||||
)
|
||||
|
||||
return await lineItemRepository
|
||||
.findOne({ where: { id } })
|
||||
.then(
|
||||
async (lineItem) => lineItem && lineItemRepository.remove(lineItem)
|
||||
)
|
||||
const lineItems = await lineItemRepository.find({
|
||||
where: { id: In(ids) },
|
||||
})
|
||||
|
||||
if (!lineItems?.length) {
|
||||
return Array.isArray(id) ? [] : void 0
|
||||
}
|
||||
|
||||
const removedItems = await lineItemRepository.remove(lineItems)
|
||||
return Array.isArray(id) ? removedItems : removedItems[0]
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -511,7 +520,7 @@ class LineItemService extends TransactionBaseService {
|
||||
* @param id - the id of the line item to delete
|
||||
* @return the result of the delete operation
|
||||
*/
|
||||
async deleteWithTaxLines(id: string): Promise<LineItem | undefined | null> {
|
||||
async deleteWithTaxLines(id: string): Promise<LineItem | void> {
|
||||
return await this.atomicPhase_(
|
||||
async (transactionManager: EntityManager) => {
|
||||
await this.taxProviderService_
|
||||
|
||||
Reference in New Issue
Block a user