Browse Source

feat(admin-ui): Set default shipping and billing address for draft orders (#3196)

Closes #2342
Oliver Streißelberger 1 year ago
parent
commit
dec72e735a

+ 1 - 1
README.md

@@ -106,7 +106,7 @@ cd packages/dev-server
 If you are making changes to the admin ui, you need to start the admin ui independent from the dev-server:
 
 1. `cd packages/admin-ui`
-2. `npm run dev`
+2. `npm run start`
 3. Go to http://localhost:4200 and log in with "superadmin", "superadmin"
 
 This will auto restart when you make changes to the admin ui. You don't need this step when you just use the admin ui just

File diff suppressed because it is too large
+ 14 - 0
packages/admin-ui/src/lib/core/src/common/generated-types.ts


+ 18 - 0
packages/admin-ui/src/lib/core/src/data/definitions/order-definitions.ts

@@ -587,6 +587,24 @@ export const SET_BILLING_ADDRESS_FOR_DRAFT_ORDER = gql`
     ${ORDER_DETAIL_FRAGMENT}
 `;
 
+export const UNSET_SHIPPING_ADDRESS_FOR_DRAFT_ORDER = gql`
+    mutation UnsetDraftOrderShippingAddress($orderId: ID!) {
+        unsetDraftOrderShippingAddress(orderId: $orderId) {
+            ...OrderDetail
+        }
+    }
+    ${ORDER_DETAIL_FRAGMENT}
+`;
+
+export const UNSET_BILLING_ADDRESS_FOR_DRAFT_ORDER = gql`
+    mutation UnsetDraftOrderBillingAddress($orderId: ID!) {
+        unsetDraftOrderBillingAddress(orderId: $orderId) {
+            ...OrderDetail
+        }
+    }
+    ${ORDER_DETAIL_FRAGMENT}
+`;
+
 export const APPLY_COUPON_CODE_TO_DRAFT_ORDER = gql`
     mutation ApplyCouponCodeToDraftOrder($orderId: ID!, $couponCode: String!) {
         applyCouponCodeToDraftOrder(orderId: $orderId, couponCode: $couponCode) {

+ 16 - 0
packages/admin-ui/src/lib/core/src/data/providers/order-data.service.ts

@@ -28,6 +28,8 @@ import {
     TRANSITION_FULFILLMENT_TO_STATE,
     TRANSITION_ORDER_TO_STATE,
     TRANSITION_PAYMENT_TO_STATE,
+    UNSET_BILLING_ADDRESS_FOR_DRAFT_ORDER,
+    UNSET_SHIPPING_ADDRESS_FOR_DRAFT_ORDER,
     UPDATE_ORDER_CUSTOM_FIELDS,
     UPDATE_ORDER_NOTE,
 } from '../definitions/order-definitions';
@@ -254,6 +256,20 @@ export class OrderDataService {
         >(SET_BILLING_ADDRESS_FOR_DRAFT_ORDER, { orderId, input });
     }
 
+    unsetDraftOrderShippingAddress(orderId: string) {
+        return this.baseDataService.mutate<
+            Codegen.UnsetDraftOrderShippingAddressMutation,
+            Codegen.UnsetDraftOrderShippingAddressMutationVariables
+        >(UNSET_SHIPPING_ADDRESS_FOR_DRAFT_ORDER, { orderId });
+    }
+
+    unsetDraftOrderBillingAddress(orderId: string) {
+        return this.baseDataService.mutate<
+            Codegen.UnsetDraftOrderBillingAddressMutation,
+            Codegen.UnsetDraftOrderBillingAddressMutationVariables
+        >(UNSET_BILLING_ADDRESS_FOR_DRAFT_ORDER, { orderId });
+    }
+
     applyCouponCodeToDraftOrder(orderId: string, couponCode: string) {
         return this.baseDataService.mutate<
             Codegen.ApplyCouponCodeToDraftOrderMutation,

+ 50 - 1
packages/admin-ui/src/lib/order/src/components/draft-order-detail/draft-order-detail.component.ts

@@ -2,9 +2,12 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnIni
 import { UntypedFormGroup } from '@angular/forms';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
+    AddressFragment,
+    CreateAddressInput,
     DataService,
     DeletionResult,
     DraftOrderEligibleShippingMethodsQuery,
+    GetCustomerAddressesDocument,
     ModalService,
     NotificationService,
     Order,
@@ -12,7 +15,7 @@ import {
     OrderDetailQueryDocument,
     TypedBaseDetailComponent,
 } from '@vendure/admin-ui/core';
-import { combineLatest, Observable, Subject } from 'rxjs';
+import { combineLatest, forkJoin, Observable, of, Subject } from 'rxjs';
 import { switchMap, take } from 'rxjs/operators';
 
 import { OrderTransitionService } from '../../providers/order-transition.service';
@@ -108,6 +111,36 @@ export class DraftOrderDetailComponent
             if (this.hasId(result)) {
                 this.dataService.order
                     .setCustomerForDraftOrder(this.id, { customerId: result.id })
+                    .pipe(
+                        switchMap(() => {
+                            return this.dataService.query(GetCustomerAddressesDocument, {
+                                customerId: result.id,
+                            }).single$;
+                        }),
+                        switchMap(({ customer }) => {
+                            const defaultShippingAddress = customer?.addresses?.find(
+                                addr => addr.defaultShippingAddress,
+                            );
+                            const defaultBillingAddress = customer?.addresses?.find(
+                                addr => addr.defaultBillingAddress,
+                            );
+
+                            return forkJoin([
+                                defaultShippingAddress
+                                    ? this.dataService.order.setDraftOrderShippingAddress(
+                                          this.id,
+                                          this.mapToAddressInput(defaultShippingAddress),
+                                      )
+                                    : this.dataService.order.unsetDraftOrderShippingAddress(this.id),
+                                defaultBillingAddress
+                                    ? this.dataService.order.setDraftOrderBillingAddress(
+                                          this.id,
+                                          this.mapToAddressInput(defaultBillingAddress),
+                                      )
+                                    : this.dataService.order.unsetDraftOrderBillingAddress(this.id),
+                            ]);
+                        }),
+                    )
                     .subscribe();
             } else if (result) {
                 const { note, ...input } = result;
@@ -116,6 +149,22 @@ export class DraftOrderDetailComponent
         });
     }
 
+    private mapToAddressInput(address: AddressFragment): CreateAddressInput {
+        return {
+            fullName: address.fullName,
+            company: address.company,
+            streetLine1: address.streetLine1,
+            streetLine2: address.streetLine2,
+            city: address.city,
+            province: address.province,
+            postalCode: address.postalCode,
+            countryCode: address.country.code,
+            phoneNumber: address.phoneNumber,
+            defaultShippingAddress: address.defaultShippingAddress,
+            defaultBillingAddress: address.defaultBillingAddress,
+        };
+    }
+
     setShippingAddress() {
         this.entity$
             .pipe(

+ 12 - 0
packages/asset-server-plugin/e2e/graphql/generated-e2e-asset-server-plugin-types.ts

@@ -2873,6 +2873,10 @@ export type Mutation = {
     transitionFulfillmentToState: TransitionFulfillmentToStateResult;
     transitionOrderToState?: Maybe<TransitionOrderToStateResult>;
     transitionPaymentToState: TransitionPaymentToStateResult;
+    /** Unsets the billing address for a draft Order */
+    unsetDraftOrderBillingAddress: Order;
+    /** Unsets the sthipping address for a draft Order */
+    unsetDraftOrderShippingAddress: Order;
     /** Update the active (currently logged-in) Administrator */
     updateActiveAdministrator: Administrator;
     /** Update an existing Administrator */
@@ -3475,6 +3479,14 @@ export type MutationTransitionPaymentToStateArgs = {
     state: Scalars['String']['input'];
 };
 
+export type MutationUnsetDraftOrderBillingAddressArgs = {
+    orderId: Scalars['ID']['input'];
+};
+
+export type MutationUnsetDraftOrderShippingAddressArgs = {
+    orderId: Scalars['ID']['input'];
+};
+
 export type MutationUpdateActiveAdministratorArgs = {
     input: UpdateActiveAdministratorInput;
 };

+ 14 - 0
packages/common/src/generated-types.ts

@@ -2921,6 +2921,10 @@ export type Mutation = {
   transitionFulfillmentToState: TransitionFulfillmentToStateResult;
   transitionOrderToState?: Maybe<TransitionOrderToStateResult>;
   transitionPaymentToState: TransitionPaymentToStateResult;
+  /** Unsets the billing address for a draft Order */
+  unsetDraftOrderBillingAddress: Order;
+  /** Unsets the sthipping address for a draft Order */
+  unsetDraftOrderShippingAddress: Order;
   /** Update the active (currently logged-in) Administrator */
   updateActiveAdministrator: Administrator;
   /** Update an existing Administrator */
@@ -3652,6 +3656,16 @@ export type MutationTransitionPaymentToStateArgs = {
 };
 
 
+export type MutationUnsetDraftOrderBillingAddressArgs = {
+  orderId: Scalars['ID']['input'];
+};
+
+
+export type MutationUnsetDraftOrderShippingAddressArgs = {
+  orderId: Scalars['ID']['input'];
+};
+
+
 export type MutationUpdateActiveAdministratorArgs = {
   input: UpdateActiveAdministratorInput;
 };

+ 66 - 0
packages/core/e2e/draft-order.e2e-spec.ts

@@ -271,6 +271,48 @@ describe('Draft Orders resolver', () => {
         });
     });
 
+    it('unsetDraftOrderShippingAddress', async () => {
+        const { unsetDraftOrderShippingAddress } = await adminClient.query<
+            Codegen.UnsetDraftOrderShippingAddressMutation,
+            Codegen.UnsetDraftOrderShippingAddressMutationVariables
+        >(UNSET_SHIPPING_ADDRESS_FOR_DRAFT_ORDER, {
+            orderId: draftOrder.id,
+        });
+
+        expect(unsetDraftOrderShippingAddress.shippingAddress).toEqual({
+            company: null,
+            fullName: null,
+            phoneNumber: null,
+            streetLine2: null,
+            province: null,
+            city: null,
+            country: null,
+            postalCode: null,
+            streetLine1: null,
+        });
+    });
+
+    it('unsetDraftOrderBillingAddress', async () => {
+        const { unsetDraftOrderBillingAddress } = await adminClient.query<
+            Codegen.UnsetDraftOrderBillingAddressMutation,
+            Codegen.UnsetDraftOrderBillingAddressMutationVariables
+        >(UNSET_BILLING_ADDRESS_FOR_DRAFT_ORDER, {
+            orderId: draftOrder.id,
+        });
+
+        expect(unsetDraftOrderBillingAddress.billingAddress).toEqual({
+            company: null,
+            fullName: null,
+            phoneNumber: null,
+            streetLine2: null,
+            province: null,
+            city: null,
+            country: null,
+            postalCode: null,
+            streetLine1: null,
+        });
+    });
+
     it('applyCouponCodeToDraftOrder', async () => {
         const { addItemToDraftOrder } = await adminClient.query<
             Codegen.AddItemToDraftOrderMutation,
@@ -475,6 +517,30 @@ export const SET_BILLING_ADDRESS_FOR_DRAFT_ORDER = gql`
     ${ORDER_WITH_LINES_FRAGMENT}
 `;
 
+export const UNSET_SHIPPING_ADDRESS_FOR_DRAFT_ORDER = gql`
+    mutation UnsetDraftOrderShippingAddress($orderId: ID!) {
+        unsetDraftOrderShippingAddress(orderId: $orderId) {
+            ...OrderWithLines
+            shippingAddress {
+                ...ShippingAddress
+            }
+        }
+    }
+    ${ORDER_WITH_LINES_FRAGMENT}
+`;
+
+export const UNSET_BILLING_ADDRESS_FOR_DRAFT_ORDER = gql`
+    mutation UnsetDraftOrderBillingAddress($orderId: ID!) {
+        unsetDraftOrderBillingAddress(orderId: $orderId) {
+            ...OrderWithLines
+            billingAddress {
+                ...ShippingAddress
+            }
+        }
+    }
+    ${ORDER_WITH_LINES_FRAGMENT}
+`;
+
 export const APPLY_COUPON_CODE_TO_DRAFT_ORDER = gql`
     mutation ApplyCouponCodeToDraftOrder($orderId: ID!, $couponCode: String!) {
         applyCouponCodeToDraftOrder(orderId: $orderId, couponCode: $couponCode) {

+ 719 - 0
packages/core/e2e/graphql/generated-e2e-admin-types.ts

@@ -2873,6 +2873,10 @@ export type Mutation = {
     transitionFulfillmentToState: TransitionFulfillmentToStateResult;
     transitionOrderToState?: Maybe<TransitionOrderToStateResult>;
     transitionPaymentToState: TransitionPaymentToStateResult;
+    /** Unsets the billing address for a draft Order */
+    unsetDraftOrderBillingAddress: Order;
+    /** Unsets the sthipping address for a draft Order */
+    unsetDraftOrderShippingAddress: Order;
     /** Update the active (currently logged-in) Administrator */
     updateActiveAdministrator: Administrator;
     /** Update an existing Administrator */
@@ -3475,6 +3479,14 @@ export type MutationTransitionPaymentToStateArgs = {
     state: Scalars['String']['input'];
 };
 
+export type MutationUnsetDraftOrderBillingAddressArgs = {
+    orderId: Scalars['ID']['input'];
+};
+
+export type MutationUnsetDraftOrderShippingAddressArgs = {
+    orderId: Scalars['ID']['input'];
+};
+
 export type MutationUpdateActiveAdministratorArgs = {
     input: UpdateActiveAdministratorInput;
 };
@@ -7478,6 +7490,165 @@ export type SetDraftOrderBillingAddressMutation = {
     };
 };
 
+export type UnsetDraftOrderShippingAddressMutationVariables = Exact<{
+    orderId: Scalars['ID']['input'];
+}>;
+
+export type UnsetDraftOrderShippingAddressMutation = {
+    unsetDraftOrderShippingAddress: {
+        id: string;
+        createdAt: any;
+        updatedAt: any;
+        code: string;
+        state: string;
+        active: boolean;
+        subTotal: number;
+        subTotalWithTax: number;
+        total: number;
+        totalWithTax: number;
+        totalQuantity: number;
+        currencyCode: CurrencyCode;
+        shipping: number;
+        shippingWithTax: number;
+        shippingAddress?: {
+            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;
+        } | null;
+        customer?: { id: string; firstName: string; lastName: string } | null;
+        lines: Array<{
+            id: string;
+            unitPrice: number;
+            unitPriceWithTax: number;
+            quantity: number;
+            taxRate: number;
+            linePriceWithTax: number;
+            featuredAsset?: { preview: string } | null;
+            productVariant: { id: string; name: string; sku: string };
+            taxLines: Array<{ description: string; taxRate: number }>;
+        }>;
+        surcharges: Array<{
+            id: string;
+            description: string;
+            sku?: string | null;
+            price: number;
+            priceWithTax: number;
+        }>;
+        shippingLines: Array<{
+            priceWithTax: number;
+            shippingMethod: { id: string; code: string; name: string; description: string };
+        }>;
+        payments?: Array<{
+            id: string;
+            transactionId?: string | null;
+            amount: number;
+            method: string;
+            state: string;
+            nextStates: Array<string>;
+            metadata?: any | null;
+            refunds: Array<{ id: string; total: number; reason?: string | null }>;
+        }> | null;
+        fulfillments?: Array<{
+            id: string;
+            state: string;
+            method: string;
+            trackingCode?: string | null;
+            lines: Array<{ orderLineId: string; quantity: number }>;
+        }> | null;
+    };
+};
+
+export type UnsetDraftOrderBillingAddressMutationVariables = Exact<{
+    orderId: Scalars['ID']['input'];
+}>;
+
+export type UnsetDraftOrderBillingAddressMutation = {
+    unsetDraftOrderBillingAddress: {
+        id: string;
+        createdAt: any;
+        updatedAt: any;
+        code: string;
+        state: string;
+        active: boolean;
+        subTotal: number;
+        subTotalWithTax: number;
+        total: number;
+        totalWithTax: number;
+        totalQuantity: number;
+        currencyCode: CurrencyCode;
+        shipping: number;
+        shippingWithTax: number;
+        billingAddress?: {
+            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;
+        } | null;
+        customer?: { id: string; firstName: string; lastName: string } | null;
+        lines: Array<{
+            id: string;
+            unitPrice: number;
+            unitPriceWithTax: number;
+            quantity: number;
+            taxRate: number;
+            linePriceWithTax: number;
+            featuredAsset?: { preview: string } | null;
+            productVariant: { id: string; name: string; sku: string };
+            taxLines: Array<{ description: string; taxRate: number }>;
+        }>;
+        surcharges: Array<{
+            id: string;
+            description: string;
+            sku?: string | null;
+            price: number;
+            priceWithTax: number;
+        }>;
+        shippingLines: Array<{
+            priceWithTax: number;
+            shippingMethod: { id: string; code: string; name: string; description: string };
+        }>;
+        shippingAddress?: {
+            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;
+        } | null;
+        payments?: Array<{
+            id: string;
+            transactionId?: string | null;
+            amount: number;
+            method: string;
+            state: string;
+            nextStates: Array<string>;
+            metadata?: any | null;
+            refunds: Array<{ id: string; total: number; reason?: string | null }>;
+        }> | null;
+        fulfillments?: Array<{
+            id: string;
+            state: string;
+            method: string;
+            trackingCode?: string | null;
+            lines: Array<{ orderLineId: string; quantity: number }>;
+        }> | null;
+    };
+};
+
 export type ApplyCouponCodeToDraftOrderMutationVariables = Exact<{
     orderId: Scalars['ID']['input'];
     couponCode: Scalars['String']['input'];
@@ -20105,6 +20276,554 @@ export const SetDraftOrderBillingAddressDocument = {
     SetDraftOrderBillingAddressMutation,
     SetDraftOrderBillingAddressMutationVariables
 >;
+export const UnsetDraftOrderShippingAddressDocument = {
+    kind: 'Document',
+    definitions: [
+        {
+            kind: 'OperationDefinition',
+            operation: 'mutation',
+            name: { kind: 'Name', value: 'UnsetDraftOrderShippingAddress' },
+            variableDefinitions: [
+                {
+                    kind: 'VariableDefinition',
+                    variable: { kind: 'Variable', name: { kind: 'Name', value: 'orderId' } },
+                    type: {
+                        kind: 'NonNullType',
+                        type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } },
+                    },
+                },
+            ],
+            selectionSet: {
+                kind: 'SelectionSet',
+                selections: [
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'unsetDraftOrderShippingAddress' },
+                        arguments: [
+                            {
+                                kind: 'Argument',
+                                name: { kind: 'Name', value: 'orderId' },
+                                value: { kind: 'Variable', name: { kind: 'Name', value: 'orderId' } },
+                            },
+                        ],
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'FragmentSpread', name: { kind: 'Name', value: 'OrderWithLines' } },
+                                {
+                                    kind: 'Field',
+                                    name: { kind: 'Name', value: 'shippingAddress' },
+                                    selectionSet: {
+                                        kind: 'SelectionSet',
+                                        selections: [
+                                            {
+                                                kind: 'FragmentSpread',
+                                                name: { kind: 'Name', value: 'ShippingAddress' },
+                                            },
+                                        ],
+                                    },
+                                },
+                            ],
+                        },
+                    },
+                ],
+            },
+        },
+        {
+            kind: 'FragmentDefinition',
+            name: { kind: 'Name', value: 'ShippingAddress' },
+            typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'OrderAddress' } },
+            selectionSet: {
+                kind: 'SelectionSet',
+                selections: [
+                    { kind: 'Field', name: { kind: 'Name', value: 'fullName' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'company' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'streetLine1' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'streetLine2' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'city' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'province' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'postalCode' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'country' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'phoneNumber' } },
+                ],
+            },
+        },
+        {
+            kind: 'FragmentDefinition',
+            name: { kind: 'Name', value: 'Payment' },
+            typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Payment' } },
+            selectionSet: {
+                kind: 'SelectionSet',
+                selections: [
+                    { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'transactionId' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'amount' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'method' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'state' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'nextStates' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'metadata' } },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'refunds' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'total' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'reason' } },
+                            ],
+                        },
+                    },
+                ],
+            },
+        },
+        {
+            kind: 'FragmentDefinition',
+            name: { kind: 'Name', value: 'OrderWithLines' },
+            typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Order' } },
+            selectionSet: {
+                kind: 'SelectionSet',
+                selections: [
+                    { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'createdAt' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'updatedAt' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'code' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'state' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'active' } },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'customer' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'firstName' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'lastName' } },
+                            ],
+                        },
+                    },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'lines' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                {
+                                    kind: 'Field',
+                                    name: { kind: 'Name', value: 'featuredAsset' },
+                                    selectionSet: {
+                                        kind: 'SelectionSet',
+                                        selections: [
+                                            { kind: 'Field', name: { kind: 'Name', value: 'preview' } },
+                                        ],
+                                    },
+                                },
+                                {
+                                    kind: 'Field',
+                                    name: { kind: 'Name', value: 'productVariant' },
+                                    selectionSet: {
+                                        kind: 'SelectionSet',
+                                        selections: [
+                                            { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'name' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'sku' } },
+                                        ],
+                                    },
+                                },
+                                {
+                                    kind: 'Field',
+                                    name: { kind: 'Name', value: 'taxLines' },
+                                    selectionSet: {
+                                        kind: 'SelectionSet',
+                                        selections: [
+                                            { kind: 'Field', name: { kind: 'Name', value: 'description' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'taxRate' } },
+                                        ],
+                                    },
+                                },
+                                { kind: 'Field', name: { kind: 'Name', value: 'unitPrice' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'unitPriceWithTax' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'quantity' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'unitPrice' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'unitPriceWithTax' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'taxRate' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'linePriceWithTax' } },
+                            ],
+                        },
+                    },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'surcharges' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'description' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'sku' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'price' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'priceWithTax' } },
+                            ],
+                        },
+                    },
+                    { kind: 'Field', name: { kind: 'Name', value: 'subTotal' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'subTotalWithTax' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'total' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'totalWithTax' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'totalQuantity' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'currencyCode' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'shipping' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'shippingWithTax' } },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'shippingLines' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'Field', name: { kind: 'Name', value: 'priceWithTax' } },
+                                {
+                                    kind: 'Field',
+                                    name: { kind: 'Name', value: 'shippingMethod' },
+                                    selectionSet: {
+                                        kind: 'SelectionSet',
+                                        selections: [
+                                            { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'code' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'name' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'description' } },
+                                        ],
+                                    },
+                                },
+                            ],
+                        },
+                    },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'shippingAddress' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'FragmentSpread', name: { kind: 'Name', value: 'ShippingAddress' } },
+                            ],
+                        },
+                    },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'payments' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'FragmentSpread', name: { kind: 'Name', value: 'Payment' } },
+                            ],
+                        },
+                    },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'fulfillments' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'state' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'method' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'trackingCode' } },
+                                {
+                                    kind: 'Field',
+                                    name: { kind: 'Name', value: 'lines' },
+                                    selectionSet: {
+                                        kind: 'SelectionSet',
+                                        selections: [
+                                            { kind: 'Field', name: { kind: 'Name', value: 'orderLineId' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'quantity' } },
+                                        ],
+                                    },
+                                },
+                            ],
+                        },
+                    },
+                    { kind: 'Field', name: { kind: 'Name', value: 'total' } },
+                ],
+            },
+        },
+    ],
+} as unknown as DocumentNode<
+    UnsetDraftOrderShippingAddressMutation,
+    UnsetDraftOrderShippingAddressMutationVariables
+>;
+export const UnsetDraftOrderBillingAddressDocument = {
+    kind: 'Document',
+    definitions: [
+        {
+            kind: 'OperationDefinition',
+            operation: 'mutation',
+            name: { kind: 'Name', value: 'UnsetDraftOrderBillingAddress' },
+            variableDefinitions: [
+                {
+                    kind: 'VariableDefinition',
+                    variable: { kind: 'Variable', name: { kind: 'Name', value: 'orderId' } },
+                    type: {
+                        kind: 'NonNullType',
+                        type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } },
+                    },
+                },
+            ],
+            selectionSet: {
+                kind: 'SelectionSet',
+                selections: [
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'unsetDraftOrderBillingAddress' },
+                        arguments: [
+                            {
+                                kind: 'Argument',
+                                name: { kind: 'Name', value: 'orderId' },
+                                value: { kind: 'Variable', name: { kind: 'Name', value: 'orderId' } },
+                            },
+                        ],
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'FragmentSpread', name: { kind: 'Name', value: 'OrderWithLines' } },
+                                {
+                                    kind: 'Field',
+                                    name: { kind: 'Name', value: 'billingAddress' },
+                                    selectionSet: {
+                                        kind: 'SelectionSet',
+                                        selections: [
+                                            {
+                                                kind: 'FragmentSpread',
+                                                name: { kind: 'Name', value: 'ShippingAddress' },
+                                            },
+                                        ],
+                                    },
+                                },
+                            ],
+                        },
+                    },
+                ],
+            },
+        },
+        {
+            kind: 'FragmentDefinition',
+            name: { kind: 'Name', value: 'ShippingAddress' },
+            typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'OrderAddress' } },
+            selectionSet: {
+                kind: 'SelectionSet',
+                selections: [
+                    { kind: 'Field', name: { kind: 'Name', value: 'fullName' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'company' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'streetLine1' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'streetLine2' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'city' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'province' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'postalCode' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'country' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'phoneNumber' } },
+                ],
+            },
+        },
+        {
+            kind: 'FragmentDefinition',
+            name: { kind: 'Name', value: 'Payment' },
+            typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Payment' } },
+            selectionSet: {
+                kind: 'SelectionSet',
+                selections: [
+                    { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'transactionId' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'amount' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'method' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'state' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'nextStates' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'metadata' } },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'refunds' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'total' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'reason' } },
+                            ],
+                        },
+                    },
+                ],
+            },
+        },
+        {
+            kind: 'FragmentDefinition',
+            name: { kind: 'Name', value: 'OrderWithLines' },
+            typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Order' } },
+            selectionSet: {
+                kind: 'SelectionSet',
+                selections: [
+                    { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'createdAt' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'updatedAt' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'code' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'state' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'active' } },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'customer' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'firstName' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'lastName' } },
+                            ],
+                        },
+                    },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'lines' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                {
+                                    kind: 'Field',
+                                    name: { kind: 'Name', value: 'featuredAsset' },
+                                    selectionSet: {
+                                        kind: 'SelectionSet',
+                                        selections: [
+                                            { kind: 'Field', name: { kind: 'Name', value: 'preview' } },
+                                        ],
+                                    },
+                                },
+                                {
+                                    kind: 'Field',
+                                    name: { kind: 'Name', value: 'productVariant' },
+                                    selectionSet: {
+                                        kind: 'SelectionSet',
+                                        selections: [
+                                            { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'name' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'sku' } },
+                                        ],
+                                    },
+                                },
+                                {
+                                    kind: 'Field',
+                                    name: { kind: 'Name', value: 'taxLines' },
+                                    selectionSet: {
+                                        kind: 'SelectionSet',
+                                        selections: [
+                                            { kind: 'Field', name: { kind: 'Name', value: 'description' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'taxRate' } },
+                                        ],
+                                    },
+                                },
+                                { kind: 'Field', name: { kind: 'Name', value: 'unitPrice' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'unitPriceWithTax' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'quantity' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'unitPrice' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'unitPriceWithTax' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'taxRate' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'linePriceWithTax' } },
+                            ],
+                        },
+                    },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'surcharges' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'description' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'sku' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'price' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'priceWithTax' } },
+                            ],
+                        },
+                    },
+                    { kind: 'Field', name: { kind: 'Name', value: 'subTotal' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'subTotalWithTax' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'total' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'totalWithTax' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'totalQuantity' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'currencyCode' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'shipping' } },
+                    { kind: 'Field', name: { kind: 'Name', value: 'shippingWithTax' } },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'shippingLines' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'Field', name: { kind: 'Name', value: 'priceWithTax' } },
+                                {
+                                    kind: 'Field',
+                                    name: { kind: 'Name', value: 'shippingMethod' },
+                                    selectionSet: {
+                                        kind: 'SelectionSet',
+                                        selections: [
+                                            { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'code' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'name' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'description' } },
+                                        ],
+                                    },
+                                },
+                            ],
+                        },
+                    },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'shippingAddress' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'FragmentSpread', name: { kind: 'Name', value: 'ShippingAddress' } },
+                            ],
+                        },
+                    },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'payments' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'FragmentSpread', name: { kind: 'Name', value: 'Payment' } },
+                            ],
+                        },
+                    },
+                    {
+                        kind: 'Field',
+                        name: { kind: 'Name', value: 'fulfillments' },
+                        selectionSet: {
+                            kind: 'SelectionSet',
+                            selections: [
+                                { kind: 'Field', name: { kind: 'Name', value: 'id' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'state' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'method' } },
+                                { kind: 'Field', name: { kind: 'Name', value: 'trackingCode' } },
+                                {
+                                    kind: 'Field',
+                                    name: { kind: 'Name', value: 'lines' },
+                                    selectionSet: {
+                                        kind: 'SelectionSet',
+                                        selections: [
+                                            { kind: 'Field', name: { kind: 'Name', value: 'orderLineId' } },
+                                            { kind: 'Field', name: { kind: 'Name', value: 'quantity' } },
+                                        ],
+                                    },
+                                },
+                            ],
+                        },
+                    },
+                    { kind: 'Field', name: { kind: 'Name', value: 'total' } },
+                ],
+            },
+        },
+    ],
+} as unknown as DocumentNode<
+    UnsetDraftOrderBillingAddressMutation,
+    UnsetDraftOrderBillingAddressMutationVariables
+>;
 export const ApplyCouponCodeToDraftOrderDocument = {
     kind: 'Document',
     definitions: [

+ 22 - 0
packages/core/src/api/resolvers/admin/draft-order.resolver.ts

@@ -19,6 +19,8 @@ import {
     MutationSetDraftOrderBillingAddressArgs,
     MutationSetDraftOrderShippingAddressArgs,
     MutationSetDraftOrderShippingMethodArgs,
+    MutationUnsetDraftOrderShippingAddressArgs,
+    MutationUnsetDraftOrderBillingAddressArgs,
     Permission,
     QueryEligibleShippingMethodsForDraftOrderArgs,
     ShippingMethodQuote,
@@ -174,6 +176,26 @@ export class DraftOrderResolver {
         return this.orderService.setBillingAddress(ctx, args.orderId, args.input);
     }
 
+    @Transaction()
+    @Mutation()
+    @Allow(Permission.CreateOrder)
+    async unsetDraftOrderShippingAddress(
+        @Ctx() ctx: RequestContext,
+        @Args() args: MutationUnsetDraftOrderShippingAddressArgs,
+    ): Promise<ErrorResultUnion<ActiveOrderResult, Order>> {
+        return this.orderService.unsetShippingAddress(ctx, args.orderId);
+    }
+
+    @Transaction()
+    @Mutation()
+    @Allow(Permission.CreateOrder)
+    async unsetDraftOrderBillingAddress(
+        @Ctx() ctx: RequestContext,
+        @Args() args: MutationUnsetDraftOrderBillingAddressArgs,
+    ): Promise<ErrorResultUnion<ActiveOrderResult, Order>> {
+        return this.orderService.unsetBillingAddress(ctx, args.orderId);
+    }
+
     @Transaction()
     @Mutation()
     @Allow(Permission.CreateOrder)

+ 9 - 5
packages/core/src/api/schema/admin-api/order.api.graphql

@@ -57,6 +57,10 @@ type Mutation {
     setDraftOrderShippingAddress(orderId: ID!, input: CreateAddressInput!): Order!
     "Sets the billing address for a draft Order"
     setDraftOrderBillingAddress(orderId: ID!, input: CreateAddressInput!): Order!
+    "Unsets the shipping address for a draft Order"
+    unsetDraftOrderShippingAddress(orderId: ID!): Order!
+    "Unsets the billing address for a draft Order"
+    unsetDraftOrderBillingAddress(orderId: ID!): Order!
     "Allows any custom fields to be set for the active order"
     setDraftOrderCustomFields(orderId: ID!, input: UpdateOrderInput!): Order!
     "Applies the given coupon code to the draft Order"
@@ -410,13 +414,13 @@ type ManualPaymentStateError implements ErrorResult {
 
 union TransitionOrderToStateResult = Order | OrderStateTransitionError
 union SettlePaymentResult =
-      Payment
+    | Payment
     | SettlePaymentError
     | PaymentStateTransitionError
     | OrderStateTransitionError
 union CancelPaymentResult = Payment | CancelPaymentError | PaymentStateTransitionError
 union AddFulfillmentToOrderResult =
-      Fulfillment
+    | Fulfillment
     | EmptyOrderLineSelectionError
     | ItemsAlreadyFulfilledError
     | InsufficientStockOnHandError
@@ -424,14 +428,14 @@ union AddFulfillmentToOrderResult =
     | FulfillmentStateTransitionError
     | CreateFulfillmentError
 union CancelOrderResult =
-      Order
+    | Order
     | EmptyOrderLineSelectionError
     | QuantityTooGreatError
     | MultipleOrderError
     | CancelActiveOrderError
     | OrderStateTransitionError
 union RefundOrderResult =
-      Refund
+    | Refund
     | QuantityTooGreatError
     | NothingToRefundError
     | OrderStateTransitionError
@@ -445,7 +449,7 @@ union SettleRefundResult = Refund | RefundStateTransitionError
 union TransitionFulfillmentToStateResult = Fulfillment | FulfillmentStateTransitionError
 union TransitionPaymentToStateResult = Payment | PaymentStateTransitionError
 union ModifyOrderResult =
-      Order
+    | Order
     | NoChangesSpecifiedError
     | OrderModificationStateError
     | PaymentMethodMissingError

+ 12 - 0
packages/elasticsearch-plugin/e2e/graphql/generated-e2e-elasticsearch-plugin-types.ts

@@ -2873,6 +2873,10 @@ export type Mutation = {
     transitionFulfillmentToState: TransitionFulfillmentToStateResult;
     transitionOrderToState?: Maybe<TransitionOrderToStateResult>;
     transitionPaymentToState: TransitionPaymentToStateResult;
+    /** Unsets the billing address for a draft Order */
+    unsetDraftOrderBillingAddress: Order;
+    /** Unsets the sthipping address for a draft Order */
+    unsetDraftOrderShippingAddress: Order;
     /** Update the active (currently logged-in) Administrator */
     updateActiveAdministrator: Administrator;
     /** Update an existing Administrator */
@@ -3475,6 +3479,14 @@ export type MutationTransitionPaymentToStateArgs = {
     state: Scalars['String']['input'];
 };
 
+export type MutationUnsetDraftOrderBillingAddressArgs = {
+    orderId: Scalars['ID']['input'];
+};
+
+export type MutationUnsetDraftOrderShippingAddressArgs = {
+    orderId: Scalars['ID']['input'];
+};
+
 export type MutationUpdateActiveAdministratorArgs = {
     input: UpdateActiveAdministratorInput;
 };

+ 12 - 0
packages/payments-plugin/e2e/graphql/generated-admin-types.ts

@@ -2939,6 +2939,10 @@ export type Mutation = {
     transitionFulfillmentToState: TransitionFulfillmentToStateResult;
     transitionOrderToState?: Maybe<TransitionOrderToStateResult>;
     transitionPaymentToState: TransitionPaymentToStateResult;
+    /** Unsets the billing address for a draft Order */
+    unsetDraftOrderBillingAddress: Order;
+    /** Unsets the sthipping address for a draft Order */
+    unsetDraftOrderShippingAddress: Order;
     /** Update the active (currently logged-in) Administrator */
     updateActiveAdministrator: Administrator;
     /** Update an existing Administrator */
@@ -3545,6 +3549,14 @@ export type MutationTransitionPaymentToStateArgs = {
     state: Scalars['String']['input'];
 };
 
+export type MutationUnsetDraftOrderBillingAddressArgs = {
+    orderId: Scalars['ID']['input'];
+};
+
+export type MutationUnsetDraftOrderShippingAddressArgs = {
+    orderId: Scalars['ID']['input'];
+};
+
 export type MutationUpdateActiveAdministratorArgs = {
     input: UpdateActiveAdministratorInput;
 };

File diff suppressed because it is too large
+ 0 - 0
schema-admin.json


Some files were not shown because too many files changed in this diff