Просмотр исходного кода

feat: Implement TaxRate API & admin ui

Michael Bromley 7 лет назад
Родитель
Сommit
4df0ed8969
30 измененных файлов с 954 добавлено и 17 удалено
  1. 1 1
      admin-ui/src/app/catalog/components/product-detail/product-detail.component.html
  2. 1 1
      admin-ui/src/app/catalog/components/product-detail/product-detail.component.ts
  3. 8 1
      admin-ui/src/app/core/components/main-nav/main-nav.component.html
  4. 60 0
      admin-ui/src/app/data/definitions/settings-definitions.ts
  5. 4 0
      admin-ui/src/app/data/providers/data.service.mock.ts
  6. 37 0
      admin-ui/src/app/data/providers/settings-data.service.ts
  7. 10 4
      admin-ui/src/app/settings/components/tax-category-detail/tax-category-detail.component.ts
  8. 49 0
      admin-ui/src/app/settings/components/tax-rate-detail/tax-rate-detail.component.html
  9. 0 0
      admin-ui/src/app/settings/components/tax-rate-detail/tax-rate-detail.component.scss
  10. 151 0
      admin-ui/src/app/settings/components/tax-rate-detail/tax-rate-detail.component.ts
  11. 35 0
      admin-ui/src/app/settings/components/tax-rate-list/tax-rate-list.component.html
  12. 0 0
      admin-ui/src/app/settings/components/tax-rate-list/tax-rate-list.component.scss
  13. 22 0
      admin-ui/src/app/settings/components/tax-rate-list/tax-rate-list.component.ts
  14. 26 0
      admin-ui/src/app/settings/providers/routing/tax-rate-resolver.ts
  15. 6 1
      admin-ui/src/app/settings/settings.module.ts
  16. 30 2
      admin-ui/src/app/settings/settings.routes.ts
  17. 7 3
      admin-ui/src/i18n-messages/en.json
  18. 0 0
      schema.json
  19. 2 0
      server/src/api/api.module.ts
  20. 44 0
      server/src/api/resolvers/tax-rate.resolver.ts
  21. 39 0
      server/src/api/types/tax-rate.api.graphql
  22. 1 2
      server/src/entity/order-item/order-item.entity.ts
  23. 2 0
      server/src/entity/role/role.graphql
  24. 2 0
      server/src/entity/tax-category/tax-category.graphql
  25. 3 1
      server/src/entity/tax-rate/tax-rate.entity.ts
  26. 30 0
      server/src/entity/tax-rate/tax-rate.graphql
  27. 5 1
      server/src/service/providers/order.service.ts
  28. 98 0
      server/src/service/providers/tax-rate.service.ts
  29. 2 0
      server/src/service/service.module.ts
  30. 279 0
      shared/generated-types.ts

+ 1 - 1
admin-ui/src/app/catalog/components/product-detail/product-detail.component.html

@@ -74,7 +74,7 @@
                                        [productVariantsFormArray]="productForm.get('variants')"
                                        [taxCategories]="taxCategories$ | async"
                                        #productVariantsList>
-                <button class="btn btn-sm btn-secondary" (click)="selectFacetValue(productVariantsList.selectedCountryIds)">
+                <button class="btn btn-sm btn-secondary" (click)="selectFacetValue(productVariantsList.selectedVariantIds)">
                     {{ 'catalog.apply-facets' | translate }}
                 </button>
             </vdr-product-variants-list>

+ 1 - 1
admin-ui/src/app/catalog/components/product-detail/product-detail.component.ts

@@ -34,7 +34,7 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
     implements OnInit, OnDestroy {
     product$: Observable<ProductWithVariants.Fragment>;
     variants$: Observable<ProductWithVariants.Variants[]>;
-    taxCategories$: Observable<TaxCategory[]>;
+    taxCategories$: Observable<TaxCategory.Fragment[]>;
     customFields: CustomFieldConfig[];
     customVariantFields: CustomFieldConfig[];
     productForm: FormGroup;

+ 8 - 1
admin-ui/src/app/core/components/main-nav/main-nav.component.html

@@ -79,7 +79,14 @@
                     <a class="nav-link"
                        [routerLink]="['/settings', 'tax-categories']"
                        routerLinkActive="active">
-                        <clr-icon shape="calculator" size="20"></clr-icon>{{ 'nav.tax-categories' | translate }}
+                        <clr-icon shape="view-list" size="20"></clr-icon>{{ 'nav.tax-categories' | translate }}
+                    </a>
+                </li>
+                <li>
+                    <a class="nav-link"
+                       [routerLink]="['/settings', 'tax-rates']"
+                       routerLinkActive="active">
+                        <clr-icon shape="calculator" size="20"></clr-icon>{{ 'nav.tax-rates' | translate }}
                     </a>
                 </li>
                 <li>

+ 60 - 0
admin-ui/src/app/data/definitions/settings-definitions.ts

@@ -155,3 +155,63 @@ export const UPDATE_TAX_CATEGORY = gql`
     }
     ${TAX_CATEGORY_FRAGMENT}
 `;
+
+export const TAX_RATE_FRAGMENT = gql`
+    fragment TaxRate on TaxRate {
+        id
+        name
+        enabled
+        value
+        category {
+            id
+            name
+        }
+        zone {
+            id
+            name
+        }
+        customerGroup {
+            id
+            name
+        }
+    }
+`;
+
+export const GET_TAX_RATE_LIST = gql`
+    query GetTaxRateList($options: TaxRateListOptions) {
+        taxRates(options: $options) {
+            items {
+                ...TaxRate
+            }
+            totalItems
+        }
+    }
+    ${TAX_RATE_FRAGMENT}
+`;
+
+export const GET_TAX_RATE = gql`
+    query GetTaxRate($id: ID!) {
+        taxRate(id: $id) {
+            ...TaxRate
+        }
+    }
+    ${TAX_RATE_FRAGMENT}
+`;
+
+export const CREATE_TAX_RATE = gql`
+    mutation CreateTaxRate($input: CreateTaxRateInput!) {
+        createTaxRate(input: $input) {
+            ...TaxRate
+        }
+    }
+    ${TAX_RATE_FRAGMENT}
+`;
+
+export const UPDATE_TAX_RATE = gql`
+    mutation UpdateTaxRate($input: UpdateTaxRateInput!) {
+        updateTaxRate(input: $input) {
+            ...TaxRate
+        }
+    }
+    ${TAX_RATE_FRAGMENT}
+`;

+ 4 - 0
admin-ui/src/app/data/providers/data.service.mock.ts

@@ -103,5 +103,9 @@ export class MockDataService implements DataServiceMock {
         getTaxCategory: spyQueryResult('getTaxCategory'),
         createTaxCategory: spyObservable('createTaxCategory'),
         updateTaxCategory: spyObservable('updateTaxCategory'),
+        getTaxRates: spyQueryResult('getTaxRates'),
+        getTaxRate: spyQueryResult('getTaxRate'),
+        createTaxRate: spyObservable('createTaxRate'),
+        updateTaxRate: spyObservable('updateTaxRate'),
     };
 }

+ 37 - 0
admin-ui/src/app/data/providers/settings-data.service.ts

@@ -4,12 +4,16 @@ import {
     CreateCountryInput,
     CreateTaxCategory,
     CreateTaxCategoryInput,
+    CreateTaxRate,
+    CreateTaxRateInput,
     CreateZone,
     CreateZoneInput,
     GetCountry,
     GetCountryList,
     GetTaxCategories,
     GetTaxCategory,
+    GetTaxRate,
+    GetTaxRateList,
     GetZone,
     GetZones,
     RemoveMembersFromZone,
@@ -17,6 +21,8 @@ import {
     UpdateCountryInput,
     UpdateTaxCategory,
     UpdateTaxCategoryInput,
+    UpdateTaxRate,
+    UpdateTaxRateInput,
     UpdateZone,
     UpdateZoneInput,
 } from 'shared/generated-types';
@@ -25,15 +31,19 @@ import {
     ADD_MEMBERS_TO_ZONE,
     CREATE_COUNTRY,
     CREATE_TAX_CATEGORY,
+    CREATE_TAX_RATE,
     CREATE_ZONE,
     GET_COUNTRY,
     GET_COUNTRY_LIST,
     GET_TAX_CATEGORIES,
     GET_TAX_CATEGORY,
+    GET_TAX_RATE,
+    GET_TAX_RATE_LIST,
     GET_ZONES,
     REMOVE_MEMBERS_FROM_ZONE,
     UPDATE_COUNTRY,
     UPDATE_TAX_CATEGORY,
+    UPDATE_TAX_RATE,
     UPDATE_ZONE,
 } from '../definitions/settings-definitions';
 
@@ -134,4 +144,31 @@ export class SettingsDataService {
             },
         );
     }
+
+    getTaxRates(take: number = 10, skip: number = 0) {
+        return this.baseDataService.query<GetTaxRateList.Query, GetTaxRateList.Variables>(GET_TAX_RATE_LIST, {
+            options: {
+                take,
+                skip,
+            },
+        });
+    }
+
+    getTaxRate(id: string) {
+        return this.baseDataService.query<GetTaxRate.Query, GetTaxRate.Variables>(GET_TAX_RATE, {
+            id,
+        });
+    }
+
+    createTaxRate(input: CreateTaxRateInput) {
+        return this.baseDataService.mutate<CreateTaxRate.Mutation, CreateTaxRate.Variables>(CREATE_TAX_RATE, {
+            input,
+        });
+    }
+
+    updateTaxRate(input: UpdateTaxRateInput) {
+        return this.baseDataService.mutate<UpdateTaxRate.Mutation, UpdateTaxRate.Variables>(UPDATE_TAX_RATE, {
+            input,
+        });
+    }
 }

+ 10 - 4
admin-ui/src/app/settings/components/tax-category-detail/tax-category-detail.component.ts

@@ -3,7 +3,13 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { Observable } from 'rxjs';
 import { mergeMap, take } from 'rxjs/operators';
-import { AdjustmentOperation, LanguageCode, TaxCategory } from 'shared/generated-types';
+import {
+    AdjustmentOperation,
+    CreateTaxCategoryInput,
+    LanguageCode,
+    TaxCategory,
+    UpdateTaxCategoryInput,
+} from 'shared/generated-types';
 
 import { BaseDetailComponent } from '../../../common/base-detail.component';
 import { _ } from '../../../core/providers/i18n/mark-for-extraction';
@@ -59,7 +65,7 @@ export class TaxCategoryDetailComponent extends BaseDetailComponent<TaxCategory.
             return;
         }
         const formValue = this.taxCategoryForm.value;
-        const input = { name: formValue.name };
+        const input = { name: formValue.name } as CreateTaxCategoryInput;
         this.dataService.settings.createTaxCategory(input).subscribe(
             data => {
                 this.notificationService.success(_('common.notify-create-success'), {
@@ -88,8 +94,8 @@ export class TaxCategoryDetailComponent extends BaseDetailComponent<TaxCategory.
                 mergeMap(taxCategory => {
                     const input = {
                         id: taxCategory.id,
-                        nadme: formValue.name,
-                    };
+                        name: formValue.name,
+                    } as UpdateTaxCategoryInput;
                     return this.dataService.settings.updateTaxCategory(input);
                 }),
             )

+ 49 - 0
admin-ui/src/app/settings/components/tax-rate-detail/tax-rate-detail.component.html

@@ -0,0 +1,49 @@
+<vdr-action-bar>
+    <vdr-ab-left>
+    </vdr-ab-left>
+
+    <vdr-ab-right>
+        <button class="btn btn-primary"
+                *ngIf="isNew$ | async; else updateButton"
+                (click)="create()"
+                [disabled]="!saveButtonEnabled()">{{ 'common.create' | translate }}</button>
+        <ng-template #updateButton>
+            <button class="btn btn-primary"
+                    (click)="save()"
+                    [disabled]="!saveButtonEnabled()">{{ 'common.update' | translate }}</button>
+        </ng-template>
+    </vdr-ab-right>
+</vdr-action-bar>
+
+<form class="form" [formGroup]="taxRateForm" >
+    <section class="form-block">
+        <vdr-form-field [label]="'common.name' | translate" for="name">
+            <input id="name" type="text" formControlName="name">
+        </vdr-form-field>
+        <vdr-form-field [label]="'common.enabled' | translate" for="enabled">
+            <div class="toggle-switch">
+                <input type="checkbox" id="enabled" formControlName="enabled">
+                <label for="enabled"></label>
+            </div>
+        </vdr-form-field>
+        <vdr-form-field [label]="'settings.rate' | translate" for="value">
+            <vdr-affixed-input suffix="%">
+                <input id="value" type="number" step="0.1" formControlName="value">
+            </vdr-affixed-input>
+        </vdr-form-field>
+        <vdr-form-field [label]="'settings.tax-category' | translate" for="taxCategoryId">
+            <select clrSelect name="taxCategoryId"
+                    formControlName="taxCategoryId">
+                <option *ngFor="let taxCategory of taxCategories$ | async"
+                        [value]="taxCategory.id">{{ taxCategory.name }}</option>
+            </select>
+        </vdr-form-field>
+        <vdr-form-field [label]="'settings.zone' | translate" for="zoneId">
+            <select clrSelect name="zoneId"
+                    formControlName="zoneId">
+                <option *ngFor="let zone of zones$ | async"
+                        [value]="zone.id">{{ zone.name }}</option>
+            </select>
+        </vdr-form-field>
+    </section>
+</form>

+ 0 - 0
admin-ui/src/app/settings/components/tax-rate-detail/tax-rate-detail.component.scss


+ 151 - 0
admin-ui/src/app/settings/components/tax-rate-detail/tax-rate-detail.component.ts

@@ -0,0 +1,151 @@
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
+import { Observable } from 'rxjs';
+import { mergeMap, take } from 'rxjs/operators';
+import {
+    CreateTaxRateInput,
+    CustomerGroup,
+    LanguageCode,
+    TaxCategory,
+    TaxRate,
+    UpdateTaxRateInput,
+    Zone,
+} from 'shared/generated-types';
+
+import { BaseDetailComponent } from '../../../common/base-detail.component';
+import { _ } from '../../../core/providers/i18n/mark-for-extraction';
+import { NotificationService } from '../../../core/providers/notification/notification.service';
+import { DataService } from '../../../data/providers/data.service';
+import { ServerConfigService } from '../../../data/server-config';
+
+@Component({
+    selector: 'vdr-tax-rate-detail',
+    templateUrl: './tax-rate-detail.component.html',
+    styleUrls: ['./tax-rate-detail.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class TaxRateDetailComponent extends BaseDetailComponent<TaxRate.Fragment>
+    implements OnInit, OnDestroy {
+    taxCategories$: Observable<TaxCategory.Fragment[]>;
+    zones$: Observable<Zone.Fragment[]>;
+    groups$: Observable<CustomerGroup[]>;
+    taxRateForm: FormGroup;
+
+    constructor(
+        router: Router,
+        route: ActivatedRoute,
+        serverConfigService: ServerConfigService,
+        private changeDetector: ChangeDetectorRef,
+        private dataService: DataService,
+        private formBuilder: FormBuilder,
+        private notificationService: NotificationService,
+    ) {
+        super(route, router, serverConfigService);
+        this.taxRateForm = this.formBuilder.group({
+            name: ['', Validators.required],
+            enabled: [true],
+            value: [0, Validators.required],
+            taxCategoryId: [''],
+            zoneId: [''],
+            customerGroupId: [''],
+        });
+    }
+
+    ngOnInit() {
+        this.init();
+        this.taxCategories$ = this.dataService.settings
+            .getTaxCategories()
+            .mapSingle(data => data.taxCategories);
+        this.zones$ = this.dataService.settings.getZones().mapSingle(data => data.zones);
+    }
+
+    ngOnDestroy() {
+        this.destroy();
+    }
+
+    saveButtonEnabled(): boolean {
+        return this.taxRateForm.dirty && this.taxRateForm.valid;
+    }
+
+    create() {
+        if (!this.taxRateForm.dirty) {
+            return;
+        }
+        const formValue = this.taxRateForm.value;
+        const input = {
+            name: formValue.name,
+            enabled: formValue.enabled,
+            value: formValue.value,
+            categoryId: formValue.taxCategoryId,
+            zoneId: formValue.zoneId,
+            customerGroupId: formValue.customerGroupId,
+        } as CreateTaxRateInput;
+        this.dataService.settings.createTaxRate(input).subscribe(
+            data => {
+                this.notificationService.success(_('common.notify-create-success'), {
+                    entity: 'TaxRate',
+                });
+                this.taxRateForm.markAsPristine();
+                this.changeDetector.markForCheck();
+                this.router.navigate(['../', data.createTaxRate.id], { relativeTo: this.route });
+            },
+            err => {
+                this.notificationService.error(_('common.notify-create-error'), {
+                    entity: 'TaxRate',
+                });
+            },
+        );
+    }
+
+    save() {
+        if (!this.taxRateForm.dirty) {
+            return;
+        }
+        const formValue = this.taxRateForm.value;
+        this.entity$
+            .pipe(
+                take(1),
+                mergeMap(taxRate => {
+                    const input = {
+                        id: taxRate.id,
+                        name: formValue.name,
+                        enabled: formValue.enabled,
+                        value: formValue.value,
+                        categoryId: formValue.taxCategoryId,
+                        zoneId: formValue.zoneId,
+                        customerGroupId: formValue.customerGroupId,
+                    } as UpdateTaxRateInput;
+                    return this.dataService.settings.updateTaxRate(input);
+                }),
+            )
+            .subscribe(
+                data => {
+                    this.notificationService.success(_('common.notify-update-success'), {
+                        entity: 'TaxRate',
+                    });
+                    this.taxRateForm.markAsPristine();
+                    this.changeDetector.markForCheck();
+                },
+                err => {
+                    this.notificationService.error(_('common.notify-update-error'), {
+                        entity: 'TaxRate',
+                    });
+                },
+            );
+    }
+
+    /**
+     * Update the form values when the entity changes.
+     */
+    protected setFormValues(entity: TaxRate.Fragment, languageCode: LanguageCode): void {
+        this.taxRateForm.patchValue({
+            name: entity.name,
+            enabled: entity.enabled,
+            value: entity.value,
+            taxCategoryId: entity.category ? entity.category.id : '',
+            zoneId: entity.zone ? entity.zone.id : '',
+            customerGroupId: entity.customerGroup ? entity.customerGroup.id : '',
+        });
+    }
+}

+ 35 - 0
admin-ui/src/app/settings/components/tax-rate-list/tax-rate-list.component.html

@@ -0,0 +1,35 @@
+<vdr-action-bar>
+    <vdr-ab-right>
+        <a class="btn btn-primary" [routerLink]="['./create']">
+            <clr-icon shape="plus"></clr-icon>
+            {{ 'settings.create-new-tax-rate' | translate }}
+        </a>
+    </vdr-ab-right>
+</vdr-action-bar>
+
+<vdr-data-table [items]="items$ | async"
+                [itemsPerPage]="itemsPerPage$ | async"
+                [totalItems]="totalItems$ | async"
+                [currentPage]="currentPage$ | async"
+                (pageChange)="setPageNumber($event)"
+                (itemsPerPageChange)="setItemsPerPage($event)">
+    <vdr-dt-column>{{ 'common.ID' | translate }}</vdr-dt-column>
+    <vdr-dt-column>{{ 'common.name' | translate }}</vdr-dt-column>
+    <vdr-dt-column>{{ 'settings.tax-category' | translate }}</vdr-dt-column>
+    <vdr-dt-column>{{ 'settings.zone' | translate }}</vdr-dt-column>
+    <vdr-dt-column>{{ 'settings.tax-rate' | translate }}</vdr-dt-column>
+    <vdr-dt-column></vdr-dt-column>
+    <ng-template let-taxRate="item">
+        <td class="left">{{ taxRate.id }}</td>
+        <td class="left">{{ taxRate.name }}</td>
+        <td class="left">{{ taxRate.category.name }}</td>
+        <td class="left">{{ taxRate.zone.name }}</td>
+        <td class="left">{{ taxRate.value }}%</td>
+        <td class="right">
+            <vdr-table-row-action iconShape="edit"
+                                  [label]="'common.edit' | translate"
+                                  [linkTo]="['./', taxRate.id]">
+            </vdr-table-row-action>
+        </td>
+    </ng-template>
+</vdr-data-table>

+ 0 - 0
admin-ui/src/app/settings/components/tax-rate-list/tax-rate-list.component.scss


+ 22 - 0
admin-ui/src/app/settings/components/tax-rate-list/tax-rate-list.component.ts

@@ -0,0 +1,22 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { GetTaxRateList } from 'shared/generated-types';
+
+import { BaseListComponent } from '../../../common/base-list.component';
+import { DataService } from '../../../data/providers/data.service';
+
+@Component({
+    selector: 'vdr-tax-rate-list',
+    templateUrl: './tax-rate-list.component.html',
+    styleUrls: ['./tax-rate-list.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class TaxRateListComponent extends BaseListComponent<GetTaxRateList.Query, GetTaxRateList.Items> {
+    constructor(private dataService: DataService, router: Router, route: ActivatedRoute) {
+        super(router, route);
+        super.setQueryFn(
+            (...args: any[]) => this.dataService.settings.getTaxRates(...args),
+            data => data.taxRates,
+        );
+    }
+}

+ 26 - 0
admin-ui/src/app/settings/providers/routing/tax-rate-resolver.ts

@@ -0,0 +1,26 @@
+import { Injectable } from '@angular/core';
+import { TaxRate } from 'shared/generated-types';
+
+import { BaseEntityResolver } from '../../../common/base-entity-resolver';
+import { DataService } from '../../../data/providers/data.service';
+
+/**
+ * Resolves the id from the path into a Customer entity.
+ */
+@Injectable()
+export class TaxRateResolver extends BaseEntityResolver<TaxRate.Fragment> {
+    constructor(private dataService: DataService) {
+        super(
+            {
+                __typename: 'TaxRate',
+                id: '',
+                name: '',
+                value: 0,
+                enabled: true,
+                category: {} as any,
+                zone: {} as any,
+            },
+            id => this.dataService.settings.getTaxRate(id).mapStream(data => data.taxRate),
+        );
+    }
+}

+ 6 - 1
admin-ui/src/app/settings/settings.module.ts

@@ -12,11 +12,14 @@ import { RoleDetailComponent } from './components/role-detail/role-detail.compon
 import { RoleListComponent } from './components/role-list/role-list.component';
 import { TaxCategoryDetailComponent } from './components/tax-category-detail/tax-category-detail.component';
 import { TaxCategoryListComponent } from './components/tax-category-list/tax-category-list.component';
+import { TaxRateDetailComponent } from './components/tax-rate-detail/tax-rate-detail.component';
+import { TaxRateListComponent } from './components/tax-rate-list/tax-rate-list.component';
 import { ZoneSelectorDialogComponent } from './components/zone-selector-dialog/zone-selector-dialog.component';
 import { AdministratorResolver } from './providers/routing/administrator-resolver';
 import { CountryResolver } from './providers/routing/country-resolver';
 import { RoleResolver } from './providers/routing/role-resolver';
 import { TaxCategoryResolver } from './providers/routing/tax-category-resolver';
+import { TaxRateResolver } from './providers/routing/tax-rate-resolver';
 import { settingsRoutes } from './settings.routes';
 
 @NgModule({
@@ -32,8 +35,10 @@ import { settingsRoutes } from './settings.routes';
         CountryListComponent,
         CountryDetailComponent,
         ZoneSelectorDialogComponent,
+        TaxRateListComponent,
+        TaxRateDetailComponent,
     ],
     entryComponents: [ZoneSelectorDialogComponent],
-    providers: [TaxCategoryResolver, AdministratorResolver, RoleResolver, CountryResolver],
+    providers: [TaxCategoryResolver, AdministratorResolver, RoleResolver, CountryResolver, TaxRateResolver],
 })
 export class SettingsModule {}

+ 30 - 2
admin-ui/src/app/settings/settings.routes.ts

@@ -1,5 +1,5 @@
 import { Route } from '@angular/router';
-import { Administrator, Country, GetCountry, Role, TaxCategory } from 'shared/generated-types';
+import { Administrator, Country, GetCountry, Role, TaxCategory, TaxRate } from 'shared/generated-types';
 
 import { createResolveData } from '../common/base-entity-resolver';
 import { detailBreadcrumb } from '../common/detail-breadcrumb';
@@ -13,10 +13,13 @@ import { RoleDetailComponent } from './components/role-detail/role-detail.compon
 import { RoleListComponent } from './components/role-list/role-list.component';
 import { TaxCategoryDetailComponent } from './components/tax-category-detail/tax-category-detail.component';
 import { TaxCategoryListComponent } from './components/tax-category-list/tax-category-list.component';
+import { TaxRateDetailComponent } from './components/tax-rate-detail/tax-rate-detail.component';
+import { TaxRateListComponent } from './components/tax-rate-list/tax-rate-list.component';
 import { AdministratorResolver } from './providers/routing/administrator-resolver';
 import { CountryResolver } from './providers/routing/country-resolver';
 import { RoleResolver } from './providers/routing/role-resolver';
 import { TaxCategoryResolver } from './providers/routing/tax-category-resolver';
+import { TaxRateResolver } from './providers/routing/tax-rate-resolver';
 
 export const settingsRoutes: Route[] = [
     {
@@ -60,6 +63,21 @@ export const settingsRoutes: Route[] = [
             breadcrumb: taxCategoryBreadcrumb,
         },
     },
+    {
+        path: 'tax-rates',
+        component: TaxRateListComponent,
+        data: {
+            breadcrumb: _('breadcrumb.tax-rates'),
+        },
+    },
+    {
+        path: 'tax-rates/:id',
+        component: TaxRateDetailComponent,
+        resolve: createResolveData(TaxRateResolver),
+        data: {
+            breadcrumb: taxRateBreadcrumb,
+        },
+    },
     {
         path: 'countries',
         component: CountryListComponent,
@@ -102,11 +120,21 @@ export function taxCategoryBreadcrumb(data: any, params: any) {
         entity: data.entity,
         id: params.id,
         breadcrumbKey: 'breadcrumb.tax-categories',
-        getName: promotion => promotion.name,
+        getName: category => category.name,
         route: 'tax-categories',
     });
 }
 
+export function taxRateBreadcrumb(data: any, params: any) {
+    return detailBreadcrumb<TaxRate.Fragment>({
+        entity: data.entity,
+        id: params.id,
+        breadcrumbKey: 'breadcrumb.tax-rates',
+        getName: category => category.name,
+        route: 'tax-rates',
+    });
+}
+
 export function countryBreadcrumb(data: any, params: any) {
     return detailBreadcrumb<Country.Fragment>({
         entity: data.entity,

+ 7 - 3
admin-ui/src/i18n-messages/en.json

@@ -12,7 +12,8 @@
     "products": "Products",
     "promotions": "Promotions",
     "roles": "Roles",
-    "tax-categories": "Tax categories"
+    "tax-categories": "Tax categories",
+    "tax-rates": ""
   },
   "catalog": {
     "add-asset": "Add asset",
@@ -46,7 +47,6 @@
     "option-group-options-tooltip": "Enter each option on a new line in the default language ({ defaultLanguage })",
     "original-asset-size": "Source size",
     "price": "Price",
-    "price-before-tax": "Price before tax",
     "product": "Product",
     "product-name": "Product name",
     "product-option-groups": "Option groups",
@@ -122,7 +122,8 @@
     "roles": "Roles",
     "sales": "Sales",
     "settings": "Settings",
-    "tax-categories": "Tax categories"
+    "tax-categories": "Tax categories",
+    "tax-rates": "Tax Rates"
   },
   "order": {
     "create-new-order": "Create new order"
@@ -136,6 +137,7 @@
     "create-new-country": "Create new country",
     "create-new-role": "Create new role",
     "create-new-tax-category": "Create tax category",
+    "create-new-tax-rate": "Create new tax rate",
     "create-zone": "Create zone",
     "customer": "Customer",
     "delete": "Delete",
@@ -146,6 +148,7 @@
     "order": "Order",
     "password": "Password",
     "permissions": "Permissions",
+    "rate": "Rate",
     "read": "Read",
     "remove-countries-from-zone": "Remove countries from zone...",
     "remove-countries-from-zone-success": "Removed { countryCount } {countryCount, plural, one {country} other {countries}} from zone \"{ zoneName }\"",
@@ -153,6 +156,7 @@
     "roles": "Roles",
     "section": "Section",
     "select-zone": "Select zone",
+    "tax-category": "Tax category",
     "tax-rate": "Tax rate",
     "update": "Update",
     "zone": "Zone"

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
schema.json


+ 2 - 0
server/src/api/api.module.ts

@@ -27,6 +27,7 @@ import { ProductResolver } from './resolvers/product.resolver';
 import { PromotionResolver } from './resolvers/promotion.resolver';
 import { RoleResolver } from './resolvers/role.resolver';
 import { TaxCategoryResolver } from './resolvers/tax-category.resolver';
+import { TaxRateResolver } from './resolvers/tax-rate.resolver';
 import { ZoneResolver } from './resolvers/zone.resolver';
 
 const exportedProviders = [
@@ -45,6 +46,7 @@ const exportedProviders = [
     ProductResolver,
     RoleResolver,
     TaxCategoryResolver,
+    TaxRateResolver,
     ZoneResolver,
 ];
 

+ 44 - 0
server/src/api/resolvers/tax-rate.resolver.ts

@@ -0,0 +1,44 @@
+import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
+import {
+    CreateTaxRateMutationArgs,
+    Permission,
+    TaxRateQueryArgs,
+    TaxRatesQueryArgs,
+    UpdateTaxRateMutationArgs,
+} from 'shared/generated-types';
+import { PaginatedList } from 'shared/shared-types';
+
+import { TaxRate } from '../../entity/tax-rate/tax-rate.entity';
+import { TaxRateService } from '../../service/providers/tax-rate.service';
+import { Allow } from '../common/auth-guard';
+import { RequestContext } from '../common/request-context';
+import { Ctx } from '../common/request-context.decorator';
+
+@Resolver('TaxRate')
+export class TaxRateResolver {
+    constructor(private taxRateService: TaxRateService) {}
+
+    @Query()
+    @Allow(Permission.ReadSettings)
+    taxRates(@Ctx() ctx: RequestContext, @Args() args: TaxRatesQueryArgs): Promise<PaginatedList<TaxRate>> {
+        return this.taxRateService.findAll(args.options || undefined);
+    }
+
+    @Query()
+    @Allow(Permission.ReadSettings)
+    async taxRate(@Ctx() ctx: RequestContext, @Args() args: TaxRateQueryArgs): Promise<TaxRate | undefined> {
+        return this.taxRateService.findOne(args.id);
+    }
+
+    @Mutation()
+    @Allow(Permission.CreateSettings)
+    async createTaxRate(@Args() args: CreateTaxRateMutationArgs): Promise<TaxRate> {
+        return this.taxRateService.create(args.input);
+    }
+
+    @Mutation()
+    @Allow(Permission.UpdateSettings)
+    async updateTaxRate(@Args() args: UpdateTaxRateMutationArgs): Promise<TaxRate> {
+        return this.taxRateService.update(args.input);
+    }
+}

+ 39 - 0
server/src/api/types/tax-rate.api.graphql

@@ -0,0 +1,39 @@
+type Query {
+  taxRates(options: TaxRateListOptions): TaxRateList!
+  taxRate(id: ID!): TaxRate
+}
+
+type Mutation {
+  "Create a new TaxRate"
+  createTaxRate(input: CreateTaxRateInput!): TaxRate!
+  "Update an existing TaxRate"
+  updateTaxRate(input: UpdateTaxRateInput!): TaxRate!
+}
+
+type TaxRateList implements PaginatedList {
+    items: [TaxRate!]!
+    totalItems: Int!
+}
+
+input TaxRateListOptions {
+    take: Int
+    skip: Int
+    sort: TaxRateSortParameter
+    filter: TaxRateFilterParameter
+}
+
+input TaxRateSortParameter {
+    id: SortOrder
+    createdAt: SortOrder
+    updatedAt: SortOrder
+    name: SortOrder
+    enabled: SortOrder
+}
+
+input TaxRateFilterParameter {
+    code: StringOperators
+    name: StringOperators
+    enabled: BooleanOperators
+    createdAt: DateOperators
+    updatedAt: DateOperators
+}

+ 1 - 2
server/src/entity/order-item/order-item.entity.ts

@@ -14,6 +14,5 @@ export class OrderItem extends VendureEntity {
     @ManyToOne(type => OrderLine, line => line.items)
     line: OrderLine;
 
-    /*@Column('simple-json')
-    pendingAdjustments: Adjustment[];*/
+    @Column('simple-json') pendingAdjustments: Adjustment[];
 }

+ 2 - 0
server/src/entity/role/role.graphql

@@ -1,5 +1,7 @@
 type Role implements Node {
     id: ID!
+    createdAt: DateTime!
+    updatedAt: DateTime!
     code: String!
     description: String!
     permissions: [Permission!]!

+ 2 - 0
server/src/entity/tax-category/tax-category.graphql

@@ -1,5 +1,7 @@
 type TaxCategory implements Node {
     id: ID!
+    createdAt: DateTime!
+    updatedAt: DateTime!
     name: String!
 }
 

+ 3 - 1
server/src/entity/tax-rate/tax-rate.entity.ts

@@ -1,4 +1,4 @@
-import { AdjustmentOperation, AdjustmentType } from 'shared/generated-types';
+import { AdjustmentOperation } from 'shared/generated-types';
 import { DeepPartial } from 'shared/shared-types';
 import { Column, Entity, JoinTable, ManyToMany, ManyToOne } from 'typeorm';
 
@@ -19,6 +19,8 @@ export class TaxRate extends VendureEntity implements AdjustmentSource {
 
     @Column() enabled: boolean;
 
+    @Column() value: number;
+
     @ManyToOne(type => TaxCategory)
     category: TaxCategory;
 

+ 30 - 0
server/src/entity/tax-rate/tax-rate.graphql

@@ -0,0 +1,30 @@
+type TaxRate implements Node {
+    id: ID!
+    createdAt: DateTime!
+    updatedAt: DateTime!
+    name: String!
+    enabled: Boolean!
+    value: Int!
+    category: TaxCategory!
+    zone: Zone!
+    customerGroup: CustomerGroup
+}
+
+input CreateTaxRateInput {
+    name: String!
+    enabled: Boolean!
+    value: Int!
+    categoryId: ID!
+    zoneId: ID!
+    customerGroupId: ID
+}
+
+input UpdateTaxRateInput {
+    id: ID!
+    name: String
+    value: Int
+    enabled: Boolean
+    categoryId: ID
+    zoneId: ID
+    customerGroupId: ID
+}

+ 5 - 1
server/src/service/providers/order.service.ts

@@ -96,7 +96,11 @@ export class OrderService {
                 orderLine.items = [];
             }
             for (let i = currentQuantity; i < quantity; i++) {
-                const orderItem = await this.connection.getRepository(OrderItem).save(new OrderItem());
+                const orderItem = await this.connection.getRepository(OrderItem).save(
+                    new OrderItem({
+                        pendingAdjustments: [],
+                    }),
+                );
                 orderLine.items.push(orderItem);
             }
         } else if (quantity < currentQuantity) {

+ 98 - 0
server/src/service/providers/tax-rate.service.ts

@@ -0,0 +1,98 @@
+import { InjectConnection } from '@nestjs/typeorm';
+import { CreateTaxRateInput, UpdateTaxRateInput } from 'shared/generated-types';
+import { ID, PaginatedList } from 'shared/shared-types';
+import { Connection } from 'typeorm';
+
+import { ListQueryOptions } from '../../common/types/common-types';
+import { assertFound } from '../../common/utils';
+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 { I18nError } from '../../i18n/i18n-error';
+import { buildListQuery } from '../helpers/build-list-query';
+import { patchEntity } from '../helpers/patch-entity';
+
+export class TaxRateService {
+    constructor(@InjectConnection() private connection: Connection) {}
+
+    findAll(options?: ListQueryOptions<TaxRate>): Promise<PaginatedList<TaxRate>> {
+        return buildListQuery(this.connection, TaxRate, options, ['category', 'zone', 'customerGroup'])
+            .getManyAndCount()
+            .then(([items, totalItems]) => ({
+                items,
+                totalItems,
+            }));
+    }
+
+    findOne(taxRateId: ID): Promise<TaxRate | undefined> {
+        return this.connection.manager.findOne(TaxRate, taxRateId, {
+            relations: ['category', 'zone', 'customerGroup'],
+        });
+    }
+    async create(input: CreateTaxRateInput): Promise<TaxRate> {
+        const taxRate = new TaxRate(input);
+        taxRate.category = await this.getTaxCategoryOrThrow(input.categoryId);
+        taxRate.zone = await this.getZoneOrThrow(input.zoneId);
+        if (input.customerGroupId) {
+            taxRate.customerGroup = await this.getCustomerGroupOrThrow(input.customerGroupId);
+        }
+        const newTaxRate = await this.connection.getRepository(TaxRate).save(taxRate);
+        return assertFound(this.findOne(newTaxRate.id));
+    }
+
+    async update(input: UpdateTaxRateInput): Promise<TaxRate> {
+        const taxRate = await this.findOne(input.id);
+        if (!taxRate) {
+            throw new I18nError(`error.entity-with-id-not-found`, {
+                entityName: 'TaxRate',
+                id: input.id,
+            });
+        }
+        const updatedTaxRate = patchEntity(taxRate, input);
+        if (input.categoryId) {
+            taxRate.category = await this.getTaxCategoryOrThrow(input.categoryId);
+        }
+        if (input.zoneId) {
+            taxRate.category = await this.getZoneOrThrow(input.zoneId);
+        }
+        if (input.customerGroupId) {
+            taxRate.customerGroup = await this.getCustomerGroupOrThrow(input.customerGroupId);
+        }
+        await this.connection.getRepository(TaxRate).save(updatedTaxRate);
+        return assertFound(this.findOne(taxRate.id));
+    }
+
+    private async getTaxCategoryOrThrow(id: ID): Promise<TaxCategory> {
+        const taxCategory = await this.connection.getRepository(TaxCategory).findOne(id);
+        if (!taxCategory) {
+            throw new I18nError(`error.entity-with-id-not-found`, {
+                entityName: 'TaxCategory',
+                id,
+            });
+        }
+        return taxCategory;
+    }
+
+    private async getZoneOrThrow(id: ID): Promise<Zone> {
+        const zone = await this.connection.getRepository(Zone).findOne(id);
+        if (!zone) {
+            throw new I18nError(`error.entity-with-id-not-found`, {
+                entityName: 'Zone',
+                id,
+            });
+        }
+        return zone;
+    }
+
+    private async getCustomerGroupOrThrow(id: ID): Promise<CustomerGroup> {
+        const group = await this.connection.getRepository(CustomerGroup).findOne(id);
+        if (!group) {
+            throw new I18nError(`error.entity-with-id-not-found`, {
+                entityName: 'CustomerGroup',
+                id,
+            });
+        }
+        return group;
+    }
+}

+ 2 - 0
server/src/service/service.module.ts

@@ -24,6 +24,7 @@ import { ProductService } from './providers/product.service';
 import { PromotionService } from './providers/promotion.service';
 import { RoleService } from './providers/role.service';
 import { TaxCategoryService } from './providers/tax-category.service';
+import { TaxRateService } from './providers/tax-rate.service';
 import { ZoneService } from './providers/zone.service';
 
 const exportedProviders = [
@@ -44,6 +45,7 @@ const exportedProviders = [
     ProductVariantService,
     RoleService,
     TaxCategoryService,
+    TaxRateService,
     ZoneService,
 ];
 

+ 279 - 0
shared/generated-types.ts

@@ -67,6 +67,8 @@ export interface Query {
     role?: Role | null;
     taxCategories: TaxCategory[];
     taxCategory?: TaxCategory | null;
+    taxRates: TaxRateList;
+    taxRate?: TaxRate | null;
     zones: Zone[];
     zone?: Zone | null;
     networkStatus: NetworkStatus;
@@ -102,6 +104,8 @@ export interface User extends Node {
 
 export interface Role extends Node {
     id: string;
+    createdAt: DateTime;
+    updatedAt: DateTime;
     code: string;
     description: string;
     permissions: Permission[];
@@ -268,6 +272,7 @@ export interface OrderLine extends Node {
     featuredAsset?: Asset | null;
     unitPrice: number;
     quantity: number;
+    items: OrderItem[];
     totalPrice: number;
     order: Order;
 }
@@ -289,6 +294,8 @@ export interface ProductVariant extends Node {
 
 export interface TaxCategory extends Node {
     id: string;
+    createdAt: DateTime;
+    updatedAt: DateTime;
     name: string;
 }
 
@@ -319,6 +326,12 @@ export interface ProductVariantTranslation {
     name: string;
 }
 
+export interface OrderItem extends Node {
+    id: string;
+    createdAt: DateTime;
+    updatedAt: DateTime;
+}
+
 export interface Adjustment {
     promotionId: string;
     description: string;
@@ -429,6 +442,23 @@ export interface RoleList extends PaginatedList {
     totalItems: number;
 }
 
+export interface TaxRateList extends PaginatedList {
+    items: TaxRate[];
+    totalItems: number;
+}
+
+export interface TaxRate extends Node {
+    id: string;
+    createdAt: DateTime;
+    updatedAt: DateTime;
+    name: string;
+    enabled: boolean;
+    value: number;
+    category: TaxCategory;
+    zone: Zone;
+    customerGroup?: CustomerGroup | null;
+}
+
 export interface Zone extends Node {
     id: string;
     createdAt: DateTime;
@@ -489,6 +519,8 @@ export interface Mutation {
     updateRole: Role;
     createTaxCategory: TaxCategory;
     updateTaxCategory: TaxCategory;
+    createTaxRate: TaxRate;
+    updateTaxRate: TaxRate;
     createZone: Zone;
     updateZone: Zone;
     addMembersToZone: Zone;
@@ -740,6 +772,29 @@ export interface RoleFilterParameter {
     updatedAt?: DateOperators | null;
 }
 
+export interface TaxRateListOptions {
+    take?: number | null;
+    skip?: number | null;
+    sort?: TaxRateSortParameter | null;
+    filter?: TaxRateFilterParameter | null;
+}
+
+export interface TaxRateSortParameter {
+    id?: SortOrder | null;
+    createdAt?: SortOrder | null;
+    updatedAt?: SortOrder | null;
+    name?: SortOrder | null;
+    enabled?: SortOrder | null;
+}
+
+export interface TaxRateFilterParameter {
+    code?: StringOperators | null;
+    name?: StringOperators | null;
+    enabled?: BooleanOperators | null;
+    createdAt?: DateOperators | null;
+    updatedAt?: DateOperators | null;
+}
+
 export interface CreateAdministratorInput {
     firstName: string;
     lastName: string;
@@ -995,6 +1050,25 @@ export interface UpdateTaxCategoryInput {
     name?: string | null;
 }
 
+export interface CreateTaxRateInput {
+    name: string;
+    enabled: boolean;
+    value: number;
+    categoryId: string;
+    zoneId: string;
+    customerGroupId?: string | null;
+}
+
+export interface UpdateTaxRateInput {
+    id: string;
+    name?: string | null;
+    value?: number | null;
+    enabled?: boolean | null;
+    categoryId?: string | null;
+    zoneId?: string | null;
+    customerGroupId?: string | null;
+}
+
 export interface CreateZoneInput {
     name: string;
     memberIds?: string[] | null;
@@ -1106,6 +1180,12 @@ export interface RoleQueryArgs {
 export interface TaxCategoryQueryArgs {
     id: string;
 }
+export interface TaxRatesQueryArgs {
+    options?: TaxRateListOptions | null;
+}
+export interface TaxRateQueryArgs {
+    id: string;
+}
 export interface ZoneQueryArgs {
     id: string;
 }
@@ -1232,6 +1312,12 @@ export interface CreateTaxCategoryMutationArgs {
 export interface UpdateTaxCategoryMutationArgs {
     input: UpdateTaxCategoryInput;
 }
+export interface CreateTaxRateMutationArgs {
+    input: CreateTaxRateInput;
+}
+export interface UpdateTaxRateMutationArgs {
+    input: UpdateTaxRateInput;
+}
 export interface CreateZoneMutationArgs {
     input: CreateZoneInput;
 }
@@ -1513,6 +1599,8 @@ export namespace QueryResolvers {
         role?: RoleResolver<Role | null, any, Context>;
         taxCategories?: TaxCategoriesResolver<TaxCategory[], any, Context>;
         taxCategory?: TaxCategoryResolver<TaxCategory | null, any, Context>;
+        taxRates?: TaxRatesResolver<TaxRateList, any, Context>;
+        taxRate?: TaxRateResolver<TaxRate | null, any, Context>;
         zones?: ZonesResolver<Zone[], any, Context>;
         zone?: ZoneResolver<Zone | null, any, Context>;
         networkStatus?: NetworkStatusResolver<NetworkStatus, any, Context>;
@@ -1771,6 +1859,26 @@ export namespace QueryResolvers {
         id: string;
     }
 
+    export type TaxRatesResolver<R = TaxRateList, Parent = any, Context = any> = Resolver<
+        R,
+        Parent,
+        Context,
+        TaxRatesArgs
+    >;
+    export interface TaxRatesArgs {
+        options?: TaxRateListOptions | null;
+    }
+
+    export type TaxRateResolver<R = TaxRate | null, Parent = any, Context = any> = Resolver<
+        R,
+        Parent,
+        Context,
+        TaxRateArgs
+    >;
+    export interface TaxRateArgs {
+        id: string;
+    }
+
     export type ZonesResolver<R = Zone[], Parent = any, Context = any> = Resolver<R, Parent, Context>;
     export type ZoneResolver<R = Zone | null, Parent = any, Context = any> = Resolver<
         R,
@@ -1862,6 +1970,8 @@ export namespace UserResolvers {
 export namespace RoleResolvers {
     export interface Resolvers<Context = any> {
         id?: IdResolver<string, any, Context>;
+        createdAt?: CreatedAtResolver<DateTime, any, Context>;
+        updatedAt?: UpdatedAtResolver<DateTime, any, Context>;
         code?: CodeResolver<string, any, Context>;
         description?: DescriptionResolver<string, any, Context>;
         permissions?: PermissionsResolver<Permission[], any, Context>;
@@ -1869,6 +1979,8 @@ export namespace RoleResolvers {
     }
 
     export type IdResolver<R = string, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type CreatedAtResolver<R = DateTime, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type UpdatedAtResolver<R = DateTime, Parent = any, Context = any> = Resolver<R, Parent, Context>;
     export type CodeResolver<R = string, Parent = any, Context = any> = Resolver<R, Parent, Context>;
     export type DescriptionResolver<R = string, Parent = any, Context = any> = Resolver<R, Parent, Context>;
     export type PermissionsResolver<R = Permission[], Parent = any, Context = any> = Resolver<
@@ -2304,6 +2416,7 @@ export namespace OrderLineResolvers {
         featuredAsset?: FeaturedAssetResolver<Asset | null, any, Context>;
         unitPrice?: UnitPriceResolver<number, any, Context>;
         quantity?: QuantityResolver<number, any, Context>;
+        items?: ItemsResolver<OrderItem[], any, Context>;
         totalPrice?: TotalPriceResolver<number, any, Context>;
         order?: OrderResolver<Order, any, Context>;
     }
@@ -2323,6 +2436,7 @@ export namespace OrderLineResolvers {
     >;
     export type UnitPriceResolver<R = number, Parent = any, Context = any> = Resolver<R, Parent, Context>;
     export type QuantityResolver<R = number, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type ItemsResolver<R = OrderItem[], Parent = any, Context = any> = Resolver<R, Parent, Context>;
     export type TotalPriceResolver<R = number, Parent = any, Context = any> = Resolver<R, Parent, Context>;
     export type OrderResolver<R = Order, Parent = any, Context = any> = Resolver<R, Parent, Context>;
 }
@@ -2384,10 +2498,14 @@ export namespace ProductVariantResolvers {
 export namespace TaxCategoryResolvers {
     export interface Resolvers<Context = any> {
         id?: IdResolver<string, any, Context>;
+        createdAt?: CreatedAtResolver<DateTime, any, Context>;
+        updatedAt?: UpdatedAtResolver<DateTime, any, Context>;
         name?: NameResolver<string, any, Context>;
     }
 
     export type IdResolver<R = string, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type CreatedAtResolver<R = DateTime, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type UpdatedAtResolver<R = DateTime, Parent = any, Context = any> = Resolver<R, Parent, Context>;
     export type NameResolver<R = string, Parent = any, Context = any> = Resolver<R, Parent, Context>;
 }
 
@@ -2465,6 +2583,18 @@ export namespace ProductVariantTranslationResolvers {
     export type NameResolver<R = string, Parent = any, Context = any> = Resolver<R, Parent, Context>;
 }
 
+export namespace OrderItemResolvers {
+    export interface Resolvers<Context = any> {
+        id?: IdResolver<string, any, Context>;
+        createdAt?: CreatedAtResolver<DateTime, any, Context>;
+        updatedAt?: UpdatedAtResolver<DateTime, any, Context>;
+    }
+
+    export type IdResolver<R = string, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type CreatedAtResolver<R = DateTime, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type UpdatedAtResolver<R = DateTime, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+}
+
 export namespace AdjustmentResolvers {
     export interface Resolvers<Context = any> {
         promotionId?: PromotionIdResolver<string, any, Context>;
@@ -2769,6 +2899,44 @@ export namespace RoleListResolvers {
     export type TotalItemsResolver<R = number, Parent = any, Context = any> = Resolver<R, Parent, Context>;
 }
 
+export namespace TaxRateListResolvers {
+    export interface Resolvers<Context = any> {
+        items?: ItemsResolver<TaxRate[], any, Context>;
+        totalItems?: TotalItemsResolver<number, any, Context>;
+    }
+
+    export type ItemsResolver<R = TaxRate[], Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type TotalItemsResolver<R = number, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+}
+
+export namespace TaxRateResolvers {
+    export interface Resolvers<Context = any> {
+        id?: IdResolver<string, any, Context>;
+        createdAt?: CreatedAtResolver<DateTime, any, Context>;
+        updatedAt?: UpdatedAtResolver<DateTime, any, Context>;
+        name?: NameResolver<string, any, Context>;
+        enabled?: EnabledResolver<boolean, any, Context>;
+        value?: ValueResolver<number, any, Context>;
+        category?: CategoryResolver<TaxCategory, any, Context>;
+        zone?: ZoneResolver<Zone, any, Context>;
+        customerGroup?: CustomerGroupResolver<CustomerGroup | null, any, Context>;
+    }
+
+    export type IdResolver<R = string, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type CreatedAtResolver<R = DateTime, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type UpdatedAtResolver<R = DateTime, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type NameResolver<R = string, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type EnabledResolver<R = boolean, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type ValueResolver<R = number, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type CategoryResolver<R = TaxCategory, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type ZoneResolver<R = Zone, Parent = any, Context = any> = Resolver<R, Parent, Context>;
+    export type CustomerGroupResolver<R = CustomerGroup | null, Parent = any, Context = any> = Resolver<
+        R,
+        Parent,
+        Context
+    >;
+}
+
 export namespace ZoneResolvers {
     export interface Resolvers<Context = any> {
         id?: IdResolver<string, any, Context>;
@@ -2864,6 +3032,8 @@ export namespace MutationResolvers {
         updateRole?: UpdateRoleResolver<Role, any, Context>;
         createTaxCategory?: CreateTaxCategoryResolver<TaxCategory, any, Context>;
         updateTaxCategory?: UpdateTaxCategoryResolver<TaxCategory, any, Context>;
+        createTaxRate?: CreateTaxRateResolver<TaxRate, any, Context>;
+        updateTaxRate?: UpdateTaxRateResolver<TaxRate, any, Context>;
         createZone?: CreateZoneResolver<Zone, any, Context>;
         updateZone?: UpdateZoneResolver<Zone, any, Context>;
         addMembersToZone?: AddMembersToZoneResolver<Zone, any, Context>;
@@ -3247,6 +3417,26 @@ export namespace MutationResolvers {
         input: UpdateTaxCategoryInput;
     }
 
+    export type CreateTaxRateResolver<R = TaxRate, Parent = any, Context = any> = Resolver<
+        R,
+        Parent,
+        Context,
+        CreateTaxRateArgs
+    >;
+    export interface CreateTaxRateArgs {
+        input: CreateTaxRateInput;
+    }
+
+    export type UpdateTaxRateResolver<R = TaxRate, Parent = any, Context = any> = Resolver<
+        R,
+        Parent,
+        Context,
+        UpdateTaxRateArgs
+    >;
+    export interface UpdateTaxRateArgs {
+        input: UpdateTaxRateInput;
+    }
+
     export type CreateZoneResolver<R = Zone, Parent = any, Context = any> = Resolver<
         R,
         Parent,
@@ -4240,6 +4430,64 @@ export namespace UpdateTaxCategory {
     export type UpdateTaxCategory = TaxCategory.Fragment;
 }
 
+export namespace GetTaxRateList {
+    export type Variables = {
+        options?: TaxRateListOptions | null;
+    };
+
+    export type Query = {
+        __typename?: 'Query';
+        taxRates: TaxRates;
+    };
+
+    export type TaxRates = {
+        __typename?: 'TaxRateList';
+        items: Items[];
+        totalItems: number;
+    };
+
+    export type Items = TaxRate.Fragment;
+}
+
+export namespace GetTaxRate {
+    export type Variables = {
+        id: string;
+    };
+
+    export type Query = {
+        __typename?: 'Query';
+        taxRate?: TaxRate | null;
+    };
+
+    export type TaxRate = TaxRate.Fragment;
+}
+
+export namespace CreateTaxRate {
+    export type Variables = {
+        input: CreateTaxRateInput;
+    };
+
+    export type Mutation = {
+        __typename?: 'Mutation';
+        createTaxRate: CreateTaxRate;
+    };
+
+    export type CreateTaxRate = TaxRate.Fragment;
+}
+
+export namespace UpdateTaxRate {
+    export type Variables = {
+        input: UpdateTaxRateInput;
+    };
+
+    export type Mutation = {
+        __typename?: 'Mutation';
+        updateTaxRate: UpdateTaxRate;
+    };
+
+    export type UpdateTaxRate = TaxRate.Fragment;
+}
+
 export namespace Administrator {
     export type Fragment = {
         __typename?: 'Administrator';
@@ -4536,3 +4784,34 @@ export namespace TaxCategory {
         name: string;
     };
 }
+
+export namespace TaxRate {
+    export type Fragment = {
+        __typename?: 'TaxRate';
+        id: string;
+        name: string;
+        enabled: boolean;
+        value: number;
+        category: Category;
+        zone: Zone;
+        customerGroup?: CustomerGroup | null;
+    };
+
+    export type Category = {
+        __typename?: 'TaxCategory';
+        id: string;
+        name: string;
+    };
+
+    export type Zone = {
+        __typename?: 'Zone';
+        id: string;
+        name: string;
+    };
+
+    export type CustomerGroup = {
+        __typename?: 'CustomerGroup';
+        id: string;
+        name: string;
+    };
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов