Fix/pricing update fixes (#5275)

* fix for merging line items and quantity prices

* add changeset

* fix draft order unit_price calculation

* update test to reflect only quantity change

* fix unit tests

* update conditional
This commit is contained in:
Philip Korsholm
2023-10-03 11:20:49 +02:00
committed by GitHub
parent c5703a4765
commit 90e24c593f
9 changed files with 186 additions and 67 deletions
@@ -1,6 +1,6 @@
import { CartServiceMock } from "../../../../../services/__mocks__/cart"
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { CartServiceMock } from "../../../../../services/__mocks__/cart"
describe("POST /store/carts/:id/line-items/:line_id", () => {
describe("successfully updates a line item", () => {
@@ -34,6 +34,7 @@ describe("POST /store/carts/:id/line-items/:line_id", () => {
region_id: IdMap.getId("region-france"),
quantity: 3,
metadata: {},
should_calculate_prices: true,
}
)
})
@@ -126,6 +127,7 @@ describe("POST /store/carts/:id/line-items/:line_id", () => {
quantity: 3,
region_id: expect.any(String),
variant_id: expect.any(String),
should_calculate_prices: true,
}
)
})
@@ -170,6 +172,7 @@ describe("POST /store/carts/:id/line-items/:line_id", () => {
quantity: 3,
region_id: expect.any(String),
variant_id: expect.any(String),
should_calculate_prices: true,
}
)
})
@@ -215,6 +218,7 @@ describe("POST /store/carts/:id/line-items/:line_id", () => {
quantity: 3,
region_id: expect.any(String),
variant_id: expect.any(String),
should_calculate_prices: true,
}
)
})
@@ -1,8 +1,9 @@
import { IsInt, IsOptional } from "class-validator"
import { MedusaError } from "medusa-core-utils"
import { EntityManager } from "typeorm"
import { defaultStoreCartFields, defaultStoreCartRelations } from "."
import { CartService } from "../../../../services"
import { EntityManager } from "typeorm"
import { MedusaError } from "medusa-core-utils"
import { cleanResponseData } from "../../../../utils/clean-response-data"
import { handleAddOrUpdateLineItem } from "./create-line-item/utils/handler-steps"
@@ -91,6 +92,7 @@ export default async (req, res) => {
region_id: cart.region_id,
quantity: validated.quantity,
metadata: validated.metadata || {},
should_calculate_prices: true,
}
await cartService
+86 -59
View File
@@ -1,10 +1,34 @@
import { FlagRouter } from "@medusajs/utils"
import { isEmpty, isEqual } from "lodash"
import { isDefined, MedusaError } from "medusa-core-utils"
import { DeepPartial, EntityManager, In, IsNull, Not } from "typeorm"
import {
CustomerService,
Address,
Cart,
CustomShippingOption,
Customer,
Discount,
DiscountRule,
DiscountRuleType,
LineItem,
PaymentSession,
PaymentSessionStatus,
SalesChannel,
ShippingMethod,
} from "../models"
import {
AddressPayload,
FindConfig,
TotalField,
WithRequiredProperty,
} from "../types/common"
import {
CartCreateProps,
CartUpdateProps,
FilterableCartProps,
LineItemUpdate,
LineItemValidateData,
isCart,
} from "../types/cart"
import {
CustomShippingOptionService,
CustomerService,
DiscountService,
EventBusService,
GiftCardService,
@@ -24,46 +48,23 @@ import {
TaxProviderService,
TotalsService,
} from "."
import { DeepPartial, EntityManager, In, IsNull, Not } from "typeorm"
import { IPriceSelectionStrategy, TransactionBaseService } from "../interfaces"
import IsolateProductDomainFeatureFlag from "../loaders/feature-flags/isolate-product-domain"
import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels"
import {
Address,
Cart,
Customer,
CustomShippingOption,
Discount,
DiscountRule,
DiscountRuleType,
LineItem,
PaymentSession,
PaymentSessionStatus,
SalesChannel,
ShippingMethod,
} from "../models"
import { MedusaError, isDefined } from "medusa-core-utils"
import { buildQuery, isString, setMetadata } from "../utils"
import { isEmpty, isEqual } from "lodash"
import { AddressRepository } from "../repositories/address"
import { CartRepository } from "../repositories/cart"
import { LineItemRepository } from "../repositories/line-item"
import { PaymentSessionRepository } from "../repositories/payment-session"
import { ShippingMethodRepository } from "../repositories/shipping-method"
import {
CartCreateProps,
CartUpdateProps,
FilterableCartProps,
isCart,
LineItemUpdate,
LineItemValidateData,
} from "../types/cart"
import {
AddressPayload,
FindConfig,
TotalField,
WithRequiredProperty,
} from "../types/common"
import { PaymentSessionInput } from "../types/payment"
import { buildQuery, isString, setMetadata } from "../utils"
import { validateEmail } from "../utils/is-email"
import { FlagRouter } from "@medusajs/utils"
import { IsNumber } from "class-validator"
import IsolateProductDomainFeatureFlag from "../loaders/feature-flags/isolate-product-domain"
import { LineItemRepository } from "../repositories/line-item"
import { PaymentSessionInput } from "../types/payment"
import { PaymentSessionRepository } from "../repositories/payment-session"
import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels"
import { ShippingMethodRepository } from "../repositories/shipping-method"
import { validateEmail } from "../utils/is-email"
type InjectedDependencies = {
manager: EntityManager
@@ -797,7 +798,7 @@ class CartService extends TransactionBaseService {
): Promise<void> {
const items: LineItem[] = Array.isArray(lineItems) ? lineItems : [lineItems]
const select: (keyof Cart)[] = ["id"]
const select: (keyof Cart)[] = ["id", "customer_id", "region_id"]
if (this.featureFlagRouter_.isFeatureEnabled("sales_channels")) {
select.push("sales_channel_id")
@@ -900,10 +901,33 @@ class CartService extends TransactionBaseService {
}
if (currentItem) {
const variantsPricing = await this.pricingService_
.withTransaction(transactionManager)
.getProductVariantsPricing(
[
{
variantId: item.variant_id!,
quantity: item.quantity,
},
],
{
region_id: cart.region_id,
customer_id: cart.customer_id,
include_discount_prices: true,
}
)
const { calculated_price } =
variantsPricing[currentItem.variant_id!]
lineItemsToUpdate[currentItem.id] = {
quantity: item.quantity,
has_shipping: false,
}
if (isDefined(calculated_price)) {
lineItemsToUpdate[currentItem.id].unit_price = calculated_price
}
} else {
// Since the variant is eager loaded, we are removing it before the line item is being created.
delete (item as Partial<LineItem>).variant
@@ -977,8 +1001,9 @@ class CartService extends TransactionBaseService {
async updateLineItem(
cartId: string,
lineItemId: string,
lineItemUpdate: LineItemUpdate
update: LineItemUpdate
): Promise<Cart> {
const { should_calculate_prices, ...lineItemUpdate } = update
return await this.atomicPhase_(
async (transactionManager: EntityManager) => {
const select: (keyof Cart)[] = ["id", "region_id", "customer_id"]
@@ -1021,24 +1046,26 @@ class CartService extends TransactionBaseService {
)
}
const variantsPricing = await this.pricingService_
.withTransaction(transactionManager)
.getProductVariantsPricing(
[
if (should_calculate_prices) {
const variantsPricing = await this.pricingService_
.withTransaction(transactionManager)
.getProductVariantsPricing(
[
{
variantId: lineItem.variant_id,
quantity: lineItemUpdate.quantity,
},
],
{
variantId: lineItem.variant_id,
quantity: lineItemUpdate.quantity,
},
],
{
region_id: cart.region_id,
customer_id: cart.customer_id,
include_discount_prices: true,
}
)
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
const { calculated_price } = variantsPricing[lineItem.variant_id]
lineItemUpdate.unit_price = calculated_price ?? undefined
}
}
}
+10 -4
View File
@@ -1,8 +1,13 @@
import { ValidateNested } from "class-validator"
import { IsType } from "../utils/validators/is-type"
import {
AddressPayload,
DateComparisonOperator,
StringComparisonOperator,
} from "./common"
import { Cart, CartType } from "../models/cart"
import { AddressPayload, DateComparisonOperator, StringComparisonOperator } from "./common"
import { IsType } from "../utils/validators/is-type"
import { Region } from "../models"
import { ValidateNested } from "class-validator"
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isCart(object: any): object is Cart {
@@ -29,10 +34,11 @@ export type LineItemUpdate = {
metadata?: Record<string, unknown>
region_id?: string
variant_id?: string
should_calculate_prices?: boolean
}
export type LineItemValidateData = {
variant?: { product_id: string };
variant?: { product_id: string }
variant_id: string
}