Browse Source

feat(admin-ui): Display CustomFields for OrderLines in order detail view

Closes #227
Michael Bromley 6 years ago
parent
commit
c33f1f61ee

+ 35 - 28
packages/admin-ui/src/app/data/definitions/order-definitions.ts

@@ -62,6 +62,39 @@ export const FULFILLMENT_FRAGMENT = gql`
     }
     }
 `;
 `;
 
 
+export const ORDER_LINE_FRAGMENT = gql`
+    fragment OrderLine on OrderLine {
+        id
+        featuredAsset {
+            preview
+        }
+        productVariant {
+            id
+            name
+            sku
+        }
+        adjustments {
+            ...Adjustment
+        }
+        unitPrice
+        unitPriceWithTax
+        quantity
+        items {
+            id
+            unitPrice
+            unitPriceIncludesTax
+            unitPriceWithTax
+            taxRate
+            refundId
+            cancelled
+            fulfillment {
+                ...Fulfillment
+            }
+        }
+        totalPrice
+    }
+`;
+
 export const ORDER_DETAIL_FRAGMENT = gql`
 export const ORDER_DETAIL_FRAGMENT = gql`
     fragment OrderDetail on Order {
     fragment OrderDetail on Order {
         id
         id
@@ -76,34 +109,7 @@ export const ORDER_DETAIL_FRAGMENT = gql`
             lastName
             lastName
         }
         }
         lines {
         lines {
-            id
-            featuredAsset {
-                preview
-            }
-            productVariant {
-                id
-                name
-                sku
-            }
-            adjustments {
-                ...Adjustment
-            }
-            unitPrice
-            unitPriceWithTax
-            quantity
-            items {
-                id
-                unitPrice
-                unitPriceIncludesTax
-                unitPriceWithTax
-                taxRate
-                refundId
-                cancelled
-                fulfillment {
-                    ...Fulfillment
-                }
-            }
-            totalPrice
+            ...OrderLine
         }
         }
         adjustments {
         adjustments {
             ...Adjustment
             ...Adjustment
@@ -159,6 +165,7 @@ export const ORDER_DETAIL_FRAGMENT = gql`
     ${ADJUSTMENT_FRAGMENT}
     ${ADJUSTMENT_FRAGMENT}
     ${SHIPPING_ADDRESS_FRAGMENT}
     ${SHIPPING_ADDRESS_FRAGMENT}
     ${FULFILLMENT_FRAGMENT}
     ${FULFILLMENT_FRAGMENT}
+    ${ORDER_LINE_FRAGMENT}
 `;
 `;
 
 
 export const GET_ORDERS_LIST = gql`
 export const GET_ORDERS_LIST = gql`

+ 105 - 22
packages/admin-ui/src/app/order/components/order-detail/order-detail.component.html

@@ -53,6 +53,31 @@
                     <th>{{ 'order.product-sku' | translate }}</th>
                     <th>{{ 'order.product-sku' | translate }}</th>
                     <th>{{ 'order.unit-price' | translate }}</th>
                     <th>{{ 'order.unit-price' | translate }}</th>
                     <th>{{ 'order.quantity' | translate }}</th>
                     <th>{{ 'order.quantity' | translate }}</th>
+                    <ng-container *ngFor="let customField of visibileOrderLineCustomFields">
+                        <th class="order-line-custom-field">
+                            <button
+                                class="custom-field-header-button"
+                                (click)="toggleOrderLineCustomFields()"
+                                [title]="'common.hide-custom-fields' | translate"
+                            >
+                                {{ customField | customFieldLabel }}
+                            </button>
+                        </th>
+                    </ng-container>
+                    <ng-container *ngIf="showElided">
+                        <th>
+                            <button
+                                class="custom-field-header-button"
+                                (click)="toggleOrderLineCustomFields()"
+                                [title]="'common.display-custom-fields' | translate"
+                            >
+                                <clr-icon
+                                    shape="ellipsis-horizontal"
+                                    class="custom-field-ellipsis"
+                                ></clr-icon>
+                            </button>
+                        </th>
+                    </ng-container>
                     <th>{{ 'order.total' | translate }}</th>
                     <th>{{ 'order.total' | translate }}</th>
                 </tr>
                 </tr>
                 </thead>
                 </thead>
@@ -68,67 +93,123 @@
                     <td class="align-middle sku">{{ line.productVariant.sku }}</td>
                     <td class="align-middle sku">{{ line.productVariant.sku }}</td>
                     <td class="align-middle unit-price">
                     <td class="align-middle unit-price">
                         {{ line.unitPriceWithTax / 100 | currency: order.currencyCode }}
                         {{ line.unitPriceWithTax / 100 | currency: order.currencyCode }}
-                        <div class="net-price" [title]="'order.net-price' | translate">{{ line.unitPrice / 100 | currency: order.currencyCode }}</div>
+                        <div class="net-price" [title]="'order.net-price' | translate">
+                            {{ line.unitPrice / 100 | currency: order.currencyCode }}
+                        </div>
                     </td>
                     </td>
                     <td class="align-middle quantity">
                     <td class="align-middle quantity">
                         {{ line.quantity }}
                         {{ line.quantity }}
                         <vdr-line-refunds [line]="line"></vdr-line-refunds>
                         <vdr-line-refunds [line]="line"></vdr-line-refunds>
                         <vdr-line-fulfillment [line]="line" [orderState]="order.state"></vdr-line-fulfillment>
                         <vdr-line-fulfillment [line]="line" [orderState]="order.state"></vdr-line-fulfillment>
                     </td>
                     </td>
+                    <ng-container *ngFor="let customField of visibileOrderLineCustomFields">
+                        <td class="order-line-custom-field align-middle">
+                            <ng-container [ngSwitch]="customField.type">
+                                <ng-template [ngSwitchCase]="'datetime'">
+                                    <span [title]="line.customFields[customField.name]">{{
+                                        line.customFields[customField.name] | date: 'short'
+                                        }}</span>
+                                </ng-template>
+                                <ng-template [ngSwitchCase]="'boolean'">
+                                    <ng-template [ngIf]="line.customFields[customField.name] === true">
+                                        <clr-icon shape="check"></clr-icon>
+                                    </ng-template>
+                                    <ng-template [ngIf]="line.customFields[customField.name] === false">
+                                        <clr-icon shape="times"></clr-icon>
+                                    </ng-template>
+                                </ng-template>
+                                <ng-template ngSwitchDefault>
+                                    {{ line.customFields[customField.name] }}
+                                </ng-template>
+                            </ng-container>
+                        </td>
+                    </ng-container>
+                    <ng-container *ngIf="showElided"
+                    ><td class="order-line-custom-field align-middle">
+                        <clr-icon
+                            shape="ellipsis-horizontal"
+                            class="custom-field-ellipsis"
+                        ></clr-icon></td
+                    ></ng-container>
                     <td class="align-middle total">
                     <td class="align-middle total">
                         {{ line.totalPrice / 100 | currency: order.currencyCode }}
                         {{ line.totalPrice / 100 | currency: order.currencyCode }}
-                        <div class="net-price" [title]="'order.net-price' | translate">{{ (line.unitPrice * line.quantity) / 100 | currency: order.currencyCode }}</div>
+                        <div class="net-price" [title]="'order.net-price' | translate">
+                            {{ (line.unitPrice * line.quantity) / 100 | currency: order.currencyCode }}
+                        </div>
 
 
                         <ng-container *ngIf="getLinePromotions(line) as promotions">
                         <ng-container *ngIf="getLinePromotions(line) as promotions">
                             <vdr-dropdown *ngIf="promotions.length">
                             <vdr-dropdown *ngIf="promotions.length">
-                                <div class="promotions-label" vdrDropdownTrigger>{{ 'order.promotions-applied' | translate }}</div>
+                                <div class="promotions-label" vdrDropdownTrigger>
+                                    {{ 'order.promotions-applied' | translate }}
+                                </div>
                                 <vdr-dropdown-menu>
                                 <vdr-dropdown-menu>
-                                    <div class="line-promotion" *ngFor="let promotion of getLinePromotions(line)">
-                                        <a class="promotion-name" [routerLink]="getPromotionLink(promotion)">{{ promotion.description }}</a>
-                                        <div class="promotion-amount">{{ promotion.amount / 100 | currency: order.currencyCode }}</div>
+                                    <div
+                                        class="line-promotion"
+                                        *ngFor="let promotion of getLinePromotions(line)"
+                                    >
+                                        <a
+                                            class="promotion-name"
+                                            [routerLink]="getPromotionLink(promotion)"
+                                        >{{ promotion.description }}</a
+                                        >
+                                        <div class="promotion-amount">
+                                            {{ promotion.amount / 100 | currency: order.currencyCode }}
+                                        </div>
                                     </div>
                                     </div>
                                 </vdr-dropdown-menu>
                                 </vdr-dropdown-menu>
                             </vdr-dropdown>
                             </vdr-dropdown>
                         </ng-container>
                         </ng-container>
-
                     </td>
                     </td>
                 </tr>
                 </tr>
                 <tr class="sub-total">
                 <tr class="sub-total">
                     <td class="left clr-align-middle">{{ 'order.sub-total' | translate }}</td>
                     <td class="left clr-align-middle">{{ 'order.sub-total' | translate }}</td>
                     <td></td>
                     <td></td>
-                    <td></td>
-                    <td></td>
-                    <td></td>
+                    <td [attr.colspan]="3 + visibileOrderLineCustomFields.length"></td>
+                    <ng-container *ngIf="showElided"><td></td></ng-container>
                     <td class="clr-align-middle">
                     <td class="clr-align-middle">
                         {{ order.subTotal / 100 | currency: order.currencyCode }}
                         {{ order.subTotal / 100 | currency: order.currencyCode }}
-                        <div class="net-price" [title]="'order.net-price' | translate">{{ order.subTotalBeforeTax / 100 | currency: order.currencyCode }}</div>
+                        <div class="net-price" [title]="'order.net-price' | translate">
+                            {{ order.subTotalBeforeTax / 100 | currency: order.currencyCode }}
+                        </div>
                     </td>
                     </td>
                 </tr>
                 </tr>
                 <tr class="order-ajustment" *ngFor="let adjustment of order.adjustments">
                 <tr class="order-ajustment" *ngFor="let adjustment of order.adjustments">
-                    <td colspan="5" class="left clr-align-middle">
+                    <td
+                        [attr.colspan]="5 + visibileOrderLineCustomFields.length"
+                        class="left clr-align-middle"
+                    >
                         <a [routerLink]="getPromotionLink(adjustment)">{{ adjustment.description }}</a>
                         <a [routerLink]="getPromotionLink(adjustment)">{{ adjustment.description }}</a>
-                        <vdr-chip *ngIf="getCouponCodeForAdjustment(order, adjustment) as couponCode">{{ couponCode }}</vdr-chip>
+                        <vdr-chip *ngIf="getCouponCodeForAdjustment(order, adjustment) as couponCode">{{
+                            couponCode
+                            }}</vdr-chip>
+                    </td>
+                    <ng-container *ngIf="showElided"><td></td></ng-container>
+                    <td class="clr-align-middle">
+                        {{ adjustment.amount / 100 | currency: order.currencyCode }}
                     </td>
                     </td>
-                    <td class="clr-align-middle">{{ adjustment.amount / 100 | currency: order.currencyCode }}</td>
                 </tr>
                 </tr>
                 <tr class="shipping">
                 <tr class="shipping">
                     <td class="left clr-align-middle">{{ 'order.shipping' | translate }}</td>
                     <td class="left clr-align-middle">{{ 'order.shipping' | translate }}</td>
                     <td class="clr-align-middle">{{ order.shippingMethod?.description }}</td>
                     <td class="clr-align-middle">{{ order.shippingMethod?.description }}</td>
-                    <td colspan="3"></td>
+                    <td [attr.colspan]="3 + visibileOrderLineCustomFields.length"></td>
+                    <ng-container *ngIf="showElided"><td></td></ng-container>
                     <td class="clr-align-middle">
                     <td class="clr-align-middle">
                         {{ order.shippingWithTax / 100 | currency: order.currencyCode }}
                         {{ order.shippingWithTax / 100 | currency: order.currencyCode }}
-                        <div class="net-price" [title]="'order.net-price' | translate">{{ order.shipping / 100 | currency: order.currencyCode }}</div>
+                        <div class="net-price" [title]="'order.net-price' | translate">
+                            {{ order.shipping / 100 | currency: order.currencyCode }}
+                        </div>
                     </td>
                     </td>
                 </tr>
                 </tr>
                 <tr class="total">
                 <tr class="total">
                     <td class="left clr-align-middle">{{ 'order.total' | translate }}</td>
                     <td class="left clr-align-middle">{{ 'order.total' | translate }}</td>
                     <td></td>
                     <td></td>
-                    <td></td>
-                    <td></td>
-                    <td></td>
+                    <td [attr.colspan]="3 + visibileOrderLineCustomFields.length"></td>
+                    <ng-container *ngIf="showElided"><td></td></ng-container>
                     <td class="clr-align-middle">
                     <td class="clr-align-middle">
                         {{ order.total / 100 | currency: order.currencyCode }}
                         {{ order.total / 100 | currency: order.currencyCode }}
-                        <div class="net-price" [title]="'order.net-price' | translate">{{ order.totalBeforeTax / 100 | currency: order.currencyCode }}</div>
+                        <div class="net-price" [title]="'order.net-price' | translate">
+                            {{ order.totalBeforeTax / 100 | currency: order.currencyCode }}
+                        </div>
                     </td>
                     </td>
                 </tr>
                 </tr>
             </table>
             </table>
@@ -140,8 +221,10 @@
             ></vdr-order-history>
             ></vdr-order-history>
         </div>
         </div>
         <div class="clr-col-lg-4 order-cards">
         <div class="clr-col-lg-4 order-cards">
-            <vdr-order-custom-fields-card [customFieldsConfig]="customFields"
-                                          [customFieldValues]="order.customFields"></vdr-order-custom-fields-card>
+            <vdr-order-custom-fields-card
+                [customFieldsConfig]="customFields"
+                [customFieldValues]="order.customFields"
+            ></vdr-order-custom-fields-card>
             <div class="card">
             <div class="card">
                 <div class="card-header">
                 <div class="card-header">
                     {{ 'order.customer' | translate }}
                     {{ 'order.customer' | translate }}

+ 17 - 0
packages/admin-ui/src/app/order/components/order-detail/order-detail.component.scss

@@ -23,6 +23,23 @@
     }
     }
 }
 }
 
 
+.custom-field-header-button {
+    background: none;
+    margin: 0;
+    padding: 0;
+    border: none;
+    cursor: pointer;
+    color: $color-primary-600;
+}
+
+.order-line-custom-field {
+    background-color: $color-grey-100;
+
+    .custom-field-ellipsis {
+        color: $color-grey-300;
+    }
+}
+
 .net-price {
 .net-price {
     font-size: 11px;
     font-size: 11px;
     color: $color-grey-400;
     color: $color-grey-400;

+ 16 - 0
packages/admin-ui/src/app/order/components/order-detail/order-detail.component.ts

@@ -36,6 +36,8 @@ export class OrderDetailComponent extends BaseDetailComponent<OrderDetail.Fragme
     history$: Observable<GetOrderHistory.Items[] | null>;
     history$: Observable<GetOrderHistory.Items[] | null>;
     fetchHistory = new Subject<void>();
     fetchHistory = new Subject<void>();
     customFields: CustomFieldConfig[];
     customFields: CustomFieldConfig[];
+    orderLineCustomFields: CustomFieldConfig[];
+    orderLineCustomFieldsVisible = false;
     constructor(
     constructor(
         router: Router,
         router: Router,
         route: ActivatedRoute,
         route: ActivatedRoute,
@@ -48,9 +50,19 @@ export class OrderDetailComponent extends BaseDetailComponent<OrderDetail.Fragme
         super(route, router, serverConfigService);
         super(route, router, serverConfigService);
     }
     }
 
 
+    get visibileOrderLineCustomFields(): CustomFieldConfig[] {
+        return this.orderLineCustomFieldsVisible ? this.orderLineCustomFields : [];
+    }
+
+    get showElided(): boolean {
+        return !this.orderLineCustomFieldsVisible && 0 < this.orderLineCustomFields.length;
+    }
+
     ngOnInit() {
     ngOnInit() {
         this.init();
         this.init();
         this.customFields = this.getCustomFieldConfig('Order');
         this.customFields = this.getCustomFieldConfig('Order');
+        this.orderLineCustomFields = this.getCustomFieldConfig('OrderLine');
+        this.orderLineCustomFieldsVisible = this.orderLineCustomFields.length < 2;
         this.history$ = this.fetchHistory.pipe(
         this.history$ = this.fetchHistory.pipe(
             startWith(null),
             startWith(null),
             switchMap(() => {
             switchMap(() => {
@@ -69,6 +81,10 @@ export class OrderDetailComponent extends BaseDetailComponent<OrderDetail.Fragme
         this.destroy();
         this.destroy();
     }
     }
 
 
+    toggleOrderLineCustomFields() {
+        this.orderLineCustomFieldsVisible = !this.orderLineCustomFieldsVisible;
+    }
+
     getLinePromotions(line: OrderDetail.Lines) {
     getLinePromotions(line: OrderDetail.Lines) {
         return line.adjustments.filter(a => a.type === AdjustmentType.PROMOTION);
         return line.adjustments.filter(a => a.type === AdjustmentType.PROMOTION);
     }
     }

+ 2 - 0
packages/admin-ui/src/i18n-messages/en.json

@@ -136,12 +136,14 @@
     "description": "Description",
     "description": "Description",
     "disabled": "Disabled",
     "disabled": "Disabled",
     "discard-changes": "Discard changes",
     "discard-changes": "Discard changes",
+    "display-custom-fields": "Display custom fields",
     "done": "Done",
     "done": "Done",
     "edit": "Edit",
     "edit": "Edit",
     "edit-field": "Edit field",
     "edit-field": "Edit field",
     "enabled": "Enabled",
     "enabled": "Enabled",
     "extension-running-in-separate-window": "Extension is running in a separate window",
     "extension-running-in-separate-window": "Extension is running in a separate window",
     "guest": "Guest",
     "guest": "Guest",
+    "hide-custom-fields": "Hide custom fields",
     "items-per-page-option": "{ count } per page",
     "items-per-page-option": "{ count } per page",
     "jobs-in-progress": "{ count } {count, plural, one {job} other {jobs}} in progress",
     "jobs-in-progress": "{ count } {count, plural, one {job} other {jobs}} in progress",
     "language": "Language",
     "language": "Language",