ソースを参照

feat: Create & Update for Customers

Michael Bromley 7 年 前
コミット
0538c2b37d

+ 5 - 2
admin-ui/src/app/common/base-detail.component.ts

@@ -1,6 +1,6 @@
 import { ActivatedRoute, Router } from '@angular/router';
 import { combineLatest, Observable, of, Subject } from 'rxjs';
-import { map, switchMap, takeUntil } from 'rxjs/operators';
+import { map, shareReplay, switchMap, takeUntil } from 'rxjs/operators';
 import { LanguageCode } from 'shared/generated-types';
 import { CustomFieldConfig, CustomFields } from 'shared/shared-types';
 
@@ -23,7 +23,10 @@ export abstract class BaseDetailComponent<Entity extends { id: string }> {
 
     init() {
         this.entity$ = this.route.data.pipe(switchMap(data => data.entity));
-        this.isNew$ = this.entity$.pipe(map(entity => entity.id === ''));
+        this.isNew$ = this.entity$.pipe(
+            map(entity => entity.id === ''),
+            shareReplay(1),
+        );
         this.languageCode$ = this.route.queryParamMap.pipe(
             map(qpm => qpm.get('lang')),
             map(lang => (!lang ? getDefaultLanguage() : (lang as LanguageCode))),

+ 11 - 2
admin-ui/src/app/customer/components/customer-detail/customer-detail.component.html

@@ -18,12 +18,21 @@
 
 <form class="form" [formGroup]="customerForm" >
     <section class="form-block">
-        <vdr-form-field [label]="'customer.firstName' | translate" for="firstName" [readOnlyToggle]="true">
+        <vdr-form-field [label]="'customer.title' | translate" for="title" [readOnlyToggle]="!(isNew$ | async)">
+            <input id="title" type="text" formControlName="title">
+        </vdr-form-field>
+        <vdr-form-field [label]="'customer.first-name' | translate" for="firstName" [readOnlyToggle]="!(isNew$ | async)">
             <input id="firstName" type="text" formControlName="firstName">
         </vdr-form-field>
-        <vdr-form-field [label]="'customer.lastName' | translate" for="lastName" [readOnlyToggle]="true">
+        <vdr-form-field [label]="'customer.last-name' | translate" for="lastName" [readOnlyToggle]="!(isNew$ | async)">
             <input id="lastName" type="text" formControlName="lastName">
         </vdr-form-field>
+        <vdr-form-field [label]="'customer.email-address' | translate" for="emailAddress" [readOnlyToggle]="!(isNew$ | async)">
+            <input id="emailAddress" type="text" formControlName="emailAddress">
+        </vdr-form-field>
+        <vdr-form-field [label]="'customer.password' | translate" for="password" *ngIf="isNew$ | async">
+            <input id="password" type="password" formControlName="password">
+        </vdr-form-field>
 
         <section formGroupName="customFields" *ngIf="customFields.length">
             <label>{{ 'common.custom-fields' }}</label>

+ 79 - 3
admin-ui/src/app/customer/components/customer-detail/customer-detail.component.ts

@@ -1,11 +1,20 @@
-import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
 import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
-import { map } from 'rxjs/operators';
-import { Customer } from 'shared/generated-types';
+import { map, mergeMap, take } from 'rxjs/operators';
+import {
+    CreateAdministratorInput,
+    CreateCustomerInput,
+    Customer,
+    UpdateAdministratorInput,
+    UpdateCustomerInput,
+} from 'shared/generated-types';
 import { CustomFieldConfig } from 'shared/shared-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({
@@ -23,14 +32,21 @@ export class CustomerDetailComponent extends BaseDetailComponent<Customer.Fragme
         route: ActivatedRoute,
         router: Router,
         serverConfigService: ServerConfigService,
+        private changeDetector: ChangeDetectorRef,
         private formBuilder: FormBuilder,
+        private dataService: DataService,
+        private notificationService: NotificationService,
     ) {
         super(route, router, serverConfigService);
 
         this.customFields = this.getCustomFieldConfig('Customer');
         this.customerForm = this.formBuilder.group({
+            title: '',
             firstName: ['', Validators.required],
             lastName: ['', Validators.required],
+            phoneNumber: '',
+            emailAddress: '',
+            password: '',
             customFields: this.formBuilder.group(
                 this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),
             ),
@@ -49,10 +65,70 @@ export class CustomerDetailComponent extends BaseDetailComponent<Customer.Fragme
         return !!this.customerForm.get(['customFields', name]);
     }
 
+    create() {
+        const formValue = this.customerForm.value;
+        const customer: CreateCustomerInput = {
+            title: formValue.title,
+            emailAddress: formValue.emailAddress,
+            firstName: formValue.firstName,
+            lastName: formValue.lastName,
+        };
+        this.dataService.customer.createCustomer(customer, formValue.password).subscribe(
+            data => {
+                this.notificationService.success(_('common.notify-create-success'), {
+                    entity: 'Customer',
+                });
+                this.customerForm.markAsPristine();
+                this.changeDetector.markForCheck();
+                this.router.navigate(['../', data.createCustomer.id], { relativeTo: this.route });
+            },
+            err => {
+                this.notificationService.error(_('common.notify-create-error'), {
+                    entity: 'Customer',
+                });
+            },
+        );
+    }
+
+    save() {
+        this.entity$
+            .pipe(
+                take(1),
+                mergeMap(({ id }) => {
+                    const formValue = this.customerForm.value;
+                    const customer: UpdateCustomerInput = {
+                        id,
+                        title: formValue.title,
+                        emailAddress: formValue.emailAddress,
+                        firstName: formValue.firstName,
+                        lastName: formValue.lastName,
+                    };
+                    return this.dataService.customer.updateCustomer(customer);
+                }),
+            )
+            .subscribe(
+                data => {
+                    this.notificationService.success(_('common.notify-update-success'), {
+                        entity: 'Customer',
+                    });
+                    this.customerForm.markAsPristine();
+                    this.changeDetector.markForCheck();
+                },
+                err => {
+                    this.notificationService.error(_('common.notify-update-error'), {
+                        entity: 'Customer',
+                    });
+                },
+            );
+    }
+
     protected setFormValues(entity: Customer.Fragment): void {
         this.customerForm.patchValue({
+            title: entity.title,
             firstName: entity.firstName,
             lastName: entity.lastName,
+            phoneNumber: entity.phoneNumber,
+            emailAddress: entity.emailAddress,
         });
 
         if (this.customFields.length) {

+ 3 - 3
admin-ui/src/app/customer/components/customer-list/customer-list.component.html

@@ -20,13 +20,13 @@
     <vdr-dt-column></vdr-dt-column>
     <ng-template let-customer="item">
         <td class="left">{{ customer.id }}</td>
-        <td class="left">{{ customer.firstName }} {{ customer.lastName }}</td>
+        <td class="left">{{ customer.title }} {{ customer.firstName }} {{ customer.lastName }}</td>
         <td class="left">{{ customer.emailAddress }}</td>
         <td class="left">
-            <vdr-chip *ngIf="customer.user.id">
+            <vdr-chip *ngIf="customer.user?.id">
                 <clr-icon shape="check-circle" class="registered-user-icon"></clr-icon> {{ 'customer.registered' | translate }}
             </vdr-chip>
-            <vdr-chip *ngIf="!customer.user.id">{{ 'customer.guest' | translate }}</vdr-chip>
+            <vdr-chip *ngIf="!customer.user?.id">{{ 'customer.guest' | translate }}</vdr-chip>
         </td>
         <td class="right">
             <vdr-table-row-action iconShape="edit"

+ 1 - 0
admin-ui/src/app/customer/providers/routing/customer-resolver.ts

@@ -11,6 +11,7 @@ export class CustomerResolver extends BaseEntityResolver<Customer.Fragment> {
             {
                 __typename: 'Customer',
                 id: '',
+                title: '',
                 firstName: '',
                 lastName: '',
                 emailAddress: '',

+ 50 - 0
admin-ui/src/app/data/definitions/customer-definitions.ts

@@ -1,17 +1,39 @@
 import gql from 'graphql-tag';
 
+export const ADDRESS_FRAGMENT = gql`
+    fragment Address on Address {
+        id
+        fullName
+        streetLine1
+        streetLine2
+        city
+        province
+        postalCode
+        country
+        phoneNumber
+        defaultShippingAddress
+        defaultBillingAddress
+    }
+`;
+
 export const CUSTOMER_FRAGMENT = gql`
     fragment Customer on Customer {
         id
+        title
         firstName
         lastName
+        phoneNumber
         emailAddress
         user {
             id
             identifier
             lastLogin
         }
+        addresses {
+            ...Address
+        }
     }
+    ${ADDRESS_FRAGMENT}
 `;
 
 export const GET_CUSTOMER_LIST = gql`
@@ -19,6 +41,7 @@ export const GET_CUSTOMER_LIST = gql`
         customers(options: $options) {
             items {
                 id
+                title
                 firstName
                 lastName
                 emailAddress
@@ -39,3 +62,30 @@ export const GET_CUSTOMER = gql`
     }
     ${CUSTOMER_FRAGMENT}
 `;
+
+export const CREATE_CUSTOMER = gql`
+    mutation CreateCustomer($input: CreateCustomerInput!, $password: String) {
+        createCustomer(input: $input, password: $password) {
+            ...Customer
+        }
+    }
+    ${CUSTOMER_FRAGMENT}
+`;
+
+export const UPDATE_CUSTOMER = gql`
+    mutation UpdateCustomer($input: UpdateCustomerInput!) {
+        updateCustomer(input: $input) {
+            ...Customer
+        }
+    }
+    ${CUSTOMER_FRAGMENT}
+`;
+
+export const UPDATE_CUSTOMER_ADDRESS = gql`
+    mutation UpdateCustomerAddress($input: UpdateAddressInput!) {
+        updateCustomerAddress(input: $input) {
+            ...Address
+        }
+    }
+    ${ADDRESS_FRAGMENT}
+`;

+ 45 - 2
admin-ui/src/app/data/providers/customer-data.service.ts

@@ -1,6 +1,21 @@
-import { GetCustomer, GetCustomerList } from 'shared/generated-types';
+import {
+    CreateCustomer,
+    CreateCustomerInput,
+    GetCustomer,
+    GetCustomerList,
+    UpdateAddressInput,
+    UpdateCustomer,
+    UpdateCustomerAddress,
+    UpdateCustomerInput,
+} from 'shared/generated-types';
 
-import { GET_CUSTOMER, GET_CUSTOMER_LIST } from '../definitions/customer-definitions';
+import {
+    CREATE_CUSTOMER,
+    GET_CUSTOMER,
+    GET_CUSTOMER_LIST,
+    UPDATE_CUSTOMER,
+    UPDATE_CUSTOMER_ADDRESS,
+} from '../definitions/customer-definitions';
 
 import { BaseDataService } from './base-data.service';
 
@@ -22,4 +37,32 @@ export class CustomerDataService {
     getCustomer(id: string) {
         return this.baseDataService.query<GetCustomer.Query, GetCustomer.Variables>(GET_CUSTOMER, { id });
     }
+
+    createCustomer(input: CreateCustomerInput, password?: string) {
+        return this.baseDataService.mutate<CreateCustomer.Mutation, CreateCustomer.Variables>(
+            CREATE_CUSTOMER,
+            {
+                input,
+                password,
+            },
+        );
+    }
+
+    updateCustomer(input: UpdateCustomerInput) {
+        return this.baseDataService.mutate<UpdateCustomer.Mutation, UpdateCustomer.Variables>(
+            UPDATE_CUSTOMER,
+            {
+                input,
+            },
+        );
+    }
+
+    updateCustomerAddress(input: UpdateAddressInput) {
+        return this.baseDataService.mutate<UpdateCustomerAddress.Mutation, UpdateCustomerAddress.Variables>(
+            UPDATE_CUSTOMER_ADDRESS,
+            {
+                input,
+            },
+        );
+    }
 }

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

@@ -33,6 +33,9 @@ export class MockDataService implements DataServiceMock {
     customer = {
         getCustomerList: spyQueryResult('getCustomerList'),
         getCustomer: spyQueryResult('getCustomer'),
+        createCustomer: spyObservable('createCustomer'),
+        updateCustomer: spyObservable('updateCustomer'),
+        updateCustomerAddress: spyObservable('updateCustomerAddress'),
     };
     promotion = {
         getPromotions: spyQueryResult('getPromotions'),

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

@@ -104,11 +104,13 @@
     "create-new-customer": "Create new customer",
     "customer-type": "Customer type",
     "email-address": "Email address",
-    "firstName": "First name",
+    "first-name": "First name",
     "guest": "Guest",
-    "lastName": "Last name",
+    "last-name": "Last name",
     "name": "Name",
-    "registered": "Registered"
+    "password": "Password",
+    "registered": "Registered",
+    "title": "Title"
   },
   "error": {
     "401-unauthorized": "Invalid login. Please try again",

ファイルの差分が大きいため隠しています
+ 0 - 0
schema.json


+ 11 - 11
server/e2e/order.e2e-spec.ts

@@ -1,7 +1,7 @@
 import gql from 'graphql-tag';
+import { GetCustomerList } from 'shared/generated-types';
 
-import { Customer } from '../src/entity/customer/customer.entity';
-import { OrderLine } from '../src/entity/order-line/order-line.entity';
+import { GET_CUSTOMER_LIST } from '../../admin-ui/src/app/data/definitions/customer-definitions';
 
 import { TEST_SETUP_TIMEOUT_MS } from './config/test-config';
 import { TestClient } from './test-client';
@@ -207,15 +207,15 @@ describe('Orders', () => {
 
         beforeAll(async () => {
             await client.asSuperAdmin();
-            const result = await client.query(gql`
-                query {
-                    customer(id: "T_1") {
-                        id
-                        emailAddress
-                    }
-                }
-            `);
-            const customer: Customer = result.customer;
+            const result = await client.query<GetCustomerList.Query, GetCustomerList.Variables>(
+                GET_CUSTOMER_LIST,
+                {
+                    options: {
+                        take: 1,
+                    },
+                },
+            );
+            const customer = result.customers.items[0];
             await client.asUserWithCredentials(customer.emailAddress, 'test');
         });
 

+ 16 - 0
server/src/api/resolvers/customer.resolver.ts

@@ -5,6 +5,8 @@ import {
     CustomerQueryArgs,
     CustomersQueryArgs,
     Permission,
+    UpdateCustomerAddressMutationArgs,
+    UpdateCustomerMutationArgs,
 } from 'shared/generated-types';
 import { PaginatedList } from 'shared/shared-types';
 
@@ -43,6 +45,13 @@ export class CustomerResolver {
         return this.customerService.create(input, password || undefined);
     }
 
+    @Mutation()
+    @Allow(Permission.UpdateCustomer)
+    async updateCustomer(@Args() args: UpdateCustomerMutationArgs): Promise<Customer> {
+        const { input } = args;
+        return this.customerService.update(input);
+    }
+
     @Mutation()
     @Allow(Permission.CreateCustomer)
     @Decode('customerId')
@@ -50,4 +59,11 @@ export class CustomerResolver {
         const { customerId, input } = args;
         return this.customerService.createAddress(customerId, input);
     }
+
+    @Mutation()
+    @Allow(Permission.UpdateCustomer)
+    async updateCustomerAddress(@Args() args: UpdateCustomerAddressMutationArgs): Promise<Address> {
+        const { input } = args;
+        return this.customerService.updateAddress(input);
+    }
 }

+ 10 - 6
server/src/api/types/customer.api.graphql

@@ -1,13 +1,17 @@
 type Query {
-  customers(options: CustomerListOptions): CustomerList!
-  customer(id: ID!): Customer
+    customers(options: CustomerListOptions): CustomerList!
+    customer(id: ID!): Customer
 }
 
 type Mutation {
-  "Create a new Customer. If a password is provided, a new User will also be created an linked to the Customer."
-  createCustomer(input: CreateCustomerInput!, password: String): Customer!
-  "Create a new Address and associate it with the Customer specified by customerId"
-  createCustomerAddress(customerId: ID!, input: CreateAddressInput!): Address!
+    "Create a new Customer. If a password is provided, a new User will also be created an linked to the Customer."
+    createCustomer(input: CreateCustomerInput!, password: String): Customer!
+    "Update an existing Customer"
+    updateCustomer(input: UpdateCustomerInput!): Customer!
+    "Create a new Address and associate it with the Customer specified by customerId"
+    createCustomerAddress(customerId: ID!, input: CreateAddressInput!): Address!
+    "Update an existing Address"
+    updateCustomerAddress(input: UpdateAddressInput!): Address!
 }
 
 type CustomerList implements PaginatedList {

+ 15 - 0
server/src/entity/address/address.graphql

@@ -28,3 +28,18 @@ input CreateAddressInput {
     defaultShippingAddress: Boolean
     defaultBillingAddress: Boolean
 }
+
+input UpdateAddressInput {
+    id: ID!
+    fullName: String
+    company: String
+    streetLine1: String
+    streetLine2: String
+    city: String
+    province: String
+    postalCode: String
+    country: String
+    phoneNumber: String
+    defaultShippingAddress: Boolean
+    defaultBillingAddress: Boolean
+}

+ 3 - 0
server/src/entity/customer/customer.entity.ts

@@ -15,6 +15,9 @@ export class Customer extends VendureEntity implements HasCustomFields {
         super(input);
     }
 
+    @Column({ nullable: true })
+    title: string;
+
     @Column() firstName: string;
 
     @Column() lastName: string;

+ 11 - 0
server/src/entity/customer/customer.graphql

@@ -2,6 +2,7 @@ type Customer implements Node {
     id: ID!
     createdAt: DateTime!
     updatedAt: DateTime!
+    title: String
     firstName: String!
     lastName: String!
     phoneNumber: String
@@ -11,8 +12,18 @@ type Customer implements Node {
 }
 
 input CreateCustomerInput {
+    title: String
     firstName: String!
     lastName: String!
     phoneNumber: String
     emailAddress: String!
 }
+
+input UpdateCustomerInput {
+    id: ID!
+    title: String
+    firstName: String
+    lastName: String
+    phoneNumber: String
+    emailAddress: String
+}

+ 24 - 5
server/src/service/services/customer.service.ts

@@ -1,16 +1,24 @@
 import { Injectable } from '@nestjs/common';
 import { InjectConnection } from '@nestjs/typeorm';
-import { CreateAddressInput, CreateCustomerInput } from 'shared/generated-types';
+import {
+    CreateAddressInput,
+    CreateCustomerInput,
+    UpdateAddressInput,
+    UpdateCustomerInput,
+} 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 { Address } from '../../entity/address/address.entity';
 import { Customer } from '../../entity/customer/customer.entity';
 import { User } from '../../entity/user/user.entity';
 import { I18nError } from '../../i18n/i18n-error';
 import { ListQueryBuilder } from '../helpers/list-query-builder/list-query-builder';
 import { PasswordCiper } from '../helpers/password-cipher/password-ciper';
+import { getEntityOrThrow } from '../helpers/utils/get-entity-or-throw';
+import { patchEntity } from '../helpers/utils/patch-entity';
 
 import { RoleService } from './role.service';
 
@@ -30,7 +38,7 @@ export class CustomerService {
             .then(([items, totalItems]) => ({ items, totalItems }));
     }
 
-    findOne(userId: string): Promise<Customer | undefined> {
+    findOne(userId: ID): Promise<Customer | undefined> {
         return this.connection.manager.findOne(Customer, userId);
     }
 
@@ -57,6 +65,13 @@ export class CustomerService {
         return this.connection.getRepository(Customer).save(customer);
     }
 
+    async update(input: UpdateCustomerInput): Promise<Customer> {
+        const customer = await getEntityOrThrow(this.connection, Customer, input.id);
+        const updatedCustomer = patchEntity(customer, input);
+        await this.connection.getRepository(Customer).save(customer);
+        return assertFound(this.findOne(customer.id));
+    }
+
     async createAddress(customerId: string, input: CreateAddressInput): Promise<Address> {
         const customer = await this.connection.manager.findOne(Customer, customerId, {
             relations: ['addresses'],
@@ -67,12 +82,16 @@ export class CustomerService {
         }
 
         const address = new Address(input);
-
         const createdAddress = await this.connection.manager.getRepository(Address).save(address);
-
         customer.addresses.push(createdAddress);
         await this.connection.manager.save(customer);
-
         return createdAddress;
     }
+
+    async updateAddress(input: UpdateAddressInput): Promise<Address> {
+        const address = await getEntityOrThrow(this.connection, Address, input.id);
+        const updatedAddress = patchEntity(address, input);
+        await this.connection.getRepository(Address).save(updatedAddress);
+        return updatedAddress;
+    }
 }

+ 123 - 0
shared/generated-types.ts

@@ -189,6 +189,7 @@ export interface Customer extends Node {
     id: string;
     createdAt: DateTime;
     updatedAt: DateTime;
+    title?: string | null;
     firstName: string;
     lastName: string;
     phoneNumber?: string | null;
@@ -520,7 +521,9 @@ export interface Mutation {
     addCustomersToGroup: CustomerGroup;
     removeCustomersFromGroup: CustomerGroup;
     createCustomer: Customer;
+    updateCustomer: Customer;
     createCustomerAddress: Address;
+    updateCustomerAddress: Address;
     createFacet: Facet;
     updateFacet: Facet;
     createFacetValues: FacetValue[];
@@ -884,6 +887,7 @@ export interface UpdateCustomerGroupInput {
 }
 
 export interface CreateCustomerInput {
+    title?: string | null;
     firstName: string;
     lastName: string;
     phoneNumber?: string | null;
@@ -891,6 +895,16 @@ export interface CreateCustomerInput {
     customFields?: Json | null;
 }
 
+export interface UpdateCustomerInput {
+    id: string;
+    title?: string | null;
+    firstName?: string | null;
+    lastName?: string | null;
+    phoneNumber?: string | null;
+    emailAddress?: string | null;
+    customFields?: Json | null;
+}
+
 export interface CreateAddressInput {
     fullName?: string | null;
     company?: string | null;
@@ -906,6 +920,22 @@ export interface CreateAddressInput {
     customFields?: Json | null;
 }
 
+export interface UpdateAddressInput {
+    id: string;
+    fullName?: string | null;
+    company?: string | null;
+    streetLine1?: string | null;
+    streetLine2?: string | null;
+    city?: string | null;
+    province?: string | null;
+    postalCode?: string | null;
+    country?: string | null;
+    phoneNumber?: string | null;
+    defaultShippingAddress?: boolean | null;
+    defaultBillingAddress?: boolean | null;
+    customFields?: Json | null;
+}
+
 export interface CreateFacetInput {
     code: string;
     translations: FacetTranslationInput[];
@@ -1289,10 +1319,16 @@ export interface CreateCustomerMutationArgs {
     input: CreateCustomerInput;
     password?: string | null;
 }
+export interface UpdateCustomerMutationArgs {
+    input: UpdateCustomerInput;
+}
 export interface CreateCustomerAddressMutationArgs {
     customerId: string;
     input: CreateAddressInput;
 }
+export interface UpdateCustomerAddressMutationArgs {
+    input: UpdateAddressInput;
+}
 export interface CreateFacetMutationArgs {
     input: CreateFacetInput;
 }
@@ -2245,6 +2281,7 @@ export namespace CustomerResolvers {
         id?: IdResolver<string, any, Context>;
         createdAt?: CreatedAtResolver<DateTime, any, Context>;
         updatedAt?: UpdatedAtResolver<DateTime, any, Context>;
+        title?: TitleResolver<string | null, any, Context>;
         firstName?: FirstNameResolver<string, any, Context>;
         lastName?: LastNameResolver<string, any, Context>;
         phoneNumber?: PhoneNumberResolver<string | null, any, Context>;
@@ -2257,6 +2294,7 @@ export namespace CustomerResolvers {
     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 TitleResolver<R = string | null, Parent = any, Context = any> = Resolver<R, Parent, Context>;
     export type FirstNameResolver<R = string, Parent = any, Context = any> = Resolver<R, Parent, Context>;
     export type LastNameResolver<R = string, Parent = any, Context = any> = Resolver<R, Parent, Context>;
     export type PhoneNumberResolver<R = string | null, Parent = any, Context = any> = Resolver<
@@ -3187,7 +3225,9 @@ export namespace MutationResolvers {
         addCustomersToGroup?: AddCustomersToGroupResolver<CustomerGroup, any, Context>;
         removeCustomersFromGroup?: RemoveCustomersFromGroupResolver<CustomerGroup, any, Context>;
         createCustomer?: CreateCustomerResolver<Customer, any, Context>;
+        updateCustomer?: UpdateCustomerResolver<Customer, any, Context>;
         createCustomerAddress?: CreateCustomerAddressResolver<Address, any, Context>;
+        updateCustomerAddress?: UpdateCustomerAddressResolver<Address, any, Context>;
         createFacet?: CreateFacetResolver<Facet, any, Context>;
         updateFacet?: UpdateFacetResolver<Facet, any, Context>;
         createFacetValues?: CreateFacetValuesResolver<FacetValue[], any, Context>;
@@ -3375,6 +3415,16 @@ export namespace MutationResolvers {
         password?: string | null;
     }
 
+    export type UpdateCustomerResolver<R = Customer, Parent = any, Context = any> = Resolver<
+        R,
+        Parent,
+        Context,
+        UpdateCustomerArgs
+    >;
+    export interface UpdateCustomerArgs {
+        input: UpdateCustomerInput;
+    }
+
     export type CreateCustomerAddressResolver<R = Address, Parent = any, Context = any> = Resolver<
         R,
         Parent,
@@ -3386,6 +3436,16 @@ export namespace MutationResolvers {
         input: CreateAddressInput;
     }
 
+    export type UpdateCustomerAddressResolver<R = Address, Parent = any, Context = any> = Resolver<
+        R,
+        Parent,
+        Context,
+        UpdateCustomerAddressArgs
+    >;
+    export interface UpdateCustomerAddressArgs {
+        input: UpdateAddressInput;
+    }
+
     export type CreateFacetResolver<R = Facet, Parent = any, Context = any> = Resolver<
         R,
         Parent,
@@ -4038,6 +4098,7 @@ export namespace GetCustomerList {
     export type Items = {
         __typename?: 'Customer';
         id: string;
+        title?: string | null;
         firstName: string;
         lastName: string;
         emailAddress: string;
@@ -4063,6 +4124,46 @@ export namespace GetCustomer {
     export type Customer = Customer.Fragment;
 }
 
+export namespace CreateCustomer {
+    export type Variables = {
+        input: CreateCustomerInput;
+        password?: string | null;
+    };
+
+    export type Mutation = {
+        __typename?: 'Mutation';
+        createCustomer: CreateCustomer;
+    };
+
+    export type CreateCustomer = Customer.Fragment;
+}
+
+export namespace UpdateCustomer {
+    export type Variables = {
+        input: UpdateCustomerInput;
+    };
+
+    export type Mutation = {
+        __typename?: 'Mutation';
+        updateCustomer: UpdateCustomer;
+    };
+
+    export type UpdateCustomer = Customer.Fragment;
+}
+
+export namespace UpdateCustomerAddress {
+    export type Variables = {
+        input: UpdateAddressInput;
+    };
+
+    export type Mutation = {
+        __typename?: 'Mutation';
+        updateCustomerAddress: UpdateCustomerAddress;
+    };
+
+    export type UpdateCustomerAddress = Address.Fragment;
+}
+
 export namespace CreateFacet {
     export type Variables = {
         input: CreateFacetInput;
@@ -4863,14 +4964,34 @@ export namespace CurrentUser {
     };
 }
 
+export namespace Address {
+    export type Fragment = {
+        __typename?: 'Address';
+        id: string;
+        fullName?: string | null;
+        streetLine1?: string | null;
+        streetLine2?: string | null;
+        city?: string | null;
+        province?: string | null;
+        postalCode?: string | null;
+        country?: string | null;
+        phoneNumber?: string | null;
+        defaultShippingAddress?: boolean | null;
+        defaultBillingAddress?: boolean | null;
+    };
+}
+
 export namespace Customer {
     export type Fragment = {
         __typename?: 'Customer';
         id: string;
+        title?: string | null;
         firstName: string;
         lastName: string;
+        phoneNumber?: string | null;
         emailAddress: string;
         user?: User | null;
+        addresses?: Addresses[] | null;
     };
 
     export type User = {
@@ -4879,6 +5000,8 @@ export namespace Customer {
         identifier: string;
         lastLogin?: string | null;
     };
+
+    export type Addresses = Address.Fragment;
 }
 
 export namespace FacetValue {

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません