fix(medusa): quantity prices for line item updates (#5137)

* initial code push

* update metadata and only merge if the existing line item allows merging

* update should_merge check

* undo changes to taxrate service

* update results with unit pricing corresponding to the db values after update

* add should_merge property to line_item creation

* add should_merge property to line_item creation

* fix unit tests

* undo adding "should_merge" to create-line-item

* undo change to "addOrUpdateLineItem"

* :wqh_merge from generate method

* undo changes to unit tests

* revert to adding pricing in updateLineItem method

* update cart service test

* Create funny-radios-juggle.md

---------

Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
Philip Korsholm
2023-09-28 14:26:58 +02:00
committed by GitHub
parent f88e3865a0
commit 2b91049f58
11 changed files with 202 additions and 20 deletions

View File

@@ -1,4 +1,10 @@
import { IsInt, IsObject, IsOptional, IsString } from "class-validator"
import {
IsBoolean,
IsInt,
IsObject,
IsOptional,
IsString,
} from "class-validator"
import {
defaultAdminDraftOrdersCartFields,
defaultAdminDraftOrdersCartRelations,
@@ -114,7 +120,10 @@ export default async (req, res) => {
validated.variant_id,
draftOrder.cart.region_id,
validated.quantity,
{ metadata: validated.metadata, unit_price: validated.unit_price }
{
metadata: validated.metadata,
unit_price: validated.unit_price,
}
)
await cartService

View File

@@ -4,6 +4,7 @@ import { EntityManager } from "typeorm"
import { defaultStoreCartFields, defaultStoreCartRelations } from "."
import { CartService } from "../../../../services"
import { cleanResponseData } from "../../../../utils/clean-response-data"
import { handleAddOrUpdateLineItem } from "./create-line-item/utils/handler-steps"
/**
* @oas [post] /store/carts/{id}/line-items/{line_id}

View File

@@ -77,6 +77,7 @@ export const carts = {
title: "merge line",
description: "This is a new line",
thumbnail: "test-img-yeah.com/thumb",
variant_id: IdMap.getId("eur-10-us-12"),
unit_price: 10,
variant: {
id: IdMap.getId("eur-10-us-12"),

View File

@@ -58,7 +58,7 @@ export const LineItemServiceMock = {
variant_id: variantId,
unit_price: 100,
quantity,
metadata,
...metadata,
})
}),
delete: jest.fn().mockImplementation(() => Promise.resolve()),

View File

@@ -21,7 +21,7 @@ import { ShippingOptionServiceMock } from "../__mocks__/shipping-option"
import { ShippingProfileServiceMock } from "../__mocks__/shipping-profile"
import { taxProviderServiceMock } from "../__mocks__/tax-provider"
import CartService from "../cart"
import { NewTotalsService, TaxProviderService } from "../index"
import { NewTotalsService, PricingService, TaxProviderService } from "../index"
import SystemTaxService from "../system-tax"
const eventBusService = {
@@ -2657,6 +2657,7 @@ describe("CartService", () => {
.register("taxProviderService", asClass(TaxProviderService))
.register("newTotalsService", asClass(NewTotalsService))
.register("cartService", asClass(CartService))
.register("pricingService", asClass(PricingService))
const cartService = container.resolve("cartService")

View File

@@ -12,6 +12,7 @@ import {
LineItemService,
NewTotalsService,
PaymentProviderService,
PricingService,
ProductService,
ProductVariantInventoryService,
ProductVariantService,
@@ -62,6 +63,7 @@ import {
import { PaymentSessionInput } from "../types/payment"
import { buildQuery, isString, setMetadata } from "../utils"
import { validateEmail } from "../utils/is-email"
import { IsNumber } from "class-validator"
type InjectedDependencies = {
manager: EntityManager
@@ -91,6 +93,7 @@ type InjectedDependencies = {
lineItemAdjustmentService: LineItemAdjustmentService
priceSelectionStrategy: IPriceSelectionStrategy
productVariantInventoryService: ProductVariantInventoryService
pricingService: PricingService
}
type TotalsConfig = {
@@ -134,6 +137,7 @@ class CartService extends TransactionBaseService {
protected readonly featureFlagRouter_: FlagRouter
// eslint-disable-next-line max-len
protected readonly productVariantInventoryService_: ProductVariantInventoryService
protected readonly pricingService_: PricingService
constructor({
cartRepository,
@@ -162,6 +166,7 @@ class CartService extends TransactionBaseService {
featureFlagRouter,
storeService,
productVariantInventoryService,
pricingService,
}: InjectedDependencies) {
// eslint-disable-next-line prefer-rest-params
super(arguments[0])
@@ -192,6 +197,7 @@ class CartService extends TransactionBaseService {
this.featureFlagRouter_ = featureFlagRouter
this.storeService_ = storeService
this.productVariantInventoryService_ = productVariantInventoryService
this.pricingService_ = pricingService
}
/**
@@ -975,7 +981,7 @@ class CartService extends TransactionBaseService {
): Promise<Cart> {
return await this.atomicPhase_(
async (transactionManager: EntityManager) => {
const select: (keyof Cart)[] = ["id"]
const select: (keyof Cart)[] = ["id", "region_id", "customer_id"]
if (
this.featureFlagRouter_.isFeatureEnabled(SalesChannelFeatureFlag.key)
) {
@@ -1014,6 +1020,25 @@ class CartService extends TransactionBaseService {
"Inventory doesn't cover the desired quantity"
)
}
const variantsPricing = await this.pricingService_
.withTransaction(transactionManager)
.getProductVariantsPricing(
[
{
variantId: lineItem.variant_id,
quantity: lineItemUpdate.quantity,
},
],
{
region_id: cart.region_id,
customer_id: cart.customer_id,
include_discount_prices: true,
}
)
const { calculated_price } = variantsPricing[lineItem.variant_id]
lineItemUpdate.unit_price = calculated_price ?? undefined
}
}

View File

@@ -2,10 +2,10 @@ import { FlagRouter } from "@medusajs/utils"
import { ITaxCalculationStrategy, TaxCalculationContext } from "../interfaces"
import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing"
import {
LineItem,
LineItemTaxLine,
ShippingMethod,
ShippingMethodTaxLine,
LineItem,
LineItemTaxLine,
ShippingMethod,
ShippingMethodTaxLine,
} from "../models"
import { calculatePriceTaxAmount } from "../utils"
@@ -28,13 +28,18 @@ class TaxCalculationStrategy implements ITaxCalculationStrategy {
(tl) => "shipping_method_id" in tl
) as ShippingMethodTaxLine[]
return Math.round(
this.calculateLineItemsTax(items, lineItemsTaxLines, calculationContext) +
this.calculateShippingMethodsTax(
calculationContext.shipping_methods,
shippingMethodsTaxLines
)
const lineItemsTax = this.calculateLineItemsTax(
items,
lineItemsTaxLines,
calculationContext
)
const shippingMethodsTax = this.calculateShippingMethodsTax(
calculationContext.shipping_methods,
shippingMethodsTaxLines
)
return Math.round(lineItemsTax + shippingMethodsTax)
}
private calculateLineItemsTax(