perf(medusa): Shipping options + TransactionBaseService initialization (#2632)
This commit is contained in:
1 parent
d7997ef256
commit
5d977a8f57
10 files changed
+51
-69
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(medusa): Performance improvements of listing shipping options
|
||||||
+1
-7
@@ -23,13 +23,7 @@ describe("GET /store/shipping-options", () => {
|
|||||||
expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledWith(
|
expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledWith(
|
||||||
IdMap.getId("emptyCart"),
|
IdMap.getId("emptyCart"),
|
||||||
{
|
{
|
||||||
relations: [
|
relations: ["items.variant", "items.variant.product"],
|
||||||
"region",
|
|
||||||
"items",
|
|
||||||
"items.adjustments",
|
|
||||||
"items.variant",
|
|
||||||
"items.variant.product",
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -56,13 +56,7 @@ export default async (req, res) => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const cart = await cartService.retrieveWithTotals(cart_id, {
|
const cart = await cartService.retrieveWithTotals(cart_id, {
|
||||||
relations: [
|
relations: ["items.variant", "items.variant.product"],
|
||||||
"region",
|
|
||||||
"items",
|
|
||||||
"items.adjustments",
|
|
||||||
"items.variant",
|
|
||||||
"items.variant.product",
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const options = await shippingProfileService.fetchCartOptions(cart)
|
const options = await shippingProfileService.fetchCartOptions(cart)
|
||||||
|
|||||||
@@ -16,13 +16,11 @@ export abstract class TransactionBaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cloned = new (this.constructor as any)(
|
const cloned = new (this.constructor as any)(
|
||||||
{
|
this.__container__,
|
||||||
...this.__container__,
|
|
||||||
manager: transactionManager,
|
|
||||||
},
|
|
||||||
this.__configModule__
|
this.__configModule__
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cloned.manager_ = transactionManager
|
||||||
cloned.transactionManager_ = transactionManager
|
cloned.transactionManager_ = transactionManager
|
||||||
|
|
||||||
return cloned
|
return cloned
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { IdMap, MockRepository, MockManager } from "medusa-test-utils"
|
import { IdMap, MockManager, MockRepository } from "medusa-test-utils"
|
||||||
import ShippingProfileService from "../shipping-profile"
|
import ShippingProfileService from "../shipping-profile"
|
||||||
|
|
||||||
describe("ShippingProfileService", () => {
|
describe("ShippingProfileService", () => {
|
||||||
@@ -188,7 +188,7 @@ describe("ShippingProfileService", () => {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
}),
|
}),
|
||||||
validateCartOption: jest.fn().mockImplementation((s) => s),
|
validateCartOption: jest.fn().mockImplementation(async (s) => s),
|
||||||
withTransaction: function () {
|
withTransaction: function () {
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
FulfillmentProvider,
|
FulfillmentProvider,
|
||||||
LineItem,
|
LineItem,
|
||||||
Order,
|
Order,
|
||||||
Return,
|
|
||||||
ShippingMethod,
|
ShippingMethod,
|
||||||
ShippingOption,
|
ShippingOption,
|
||||||
} from "../models"
|
} from "../models"
|
||||||
@@ -150,7 +149,11 @@ class FulfillmentProviderService extends TransactionBaseService {
|
|||||||
cart?: Order | Cart
|
cart?: Order | Cart
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
const provider = this.retrieveProvider(option.provider_id)
|
const provider = this.retrieveProvider(option.provider_id)
|
||||||
return provider.calculatePrice(option.data, data, cart) as unknown as number
|
return (await provider.calculatePrice(
|
||||||
|
option.data,
|
||||||
|
data,
|
||||||
|
cart
|
||||||
|
)) as unknown as number
|
||||||
}
|
}
|
||||||
|
|
||||||
async validateOption(option: ShippingOption): Promise<boolean> {
|
async validateOption(option: ShippingOption): Promise<boolean> {
|
||||||
|
|||||||
@@ -432,7 +432,9 @@ class PricingService extends TransactionBaseService {
|
|||||||
if ("automatic_taxes" in context) {
|
if ("automatic_taxes" in context) {
|
||||||
pricingContext = context
|
pricingContext = context
|
||||||
} else {
|
} else {
|
||||||
pricingContext = await this.collectPricingContext(context)
|
pricingContext =
|
||||||
|
(context as PricingContext) ??
|
||||||
|
(await this.collectPricingContext(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
let shippingOptionRates: TaxServiceRate[] = []
|
let shippingOptionRates: TaxServiceRate[] = []
|
||||||
@@ -470,14 +472,12 @@ class PricingService extends TransactionBaseService {
|
|||||||
)
|
)
|
||||||
const totalInclTax = includesTax ? price : price + taxAmount
|
const totalInclTax = includesTax ? price : price + taxAmount
|
||||||
|
|
||||||
const result: PricedShippingOption = {
|
return {
|
||||||
...shippingOption,
|
...shippingOption,
|
||||||
price_incl_tax: totalInclTax,
|
price_incl_tax: totalInclTax,
|
||||||
tax_rates: shippingOptionRates,
|
tax_rates: shippingOptionRates,
|
||||||
tax_amount: taxAmount,
|
tax_amount: taxAmount,
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -508,7 +508,8 @@ class PricingService extends TransactionBaseService {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
return await Promise.all(
|
const shippingOptionPricingPromises: Promise<PricedShippingOption>[] = []
|
||||||
|
|
||||||
shippingOptions.map(async (shippingOption) => {
|
shippingOptions.map(async (shippingOption) => {
|
||||||
const pricingContext = contexts.find(
|
const pricingContext = contexts.find(
|
||||||
(c) => c.region_id === shippingOption.region_id
|
(c) => c.region_id === shippingOption.region_id
|
||||||
@@ -521,16 +522,12 @@ class PricingService extends TransactionBaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const shippingOptionPricing = await this.getShippingOptionPricing(
|
shippingOptionPricingPromises.push(
|
||||||
shippingOption,
|
this.getShippingOptionPricing(shippingOption, pricingContext.context)
|
||||||
pricingContext.context
|
|
||||||
)
|
)
|
||||||
return {
|
|
||||||
...shippingOption,
|
|
||||||
...shippingOptionPricing,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
)
|
|
||||||
|
return await Promise.all(shippingOptionPricingPromises)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ import { ShippingOptionRequirementRepository } from "../repositories/shipping-op
|
|||||||
import { ExtendedFindConfig, FindConfig, Selector } from "../types/common"
|
import { ExtendedFindConfig, FindConfig, Selector } from "../types/common"
|
||||||
import {
|
import {
|
||||||
CreateShippingMethodDto,
|
CreateShippingMethodDto,
|
||||||
|
CreateShippingOptionInput,
|
||||||
ShippingMethodUpdate,
|
ShippingMethodUpdate,
|
||||||
UpdateShippingOptionInput,
|
UpdateShippingOptionInput,
|
||||||
CreateShippingOptionInput,
|
|
||||||
} from "../types/shipping-options"
|
} from "../types/shipping-options"
|
||||||
import { buildQuery, isDefined, setMetadata } from "../utils"
|
import { buildQuery, isDefined, setMetadata } from "../utils"
|
||||||
import FulfillmentProviderService from "./fulfillment-provider"
|
import FulfillmentProviderService from "./fulfillment-provider"
|
||||||
@@ -370,7 +370,7 @@ class ShippingOptionService extends TransactionBaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const amount = (option.includes_tax ? cart.total : cart.subtotal) as number
|
const amount = option.includes_tax ? cart.total! : cart.subtotal!
|
||||||
|
|
||||||
const requirementResults: boolean[] = option.requirements.map(
|
const requirementResults: boolean[] = option.requirements.map(
|
||||||
(requirement) => {
|
(requirement) => {
|
||||||
@@ -385,7 +385,7 @@ class ShippingOptionService extends TransactionBaseService {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!requirementResults.every(Boolean)) {
|
if (requirementResults.some((requirement) => !requirement)) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.NOT_ALLOWED,
|
MedusaError.Types.NOT_ALLOWED,
|
||||||
"The Cart does not satisfy the shipping option's requirements"
|
"The Cart does not satisfy the shipping option's requirements"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { EntityManager } from "typeorm"
|
|||||||
import { TransactionBaseService } from "../interfaces"
|
import { TransactionBaseService } from "../interfaces"
|
||||||
import {
|
import {
|
||||||
Cart,
|
Cart,
|
||||||
|
CustomShippingOption,
|
||||||
ShippingOption,
|
ShippingOption,
|
||||||
ShippingProfile,
|
ShippingProfile,
|
||||||
ShippingProfileType,
|
ShippingProfileType,
|
||||||
@@ -422,10 +423,14 @@ class ShippingProfileService extends TransactionBaseService {
|
|||||||
|
|
||||||
// if there are custom shipping options associated with the cart, return cart shipping options with custom price
|
// if there are custom shipping options associated with the cart, return cart shipping options with custom price
|
||||||
if (hasCustomShippingOptions) {
|
if (hasCustomShippingOptions) {
|
||||||
|
const customShippingOptionsMap = new Map<string, CustomShippingOption>()
|
||||||
|
|
||||||
|
customShippingOptions.forEach((option) => {
|
||||||
|
customShippingOptionsMap.set(option.shipping_option_id, option)
|
||||||
|
})
|
||||||
|
|
||||||
return rawOpts.map((so) => {
|
return rawOpts.map((so) => {
|
||||||
const customOption = customShippingOptions.find(
|
const customOption = customShippingOptionsMap.get(so.id)
|
||||||
(cso) => cso.shipping_option_id === so.id
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...so,
|
...so,
|
||||||
@@ -434,24 +439,16 @@ class ShippingProfileService extends TransactionBaseService {
|
|||||||
}) as ShippingOption[]
|
}) as ShippingOption[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = await Promise.all(
|
return (
|
||||||
|
await Promise.all(
|
||||||
rawOpts.map(async (so) => {
|
rawOpts.map(async (so) => {
|
||||||
try {
|
return await this.shippingOptionService_
|
||||||
const option = await this.shippingOptionService_
|
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.validateCartOption(so, cart)
|
.validateCartOption(so, cart)
|
||||||
if (option) {
|
.catch(() => null) // if validateCartOption fails it means the option is not valid
|
||||||
return option
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
} catch (err) {
|
|
||||||
// if validateCartOption fails it means the option is not valid
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
).filter((option): option is ShippingOption => !!option)
|
||||||
return options.filter(Boolean) as ShippingOption[]
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,16 +458,15 @@ class ShippingProfileService extends TransactionBaseService {
|
|||||||
* @return a list of product ids
|
* @return a list of product ids
|
||||||
*/
|
*/
|
||||||
protected getProfilesInCart(cart: Cart): string[] {
|
protected getProfilesInCart(cart: Cart): string[] {
|
||||||
return cart.items.reduce((acc, next) => {
|
const profileIds = new Set<string>()
|
||||||
// We may have line items that are not associated with a product
|
|
||||||
if (next.variant && next.variant.product) {
|
|
||||||
if (!acc.includes(next.variant.product.profile_id)) {
|
|
||||||
acc.push(next.variant.product.profile_id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc
|
cart.items.forEach((item) => {
|
||||||
}, [] as string[])
|
if (item.variant?.product) {
|
||||||
|
profileIds.add(item.variant.product.profile_id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return [...profileIds]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,12 +34,7 @@ class StoreService extends TransactionBaseService {
|
|||||||
currencyRepository,
|
currencyRepository,
|
||||||
eventBusService,
|
eventBusService,
|
||||||
}: InjectedDependencies) {
|
}: InjectedDependencies) {
|
||||||
super({
|
super(arguments[0])
|
||||||
manager,
|
|
||||||
storeRepository,
|
|
||||||
currencyRepository,
|
|
||||||
eventBusService,
|
|
||||||
})
|
|
||||||
|
|
||||||
this.manager_ = manager
|
this.manager_ = manager
|
||||||
this.storeRepository_ = storeRepository
|
this.storeRepository_ = storeRepository
|
||||||
|
|||||||
Reference in new issue
Block a user