فهرست منبع

feat(core): Add ProductVariantPriceSelectionStrategy

Relates to #1691
This adds a new configurable strategy which allows you to define the logic by which a variant price
is selected based on factors like active channel and currency code.
Michael Bromley 2 سال پیش
والد
کامیت
efe23d127f

+ 15 - 0
packages/core/src/config/catalog/default-product-variant-price-selection-strategy.ts

@@ -0,0 +1,15 @@
+import { RequestContext } from '../../api/common/request-context';
+import { idsAreEqual } from '../../common/utils';
+import { ProductVariantPrice } from '../../entity/product-variant/product-variant-price.entity';
+
+import { ProductVariantPriceSelectionStrategy } from './product-variant-price-selection-strategy';
+
+/**
+ * @description
+ * The default strategy for selecting the price for a ProductVariant in a given Channel.
+ */
+export class DefaultProductVariantPriceSelectionStrategy implements ProductVariantPriceSelectionStrategy {
+    selectPrice(ctx: RequestContext, prices: ProductVariantPrice[]) {
+        return prices.find(p => idsAreEqual(p.channelId, ctx.channelId));
+    }
+}

+ 10 - 0
packages/core/src/config/catalog/product-variant-price-selection-strategy.ts

@@ -0,0 +1,10 @@
+import { RequestContext } from '../../api/common/request-context';
+import { InjectableStrategy } from '../../common/types/injectable-strategy';
+import { ProductVariantPrice } from '../../entity/product-variant/product-variant-price.entity';
+
+export interface ProductVariantPriceSelectionStrategy extends InjectableStrategy {
+    selectPrice(
+        ctx: RequestContext,
+        prices: ProductVariantPrice[],
+    ): ProductVariantPrice | undefined | Promise<ProductVariantPrice | undefined>;
+}

+ 7 - 2
packages/core/src/config/config.module.ts

@@ -67,8 +67,12 @@ export class ConfigModule implements OnApplicationBootstrap, OnApplicationShutdo
     private getInjectableStrategies(): InjectableStrategy[] {
         const { assetNamingStrategy, assetPreviewStrategy, assetStorageStrategy } =
             this.configService.assetOptions;
-        const { productVariantPriceCalculationStrategy, stockDisplayStrategy, stockLocationStrategy } =
-            this.configService.catalogOptions;
+        const {
+            productVariantPriceCalculationStrategy,
+            productVariantPriceSelectionStrategy,
+            stockDisplayStrategy,
+            stockLocationStrategy,
+        } = this.configService.catalogOptions;
         const {
             adminAuthenticationStrategy,
             shopAuthenticationStrategy,
@@ -135,6 +139,7 @@ export class ConfigModule implements OnApplicationBootstrap, OnApplicationShutdo
             orderSellerStrategy,
             shippingLineAssignmentStrategy,
             stockLocationStrategy,
+            productVariantPriceSelectionStrategy,
         ];
     }
 

+ 2 - 0
packages/core/src/config/default-config.ts

@@ -18,6 +18,7 @@ import { DefaultPasswordValidationStrategy } from './auth/default-password-valid
 import { NativeAuthenticationStrategy } from './auth/native-authentication-strategy';
 import { defaultCollectionFilters } from './catalog/default-collection-filters';
 import { DefaultProductVariantPriceCalculationStrategy } from './catalog/default-product-variant-price-calculation-strategy';
+import { DefaultProductVariantPriceSelectionStrategy } from './catalog/default-product-variant-price-selection-strategy';
 import { DefaultStockDisplayStrategy } from './catalog/default-stock-display-strategy';
 import { DefaultStockLocationStrategy } from './catalog/default-stock-location-strategy';
 import { AutoIncrementIdStrategy } from './entity/auto-increment-id-strategy';
@@ -103,6 +104,7 @@ export const defaultConfig: RuntimeVendureConfig = {
     },
     catalogOptions: {
         collectionFilters: defaultCollectionFilters,
+        productVariantPriceSelectionStrategy: new DefaultProductVariantPriceSelectionStrategy(),
         productVariantPriceCalculationStrategy: new DefaultProductVariantPriceCalculationStrategy(),
         stockDisplayStrategy: new DefaultStockDisplayStrategy(),
         stockLocationStrategy: new DefaultStockLocationStrategy(),

+ 2 - 0
packages/core/src/config/index.ts

@@ -11,9 +11,11 @@ export * from './auth/password-hashing-strategy';
 export * from './auth/password-validation-strategy';
 export * from './catalog/collection-filter';
 export * from './catalog/default-collection-filters';
+export * from './catalog/default-product-variant-price-selection-strategy';
 export * from './catalog/default-stock-display-strategy';
 export * from './catalog/default-stock-location-strategy';
 export * from './catalog/product-variant-price-calculation-strategy';
+export * from './catalog/product-variant-price-selection-strategy';
 export * from './catalog/stock-display-strategy';
 export * from './catalog/stock-location-strategy';
 export * from './config.module';

+ 10 - 0
packages/core/src/config/vendure-config.ts

@@ -18,6 +18,7 @@ import { PasswordHashingStrategy } from './auth/password-hashing-strategy';
 import { PasswordValidationStrategy } from './auth/password-validation-strategy';
 import { CollectionFilter } from './catalog/collection-filter';
 import { ProductVariantPriceCalculationStrategy } from './catalog/product-variant-price-calculation-strategy';
+import { ProductVariantPriceSelectionStrategy } from './catalog/product-variant-price-selection-strategy';
 import { StockDisplayStrategy } from './catalog/stock-display-strategy';
 import { StockLocationStrategy } from './catalog/stock-location-strategy';
 import { CustomFields } from './custom-field/custom-field-types';
@@ -647,6 +648,15 @@ export interface CatalogOptions {
      * @default defaultCollectionFilters
      */
     collectionFilters?: Array<CollectionFilter<any>>;
+    /**
+     * @description
+     * Defines the strategy used to select the price of a ProductVariant, based on factors
+     * such as the active Channel and active CurrencyCode.
+     *
+     * @since 2.0.0
+     * @default DefaultProductVariantPriceSelectionStrategy
+     */
+    productVariantPriceSelectionStrategy?: ProductVariantPriceSelectionStrategy;
     /**
      * @description
      * Defines the strategy used for calculating the price of ProductVariants based

+ 6 - 2
packages/core/src/service/helpers/product-price-applicator/product-price-applicator.ts

@@ -57,7 +57,12 @@ export class ProductPriceApplicator {
         ctx: RequestContext,
         order?: Order,
     ): Promise<ProductVariant> {
-        const channelPrice = variant.productVariantPrices.find(p => idsAreEqual(p.channelId, ctx.channelId));
+        const { productVariantPriceSelectionStrategy, productVariantPriceCalculationStrategy } =
+            this.configService.catalogOptions;
+        const channelPrice = await productVariantPriceSelectionStrategy.selectPrice(
+            ctx,
+            variant.productVariantPrices,
+        );
         if (!channelPrice) {
             throw new InternalServerError(`error.no-price-found-for-channel`, {
                 variantId: variant.id,
@@ -78,7 +83,6 @@ export class ProductPriceApplicator {
             () => this.taxRateService.getApplicableTaxRate(ctx, activeTaxZone, variant.taxCategory),
         );
 
-        const { productVariantPriceCalculationStrategy } = this.configService.catalogOptions;
         const { price, priceIncludesTax } = await productVariantPriceCalculationStrategy.calculate({
             inputPrice: channelPrice.price,
             taxCategory: variant.taxCategory,