Jelajahi Sumber

feat(server): Expose priceWithTax in search results

Closes #82
Michael Bromley 6 tahun lalu
induk
melakukan
a9dd4971a8

File diff ditekan karena terlalu besar
+ 0 - 0
schema-admin.json


File diff ditekan karena terlalu besar
+ 0 - 0
schema-shop.json


+ 18 - 2
schema.json

@@ -12287,6 +12287,22 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "priceWithTax",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "UNION",
+                "name": "SearchResultPrice",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "currencyCode",
             "description": null,
@@ -12437,7 +12453,7 @@
       {
         "kind": "OBJECT",
         "name": "PriceRange",
-        "description": null,
+        "description": "The price range where the result has more than one price",
         "fields": [
           {
             "name": "min",
@@ -12480,7 +12496,7 @@
       {
         "kind": "OBJECT",
         "name": "SinglePrice",
-        "description": null,
+        "description": "The price value where the result has a single price",
         "fields": [
           {
             "name": "value",

+ 60 - 8
server/e2e/default-search-plugin.e2e-spec.ts

@@ -6,6 +6,7 @@ import {
     UPDATE_COLLECTION,
 } from '../../admin-ui/src/app/data/definitions/collection-definitions';
 import { SEARCH_PRODUCTS, UPDATE_PRODUCT } from '../../admin-ui/src/app/data/definitions/product-definitions';
+import { UPDATE_TAX_RATE } from '../../admin-ui/src/app/data/definitions/settings-definitions';
 import {
     ConfigArgType,
     CreateCollection,
@@ -14,6 +15,7 @@ import {
     SearchProducts,
     UpdateCollection,
     UpdateProduct,
+    UpdateTaxRate,
 } from '../../shared/generated-types';
 import { SimpleGraphQLClient } from '../mock-data/simple-graphql-client';
 import { facetValueCollectionFilter } from '../src/config/collection/default-collection-filters';
@@ -116,10 +118,19 @@ describe('Default search plugin', () => {
                 take: 3,
             } as SearchInput,
         });
-        expect(result.search.items.map(i => i.price)).toEqual([
-            { value: 129900 },
-            { value: 139900 },
-            { value: 219900 },
+        expect(result.search.items).toEqual([
+            {
+                price: { value: 129900 },
+                priceWithTax: { value: 155880 },
+            },
+            {
+                price: { value: 139900 },
+                priceWithTax: { value: 167880 },
+            },
+            {
+                price: { value: 219900 },
+                priceWithTax: { value: 263880 },
+            },
         ]);
     }
 
@@ -130,10 +141,19 @@ describe('Default search plugin', () => {
                 take: 3,
             } as SearchInput,
         });
-        expect(result.search.items.map(i => i.price)).toEqual([
-            { min: 129900, max: 229900 },
-            { min: 14374, max: 16994 },
-            { min: 93120, max: 109995 },
+        expect(result.search.items).toEqual([
+            {
+                price: { min: 129900, max: 229900 },
+                priceWithTax: { min: 155880, max: 275880 },
+            },
+            {
+                price: { min: 14374, max: 16994 },
+                priceWithTax: { min: 17249, max: 20393 },
+            },
+            {
+                price: { min: 93120, max: 109995 },
+                priceWithTax: { min: 111744, max: 131994 },
+            },
         ]);
     }
 
@@ -312,6 +332,29 @@ describe('Default search plugin', () => {
                 'SLR Camera',
             ]);
         });
+
+        it('updates index when a taxRate is changed', async () => {
+            await adminClient.query<UpdateTaxRate.Mutation, UpdateTaxRate.Variables>(UPDATE_TAX_RATE, {
+                input: {
+                    // Default Channel's defaultTaxZone is Europe (id 2) and the id of the standard TaxRate
+                    // to Europe is 2.
+                    id: 'T_2',
+                    value: 50,
+                },
+            });
+            const result = await adminClient.query(SEARCH_GET_PRICES, {
+                input: {
+                    groupByProduct: true,
+                    term: 'laptop',
+                } as SearchInput,
+            });
+            expect(result.search.items).toEqual([
+                {
+                    price: { min: 129900, max: 229900 },
+                    priceWithTax: { min: 194850, max: 344850 },
+                },
+            ]);
+        });
     });
 });
 
@@ -343,6 +386,15 @@ export const SEARCH_GET_PRICES = gql`
                         value
                     }
                 }
+                priceWithTax {
+                    ... on PriceRange {
+                        min
+                        max
+                    }
+                    ... on SinglePrice {
+                        value
+                    }
+                }
             }
         }
     }

+ 10 - 4
server/src/api/resolvers/admin/tax-rate.resolver.ts

@@ -34,14 +34,20 @@ export class TaxRateResolver {
     @Mutation()
     @Allow(Permission.CreateSettings)
     @Decode('categoryId', 'zoneId', 'customerGroupId')
-    async createTaxRate(@Args() args: CreateTaxRateMutationArgs): Promise<TaxRate> {
-        return this.taxRateService.create(args.input);
+    async createTaxRate(
+        @Ctx() ctx: RequestContext,
+        @Args() args: CreateTaxRateMutationArgs,
+    ): Promise<TaxRate> {
+        return this.taxRateService.create(ctx, args.input);
     }
 
     @Mutation()
     @Allow(Permission.UpdateSettings)
     @Decode('categoryId', 'zoneId', 'customerGroupId')
-    async updateTaxRate(@Args() args: UpdateTaxRateMutationArgs): Promise<TaxRate> {
-        return this.taxRateService.update(args.input);
+    async updateTaxRate(
+        @Ctx() ctx: RequestContext,
+        @Args() args: UpdateTaxRateMutationArgs,
+    ): Promise<TaxRate> {
+        return this.taxRateService.update(ctx, args.input);
     }
 }

+ 1 - 0
server/src/api/schema/type/product-search.type.graphql

@@ -27,6 +27,7 @@ type SearchResult {
     productVariantName: String!
     productVariantPreview: String!
     price: SearchResultPrice!
+    priceWithTax: SearchResultPrice!
     currencyCode: CurrencyCode!
     description: String!
     facetIds: [String!]!

+ 2 - 2
server/src/data-import/providers/populator/populator.ts

@@ -106,7 +106,7 @@ export class Populator {
         // Wait for the created collection operations to complete before running
         // the reindex of the search index.
         await new Promise(resolve => setTimeout(resolve, 50));
-        await this.searchService.reindex(ctx.languageCode);
+        await this.searchService.reindex(ctx);
     }
 
     private async createRequestContext(data: InitialData) {
@@ -174,7 +174,7 @@ export class Populator {
             const category = await this.taxCategoryService.create({ name: taxRate.name });
 
             for (const { entity } of zoneMap.values()) {
-                await this.taxRateService.create({
+                await this.taxRateService.create(ctx, {
                     zoneId: entity.id as string,
                     value: taxRate.percentage,
                     categoryId: category.id as string,

+ 15 - 0
server/src/event-bus/events/tax-rate-modification-event.ts

@@ -0,0 +1,15 @@
+import { RequestContext } from '../../api/common/request-context';
+import { TaxRate } from '../../entity';
+import { VendureEvent } from '../vendure-event';
+
+/**
+ * @description
+ * This event is fired whenever a TaxRate is changed
+ *
+ * @docsCategory events
+ */
+export class TaxRateModificationEvent extends VendureEvent {
+    constructor(public ctx: RequestContext, public taxRate: TaxRate) {
+        super();
+    }
+}

+ 8 - 0
server/src/plugin/default-search-plugin/default-search-plugin.ts

@@ -3,12 +3,14 @@ import gql from 'graphql-tag';
 
 import { SearchReindexResponse } from '../../../../shared/generated-types';
 import { Type } from '../../../../shared/shared-types';
+import { idsAreEqual } from '../../common/utils';
 import { APIExtensionDefinition, VendurePlugin } from '../../config';
 import { ProductVariant } from '../../entity/product-variant/product-variant.entity';
 import { Product } from '../../entity/product/product.entity';
 import { EventBus } from '../../event-bus/event-bus';
 import { CatalogModificationEvent } from '../../event-bus/events/catalog-modification-event';
 import { CollectionModificationEvent } from '../../event-bus/events/collection-modification-event';
+import { TaxRateModificationEvent } from '../../event-bus/events/tax-rate-modification-event';
 import { SearchService } from '../../service/services/search.service';
 
 import { AdminFulltextSearchResolver, ShopFulltextSearchResolver } from './fulltext-search.resolver';
@@ -32,6 +34,12 @@ export class DefaultSearchPlugin implements VendurePlugin {
         eventBus.subscribe(CollectionModificationEvent, event => {
             return fulltextSearchService.updateVariantsById(event.ctx, event.productVariantIds);
         });
+        eventBus.subscribe(TaxRateModificationEvent, event => {
+            const defaultTaxZone = event.ctx.channel.defaultTaxZone;
+            if (defaultTaxZone && idsAreEqual(defaultTaxZone.id, event.taxRate.zone.id)) {
+                return fulltextSearchService.reindex(event.ctx);
+            }
+        });
     }
 
     extendAdminAPI(): APIExtensionDefinition {

+ 1 - 1
server/src/plugin/default-search-plugin/fulltext-search.resolver.ts

@@ -61,6 +61,6 @@ export class AdminFulltextSearchResolver implements BaseSearchResolver {
     @Mutation()
     @Allow(Permission.UpdateCatalog)
     async reindex(@Ctx() ctx: RequestContext): Promise<DefaultSearchReindexResponse> {
-        return this.fulltextSearchService.reindex(ctx.languageCode);
+        return this.fulltextSearchService.reindex(ctx);
     }
 }

+ 13 - 8
server/src/plugin/default-search-plugin/fulltext-search.service.ts

@@ -13,6 +13,7 @@ import { FacetValue, Product, ProductVariant } from '../../entity';
 import { EventBus } from '../../event-bus/event-bus';
 import { translateDeep } from '../../service/helpers/utils/translate-entity';
 import { FacetValueService } from '../../service/services/facet-value.service';
+import { ProductVariantService } from '../../service/services/product-variant.service';
 import { SearchService } from '../../service/services/search.service';
 
 import { DefaultSearchReindexResponse } from './default-search-plugin';
@@ -39,12 +40,14 @@ export class FulltextSearchService implements SearchService {
         'facetValues',
         'facetValues.facet',
         'collections',
+        'taxCategory',
     ];
 
     constructor(
         @InjectConnection() private connection: Connection,
         private eventBus: EventBus,
         private facetValueService: FacetValueService,
+        private productVariantService: ProductVariantService,
     ) {
         this.setSearchStrategy();
     }
@@ -84,7 +87,7 @@ export class FulltextSearchService implements SearchService {
     /**
      * Rebuilds the full search index.
      */
-    async reindex(languageCode: LanguageCode): Promise<DefaultSearchReindexResponse> {
+    async reindex(ctx: RequestContext): Promise<DefaultSearchReindexResponse> {
         const timeStart = Date.now();
         const qb = await this.connection.getRepository(ProductVariant).createQueryBuilder('variants');
         FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder(qb, {
@@ -92,8 +95,8 @@ export class FulltextSearchService implements SearchService {
         });
         FindOptionsUtils.joinEagerRelations(qb, qb.alias, this.connection.getMetadata(ProductVariant));
         const variants = await qb.where('variants_product.deletedAt IS NULL').getMany();
-        await this.connection.getRepository(SearchIndexItem).delete({ languageCode });
-        await this.saveSearchIndexItems(languageCode, variants);
+        await this.connection.getRepository(SearchIndexItem).delete({ languageCode: ctx.languageCode });
+        await this.saveSearchIndexItems(ctx, variants);
         return {
             success: true,
             indexedItemCount: variants.length,
@@ -131,7 +134,7 @@ export class FulltextSearchService implements SearchService {
             }
         }
         if (updatedVariants.length) {
-            await this.saveSearchIndexItems(ctx.languageCode, updatedVariants);
+            await this.saveSearchIndexItems(ctx, updatedVariants);
         }
         if (removedVariantIds.length) {
             await this.removeSearchIndexItems(ctx.languageCode, removedVariantIds);
@@ -143,7 +146,7 @@ export class FulltextSearchService implements SearchService {
             const updatedVariants = await this.connection.getRepository(ProductVariant).findByIds(ids, {
                 relations: this.variantRelations,
             });
-            await this.saveSearchIndexItems(ctx.languageCode, updatedVariants);
+            await this.saveSearchIndexItems(ctx, updatedVariants);
         }
     }
 
@@ -171,16 +174,18 @@ export class FulltextSearchService implements SearchService {
     /**
      * Add or update items in the search index
      */
-    private async saveSearchIndexItems(languageCode: LanguageCode, variants: ProductVariant[]) {
+    private async saveSearchIndexItems(ctx: RequestContext, variants: ProductVariant[]) {
         const items = variants
-            .map(v => translateDeep(v, languageCode, ['product']))
+            .map(v => this.productVariantService.applyChannelPriceAndTax(v, ctx))
+            .map(v => translateDeep(v, ctx.languageCode, ['product']))
             .map(
                 v =>
                     new SearchIndexItem({
                         sku: v.sku,
                         slug: v.product.slug,
                         price: v.price,
-                        languageCode,
+                        priceWithTax: v.priceWithTax,
+                        languageCode: ctx.languageCode,
                         productVariantId: v.id,
                         productId: v.product.id,
                         productName: v.product.name,

+ 3 - 0
server/src/plugin/default-search-plugin/search-index-item.entity.ts

@@ -44,6 +44,9 @@ export class SearchIndexItem {
     @Column()
     price: number;
 
+    @Column()
+    priceWithTax: number;
+
     currencyCode: CurrencyCode;
 
     @Column('simple-array')

+ 4 - 1
server/src/plugin/default-search-plugin/search-strategy/mysql-search-strategy.ts

@@ -38,7 +38,10 @@ export class MysqlSearchStrategy implements SearchStrategy {
         const sort = input.sort;
         const qb = this.connection.getRepository(SearchIndexItem).createQueryBuilder('si');
         if (input.groupByProduct) {
-            qb.addSelect('MIN(price)', 'minPrice').addSelect('MAX(price)', 'maxPrice');
+            qb.addSelect('MIN(price)', 'minPrice')
+                .addSelect('MAX(price)', 'maxPrice')
+                .addSelect('MIN(priceWithTax)', 'minPriceWithTax')
+                .addSelect('MAX(priceWithTax)', 'maxPriceWithTax');
         }
         this.applyTermAndFilters(qb, input);
         if (input.term && input.term.length > this.minTermLength) {

+ 5 - 1
server/src/plugin/default-search-plugin/search-strategy/postgres-search-strategy.ts

@@ -41,7 +41,10 @@ export class PostgresSearchStrategy implements SearchStrategy {
             .createQueryBuilder('si')
             .select(this.createPostgresSelect(!!input.groupByProduct));
         if (input.groupByProduct) {
-            qb.addSelect('MIN(price)', 'minPrice').addSelect('MAX(price)', 'maxPrice');
+            qb.addSelect('MIN(price)', 'minPrice')
+                .addSelect('MAX(price)', 'maxPrice')
+                .addSelect('MIN("priceWithTax")', 'minPriceWithTax')
+                .addSelect('MAX("priceWithTax")', 'maxPriceWithTax');
         }
         this.applyTermAndFilters(qb, input);
         if (input.term && input.term.length > this.minTermLength) {
@@ -142,6 +145,7 @@ export class PostgresSearchStrategy implements SearchStrategy {
             'sku',
             'slug',
             'price',
+            'priceWithTax',
             'productVariantId',
             'languageCode',
             'productId',

+ 5 - 0
server/src/plugin/default-search-plugin/search-strategy/search-strategy-utils.ts

@@ -10,10 +10,15 @@ export function mapToSearchResult(raw: any, currencyCode: CurrencyCode): SearchR
         raw.minPrice !== undefined
             ? ({ min: raw.minPrice, max: raw.maxPrice } as PriceRange)
             : ({ value: raw.si_price } as SinglePrice);
+    const priceWithTax =
+        raw.minPriceWithTax !== undefined
+            ? ({ min: raw.minPriceWithTax, max: raw.maxPriceWithTax } as PriceRange)
+            : ({ value: raw.si_priceWithTax } as SinglePrice);
     return {
         sku: raw.si_sku,
         slug: raw.si_slug,
         price,
+        priceWithTax,
         currencyCode,
         productVariantId: raw.si_productVariantId,
         productId: raw.si_productId,

+ 4 - 0
server/src/plugin/default-search-plugin/search-strategy/sqlite-search-strategy.ts

@@ -40,6 +40,10 @@ export class SqliteSearchStrategy implements SearchStrategy {
         const qb = this.connection.getRepository(SearchIndexItem).createQueryBuilder('si');
         if (input.groupByProduct) {
             qb.addSelect('MIN(price)', 'minPrice').addSelect('MAX(price)', 'maxPrice');
+            qb.addSelect('MIN(priceWithTax)', 'minPriceWithTax').addSelect(
+                'MAX(priceWithTax)',
+                'maxPriceWithTax',
+            );
         }
         this.applyTermAndFilters(qb, input);
         if (input.term && input.term.length > this.minTermLength) {

+ 2 - 0
server/src/service/helpers/order-calculator/order-calculator.spec.ts

@@ -14,6 +14,7 @@ import { OrderItem } from '../../../entity/order-item/order-item.entity';
 import { OrderLine } from '../../../entity/order-line/order-line.entity';
 import { Order } from '../../../entity/order/order.entity';
 import { TaxCategory } from '../../../entity/tax-category/tax-category.entity';
+import { EventBus } from '../../../event-bus/event-bus';
 import { TaxRateService } from '../../services/tax-rate.service';
 import { ZoneService } from '../../services/zone.service';
 import { ListQueryBuilder } from '../list-query-builder/list-query-builder';
@@ -40,6 +41,7 @@ describe('OrderCalculator', () => {
                 { provide: Connection, useClass: MockConnection },
                 { provide: ListQueryBuilder, useValue: {} },
                 { provide: ConfigService, useClass: MockConfigService },
+                { provide: EventBus, useValue: { publish: () => ({}) } },
                 { provide: ZoneService, useValue: { findAll: () => [] } },
             ],
         }).compile();

+ 2 - 1
server/src/service/helpers/tax-calculator/tax-calculator.spec.ts

@@ -3,8 +3,8 @@ import { Connection } from 'typeorm';
 
 import { ConfigService } from '../../../config/config.service';
 import { MockConfigService } from '../../../config/config.service.mock';
-import { MergeOrdersStrategy } from '../../../config/order-merge-strategy/merge-orders-strategy';
 import { DefaultTaxCalculationStrategy } from '../../../config/tax/default-tax-calculation-strategy';
+import { EventBus } from '../../../event-bus/event-bus';
 import { TaxRateService } from '../../services/tax-rate.service';
 import { ListQueryBuilder } from '../list-query-builder/list-query-builder';
 
@@ -35,6 +35,7 @@ describe('TaxCalculator', () => {
                 { provide: ConfigService, useClass: MockConfigService },
                 { provide: Connection, useClass: MockConnection },
                 { provide: ListQueryBuilder, useValue: {} },
+                { provide: EventBus, useValue: { publish: () => ({}) } },
             ],
         }).compile();
 

+ 3 - 2
server/src/service/services/search.service.ts

@@ -1,6 +1,7 @@
 import { Injectable } from '@nestjs/common';
 
-import { LanguageCode, SearchReindexResponse } from '../../../../shared/generated-types';
+import { SearchReindexResponse } from '../../../../shared/generated-types';
+import { RequestContext } from '../../api/common/request-context';
 
 /**
  * This service should be overridden by a VendurePlugin which implements search.
@@ -15,7 +16,7 @@ import { LanguageCode, SearchReindexResponse } from '../../../../shared/generate
  */
 @Injectable()
 export class SearchService {
-    async reindex(languageCode: LanguageCode): Promise<SearchReindexResponse> {
+    async reindex(ctx: RequestContext): Promise<SearchReindexResponse> {
         if (!process.env.CI) {
             // tslint:disable-next-line:no-console
             console.warn(`The SearchService should be overridden by an appropriate search plugin.`);

+ 9 - 3
server/src/service/services/tax-rate.service.ts

@@ -3,6 +3,7 @@ import { Connection } from 'typeorm';
 
 import { CreateTaxRateInput, UpdateTaxRateInput } from '../../../../shared/generated-types';
 import { ID, PaginatedList } from '../../../../shared/shared-types';
+import { RequestContext } from '../../api/common/request-context';
 import { EntityNotFoundError } from '../../common/error/errors';
 import { ListQueryOptions } from '../../common/types/common-types';
 import { assertFound } from '../../common/utils';
@@ -10,6 +11,8 @@ import { CustomerGroup } from '../../entity/customer-group/customer-group.entity
 import { TaxCategory } from '../../entity/tax-category/tax-category.entity';
 import { TaxRate } from '../../entity/tax-rate/tax-rate.entity';
 import { Zone } from '../../entity/zone/zone.entity';
+import { EventBus } from '../../event-bus/event-bus';
+import { TaxRateModificationEvent } from '../../event-bus/events/tax-rate-modification-event';
 import { ListQueryBuilder } from '../helpers/list-query-builder/list-query-builder';
 import { getEntityOrThrow } from '../helpers/utils/get-entity-or-throw';
 import { patchEntity } from '../helpers/utils/patch-entity';
@@ -29,6 +32,7 @@ export class TaxRateService {
 
     constructor(
         @InjectConnection() private connection: Connection,
+        private eventBus: EventBus,
         private listQueryBuilder: ListQueryBuilder,
     ) {}
 
@@ -52,7 +56,7 @@ export class TaxRateService {
         });
     }
 
-    async create(input: CreateTaxRateInput): Promise<TaxRate> {
+    async create(ctx: RequestContext, input: CreateTaxRateInput): Promise<TaxRate> {
         const taxRate = new TaxRate(input);
         taxRate.category = await getEntityOrThrow(this.connection, TaxCategory, input.categoryId);
         taxRate.zone = await getEntityOrThrow(this.connection, Zone, input.zoneId);
@@ -65,10 +69,11 @@ export class TaxRateService {
         }
         const newTaxRate = await this.connection.getRepository(TaxRate).save(taxRate);
         await this.updateActiveTaxRates();
+        this.eventBus.publish(new TaxRateModificationEvent(ctx, newTaxRate));
         return assertFound(this.findOne(newTaxRate.id));
     }
 
-    async update(input: UpdateTaxRateInput): Promise<TaxRate> {
+    async update(ctx: RequestContext, input: UpdateTaxRateInput): Promise<TaxRate> {
         const taxRate = await this.findOne(input.id);
         if (!taxRate) {
             throw new EntityNotFoundError('TaxRate', input.id);
@@ -78,7 +83,7 @@ export class TaxRateService {
             updatedTaxRate.category = await getEntityOrThrow(this.connection, TaxCategory, input.categoryId);
         }
         if (input.zoneId) {
-            updatedTaxRate.category = await getEntityOrThrow(this.connection, Zone, input.zoneId);
+            updatedTaxRate.zone = await getEntityOrThrow(this.connection, Zone, input.zoneId);
         }
         if (input.customerGroupId) {
             updatedTaxRate.customerGroup = await getEntityOrThrow(
@@ -89,6 +94,7 @@ export class TaxRateService {
         }
         await this.connection.getRepository(TaxRate).save(updatedTaxRate);
         await this.updateActiveTaxRates();
+        this.eventBus.publish(new TaxRateModificationEvent(ctx, updatedTaxRate));
         return assertFound(this.findOne(taxRate.id));
     }
 

+ 5 - 1
shared/generated-shop-types.ts

@@ -1,5 +1,5 @@
 // tslint:disable
-// Generated in 2019-03-25T12:30:38+01:00
+// Generated in 2019-03-25T13:48:49+01:00
 export type Maybe<T> = T | null;
 
 export interface OrderListOptions {
@@ -1558,6 +1558,8 @@ export interface SearchResult {
 
     price: SearchResultPrice;
 
+    priceWithTax: SearchResultPrice;
+
     currencyCode: CurrencyCode;
 
     description: string;
@@ -1571,12 +1573,14 @@ export interface SearchResult {
     score: number;
 }
 
+/** The price range where the result has more than one price */
 export interface PriceRange {
     min: number;
 
     max: number;
 }
 
+/** The price value where the result has a single price */
 export interface SinglePrice {
     value: number;
 }

+ 5 - 3
shared/generated-types.ts

@@ -1,5 +1,5 @@
 // tslint:disable
-// Generated in 2019-03-25T12:30:39+01:00
+// Generated in 2019-03-25T13:48:50+01:00
 export type Maybe<T> = T | null;
 
 
@@ -5456,6 +5456,8 @@ export interface SearchResult {
   
   price: SearchResultPrice;
   
+  priceWithTax: SearchResultPrice;
+  
   currencyCode: CurrencyCode;
   
   description: string;
@@ -5469,7 +5471,7 @@ export interface SearchResult {
   score: number;
 }
 
-
+/** The price range where the result has more than one price */
 export interface PriceRange {
   
   min: number;
@@ -5477,7 +5479,7 @@ export interface PriceRange {
   max: number;
 }
 
-
+/** The price value where the result has a single price */
 export interface SinglePrice {
   
   value: number;

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini