perf(medusa): Shipping options + TransactionBaseService initialization (#2632)

This commit is contained in:
Adrien de Peretti authored and GitHub committed 2022-11-21 08:09:18 +01:00
1 parent d7997ef256
commit 5d977a8f57
10 files changed
+51 -69

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
---
"@medusajs/medusa": patch
---
feat(medusa): Performance improvements of listing shipping options
@@ -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> {
+10 -13
View File
@@ -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]
} }
} }
+1 -6
View File
@@ -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