Feature/order reissue (#910)
* wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * Add change to changelog * Remove console.log * Update tests * Extract messages * Add utils functions for selecting only ulfulfilled order lines * Add optional value selection for line item * Update tests * Add optional rendering of unfulfilled items card and refactor a bit * Update displaying of items card title when refunded card * UUpdate utils, form data etc. not to include refunded items when calculating replaced items amount * Uppdate return items card not to display replace buttons for refunded items * Refactor and small fixes after review * Update extracted messages * Fix card title when no fullfilemtn id * wip * Initially stitch returns page. Update types, add mutation * remove unnecessary component display names * Add loading status from form submission & refactor * Add errors from response * Add errors from response and refactor * Remove comments * Add optional error adding when no data from return create request * Update messages * wip * Update snapshots * Remove unnecessary console.log * Add better typing for getParsedLineData function * Update & refactor card title to match cards both in return and order details * Add handling of new statuses to order details cards. Also refactor, and devide order fulfillment card into couple of smaller components * Update messages * Update schema to match api * Update types * Update status label component to match colors with new designs and order details cards * RUpdate and refactor order fulfillment card components to be reusable. Also add replaced status handling * Updayte card title component to handle all cases and statuses * Update oorder unfulfilled items card and order details page, reduce some of the boilerplate * Fix card title types and adjust returns card to match * Update messages * Update snapshots * RUpdate order fulfillment card with subtitles and buttons for returned status * Add onRefund to order fulfillment card * Fix typo and wrong message in card title * Add missing condition in return form submission utils to decice if to refund products * Update fulfillment subtitles row and tests * Update messages * Change naming and locations of OrderFulfillment and items card components * Update messages * U[pdate names of components again to even better ones * Update messages * changelog * Update schema and types so that order history event also includes user first and last name * Add extended timeline event and event header components. Move some of the logic to utils and add way to display links in the event header. * FFix types * Update messages * Change naming of isOfType -> isTimelineEventOfType and refactor extended timeline event messages selection to be less complicated * Add ids and update messages * Add ids and update messages some more * Update storybook decorator to work with react router context in components and tests * Refactor after review * Update messages * Add rredirecting to draft order * Add handling draft creation from replacement * Add related order to order event fragment and update lots and lots of types * Update extended timeline event to match related order type on order history event * Update fixtures * Refactor ExtendedTimelineEvent Co-authored-by: Jakub Majorek <majorek.jakub@gmail.com> * Fix typing * Update messages * Fix missing history event for replacement draft created for replaced products * Update messages * Handle new statuses for returned and partially returned orders * Update messages * update snapshots * BBump empty line to rebuild ci * Change status to proper color * Change replaceable items in return for replace to be auto off instead of on * Add utils functions and make order details menu not show option to return items when there are returnable items in the order * Fix replace checkbox showing when previously hidden and clicked set maximal quantities * Fix return form invalid money values * Add default values to avoid returning of NaN in utils for return amount and refactor * Add ggeneral error alerts * Add eproduct error box component and style. style a lot. * Fixes * Fix lint * Add cannot refund error title + description * Extract messages * Refactor after review * Add better, nicer and fancier imports to product error cell * Use error color from palette in product error cell * Fix max refund when 0 for return * Add ddisable ability to refund products button so it's disabled when 0 products selected * Add class for order return form data parsing and add condition to not do refund when total captured on order is 0 * Update snapshots * Add condition for order lines quantity in order products table row * Fix return amount submit button * Add change to changelog Co-authored-by: Jakub Majorek <majorek.jakub@gmail.com>
This commit is contained in:
parent
b07bb08ade
commit
f0f9fe9b85
83 changed files with 6819 additions and 4215 deletions
|
@ -9,6 +9,7 @@ All notable, unreleased changes to this project will be documented in this file.
|
||||||
- Add shipping methods to translation section - #864 by @marekchoinski
|
- Add shipping methods to translation section - #864 by @marekchoinski
|
||||||
- New Miscellaneous and Product refunds - #870 by @orzechdev
|
- New Miscellaneous and Product refunds - #870 by @orzechdev
|
||||||
- Add zip code exclusion - #877 by @dominik-zeglen
|
- Add zip code exclusion - #877 by @dominik-zeglen
|
||||||
|
- Add order reissue
|
||||||
- Update quantity column in Inventory part of Product Variant view - #904 by @dominik-zeglen
|
- Update quantity column in Inventory part of Product Variant view - #904 by @dominik-zeglen
|
||||||
- Add file attributes - #884 by @orzechdev
|
- Add file attributes - #884 by @orzechdev
|
||||||
- Add shipping delivery days - #914 by @orzechdev
|
- Add shipping delivery days - #914 by @orzechdev
|
||||||
|
|
|
@ -3,6 +3,14 @@
|
||||||
"context": "dialog header",
|
"context": "dialog header",
|
||||||
"string": "Cancel Order"
|
"string": "Cancel Order"
|
||||||
},
|
},
|
||||||
|
"amount title": {
|
||||||
|
"context": "amount title",
|
||||||
|
"string": "Refunded amount"
|
||||||
|
},
|
||||||
|
"by preposition": {
|
||||||
|
"context": "by preposition",
|
||||||
|
"string": "by"
|
||||||
|
},
|
||||||
"configurationMenuAttributes": {
|
"configurationMenuAttributes": {
|
||||||
"string": "Determine attributes used to create product types"
|
"string": "Determine attributes used to create product types"
|
||||||
},
|
},
|
||||||
|
@ -42,6 +50,38 @@
|
||||||
"configurationPluginsPages": {
|
"configurationPluginsPages": {
|
||||||
"string": "View and update your plugins and their settings."
|
"string": "View and update your plugins and their settings."
|
||||||
},
|
},
|
||||||
|
"event products list title refunded": {
|
||||||
|
"context": "refunded products list title",
|
||||||
|
"string": "Products refunded"
|
||||||
|
},
|
||||||
|
"event products list title replaced": {
|
||||||
|
"context": "replaced products list title",
|
||||||
|
"string": "Products replaced"
|
||||||
|
},
|
||||||
|
"event products list title returned": {
|
||||||
|
"context": "returned products list title",
|
||||||
|
"string": "Products returned"
|
||||||
|
},
|
||||||
|
"event products title draft reissued": {
|
||||||
|
"context": "draft created from replace products list title",
|
||||||
|
"string": "Products replaced"
|
||||||
|
},
|
||||||
|
"event title draft reissued": {
|
||||||
|
"context": "draft created from replace event title",
|
||||||
|
"string": "Draft was reissued from order "
|
||||||
|
},
|
||||||
|
"event title refunded": {
|
||||||
|
"context": "refunded event title",
|
||||||
|
"string": "Products were refunded by "
|
||||||
|
},
|
||||||
|
"event title replaced": {
|
||||||
|
"context": "replaced event title",
|
||||||
|
"string": "Products were replaced by "
|
||||||
|
},
|
||||||
|
"event title returned": {
|
||||||
|
"context": "returned event title",
|
||||||
|
"string": "Products were returned by"
|
||||||
|
},
|
||||||
"homeActivityCardHeader": {
|
"homeActivityCardHeader": {
|
||||||
"context": "header",
|
"context": "header",
|
||||||
"string": "Activity"
|
"string": "Activity"
|
||||||
|
@ -336,6 +376,10 @@
|
||||||
"context": "unassign product from sale, button",
|
"context": "unassign product from sale, button",
|
||||||
"string": "Unassign"
|
"string": "Unassign"
|
||||||
},
|
},
|
||||||
|
"shipment refund title": {
|
||||||
|
"context": "shipment refund title",
|
||||||
|
"string": "Shipment was refunded"
|
||||||
|
},
|
||||||
"shippingZoneDetailsDialogsDeleteShippingMethod": {
|
"shippingZoneDetailsDialogsDeleteShippingMethod": {
|
||||||
"context": "delete shipping method",
|
"context": "delete shipping method",
|
||||||
"string": "Are you sure you want to delete {name}?"
|
"string": "Are you sure you want to delete {name}?"
|
||||||
|
@ -3164,13 +3208,17 @@
|
||||||
"src_dot_orders_dot_components_dot_OrderCustomer_dot_4282475982": {
|
"src_dot_orders_dot_components_dot_OrderCustomer_dot_4282475982": {
|
||||||
"string": "Billing Address"
|
"string": "Billing Address"
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderDetailsPage_dot_1854613983": {
|
"src_dot_orders_dot_components_dot_OrderDetailsPage_dot_cancelOrder": {
|
||||||
"context": "button",
|
"context": "cancel button",
|
||||||
"string": "Cancel order"
|
"string": "Cancel order"
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderDetailsPage_dot_3086420445": {
|
"src_dot_orders_dot_components_dot_OrderDetailsPage_dot_confirmOrder": {
|
||||||
"context": "save button",
|
"context": "save button",
|
||||||
"string": "confirm order"
|
"string": "Confirm order"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderDetailsPage_dot_returnOrder": {
|
||||||
|
"context": "return button",
|
||||||
|
"string": "Return / Replace order"
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderDraftCancelDialog_dot_1961675716": {
|
"src_dot_orders_dot_components_dot_OrderDraftCancelDialog_dot_1961675716": {
|
||||||
"context": "dialog header",
|
"context": "dialog header",
|
||||||
|
@ -3306,6 +3354,37 @@
|
||||||
"context": "product's sku",
|
"context": "product's sku",
|
||||||
"string": "SKU"
|
"string": "SKU"
|
||||||
},
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderFulfilledProductsCard_dot_1119771899": {
|
||||||
|
"context": "add tracking button",
|
||||||
|
"string": "Add tracking"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderFulfilledProductsCard_dot_2211099657": {
|
||||||
|
"context": "edit tracking button",
|
||||||
|
"string": "Edit tracking"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderFulfilledProductsCard_dot_2845258362": {
|
||||||
|
"context": "refund button",
|
||||||
|
"string": "Refund"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderFulfilledProductsCard_dot_3254150098": {
|
||||||
|
"string": "Tracking Number: {trackingNumber}"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderFulfilledProductsCard_dot_732594284": {
|
||||||
|
"context": "button",
|
||||||
|
"string": "Cancel Fulfillment"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderFulfilledProductsCard_dot_fulfilled": {
|
||||||
|
"context": "fulfillment group",
|
||||||
|
"string": "Fulfilled from: "
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderFulfilledProductsCard_dot_restocked": {
|
||||||
|
"context": "restocked group",
|
||||||
|
"string": "Restocked from: "
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderFulfilledProductsCard_dot_tracking": {
|
||||||
|
"context": "tracking number",
|
||||||
|
"string": "Tracking Number: {trackingNumber}"
|
||||||
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillmentCancelDialog_dot_1097287358": {
|
"src_dot_orders_dot_components_dot_OrderFulfillmentCancelDialog_dot_1097287358": {
|
||||||
"string": "Are you sure you want to cancel fulfillment? Canceling a fulfillment will restock products at a selected warehouse."
|
"string": "Are you sure you want to cancel fulfillment? Canceling a fulfillment will restock products at a selected warehouse."
|
||||||
},
|
},
|
||||||
|
@ -3343,71 +3422,10 @@
|
||||||
"context": "dialog header",
|
"context": "dialog header",
|
||||||
"string": "Add Tracking Code"
|
"string": "Add Tracking Code"
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillment_dot_1119771899": {
|
|
||||||
"context": "fulfillment group tracking number",
|
|
||||||
"string": "Add tracking"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillment_dot_1134347598": {
|
|
||||||
"context": "product price",
|
|
||||||
"string": "Price"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillment_dot_1895667608": {
|
|
||||||
"context": "product name",
|
|
||||||
"string": "Product"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillment_dot_2211099657": {
|
|
||||||
"context": "fulfillment group tracking number",
|
|
||||||
"string": "Edit tracking"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillment_dot_2567258278": {
|
|
||||||
"context": "refunded fulfillment, section header",
|
|
||||||
"string": "Refunded ({quantity})"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillment_dot_2796503714": {
|
|
||||||
"context": "ordered product quantity",
|
|
||||||
"string": "Quantity"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillment_dot_3254150098": {
|
|
||||||
"string": "Tracking Number: {trackingNumber}"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillment_dot_3494686506": {
|
|
||||||
"context": "section header",
|
|
||||||
"string": "Fulfilled ({quantity})"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillment_dot_4039425374": {
|
|
||||||
"context": "cancelled fulfillment, section header",
|
|
||||||
"string": "Cancelled ({quantity})"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillment_dot_693960049": {
|
|
||||||
"context": "ordered product sku",
|
|
||||||
"string": "SKU"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillment_dot_732594284": {
|
|
||||||
"context": "button",
|
|
||||||
"string": "Cancel Fulfillment"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillment_dot_77179533": {
|
|
||||||
"context": "fulfillment group",
|
|
||||||
"string": "Fulfilled from: {warehouseName}"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderFulfillment_dot_878013594": {
|
|
||||||
"context": "order line total price",
|
|
||||||
"string": "Total"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderHistory_dot_1154330234": {
|
|
||||||
"context": "transaction reference",
|
|
||||||
"string": "Transaction Reference {transactionReference}"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderHistory_dot_1230178536": {
|
"src_dot_orders_dot_components_dot_OrderHistory_dot_1230178536": {
|
||||||
"context": "order history message",
|
"context": "order history message",
|
||||||
"string": "Order address was updated"
|
"string": "Order address was updated"
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderHistory_dot_123236698": {
|
|
||||||
"string": "Shipment was refunded"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderHistory_dot_1322321687": {
|
|
||||||
"string": "Refunded amount"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderHistory_dot_1463685940": {
|
"src_dot_orders_dot_components_dot_OrderHistory_dot_1463685940": {
|
||||||
"context": "order history message",
|
"context": "order history message",
|
||||||
"string": "Order was marked as paid"
|
"string": "Order was marked as paid"
|
||||||
|
@ -3523,9 +3541,6 @@
|
||||||
"context": "order history message",
|
"context": "order history message",
|
||||||
"string": "Payment failed"
|
"string": "Payment failed"
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderHistory_dot_492197448": {
|
|
||||||
"string": "Products refunded"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderHistory_dot_493321552": {
|
"src_dot_orders_dot_components_dot_OrderHistory_dot_493321552": {
|
||||||
"context": "order history message",
|
"context": "order history message",
|
||||||
"string": "Order cancel information was sent to customer"
|
"string": "Order cancel information was sent to customer"
|
||||||
|
@ -3546,6 +3561,14 @@
|
||||||
"context": "order history message",
|
"context": "order history message",
|
||||||
"string": "Order was cancelled"
|
"string": "Order was cancelled"
|
||||||
},
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderHistory_dot_description": {
|
||||||
|
"context": "replacement created order history message description",
|
||||||
|
"string": "was created for replaced products"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderHistory_dot_draftNumber": {
|
||||||
|
"context": "replacement created order history message draft number",
|
||||||
|
"string": "Draft #{orderNumber} "
|
||||||
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderInvoiceEmailSendDialog_dot_1821123638": {
|
"src_dot_orders_dot_components_dot_OrderInvoiceEmailSendDialog_dot_1821123638": {
|
||||||
"string": "Are you sure you want to send this invoice: {invoiceNumber} to the customer?"
|
"string": "Are you sure you want to send this invoice: {invoiceNumber} to the customer?"
|
||||||
},
|
},
|
||||||
|
@ -3729,71 +3752,25 @@
|
||||||
"src_dot_orders_dot_components_dot_OrderProductAddDialog_dot_353369701": {
|
"src_dot_orders_dot_components_dot_OrderProductAddDialog_dot_353369701": {
|
||||||
"string": "No products matching given query"
|
"string": "No products matching given query"
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmountValues_dot_1580639738": {
|
"src_dot_orders_dot_components_dot_OrderProductsCardElements_dot_1134347598": {
|
||||||
"context": "order refund amount",
|
"context": "product price",
|
||||||
"string": "Proposed refund amount"
|
"string": "Price"
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmountValues_dot_1705174606": {
|
"src_dot_orders_dot_components_dot_OrderProductsCardElements_dot_1895667608": {
|
||||||
"context": "order refund amount",
|
"context": "product name",
|
||||||
"string": "Max Refund"
|
"string": "Product"
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmountValues_dot_1734445951": {
|
"src_dot_orders_dot_components_dot_OrderProductsCardElements_dot_2796503714": {
|
||||||
"context": "order refund amount",
|
"context": "ordered product quantity",
|
||||||
"string": "Refund total amount"
|
"string": "Quantity"
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmountValues_dot_2045860028": {
|
"src_dot_orders_dot_components_dot_OrderProductsCardElements_dot_693960049": {
|
||||||
"context": "order refund amount",
|
"context": "ordered product sku",
|
||||||
"string": "Authorized Amount"
|
"string": "SKU"
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmountValues_dot_2854815744": {
|
"src_dot_orders_dot_components_dot_OrderProductsCardElements_dot_878013594": {
|
||||||
"context": "order refund amount",
|
"context": "order line total price",
|
||||||
"string": "Previously refunded"
|
"string": "Total"
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmountValues_dot_2907874606": {
|
|
||||||
"context": "order refund amount",
|
|
||||||
"string": "Selected products value"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmountValues_dot_79173946": {
|
|
||||||
"context": "order refund amount",
|
|
||||||
"string": "Shipment cost"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmount_dot_120912052": {
|
|
||||||
"context": "order refund amount",
|
|
||||||
"string": "Refunded items can’t be fulfilled"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmount_dot_159210811": {
|
|
||||||
"string": "Amount must be bigger than 0"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmount_dot_2256869831": {
|
|
||||||
"context": "section header",
|
|
||||||
"string": "Refunded Amount"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmount_dot_2845258362": {
|
|
||||||
"context": "order refund amount, input button",
|
|
||||||
"string": "Refund"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmount_dot_4033685232": {
|
|
||||||
"string": "Amount cannot be bigger than max refund"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmount_dot_40513382": {
|
|
||||||
"context": "order refund amount, input button",
|
|
||||||
"string": "Refund {currency} {amount}"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmount_dot_4224226791": {
|
|
||||||
"context": "label",
|
|
||||||
"string": "Automatic Amount"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmount_dot_508357513": {
|
|
||||||
"context": "label",
|
|
||||||
"string": "Manual Amount"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmount_dot_553737700": {
|
|
||||||
"context": "checkbox",
|
|
||||||
"string": "Refund shipment costs"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundAmount_dot_75546233": {
|
|
||||||
"context": "order refund amount, input label",
|
|
||||||
"string": "Amount"
|
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundFulfilledProducts_dot_1134347598": {
|
"src_dot_orders_dot_components_dot_OrderRefundFulfilledProducts_dot_1134347598": {
|
||||||
"context": "tabel column header",
|
"context": "tabel column header",
|
||||||
|
@ -3838,6 +3815,86 @@
|
||||||
"context": "page header with order number",
|
"context": "page header with order number",
|
||||||
"string": "Order #{orderNumber}"
|
"string": "Order #{orderNumber}"
|
||||||
},
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_2256869831": {
|
||||||
|
"context": "section header",
|
||||||
|
"string": "Refunded Amount"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_40513382": {
|
||||||
|
"context": "order refund amount, input button",
|
||||||
|
"string": "Refund {currency} {amount}"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_4224226791": {
|
||||||
|
"context": "label",
|
||||||
|
"string": "Automatic Amount"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_508357513": {
|
||||||
|
"context": "label",
|
||||||
|
"string": "Manual Amount"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_553737700": {
|
||||||
|
"context": "checkbox",
|
||||||
|
"string": "Refund shipment costs"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_amountTooBig": {
|
||||||
|
"context": "Amount error message",
|
||||||
|
"string": "Amount cannot be bigger than max refund"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_amountTooSmall": {
|
||||||
|
"context": "Amount error message",
|
||||||
|
"string": "Amount must be bigger than 0"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_authorizedAmount": {
|
||||||
|
"context": "order refund amount",
|
||||||
|
"string": "Authorized Amount"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_label": {
|
||||||
|
"context": "order refund amount, input label",
|
||||||
|
"string": "Amount"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_maxRefund": {
|
||||||
|
"context": "order refund amount",
|
||||||
|
"string": "Max Refund"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_previouslyRefunded": {
|
||||||
|
"context": "order refund amount",
|
||||||
|
"string": "Previously refunded"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_proposedRefundAmount": {
|
||||||
|
"context": "order refund amount",
|
||||||
|
"string": "Proposed refund amount"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_refundButton": {
|
||||||
|
"context": "order refund amount button",
|
||||||
|
"string": "Refund"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_refundCannotBeFulfilled": {
|
||||||
|
"context": "order refund subtitle",
|
||||||
|
"string": "Refunded items can't be fulfilled"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_refundTotalAmount": {
|
||||||
|
"context": "order refund amount",
|
||||||
|
"string": "Refund total amount"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_replacedProductsValue": {
|
||||||
|
"context": "order refund amount",
|
||||||
|
"string": "Replaced Products Value"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_returnButton": {
|
||||||
|
"context": "order return amount button",
|
||||||
|
"string": "Return & Replace products"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_returnCannotBeFulfilled": {
|
||||||
|
"context": "order return subtitle",
|
||||||
|
"string": "Returned items can't be fulfilled"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_selectedProductsValue": {
|
||||||
|
"context": "order refund amount",
|
||||||
|
"string": "Selected Products Value"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderRefundReturnAmount_dot_shipmentCost": {
|
||||||
|
"context": "order refund amount",
|
||||||
|
"string": "Shipment Cost"
|
||||||
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderRefundUnfulfilledProducts_dot_1134347598": {
|
"src_dot_orders_dot_components_dot_OrderRefundUnfulfilledProducts_dot_1134347598": {
|
||||||
"context": "tabel column header",
|
"context": "tabel column header",
|
||||||
"string": "Price"
|
"string": "Price"
|
||||||
|
@ -3885,6 +3942,82 @@
|
||||||
"context": "refund type",
|
"context": "refund type",
|
||||||
"string": "Refund Products"
|
"string": "Refund Products"
|
||||||
},
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_1134347598": {
|
||||||
|
"context": "table column header",
|
||||||
|
"string": "Price"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_1784788864": {
|
||||||
|
"context": "table column header",
|
||||||
|
"string": "Return"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_1895667608": {
|
||||||
|
"context": "table column header",
|
||||||
|
"string": "Product"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_2049070632": {
|
||||||
|
"context": "table column header",
|
||||||
|
"string": "Replace"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_3988345170": {
|
||||||
|
"context": "button",
|
||||||
|
"string": "Set maximal quantities"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_cancelled": {
|
||||||
|
"context": "cancelled fulfillment, section header",
|
||||||
|
"string": "Cancelled ({quantity})"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_description": {
|
||||||
|
"context": "product no longer exists error description",
|
||||||
|
"string": "This product is no longer in database so it can’t be replaced, nor returned"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_fulfilled": {
|
||||||
|
"context": "section header",
|
||||||
|
"string": "Fulfilled ({quantity})"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_improperValue": {
|
||||||
|
"context": "error message",
|
||||||
|
"string": "Improper value"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_refunded": {
|
||||||
|
"context": "refunded fulfillment, section header",
|
||||||
|
"string": "Refunded ({quantity})"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_refundedAndReturned": {
|
||||||
|
"context": "cancelled fulfillment, section header",
|
||||||
|
"string": "Refunded and Returned ({quantity})"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_replaced": {
|
||||||
|
"context": "refunded fulfillment, section header",
|
||||||
|
"string": "Replaced ({quantity})"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_returned": {
|
||||||
|
"context": "refunded fulfillment, section header",
|
||||||
|
"string": "Returned ({quantity})"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_title": {
|
||||||
|
"context": "product no longer exists error title",
|
||||||
|
"string": "Product no longer exists"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_titleFulfilled": {
|
||||||
|
"context": "section header",
|
||||||
|
"string": "Fulfillment - #{fulfilmentId}"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_titleUnfulfilled": {
|
||||||
|
"context": "section header",
|
||||||
|
"string": "Unfulfilled Items"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_unfulfilled": {
|
||||||
|
"context": "section header",
|
||||||
|
"string": "Unfulfilled"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_appTitle": {
|
||||||
|
"context": "page header with order number",
|
||||||
|
"string": "Order #{orderNumber}"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_pageTitle": {
|
||||||
|
"context": "page header",
|
||||||
|
"string": "Order no. {orderNumber} - Replace/Return"
|
||||||
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderSettingsPage_dot_1149215359": {
|
"src_dot_orders_dot_components_dot_OrderSettingsPage_dot_1149215359": {
|
||||||
"context": "header",
|
"context": "header",
|
||||||
"string": "Order settings"
|
"string": "Order settings"
|
||||||
|
@ -3908,34 +4041,10 @@
|
||||||
"context": "dialog header",
|
"context": "dialog header",
|
||||||
"string": "Edit Shipping Method"
|
"string": "Edit Shipping Method"
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderUnfulfilledItems_dot_1134347598": {
|
"src_dot_orders_dot_components_dot_OrderUnfulfilledProductsCard_dot_2095687440": {
|
||||||
"context": "product unit price",
|
|
||||||
"string": "Price"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderUnfulfilledItems_dot_1895667608": {
|
|
||||||
"context": "product name",
|
|
||||||
"string": "Product"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderUnfulfilledItems_dot_2095687440": {
|
|
||||||
"context": "button",
|
"context": "button",
|
||||||
"string": "Fulfill"
|
"string": "Fulfill"
|
||||||
},
|
},
|
||||||
"src_dot_orders_dot_components_dot_OrderUnfulfilledItems_dot_2796503714": {
|
|
||||||
"context": "ordered products",
|
|
||||||
"string": "Quantity"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderUnfulfilledItems_dot_2886647373": {
|
|
||||||
"context": "section header",
|
|
||||||
"string": "Unfulfilled ({quantity})"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderUnfulfilledItems_dot_693960049": {
|
|
||||||
"context": "ordered product sku",
|
|
||||||
"string": "SKU"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_components_dot_OrderUnfulfilledItems_dot_878013594": {
|
|
||||||
"context": "order line total price",
|
|
||||||
"string": "Total"
|
|
||||||
},
|
|
||||||
"src_dot_orders_dot_views_dot_OrderDetails_dot_1039259580": {
|
"src_dot_orders_dot_views_dot_OrderDetails_dot_1039259580": {
|
||||||
"string": "We’re generating the invoice you requested. Please wait a couple of moments"
|
"string": "We’re generating the invoice you requested. Please wait a couple of moments"
|
||||||
},
|
},
|
||||||
|
@ -4025,6 +4134,18 @@
|
||||||
"context": "order refunded success message",
|
"context": "order refunded success message",
|
||||||
"string": "Refunded Items"
|
"string": "Refunded Items"
|
||||||
},
|
},
|
||||||
|
"src_dot_orders_dot_views_dot_OrderReturn_dot_cannotRefundDescription": {
|
||||||
|
"context": "order return error description when cannot refund",
|
||||||
|
"string": "We’ve encountered a problem while refunding the products. Product’s were not refunded. Please try again."
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_views_dot_OrderReturn_dot_cannotRefundTitle": {
|
||||||
|
"context": "order return error title when cannot refund",
|
||||||
|
"string": "Couldn't refund products"
|
||||||
|
},
|
||||||
|
"src_dot_orders_dot_views_dot_OrderReturn_dot_successAlert": {
|
||||||
|
"context": "order returned success message",
|
||||||
|
"string": "Successfully returned products!"
|
||||||
|
},
|
||||||
"src_dot_pageTypes": {
|
"src_dot_pageTypes": {
|
||||||
"context": "page types section name",
|
"context": "page types section name",
|
||||||
"string": "Page Types"
|
"string": "Page Types"
|
||||||
|
@ -4271,6 +4392,10 @@
|
||||||
"context": "payment status",
|
"context": "payment status",
|
||||||
"string": "Partially refunded"
|
"string": "Partially refunded"
|
||||||
},
|
},
|
||||||
|
"src_dot_partiallyReturned": {
|
||||||
|
"context": "order status",
|
||||||
|
"string": "Partially returned"
|
||||||
|
},
|
||||||
"src_dot_permissionGroups": {
|
"src_dot_permissionGroups": {
|
||||||
"context": "permission groups section name",
|
"context": "permission groups section name",
|
||||||
"string": "Permission Groups"
|
"string": "Permission Groups"
|
||||||
|
@ -5306,6 +5431,10 @@
|
||||||
"src_dot_requiredField": {
|
"src_dot_requiredField": {
|
||||||
"string": "This field is required"
|
"string": "This field is required"
|
||||||
},
|
},
|
||||||
|
"src_dot_returned": {
|
||||||
|
"context": "order status",
|
||||||
|
"string": "Returned"
|
||||||
|
},
|
||||||
"src_dot_sales": {
|
"src_dot_sales": {
|
||||||
"context": "sales section name",
|
"context": "sales section name",
|
||||||
"string": "Sales"
|
"string": "Sales"
|
||||||
|
|
|
@ -2006,9 +2006,21 @@ type FulfillmentRefundProducts {
|
||||||
orderErrors: [OrderError!]!
|
orderErrors: [OrderError!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FulfillmentReturnProducts {
|
||||||
|
errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.")
|
||||||
|
returnFulfillment: Fulfillment
|
||||||
|
replaceFulfillment: Fulfillment
|
||||||
|
order: Order
|
||||||
|
replaceOrder: Order
|
||||||
|
orderErrors: [OrderError!]!
|
||||||
|
}
|
||||||
|
|
||||||
enum FulfillmentStatus {
|
enum FulfillmentStatus {
|
||||||
FULFILLED
|
FULFILLED
|
||||||
REFUNDED
|
REFUNDED
|
||||||
|
RETURNED
|
||||||
|
REPLACED
|
||||||
|
REFUNDED_AND_RETURNED
|
||||||
CANCELED
|
CANCELED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2662,6 +2674,7 @@ type Mutation {
|
||||||
orderFulfillmentCancel(id: ID!, input: FulfillmentCancelInput!): FulfillmentCancel
|
orderFulfillmentCancel(id: ID!, input: FulfillmentCancelInput!): FulfillmentCancel
|
||||||
orderFulfillmentUpdateTracking(id: ID!, input: FulfillmentUpdateTrackingInput!): FulfillmentUpdateTracking
|
orderFulfillmentUpdateTracking(id: ID!, input: FulfillmentUpdateTrackingInput!): FulfillmentUpdateTracking
|
||||||
orderFulfillmentRefundProducts(input: OrderRefundProductsInput!, order: ID!): FulfillmentRefundProducts
|
orderFulfillmentRefundProducts(input: OrderRefundProductsInput!, order: ID!): FulfillmentRefundProducts
|
||||||
|
orderFulfillmentReturnProducts(input: OrderReturnProductsInput!, order: ID!): FulfillmentReturnProducts
|
||||||
orderMarkAsPaid(id: ID!, transactionReference: String): OrderMarkAsPaid
|
orderMarkAsPaid(id: ID!, transactionReference: String): OrderMarkAsPaid
|
||||||
orderRefund(amount: PositiveDecimal!, id: ID!): OrderRefund
|
orderRefund(amount: PositiveDecimal!, id: ID!): OrderRefund
|
||||||
orderUpdate(id: ID!, input: OrderUpdateInput!): OrderUpdate
|
orderUpdate(id: ID!, input: OrderUpdateInput!): OrderUpdate
|
||||||
|
@ -2959,8 +2972,7 @@ enum OrderErrorCode {
|
||||||
UNIQUE
|
UNIQUE
|
||||||
VOID_INACTIVE_PAYMENT
|
VOID_INACTIVE_PAYMENT
|
||||||
ZERO_QUANTITY
|
ZERO_QUANTITY
|
||||||
INVALID_REFUND_QUANTITY
|
INVALID_QUANTITY
|
||||||
CANNOT_REFUND_FULFILLMENT_LINE
|
|
||||||
INSUFFICIENT_STOCK
|
INSUFFICIENT_STOCK
|
||||||
DUPLICATED_INPUT_ITEM
|
DUPLICATED_INPUT_ITEM
|
||||||
NOT_AVAILABLE_IN_CHANNEL
|
NOT_AVAILABLE_IN_CHANNEL
|
||||||
|
@ -2988,6 +3000,7 @@ type OrderEvent implements Node {
|
||||||
warehouse: Warehouse
|
warehouse: Warehouse
|
||||||
transactionReference: String
|
transactionReference: String
|
||||||
shippingCostsIncluded: Boolean
|
shippingCostsIncluded: Boolean
|
||||||
|
relatedOrder: Order
|
||||||
}
|
}
|
||||||
|
|
||||||
type OrderEventCountableConnection {
|
type OrderEventCountableConnection {
|
||||||
|
@ -3021,6 +3034,7 @@ enum OrderEventsEmailsEnum {
|
||||||
|
|
||||||
enum OrderEventsEnum {
|
enum OrderEventsEnum {
|
||||||
DRAFT_CREATED
|
DRAFT_CREATED
|
||||||
|
DRAFT_CREATED_FROM_REPLACE
|
||||||
DRAFT_ADDED_PRODUCTS
|
DRAFT_ADDED_PRODUCTS
|
||||||
DRAFT_REMOVED_PRODUCTS
|
DRAFT_REMOVED_PRODUCTS
|
||||||
PLACED
|
PLACED
|
||||||
|
@ -3029,6 +3043,7 @@ enum OrderEventsEnum {
|
||||||
CANCELED
|
CANCELED
|
||||||
ORDER_MARKED_AS_PAID
|
ORDER_MARKED_AS_PAID
|
||||||
ORDER_FULLY_PAID
|
ORDER_FULLY_PAID
|
||||||
|
ORDER_REPLACEMENT_CREATED
|
||||||
UPDATED_ADDRESS
|
UPDATED_ADDRESS
|
||||||
EMAIL_SENT
|
EMAIL_SENT
|
||||||
CONFIRMED
|
CONFIRMED
|
||||||
|
@ -3046,6 +3061,8 @@ enum OrderEventsEnum {
|
||||||
FULFILLMENT_RESTOCKED_ITEMS
|
FULFILLMENT_RESTOCKED_ITEMS
|
||||||
FULFILLMENT_FULFILLED_ITEMS
|
FULFILLMENT_FULFILLED_ITEMS
|
||||||
FULFILLMENT_REFUNDED
|
FULFILLMENT_REFUNDED
|
||||||
|
FULFILLMENT_RETURNED
|
||||||
|
FULFILLMENT_REPLACED
|
||||||
TRACKING_UPDATED
|
TRACKING_UPDATED
|
||||||
NOTE_ADDED
|
NOTE_ADDED
|
||||||
OTHER
|
OTHER
|
||||||
|
@ -3139,6 +3156,26 @@ input OrderRefundProductsInput {
|
||||||
includeShippingCosts: Boolean = false
|
includeShippingCosts: Boolean = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input OrderReturnFulfillmentLineInput {
|
||||||
|
fulfillmentLineId: ID!
|
||||||
|
quantity: Int!
|
||||||
|
replace: Boolean = false
|
||||||
|
}
|
||||||
|
|
||||||
|
input OrderReturnLineInput {
|
||||||
|
orderLineId: ID!
|
||||||
|
quantity: Int!
|
||||||
|
replace: Boolean = false
|
||||||
|
}
|
||||||
|
|
||||||
|
input OrderReturnProductsInput {
|
||||||
|
orderLines: [OrderReturnLineInput!]
|
||||||
|
fulfillmentLines: [OrderReturnFulfillmentLineInput!]
|
||||||
|
amountToRefund: PositiveDecimal
|
||||||
|
includeShippingCosts: Boolean = false
|
||||||
|
refund: Boolean = false
|
||||||
|
}
|
||||||
|
|
||||||
type OrderSettings {
|
type OrderSettings {
|
||||||
automaticallyConfirmAllNewOrders: Boolean!
|
automaticallyConfirmAllNewOrders: Boolean!
|
||||||
}
|
}
|
||||||
|
@ -3181,6 +3218,8 @@ enum OrderStatus {
|
||||||
UNCONFIRMED
|
UNCONFIRMED
|
||||||
UNFULFILLED
|
UNFULFILLED
|
||||||
PARTIALLY_FULFILLED
|
PARTIALLY_FULFILLED
|
||||||
|
PARTIALLY_RETURNED
|
||||||
|
RETURNED
|
||||||
FULFILLED
|
FULFILLED
|
||||||
CANCELED
|
CANCELED
|
||||||
}
|
}
|
||||||
|
@ -5819,4 +5858,4 @@ union _Entity = Address | User | Group | App | ProductVariant | Product | Produc
|
||||||
|
|
||||||
type _Service {
|
type _Service {
|
||||||
sdl: String
|
sdl: String
|
||||||
}
|
}
|
|
@ -19,11 +19,14 @@ const useStyles = makeStyles(
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
alertDot: {
|
||||||
|
"&:before": { backgroundColor: yellow[500], ...dot }
|
||||||
|
},
|
||||||
errorDot: {
|
errorDot: {
|
||||||
"&:before": { backgroundColor: theme.palette.error.main, ...dot }
|
"&:before": { backgroundColor: theme.palette.error.main, ...dot }
|
||||||
},
|
},
|
||||||
neutralDot: {
|
neutralDot: {
|
||||||
"&:before": { backgroundColor: yellow[500], ...dot }
|
"&:before": { backgroundColor: grey[300], ...dot }
|
||||||
},
|
},
|
||||||
root: {
|
root: {
|
||||||
display: "inline-block",
|
display: "inline-block",
|
||||||
|
@ -35,9 +38,6 @@ const useStyles = makeStyles(
|
||||||
},
|
},
|
||||||
successDot: {
|
successDot: {
|
||||||
"&:before": { backgroundColor: theme.palette.primary.main, ...dot }
|
"&:before": { backgroundColor: theme.palette.primary.main, ...dot }
|
||||||
},
|
|
||||||
unspecifiedDot: {
|
|
||||||
"&:before": { backgroundColor: grey[500], ...dot }
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -47,7 +47,7 @@ const useStyles = makeStyles(
|
||||||
interface StatusLabelProps {
|
interface StatusLabelProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
label: string | React.ReactNode;
|
label: string | React.ReactNode;
|
||||||
status: "success" | "neutral" | "unspecified" | "error" | string;
|
status: "success" | "alert" | "neutral" | "error" | string;
|
||||||
typographyProps?: TypographyProps;
|
typographyProps?: TypographyProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,8 +62,8 @@ const StatusLabel: React.FC<StatusLabelProps> = props => {
|
||||||
[classes.root]: true,
|
[classes.root]: true,
|
||||||
[className]: true,
|
[className]: true,
|
||||||
[classes.successDot]: status === "success",
|
[classes.successDot]: status === "success",
|
||||||
|
[classes.alertDot]: status === "alert",
|
||||||
[classes.neutralDot]: status === "neutral",
|
[classes.neutralDot]: status === "neutral",
|
||||||
[classes.unspecifiedDot]: status === "unspecified",
|
|
||||||
[classes.errorDot]: status === "error"
|
[classes.errorDot]: status === "error"
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
|
|
@ -77,7 +77,7 @@ export const light: IThemeColors = {
|
||||||
default: "#616161"
|
default: "#616161"
|
||||||
},
|
},
|
||||||
divider: "#EAEAEA",
|
divider: "#EAEAEA",
|
||||||
error: "#C22D74",
|
error: "#FE6D76",
|
||||||
font: {
|
font: {
|
||||||
button: "#FFFFFF",
|
button: "#FFFFFF",
|
||||||
default: "#3D3D3D",
|
default: "#3D3D3D",
|
||||||
|
|
|
@ -4,30 +4,12 @@ import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||||
import classNames from "classnames";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { DateTime } from "../Date";
|
import TimelineEventHeader, { TitleElement } from "./TimelineEventHeader";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
container: {
|
|
||||||
alignItems: "center",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
marginBottom: theme.spacing(),
|
|
||||||
marginLeft: theme.spacing(3),
|
|
||||||
width: "100%"
|
|
||||||
},
|
|
||||||
date: {
|
|
||||||
color: theme.typography.caption.color
|
|
||||||
},
|
|
||||||
dateExpander: {
|
|
||||||
color: theme.typography.caption.color,
|
|
||||||
position: "absolute",
|
|
||||||
right: 0
|
|
||||||
},
|
|
||||||
dot: {
|
dot: {
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: theme.palette.primary.main,
|
||||||
borderRadius: "100%",
|
borderRadius: "100%",
|
||||||
|
@ -37,27 +19,27 @@ const useStyles = makeStyles(
|
||||||
top: 6,
|
top: 6,
|
||||||
width: 8
|
width: 8
|
||||||
},
|
},
|
||||||
expanded: {},
|
|
||||||
noExpander: {
|
|
||||||
alignItems: "center",
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
width: "100%"
|
|
||||||
},
|
|
||||||
panel: {
|
panel: {
|
||||||
"&$expanded": {
|
"& .MuiExpansionPanelDetails-root": {
|
||||||
margin: 0
|
padding: 0,
|
||||||
|
paddingTop: theme.spacing(2)
|
||||||
|
},
|
||||||
|
"&.Mui-expanded": {
|
||||||
|
borderColor: "red",
|
||||||
|
margin: 0,
|
||||||
|
minHeight: 0
|
||||||
},
|
},
|
||||||
"&:before": {
|
"&:before": {
|
||||||
display: "none"
|
display: "none"
|
||||||
},
|
},
|
||||||
background: "none",
|
background: "none",
|
||||||
|
display: "",
|
||||||
margin: 0,
|
margin: 0,
|
||||||
|
minHeight: 0,
|
||||||
width: "100%"
|
width: "100%"
|
||||||
},
|
},
|
||||||
panelExpander: {
|
panelExpander: {
|
||||||
"&$expanded": {
|
"&.MuiExpansionPanelSummary-root.Mui-expanded": {
|
||||||
margin: 0,
|
|
||||||
minHeight: 0
|
minHeight: 0
|
||||||
},
|
},
|
||||||
"&> .MuiExpansionPanelSummary-content": {
|
"&> .MuiExpansionPanelSummary-content": {
|
||||||
|
@ -65,9 +47,12 @@ const useStyles = makeStyles(
|
||||||
},
|
},
|
||||||
"&> .MuiExpansionPanelSummary-expandIcon": {
|
"&> .MuiExpansionPanelSummary-expandIcon": {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
|
position: "absolute",
|
||||||
right: theme.spacing(18)
|
right: theme.spacing(18)
|
||||||
},
|
},
|
||||||
margin: 0
|
margin: 0,
|
||||||
|
minHeight: 0,
|
||||||
|
padding: 0
|
||||||
},
|
},
|
||||||
root: {
|
root: {
|
||||||
"&:last-child:after": {
|
"&:last-child:after": {
|
||||||
|
@ -82,27 +67,24 @@ const useStyles = makeStyles(
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
marginBottom: theme.spacing(3),
|
marginBottom: theme.spacing(3),
|
||||||
|
marginTop: 0,
|
||||||
position: "relative",
|
position: "relative",
|
||||||
width: "100%"
|
width: "100%"
|
||||||
},
|
|
||||||
secondaryTitle: {
|
|
||||||
color: "#9e9e9e",
|
|
||||||
fontSize: 14,
|
|
||||||
marginTop: theme.spacing(2)
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{ name: "TimelineEvent" }
|
{ name: "TimelineEvent" }
|
||||||
);
|
);
|
||||||
|
|
||||||
interface TimelineEventProps {
|
export interface TimelineEventProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
date: string;
|
date: string;
|
||||||
secondaryTitle?: string;
|
secondaryTitle?: string;
|
||||||
title: string;
|
title?: string;
|
||||||
|
titleElements?: TitleElement[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TimelineEvent: React.FC<TimelineEventProps> = props => {
|
export const TimelineEvent: React.FC<TimelineEventProps> = props => {
|
||||||
const { children, date, secondaryTitle, title } = props;
|
const { children, date, secondaryTitle, title, titleElements } = props;
|
||||||
|
|
||||||
const classes = useStyles(props);
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
@ -110,39 +92,28 @@ export const TimelineEvent: React.FC<TimelineEventProps> = props => {
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<span className={classes.dot} />
|
<span className={classes.dot} />
|
||||||
{children ? (
|
{children ? (
|
||||||
<ExpansionPanel
|
<ExpansionPanel className={classes.panel} elevation={0}>
|
||||||
className={classNames(classes.panel, classes.expanded)}
|
|
||||||
elevation={0}
|
|
||||||
>
|
|
||||||
<ExpansionPanelSummary
|
<ExpansionPanelSummary
|
||||||
className={classNames(classes.panelExpander, classes.expanded)}
|
className={classes.panelExpander}
|
||||||
expandIcon={<ExpandMoreIcon />}
|
expandIcon={<ExpandMoreIcon />}
|
||||||
>
|
>
|
||||||
<Typography>{title}</Typography>
|
<TimelineEventHeader
|
||||||
<Typography className={classes.dateExpander}>
|
title={title}
|
||||||
<DateTime date={date} />
|
date={date}
|
||||||
</Typography>
|
titleElements={titleElements}
|
||||||
|
/>
|
||||||
</ExpansionPanelSummary>
|
</ExpansionPanelSummary>
|
||||||
<ExpansionPanelDetails>
|
<ExpansionPanelDetails>
|
||||||
<Typography>{children}</Typography>
|
<Typography>{children}</Typography>
|
||||||
</ExpansionPanelDetails>
|
</ExpansionPanelDetails>
|
||||||
</ExpansionPanel>
|
</ExpansionPanel>
|
||||||
) : (
|
) : (
|
||||||
<div className={classes.container}>
|
<TimelineEventHeader
|
||||||
<div className={classes.noExpander}>
|
title={title}
|
||||||
<Typography>{title}</Typography>
|
titleElements={titleElements}
|
||||||
<Typography className={classes.date}>
|
secondaryTitle={secondaryTitle}
|
||||||
<DateTime date={date} />
|
date={date}
|
||||||
</Typography>
|
/>
|
||||||
</div>
|
|
||||||
{secondaryTitle && (
|
|
||||||
<div className={classes.noExpander}>
|
|
||||||
<Typography className={classes.secondaryTitle}>
|
|
||||||
{secondaryTitle}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
93
src/components/Timeline/TimelineEventHeader.tsx
Normal file
93
src/components/Timeline/TimelineEventHeader.tsx
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { DateTime } from "../Date";
|
||||||
|
import Link from "../Link";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
container: {
|
||||||
|
alignItems: "center",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
width: "100%"
|
||||||
|
},
|
||||||
|
date: {
|
||||||
|
color: theme.typography.caption.color,
|
||||||
|
paddingLeft: 24
|
||||||
|
},
|
||||||
|
elementsContainer: {
|
||||||
|
alignItems: "center",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
flexWrap: "wrap"
|
||||||
|
},
|
||||||
|
secondaryTitle: {
|
||||||
|
color: "#9e9e9e",
|
||||||
|
fontSize: 14,
|
||||||
|
marginTop: theme.spacing(2)
|
||||||
|
},
|
||||||
|
titleElement: {
|
||||||
|
marginRight: "0.5rem"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "TimelineEventHeader" }
|
||||||
|
);
|
||||||
|
|
||||||
|
export interface TitleElement {
|
||||||
|
text: string;
|
||||||
|
link?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimelineEventHeaderProps {
|
||||||
|
title?: string;
|
||||||
|
date: string;
|
||||||
|
titleElements?: TitleElement[];
|
||||||
|
secondaryTitle?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TimelineEventHeader: React.FC<TimelineEventHeaderProps> = props => {
|
||||||
|
const { title, date, titleElements, secondaryTitle } = props;
|
||||||
|
const navigate = useNavigator();
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.container}>
|
||||||
|
{title && <Typography>{title}</Typography>}
|
||||||
|
{titleElements && (
|
||||||
|
<div className={classes.elementsContainer}>
|
||||||
|
{titleElements.map(({ text, link }) => {
|
||||||
|
if (link) {
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
className={classes.titleElement}
|
||||||
|
onClick={() => navigate(link)}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Typography className={classes.titleElement}>{text}</Typography>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Typography className={classes.date}>
|
||||||
|
<DateTime date={date} />
|
||||||
|
</Typography>
|
||||||
|
{secondaryTitle && (
|
||||||
|
<Typography className={classes.secondaryTitle}>
|
||||||
|
{secondaryTitle}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TimelineEventHeader;
|
|
@ -12,6 +12,10 @@ export const fragmentOrderEvent = gql`
|
||||||
email
|
email
|
||||||
emailType
|
emailType
|
||||||
invoiceNumber
|
invoiceNumber
|
||||||
|
relatedOrder {
|
||||||
|
id
|
||||||
|
number
|
||||||
|
}
|
||||||
message
|
message
|
||||||
quantity
|
quantity
|
||||||
transactionReference
|
transactionReference
|
||||||
|
@ -19,6 +23,8 @@ export const fragmentOrderEvent = gql`
|
||||||
user {
|
user {
|
||||||
id
|
id
|
||||||
email
|
email
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
}
|
}
|
||||||
lines {
|
lines {
|
||||||
quantity
|
quantity
|
||||||
|
|
|
@ -42,10 +42,18 @@ export interface OrderDetailsFragment_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderDetailsFragment_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderDetailsFragment_events_user {
|
export interface OrderDetailsFragment_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderDetailsFragment_events_lines_orderLine {
|
export interface OrderDetailsFragment_events_lines_orderLine {
|
||||||
|
@ -70,6 +78,7 @@ export interface OrderDetailsFragment_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderDetailsFragment_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -8,10 +8,18 @@ import { OrderEventsEmailsEnum, OrderEventsEnum } from "./../../types/globalType
|
||||||
// GraphQL fragment: OrderEventFragment
|
// GraphQL fragment: OrderEventFragment
|
||||||
// ====================================================
|
// ====================================================
|
||||||
|
|
||||||
|
export interface OrderEventFragment_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderEventFragment_user {
|
export interface OrderEventFragment_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderEventFragment_lines_orderLine {
|
export interface OrderEventFragment_lines_orderLine {
|
||||||
|
@ -36,6 +44,7 @@ export interface OrderEventFragment {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderEventFragment_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
25
src/icons/ErrorExclamationCircle.tsx
Normal file
25
src/icons/ErrorExclamationCircle.tsx
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import createSvgIcon from "@material-ui/icons/utils/createSvgIcon";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const ErrorExclamationCircle = createSvgIcon(
|
||||||
|
<>
|
||||||
|
<svg
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<circle cx="12" cy="12" r="12" fill="#FE6D76" />
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M12.75 6H11.25V15H12.75V6ZM12.75 16.5H11.25V18H12.75V16.5Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</>,
|
||||||
|
"ErrorExclamationCircle"
|
||||||
|
);
|
||||||
|
|
||||||
|
export default ErrorExclamationCircle;
|
18
src/misc.ts
18
src/misc.ts
|
@ -136,6 +136,10 @@ export const orderStatusMessages = defineMessages({
|
||||||
defaultMessage: "Partially fulfilled",
|
defaultMessage: "Partially fulfilled",
|
||||||
description: "order status"
|
description: "order status"
|
||||||
},
|
},
|
||||||
|
partiallyReturned: {
|
||||||
|
defaultMessage: "Partially returned",
|
||||||
|
description: "order status"
|
||||||
|
},
|
||||||
readyToCapture: {
|
readyToCapture: {
|
||||||
defaultMessage: "Ready to capture",
|
defaultMessage: "Ready to capture",
|
||||||
description: "order status"
|
description: "order status"
|
||||||
|
@ -144,6 +148,10 @@ export const orderStatusMessages = defineMessages({
|
||||||
defaultMessage: "Ready to fulfill",
|
defaultMessage: "Ready to fulfill",
|
||||||
description: "order status"
|
description: "order status"
|
||||||
},
|
},
|
||||||
|
returned: {
|
||||||
|
defaultMessage: "Returned",
|
||||||
|
description: "order status"
|
||||||
|
},
|
||||||
unconfirmed: {
|
unconfirmed: {
|
||||||
defaultMessage: "Unconfirmed",
|
defaultMessage: "Unconfirmed",
|
||||||
description: "order status"
|
description: "order status"
|
||||||
|
@ -189,6 +197,16 @@ export const transformOrderStatus = (
|
||||||
localized: intl.formatMessage(orderStatusMessages.unconfirmed),
|
localized: intl.formatMessage(orderStatusMessages.unconfirmed),
|
||||||
status: StatusType.NEUTRAL
|
status: StatusType.NEUTRAL
|
||||||
};
|
};
|
||||||
|
case OrderStatus.PARTIALLY_RETURNED:
|
||||||
|
return {
|
||||||
|
localized: intl.formatMessage(orderStatusMessages.partiallyReturned),
|
||||||
|
status: StatusType.NEUTRAL
|
||||||
|
};
|
||||||
|
case OrderStatus.RETURNED:
|
||||||
|
return {
|
||||||
|
localized: intl.formatMessage(orderStatusMessages.returned),
|
||||||
|
status: StatusType.NEUTRAL
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
localized: status,
|
localized: status,
|
||||||
|
|
|
@ -19,19 +19,20 @@ import { UserPermissionProps } from "@saleor/types";
|
||||||
import { mapMetadataItemToInput } from "@saleor/utils/maps";
|
import { mapMetadataItemToInput } from "@saleor/utils/maps";
|
||||||
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
|
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { defineMessages, useIntl } from "react-intl";
|
||||||
|
|
||||||
import { maybe, renderCollection } from "../../../misc";
|
import { maybe } from "../../../misc";
|
||||||
import { OrderStatus } from "../../../types/globalTypes";
|
import { OrderStatus } from "../../../types/globalTypes";
|
||||||
import { OrderDetails_order } from "../../types/OrderDetails";
|
import { OrderDetails_order } from "../../types/OrderDetails";
|
||||||
import OrderCustomer from "../OrderCustomer";
|
import OrderCustomer from "../OrderCustomer";
|
||||||
import OrderCustomerNote from "../OrderCustomerNote";
|
import OrderCustomerNote from "../OrderCustomerNote";
|
||||||
import OrderFulfillment from "../OrderFulfillment";
|
import OrderFulfilledProductsCard from "../OrderFulfilledProductsCard";
|
||||||
import OrderHistory, { FormData as HistoryFormData } from "../OrderHistory";
|
import OrderHistory, { FormData as HistoryFormData } from "../OrderHistory";
|
||||||
import OrderInvoiceList from "../OrderInvoiceList";
|
import OrderInvoiceList from "../OrderInvoiceList";
|
||||||
import OrderPayment from "../OrderPayment/OrderPayment";
|
import OrderPayment from "../OrderPayment/OrderPayment";
|
||||||
import OrderUnfulfilledItems from "../OrderUnfulfilledItems/OrderUnfulfilledItems";
|
import OrderUnfulfilledProductsCard from "../OrderUnfulfilledProductsCard";
|
||||||
import Title from "./Title";
|
import Title from "./Title";
|
||||||
|
import { filteredConditionalItems, hasAnyItemsReplaceable } from "./utils";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
|
@ -75,12 +76,28 @@ export interface OrderDetailsPageProps extends UserPermissionProps {
|
||||||
onOrderCancel();
|
onOrderCancel();
|
||||||
onNoteAdd(data: HistoryFormData);
|
onNoteAdd(data: HistoryFormData);
|
||||||
onProfileView();
|
onProfileView();
|
||||||
|
onOrderReturn();
|
||||||
onInvoiceClick(invoiceId: string);
|
onInvoiceClick(invoiceId: string);
|
||||||
onInvoiceGenerate();
|
onInvoiceGenerate();
|
||||||
onInvoiceSend(invoiceId: string);
|
onInvoiceSend(invoiceId: string);
|
||||||
onSubmit(data: MetadataFormData): SubmitPromise;
|
onSubmit(data: MetadataFormData): SubmitPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
cancelOrder: {
|
||||||
|
defaultMessage: "Cancel order",
|
||||||
|
description: "cancel button"
|
||||||
|
},
|
||||||
|
confirmOrder: {
|
||||||
|
defaultMessage: "Confirm order",
|
||||||
|
description: "save button"
|
||||||
|
},
|
||||||
|
returnOrder: {
|
||||||
|
defaultMessage: "Return / Replace order",
|
||||||
|
description: "return button"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
|
const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
|
||||||
const {
|
const {
|
||||||
disabled,
|
disabled,
|
||||||
|
@ -103,6 +120,7 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
|
||||||
onInvoiceClick,
|
onInvoiceClick,
|
||||||
onInvoiceGenerate,
|
onInvoiceGenerate,
|
||||||
onInvoiceSend,
|
onInvoiceSend,
|
||||||
|
onOrderReturn,
|
||||||
onSubmit
|
onSubmit
|
||||||
} = props;
|
} = props;
|
||||||
const classes = useStyles(props);
|
const classes = useStyles(props);
|
||||||
|
@ -140,10 +158,7 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
|
||||||
|
|
||||||
const saveLabel =
|
const saveLabel =
|
||||||
order?.status === OrderStatus.UNCONFIRMED
|
order?.status === OrderStatus.UNCONFIRMED
|
||||||
? intl.formatMessage({
|
? intl.formatMessage(messages.confirmOrder)
|
||||||
defaultMessage: "confirm order",
|
|
||||||
description: "save button"
|
|
||||||
})
|
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const allowSave = (hasChanged: boolean) => {
|
const allowSave = (hasChanged: boolean) => {
|
||||||
|
@ -154,6 +169,23 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
|
||||||
return disabled;
|
return disabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const selectCardMenuItems = filteredConditionalItems([
|
||||||
|
{
|
||||||
|
item: {
|
||||||
|
label: intl.formatMessage(messages.cancelOrder),
|
||||||
|
onSelect: onOrderCancel
|
||||||
|
},
|
||||||
|
shouldExist: canCancel
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: {
|
||||||
|
label: intl.formatMessage(messages.returnOrder),
|
||||||
|
onSelect: onOrderReturn
|
||||||
|
},
|
||||||
|
shouldExist: hasAnyItemsReplaceable(order)
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form initial={initial} onSubmit={handleSubmit}>
|
<Form initial={initial} onSubmit={handleSubmit}>
|
||||||
{({ change, data, hasChanged, submit }) => {
|
{({ change, data, hasChanged, submit }) => {
|
||||||
|
@ -169,19 +201,7 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
|
||||||
inline
|
inline
|
||||||
title={<Title order={order} />}
|
title={<Title order={order} />}
|
||||||
>
|
>
|
||||||
{canCancel && (
|
<CardMenu menuItems={selectCardMenuItems} />
|
||||||
<CardMenu
|
|
||||||
menuItems={[
|
|
||||||
{
|
|
||||||
label: intl.formatMessage({
|
|
||||||
defaultMessage: "Cancel order",
|
|
||||||
description: "button"
|
|
||||||
}),
|
|
||||||
onSelect: onOrderCancel
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<div className={classes.date}>
|
<div className={classes.date}>
|
||||||
{order && order.created ? (
|
{order && order.created ? (
|
||||||
|
@ -194,36 +214,26 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
|
||||||
</div>
|
</div>
|
||||||
<Grid>
|
<Grid>
|
||||||
<div>
|
<div>
|
||||||
{unfulfilled.length > 0 && (
|
<OrderUnfulfilledProductsCard
|
||||||
<OrderUnfulfilledItems
|
canFulfill={canFulfill}
|
||||||
canFulfill={canFulfill}
|
lines={unfulfilled}
|
||||||
lines={unfulfilled}
|
onFulfill={onOrderFulfill}
|
||||||
onFulfill={onOrderFulfill}
|
/>
|
||||||
/>
|
{order?.fulfillments?.map(fulfillment => (
|
||||||
)}
|
<React.Fragment key={fulfillment.id}>
|
||||||
{renderCollection(
|
<OrderFulfilledProductsCard
|
||||||
maybe(() => order.fulfillments),
|
fulfillment={fulfillment}
|
||||||
(fulfillment, fulfillmentIndex) => (
|
orderNumber={order.number}
|
||||||
<React.Fragment
|
onOrderFulfillmentCancel={() =>
|
||||||
key={maybe(() => fulfillment.id, "loading")}
|
onFulfillmentCancel(fulfillment.id)
|
||||||
>
|
}
|
||||||
{!(
|
onTrackingCodeAdd={() =>
|
||||||
unfulfilled.length === 0 && fulfillmentIndex === 0
|
onFulfillmentTrackingNumberUpdate(fulfillment.id)
|
||||||
) && <CardSpacer />}
|
}
|
||||||
<OrderFulfillment
|
onRefund={onPaymentRefund}
|
||||||
fulfillment={fulfillment}
|
/>
|
||||||
orderNumber={maybe(() => order.number)}
|
</React.Fragment>
|
||||||
onOrderFulfillmentCancel={() =>
|
))}
|
||||||
onFulfillmentCancel(fulfillment.id)
|
|
||||||
}
|
|
||||||
onTrackingCodeAdd={() =>
|
|
||||||
onFulfillmentTrackingNumberUpdate(fulfillment.id)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
<CardSpacer />
|
|
||||||
<OrderPayment
|
<OrderPayment
|
||||||
order={order}
|
order={order}
|
||||||
onCapture={onPaymentCapture}
|
onCapture={onPaymentCapture}
|
||||||
|
@ -281,5 +291,6 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
OrderDetailsPage.displayName = "OrderDetailsPage";
|
OrderDetailsPage.displayName = "OrderDetailsPage";
|
||||||
export default OrderDetailsPage;
|
export default OrderDetailsPage;
|
||||||
|
|
44
src/orders/components/OrderDetailsPage/utils.test.tsx
Normal file
44
src/orders/components/OrderDetailsPage/utils.test.tsx
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import { filteredConditionalItems } from "./utils";
|
||||||
|
|
||||||
|
describe("filteredConditionalItems", () => {
|
||||||
|
it("should return empty [] when no items has shouldExist set to true", () => {
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
item: { id: "#1" },
|
||||||
|
shouldExist: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: { id: "#2" },
|
||||||
|
shouldExist: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: { id: "#3" },
|
||||||
|
shouldExist: false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(filteredConditionalItems(items)).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return only items that has shouldExist set to true", () => {
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
item: { id: "#1" },
|
||||||
|
shouldExist: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: { id: "#2" },
|
||||||
|
shouldExist: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: { id: "#3" },
|
||||||
|
shouldExist: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(filteredConditionalItems(items)).toEqual([
|
||||||
|
{ id: "#2" },
|
||||||
|
{ id: "#3" }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
26
src/orders/components/OrderDetailsPage/utils.ts
Normal file
26
src/orders/components/OrderDetailsPage/utils.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import { OrderDetails_order } from "@saleor/orders/types/OrderDetails";
|
||||||
|
|
||||||
|
import {
|
||||||
|
getFulfilledFulfillemnts,
|
||||||
|
getUnfulfilledLines
|
||||||
|
} from "../OrderReturnPage/utils";
|
||||||
|
|
||||||
|
export const hasAnyItemsReplaceable = (order?: OrderDetails_order) => {
|
||||||
|
if (!order) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasAnyUnfulfilledItems = getUnfulfilledLines(order).length > 0;
|
||||||
|
|
||||||
|
const hasAnyFulfilmentsToReturn = getFulfilledFulfillemnts(order).length > 0;
|
||||||
|
|
||||||
|
return hasAnyUnfulfilledItems || hasAnyFulfilmentsToReturn;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ConditionalItem {
|
||||||
|
shouldExist: boolean;
|
||||||
|
item: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const filteredConditionalItems = (items: ConditionalItem[]) =>
|
||||||
|
items.filter(({ shouldExist }) => shouldExist).map(({ item }) => item);
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { Button, CardActions } from "@material-ui/core";
|
||||||
|
import { FulfillmentStatus } from "@saleor/types/globalTypes";
|
||||||
|
import React from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
interface AcionButtonsProps {
|
||||||
|
status: FulfillmentStatus;
|
||||||
|
trackingNumber?: string;
|
||||||
|
onTrackingCodeAdd();
|
||||||
|
onRefund();
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusesToShow = [
|
||||||
|
FulfillmentStatus.FULFILLED,
|
||||||
|
FulfillmentStatus.RETURNED
|
||||||
|
];
|
||||||
|
|
||||||
|
const ActionButtons: React.FC<AcionButtonsProps> = ({
|
||||||
|
status,
|
||||||
|
onTrackingCodeAdd,
|
||||||
|
trackingNumber,
|
||||||
|
onRefund
|
||||||
|
}) => {
|
||||||
|
const hasTrackingNumber = !!trackingNumber;
|
||||||
|
|
||||||
|
if (!statusesToShow.includes(status)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === FulfillmentStatus.RETURNED) {
|
||||||
|
return (
|
||||||
|
<CardActions>
|
||||||
|
<Button color="primary" onClick={onRefund}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Refund"
|
||||||
|
description="refund button"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</CardActions>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasTrackingNumber ? (
|
||||||
|
<CardActions>
|
||||||
|
<Button color="primary" onClick={onTrackingCodeAdd}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Edit tracking"
|
||||||
|
description="edit tracking button"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</CardActions>
|
||||||
|
) : (
|
||||||
|
<CardActions>
|
||||||
|
<Button color="primary" onClick={onTrackingCodeAdd}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Add tracking"
|
||||||
|
description="add tracking button"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</CardActions>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ActionButtons;
|
|
@ -0,0 +1,103 @@
|
||||||
|
import { makeStyles, TableCell, TableRow, Typography } from "@material-ui/core";
|
||||||
|
import { getStringOrPlaceholder } from "@saleor/misc";
|
||||||
|
import { FulfillmentStatus } from "@saleor/types/globalTypes";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import React from "react";
|
||||||
|
import { defineMessages, useIntl } from "react-intl";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
import { OrderDetails_order_fulfillments } from "../../types/OrderDetails";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
infoLabel: {
|
||||||
|
display: "inline-block"
|
||||||
|
},
|
||||||
|
infoLabelWithMargin: {
|
||||||
|
marginBottom: theme.spacing()
|
||||||
|
},
|
||||||
|
infoRow: {
|
||||||
|
padding: theme.spacing(2, 3)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "ExtraInfoLines" }
|
||||||
|
);
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
fulfilled: {
|
||||||
|
defaultMessage: "Fulfilled from: ",
|
||||||
|
description: "fulfillment group"
|
||||||
|
},
|
||||||
|
restocked: {
|
||||||
|
defaultMessage: "Restocked from: ",
|
||||||
|
description: "restocked group"
|
||||||
|
},
|
||||||
|
tracking: {
|
||||||
|
defaultMessage: "Tracking Number: {trackingNumber}",
|
||||||
|
description: "tracking number"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const NUMBER_OF_COLUMNS = 5;
|
||||||
|
|
||||||
|
interface ExtraInfoLinesProps {
|
||||||
|
fulfillment?: OrderDetails_order_fulfillments;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ExtraInfoLines: React.FC<ExtraInfoLinesProps> = ({ fulfillment }) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const classes = useStyles({});
|
||||||
|
|
||||||
|
if (!fulfillment || !fulfillment?.warehouse || !fulfillment?.trackingNumber) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { warehouse, trackingNumber, status } = fulfillment;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell className={classes.infoRow} colSpan={NUMBER_OF_COLUMNS}>
|
||||||
|
<Typography color="textSecondary" variant="body2">
|
||||||
|
{warehouse && (
|
||||||
|
<>
|
||||||
|
{intl.formatMessage(
|
||||||
|
status === FulfillmentStatus.RETURNED
|
||||||
|
? messages.restocked
|
||||||
|
: messages.fulfilled
|
||||||
|
)}
|
||||||
|
<Typography
|
||||||
|
className={classNames(classes.infoLabel, {
|
||||||
|
[classes.infoLabelWithMargin]: !!trackingNumber
|
||||||
|
})}
|
||||||
|
color="textPrimary"
|
||||||
|
variant="body2"
|
||||||
|
>
|
||||||
|
{getStringOrPlaceholder(warehouse?.name)}
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
|
<Typography color="textSecondary" variant="body2">
|
||||||
|
{trackingNumber && (
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Tracking Number: {trackingNumber}"
|
||||||
|
values={{
|
||||||
|
trackingNumber: (
|
||||||
|
<Typography
|
||||||
|
className={classes.infoLabel}
|
||||||
|
color="textPrimary"
|
||||||
|
variant="body2"
|
||||||
|
>
|
||||||
|
{trackingNumber}
|
||||||
|
</Typography>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ExtraInfoLines;
|
|
@ -0,0 +1,114 @@
|
||||||
|
import Card from "@material-ui/core/Card";
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
import TableBody from "@material-ui/core/TableBody";
|
||||||
|
import CardMenu from "@saleor/components/CardMenu";
|
||||||
|
import CardSpacer from "@saleor/components/CardSpacer";
|
||||||
|
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||||
|
import { mergeRepeatedOrderLines } from "@saleor/orders/utils/data";
|
||||||
|
import React from "react";
|
||||||
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import { maybe, renderCollection } from "../../../misc";
|
||||||
|
import { FulfillmentStatus } from "../../../types/globalTypes";
|
||||||
|
import { OrderDetails_order_fulfillments } from "../../types/OrderDetails";
|
||||||
|
import TableHeader from "../OrderProductsCardElements/OrderProductsCardHeader";
|
||||||
|
import TableLine from "../OrderProductsCardElements/OrderProductsTableRow";
|
||||||
|
import CardTitle from "../OrderReturnPage/OrderReturnRefundItemsCard/CardTitle";
|
||||||
|
import ActionButtons from "./ActionButtons";
|
||||||
|
import ExtraInfoLines from "./ExtraInfoLines";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
() => ({
|
||||||
|
table: {
|
||||||
|
tableLayout: "fixed"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "OrderFulfillment" }
|
||||||
|
);
|
||||||
|
|
||||||
|
interface OrderFulfilledProductsCardProps {
|
||||||
|
fulfillment: OrderDetails_order_fulfillments;
|
||||||
|
orderNumber?: string;
|
||||||
|
onOrderFulfillmentCancel: () => void;
|
||||||
|
onTrackingCodeAdd: () => void;
|
||||||
|
onRefund: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const OrderFulfilledProductsCard: React.FC<OrderFulfilledProductsCardProps> = props => {
|
||||||
|
const {
|
||||||
|
fulfillment,
|
||||||
|
orderNumber,
|
||||||
|
onOrderFulfillmentCancel,
|
||||||
|
onTrackingCodeAdd,
|
||||||
|
onRefund
|
||||||
|
} = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
if (!fulfillment) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getLines = () => {
|
||||||
|
const statusesToMergeLines = [
|
||||||
|
FulfillmentStatus.REFUNDED,
|
||||||
|
FulfillmentStatus.REFUNDED_AND_RETURNED,
|
||||||
|
FulfillmentStatus.RETURNED,
|
||||||
|
FulfillmentStatus.REPLACED
|
||||||
|
];
|
||||||
|
|
||||||
|
if (statusesToMergeLines.includes(fulfillment?.status)) {
|
||||||
|
return mergeRepeatedOrderLines(fulfillment.lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fulfillment?.lines || [];
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Card>
|
||||||
|
<CardTitle
|
||||||
|
withStatus
|
||||||
|
lines={fulfillment?.lines}
|
||||||
|
fulfillmentOrder={fulfillment?.fulfillmentOrder}
|
||||||
|
status={fulfillment?.status}
|
||||||
|
orderNumber={orderNumber}
|
||||||
|
toolbar={
|
||||||
|
maybe(() => fulfillment.status) === FulfillmentStatus.FULFILLED && (
|
||||||
|
<CardMenu
|
||||||
|
menuItems={[
|
||||||
|
{
|
||||||
|
label: intl.formatMessage({
|
||||||
|
defaultMessage: "Cancel Fulfillment",
|
||||||
|
description: "button"
|
||||||
|
}),
|
||||||
|
onSelect: onOrderFulfillmentCancel
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ResponsiveTable className={classes.table}>
|
||||||
|
<TableHeader />
|
||||||
|
<TableBody>
|
||||||
|
{renderCollection(getLines(), line => (
|
||||||
|
<TableLine line={line} />
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
<ExtraInfoLines fulfillment={fulfillment} />
|
||||||
|
</ResponsiveTable>
|
||||||
|
<ActionButtons
|
||||||
|
status={fulfillment?.status}
|
||||||
|
trackingNumber={fulfillment?.trackingNumber}
|
||||||
|
onTrackingCodeAdd={onTrackingCodeAdd}
|
||||||
|
onRefund={onRefund}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
<CardSpacer />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OrderFulfilledProductsCard;
|
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./OrderFulfilledProductsCard";
|
||||||
|
export * from "./OrderFulfilledProductsCard";
|
|
@ -1,333 +0,0 @@
|
||||||
import Button from "@material-ui/core/Button";
|
|
||||||
import Card from "@material-ui/core/Card";
|
|
||||||
import CardActions from "@material-ui/core/CardActions";
|
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
|
||||||
import TableHead from "@material-ui/core/TableHead";
|
|
||||||
import TableRow from "@material-ui/core/TableRow";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
|
||||||
import CardMenu from "@saleor/components/CardMenu";
|
|
||||||
import CardTitle from "@saleor/components/CardTitle";
|
|
||||||
import Money from "@saleor/components/Money";
|
|
||||||
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
|
||||||
import Skeleton from "@saleor/components/Skeleton";
|
|
||||||
import StatusLabel from "@saleor/components/StatusLabel";
|
|
||||||
import TableCellAvatar, {
|
|
||||||
AVATAR_MARGIN
|
|
||||||
} from "@saleor/components/TableCellAvatar";
|
|
||||||
import { mergeRepeatedOrderLines } from "@saleor/orders/utils/data";
|
|
||||||
import classNames from "classnames";
|
|
||||||
import React from "react";
|
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
|
||||||
|
|
||||||
import { getStringOrPlaceholder, maybe, renderCollection } from "../../../misc";
|
|
||||||
import { FulfillmentStatus } from "../../../types/globalTypes";
|
|
||||||
import { OrderDetails_order_fulfillments } from "../../types/OrderDetails";
|
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
|
||||||
theme => ({
|
|
||||||
clickableRow: {
|
|
||||||
cursor: "pointer"
|
|
||||||
},
|
|
||||||
colName: {
|
|
||||||
width: "auto"
|
|
||||||
},
|
|
||||||
colNameLabel: {
|
|
||||||
marginLeft: AVATAR_MARGIN
|
|
||||||
},
|
|
||||||
colPrice: {
|
|
||||||
textAlign: "right",
|
|
||||||
width: 120
|
|
||||||
},
|
|
||||||
colQuantity: {
|
|
||||||
textAlign: "center",
|
|
||||||
width: 120
|
|
||||||
},
|
|
||||||
colSku: {
|
|
||||||
textAlign: "right",
|
|
||||||
textOverflow: "ellipsis",
|
|
||||||
width: 120
|
|
||||||
},
|
|
||||||
colTotal: {
|
|
||||||
textAlign: "right",
|
|
||||||
width: 120
|
|
||||||
},
|
|
||||||
infoLabel: {
|
|
||||||
display: "inline-block"
|
|
||||||
},
|
|
||||||
infoLabelWithMargin: {
|
|
||||||
marginBottom: theme.spacing()
|
|
||||||
},
|
|
||||||
infoRow: {
|
|
||||||
padding: theme.spacing(2, 3)
|
|
||||||
},
|
|
||||||
orderNumber: {
|
|
||||||
display: "inline",
|
|
||||||
marginLeft: theme.spacing(1)
|
|
||||||
},
|
|
||||||
statusBar: {
|
|
||||||
paddingTop: 0
|
|
||||||
},
|
|
||||||
table: {
|
|
||||||
tableLayout: "fixed"
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
{ name: "OrderFulfillment" }
|
|
||||||
);
|
|
||||||
|
|
||||||
interface OrderFulfillmentProps {
|
|
||||||
fulfillment: OrderDetails_order_fulfillments;
|
|
||||||
orderNumber: string;
|
|
||||||
onOrderFulfillmentCancel: () => void;
|
|
||||||
onTrackingCodeAdd: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const numberOfColumns = 5;
|
|
||||||
|
|
||||||
const OrderFulfillment: React.FC<OrderFulfillmentProps> = props => {
|
|
||||||
const {
|
|
||||||
fulfillment,
|
|
||||||
orderNumber,
|
|
||||||
onOrderFulfillmentCancel,
|
|
||||||
onTrackingCodeAdd
|
|
||||||
} = props;
|
|
||||||
const classes = useStyles(props);
|
|
||||||
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
const lines =
|
|
||||||
fulfillment?.status === FulfillmentStatus.REFUNDED
|
|
||||||
? mergeRepeatedOrderLines(fulfillment?.lines)
|
|
||||||
: fulfillment?.lines;
|
|
||||||
const status = maybe(() => fulfillment.status);
|
|
||||||
const quantity = lines
|
|
||||||
? lines.map(line => line.quantity).reduce((prev, curr) => prev + curr, 0)
|
|
||||||
: "...";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<CardTitle
|
|
||||||
title={
|
|
||||||
!!lines ? (
|
|
||||||
<StatusLabel
|
|
||||||
label={
|
|
||||||
<>
|
|
||||||
{status === FulfillmentStatus.FULFILLED
|
|
||||||
? intl.formatMessage(
|
|
||||||
{
|
|
||||||
defaultMessage: "Fulfilled ({quantity})",
|
|
||||||
description: "section header"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
quantity
|
|
||||||
}
|
|
||||||
)
|
|
||||||
: status === FulfillmentStatus.REFUNDED
|
|
||||||
? intl.formatMessage(
|
|
||||||
{
|
|
||||||
defaultMessage: "Refunded ({quantity})",
|
|
||||||
description: "refunded fulfillment, section header"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
quantity
|
|
||||||
}
|
|
||||||
)
|
|
||||||
: intl.formatMessage(
|
|
||||||
{
|
|
||||||
defaultMessage: "Cancelled ({quantity})",
|
|
||||||
description: "cancelled fulfillment, section header"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
quantity
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
<Typography className={classes.orderNumber} variant="body1">
|
|
||||||
{maybe(
|
|
||||||
() => `#${orderNumber}-${fulfillment.fulfillmentOrder}`
|
|
||||||
)}
|
|
||||||
</Typography>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
status={
|
|
||||||
status === FulfillmentStatus.FULFILLED
|
|
||||||
? "success"
|
|
||||||
: status === FulfillmentStatus.REFUNDED
|
|
||||||
? "unspecified"
|
|
||||||
: "error"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Skeleton />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
toolbar={
|
|
||||||
maybe(() => fulfillment.status) === FulfillmentStatus.FULFILLED && (
|
|
||||||
<CardMenu
|
|
||||||
menuItems={[
|
|
||||||
{
|
|
||||||
label: intl.formatMessage({
|
|
||||||
defaultMessage: "Cancel Fulfillment",
|
|
||||||
description: "button"
|
|
||||||
}),
|
|
||||||
onSelect: onOrderFulfillmentCancel
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ResponsiveTable className={classes.table}>
|
|
||||||
<TableHead>
|
|
||||||
<TableRow>
|
|
||||||
<TableCell className={classes.colName}>
|
|
||||||
<span className={classes.colNameLabel}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Product"
|
|
||||||
description="product name"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colSku}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="SKU"
|
|
||||||
description="ordered product sku"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colQuantity}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Quantity"
|
|
||||||
description="ordered product quantity"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colPrice}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Price"
|
|
||||||
description="product price"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colTotal}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Total"
|
|
||||||
description="order line total price"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</TableHead>
|
|
||||||
<TableBody>
|
|
||||||
{renderCollection(lines, line => (
|
|
||||||
<TableRow
|
|
||||||
className={!!line ? classes.clickableRow : undefined}
|
|
||||||
hover={!!line}
|
|
||||||
key={maybe(() => line.id)}
|
|
||||||
>
|
|
||||||
<TableCellAvatar
|
|
||||||
className={classes.colName}
|
|
||||||
thumbnail={maybe(() => line.orderLine.thumbnail.url)}
|
|
||||||
>
|
|
||||||
{maybe(() => line.orderLine.productName) || <Skeleton />}
|
|
||||||
</TableCellAvatar>
|
|
||||||
<TableCell className={classes.colSku}>
|
|
||||||
{line?.orderLine.productSku || <Skeleton />}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colQuantity}>
|
|
||||||
{line?.quantity || <Skeleton />}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colPrice}>
|
|
||||||
{maybe(() => line.orderLine.unitPrice.gross) ? (
|
|
||||||
<Money money={line.orderLine.unitPrice.gross} />
|
|
||||||
) : (
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colTotal}>
|
|
||||||
{maybe(
|
|
||||||
() => line.quantity * line.orderLine.unitPrice.gross.amount
|
|
||||||
) ? (
|
|
||||||
<Money
|
|
||||||
money={{
|
|
||||||
amount:
|
|
||||||
line.quantity * line.orderLine.unitPrice.gross.amount,
|
|
||||||
currency: line.orderLine.unitPrice.gross.currency
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
{(fulfillment?.warehouse || fulfillment?.trackingNumber) && (
|
|
||||||
<TableRow>
|
|
||||||
<TableCell className={classes.infoRow} colSpan={numberOfColumns}>
|
|
||||||
<Typography color="textSecondary" variant="body2">
|
|
||||||
{fulfillment?.warehouse && (
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Fulfilled from: {warehouseName}"
|
|
||||||
description="fulfillment group"
|
|
||||||
values={{
|
|
||||||
warehouseName: (
|
|
||||||
<Typography
|
|
||||||
className={classNames(classes.infoLabel, {
|
|
||||||
[classes.infoLabelWithMargin]: !!fulfillment?.trackingNumber
|
|
||||||
})}
|
|
||||||
color="textPrimary"
|
|
||||||
variant="body2"
|
|
||||||
>
|
|
||||||
{getStringOrPlaceholder(
|
|
||||||
fulfillment?.warehouse?.name
|
|
||||||
)}
|
|
||||||
</Typography>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Typography>
|
|
||||||
<Typography color="textSecondary" variant="body2">
|
|
||||||
{fulfillment?.trackingNumber && (
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Tracking Number: {trackingNumber}"
|
|
||||||
values={{
|
|
||||||
trackingNumber: (
|
|
||||||
<Typography
|
|
||||||
className={classes.infoLabel}
|
|
||||||
color="textPrimary"
|
|
||||||
variant="body2"
|
|
||||||
>
|
|
||||||
{fulfillment.trackingNumber}
|
|
||||||
</Typography>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Typography>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
)}
|
|
||||||
</TableBody>
|
|
||||||
</ResponsiveTable>
|
|
||||||
{status === FulfillmentStatus.FULFILLED && !fulfillment.trackingNumber && (
|
|
||||||
<CardActions>
|
|
||||||
<Button color="primary" onClick={onTrackingCodeAdd}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Add tracking"
|
|
||||||
description="fulfillment group tracking number"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</CardActions>
|
|
||||||
)}
|
|
||||||
{status === FulfillmentStatus.FULFILLED && fulfillment.trackingNumber && (
|
|
||||||
<CardActions>
|
|
||||||
<Button color="primary" onClick={onTrackingCodeAdd}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Edit tracking"
|
|
||||||
description="fulfillment group tracking number"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</CardActions>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
OrderFulfillment.displayName = "OrderFulfillment";
|
|
||||||
export default OrderFulfillment;
|
|
|
@ -1,2 +0,0 @@
|
||||||
export { default } from "./OrderFulfillment";
|
|
||||||
export * from "./OrderFulfillment";
|
|
211
src/orders/components/OrderHistory/ExtendedTimelineEvent.tsx
Normal file
211
src/orders/components/OrderHistory/ExtendedTimelineEvent.tsx
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
import { makeStyles, Typography } from "@material-ui/core";
|
||||||
|
import Money from "@saleor/components/Money";
|
||||||
|
import { TimelineEvent } from "@saleor/components/Timeline";
|
||||||
|
import { orderUrl } from "@saleor/orders/urls";
|
||||||
|
import { staffMemberDetailsUrl } from "@saleor/staff/urls";
|
||||||
|
import { OrderEventsEnum } from "@saleor/types/globalTypes";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import camelCase from "lodash/camelCase";
|
||||||
|
import React from "react";
|
||||||
|
import { defineMessages, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import { OrderDetails_order_events } from "../../types/OrderDetails";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
eventSubtitle: {
|
||||||
|
marginBottom: theme.spacing(0.5),
|
||||||
|
marginTop: theme.spacing(1)
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
fontWeight: 500,
|
||||||
|
marginBottom: theme.spacing(1)
|
||||||
|
},
|
||||||
|
linesTableCell: {
|
||||||
|
paddingRight: theme.spacing(3)
|
||||||
|
},
|
||||||
|
root: { marginTop: theme.spacing(4) },
|
||||||
|
topSpacer: {
|
||||||
|
marginTop: theme.spacing(3)
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
marginBottom: theme.spacing(1)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "OrderHistory" }
|
||||||
|
);
|
||||||
|
|
||||||
|
export const productTitles = defineMessages({
|
||||||
|
draftCreatedFromReplace: {
|
||||||
|
defaultMessage: "Products replaced",
|
||||||
|
description: "draft created from replace products list title",
|
||||||
|
id: "event products title draft reissued"
|
||||||
|
},
|
||||||
|
fulfillmentRefunded: {
|
||||||
|
defaultMessage: "Products refunded",
|
||||||
|
description: "refunded products list title",
|
||||||
|
id: "event products list title refunded"
|
||||||
|
},
|
||||||
|
fulfillmentReplaced: {
|
||||||
|
defaultMessage: "Products replaced",
|
||||||
|
description: "replaced products list title",
|
||||||
|
id: "event products list title replaced"
|
||||||
|
},
|
||||||
|
fulfillmentReturned: {
|
||||||
|
defaultMessage: "Products returned",
|
||||||
|
description: "returned products list title",
|
||||||
|
id: "event products list title returned"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const titles = defineMessages({
|
||||||
|
draftCreatedFromReplace: {
|
||||||
|
defaultMessage: "Draft was reissued from order ",
|
||||||
|
description: "draft created from replace event title",
|
||||||
|
id: "event title draft reissued"
|
||||||
|
},
|
||||||
|
fulfillmentRefunded: {
|
||||||
|
defaultMessage: "Products were refunded by ",
|
||||||
|
description: "refunded event title",
|
||||||
|
id: "event title refunded"
|
||||||
|
},
|
||||||
|
fulfillmentReplaced: {
|
||||||
|
defaultMessage: "Products were replaced by ",
|
||||||
|
description: "replaced event title",
|
||||||
|
id: "event title replaced"
|
||||||
|
},
|
||||||
|
fulfillmentReturned: {
|
||||||
|
defaultMessage: "Products were returned by",
|
||||||
|
description: "returned event title",
|
||||||
|
id: "event title returned"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
by: {
|
||||||
|
defaultMessage: "by",
|
||||||
|
description: "by preposition",
|
||||||
|
id: "by preposition"
|
||||||
|
},
|
||||||
|
refundedAmount: {
|
||||||
|
defaultMessage: "Refunded amount",
|
||||||
|
description: "amount title",
|
||||||
|
id: "amount title"
|
||||||
|
},
|
||||||
|
refundedShipment: {
|
||||||
|
defaultMessage: "Shipment was refunded",
|
||||||
|
description: "shipment refund title",
|
||||||
|
id: "shipment refund title"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
interface ExtendedTimelineEventProps {
|
||||||
|
event: OrderDetails_order_events;
|
||||||
|
orderCurrency: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ExtendedTimelineEvent: React.FC<ExtendedTimelineEventProps> = ({
|
||||||
|
event,
|
||||||
|
orderCurrency
|
||||||
|
}) => {
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
date,
|
||||||
|
type,
|
||||||
|
user,
|
||||||
|
lines,
|
||||||
|
amount,
|
||||||
|
shippingCostsIncluded,
|
||||||
|
relatedOrder
|
||||||
|
} = event;
|
||||||
|
const classes = useStyles({});
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const eventTypeInCamelCase = camelCase(type);
|
||||||
|
|
||||||
|
const employeeName = `${user.firstName} ${user.lastName}`;
|
||||||
|
|
||||||
|
const titleElements = {
|
||||||
|
by: { text: intl.formatMessage(messages.by) },
|
||||||
|
employeeName: { link: staffMemberDetailsUrl(user.id), text: employeeName },
|
||||||
|
orderNumber: {
|
||||||
|
link: orderUrl(relatedOrder?.id),
|
||||||
|
text: `#${relatedOrder?.number}`
|
||||||
|
},
|
||||||
|
title: { text: intl.formatMessage(titles[eventTypeInCamelCase]) }
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectTitleElements = () => {
|
||||||
|
const { title, by, employeeName, orderNumber } = titleElements;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case OrderEventsEnum.DRAFT_CREATED_FROM_REPLACE: {
|
||||||
|
return [title, orderNumber, by, employeeName];
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return [title, employeeName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TimelineEvent date={date} titleElements={selectTitleElements()} key={id}>
|
||||||
|
{lines && (
|
||||||
|
<>
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
color="textSecondary"
|
||||||
|
className={classes.eventSubtitle}
|
||||||
|
>
|
||||||
|
{intl.formatMessage(productTitles[eventTypeInCamelCase])}
|
||||||
|
</Typography>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
{lines.map(({ orderLine, quantity }) => (
|
||||||
|
<tr key={orderLine.id}>
|
||||||
|
<td className={classes.linesTableCell}>
|
||||||
|
{orderLine.productName}
|
||||||
|
</td>
|
||||||
|
<td className={classes.linesTableCell}>
|
||||||
|
<Typography variant="caption" color="textSecondary">
|
||||||
|
{orderLine.variantName}
|
||||||
|
</Typography>
|
||||||
|
</td>
|
||||||
|
<td className={classes.linesTableCell}>
|
||||||
|
<Typography variant="caption" color="textSecondary">
|
||||||
|
{`qty: ${quantity}`}
|
||||||
|
</Typography>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{(amount || amount === 0) && (
|
||||||
|
<>
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
color="textSecondary"
|
||||||
|
className={classNames(classes.eventSubtitle, classes.topSpacer)}
|
||||||
|
>
|
||||||
|
{intl.formatMessage(messages.refundedAmount)}
|
||||||
|
</Typography>
|
||||||
|
<Money
|
||||||
|
money={{
|
||||||
|
amount,
|
||||||
|
currency: orderCurrency
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{shippingCostsIncluded && (
|
||||||
|
<Typography>
|
||||||
|
{intl.formatMessage(messages.refundedShipment)}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</TimelineEvent>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ExtendedTimelineEvent;
|
|
@ -2,28 +2,32 @@ import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import Form from "@saleor/components/Form";
|
import Form from "@saleor/components/Form";
|
||||||
import Hr from "@saleor/components/Hr";
|
import Hr from "@saleor/components/Hr";
|
||||||
import Money from "@saleor/components/Money";
|
|
||||||
import Skeleton from "@saleor/components/Skeleton";
|
import Skeleton from "@saleor/components/Skeleton";
|
||||||
import {
|
import {
|
||||||
Timeline,
|
Timeline,
|
||||||
TimelineAddNote,
|
TimelineAddNote,
|
||||||
TimelineEvent,
|
TimelineEvent,
|
||||||
|
TimelineEventProps,
|
||||||
TimelineNote
|
TimelineNote
|
||||||
} from "@saleor/components/Timeline";
|
} from "@saleor/components/Timeline";
|
||||||
import React from "react";
|
import { TitleElement } from "@saleor/components/Timeline/TimelineEventHeader";
|
||||||
import { FormattedMessage, IntlShape, useIntl } from "react-intl";
|
import { OrderDetails_order_events } from "@saleor/orders/types/OrderDetails";
|
||||||
|
import { orderUrl } from "@saleor/orders/urls";
|
||||||
import {
|
import {
|
||||||
OrderEventsEmailsEnum,
|
OrderEventsEmailsEnum,
|
||||||
OrderEventsEnum
|
OrderEventsEnum
|
||||||
} from "../../../types/globalTypes";
|
} from "@saleor/types/globalTypes";
|
||||||
import { OrderDetails_order_events } from "../../types/OrderDetails";
|
import React from "react";
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
import { FormattedMessage, IntlShape, useIntl } from "react-intl";
|
||||||
|
|
||||||
export interface FormData {
|
import ExtendedTimelineEvent from "./ExtendedTimelineEvent";
|
||||||
message: string;
|
import { getEventSecondaryTitle, isTimelineEventOfType } from "./utils";
|
||||||
}
|
|
||||||
|
|
||||||
const getEventMessage = (event: OrderDetails_order_events, intl: IntlShape) => {
|
export const getEventMessage = (
|
||||||
|
event: OrderDetails_order_events,
|
||||||
|
intl: IntlShape
|
||||||
|
) => {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case OrderEventsEnum.CANCELED:
|
case OrderEventsEnum.CANCELED:
|
||||||
return intl.formatMessage({
|
return intl.formatMessage({
|
||||||
|
@ -247,6 +251,21 @@ const getEventMessage = (event: OrderDetails_order_events, intl: IntlShape) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const replacementCreatedMessages = defineMessages({
|
||||||
|
description: {
|
||||||
|
defaultMessage: "was created for replaced products",
|
||||||
|
description: "replacement created order history message description"
|
||||||
|
},
|
||||||
|
draftNumber: {
|
||||||
|
defaultMessage: "Draft #{orderNumber} ",
|
||||||
|
description: "replacement created order history message draft number"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export interface FormData {
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
eventSubtitle: {
|
eventSubtitle: {
|
||||||
|
@ -279,6 +298,45 @@ const OrderHistory: React.FC<OrderHistoryProps> = props => {
|
||||||
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const getTimelineEventTitleProps = (
|
||||||
|
event: OrderDetails_order_events
|
||||||
|
): Partial<TimelineEventProps> => {
|
||||||
|
const { type, message } = event;
|
||||||
|
|
||||||
|
const title = isTimelineEventOfType("rawMessage", type)
|
||||||
|
? message
|
||||||
|
: getEventMessage(event, intl);
|
||||||
|
|
||||||
|
if (isTimelineEventOfType("secondaryTitle", type)) {
|
||||||
|
return {
|
||||||
|
secondaryTitle: intl.formatMessage(...getEventSecondaryTitle(event)),
|
||||||
|
title
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return { title };
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTitleElements = (
|
||||||
|
event: OrderDetails_order_events
|
||||||
|
): TitleElement[] => {
|
||||||
|
const { type, relatedOrder } = event;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case OrderEventsEnum.ORDER_REPLACEMENT_CREATED: {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
link: orderUrl(relatedOrder?.id),
|
||||||
|
text: intl.formatMessage(replacementCreatedMessages.draftNumber, {
|
||||||
|
orderNumber: relatedOrder?.number
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{ text: intl.formatMessage(replacementCreatedMessages.description) }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<Typography className={classes.header} color="textSecondary">
|
<Typography className={classes.header} color="textSecondary">
|
||||||
|
@ -301,106 +359,42 @@ const OrderHistory: React.FC<OrderHistoryProps> = props => {
|
||||||
.slice()
|
.slice()
|
||||||
.reverse()
|
.reverse()
|
||||||
.map(event => {
|
.map(event => {
|
||||||
if (event.type === OrderEventsEnum.NOTE_ADDED) {
|
const { id, user, date, message, type } = event;
|
||||||
|
|
||||||
|
if (isTimelineEventOfType("note", type)) {
|
||||||
return (
|
return (
|
||||||
<TimelineNote
|
<TimelineNote
|
||||||
date={event.date}
|
date={date}
|
||||||
user={event.user}
|
user={user}
|
||||||
message={event.message}
|
message={message}
|
||||||
key={event.id}
|
key={id}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (event.type === OrderEventsEnum.ORDER_MARKED_AS_PAID) {
|
if (isTimelineEventOfType("extendable", type)) {
|
||||||
return (
|
return (
|
||||||
<TimelineEvent
|
<ExtendedTimelineEvent
|
||||||
date={event.date}
|
event={event}
|
||||||
title={getEventMessage(event, intl)}
|
orderCurrency={orderCurrency}
|
||||||
secondaryTitle={intl.formatMessage(
|
|
||||||
{
|
|
||||||
defaultMessage:
|
|
||||||
"Transaction Reference {transactionReference}",
|
|
||||||
description: "transaction reference"
|
|
||||||
},
|
|
||||||
{ transactionReference: event.transactionReference }
|
|
||||||
)}
|
|
||||||
key={event.id}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (event.type === OrderEventsEnum.FULFILLMENT_REFUNDED) {
|
|
||||||
|
if (isTimelineEventOfType("linked", type)) {
|
||||||
return (
|
return (
|
||||||
<TimelineEvent
|
<TimelineEvent
|
||||||
date={event.date}
|
titleElements={getTitleElements(event)}
|
||||||
title={getEventMessage(event, intl)}
|
key={id}
|
||||||
key={event.id}
|
date={date}
|
||||||
>
|
/>
|
||||||
{event.lines && (
|
|
||||||
<>
|
|
||||||
<Typography
|
|
||||||
variant="caption"
|
|
||||||
color="textSecondary"
|
|
||||||
className={classes.eventSubtitle}
|
|
||||||
>
|
|
||||||
<FormattedMessage defaultMessage="Products refunded" />
|
|
||||||
</Typography>
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
{event.lines.map(line => (
|
|
||||||
<tr key={line.orderLine.id}>
|
|
||||||
<td className={classes.linesTableCell}>
|
|
||||||
{line.orderLine.productName}
|
|
||||||
</td>
|
|
||||||
<td className={classes.linesTableCell}>
|
|
||||||
<Typography
|
|
||||||
variant="caption"
|
|
||||||
color="textSecondary"
|
|
||||||
>
|
|
||||||
{line.orderLine.variantName}
|
|
||||||
</Typography>
|
|
||||||
</td>
|
|
||||||
<td className={classes.linesTableCell}>
|
|
||||||
<Typography
|
|
||||||
variant="caption"
|
|
||||||
color="textSecondary"
|
|
||||||
>
|
|
||||||
{`qty: ${line.quantity}`}
|
|
||||||
</Typography>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<Typography
|
|
||||||
variant="caption"
|
|
||||||
color="textSecondary"
|
|
||||||
className={classes.eventSubtitle}
|
|
||||||
>
|
|
||||||
<FormattedMessage defaultMessage="Refunded amount" />
|
|
||||||
</Typography>
|
|
||||||
{(event.amount || event.amount === 0) && (
|
|
||||||
<Money
|
|
||||||
money={{
|
|
||||||
amount: event.amount,
|
|
||||||
currency: orderCurrency
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{event.shippingCostsIncluded && (
|
|
||||||
<Typography>
|
|
||||||
<FormattedMessage defaultMessage="Shipment was refunded" />
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</TimelineEvent>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TimelineEvent
|
<TimelineEvent
|
||||||
date={event.date}
|
{...getTimelineEventTitleProps(event)}
|
||||||
title={getEventMessage(event, intl)}
|
key={id}
|
||||||
key={event.id}
|
date={date}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
41
src/orders/components/OrderHistory/utils.tsx
Normal file
41
src/orders/components/OrderHistory/utils.tsx
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import { OrderDetails_order_events } from "@saleor/orders/types/OrderDetails";
|
||||||
|
import { OrderEventsEnum } from "@saleor/types/globalTypes";
|
||||||
|
import { MessageDescriptor } from "react-intl";
|
||||||
|
|
||||||
|
export const getEventSecondaryTitle = (
|
||||||
|
event: OrderDetails_order_events
|
||||||
|
): [MessageDescriptor, any?] => {
|
||||||
|
switch (event.type) {
|
||||||
|
case OrderEventsEnum.ORDER_MARKED_AS_PAID: {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
defaultMessage: "Transaction Reference {transactionReference}",
|
||||||
|
description: "transaction reference",
|
||||||
|
id: "transaction-reference-order-history"
|
||||||
|
},
|
||||||
|
{ transactionReference: event.transactionReference }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const timelineEventTypes = {
|
||||||
|
extendable: [
|
||||||
|
OrderEventsEnum.FULFILLMENT_REFUNDED,
|
||||||
|
OrderEventsEnum.FULFILLMENT_REPLACED,
|
||||||
|
OrderEventsEnum.FULFILLMENT_RETURNED,
|
||||||
|
OrderEventsEnum.DRAFT_CREATED_FROM_REPLACE
|
||||||
|
],
|
||||||
|
linked: [OrderEventsEnum.ORDER_REPLACEMENT_CREATED],
|
||||||
|
note: [OrderEventsEnum.NOTE_ADDED],
|
||||||
|
rawMessage: [
|
||||||
|
OrderEventsEnum.OTHER,
|
||||||
|
OrderEventsEnum.EXTERNAL_SERVICE_NOTIFICATION
|
||||||
|
],
|
||||||
|
secondaryTitle: [OrderEventsEnum.ORDER_MARKED_AS_PAID]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isTimelineEventOfType = (
|
||||||
|
type: "extendable" | "secondaryTitle" | "rawMessage" | "note" | "linked",
|
||||||
|
eventType: OrderEventsEnum
|
||||||
|
) => !!timelineEventTypes[type]?.includes(eventType);
|
|
@ -0,0 +1,95 @@
|
||||||
|
import { makeStyles, TableCell, TableHead, TableRow } from "@material-ui/core";
|
||||||
|
import React from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
clickableRow: {
|
||||||
|
cursor: "pointer"
|
||||||
|
},
|
||||||
|
colName: {
|
||||||
|
textAlign: "left",
|
||||||
|
width: "auto"
|
||||||
|
},
|
||||||
|
colPrice: {
|
||||||
|
textAlign: "right",
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
colQuantity: {
|
||||||
|
textAlign: "center",
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
colSku: {
|
||||||
|
textAlign: "right",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
colTotal: {
|
||||||
|
textAlign: "right",
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
infoLabel: {
|
||||||
|
display: "inline-block"
|
||||||
|
},
|
||||||
|
infoLabelWithMargin: {
|
||||||
|
marginBottom: theme.spacing()
|
||||||
|
},
|
||||||
|
infoRow: {
|
||||||
|
padding: theme.spacing(2, 3)
|
||||||
|
},
|
||||||
|
orderNumber: {
|
||||||
|
display: "inline",
|
||||||
|
marginLeft: theme.spacing(1)
|
||||||
|
},
|
||||||
|
statusBar: {
|
||||||
|
paddingTop: 0
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
tableLayout: "fixed"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "TableHeader" }
|
||||||
|
);
|
||||||
|
|
||||||
|
const TableHeader = () => {
|
||||||
|
const classes = useStyles({});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell className={classes.colName}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Product"
|
||||||
|
description="product name"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colSku}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="SKU"
|
||||||
|
description="ordered product sku"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colQuantity}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Quantity"
|
||||||
|
description="ordered product quantity"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colPrice}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Price"
|
||||||
|
description="product price"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colTotal}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Total"
|
||||||
|
description="order line total price"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableHeader;
|
|
@ -0,0 +1,129 @@
|
||||||
|
import { makeStyles, TableCell, TableRow } from "@material-ui/core";
|
||||||
|
import Money from "@saleor/components/Money";
|
||||||
|
import Skeleton from "@saleor/components/Skeleton";
|
||||||
|
import TableCellAvatar, {
|
||||||
|
AVATAR_MARGIN
|
||||||
|
} from "@saleor/components/TableCellAvatar";
|
||||||
|
import { maybe } from "@saleor/misc";
|
||||||
|
import {
|
||||||
|
OrderDetails_order_fulfillments_lines,
|
||||||
|
OrderDetails_order_lines
|
||||||
|
} from "@saleor/orders/types/OrderDetails";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
clickableRow: {
|
||||||
|
cursor: "pointer"
|
||||||
|
},
|
||||||
|
colName: {
|
||||||
|
width: "auto"
|
||||||
|
},
|
||||||
|
colNameLabel: {
|
||||||
|
marginLeft: AVATAR_MARGIN
|
||||||
|
},
|
||||||
|
colPrice: {
|
||||||
|
textAlign: "right",
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
colQuantity: {
|
||||||
|
textAlign: "center",
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
colSku: {
|
||||||
|
textAlign: "right",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
colTotal: {
|
||||||
|
textAlign: "right",
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
infoLabel: {
|
||||||
|
display: "inline-block"
|
||||||
|
},
|
||||||
|
infoLabelWithMargin: {
|
||||||
|
marginBottom: theme.spacing()
|
||||||
|
},
|
||||||
|
infoRow: {
|
||||||
|
padding: theme.spacing(2, 3)
|
||||||
|
},
|
||||||
|
orderNumber: {
|
||||||
|
display: "inline",
|
||||||
|
marginLeft: theme.spacing(1)
|
||||||
|
},
|
||||||
|
statusBar: {
|
||||||
|
paddingTop: 0
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
tableLayout: "fixed"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "TableLine" }
|
||||||
|
);
|
||||||
|
|
||||||
|
interface TableLineProps {
|
||||||
|
line: OrderDetails_order_fulfillments_lines | OrderDetails_order_lines;
|
||||||
|
isOrderLine?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TableLine: React.FC<TableLineProps> = ({
|
||||||
|
line: lineData,
|
||||||
|
isOrderLine = false
|
||||||
|
}) => {
|
||||||
|
const classes = useStyles({});
|
||||||
|
const { quantity, quantityFulfilled } = lineData as OrderDetails_order_lines;
|
||||||
|
|
||||||
|
if (!lineData) {
|
||||||
|
return <Skeleton />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const line = isOrderLine
|
||||||
|
? ({
|
||||||
|
...lineData,
|
||||||
|
orderLine: lineData
|
||||||
|
} as OrderDetails_order_fulfillments_lines)
|
||||||
|
: (lineData as OrderDetails_order_fulfillments_lines);
|
||||||
|
|
||||||
|
const quantityToDisplay = isOrderLine
|
||||||
|
? quantity - quantityFulfilled
|
||||||
|
: quantity;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow className={classes.clickableRow} hover key={line.id}>
|
||||||
|
<TableCellAvatar
|
||||||
|
className={classes.colName}
|
||||||
|
thumbnail={maybe(() => line.orderLine.thumbnail.url)}
|
||||||
|
>
|
||||||
|
{maybe(() => line.orderLine.productName) || <Skeleton />}
|
||||||
|
</TableCellAvatar>
|
||||||
|
<TableCell className={classes.colSku}>
|
||||||
|
{line?.orderLine.productSku || <Skeleton />}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colQuantity}>
|
||||||
|
{quantityToDisplay || <Skeleton />}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colPrice}>
|
||||||
|
{maybe(() => line.orderLine.unitPrice.gross) ? (
|
||||||
|
<Money money={line.orderLine.unitPrice.gross} />
|
||||||
|
) : (
|
||||||
|
<Skeleton />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colTotal}>
|
||||||
|
{maybe(() => line.quantity * line.orderLine.unitPrice.gross.amount) ? (
|
||||||
|
<Money
|
||||||
|
money={{
|
||||||
|
amount: line.quantity * line.orderLine.unitPrice.gross.amount,
|
||||||
|
currency: line.orderLine.unitPrice.gross.currency
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Skeleton />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableLine;
|
|
@ -1,2 +0,0 @@
|
||||||
export * from "./OrderRefundAmount";
|
|
||||||
export { default } from "./OrderRefundAmount";
|
|
|
@ -1,153 +0,0 @@
|
||||||
import { makeStyles } from "@material-ui/core";
|
|
||||||
import Money, { IMoney } from "@saleor/components/Money";
|
|
||||||
import Skeleton from "@saleor/components/Skeleton";
|
|
||||||
import React from "react";
|
|
||||||
import { FormattedMessage } from "react-intl";
|
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
|
||||||
theme => ({
|
|
||||||
highlightedRow: {
|
|
||||||
fontWeight: 600
|
|
||||||
},
|
|
||||||
root: {
|
|
||||||
...theme.typography.body1,
|
|
||||||
lineHeight: 1.9,
|
|
||||||
width: "100%"
|
|
||||||
},
|
|
||||||
textRight: {
|
|
||||||
minWidth: 30,
|
|
||||||
textAlign: "right"
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
{ name: "OrderRefundAmountValues" }
|
|
||||||
);
|
|
||||||
|
|
||||||
export interface OrderRefundAmountValuesProps {
|
|
||||||
authorizedAmount: IMoney;
|
|
||||||
shipmentCost?: IMoney;
|
|
||||||
selectedProductsValue?: IMoney;
|
|
||||||
previouslyRefunded: IMoney;
|
|
||||||
maxRefund: IMoney;
|
|
||||||
proposedRefundAmount?: IMoney;
|
|
||||||
refundTotalAmount?: IMoney;
|
|
||||||
}
|
|
||||||
|
|
||||||
const OrderRefundAmountValues: React.FC<OrderRefundAmountValuesProps> = ({
|
|
||||||
authorizedAmount,
|
|
||||||
shipmentCost,
|
|
||||||
selectedProductsValue,
|
|
||||||
previouslyRefunded,
|
|
||||||
maxRefund,
|
|
||||||
proposedRefundAmount,
|
|
||||||
refundTotalAmount
|
|
||||||
}) => {
|
|
||||||
const classes = useStyles({});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<table className={classes.root}>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Authorized Amount"
|
|
||||||
description="order refund amount"
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td className={classes.textRight}>
|
|
||||||
{authorizedAmount?.amount !== undefined ? (
|
|
||||||
<Money money={authorizedAmount} />
|
|
||||||
) : (
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{shipmentCost?.amount !== undefined && (
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Shipment cost"
|
|
||||||
description="order refund amount"
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td className={classes.textRight}>
|
|
||||||
<Money money={shipmentCost} />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
)}
|
|
||||||
{selectedProductsValue?.amount !== undefined && (
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Selected products value"
|
|
||||||
description="order refund amount"
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td className={classes.textRight}>
|
|
||||||
<Money money={selectedProductsValue} />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
)}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Previously refunded"
|
|
||||||
description="order refund amount"
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td className={classes.textRight}>
|
|
||||||
{previouslyRefunded?.amount !== undefined ? (
|
|
||||||
<>
|
|
||||||
<Money money={previouslyRefunded} />
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr className={classes.highlightedRow}>
|
|
||||||
<td>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Max Refund"
|
|
||||||
description="order refund amount"
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td className={classes.textRight}>
|
|
||||||
{maxRefund?.amount !== undefined ? (
|
|
||||||
<Money money={maxRefund} />
|
|
||||||
) : (
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{proposedRefundAmount?.amount !== undefined && (
|
|
||||||
<tr className={classes.highlightedRow}>
|
|
||||||
<td>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Proposed refund amount"
|
|
||||||
description="order refund amount"
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td className={classes.textRight}>
|
|
||||||
<Money money={proposedRefundAmount} />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
)}
|
|
||||||
{refundTotalAmount?.amount !== undefined && (
|
|
||||||
<tr className={classes.highlightedRow}>
|
|
||||||
<td>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Refund total amount"
|
|
||||||
description="order refund amount"
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td className={classes.textRight}>
|
|
||||||
<Money money={refundTotalAmount} />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
)}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
OrderRefundAmountValues.displayName = "OrderRefundAmountValues";
|
|
||||||
export default OrderRefundAmountValues;
|
|
|
@ -1,2 +0,0 @@
|
||||||
export * from "./OrderRefundAmountValues";
|
|
||||||
export { default } from "./OrderRefundAmountValues";
|
|
|
@ -12,8 +12,12 @@ import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import OrderRefund from "../OrderRefund";
|
import OrderRefund from "../OrderRefund";
|
||||||
import OrderRefundAmount from "../OrderRefundAmount";
|
|
||||||
import OrderRefundFulfilledProducts from "../OrderRefundFulfilledProducts";
|
import OrderRefundFulfilledProducts from "../OrderRefundFulfilledProducts";
|
||||||
|
import OrderRefundAmount from "../OrderRefundReturnAmount";
|
||||||
|
import {
|
||||||
|
getMiscellaneousAmountValues,
|
||||||
|
getRefundProductsAmountValues
|
||||||
|
} from "../OrderRefundReturnAmount/utils";
|
||||||
import OrderRefundUnfulfilledProducts from "../OrderRefundUnfulfilledProducts";
|
import OrderRefundUnfulfilledProducts from "../OrderRefundUnfulfilledProducts";
|
||||||
import OrderRefundForm, {
|
import OrderRefundForm, {
|
||||||
OrderRefundSubmitData,
|
OrderRefundSubmitData,
|
||||||
|
@ -55,91 +59,104 @@ const OrderRefundPage: React.FC<OrderRefundPageProps> = props => {
|
||||||
defaultType={defaultType}
|
defaultType={defaultType}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
>
|
>
|
||||||
{({ data, handlers, change, submit }) => (
|
{({ data, handlers, change, submit }) => {
|
||||||
<Container>
|
const isProductRefund = data.type === OrderRefundType.PRODUCTS;
|
||||||
<AppHeader onBack={onBack}>
|
|
||||||
{order?.number
|
return (
|
||||||
? intl.formatMessage(
|
<Container>
|
||||||
{
|
<AppHeader onBack={onBack}>
|
||||||
defaultMessage: "Order #{orderNumber}",
|
{order?.number
|
||||||
description: "page header with order number"
|
? intl.formatMessage(
|
||||||
},
|
{
|
||||||
{
|
defaultMessage: "Order #{orderNumber}",
|
||||||
orderNumber: order.number
|
description: "page header with order number"
|
||||||
}
|
},
|
||||||
)
|
{
|
||||||
: intl.formatMessage({
|
orderNumber: order.number
|
||||||
defaultMessage: "Order",
|
}
|
||||||
|
)
|
||||||
|
: intl.formatMessage({
|
||||||
|
defaultMessage: "Order",
|
||||||
|
description: "page header"
|
||||||
|
})}
|
||||||
|
</AppHeader>
|
||||||
|
<PageHeader
|
||||||
|
title={intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage: "Order no. {orderNumber} - Refund",
|
||||||
description: "page header"
|
description: "page header"
|
||||||
})}
|
},
|
||||||
</AppHeader>
|
{
|
||||||
<PageHeader
|
orderNumber: order?.number
|
||||||
title={intl.formatMessage(
|
}
|
||||||
{
|
|
||||||
defaultMessage: "Order no. {orderNumber} - Refund",
|
|
||||||
description: "page header"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
orderNumber: order?.number
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Grid>
|
|
||||||
<div>
|
|
||||||
<OrderRefund data={data} disabled={disabled} onChange={change} />
|
|
||||||
{data.type === OrderRefundType.PRODUCTS && (
|
|
||||||
<>
|
|
||||||
{unfulfilledLines?.length > 0 && (
|
|
||||||
<>
|
|
||||||
<CardSpacer />
|
|
||||||
<OrderRefundUnfulfilledProducts
|
|
||||||
unfulfilledLines={unfulfilledLines}
|
|
||||||
data={data}
|
|
||||||
disabled={disabled}
|
|
||||||
onRefundedProductQuantityChange={
|
|
||||||
handlers.changeRefundedProductQuantity
|
|
||||||
}
|
|
||||||
onSetMaximalQuantities={
|
|
||||||
handlers.setMaximalRefundedProductQuantities
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{renderCollection(fulfilledFulfillemnts, fulfillment => (
|
|
||||||
<React.Fragment key={fulfillment?.id}>
|
|
||||||
<CardSpacer />
|
|
||||||
<OrderRefundFulfilledProducts
|
|
||||||
fulfillment={fulfillment}
|
|
||||||
data={data}
|
|
||||||
disabled={disabled}
|
|
||||||
orderNumber={order?.number}
|
|
||||||
onRefundedProductQuantityChange={
|
|
||||||
handlers.changeRefundedFulfilledProductQuantity
|
|
||||||
}
|
|
||||||
onSetMaximalQuantities={() =>
|
|
||||||
handlers.setMaximalRefundedFulfilledProductQuantities(
|
|
||||||
fulfillment?.id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
/>
|
||||||
<div>
|
<Grid>
|
||||||
<OrderRefundAmount
|
<div>
|
||||||
data={data}
|
<OrderRefund
|
||||||
order={order}
|
data={data}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
errors={errors}
|
onChange={change}
|
||||||
onChange={change}
|
/>
|
||||||
onRefund={submit}
|
{isProductRefund && (
|
||||||
/>
|
<>
|
||||||
</div>
|
{unfulfilledLines?.length > 0 && (
|
||||||
</Grid>
|
<>
|
||||||
</Container>
|
<CardSpacer />
|
||||||
)}
|
<OrderRefundUnfulfilledProducts
|
||||||
|
unfulfilledLines={unfulfilledLines}
|
||||||
|
data={data}
|
||||||
|
disabled={disabled}
|
||||||
|
onRefundedProductQuantityChange={
|
||||||
|
handlers.changeRefundedProductQuantity
|
||||||
|
}
|
||||||
|
onSetMaximalQuantities={
|
||||||
|
handlers.setMaximalRefundedProductQuantities
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{renderCollection(fulfilledFulfillemnts, fulfillment => (
|
||||||
|
<React.Fragment key={fulfillment?.id}>
|
||||||
|
<CardSpacer />
|
||||||
|
<OrderRefundFulfilledProducts
|
||||||
|
fulfillment={fulfillment}
|
||||||
|
data={data}
|
||||||
|
disabled={disabled}
|
||||||
|
orderNumber={order?.number}
|
||||||
|
onRefundedProductQuantityChange={
|
||||||
|
handlers.changeRefundedFulfilledProductQuantity
|
||||||
|
}
|
||||||
|
onSetMaximalQuantities={() =>
|
||||||
|
handlers.setMaximalRefundedFulfilledProductQuantities(
|
||||||
|
fulfillment?.id
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<OrderRefundAmount
|
||||||
|
amountData={
|
||||||
|
isProductRefund
|
||||||
|
? getRefundProductsAmountValues(order, data)
|
||||||
|
: getMiscellaneousAmountValues(order)
|
||||||
|
}
|
||||||
|
data={data}
|
||||||
|
order={order}
|
||||||
|
disabled={disabled}
|
||||||
|
errors={errors}
|
||||||
|
onChange={change}
|
||||||
|
onRefund={submit}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}}
|
||||||
</OrderRefundForm>
|
</OrderRefundForm>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,91 +9,22 @@ import CardSpacer from "@saleor/components/CardSpacer";
|
||||||
import CardTitle from "@saleor/components/CardTitle";
|
import CardTitle from "@saleor/components/CardTitle";
|
||||||
import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
|
import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
|
||||||
import Hr from "@saleor/components/Hr";
|
import Hr from "@saleor/components/Hr";
|
||||||
import { IMoney } from "@saleor/components/Money";
|
|
||||||
import PriceField from "@saleor/components/PriceField";
|
|
||||||
import { OrderErrorFragment } from "@saleor/fragments/types/OrderErrorFragment";
|
import { OrderErrorFragment } from "@saleor/fragments/types/OrderErrorFragment";
|
||||||
|
import { OrderDetails_order } from "@saleor/orders/types/OrderDetails";
|
||||||
import { OrderRefundData_order } from "@saleor/orders/types/OrderRefundData";
|
import { OrderRefundData_order } from "@saleor/orders/types/OrderRefundData";
|
||||||
import {
|
|
||||||
getAllFulfillmentLinesPriceSum,
|
|
||||||
getPreviouslyRefundedPrice,
|
|
||||||
getRefundedLinesPriceSum
|
|
||||||
} from "@saleor/orders/utils/data";
|
|
||||||
import { getFormErrors } from "@saleor/utils/errors";
|
|
||||||
import getOrderErrorMessage from "@saleor/utils/errors/order";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { defineMessages, FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import OrderRefundAmountValues, {
|
|
||||||
OrderRefundAmountValuesProps
|
|
||||||
} from "../OrderRefundAmountValues";
|
|
||||||
import {
|
import {
|
||||||
OrderRefundAmountCalculationMode,
|
OrderRefundAmountCalculationMode,
|
||||||
OrderRefundFormData,
|
OrderRefundFormData,
|
||||||
OrderRefundType
|
OrderRefundType
|
||||||
} from "../OrderRefundPage/form";
|
} from "../OrderRefundPage/form";
|
||||||
|
import { OrderReturnFormData } from "../OrderReturnPage/form";
|
||||||
const getMiscellaneousAmountValues = (
|
import OrderRefundAmountValues, {
|
||||||
order: OrderRefundData_order
|
OrderRefundAmountValuesProps
|
||||||
): OrderRefundAmountValuesProps => {
|
} from "./OrderRefundReturnAmountValues";
|
||||||
const authorizedAmount = order?.total?.gross;
|
import RefundAmountInput from "./RefundAmountInput";
|
||||||
const previouslyRefunded = getPreviouslyRefundedPrice(order);
|
|
||||||
const maxRefund = order?.totalCaptured;
|
|
||||||
|
|
||||||
return {
|
|
||||||
authorizedAmount,
|
|
||||||
maxRefund,
|
|
||||||
previouslyRefunded
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const getProductsAmountValues = (
|
|
||||||
order: OrderRefundData_order,
|
|
||||||
data: OrderRefundFormData
|
|
||||||
): OrderRefundAmountValuesProps => {
|
|
||||||
const authorizedAmount = order?.total?.gross;
|
|
||||||
const shipmentCost =
|
|
||||||
authorizedAmount?.currency &&
|
|
||||||
(order?.shippingPrice?.gross || {
|
|
||||||
amount: 0,
|
|
||||||
currency: authorizedAmount?.currency
|
|
||||||
});
|
|
||||||
const previouslyRefunded = getPreviouslyRefundedPrice(order);
|
|
||||||
const maxRefund = order?.totalCaptured;
|
|
||||||
const refundedLinesSum = getRefundedLinesPriceSum(
|
|
||||||
order?.lines,
|
|
||||||
data.refundedProductQuantities
|
|
||||||
);
|
|
||||||
const allFulfillmentLinesSum = getAllFulfillmentLinesPriceSum(
|
|
||||||
order?.fulfillments,
|
|
||||||
data.refundedFulfilledProductQuantities
|
|
||||||
);
|
|
||||||
const allLinesSum = refundedLinesSum + allFulfillmentLinesSum;
|
|
||||||
const calculatedTotalAmount = data.refundShipmentCosts
|
|
||||||
? allLinesSum + shipmentCost?.amount
|
|
||||||
: allLinesSum;
|
|
||||||
const selectedProductsValue = authorizedAmount?.currency && {
|
|
||||||
amount: allLinesSum,
|
|
||||||
currency: authorizedAmount.currency
|
|
||||||
};
|
|
||||||
const proposedRefundAmount = authorizedAmount?.currency && {
|
|
||||||
amount: calculatedTotalAmount,
|
|
||||||
currency: authorizedAmount.currency
|
|
||||||
};
|
|
||||||
const refundTotalAmount = authorizedAmount?.currency && {
|
|
||||||
amount: calculatedTotalAmount,
|
|
||||||
currency: authorizedAmount.currency
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
authorizedAmount,
|
|
||||||
maxRefund,
|
|
||||||
previouslyRefunded,
|
|
||||||
proposedRefundAmount,
|
|
||||||
refundTotalAmount,
|
|
||||||
selectedProductsValue,
|
|
||||||
shipmentCost
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
|
@ -124,80 +55,54 @@ const useStyles = makeStyles(
|
||||||
{ name: "OrderRefundAmount" }
|
{ name: "OrderRefundAmount" }
|
||||||
);
|
);
|
||||||
|
|
||||||
interface RefundAmountInputProps {
|
const messages = defineMessages({
|
||||||
data: OrderRefundFormData;
|
refundButton: {
|
||||||
maxRefund: IMoney;
|
defaultMessage: "Refund",
|
||||||
currencySymbol: string;
|
description: "order refund amount button"
|
||||||
amountTooSmall: boolean;
|
},
|
||||||
amountTooBig: boolean;
|
refundCannotBeFulfilled: {
|
||||||
disabled: boolean;
|
defaultMessage: "Refunded items can't be fulfilled",
|
||||||
errors: OrderErrorFragment[];
|
description: "order refund subtitle"
|
||||||
onChange: (event: React.ChangeEvent<any>) => void;
|
},
|
||||||
}
|
returnButton: {
|
||||||
|
defaultMessage: "Return & Replace products",
|
||||||
const RefundAmountInput: React.FC<RefundAmountInputProps> = props => {
|
description: "order return amount button"
|
||||||
const {
|
},
|
||||||
data,
|
returnCannotBeFulfilled: {
|
||||||
maxRefund,
|
defaultMessage: "Returned items can't be fulfilled",
|
||||||
amountTooSmall,
|
description: "order return subtitle"
|
||||||
amountTooBig,
|
}
|
||||||
currencySymbol,
|
});
|
||||||
disabled,
|
|
||||||
errors,
|
|
||||||
onChange
|
|
||||||
} = props;
|
|
||||||
const intl = useIntl();
|
|
||||||
const classes = useStyles(props);
|
|
||||||
|
|
||||||
const formErrors = getFormErrors(["amount"], errors);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PriceField
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={onChange}
|
|
||||||
currencySymbol={currencySymbol}
|
|
||||||
name={"amount" as keyof FormData}
|
|
||||||
value={data.amount}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Amount",
|
|
||||||
description: "order refund amount, input label"
|
|
||||||
})}
|
|
||||||
className={classes.priceField}
|
|
||||||
InputProps={{ inputProps: { max: maxRefund?.amount } }}
|
|
||||||
inputProps={{
|
|
||||||
"data-test": "amountInput",
|
|
||||||
max: maxRefund?.amount
|
|
||||||
}}
|
|
||||||
error={!!formErrors.amount || amountTooSmall || amountTooBig}
|
|
||||||
hint={
|
|
||||||
getOrderErrorMessage(formErrors.amount, intl) ||
|
|
||||||
(amountTooSmall &&
|
|
||||||
intl.formatMessage({
|
|
||||||
defaultMessage: "Amount must be bigger than 0"
|
|
||||||
})) ||
|
|
||||||
(amountTooBig &&
|
|
||||||
intl.formatMessage({
|
|
||||||
defaultMessage: "Amount cannot be bigger than max refund"
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface OrderRefundAmountProps {
|
interface OrderRefundAmountProps {
|
||||||
data: OrderRefundFormData;
|
data: OrderRefundFormData | OrderReturnFormData;
|
||||||
order: OrderRefundData_order;
|
order: OrderRefundData_order | OrderDetails_order;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
|
disableSubmitButton?: boolean;
|
||||||
|
isReturn?: boolean;
|
||||||
errors: OrderErrorFragment[];
|
errors: OrderErrorFragment[];
|
||||||
|
amountData: OrderRefundAmountValuesProps;
|
||||||
onChange: (event: React.ChangeEvent<any>) => void;
|
onChange: (event: React.ChangeEvent<any>) => void;
|
||||||
onRefund: () => void;
|
onRefund: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const OrderRefundAmount: React.FC<OrderRefundAmountProps> = props => {
|
const OrderRefundAmount: React.FC<OrderRefundAmountProps> = props => {
|
||||||
const { data, order, disabled, errors, onChange, onRefund } = props;
|
const {
|
||||||
|
data,
|
||||||
|
order,
|
||||||
|
disabled,
|
||||||
|
errors,
|
||||||
|
onChange,
|
||||||
|
onRefund,
|
||||||
|
isReturn = false,
|
||||||
|
amountData,
|
||||||
|
disableSubmitButton
|
||||||
|
} = props;
|
||||||
const classes = useStyles(props);
|
const classes = useStyles(props);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const { type = OrderRefundType.PRODUCTS } = data as OrderRefundFormData;
|
||||||
|
|
||||||
const amountCurrency = order?.total?.gross?.currency;
|
const amountCurrency = order?.total?.gross?.currency;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -207,14 +112,12 @@ const OrderRefundAmount: React.FC<OrderRefundAmountProps> = props => {
|
||||||
proposedRefundAmount,
|
proposedRefundAmount,
|
||||||
refundTotalAmount,
|
refundTotalAmount,
|
||||||
selectedProductsValue,
|
selectedProductsValue,
|
||||||
shipmentCost
|
shipmentCost,
|
||||||
} =
|
replacedProductsValue
|
||||||
data.type === OrderRefundType.PRODUCTS
|
} = amountData;
|
||||||
? getProductsAmountValues(order, data)
|
|
||||||
: getMiscellaneousAmountValues(order);
|
|
||||||
|
|
||||||
const selectedRefundAmount =
|
const selectedRefundAmount =
|
||||||
data.type === OrderRefundType.PRODUCTS &&
|
type === OrderRefundType.PRODUCTS &&
|
||||||
data.amountCalculationMode === OrderRefundAmountCalculationMode.AUTOMATIC
|
data.amountCalculationMode === OrderRefundAmountCalculationMode.AUTOMATIC
|
||||||
? refundTotalAmount?.amount
|
? refundTotalAmount?.amount
|
||||||
: data.amount;
|
: data.amount;
|
||||||
|
@ -222,8 +125,9 @@ const OrderRefundAmount: React.FC<OrderRefundAmountProps> = props => {
|
||||||
const isAmountTooSmall = selectedRefundAmount && selectedRefundAmount <= 0;
|
const isAmountTooSmall = selectedRefundAmount && selectedRefundAmount <= 0;
|
||||||
const isAmountTooBig = selectedRefundAmount > maxRefund?.amount;
|
const isAmountTooBig = selectedRefundAmount > maxRefund?.amount;
|
||||||
|
|
||||||
const disableRefundButton =
|
const disableRefundButton = isReturn
|
||||||
!selectedRefundAmount || isAmountTooSmall || isAmountTooBig;
|
? disableSubmitButton || isAmountTooSmall || isAmountTooBig
|
||||||
|
: !selectedRefundAmount || isAmountTooBig || isAmountTooSmall;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
|
@ -234,7 +138,7 @@ const OrderRefundAmount: React.FC<OrderRefundAmountProps> = props => {
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
{data.type === OrderRefundType.PRODUCTS && (
|
{type === OrderRefundType.PRODUCTS && (
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
value={data.amountCalculationMode}
|
value={data.amountCalculationMode}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
@ -261,6 +165,7 @@ const OrderRefundAmount: React.FC<OrderRefundAmountProps> = props => {
|
||||||
name="refundShipmentCosts"
|
name="refundShipmentCosts"
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
|
<CardSpacer />
|
||||||
<OrderRefundAmountValues
|
<OrderRefundAmountValues
|
||||||
authorizedAmount={authorizedAmount}
|
authorizedAmount={authorizedAmount}
|
||||||
previouslyRefunded={previouslyRefunded}
|
previouslyRefunded={previouslyRefunded}
|
||||||
|
@ -268,8 +173,8 @@ const OrderRefundAmount: React.FC<OrderRefundAmountProps> = props => {
|
||||||
selectedProductsValue={selectedProductsValue}
|
selectedProductsValue={selectedProductsValue}
|
||||||
refundTotalAmount={refundTotalAmount}
|
refundTotalAmount={refundTotalAmount}
|
||||||
shipmentCost={data.refundShipmentCosts && shipmentCost}
|
shipmentCost={data.refundShipmentCosts && shipmentCost}
|
||||||
|
replacedProductsValue={replacedProductsValue}
|
||||||
/>
|
/>
|
||||||
<CardSpacer />
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Hr className={classes.hr} />
|
<Hr className={classes.hr} />
|
||||||
|
@ -302,9 +207,10 @@ const OrderRefundAmount: React.FC<OrderRefundAmountProps> = props => {
|
||||||
selectedProductsValue={selectedProductsValue}
|
selectedProductsValue={selectedProductsValue}
|
||||||
proposedRefundAmount={proposedRefundAmount}
|
proposedRefundAmount={proposedRefundAmount}
|
||||||
shipmentCost={data.refundShipmentCosts && shipmentCost}
|
shipmentCost={data.refundShipmentCosts && shipmentCost}
|
||||||
|
replacedProductsValue={replacedProductsValue}
|
||||||
/>
|
/>
|
||||||
<RefundAmountInput
|
<RefundAmountInput
|
||||||
data={data}
|
data={data as OrderRefundFormData}
|
||||||
maxRefund={maxRefund}
|
maxRefund={maxRefund}
|
||||||
amountTooSmall={isAmountTooSmall}
|
amountTooSmall={isAmountTooSmall}
|
||||||
amountTooBig={isAmountTooBig}
|
amountTooBig={isAmountTooBig}
|
||||||
|
@ -317,7 +223,7 @@ const OrderRefundAmount: React.FC<OrderRefundAmountProps> = props => {
|
||||||
)}
|
)}
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
)}
|
)}
|
||||||
{data.type === OrderRefundType.MISCELLANEOUS && (
|
{type === OrderRefundType.MISCELLANEOUS && (
|
||||||
<>
|
<>
|
||||||
<OrderRefundAmountValues
|
<OrderRefundAmountValues
|
||||||
authorizedAmount={authorizedAmount}
|
authorizedAmount={authorizedAmount}
|
||||||
|
@ -325,7 +231,7 @@ const OrderRefundAmount: React.FC<OrderRefundAmountProps> = props => {
|
||||||
maxRefund={maxRefund}
|
maxRefund={maxRefund}
|
||||||
/>
|
/>
|
||||||
<RefundAmountInput
|
<RefundAmountInput
|
||||||
data={data}
|
data={data as OrderRefundFormData}
|
||||||
maxRefund={maxRefund}
|
maxRefund={maxRefund}
|
||||||
amountTooSmall={isAmountTooSmall}
|
amountTooSmall={isAmountTooSmall}
|
||||||
amountTooBig={isAmountTooBig}
|
amountTooBig={isAmountTooBig}
|
||||||
|
@ -337,17 +243,16 @@ const OrderRefundAmount: React.FC<OrderRefundAmountProps> = props => {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
fullWidth
|
fullWidth
|
||||||
size="large"
|
size="large"
|
||||||
onClick={onRefund}
|
onClick={onRefund}
|
||||||
className={classes.refundButton}
|
className={classes.refundButton}
|
||||||
disabled={disabled || disableRefundButton}
|
disabled={disableRefundButton}
|
||||||
data-test="submit"
|
data-test="submit"
|
||||||
>
|
>
|
||||||
{!disableRefundButton ? (
|
{!disableRefundButton && !isReturn ? (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Refund {currency} {amount}"
|
defaultMessage="Refund {currency} {amount}"
|
||||||
description="order refund amount, input button"
|
description="order refund amount, input button"
|
||||||
|
@ -357,10 +262,9 @@ const OrderRefundAmount: React.FC<OrderRefundAmountProps> = props => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<FormattedMessage
|
intl.formatMessage(
|
||||||
defaultMessage="Refund"
|
isReturn ? messages.returnButton : messages.refundButton
|
||||||
description="order refund amount, input button"
|
)
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
<Typography
|
<Typography
|
||||||
|
@ -368,10 +272,11 @@ const OrderRefundAmount: React.FC<OrderRefundAmountProps> = props => {
|
||||||
color="textSecondary"
|
color="textSecondary"
|
||||||
className={classes.refundCaution}
|
className={classes.refundCaution}
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
{intl.formatMessage(
|
||||||
defaultMessage="Refunded items can’t be fulfilled"
|
isReturn
|
||||||
description="order refund amount"
|
? messages.returnCannotBeFulfilled
|
||||||
/>
|
: messages.refundCannotBeFulfilled
|
||||||
|
)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
|
@ -0,0 +1,133 @@
|
||||||
|
import { makeStyles } from "@material-ui/core";
|
||||||
|
import Money, { IMoney } from "@saleor/components/Money";
|
||||||
|
import Skeleton from "@saleor/components/Skeleton";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import { reduce } from "lodash";
|
||||||
|
import React from "react";
|
||||||
|
import { useIntl } from "react-intl";
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
container: {
|
||||||
|
...theme.typography.body1,
|
||||||
|
lineHeight: 1.9,
|
||||||
|
width: "100%"
|
||||||
|
},
|
||||||
|
highlightedRow: {
|
||||||
|
fontWeight: 600
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
marginBottom: theme.spacing(2),
|
||||||
|
textAlign: "right"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "OrderRefundAmountValues" }
|
||||||
|
);
|
||||||
|
|
||||||
|
export interface OrderRefundAmountValuesProps {
|
||||||
|
authorizedAmount: IMoney;
|
||||||
|
shipmentCost?: IMoney;
|
||||||
|
selectedProductsValue?: IMoney;
|
||||||
|
previouslyRefunded: IMoney;
|
||||||
|
maxRefund: IMoney;
|
||||||
|
proposedRefundAmount?: IMoney;
|
||||||
|
replacedProductsValue?: IMoney;
|
||||||
|
refundTotalAmount?: IMoney;
|
||||||
|
}
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
authorizedAmount: {
|
||||||
|
defaultMessage: "Authorized Amount",
|
||||||
|
description: "order refund amount"
|
||||||
|
},
|
||||||
|
maxRefund: {
|
||||||
|
defaultMessage: "Max Refund",
|
||||||
|
description: "order refund amount"
|
||||||
|
},
|
||||||
|
previouslyRefunded: {
|
||||||
|
defaultMessage: "Previously refunded",
|
||||||
|
description: "order refund amount"
|
||||||
|
},
|
||||||
|
proposedRefundAmount: {
|
||||||
|
defaultMessage: "Proposed refund amount",
|
||||||
|
description: "order refund amount"
|
||||||
|
},
|
||||||
|
refundTotalAmount: {
|
||||||
|
defaultMessage: "Refund total amount",
|
||||||
|
description: "order refund amount"
|
||||||
|
},
|
||||||
|
replacedProductsValue: {
|
||||||
|
defaultMessage: "Replaced Products Value",
|
||||||
|
description: "order refund amount"
|
||||||
|
},
|
||||||
|
selectedProductsValue: {
|
||||||
|
defaultMessage: "Selected Products Value",
|
||||||
|
description: "order refund amount"
|
||||||
|
},
|
||||||
|
shipmentCost: {
|
||||||
|
defaultMessage: "Shipment Cost",
|
||||||
|
description: "order refund amount"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const OrderRefundAmountValues: React.FC<OrderRefundAmountValuesProps> = props => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const classes = useStyles({});
|
||||||
|
|
||||||
|
const orderedKeys: Array<keyof OrderRefundAmountValuesProps> = [
|
||||||
|
"authorizedAmount",
|
||||||
|
"shipmentCost",
|
||||||
|
"selectedProductsValue",
|
||||||
|
"previouslyRefunded",
|
||||||
|
"replacedProductsValue",
|
||||||
|
"maxRefund",
|
||||||
|
"refundTotalAmount"
|
||||||
|
];
|
||||||
|
|
||||||
|
const highlightedItems: Array<keyof OrderRefundAmountValuesProps> = [
|
||||||
|
"maxRefund",
|
||||||
|
"refundTotalAmount"
|
||||||
|
];
|
||||||
|
|
||||||
|
const items = reduce(
|
||||||
|
orderedKeys,
|
||||||
|
(result, key) => {
|
||||||
|
const value = props[key];
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
...result,
|
||||||
|
{ data: value, highlighted: highlightedItems.includes(key), key }
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.container}>
|
||||||
|
{items.map(({ key, data, highlighted }) => (
|
||||||
|
<div
|
||||||
|
className={classNames(classes.row, {
|
||||||
|
[classes.highlightedRow]: highlighted
|
||||||
|
})}
|
||||||
|
key={key}
|
||||||
|
>
|
||||||
|
{intl.formatMessage(messages[key])}
|
||||||
|
<div>
|
||||||
|
{data?.amount !== undefined ? <Money money={data} /> : <Skeleton />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
OrderRefundAmountValues.displayName = "OrderRefundAmountValues";
|
||||||
|
export default OrderRefundAmountValues;
|
|
@ -0,0 +1,108 @@
|
||||||
|
import { makeStyles } from "@material-ui/core";
|
||||||
|
import { IMoney } from "@saleor/components/Money";
|
||||||
|
import PriceField from "@saleor/components/PriceField";
|
||||||
|
import { OrderErrorFragment } from "@saleor/fragments/types/OrderErrorFragment";
|
||||||
|
import { getFormErrors } from "@saleor/utils/errors";
|
||||||
|
import getOrderErrorMessage from "@saleor/utils/errors/order";
|
||||||
|
import React from "react";
|
||||||
|
import { defineMessages, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import { OrderRefundFormData } from "../OrderRefundPage/form";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
hr: {
|
||||||
|
margin: theme.spacing(1, 0)
|
||||||
|
},
|
||||||
|
maxRefundRow: {
|
||||||
|
fontWeight: 600
|
||||||
|
},
|
||||||
|
priceField: {
|
||||||
|
marginTop: theme.spacing(2)
|
||||||
|
},
|
||||||
|
refundButton: {
|
||||||
|
marginTop: theme.spacing(2)
|
||||||
|
},
|
||||||
|
refundCaution: {
|
||||||
|
marginTop: theme.spacing(1)
|
||||||
|
},
|
||||||
|
root: {
|
||||||
|
...theme.typography.body1,
|
||||||
|
lineHeight: 1.9,
|
||||||
|
width: "100%"
|
||||||
|
},
|
||||||
|
textRight: {
|
||||||
|
textAlign: "right"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "OrderRefundAmount" }
|
||||||
|
);
|
||||||
|
|
||||||
|
interface RefundAmountInputProps {
|
||||||
|
data: OrderRefundFormData;
|
||||||
|
maxRefund: IMoney;
|
||||||
|
currencySymbol: string;
|
||||||
|
amountTooSmall: boolean;
|
||||||
|
amountTooBig: boolean;
|
||||||
|
disabled: boolean;
|
||||||
|
errors: OrderErrorFragment[];
|
||||||
|
onChange: (event: React.ChangeEvent<any>) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
amountTooBig: {
|
||||||
|
defaultMessage: "Amount cannot be bigger than max refund",
|
||||||
|
description: "Amount error message"
|
||||||
|
},
|
||||||
|
amountTooSmall: {
|
||||||
|
defaultMessage: "Amount must be bigger than 0",
|
||||||
|
description: "Amount error message"
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
defaultMessage: "Amount",
|
||||||
|
description: "order refund amount, input label"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const RefundAmountInput: React.FC<RefundAmountInputProps> = props => {
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
maxRefund,
|
||||||
|
amountTooSmall,
|
||||||
|
amountTooBig,
|
||||||
|
currencySymbol,
|
||||||
|
disabled,
|
||||||
|
errors,
|
||||||
|
onChange
|
||||||
|
} = props;
|
||||||
|
const intl = useIntl();
|
||||||
|
const classes = useStyles(props);
|
||||||
|
const formErrors = getFormErrors(["amount"], errors);
|
||||||
|
|
||||||
|
const isError = !!formErrors.amount || amountTooSmall || amountTooBig;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PriceField
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={onChange}
|
||||||
|
currencySymbol={currencySymbol}
|
||||||
|
name={"amount" as keyof FormData}
|
||||||
|
value={data.amount}
|
||||||
|
label={intl.formatMessage(messages.label)}
|
||||||
|
className={classes.priceField}
|
||||||
|
InputProps={{ inputProps: { max: maxRefund?.amount } }}
|
||||||
|
inputProps={{
|
||||||
|
"data-test": "amountInput",
|
||||||
|
max: maxRefund?.amount
|
||||||
|
}}
|
||||||
|
error={isError}
|
||||||
|
hint={
|
||||||
|
getOrderErrorMessage(formErrors.amount, intl) ||
|
||||||
|
(amountTooSmall && intl.formatMessage(messages.amountTooSmall)) ||
|
||||||
|
(amountTooBig && intl.formatMessage(messages.amountTooBig))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RefundAmountInput;
|
2
src/orders/components/OrderRefundReturnAmount/index.ts
Normal file
2
src/orders/components/OrderRefundReturnAmount/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./OrderRefundReturnAmount";
|
||||||
|
export { default } from "./OrderRefundReturnAmount";
|
203
src/orders/components/OrderRefundReturnAmount/utils.ts
Normal file
203
src/orders/components/OrderRefundReturnAmount/utils.ts
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
import { IMoney } from "@saleor/components/Money";
|
||||||
|
import { FormsetData } from "@saleor/hooks/useFormset";
|
||||||
|
import { OrderDetails_order } from "@saleor/orders/types/OrderDetails";
|
||||||
|
import { OrderRefundData_order } from "@saleor/orders/types/OrderRefundData";
|
||||||
|
import {
|
||||||
|
getAllFulfillmentLinesPriceSum,
|
||||||
|
getPreviouslyRefundedPrice,
|
||||||
|
getRefundedLinesPriceSum,
|
||||||
|
getReplacedProductsAmount,
|
||||||
|
getReturnSelectedProductsAmount
|
||||||
|
} from "@saleor/orders/utils/data";
|
||||||
|
|
||||||
|
import { OrderRefundFormData } from "../OrderRefundPage/form";
|
||||||
|
import { LineItemData, OrderReturnFormData } from "../OrderReturnPage/form";
|
||||||
|
import { OrderRefundAmountValuesProps } from "./OrderRefundReturnAmountValues";
|
||||||
|
|
||||||
|
export const getMiscellaneousAmountValues = (
|
||||||
|
order: OrderRefundData_order
|
||||||
|
): OrderRefundAmountValuesProps => {
|
||||||
|
const authorizedAmount = order?.total?.gross;
|
||||||
|
const previouslyRefunded = getPreviouslyRefundedPrice(order);
|
||||||
|
const maxRefund = order?.totalCaptured;
|
||||||
|
|
||||||
|
return {
|
||||||
|
authorizedAmount,
|
||||||
|
maxRefund,
|
||||||
|
previouslyRefunded
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAuthorizedAmount = (order: OrderRefundData_order) =>
|
||||||
|
order?.total?.gross;
|
||||||
|
|
||||||
|
const getShipmentCost = (order: OrderRefundData_order) =>
|
||||||
|
getAuthorizedAmount(order)?.currency &&
|
||||||
|
(order?.shippingPrice?.gross || {
|
||||||
|
amount: 0,
|
||||||
|
currency: getAuthorizedAmount(order)?.currency
|
||||||
|
});
|
||||||
|
|
||||||
|
const getMaxRefund = (order: OrderRefundData_order) => order?.totalCaptured;
|
||||||
|
|
||||||
|
export const getProductsAmountValues = (
|
||||||
|
order: OrderRefundData_order,
|
||||||
|
fulfilledItemsQuantities: FormsetData<null | LineItemData, string | number>,
|
||||||
|
unfulfilledItemsQuantities: FormsetData<null | LineItemData, string | number>,
|
||||||
|
shipmentCosts
|
||||||
|
): OrderRefundAmountValuesProps => {
|
||||||
|
const authorizedAmount = getAuthorizedAmount(order);
|
||||||
|
const shipmentCost = getShipmentCost(order);
|
||||||
|
|
||||||
|
const previouslyRefunded = getPreviouslyRefundedPrice(order);
|
||||||
|
const maxRefund = getMaxRefund(order);
|
||||||
|
const refundedLinesSum = getRefundedLinesPriceSum(
|
||||||
|
order?.lines,
|
||||||
|
unfulfilledItemsQuantities as FormsetData<null, string>
|
||||||
|
);
|
||||||
|
const allFulfillmentLinesSum = getAllFulfillmentLinesPriceSum(
|
||||||
|
order?.fulfillments,
|
||||||
|
fulfilledItemsQuantities as FormsetData<null, string>
|
||||||
|
);
|
||||||
|
const allLinesSum = refundedLinesSum + allFulfillmentLinesSum;
|
||||||
|
const calculatedTotalAmount = getCalculatedTotalAmount({
|
||||||
|
allLinesSum,
|
||||||
|
maxRefund,
|
||||||
|
previouslyRefunded,
|
||||||
|
shipmentCost,
|
||||||
|
shipmentCosts
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedProductsValue = authorizedAmount?.currency && {
|
||||||
|
amount: allLinesSum,
|
||||||
|
currency: authorizedAmount.currency
|
||||||
|
};
|
||||||
|
|
||||||
|
const proposedRefundAmount = authorizedAmount?.currency && {
|
||||||
|
amount: calculatedTotalAmount,
|
||||||
|
currency: authorizedAmount.currency
|
||||||
|
};
|
||||||
|
const refundTotalAmount = authorizedAmount?.currency && {
|
||||||
|
amount: calculatedTotalAmount,
|
||||||
|
currency: authorizedAmount.currency
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
authorizedAmount,
|
||||||
|
maxRefund,
|
||||||
|
previouslyRefunded,
|
||||||
|
proposedRefundAmount,
|
||||||
|
refundTotalAmount,
|
||||||
|
selectedProductsValue,
|
||||||
|
shipmentCost
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCalculatedTotalAmount = ({
|
||||||
|
shipmentCost,
|
||||||
|
shipmentCosts,
|
||||||
|
allLinesSum,
|
||||||
|
maxRefund
|
||||||
|
}: {
|
||||||
|
shipmentCost: IMoney;
|
||||||
|
shipmentCosts: IMoney;
|
||||||
|
allLinesSum: number;
|
||||||
|
previouslyRefunded: IMoney;
|
||||||
|
maxRefund: IMoney;
|
||||||
|
}) => {
|
||||||
|
if (maxRefund?.amount === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shipmentCostValue = shipmentCost ? shipmentCost.amount : 0;
|
||||||
|
|
||||||
|
const calculatedTotalAmount = shipmentCosts
|
||||||
|
? allLinesSum + shipmentCostValue
|
||||||
|
: allLinesSum;
|
||||||
|
|
||||||
|
return calculatedTotalAmount;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getReturnTotalAmount = ({
|
||||||
|
selectedProductsValue,
|
||||||
|
refundShipmentCosts,
|
||||||
|
order,
|
||||||
|
maxRefund
|
||||||
|
}: {
|
||||||
|
order: OrderDetails_order;
|
||||||
|
selectedProductsValue: IMoney;
|
||||||
|
refundShipmentCosts: boolean;
|
||||||
|
maxRefund: IMoney;
|
||||||
|
}) => {
|
||||||
|
if (maxRefund?.amount === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refundShipmentCosts) {
|
||||||
|
const totalValue =
|
||||||
|
selectedProductsValue?.amount + getShipmentCost(order)?.amount;
|
||||||
|
return totalValue || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedProductsValue?.amount || 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getReturnProductsAmountValues = (
|
||||||
|
order: OrderDetails_order,
|
||||||
|
formData: OrderReturnFormData
|
||||||
|
) => {
|
||||||
|
const authorizedAmount = getAuthorizedAmount(order);
|
||||||
|
|
||||||
|
const {
|
||||||
|
fulfiledItemsQuantities,
|
||||||
|
unfulfiledItemsQuantities,
|
||||||
|
refundShipmentCosts
|
||||||
|
} = formData;
|
||||||
|
|
||||||
|
const replacedProductsValue = authorizedAmount?.currency && {
|
||||||
|
amount: getReplacedProductsAmount(order, formData),
|
||||||
|
currency: authorizedAmount.currency
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectedProductsValue = authorizedAmount?.currency && {
|
||||||
|
amount: getReturnSelectedProductsAmount(order, formData),
|
||||||
|
currency: authorizedAmount.currency
|
||||||
|
};
|
||||||
|
|
||||||
|
const refundTotalAmount = authorizedAmount?.currency && {
|
||||||
|
amount: getReturnTotalAmount({
|
||||||
|
maxRefund: getMaxRefund(order),
|
||||||
|
order,
|
||||||
|
refundShipmentCosts,
|
||||||
|
selectedProductsValue
|
||||||
|
}),
|
||||||
|
currency: authorizedAmount.currency
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...getProductsAmountValues(
|
||||||
|
order,
|
||||||
|
fulfiledItemsQuantities,
|
||||||
|
unfulfiledItemsQuantities,
|
||||||
|
refundShipmentCosts
|
||||||
|
),
|
||||||
|
refundTotalAmount,
|
||||||
|
replacedProductsValue,
|
||||||
|
selectedProductsValue
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRefundProductsAmountValues = (
|
||||||
|
order: OrderRefundData_order,
|
||||||
|
{
|
||||||
|
refundedFulfilledProductQuantities,
|
||||||
|
refundShipmentCosts,
|
||||||
|
refundedProductQuantities
|
||||||
|
}: OrderRefundFormData
|
||||||
|
) =>
|
||||||
|
getProductsAmountValues(
|
||||||
|
order,
|
||||||
|
refundedFulfilledProductQuantities,
|
||||||
|
refundedProductQuantities,
|
||||||
|
refundShipmentCosts
|
||||||
|
);
|
129
src/orders/components/OrderReturnPage/OrderReturnPage.tsx
Normal file
129
src/orders/components/OrderReturnPage/OrderReturnPage.tsx
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
import AppHeader from "@saleor/components/AppHeader";
|
||||||
|
import CardSpacer from "@saleor/components/CardSpacer";
|
||||||
|
import Container from "@saleor/components/Container";
|
||||||
|
import Grid from "@saleor/components/Grid";
|
||||||
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
|
import { OrderErrorFragment } from "@saleor/fragments/types/OrderErrorFragment";
|
||||||
|
import { SubmitPromise } from "@saleor/hooks/useForm";
|
||||||
|
import { renderCollection } from "@saleor/misc";
|
||||||
|
import { OrderDetails_order } from "@saleor/orders/types/OrderDetails";
|
||||||
|
import React from "react";
|
||||||
|
import { defineMessages, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import OrderAmount from "../OrderRefundReturnAmount";
|
||||||
|
import { getReturnProductsAmountValues } from "../OrderRefundReturnAmount/utils";
|
||||||
|
import OrderRefundForm, { OrderRefundSubmitData } from "./form";
|
||||||
|
import ItemsCard from "./OrderReturnRefundItemsCard/ReturnItemsCard";
|
||||||
|
import {
|
||||||
|
getFulfilledFulfillemnts,
|
||||||
|
getParsedFulfiledLines,
|
||||||
|
getUnfulfilledLines
|
||||||
|
} from "./utils";
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
appTitle: {
|
||||||
|
defaultMessage: "Order #{orderNumber}",
|
||||||
|
description: "page header with order number"
|
||||||
|
},
|
||||||
|
pageTitle: {
|
||||||
|
defaultMessage: "Order no. {orderNumber} - Replace/Return",
|
||||||
|
description: "page header"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export interface OrderReturnPageProps {
|
||||||
|
order: OrderDetails_order;
|
||||||
|
loading: boolean;
|
||||||
|
errors?: OrderErrorFragment[];
|
||||||
|
onBack: () => void;
|
||||||
|
onSubmit: (data: OrderRefundSubmitData) => SubmitPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
const OrderRefundPage: React.FC<OrderReturnPageProps> = props => {
|
||||||
|
const { order, loading, errors = [], onBack, onSubmit } = props;
|
||||||
|
|
||||||
|
const intl = useIntl();
|
||||||
|
return (
|
||||||
|
<OrderRefundForm order={order} onSubmit={onSubmit}>
|
||||||
|
{({ data, handlers, change, submit }) => {
|
||||||
|
const { fulfiledItemsQuantities, unfulfiledItemsQuantities } = data;
|
||||||
|
|
||||||
|
const hasAnyItemsSelected =
|
||||||
|
fulfiledItemsQuantities.some(({ value }) => !!value) ||
|
||||||
|
unfulfiledItemsQuantities.some(({ value }) => !!value);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<AppHeader onBack={onBack}>
|
||||||
|
{intl.formatMessage(messages.appTitle, {
|
||||||
|
orderNumber: order?.number
|
||||||
|
})}
|
||||||
|
</AppHeader>
|
||||||
|
<PageHeader
|
||||||
|
title={intl.formatMessage(messages.pageTitle, {
|
||||||
|
orderNumber: order?.number
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<Grid>
|
||||||
|
<div>
|
||||||
|
{!!data.unfulfiledItemsQuantities.length && (
|
||||||
|
<>
|
||||||
|
<ItemsCard
|
||||||
|
errors={errors}
|
||||||
|
order={order}
|
||||||
|
lines={getUnfulfilledLines(order)}
|
||||||
|
itemsQuantities={data.unfulfiledItemsQuantities}
|
||||||
|
itemsSelections={data.itemsToBeReplaced}
|
||||||
|
onChangeQuantity={handlers.changeUnfulfiledItemsQuantity}
|
||||||
|
onSetMaxQuantity={
|
||||||
|
handlers.handleSetMaximalUnfulfiledItemsQuantities
|
||||||
|
}
|
||||||
|
onChangeSelected={handlers.changeItemsToBeReplaced}
|
||||||
|
/>
|
||||||
|
<CardSpacer />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{renderCollection(
|
||||||
|
getFulfilledFulfillemnts(order),
|
||||||
|
({ id, lines }) => (
|
||||||
|
<React.Fragment key={id}>
|
||||||
|
<ItemsCard
|
||||||
|
errors={errors}
|
||||||
|
order={order}
|
||||||
|
fulfilmentId={id}
|
||||||
|
lines={getParsedFulfiledLines(lines)}
|
||||||
|
itemsQuantities={data.fulfiledItemsQuantities}
|
||||||
|
itemsSelections={data.itemsToBeReplaced}
|
||||||
|
onChangeQuantity={handlers.changeFulfiledItemsQuantity}
|
||||||
|
onSetMaxQuantity={handlers.handleSetMaximalFulfiledItemsQuantities(
|
||||||
|
id
|
||||||
|
)}
|
||||||
|
onChangeSelected={handlers.changeItemsToBeReplaced}
|
||||||
|
/>
|
||||||
|
<CardSpacer />
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<OrderAmount
|
||||||
|
isReturn
|
||||||
|
amountData={getReturnProductsAmountValues(order, data)}
|
||||||
|
data={data}
|
||||||
|
order={order}
|
||||||
|
disableSubmitButton={!hasAnyItemsSelected}
|
||||||
|
disabled={loading}
|
||||||
|
errors={errors}
|
||||||
|
onChange={change}
|
||||||
|
onRefund={submit}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</OrderRefundForm>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OrderRefundPage;
|
|
@ -0,0 +1,135 @@
|
||||||
|
import { makeStyles, Typography } from "@material-ui/core";
|
||||||
|
import DefaultCardTitle from "@saleor/components/CardTitle";
|
||||||
|
import { StatusType } from "@saleor/components/StatusChip/types";
|
||||||
|
import StatusLabel from "@saleor/components/StatusLabel";
|
||||||
|
import { FulfillmentStatus } from "@saleor/types/globalTypes";
|
||||||
|
import camelCase from "lodash/camelCase";
|
||||||
|
import React from "react";
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
orderNumber: {
|
||||||
|
display: "inline",
|
||||||
|
marginLeft: theme.spacing(1)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "CardTitle" }
|
||||||
|
);
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
cancelled: {
|
||||||
|
defaultMessage: "Cancelled ({quantity})",
|
||||||
|
description: "cancelled fulfillment, section header"
|
||||||
|
},
|
||||||
|
fulfilled: {
|
||||||
|
defaultMessage: "Fulfilled ({quantity})",
|
||||||
|
description: "section header"
|
||||||
|
},
|
||||||
|
refunded: {
|
||||||
|
defaultMessage: "Refunded ({quantity})",
|
||||||
|
description: "refunded fulfillment, section header"
|
||||||
|
},
|
||||||
|
refundedAndReturned: {
|
||||||
|
defaultMessage: "Refunded and Returned ({quantity})",
|
||||||
|
description: "cancelled fulfillment, section header"
|
||||||
|
},
|
||||||
|
replaced: {
|
||||||
|
defaultMessage: "Replaced ({quantity})",
|
||||||
|
description: "refunded fulfillment, section header"
|
||||||
|
},
|
||||||
|
returned: {
|
||||||
|
defaultMessage: "Returned ({quantity})",
|
||||||
|
description: "refunded fulfillment, section header"
|
||||||
|
},
|
||||||
|
unfulfilled: {
|
||||||
|
defaultMessage: "Unfulfilled",
|
||||||
|
description: "section header"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
type CardTitleStatus = FulfillmentStatus | "unfulfilled";
|
||||||
|
|
||||||
|
type CardTitleLines = Array<{
|
||||||
|
quantity: number;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
interface CardTitleProps {
|
||||||
|
lines?: CardTitleLines;
|
||||||
|
fulfillmentOrder?: number;
|
||||||
|
status: CardTitleStatus;
|
||||||
|
toolbar?: React.ReactNode;
|
||||||
|
orderNumber?: string;
|
||||||
|
withStatus?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectStatus = (status: CardTitleStatus) => {
|
||||||
|
switch (status) {
|
||||||
|
case FulfillmentStatus.FULFILLED:
|
||||||
|
return StatusType.SUCCESS;
|
||||||
|
case FulfillmentStatus.REFUNDED:
|
||||||
|
return StatusType.NEUTRAL;
|
||||||
|
case FulfillmentStatus.RETURNED:
|
||||||
|
return StatusType.NEUTRAL;
|
||||||
|
case FulfillmentStatus.REPLACED:
|
||||||
|
return StatusType.NEUTRAL;
|
||||||
|
case FulfillmentStatus.REFUNDED_AND_RETURNED:
|
||||||
|
return StatusType.NEUTRAL;
|
||||||
|
case FulfillmentStatus.CANCELED:
|
||||||
|
return StatusType.ERROR;
|
||||||
|
default:
|
||||||
|
return StatusType.ALERT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const CardTitle: React.FC<CardTitleProps> = ({
|
||||||
|
lines = [],
|
||||||
|
fulfillmentOrder,
|
||||||
|
status,
|
||||||
|
orderNumber = "",
|
||||||
|
withStatus = false,
|
||||||
|
toolbar
|
||||||
|
}) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const classes = useStyles({});
|
||||||
|
|
||||||
|
const fulfillmentName =
|
||||||
|
orderNumber && fulfillmentOrder
|
||||||
|
? `#${orderNumber}-${fulfillmentOrder}`
|
||||||
|
: "";
|
||||||
|
|
||||||
|
const messageForStatus = messages[camelCase(status)] || messages.unfulfilled;
|
||||||
|
|
||||||
|
const totalQuantity = lines.reduce(
|
||||||
|
(resultQuantity, { quantity }) => resultQuantity + quantity,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
const title = (
|
||||||
|
<>
|
||||||
|
{intl.formatMessage(messageForStatus, {
|
||||||
|
fulfillmentName,
|
||||||
|
quantity: totalQuantity
|
||||||
|
})}
|
||||||
|
<Typography className={classes.orderNumber} variant="body1">
|
||||||
|
{fulfillmentName}
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaultCardTitle
|
||||||
|
toolbar={toolbar}
|
||||||
|
title={
|
||||||
|
withStatus ? (
|
||||||
|
<StatusLabel label={title} status={selectStatus(status)} />
|
||||||
|
) : (
|
||||||
|
title
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CardTitle;
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { Button, makeStyles } from "@material-ui/core";
|
||||||
|
import React from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
button: {
|
||||||
|
letterSpacing: 2,
|
||||||
|
marginBottom: theme.spacing(1),
|
||||||
|
marginTop: theme.spacing(3),
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "MaximalButton" }
|
||||||
|
);
|
||||||
|
|
||||||
|
interface MaximalButtonProps {
|
||||||
|
onClick: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MaximalButton: React.FC<MaximalButtonProps> = ({ onClick }) => {
|
||||||
|
const classes = useStyles({});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
className={classes.button}
|
||||||
|
color="primary"
|
||||||
|
onClick={onClick}
|
||||||
|
data-test="setMaximalQuantityUnfulfilledButton"
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Set maximal quantities"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MaximalButton;
|
|
@ -0,0 +1,100 @@
|
||||||
|
import Popper from "@material-ui/core/Popper";
|
||||||
|
import makeStyles from "@material-ui/core/styles/makeStyles";
|
||||||
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
import ErrorExclamationCircleIcon from "@saleor/icons/ErrorExclamationCircle";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
container: {
|
||||||
|
position: "relative"
|
||||||
|
},
|
||||||
|
errorBox: {
|
||||||
|
backgroundColor: theme.palette.error.main,
|
||||||
|
borderRadius: 8,
|
||||||
|
marginRight: theme.spacing(3),
|
||||||
|
padding: theme.spacing(2, 3),
|
||||||
|
width: 280,
|
||||||
|
zIndex: 1000
|
||||||
|
},
|
||||||
|
errorText: {
|
||||||
|
color: "white",
|
||||||
|
fontSize: 14
|
||||||
|
},
|
||||||
|
errorTextHighlighted: {
|
||||||
|
color: theme.palette.error.main,
|
||||||
|
fontSize: 12,
|
||||||
|
marginRight: theme.spacing(1)
|
||||||
|
},
|
||||||
|
titleContainer: {
|
||||||
|
alignItems: "center",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "flex-end"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "ProductErrorCell" }
|
||||||
|
);
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
description: {
|
||||||
|
defaultMessage:
|
||||||
|
"This product is no longer in database so it can’t be replaced, nor returned",
|
||||||
|
description: "product no longer exists error description"
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
defaultMessage: "Product no longer exists",
|
||||||
|
description: "product no longer exists error title"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
interface ProductErrorCellProps {
|
||||||
|
hasVariant: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProductErrorCell: React.FC<ProductErrorCellProps> = ({ hasVariant }) => {
|
||||||
|
const classes = useStyles({});
|
||||||
|
const intl = useIntl();
|
||||||
|
const popperAnchorRef = React.useRef<HTMLButtonElement | null>(null);
|
||||||
|
|
||||||
|
const [showErrorBox, setShowErrorBox] = useState<boolean>(false);
|
||||||
|
|
||||||
|
if (hasVariant) {
|
||||||
|
return <TableCell />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableCell
|
||||||
|
align="right"
|
||||||
|
className={classes.container}
|
||||||
|
ref={popperAnchorRef}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={classes.titleContainer}
|
||||||
|
onMouseEnter={() => setShowErrorBox(true)}
|
||||||
|
onMouseLeave={() => setShowErrorBox(false)}
|
||||||
|
>
|
||||||
|
<Typography className={classes.errorTextHighlighted}>
|
||||||
|
{intl.formatMessage(messages.title)}
|
||||||
|
</Typography>
|
||||||
|
<ErrorExclamationCircleIcon />
|
||||||
|
</div>
|
||||||
|
<Popper
|
||||||
|
placement="bottom-end"
|
||||||
|
open={showErrorBox}
|
||||||
|
anchorEl={popperAnchorRef.current}
|
||||||
|
>
|
||||||
|
<div className={classes.errorBox}>
|
||||||
|
<Typography className={classes.errorText}>
|
||||||
|
{intl.formatMessage(messages.description)}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</Popper>
|
||||||
|
</TableCell>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProductErrorCell;
|
|
@ -0,0 +1,262 @@
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
Checkbox,
|
||||||
|
makeStyles,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
TextField
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import Money from "@saleor/components/Money";
|
||||||
|
import Skeleton from "@saleor/components/Skeleton";
|
||||||
|
import TableCellAvatar from "@saleor/components/TableCellAvatar";
|
||||||
|
import { OrderErrorFragment } from "@saleor/fragments/types/OrderErrorFragment";
|
||||||
|
import { FormsetChange } from "@saleor/hooks/useFormset";
|
||||||
|
import { renderCollection } from "@saleor/misc";
|
||||||
|
import {
|
||||||
|
OrderDetails_order,
|
||||||
|
OrderDetails_order_lines
|
||||||
|
} from "@saleor/orders/types/OrderDetails";
|
||||||
|
import React, { CSSProperties } from "react";
|
||||||
|
import { defineMessages, FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import { FormsetQuantityData, FormsetReplacementData } from "../form";
|
||||||
|
import { getById } from "../utils";
|
||||||
|
import CardTitle from "./CardTitle";
|
||||||
|
import MaximalButton from "./MaximalButton";
|
||||||
|
import ProductErrorCell from "./ProductErrorCell";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => {
|
||||||
|
const inputPadding: CSSProperties = {
|
||||||
|
paddingBottom: theme.spacing(2),
|
||||||
|
paddingTop: theme.spacing(2)
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
cartContent: {
|
||||||
|
paddingBottom: 0,
|
||||||
|
paddingTop: 0
|
||||||
|
},
|
||||||
|
|
||||||
|
notice: {
|
||||||
|
marginBottom: theme.spacing(1),
|
||||||
|
marginTop: theme.spacing(2)
|
||||||
|
},
|
||||||
|
|
||||||
|
quantityInnerInput: {
|
||||||
|
...inputPadding
|
||||||
|
},
|
||||||
|
quantityInnerInputNoRemaining: {
|
||||||
|
paddingRight: 0
|
||||||
|
},
|
||||||
|
remainingQuantity: {
|
||||||
|
...inputPadding,
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
whiteSpace: "nowrap"
|
||||||
|
},
|
||||||
|
setMaximalQuantityButton: {
|
||||||
|
marginBottom: theme.spacing(1),
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{ name: "ItemsCard" }
|
||||||
|
);
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
improperValue: {
|
||||||
|
defaultMessage: "Improper value",
|
||||||
|
description: "error message"
|
||||||
|
},
|
||||||
|
|
||||||
|
titleFulfilled: {
|
||||||
|
defaultMessage: "Fulfillment - #{fulfilmentId}",
|
||||||
|
description: "section header"
|
||||||
|
},
|
||||||
|
titleUnfulfilled: {
|
||||||
|
defaultMessage: "Unfulfilled Items",
|
||||||
|
description: "section header"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
interface OrderReturnRefundLinesCardProps {
|
||||||
|
onChangeQuantity: FormsetChange<number>;
|
||||||
|
fulfilmentId?: string;
|
||||||
|
canReplace?: boolean;
|
||||||
|
errors: OrderErrorFragment[];
|
||||||
|
lines: OrderDetails_order_lines[];
|
||||||
|
order: OrderDetails_order;
|
||||||
|
itemsSelections: FormsetReplacementData;
|
||||||
|
itemsQuantities: FormsetQuantityData;
|
||||||
|
onChangeSelected: FormsetChange<boolean>;
|
||||||
|
onSetMaxQuantity();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ItemsCard: React.FC<OrderReturnRefundLinesCardProps> = ({
|
||||||
|
lines,
|
||||||
|
onSetMaxQuantity,
|
||||||
|
onChangeQuantity,
|
||||||
|
onChangeSelected,
|
||||||
|
itemsSelections,
|
||||||
|
itemsQuantities,
|
||||||
|
fulfilmentId,
|
||||||
|
order
|
||||||
|
}) => {
|
||||||
|
const classes = useStyles({});
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const handleChangeQuantity = (id: string) => (
|
||||||
|
event: React.ChangeEvent<HTMLInputElement>
|
||||||
|
) => onChangeQuantity(id, parseInt(event.target.value, 10));
|
||||||
|
|
||||||
|
const fulfillment = order?.fulfillments.find(getById(fulfilmentId));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardTitle
|
||||||
|
orderNumber={order?.number}
|
||||||
|
lines={lines}
|
||||||
|
fulfillmentOrder={fulfillment?.fulfillmentOrder}
|
||||||
|
status={fulfillment?.status}
|
||||||
|
/>
|
||||||
|
<CardContent className={classes.cartContent}>
|
||||||
|
<MaximalButton onClick={onSetMaxQuantity} />
|
||||||
|
</CardContent>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Product"
|
||||||
|
description="table column header"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell />
|
||||||
|
<TableCell align="right">
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Price"
|
||||||
|
description="table column header"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="right">
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Return"
|
||||||
|
description="table column header"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="center">
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Replace"
|
||||||
|
description="table column header"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{renderCollection(
|
||||||
|
lines,
|
||||||
|
line => {
|
||||||
|
const {
|
||||||
|
quantity,
|
||||||
|
quantityFulfilled,
|
||||||
|
id,
|
||||||
|
thumbnail,
|
||||||
|
unitPrice,
|
||||||
|
productName,
|
||||||
|
variant
|
||||||
|
} = line;
|
||||||
|
const isValueError = false;
|
||||||
|
const isRefunded = itemsQuantities.find(getById(id)).data
|
||||||
|
.isRefunded;
|
||||||
|
const isReplacable = !!variant && !isRefunded;
|
||||||
|
const isReturnable = !!variant;
|
||||||
|
const lineQuantity = fulfilmentId
|
||||||
|
? quantity
|
||||||
|
: quantity - quantityFulfilled;
|
||||||
|
const isSelected = itemsSelections.find(getById(id))?.value;
|
||||||
|
const currentQuantity = itemsQuantities.find(getById(id))?.value;
|
||||||
|
const anyLineWithoutVariant = lines.some(
|
||||||
|
({ variant }) => !variant
|
||||||
|
);
|
||||||
|
const productNameCellWidth = anyLineWithoutVariant
|
||||||
|
? "30%"
|
||||||
|
: "50%";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow key={id}>
|
||||||
|
<TableCellAvatar
|
||||||
|
thumbnail={thumbnail?.url}
|
||||||
|
style={{ width: productNameCellWidth }}
|
||||||
|
>
|
||||||
|
{productName || <Skeleton />}
|
||||||
|
</TableCellAvatar>
|
||||||
|
<ProductErrorCell hasVariant={isReturnable} />
|
||||||
|
<TableCell align="right">
|
||||||
|
<Money
|
||||||
|
money={{
|
||||||
|
amount: unitPrice.gross.amount,
|
||||||
|
currency: unitPrice.gross.currency
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="right">
|
||||||
|
{isReturnable && (
|
||||||
|
<TextField
|
||||||
|
type="number"
|
||||||
|
inputProps={{
|
||||||
|
className: classes.quantityInnerInput,
|
||||||
|
"data-test": "quantityInput",
|
||||||
|
"data-test-id": id,
|
||||||
|
max: lineQuantity.toString(),
|
||||||
|
min: 0,
|
||||||
|
style: { textAlign: "right" }
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
value={currentQuantity}
|
||||||
|
onChange={handleChangeQuantity(id)}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: lineQuantity && (
|
||||||
|
<div className={classes.remainingQuantity}>
|
||||||
|
/ {lineQuantity}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
error={isValueError}
|
||||||
|
helperText={
|
||||||
|
isValueError &&
|
||||||
|
intl.formatMessage(messages.improperValue)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align="center">
|
||||||
|
{isReplacable && (
|
||||||
|
<Checkbox
|
||||||
|
checked={isSelected}
|
||||||
|
onChange={() => onChangeSelected(id, !isSelected)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
() => (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={4}>
|
||||||
|
<Skeleton />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ItemsCard;
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./ReturnItemsCard";
|
||||||
|
export { default } from "./ReturnItemsCard";
|
233
src/orders/components/OrderReturnPage/form.tsx
Normal file
233
src/orders/components/OrderReturnPage/form.tsx
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
import useForm, { FormChange, SubmitPromise } from "@saleor/hooks/useForm";
|
||||||
|
import useFormset, {
|
||||||
|
FormsetChange,
|
||||||
|
FormsetData
|
||||||
|
} from "@saleor/hooks/useFormset";
|
||||||
|
import { OrderDetails_order } from "@saleor/orders/types/OrderDetails";
|
||||||
|
import { FulfillmentStatus } from "@saleor/types/globalTypes";
|
||||||
|
import handleFormSubmit from "@saleor/utils/handlers/handleFormSubmit";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
import { OrderRefundAmountCalculationMode } from "../OrderRefundPage/form";
|
||||||
|
import {
|
||||||
|
getById,
|
||||||
|
getLineItem,
|
||||||
|
getOrderUnfulfilledLines,
|
||||||
|
getParsedLineData,
|
||||||
|
getParsedLineDataForFulfillmentStatus
|
||||||
|
} from "./utils";
|
||||||
|
|
||||||
|
export interface LineItemOptions<T> {
|
||||||
|
initialValue: T;
|
||||||
|
isFulfillment?: boolean;
|
||||||
|
isRefunded?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LineItemData {
|
||||||
|
isFulfillment: boolean;
|
||||||
|
isRefunded: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FormsetQuantityData = FormsetData<LineItemData, number>;
|
||||||
|
export type FormsetReplacementData = FormsetData<LineItemData, boolean>;
|
||||||
|
|
||||||
|
export interface OrderReturnData {
|
||||||
|
amount: number;
|
||||||
|
refundShipmentCosts: boolean;
|
||||||
|
amountCalculationMode: OrderRefundAmountCalculationMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderReturnHandlers {
|
||||||
|
changeFulfiledItemsQuantity: FormsetChange<number>;
|
||||||
|
changeUnfulfiledItemsQuantity: FormsetChange<number>;
|
||||||
|
changeItemsToBeReplaced: FormsetChange<boolean>;
|
||||||
|
handleSetMaximalFulfiledItemsQuantities;
|
||||||
|
handleSetMaximalUnfulfiledItemsQuantities;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderReturnFormData extends OrderReturnData {
|
||||||
|
itemsToBeReplaced: FormsetReplacementData;
|
||||||
|
fulfiledItemsQuantities: FormsetQuantityData;
|
||||||
|
unfulfiledItemsQuantities: FormsetQuantityData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OrderRefundSubmitData = OrderReturnFormData;
|
||||||
|
|
||||||
|
export interface UseOrderRefundFormResult {
|
||||||
|
change: FormChange;
|
||||||
|
hasChanged: boolean;
|
||||||
|
data: OrderReturnFormData;
|
||||||
|
handlers: OrderReturnHandlers;
|
||||||
|
submit: () => Promise<boolean>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OrderReturnProps {
|
||||||
|
children: (props: UseOrderRefundFormResult) => React.ReactNode;
|
||||||
|
order: OrderDetails_order;
|
||||||
|
onSubmit: (data: OrderRefundSubmitData) => SubmitPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getOrderRefundPageFormData = (): OrderReturnData => ({
|
||||||
|
amount: undefined,
|
||||||
|
amountCalculationMode: OrderRefundAmountCalculationMode.AUTOMATIC,
|
||||||
|
refundShipmentCosts: false
|
||||||
|
});
|
||||||
|
|
||||||
|
function useOrderReturnForm(
|
||||||
|
order: OrderDetails_order,
|
||||||
|
onSubmit: (data: OrderRefundSubmitData) => SubmitPromise
|
||||||
|
): UseOrderRefundFormResult {
|
||||||
|
const form = useForm(getOrderRefundPageFormData());
|
||||||
|
const [hasChanged, setHasChanged] = useState(false);
|
||||||
|
|
||||||
|
const handleChange: FormChange = (event, cb) => {
|
||||||
|
form.change(event, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
const unfulfiledItemsQuantites = useFormset<LineItemData, number>(
|
||||||
|
getOrderUnfulfilledLines(order).map(getParsedLineData({ initialValue: 0 }))
|
||||||
|
);
|
||||||
|
|
||||||
|
const getItemsFulfilled = () => {
|
||||||
|
const commonOptions = {
|
||||||
|
initialValue: 0,
|
||||||
|
isFulfillment: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const refundedFulfilmentsItems = getParsedLineDataForFulfillmentStatus(
|
||||||
|
order,
|
||||||
|
FulfillmentStatus.REFUNDED,
|
||||||
|
{ ...commonOptions, isRefunded: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const fulfilledFulfillmentsItems = getParsedLineDataForFulfillmentStatus(
|
||||||
|
order,
|
||||||
|
FulfillmentStatus.FULFILLED,
|
||||||
|
commonOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
return refundedFulfilmentsItems.concat(fulfilledFulfillmentsItems);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fulfiledItemsQuatities = useFormset<LineItemData, number>(
|
||||||
|
getItemsFulfilled()
|
||||||
|
);
|
||||||
|
|
||||||
|
const getItemsToBeReplaced = () => {
|
||||||
|
if (!order) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const orderLinesItems = getOrderUnfulfilledLines(order).map(
|
||||||
|
getParsedLineData({ initialValue: false })
|
||||||
|
);
|
||||||
|
|
||||||
|
const refundedFulfilmentsItems = getParsedLineDataForFulfillmentStatus(
|
||||||
|
order,
|
||||||
|
FulfillmentStatus.REFUNDED,
|
||||||
|
{ initialValue: false, isFulfillment: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const fulfilledFulfillmentsItems = getParsedLineDataForFulfillmentStatus(
|
||||||
|
order,
|
||||||
|
FulfillmentStatus.FULFILLED,
|
||||||
|
{ initialValue: false, isFulfillment: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...orderLinesItems,
|
||||||
|
...refundedFulfilmentsItems,
|
||||||
|
...fulfilledFulfillmentsItems
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemsToBeReplaced = useFormset<LineItemData, boolean>(
|
||||||
|
getItemsToBeReplaced()
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleSetMaximalUnfulfiledItemsQuantities = () => {
|
||||||
|
const newQuantities: FormsetQuantityData = unfulfiledItemsQuantites.data.map(
|
||||||
|
({ id }) => {
|
||||||
|
const line = order.lines.find(getById(id));
|
||||||
|
const initialValue = line.quantity - line.quantityFulfilled;
|
||||||
|
|
||||||
|
return getLineItem(line, { initialValue });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
triggerChange();
|
||||||
|
unfulfiledItemsQuantites.set(newQuantities);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSetMaximalFulfiledItemsQuantities = (
|
||||||
|
fulfillmentId: string
|
||||||
|
) => () => {
|
||||||
|
const { lines } = order.fulfillments.find(getById(fulfillmentId));
|
||||||
|
|
||||||
|
const newQuantities: FormsetQuantityData = fulfiledItemsQuatities.data.map(
|
||||||
|
item => {
|
||||||
|
const line = lines.find(getById(item.id));
|
||||||
|
|
||||||
|
if (!line) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getLineItem(line, {
|
||||||
|
initialValue: line.quantity,
|
||||||
|
isRefunded: item.data.isRefunded
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
triggerChange();
|
||||||
|
fulfiledItemsQuatities.set(newQuantities);
|
||||||
|
};
|
||||||
|
|
||||||
|
const data: OrderReturnFormData = {
|
||||||
|
fulfiledItemsQuantities: fulfiledItemsQuatities.data,
|
||||||
|
itemsToBeReplaced: itemsToBeReplaced.data,
|
||||||
|
unfulfiledItemsQuantities: unfulfiledItemsQuantites.data,
|
||||||
|
...form.data
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit = () => handleFormSubmit(data, onSubmit, setHasChanged);
|
||||||
|
|
||||||
|
const triggerChange = () => setHasChanged(true);
|
||||||
|
|
||||||
|
function handleHandlerChange<T>(callback: (id: string, value: T) => void) {
|
||||||
|
return (id: string, value: T) => {
|
||||||
|
triggerChange();
|
||||||
|
callback(id, value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
change: handleChange,
|
||||||
|
data,
|
||||||
|
handlers: {
|
||||||
|
changeFulfiledItemsQuantity: handleHandlerChange(
|
||||||
|
fulfiledItemsQuatities.change
|
||||||
|
),
|
||||||
|
changeItemsToBeReplaced: handleHandlerChange(itemsToBeReplaced.change),
|
||||||
|
changeUnfulfiledItemsQuantity: handleHandlerChange(
|
||||||
|
unfulfiledItemsQuantites.change
|
||||||
|
),
|
||||||
|
handleSetMaximalFulfiledItemsQuantities,
|
||||||
|
handleSetMaximalUnfulfiledItemsQuantities
|
||||||
|
},
|
||||||
|
hasChanged,
|
||||||
|
submit
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const OrderReturnForm: React.FC<OrderReturnProps> = ({
|
||||||
|
children,
|
||||||
|
order,
|
||||||
|
onSubmit
|
||||||
|
}) => {
|
||||||
|
const props = useOrderReturnForm(order, onSubmit);
|
||||||
|
|
||||||
|
return <form>{children(props)}</form>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OrderReturnForm;
|
2
src/orders/components/OrderReturnPage/index.ts
Normal file
2
src/orders/components/OrderReturnPage/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./OrderReturnPage";
|
||||||
|
export { default } from "./OrderReturnPage";
|
93
src/orders/components/OrderReturnPage/utils.tsx
Normal file
93
src/orders/components/OrderReturnPage/utils.tsx
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import { OrderDetailsFragment_fulfillments_lines } from "@saleor/fragments/types/OrderDetailsFragment";
|
||||||
|
import {
|
||||||
|
OrderDetails_order,
|
||||||
|
OrderDetails_order_fulfillments
|
||||||
|
} from "@saleor/orders/types/OrderDetails";
|
||||||
|
import { FulfillmentStatus } from "@saleor/types/globalTypes";
|
||||||
|
|
||||||
|
import { LineItemOptions } from "./form";
|
||||||
|
|
||||||
|
const fulfiledStatuses = [
|
||||||
|
FulfillmentStatus.FULFILLED,
|
||||||
|
FulfillmentStatus.REFUNDED
|
||||||
|
];
|
||||||
|
|
||||||
|
export const getOrderUnfulfilledLines = (order: OrderDetails_order) =>
|
||||||
|
order?.lines.filter(line => line.quantityFulfilled !== line.quantity) || [];
|
||||||
|
|
||||||
|
export const getFulfilledFulfillment = fulfillment =>
|
||||||
|
fulfiledStatuses.includes(fulfillment.status);
|
||||||
|
|
||||||
|
export const getFulfilledFulfillemnts = (order?: OrderDetails_order) =>
|
||||||
|
order?.fulfillments.filter(getFulfilledFulfillment) || [];
|
||||||
|
|
||||||
|
export const getUnfulfilledLines = (order?: OrderDetails_order) =>
|
||||||
|
order?.lines.filter(line => line.quantity !== line.quantityFulfilled) || [];
|
||||||
|
|
||||||
|
export const getAllOrderFulfilledLines = (order?: OrderDetails_order) =>
|
||||||
|
getFulfilledFulfillemnts(order).reduce(
|
||||||
|
(result, { lines }) => [...result, ...getParsedFulfiledLines(lines)],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
export function getLineItem<T>(
|
||||||
|
{ id }: { id: string },
|
||||||
|
{
|
||||||
|
initialValue,
|
||||||
|
isFulfillment = false,
|
||||||
|
isRefunded = false
|
||||||
|
}: LineItemOptions<T>
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
data: { isFulfillment, isRefunded },
|
||||||
|
id,
|
||||||
|
label: null,
|
||||||
|
value: initialValue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getParsedLineData<T>({
|
||||||
|
initialValue,
|
||||||
|
isFulfillment = false,
|
||||||
|
isRefunded = false
|
||||||
|
}: LineItemOptions<T>) {
|
||||||
|
return (item: { id: string }) =>
|
||||||
|
getLineItem(item, { initialValue, isFulfillment, isRefunded });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getParsedLineDataForFulfillmentStatus<T>(
|
||||||
|
order: OrderDetails_order,
|
||||||
|
fulfillmentStatus: FulfillmentStatus,
|
||||||
|
lineItemOptions: LineItemOptions<T>
|
||||||
|
) {
|
||||||
|
return getParsedLinesOfFulfillments(
|
||||||
|
getFulfillmentsWithStatus(order, fulfillmentStatus)
|
||||||
|
).map(getParsedLineData(lineItemOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getFulfillmentsWithStatus = (
|
||||||
|
order: OrderDetails_order,
|
||||||
|
fulfillmentStatus: FulfillmentStatus
|
||||||
|
) =>
|
||||||
|
order?.fulfillments.filter(({ status }) => status === fulfillmentStatus) ||
|
||||||
|
[];
|
||||||
|
|
||||||
|
export const getParsedLinesOfFulfillments = (
|
||||||
|
fullfillments: OrderDetails_order_fulfillments[]
|
||||||
|
) =>
|
||||||
|
fullfillments.reduce(
|
||||||
|
(result, { lines }) => [...result, ...getParsedFulfiledLines(lines)],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getParsedFulfiledLines = (
|
||||||
|
lines: OrderDetailsFragment_fulfillments_lines[]
|
||||||
|
) =>
|
||||||
|
lines.map(({ id, quantity, orderLine }) => ({
|
||||||
|
...orderLine,
|
||||||
|
id,
|
||||||
|
quantity
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const getById = (idToCompare: string) => (obj: { id: string }) =>
|
||||||
|
obj.id === idToCompare;
|
|
@ -1,192 +0,0 @@
|
||||||
import Button from "@material-ui/core/Button";
|
|
||||||
import Card from "@material-ui/core/Card";
|
|
||||||
import CardActions from "@material-ui/core/CardActions";
|
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
|
||||||
import TableHead from "@material-ui/core/TableHead";
|
|
||||||
import TableRow from "@material-ui/core/TableRow";
|
|
||||||
import CardTitle from "@saleor/components/CardTitle";
|
|
||||||
import Money from "@saleor/components/Money";
|
|
||||||
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
|
||||||
import Skeleton from "@saleor/components/Skeleton";
|
|
||||||
import StatusLabel from "@saleor/components/StatusLabel";
|
|
||||||
import TableCellAvatar, {
|
|
||||||
AVATAR_MARGIN
|
|
||||||
} from "@saleor/components/TableCellAvatar";
|
|
||||||
import React from "react";
|
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
|
||||||
|
|
||||||
import { maybe } from "../../../misc";
|
|
||||||
import { OrderDetails_order_lines } from "../../types/OrderDetails";
|
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
|
||||||
{
|
|
||||||
clickableRow: {
|
|
||||||
cursor: "pointer"
|
|
||||||
},
|
|
||||||
colName: {
|
|
||||||
paddingLeft: 0,
|
|
||||||
width: "auto"
|
|
||||||
},
|
|
||||||
colNameLabel: {
|
|
||||||
marginLeft: AVATAR_MARGIN
|
|
||||||
},
|
|
||||||
colPrice: {
|
|
||||||
textAlign: "right",
|
|
||||||
width: 120
|
|
||||||
},
|
|
||||||
colQuantity: {
|
|
||||||
textAlign: "center",
|
|
||||||
width: 120
|
|
||||||
},
|
|
||||||
colSku: {
|
|
||||||
textAlign: "right",
|
|
||||||
textOverflow: "ellipsis",
|
|
||||||
width: 120
|
|
||||||
},
|
|
||||||
colTotal: {
|
|
||||||
textAlign: "right",
|
|
||||||
width: 120
|
|
||||||
},
|
|
||||||
statusBar: {
|
|
||||||
paddingTop: 0
|
|
||||||
},
|
|
||||||
table: {
|
|
||||||
tableLayout: "fixed"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ name: "OrderUnfulfilledItems" }
|
|
||||||
);
|
|
||||||
|
|
||||||
interface OrderUnfulfilledItemsProps {
|
|
||||||
canFulfill: boolean;
|
|
||||||
lines: OrderDetails_order_lines[];
|
|
||||||
onFulfill: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const OrderUnfulfilledItems: React.FC<OrderUnfulfilledItemsProps> = props => {
|
|
||||||
const { canFulfill, lines, onFulfill } = props;
|
|
||||||
const classes = useStyles(props);
|
|
||||||
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<CardTitle
|
|
||||||
title={
|
|
||||||
<StatusLabel
|
|
||||||
label={intl.formatMessage(
|
|
||||||
{
|
|
||||||
defaultMessage: "Unfulfilled ({quantity})",
|
|
||||||
description: "section header"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
quantity: lines
|
|
||||||
.map(line => line.quantity - line.quantityFulfilled)
|
|
||||||
.reduce((prev, curr) => prev + curr, 0)
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
status="error"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ResponsiveTable className={classes.table}>
|
|
||||||
<TableHead>
|
|
||||||
<TableRow>
|
|
||||||
<TableCell className={classes.colName}>
|
|
||||||
<span className={classes.colNameLabel}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Product"
|
|
||||||
description="product name"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colSku}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="SKU"
|
|
||||||
description="ordered product sku"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colQuantity}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Quantity"
|
|
||||||
description="ordered products"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colPrice}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Price"
|
|
||||||
description="product unit price"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colTotal}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Total"
|
|
||||||
description="order line total price"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</TableHead>
|
|
||||||
<TableBody>
|
|
||||||
{lines.map(line => (
|
|
||||||
<TableRow
|
|
||||||
className={!!line ? classes.clickableRow : undefined}
|
|
||||||
hover={!!line}
|
|
||||||
key={maybe(() => line.id)}
|
|
||||||
>
|
|
||||||
<TableCellAvatar
|
|
||||||
className={classes.colName}
|
|
||||||
thumbnail={maybe(() => line.thumbnail.url)}
|
|
||||||
>
|
|
||||||
{maybe(() => line.productName) || <Skeleton />}
|
|
||||||
</TableCellAvatar>
|
|
||||||
<TableCell className={classes.colSku}>
|
|
||||||
{line?.productSku || <Skeleton />}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colQuantity}>
|
|
||||||
{maybe(() => line.quantity - line.quantityFulfilled) || (
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colPrice}>
|
|
||||||
{maybe(() => line.unitPrice.gross) ? (
|
|
||||||
<Money money={line.unitPrice.gross} />
|
|
||||||
) : (
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colTotal}>
|
|
||||||
{maybe(
|
|
||||||
() =>
|
|
||||||
(line.quantity - line.quantityFulfilled) *
|
|
||||||
line.unitPrice.gross.amount
|
|
||||||
) ? (
|
|
||||||
<Money
|
|
||||||
money={{
|
|
||||||
amount:
|
|
||||||
(line.quantity - line.quantityFulfilled) *
|
|
||||||
line.unitPrice.gross.amount,
|
|
||||||
currency: line.unitPrice.gross.currency
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
</ResponsiveTable>
|
|
||||||
{canFulfill && (
|
|
||||||
<CardActions>
|
|
||||||
<Button variant="text" color="primary" onClick={onFulfill}>
|
|
||||||
<FormattedMessage defaultMessage="Fulfill" description="button" />
|
|
||||||
</Button>
|
|
||||||
</CardActions>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
OrderUnfulfilledItems.displayName = "OrderUnfulfilledItems";
|
|
||||||
export default OrderUnfulfilledItems;
|
|
|
@ -1,2 +0,0 @@
|
||||||
export { default } from "./OrderUnfulfilledItems";
|
|
||||||
export * from "./OrderUnfulfilledItems";
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { makeStyles, TableBody } from "@material-ui/core";
|
||||||
|
import Button from "@material-ui/core/Button";
|
||||||
|
import Card from "@material-ui/core/Card";
|
||||||
|
import CardActions from "@material-ui/core/CardActions";
|
||||||
|
import CardSpacer from "@saleor/components/CardSpacer";
|
||||||
|
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||||
|
import { renderCollection } from "@saleor/misc";
|
||||||
|
import React from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
import { OrderDetails_order_lines } from "../../types/OrderDetails";
|
||||||
|
import TableHeader from "../OrderProductsCardElements/OrderProductsCardHeader";
|
||||||
|
import TableLine from "../OrderProductsCardElements/OrderProductsTableRow";
|
||||||
|
import CardTitle from "../OrderReturnPage/OrderReturnRefundItemsCard/CardTitle";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
() => ({
|
||||||
|
table: {
|
||||||
|
tableLayout: "fixed"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ name: "OrderUnfulfilledItems" }
|
||||||
|
);
|
||||||
|
|
||||||
|
interface OrderUnfulfilledProductsCardProps {
|
||||||
|
canFulfill: boolean;
|
||||||
|
lines: OrderDetails_order_lines[];
|
||||||
|
onFulfill: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const OrderUnfulfilledProductsCard: React.FC<OrderUnfulfilledProductsCardProps> = props => {
|
||||||
|
const { canFulfill, lines, onFulfill } = props;
|
||||||
|
const classes = useStyles({});
|
||||||
|
|
||||||
|
if (!lines.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Card>
|
||||||
|
<CardTitle withStatus status="unfulfilled" />
|
||||||
|
<ResponsiveTable className={classes.table}>
|
||||||
|
<TableHeader />
|
||||||
|
<TableBody>
|
||||||
|
{renderCollection(lines, line => (
|
||||||
|
<TableLine isOrderLine line={line} />
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</ResponsiveTable>
|
||||||
|
{canFulfill && (
|
||||||
|
<CardActions>
|
||||||
|
<Button variant="text" color="primary" onClick={onFulfill}>
|
||||||
|
<FormattedMessage defaultMessage="Fulfill" description="button" />
|
||||||
|
</Button>
|
||||||
|
</CardActions>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
<CardSpacer />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OrderUnfulfilledProductsCard;
|
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./OrderUnfulfilledProductsCard";
|
||||||
|
export * from "./OrderUnfulfilledProductsCard";
|
|
@ -834,13 +834,16 @@ export const order = (placeholder: string): OrderDetails_order => ({
|
||||||
lines: [],
|
lines: [],
|
||||||
message: null,
|
message: null,
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
|
relatedOrder: null,
|
||||||
shippingCostsIncluded: false,
|
shippingCostsIncluded: false,
|
||||||
transactionReference: "123",
|
transactionReference: "123",
|
||||||
type: OrderEventsEnum.FULFILLMENT_FULFILLED_ITEMS,
|
type: OrderEventsEnum.FULFILLMENT_FULFILLED_ITEMS,
|
||||||
user: {
|
user: {
|
||||||
__typename: "User",
|
__typename: "User",
|
||||||
email: "admin@example.com",
|
email: "admin@example.com",
|
||||||
id: "QWRkcmVzczoxNQ=="
|
firstName: "John",
|
||||||
|
id: "QWRkcmVzczoxNQ==",
|
||||||
|
lastName: "Doe"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -875,13 +878,16 @@ export const order = (placeholder: string): OrderDetails_order => ({
|
||||||
],
|
],
|
||||||
message: null,
|
message: null,
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
|
relatedOrder: null,
|
||||||
shippingCostsIncluded: true,
|
shippingCostsIncluded: true,
|
||||||
transactionReference: "123",
|
transactionReference: "123",
|
||||||
type: OrderEventsEnum.FULFILLMENT_REFUNDED,
|
type: OrderEventsEnum.FULFILLMENT_REFUNDED,
|
||||||
user: {
|
user: {
|
||||||
__typename: "User",
|
__typename: "User",
|
||||||
email: "admin@example.com",
|
email: "admin@example.com",
|
||||||
id: "QWRkcmVzczoxNQ=="
|
firstName: "Jane",
|
||||||
|
id: "QWRkcmVzczoxNQ==",
|
||||||
|
lastName: "Doe"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -895,6 +901,7 @@ export const order = (placeholder: string): OrderDetails_order => ({
|
||||||
lines: [],
|
lines: [],
|
||||||
message: "This is note",
|
message: "This is note",
|
||||||
quantity: null,
|
quantity: null,
|
||||||
|
relatedOrder: null,
|
||||||
shippingCostsIncluded: false,
|
shippingCostsIncluded: false,
|
||||||
transactionReference: "124",
|
transactionReference: "124",
|
||||||
type: OrderEventsEnum.NOTE_ADDED,
|
type: OrderEventsEnum.NOTE_ADDED,
|
||||||
|
@ -911,6 +918,7 @@ export const order = (placeholder: string): OrderDetails_order => ({
|
||||||
lines: [],
|
lines: [],
|
||||||
message: "This is note",
|
message: "This is note",
|
||||||
quantity: null,
|
quantity: null,
|
||||||
|
relatedOrder: null,
|
||||||
shippingCostsIncluded: false,
|
shippingCostsIncluded: false,
|
||||||
transactionReference: "125",
|
transactionReference: "125",
|
||||||
type: OrderEventsEnum.NOTE_ADDED,
|
type: OrderEventsEnum.NOTE_ADDED,
|
||||||
|
@ -927,6 +935,7 @@ export const order = (placeholder: string): OrderDetails_order => ({
|
||||||
lines: [],
|
lines: [],
|
||||||
message: "Note from external service",
|
message: "Note from external service",
|
||||||
quantity: null,
|
quantity: null,
|
||||||
|
relatedOrder: null,
|
||||||
shippingCostsIncluded: false,
|
shippingCostsIncluded: false,
|
||||||
transactionReference: "126",
|
transactionReference: "126",
|
||||||
type: OrderEventsEnum.EXTERNAL_SERVICE_NOTIFICATION,
|
type: OrderEventsEnum.EXTERNAL_SERVICE_NOTIFICATION,
|
||||||
|
@ -943,6 +952,7 @@ export const order = (placeholder: string): OrderDetails_order => ({
|
||||||
lines: [],
|
lines: [],
|
||||||
message: null,
|
message: null,
|
||||||
quantity: null,
|
quantity: null,
|
||||||
|
relatedOrder: null,
|
||||||
shippingCostsIncluded: false,
|
shippingCostsIncluded: false,
|
||||||
transactionReference: "127",
|
transactionReference: "127",
|
||||||
type: OrderEventsEnum.EMAIL_SENT,
|
type: OrderEventsEnum.EMAIL_SENT,
|
||||||
|
@ -959,6 +969,7 @@ export const order = (placeholder: string): OrderDetails_order => ({
|
||||||
lines: [],
|
lines: [],
|
||||||
message: null,
|
message: null,
|
||||||
quantity: null,
|
quantity: null,
|
||||||
|
relatedOrder: null,
|
||||||
shippingCostsIncluded: false,
|
shippingCostsIncluded: false,
|
||||||
transactionReference: "128",
|
transactionReference: "128",
|
||||||
type: OrderEventsEnum.EMAIL_SENT,
|
type: OrderEventsEnum.EMAIL_SENT,
|
||||||
|
@ -975,6 +986,7 @@ export const order = (placeholder: string): OrderDetails_order => ({
|
||||||
lines: [],
|
lines: [],
|
||||||
message: null,
|
message: null,
|
||||||
quantity: null,
|
quantity: null,
|
||||||
|
relatedOrder: null,
|
||||||
shippingCostsIncluded: false,
|
shippingCostsIncluded: false,
|
||||||
transactionReference: "129",
|
transactionReference: "129",
|
||||||
type: OrderEventsEnum.PAYMENT_AUTHORIZED,
|
type: OrderEventsEnum.PAYMENT_AUTHORIZED,
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
OrderListUrlSortField,
|
OrderListUrlSortField,
|
||||||
orderPath,
|
orderPath,
|
||||||
orderRefundPath,
|
orderRefundPath,
|
||||||
|
orderReturnPath,
|
||||||
orderSettingsPath,
|
orderSettingsPath,
|
||||||
OrderUrlQueryParams
|
OrderUrlQueryParams
|
||||||
} from "./urls";
|
} from "./urls";
|
||||||
|
@ -24,6 +25,7 @@ import OrderDraftListComponent from "./views/OrderDraftList";
|
||||||
import OrderFulfillComponent from "./views/OrderFulfill";
|
import OrderFulfillComponent from "./views/OrderFulfill";
|
||||||
import OrderListComponent from "./views/OrderList";
|
import OrderListComponent from "./views/OrderList";
|
||||||
import OrderRefundComponent from "./views/OrderRefund";
|
import OrderRefundComponent from "./views/OrderRefund";
|
||||||
|
import OrderReturnComponent from "./views/OrderReturn";
|
||||||
import OrderSettings from "./views/OrderSettings";
|
import OrderSettings from "./views/OrderSettings";
|
||||||
|
|
||||||
const OrderList: React.FC<RouteComponentProps<any>> = ({ location }) => {
|
const OrderList: React.FC<RouteComponentProps<any>> = ({ location }) => {
|
||||||
|
@ -71,6 +73,10 @@ const OrderRefund: React.FC<RouteComponentProps<any>> = ({ match }) => (
|
||||||
<OrderRefundComponent orderId={decodeURIComponent(match.params.id)} />
|
<OrderRefundComponent orderId={decodeURIComponent(match.params.id)} />
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const OrderReturn: React.FC<RouteComponentProps<any>> = ({ match }) => (
|
||||||
|
<OrderReturnComponent orderId={decodeURIComponent(match.params.id)} />
|
||||||
|
);
|
||||||
|
|
||||||
const Component = () => {
|
const Component = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
@ -82,6 +88,7 @@ const Component = () => {
|
||||||
<Route exact path={orderDraftListPath} component={OrderDraftList} />
|
<Route exact path={orderDraftListPath} component={OrderDraftList} />
|
||||||
<Route exact path={orderListPath} component={OrderList} />
|
<Route exact path={orderListPath} component={OrderList} />
|
||||||
<Route path={orderFulfillPath(":id")} component={OrderFulfill} />
|
<Route path={orderFulfillPath(":id")} component={OrderFulfill} />
|
||||||
|
<Route path={orderReturnPath(":id")} component={OrderReturn} />
|
||||||
<Route path={orderRefundPath(":id")} component={OrderRefund} />
|
<Route path={orderRefundPath(":id")} component={OrderRefund} />
|
||||||
<Route path={orderPath(":id")} component={OrderDetails} />
|
<Route path={orderPath(":id")} component={OrderDetails} />
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|
|
@ -14,6 +14,10 @@ import makeMutation from "@saleor/hooks/makeMutation";
|
||||||
import gql from "graphql-tag";
|
import gql from "graphql-tag";
|
||||||
|
|
||||||
import { TypedMutation } from "../mutations";
|
import { TypedMutation } from "../mutations";
|
||||||
|
import {
|
||||||
|
FulfillmentReturnProducts,
|
||||||
|
FulfillmentReturnProductsVariables
|
||||||
|
} from "./types/FulfillmentReturnProducts";
|
||||||
import { FulfillOrder, FulfillOrderVariables } from "./types/FulfillOrder";
|
import { FulfillOrder, FulfillOrderVariables } from "./types/FulfillOrder";
|
||||||
import {
|
import {
|
||||||
InvoiceEmailSend,
|
InvoiceEmailSend,
|
||||||
|
@ -172,6 +176,32 @@ const orderDraftFinalizeMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const orderReturnCreateMutation = gql`
|
||||||
|
${orderErrorFragment}
|
||||||
|
mutation FulfillmentReturnProducts(
|
||||||
|
$id: ID!
|
||||||
|
$input: OrderReturnProductsInput!
|
||||||
|
) {
|
||||||
|
orderFulfillmentReturnProducts(input: $input, order: $id) {
|
||||||
|
errors: orderErrors {
|
||||||
|
...OrderErrorFragment
|
||||||
|
}
|
||||||
|
order {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
replaceOrder {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const useOrderReturnCreateMutation = makeMutation<
|
||||||
|
FulfillmentReturnProducts,
|
||||||
|
FulfillmentReturnProductsVariables
|
||||||
|
>(orderReturnCreateMutation);
|
||||||
|
|
||||||
export const TypedOrderDraftFinalizeMutation = TypedMutation<
|
export const TypedOrderDraftFinalizeMutation = TypedMutation<
|
||||||
OrderDraftFinalize,
|
OrderDraftFinalize,
|
||||||
OrderDraftFinalizeVariables
|
OrderDraftFinalizeVariables
|
||||||
|
@ -191,6 +221,7 @@ const orderRefundMutation = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const useOrderRefundMutation = makeMutation<
|
export const useOrderRefundMutation = makeMutation<
|
||||||
OrderRefund,
|
OrderRefund,
|
||||||
OrderRefundVariables
|
OrderRefundVariables
|
||||||
|
|
|
@ -157,6 +157,10 @@ export const TypedOrderDetailsQuery = TypedQuery<
|
||||||
OrderDetailsVariables
|
OrderDetailsVariables
|
||||||
>(orderDetailsQuery);
|
>(orderDetailsQuery);
|
||||||
|
|
||||||
|
export const useOrderQuery = makeQuery<OrderDetails, OrderDetailsVariables>(
|
||||||
|
orderDetailsQuery
|
||||||
|
);
|
||||||
|
|
||||||
export const searchOrderVariant = gql`
|
export const searchOrderVariant = gql`
|
||||||
query SearchOrderVariant($first: Int!, $query: String!, $after: String) {
|
query SearchOrderVariant($first: Int!, $query: String!, $after: String) {
|
||||||
search: products(first: $first, after: $after, filter: { search: $query }) {
|
search: products(first: $first, after: $after, filter: { search: $query }) {
|
||||||
|
|
|
@ -50,10 +50,18 @@ export interface FulfillOrder_orderFulfill_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FulfillOrder_orderFulfill_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface FulfillOrder_orderFulfill_order_events_user {
|
export interface FulfillOrder_orderFulfill_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FulfillOrder_orderFulfill_order_events_lines_orderLine {
|
export interface FulfillOrder_orderFulfill_order_events_lines_orderLine {
|
||||||
|
@ -78,6 +86,7 @@ export interface FulfillOrder_orderFulfill_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: FulfillOrder_orderFulfill_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
41
src/orders/types/FulfillmentReturnProducts.ts
Normal file
41
src/orders/types/FulfillmentReturnProducts.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
import { OrderReturnProductsInput, OrderErrorCode } from "./../../types/globalTypes";
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL mutation operation: FulfillmentReturnProducts
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface FulfillmentReturnProducts_orderFulfillmentReturnProducts_errors {
|
||||||
|
__typename: "OrderError";
|
||||||
|
code: OrderErrorCode;
|
||||||
|
field: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FulfillmentReturnProducts_orderFulfillmentReturnProducts_order {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FulfillmentReturnProducts_orderFulfillmentReturnProducts_replaceOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FulfillmentReturnProducts_orderFulfillmentReturnProducts {
|
||||||
|
__typename: "FulfillmentReturnProducts";
|
||||||
|
errors: FulfillmentReturnProducts_orderFulfillmentReturnProducts_errors[];
|
||||||
|
order: FulfillmentReturnProducts_orderFulfillmentReturnProducts_order | null;
|
||||||
|
replaceOrder: FulfillmentReturnProducts_orderFulfillmentReturnProducts_replaceOrder | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FulfillmentReturnProducts {
|
||||||
|
orderFulfillmentReturnProducts: FulfillmentReturnProducts_orderFulfillmentReturnProducts | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FulfillmentReturnProductsVariables {
|
||||||
|
id: string;
|
||||||
|
input: OrderReturnProductsInput;
|
||||||
|
}
|
|
@ -14,10 +14,18 @@ export interface OrderAddNote_orderAddNote_errors {
|
||||||
field: string | null;
|
field: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderAddNote_orderAddNote_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderAddNote_orderAddNote_order_events_user {
|
export interface OrderAddNote_orderAddNote_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderAddNote_orderAddNote_order_events_lines_orderLine {
|
export interface OrderAddNote_orderAddNote_order_events_lines_orderLine {
|
||||||
|
@ -42,6 +50,7 @@ export interface OrderAddNote_orderAddNote_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderAddNote_orderAddNote_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderCancel_orderCancel_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderCancel_orderCancel_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderCancel_orderCancel_order_events_user {
|
export interface OrderCancel_orderCancel_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderCancel_orderCancel_order_events_lines_orderLine {
|
export interface OrderCancel_orderCancel_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderCancel_orderCancel_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderCancel_orderCancel_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderCapture_orderCapture_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderCapture_orderCapture_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderCapture_orderCapture_order_events_user {
|
export interface OrderCapture_orderCapture_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderCapture_orderCapture_order_events_lines_orderLine {
|
export interface OrderCapture_orderCapture_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderCapture_orderCapture_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderCapture_orderCapture_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderConfirm_orderConfirm_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderConfirm_orderConfirm_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderConfirm_orderConfirm_order_events_user {
|
export interface OrderConfirm_orderConfirm_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderConfirm_orderConfirm_order_events_lines_orderLine {
|
export interface OrderConfirm_orderConfirm_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderConfirm_orderConfirm_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderConfirm_orderConfirm_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -42,10 +42,18 @@ export interface OrderDetails_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderDetails_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderDetails_order_events_user {
|
export interface OrderDetails_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderDetails_order_events_lines_orderLine {
|
export interface OrderDetails_order_events_lines_orderLine {
|
||||||
|
@ -70,6 +78,7 @@ export interface OrderDetails_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderDetails_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderDraftCancel_draftOrderDelete_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderDraftCancel_draftOrderDelete_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderDraftCancel_draftOrderDelete_order_events_user {
|
export interface OrderDraftCancel_draftOrderDelete_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderDraftCancel_draftOrderDelete_order_events_lines_orderLine {
|
export interface OrderDraftCancel_draftOrderDelete_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderDraftCancel_draftOrderDelete_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderDraftCancel_draftOrderDelete_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderDraftFinalize_draftOrderComplete_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderDraftFinalize_draftOrderComplete_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderDraftFinalize_draftOrderComplete_order_events_user {
|
export interface OrderDraftFinalize_draftOrderComplete_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderDraftFinalize_draftOrderComplete_order_events_lines_orderLine {
|
export interface OrderDraftFinalize_draftOrderComplete_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderDraftFinalize_draftOrderComplete_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderDraftFinalize_draftOrderComplete_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderDraftUpdate_draftOrderUpdate_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderDraftUpdate_draftOrderUpdate_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderDraftUpdate_draftOrderUpdate_order_events_user {
|
export interface OrderDraftUpdate_draftOrderUpdate_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderDraftUpdate_draftOrderUpdate_order_events_lines_orderLine {
|
export interface OrderDraftUpdate_draftOrderUpdate_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderDraftUpdate_draftOrderUpdate_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderDraftUpdate_draftOrderUpdate_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_billingAddr
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_events_user {
|
export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_events_lines_orderLine {
|
export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderFulfillmentCancel_orderFulfillmentCancel_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -113,10 +113,18 @@ export interface OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_o
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_events_user {
|
export interface OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_events_lines_orderLine {
|
export interface OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_events_lines_orderLine {
|
||||||
|
@ -141,6 +149,7 @@ export interface OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_o
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_o
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_events_user {
|
export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_events_lines_orderLine {
|
export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_o
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderLineDelete_draftOrderLineDelete_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderLineDelete_draftOrderLineDelete_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderLineDelete_draftOrderLineDelete_order_events_user {
|
export interface OrderLineDelete_draftOrderLineDelete_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderLineDelete_draftOrderLineDelete_order_events_lines_orderLine {
|
export interface OrderLineDelete_draftOrderLineDelete_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderLineDelete_draftOrderLineDelete_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderLineDelete_draftOrderLineDelete_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderLineUpdate_draftOrderLineUpdate_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderLineUpdate_draftOrderLineUpdate_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderLineUpdate_draftOrderLineUpdate_order_events_user {
|
export interface OrderLineUpdate_draftOrderLineUpdate_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderLineUpdate_draftOrderLineUpdate_order_events_lines_orderLine {
|
export interface OrderLineUpdate_draftOrderLineUpdate_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderLineUpdate_draftOrderLineUpdate_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderLineUpdate_draftOrderLineUpdate_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderLinesAdd_draftOrderLinesCreate_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderLinesAdd_draftOrderLinesCreate_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderLinesAdd_draftOrderLinesCreate_order_events_user {
|
export interface OrderLinesAdd_draftOrderLinesCreate_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderLinesAdd_draftOrderLinesCreate_order_events_lines_orderLine {
|
export interface OrderLinesAdd_draftOrderLinesCreate_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderLinesAdd_draftOrderLinesCreate_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderLinesAdd_draftOrderLinesCreate_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderMarkAsPaid_orderMarkAsPaid_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderMarkAsPaid_orderMarkAsPaid_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderMarkAsPaid_orderMarkAsPaid_order_events_user {
|
export interface OrderMarkAsPaid_orderMarkAsPaid_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderMarkAsPaid_orderMarkAsPaid_order_events_lines_orderLine {
|
export interface OrderMarkAsPaid_orderMarkAsPaid_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderMarkAsPaid_orderMarkAsPaid_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderMarkAsPaid_orderMarkAsPaid_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderRefund_orderRefund_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderRefund_orderRefund_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderRefund_orderRefund_order_events_user {
|
export interface OrderRefund_orderRefund_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderRefund_orderRefund_order_events_lines_orderLine {
|
export interface OrderRefund_orderRefund_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderRefund_orderRefund_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderRefund_orderRefund_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderUpdate_orderUpdate_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderUpdate_orderUpdate_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderUpdate_orderUpdate_order_events_user {
|
export interface OrderUpdate_orderUpdate_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderUpdate_orderUpdate_order_events_lines_orderLine {
|
export interface OrderUpdate_orderUpdate_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderUpdate_orderUpdate_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderUpdate_orderUpdate_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -48,10 +48,18 @@ export interface OrderVoid_orderVoid_order_billingAddress {
|
||||||
streetAddress2: string;
|
streetAddress2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderVoid_orderVoid_order_events_relatedOrder {
|
||||||
|
__typename: "Order";
|
||||||
|
id: string;
|
||||||
|
number: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderVoid_orderVoid_order_events_user {
|
export interface OrderVoid_orderVoid_order_events_user {
|
||||||
__typename: "User";
|
__typename: "User";
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderVoid_orderVoid_order_events_lines_orderLine {
|
export interface OrderVoid_orderVoid_order_events_lines_orderLine {
|
||||||
|
@ -76,6 +84,7 @@ export interface OrderVoid_orderVoid_order_events {
|
||||||
email: string | null;
|
email: string | null;
|
||||||
emailType: OrderEventsEmailsEnum | null;
|
emailType: OrderEventsEmailsEnum | null;
|
||||||
invoiceNumber: string | null;
|
invoiceNumber: string | null;
|
||||||
|
relatedOrder: OrderVoid_orderVoid_order_events_relatedOrder | null;
|
||||||
message: string | null;
|
message: string | null;
|
||||||
quantity: number | null;
|
quantity: number | null;
|
||||||
transactionReference: string | null;
|
transactionReference: string | null;
|
||||||
|
|
|
@ -99,6 +99,7 @@ export const orderDraftListUrl = (
|
||||||
};
|
};
|
||||||
|
|
||||||
export const orderPath = (id: string) => urlJoin(orderSectionUrl, id);
|
export const orderPath = (id: string) => urlJoin(orderSectionUrl, id);
|
||||||
|
|
||||||
export type OrderUrlDialog =
|
export type OrderUrlDialog =
|
||||||
| "add-order-line"
|
| "add-order-line"
|
||||||
| "cancel"
|
| "cancel"
|
||||||
|
@ -112,17 +113,26 @@ export type OrderUrlDialog =
|
||||||
| "mark-paid"
|
| "mark-paid"
|
||||||
| "void"
|
| "void"
|
||||||
| "invoice-send";
|
| "invoice-send";
|
||||||
|
|
||||||
export type OrderUrlQueryParams = Dialog<OrderUrlDialog> & SingleAction;
|
export type OrderUrlQueryParams = Dialog<OrderUrlDialog> & SingleAction;
|
||||||
|
|
||||||
export const orderUrl = (id: string, params?: OrderUrlQueryParams) =>
|
export const orderUrl = (id: string, params?: OrderUrlQueryParams) =>
|
||||||
orderPath(encodeURIComponent(id)) + "?" + stringifyQs(params);
|
orderPath(encodeURIComponent(id)) + "?" + stringifyQs(params);
|
||||||
|
|
||||||
export const orderFulfillPath = (id: string) =>
|
export const orderFulfillPath = (id: string) =>
|
||||||
urlJoin(orderPath(id), "fulfill");
|
urlJoin(orderPath(id), "fulfill");
|
||||||
|
|
||||||
|
export const orderReturnPath = (id: string) => urlJoin(orderPath(id), "return");
|
||||||
|
|
||||||
export const orderFulfillUrl = (id: string) =>
|
export const orderFulfillUrl = (id: string) =>
|
||||||
orderFulfillPath(encodeURIComponent(id));
|
orderFulfillPath(encodeURIComponent(id));
|
||||||
|
|
||||||
export const orderSettingsPath = urlJoin(orderSectionUrl, "settings");
|
export const orderSettingsPath = urlJoin(orderSectionUrl, "settings");
|
||||||
|
|
||||||
export const orderRefundPath = (id: string) => urlJoin(orderPath(id), "refund");
|
export const orderRefundPath = (id: string) => urlJoin(orderPath(id), "refund");
|
||||||
|
|
||||||
export const orderRefundUrl = (id: string) =>
|
export const orderRefundUrl = (id: string) =>
|
||||||
orderRefundPath(encodeURIComponent(id));
|
orderRefundPath(encodeURIComponent(id));
|
||||||
|
|
||||||
|
export const orderReturnUrl = (id: string) =>
|
||||||
|
orderReturnPath(encodeURIComponent(id));
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
/* eslint-disable sort-keys */
|
/* eslint-disable sort-keys */
|
||||||
import { FormsetData } from "@saleor/hooks/useFormset";
|
import { FormsetData } from "@saleor/hooks/useFormset";
|
||||||
import { FulfillmentStatus } from "@saleor/types/globalTypes";
|
import {
|
||||||
|
FulfillmentStatus,
|
||||||
|
OrderStatus,
|
||||||
|
PaymentChargeStatusEnum
|
||||||
|
} from "@saleor/types/globalTypes";
|
||||||
|
|
||||||
import { OrderDetails_order_fulfillments_lines } from "../types/OrderDetails";
|
import { LineItemData } from "../components/OrderReturnPage/form";
|
||||||
|
import {
|
||||||
|
OrderDetails_order,
|
||||||
|
OrderDetails_order_fulfillments_lines,
|
||||||
|
OrderDetails_order_lines
|
||||||
|
} from "../types/OrderDetails";
|
||||||
import {
|
import {
|
||||||
OrderRefundData_order_fulfillments,
|
OrderRefundData_order_fulfillments,
|
||||||
OrderRefundData_order_lines
|
OrderRefundData_order_lines
|
||||||
|
@ -11,10 +20,53 @@ import {
|
||||||
getAllFulfillmentLinesPriceSum,
|
getAllFulfillmentLinesPriceSum,
|
||||||
getPreviouslyRefundedPrice,
|
getPreviouslyRefundedPrice,
|
||||||
getRefundedLinesPriceSum,
|
getRefundedLinesPriceSum,
|
||||||
|
getReplacedProductsAmount,
|
||||||
|
getReturnSelectedProductsAmount,
|
||||||
mergeRepeatedOrderLines,
|
mergeRepeatedOrderLines,
|
||||||
OrderWithTotalAndTotalCaptured
|
OrderWithTotalAndTotalCaptured
|
||||||
} from "./data";
|
} from "./data";
|
||||||
|
|
||||||
|
const orderBase: OrderDetails_order = {
|
||||||
|
__typename: "Order",
|
||||||
|
actions: [],
|
||||||
|
availableShippingMethods: [],
|
||||||
|
canFinalize: true,
|
||||||
|
channel: null,
|
||||||
|
billingAddress: {
|
||||||
|
__typename: "Address",
|
||||||
|
city: "Port Danielshire",
|
||||||
|
cityArea: "",
|
||||||
|
companyName: "",
|
||||||
|
country: {
|
||||||
|
__typename: "CountryDisplay",
|
||||||
|
code: "SE",
|
||||||
|
country: "Szwecja"
|
||||||
|
},
|
||||||
|
countryArea: "",
|
||||||
|
firstName: "Elizabeth",
|
||||||
|
id: "QWRkcmVzczoy",
|
||||||
|
lastName: "Vaughn",
|
||||||
|
phone: "",
|
||||||
|
postalCode: "52203",
|
||||||
|
streetAddress1: "419 Ruiz Orchard Apt. 199",
|
||||||
|
streetAddress2: ""
|
||||||
|
},
|
||||||
|
created: "2018-09-11T09:37:30.124154+00:00",
|
||||||
|
id: "T3JkZXI6MTk=",
|
||||||
|
number: "19",
|
||||||
|
paymentStatus: PaymentChargeStatusEnum.FULLY_CHARGED,
|
||||||
|
status: OrderStatus.FULFILLED,
|
||||||
|
// @ts-ignore
|
||||||
|
total: {
|
||||||
|
__typename: "TaxedMoney",
|
||||||
|
gross: {
|
||||||
|
__typename: "Money",
|
||||||
|
amount: 1215.89,
|
||||||
|
currency: "USD"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
describe("Get previously refunded price", () => {
|
describe("Get previously refunded price", () => {
|
||||||
it("is able to calculate refunded price from order", () => {
|
it("is able to calculate refunded price from order", () => {
|
||||||
const order: OrderWithTotalAndTotalCaptured = {
|
const order: OrderWithTotalAndTotalCaptured = {
|
||||||
|
@ -397,6 +449,762 @@ describe("Get get all fulfillment lines price sum", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Get the total value of all replaced products", () => {
|
||||||
|
it("sums up correctly", () => {
|
||||||
|
const unfulfilledLines: OrderDetails_order_lines[] = [
|
||||||
|
{
|
||||||
|
id: "1",
|
||||||
|
isShippingRequired: false,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6MzE3",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "Lake Tunes",
|
||||||
|
productSku: "lake-tunes-mp3",
|
||||||
|
quantity: 2,
|
||||||
|
quantityFulfilled: 2,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleor-digital-03_2-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "2",
|
||||||
|
isShippingRequired: false,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6MzE3",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "Lake Tunes",
|
||||||
|
productSku: "lake-tunes-mp3",
|
||||||
|
quantity: 10,
|
||||||
|
quantityFulfilled: 2,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleor-digital-03_2-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "3",
|
||||||
|
isShippingRequired: true,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6Mjg2",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "T-shirt",
|
||||||
|
productSku: "29810068",
|
||||||
|
quantity: 6,
|
||||||
|
quantityFulfilled: 1,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 2.5,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 2.5,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleordemoproduct_cl_boot06_1-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const fulfilledLines: OrderDetails_order_fulfillments_lines[] = [
|
||||||
|
{
|
||||||
|
id: "4",
|
||||||
|
quantity: 1,
|
||||||
|
orderLine: {
|
||||||
|
id: "T3JkZXJMaW5lOjQ1",
|
||||||
|
isShippingRequired: false,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6MzE3",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "Lake Tunes",
|
||||||
|
productSku: "lake-tunes-mp3",
|
||||||
|
quantity: 20,
|
||||||
|
quantityFulfilled: 6,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleor-digital-03_2-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
},
|
||||||
|
__typename: "FulfillmentLine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "5",
|
||||||
|
quantity: 1,
|
||||||
|
orderLine: {
|
||||||
|
id: "T3JkZXJMaW5lOjQ1",
|
||||||
|
isShippingRequired: false,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6MzE3",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "Lake Tunes",
|
||||||
|
productSku: "lake-tunes-mp3",
|
||||||
|
quantity: 25,
|
||||||
|
quantityFulfilled: 8,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleor-digital-03_2-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
},
|
||||||
|
__typename: "FulfillmentLine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "6",
|
||||||
|
quantity: 1,
|
||||||
|
orderLine: {
|
||||||
|
id: "T3JkZXJMaW5lOjQ3",
|
||||||
|
isShippingRequired: true,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6Mjg2",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "T-shirt",
|
||||||
|
productSku: "29810068",
|
||||||
|
quantity: 10,
|
||||||
|
quantityFulfilled: 3,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 2.5,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 2.5,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleordemoproduct_cl_boot06_1-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
},
|
||||||
|
__typename: "FulfillmentLine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "7",
|
||||||
|
quantity: 1,
|
||||||
|
orderLine: {
|
||||||
|
id: "T3JkZXJMaW5lOjQ1",
|
||||||
|
isShippingRequired: false,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6MzE3",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "Lake Tunes",
|
||||||
|
productSku: "lake-tunes-mp3",
|
||||||
|
quantity: 20,
|
||||||
|
quantityFulfilled: 6,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleor-digital-03_2-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
},
|
||||||
|
__typename: "FulfillmentLine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "8",
|
||||||
|
quantity: 1,
|
||||||
|
orderLine: {
|
||||||
|
id: "T3JkZXJMaW5lOjQ1",
|
||||||
|
isShippingRequired: false,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6MzE3",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "Lake Tunes",
|
||||||
|
productSku: "lake-tunes-mp3",
|
||||||
|
quantity: 25,
|
||||||
|
quantityFulfilled: 8,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleor-digital-03_2-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
},
|
||||||
|
__typename: "FulfillmentLine"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const unfulfiledItemsQuantities: FormsetData<LineItemData, number> = [
|
||||||
|
{
|
||||||
|
data: { isFulfillment: false, isRefunded: false },
|
||||||
|
id: "1",
|
||||||
|
label: null,
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: false, isRefunded: false },
|
||||||
|
id: "2",
|
||||||
|
label: null,
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: false, isRefunded: false },
|
||||||
|
id: "3",
|
||||||
|
label: null,
|
||||||
|
value: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const fulfiledItemsQuantities: FormsetData<LineItemData, number> = [
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: false },
|
||||||
|
id: "4",
|
||||||
|
label: null,
|
||||||
|
value: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: false },
|
||||||
|
id: "5",
|
||||||
|
label: null,
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: false },
|
||||||
|
id: "6",
|
||||||
|
label: null,
|
||||||
|
value: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: true },
|
||||||
|
id: "7",
|
||||||
|
label: null,
|
||||||
|
value: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: true },
|
||||||
|
id: "8",
|
||||||
|
label: null,
|
||||||
|
value: 3
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const itemsToBeReplaced: FormsetData<LineItemData, boolean> = [
|
||||||
|
{
|
||||||
|
data: { isFulfillment: false, isRefunded: false },
|
||||||
|
id: "1",
|
||||||
|
label: null,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: false, isRefunded: false },
|
||||||
|
id: "2",
|
||||||
|
label: null,
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: false, isRefunded: false },
|
||||||
|
id: "3",
|
||||||
|
label: null,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: false },
|
||||||
|
id: "4",
|
||||||
|
label: null,
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: false },
|
||||||
|
id: "5",
|
||||||
|
label: null,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: false },
|
||||||
|
id: "6",
|
||||||
|
label: null,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: true },
|
||||||
|
id: "7",
|
||||||
|
label: null,
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: true },
|
||||||
|
id: "8",
|
||||||
|
label: null,
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const totalValue = getReplacedProductsAmount(
|
||||||
|
{
|
||||||
|
...orderBase,
|
||||||
|
lines: unfulfilledLines,
|
||||||
|
fulfillments: [
|
||||||
|
{
|
||||||
|
id: "#1",
|
||||||
|
fulfillmentOrder: 1,
|
||||||
|
status: FulfillmentStatus.FULFILLED,
|
||||||
|
warehouse: null,
|
||||||
|
trackingNumber: "",
|
||||||
|
lines: fulfilledLines,
|
||||||
|
__typename: "Fulfillment"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itemsToBeReplaced,
|
||||||
|
unfulfiledItemsQuantities,
|
||||||
|
fulfiledItemsQuantities
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(totalValue).toBe(10);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Get the total value of all selected products", () => {
|
||||||
|
it("sums up correctly", () => {
|
||||||
|
const unfulfilledLines: OrderDetails_order_lines[] = [
|
||||||
|
{
|
||||||
|
id: "1",
|
||||||
|
isShippingRequired: false,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6MzE3",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "Lake Tunes",
|
||||||
|
productSku: "lake-tunes-mp3",
|
||||||
|
quantity: 2,
|
||||||
|
quantityFulfilled: 2,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleor-digital-03_2-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "2",
|
||||||
|
isShippingRequired: false,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6MzE3",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "Lake Tunes",
|
||||||
|
productSku: "lake-tunes-mp3",
|
||||||
|
quantity: 10,
|
||||||
|
quantityFulfilled: 2,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleor-digital-03_2-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "3",
|
||||||
|
isShippingRequired: true,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6Mjg2",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "T-shirt",
|
||||||
|
productSku: "29810068",
|
||||||
|
quantity: 6,
|
||||||
|
quantityFulfilled: 1,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 2.5,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 2.5,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleordemoproduct_cl_boot06_1-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const fulfilledLines: OrderDetails_order_fulfillments_lines[] = [
|
||||||
|
{
|
||||||
|
id: "4",
|
||||||
|
quantity: 1,
|
||||||
|
orderLine: {
|
||||||
|
id: "T3JkZXJMaW5lOjQ1",
|
||||||
|
isShippingRequired: false,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6MzE3",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "Lake Tunes",
|
||||||
|
productSku: "lake-tunes-mp3",
|
||||||
|
quantity: 20,
|
||||||
|
quantityFulfilled: 6,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleor-digital-03_2-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
},
|
||||||
|
__typename: "FulfillmentLine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "5",
|
||||||
|
quantity: 1,
|
||||||
|
orderLine: {
|
||||||
|
id: "T3JkZXJMaW5lOjQ1",
|
||||||
|
isShippingRequired: false,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6MzE3",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "Lake Tunes",
|
||||||
|
productSku: "lake-tunes-mp3",
|
||||||
|
quantity: 25,
|
||||||
|
quantityFulfilled: 8,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 9.99,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleor-digital-03_2-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
},
|
||||||
|
__typename: "FulfillmentLine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "6",
|
||||||
|
quantity: 1,
|
||||||
|
orderLine: {
|
||||||
|
id: "T3JkZXJMaW5lOjQ3",
|
||||||
|
isShippingRequired: true,
|
||||||
|
variant: {
|
||||||
|
id: "UHJvZHVjdFZhcmlhbnQ6Mjg2",
|
||||||
|
quantityAvailable: 50,
|
||||||
|
__typename: "ProductVariant"
|
||||||
|
},
|
||||||
|
productName: "T-shirt",
|
||||||
|
productSku: "29810068",
|
||||||
|
quantity: 10,
|
||||||
|
quantityFulfilled: 3,
|
||||||
|
unitPrice: {
|
||||||
|
gross: {
|
||||||
|
amount: 2.5,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
net: {
|
||||||
|
amount: 2.5,
|
||||||
|
currency: "USD",
|
||||||
|
__typename: "Money"
|
||||||
|
},
|
||||||
|
__typename: "TaxedMoney"
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
url:
|
||||||
|
"http://localhost:8000/media/__sized__/products/saleordemoproduct_cl_boot06_1-thumbnail-255x255.png",
|
||||||
|
__typename: "Image"
|
||||||
|
},
|
||||||
|
__typename: "OrderLine"
|
||||||
|
},
|
||||||
|
__typename: "FulfillmentLine"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const unfulfiledItemsQuantities: FormsetData<null, number> = [
|
||||||
|
{
|
||||||
|
data: null,
|
||||||
|
id: "1",
|
||||||
|
label: null,
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: null,
|
||||||
|
id: "2",
|
||||||
|
label: null,
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: null,
|
||||||
|
id: "3",
|
||||||
|
label: null,
|
||||||
|
value: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const fulfiledItemsQuantities: FormsetData<null, number> = [
|
||||||
|
{
|
||||||
|
data: null,
|
||||||
|
id: "4",
|
||||||
|
label: null,
|
||||||
|
value: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: null,
|
||||||
|
id: "5",
|
||||||
|
label: null,
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: null,
|
||||||
|
id: "6",
|
||||||
|
label: null,
|
||||||
|
value: 3
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const itemsToBeReplaced: FormsetData<LineItemData, boolean> = [
|
||||||
|
{
|
||||||
|
data: { isFulfillment: false, isRefunded: false },
|
||||||
|
id: "1",
|
||||||
|
label: null,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: false, isRefunded: false },
|
||||||
|
id: "2",
|
||||||
|
label: null,
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: false, isRefunded: false },
|
||||||
|
id: "3",
|
||||||
|
label: null,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: false },
|
||||||
|
id: "4",
|
||||||
|
label: null,
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: false },
|
||||||
|
id: "5",
|
||||||
|
label: null,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: false },
|
||||||
|
id: "6",
|
||||||
|
label: null,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: true },
|
||||||
|
id: "7",
|
||||||
|
label: null,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { isFulfillment: true, isRefunded: true },
|
||||||
|
id: "8",
|
||||||
|
label: null,
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const totalValue = getReturnSelectedProductsAmount(
|
||||||
|
{
|
||||||
|
...orderBase,
|
||||||
|
lines: unfulfilledLines,
|
||||||
|
fulfillments: [
|
||||||
|
{
|
||||||
|
id: "#1",
|
||||||
|
fulfillmentOrder: 1,
|
||||||
|
status: FulfillmentStatus.FULFILLED,
|
||||||
|
warehouse: null,
|
||||||
|
trackingNumber: "",
|
||||||
|
lines: fulfilledLines,
|
||||||
|
__typename: "Fulfillment"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itemsToBeReplaced,
|
||||||
|
unfulfiledItemsQuantities,
|
||||||
|
fulfiledItemsQuantities
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(totalValue).toBe(59.94);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("Merge repeated order lines of fulfillment lines", () => {
|
describe("Merge repeated order lines of fulfillment lines", () => {
|
||||||
it("is able to merge repeated order lines and sum their quantities", () => {
|
it("is able to merge repeated order lines and sum their quantities", () => {
|
||||||
const lines: OrderDetails_order_fulfillments_lines[] = [
|
const lines: OrderDetails_order_fulfillments_lines[] = [
|
||||||
|
|
|
@ -1,7 +1,19 @@
|
||||||
import { IMoney, subtractMoney } from "@saleor/components/Money";
|
import { IMoney, subtractMoney } from "@saleor/components/Money";
|
||||||
import { FormsetData } from "@saleor/hooks/useFormset";
|
import { FormsetData } from "@saleor/hooks/useFormset";
|
||||||
|
|
||||||
import { OrderDetails_order_fulfillments_lines } from "../types/OrderDetails";
|
import {
|
||||||
|
LineItemData,
|
||||||
|
OrderReturnFormData
|
||||||
|
} from "../components/OrderReturnPage/form";
|
||||||
|
import {
|
||||||
|
getAllOrderFulfilledLines,
|
||||||
|
getById
|
||||||
|
} from "../components/OrderReturnPage/utils";
|
||||||
|
import {
|
||||||
|
OrderDetails_order,
|
||||||
|
OrderDetails_order_fulfillments_lines,
|
||||||
|
OrderDetails_order_lines
|
||||||
|
} from "../types/OrderDetails";
|
||||||
import {
|
import {
|
||||||
OrderRefundData_order,
|
OrderRefundData_order,
|
||||||
OrderRefundData_order_fulfillments,
|
OrderRefundData_order_fulfillments,
|
||||||
|
@ -23,9 +35,130 @@ export function getPreviouslyRefundedPrice(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getItemPriceAndQuantity = ({
|
||||||
|
orderLines,
|
||||||
|
itemsQuantities,
|
||||||
|
id
|
||||||
|
}: {
|
||||||
|
orderLines: OrderDetails_order_lines[];
|
||||||
|
itemsQuantities: FormsetData<LineItemData, number>;
|
||||||
|
id: string;
|
||||||
|
}) => {
|
||||||
|
const { unitPrice } = orderLines.find(getById(id));
|
||||||
|
const selectedQuantity = itemsQuantities.find(getById(id))?.value;
|
||||||
|
|
||||||
|
return { selectedQuantity, unitPrice };
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectItemPriceAndQuantity = (
|
||||||
|
order: OrderDetails_order,
|
||||||
|
{
|
||||||
|
fulfiledItemsQuantities,
|
||||||
|
unfulfiledItemsQuantities
|
||||||
|
}: Partial<OrderReturnFormData>,
|
||||||
|
id: string,
|
||||||
|
isFulfillment: boolean
|
||||||
|
) =>
|
||||||
|
isFulfillment
|
||||||
|
? getItemPriceAndQuantity({
|
||||||
|
id,
|
||||||
|
itemsQuantities: fulfiledItemsQuantities,
|
||||||
|
orderLines: getAllOrderFulfilledLines(order)
|
||||||
|
})
|
||||||
|
: getItemPriceAndQuantity({
|
||||||
|
id,
|
||||||
|
itemsQuantities: unfulfiledItemsQuantities,
|
||||||
|
orderLines: order.lines
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getReplacedProductsAmount = (
|
||||||
|
order: OrderDetails_order,
|
||||||
|
{
|
||||||
|
itemsToBeReplaced,
|
||||||
|
unfulfiledItemsQuantities,
|
||||||
|
fulfiledItemsQuantities
|
||||||
|
}: Partial<OrderReturnFormData>
|
||||||
|
) => {
|
||||||
|
if (!order || !itemsToBeReplaced.length) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemsToBeReplaced.reduce(
|
||||||
|
(
|
||||||
|
resultAmount: number,
|
||||||
|
{ id, value: isItemToBeReplaced, data: { isFulfillment, isRefunded } }
|
||||||
|
) => {
|
||||||
|
if (!isItemToBeReplaced || isRefunded) {
|
||||||
|
return resultAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { unitPrice, selectedQuantity } = selectItemPriceAndQuantity(
|
||||||
|
order,
|
||||||
|
{ fulfiledItemsQuantities, unfulfiledItemsQuantities },
|
||||||
|
id,
|
||||||
|
isFulfillment
|
||||||
|
);
|
||||||
|
|
||||||
|
return resultAmount + unitPrice?.gross?.amount * selectedQuantity;
|
||||||
|
},
|
||||||
|
0
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getReturnSelectedProductsAmount = (
|
||||||
|
order: OrderDetails_order,
|
||||||
|
{ itemsToBeReplaced, unfulfiledItemsQuantities, fulfiledItemsQuantities }
|
||||||
|
) => {
|
||||||
|
if (!order) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unfulfilledItemsValue = getPartialProductsValue({
|
||||||
|
itemsQuantities: unfulfiledItemsQuantities,
|
||||||
|
itemsToBeReplaced,
|
||||||
|
orderLines: order.lines
|
||||||
|
});
|
||||||
|
|
||||||
|
const fulfiledItemsValue = getPartialProductsValue({
|
||||||
|
itemsQuantities: fulfiledItemsQuantities,
|
||||||
|
itemsToBeReplaced,
|
||||||
|
orderLines: getAllOrderFulfilledLines(order)
|
||||||
|
});
|
||||||
|
|
||||||
|
return unfulfilledItemsValue + fulfiledItemsValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPartialProductsValue = ({
|
||||||
|
orderLines,
|
||||||
|
itemsQuantities,
|
||||||
|
itemsToBeReplaced
|
||||||
|
}: {
|
||||||
|
itemsToBeReplaced: FormsetData<LineItemData, boolean>;
|
||||||
|
itemsQuantities: FormsetData<LineItemData, number>;
|
||||||
|
orderLines: OrderDetails_order_lines[];
|
||||||
|
}) =>
|
||||||
|
itemsQuantities.reduce((resultAmount, { id, value: quantity }) => {
|
||||||
|
const {
|
||||||
|
value: isItemToBeReplaced,
|
||||||
|
data: { isRefunded }
|
||||||
|
} = itemsToBeReplaced.find(getById(id));
|
||||||
|
|
||||||
|
if (quantity < 1 || isItemToBeReplaced || isRefunded) {
|
||||||
|
return resultAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { selectedQuantity, unitPrice } = getItemPriceAndQuantity({
|
||||||
|
id,
|
||||||
|
itemsQuantities,
|
||||||
|
orderLines
|
||||||
|
});
|
||||||
|
|
||||||
|
return resultAmount + unitPrice.gross.amount * selectedQuantity;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
export function getRefundedLinesPriceSum(
|
export function getRefundedLinesPriceSum(
|
||||||
lines: OrderRefundData_order_lines[],
|
lines: OrderRefundData_order_lines[],
|
||||||
refundedProductQuantities: FormsetData<null, string>
|
refundedProductQuantities: FormsetData<null, string | number>
|
||||||
): number {
|
): number {
|
||||||
return lines?.reduce((sum, line) => {
|
return lines?.reduce((sum, line) => {
|
||||||
const refundedLine = refundedProductQuantities.find(
|
const refundedLine = refundedProductQuantities.find(
|
||||||
|
@ -37,7 +170,7 @@ export function getRefundedLinesPriceSum(
|
||||||
|
|
||||||
export function getAllFulfillmentLinesPriceSum(
|
export function getAllFulfillmentLinesPriceSum(
|
||||||
fulfillments: OrderRefundData_order_fulfillments[],
|
fulfillments: OrderRefundData_order_fulfillments[],
|
||||||
refundedFulfilledProductQuantities: FormsetData<null, string>
|
refundedFulfilledProductQuantities: FormsetData<null, string | number>
|
||||||
): number {
|
): number {
|
||||||
return fulfillments?.reduce((sum, fulfillment) => {
|
return fulfillments?.reduce((sum, fulfillment) => {
|
||||||
const fulfilmentLinesSum = fulfillment?.lines.reduce((sum, line) => {
|
const fulfilmentLinesSum = fulfillment?.lines.reduce((sum, line) => {
|
||||||
|
|
|
@ -50,6 +50,7 @@ import {
|
||||||
orderFulfillUrl,
|
orderFulfillUrl,
|
||||||
orderListUrl,
|
orderListUrl,
|
||||||
orderRefundUrl,
|
orderRefundUrl,
|
||||||
|
orderReturnPath,
|
||||||
orderUrl,
|
orderUrl,
|
||||||
OrderUrlDialog,
|
OrderUrlDialog,
|
||||||
OrderUrlQueryParams
|
OrderUrlQueryParams
|
||||||
|
@ -227,6 +228,7 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<OrderDetailsPage
|
<OrderDetailsPage
|
||||||
|
onOrderReturn={() => navigate(orderReturnPath(id))}
|
||||||
disabled={
|
disabled={
|
||||||
updateMetadataOpts.loading ||
|
updateMetadataOpts.loading ||
|
||||||
updatePrivateMetadataOpts.loading
|
updatePrivateMetadataOpts.loading
|
||||||
|
|
113
src/orders/views/OrderReturn/OrderReturn.tsx
Normal file
113
src/orders/views/OrderReturn/OrderReturn.tsx
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
|
import useNotifier from "@saleor/hooks/useNotifier";
|
||||||
|
import { commonMessages } from "@saleor/intl";
|
||||||
|
import OrderReturnPage from "@saleor/orders/components/OrderReturnPage";
|
||||||
|
import { OrderReturnFormData } from "@saleor/orders/components/OrderReturnPage/form";
|
||||||
|
import { useOrderReturnCreateMutation } from "@saleor/orders/mutations";
|
||||||
|
import { useOrderQuery } from "@saleor/orders/queries";
|
||||||
|
import { orderUrl } from "@saleor/orders/urls";
|
||||||
|
import { OrderErrorCode } from "@saleor/types/globalTypes";
|
||||||
|
import React from "react";
|
||||||
|
import { defineMessages } from "react-intl";
|
||||||
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import ReturnFormDataParser from "./utils";
|
||||||
|
|
||||||
|
export const messages = defineMessages({
|
||||||
|
cannotRefundDescription: {
|
||||||
|
defaultMessage:
|
||||||
|
"We’ve encountered a problem while refunding the products. Product’s were not refunded. Please try again.",
|
||||||
|
description: "order return error description when cannot refund"
|
||||||
|
},
|
||||||
|
cannotRefundTitle: {
|
||||||
|
defaultMessage: "Couldn't refund products",
|
||||||
|
description: "order return error title when cannot refund"
|
||||||
|
},
|
||||||
|
successAlert: {
|
||||||
|
defaultMessage: "Successfully returned products!",
|
||||||
|
description: "order returned success message"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
interface OrderReturnProps {
|
||||||
|
orderId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const OrderReturn: React.FC<OrderReturnProps> = ({ orderId }) => {
|
||||||
|
const navigate = useNavigator();
|
||||||
|
const notify = useNotifier();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const { data, loading } = useOrderQuery({
|
||||||
|
displayLoader: true,
|
||||||
|
variables: {
|
||||||
|
id: orderId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [returnCreate, returnCreateOpts] = useOrderReturnCreateMutation({
|
||||||
|
onCompleted: ({
|
||||||
|
orderFulfillmentReturnProducts: { errors, replaceOrder }
|
||||||
|
}) => {
|
||||||
|
if (!errors.length) {
|
||||||
|
notify({
|
||||||
|
status: "success",
|
||||||
|
text: intl.formatMessage(messages.successAlert)
|
||||||
|
});
|
||||||
|
|
||||||
|
navigateToOrder(replaceOrder?.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors[0].code === OrderErrorCode.CANNOT_REFUND) {
|
||||||
|
notify({
|
||||||
|
autohide: 5000,
|
||||||
|
status: "error",
|
||||||
|
text: intl.formatMessage(messages.cannotRefundDescription),
|
||||||
|
title: intl.formatMessage(messages.cannotRefundTitle)
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
notify({
|
||||||
|
autohide: 5000,
|
||||||
|
status: "error",
|
||||||
|
text: intl.formatMessage(commonMessages.somethingWentWrong)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleSubmit = async (formData: OrderReturnFormData) => {
|
||||||
|
if (!data?.order) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await returnCreate({
|
||||||
|
variables: {
|
||||||
|
id: data.order.id,
|
||||||
|
input: new ReturnFormDataParser(data.order, formData).getParsedData()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: { orderFulfillmentReturnProducts }
|
||||||
|
} = result;
|
||||||
|
|
||||||
|
return orderFulfillmentReturnProducts.errors;
|
||||||
|
};
|
||||||
|
|
||||||
|
const navigateToOrder = (id?: string) => navigate(orderUrl(id || orderId));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OrderReturnPage
|
||||||
|
errors={returnCreateOpts.data?.orderFulfillmentReturnProducts.errors}
|
||||||
|
order={data?.order}
|
||||||
|
loading={loading || returnCreateOpts.loading}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
onBack={() => navigateToOrder()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
OrderReturn.displayName = "OrderReturn";
|
||||||
|
export default OrderReturn;
|
2
src/orders/views/OrderReturn/index.tsx
Normal file
2
src/orders/views/OrderReturn/index.tsx
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./OrderReturn";
|
||||||
|
export { default } from "./OrderReturn";
|
102
src/orders/views/OrderReturn/utils.tsx
Normal file
102
src/orders/views/OrderReturn/utils.tsx
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/* eslint-disable @typescript-eslint/member-ordering */
|
||||||
|
import { OrderRefundAmountCalculationMode } from "@saleor/orders/components/OrderRefundPage/form";
|
||||||
|
import {
|
||||||
|
FormsetQuantityData,
|
||||||
|
OrderReturnFormData
|
||||||
|
} from "@saleor/orders/components/OrderReturnPage/form";
|
||||||
|
import { getById } from "@saleor/orders/components/OrderReturnPage/utils";
|
||||||
|
import { OrderDetails_order } from "@saleor/orders/types/OrderDetails";
|
||||||
|
import {
|
||||||
|
OrderReturnFulfillmentLineInput,
|
||||||
|
OrderReturnLineInput,
|
||||||
|
OrderReturnProductsInput
|
||||||
|
} from "@saleor/types/globalTypes";
|
||||||
|
|
||||||
|
class ReturnFormDataParser {
|
||||||
|
private order: OrderDetails_order;
|
||||||
|
private formData: OrderReturnFormData;
|
||||||
|
|
||||||
|
constructor(order: OrderDetails_order, formData: OrderReturnFormData) {
|
||||||
|
this.order = order;
|
||||||
|
this.formData = formData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getParsedData = (): OrderReturnProductsInput => {
|
||||||
|
const {
|
||||||
|
fulfiledItemsQuantities,
|
||||||
|
unfulfiledItemsQuantities,
|
||||||
|
refundShipmentCosts
|
||||||
|
} = this.formData;
|
||||||
|
|
||||||
|
const fulfillmentLines = this.getParsedLineData<
|
||||||
|
OrderReturnFulfillmentLineInput
|
||||||
|
>(fulfiledItemsQuantities, "fulfillmentLineId");
|
||||||
|
|
||||||
|
const orderLines = this.getParsedLineData<OrderReturnLineInput>(
|
||||||
|
unfulfiledItemsQuantities,
|
||||||
|
"orderLineId"
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
amountToRefund: this.getAmountToRefund(),
|
||||||
|
fulfillmentLines,
|
||||||
|
includeShippingCosts: refundShipmentCosts,
|
||||||
|
orderLines,
|
||||||
|
refund: this.getShouldRefund(orderLines, fulfillmentLines)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
private getAmountToRefund = (): number | undefined =>
|
||||||
|
this.formData.amountCalculationMode ===
|
||||||
|
OrderRefundAmountCalculationMode.MANUAL
|
||||||
|
? this.formData.amount
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
private getParsedLineData = function<
|
||||||
|
T extends OrderReturnFulfillmentLineInput | OrderReturnLineInput
|
||||||
|
>(
|
||||||
|
itemsQuantities: FormsetQuantityData,
|
||||||
|
idKey: "fulfillmentLineId" | "orderLineId"
|
||||||
|
): T[] {
|
||||||
|
const { itemsToBeReplaced } = this.formData;
|
||||||
|
|
||||||
|
return itemsQuantities.reduce((result, { value: quantity, id }) => {
|
||||||
|
if (!quantity) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldReplace = !!itemsToBeReplaced.find(getById(id))?.value;
|
||||||
|
|
||||||
|
return [
|
||||||
|
...result,
|
||||||
|
({ [idKey]: id, quantity, replace: shouldReplace } as unknown) as T
|
||||||
|
];
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
|
||||||
|
private getShouldRefund = (
|
||||||
|
orderLines: OrderReturnLineInput[],
|
||||||
|
fulfillmentLines: OrderReturnFulfillmentLineInput[]
|
||||||
|
) => {
|
||||||
|
if (!this.order.totalCaptured?.amount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!this.getAmountToRefund()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
orderLines.some(ReturnFormDataParser.isLineRefundable) ||
|
||||||
|
fulfillmentLines.some(ReturnFormDataParser.isLineRefundable)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
private static isLineRefundable = function<
|
||||||
|
T extends OrderReturnLineInput | OrderReturnFulfillmentLineInput
|
||||||
|
>({ replace }: T) {
|
||||||
|
return !replace;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReturnFormDataParser;
|
|
@ -1,11 +1,13 @@
|
||||||
import { Locale, RawLocaleProvider } from "@saleor/components/Locale";
|
import { Locale, RawLocaleProvider } from "@saleor/components/Locale";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { IntlProvider } from "react-intl";
|
import { IntlProvider } from "react-intl";
|
||||||
|
import { BrowserRouter } from "react-router-dom";
|
||||||
|
|
||||||
import { Provider as DateProvider } from "../components/Date/DateContext";
|
import { Provider as DateProvider } from "../components/Date/DateContext";
|
||||||
import MessageManagerProvider from "../components/messages";
|
import MessageManagerProvider from "../components/messages";
|
||||||
import ThemeProvider from "../components/Theme";
|
import ThemeProvider from "../components/Theme";
|
||||||
import { TimezoneProvider } from "../components/Timezone";
|
import { TimezoneProvider } from "../components/Timezone";
|
||||||
|
import { APP_MOUNT_URI } from "../config";
|
||||||
|
|
||||||
export const Decorator = storyFn => (
|
export const Decorator = storyFn => (
|
||||||
<IntlProvider defaultLocale={Locale.EN} locale={Locale.EN}>
|
<IntlProvider defaultLocale={Locale.EN} locale={Locale.EN}>
|
||||||
|
@ -18,15 +20,17 @@ export const Decorator = storyFn => (
|
||||||
<DateProvider value={+new Date("2018-08-07T14:30:44+00:00")}>
|
<DateProvider value={+new Date("2018-08-07T14:30:44+00:00")}>
|
||||||
<TimezoneProvider value="America/New_York">
|
<TimezoneProvider value="America/New_York">
|
||||||
<ThemeProvider isDefaultDark={false}>
|
<ThemeProvider isDefaultDark={false}>
|
||||||
<MessageManagerProvider>
|
<BrowserRouter basename={APP_MOUNT_URI}>
|
||||||
<div
|
<MessageManagerProvider>
|
||||||
style={{
|
<div
|
||||||
padding: 24
|
style={{
|
||||||
}}
|
padding: 24
|
||||||
>
|
}}
|
||||||
{storyFn()}
|
>
|
||||||
</div>
|
{storyFn()}
|
||||||
</MessageManagerProvider>
|
</div>
|
||||||
|
</MessageManagerProvider>
|
||||||
|
</BrowserRouter>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</TimezoneProvider>
|
</TimezoneProvider>
|
||||||
</DateProvider>
|
</DateProvider>
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -30,6 +30,7 @@ const props: Omit<OrderDetailsPageProps, "classes"> = {
|
||||||
onNoteAdd: undefined,
|
onNoteAdd: undefined,
|
||||||
onOrderCancel: undefined,
|
onOrderCancel: undefined,
|
||||||
onOrderFulfill: undefined,
|
onOrderFulfill: undefined,
|
||||||
|
onOrderReturn: () => undefined,
|
||||||
onPaymentCapture: undefined,
|
onPaymentCapture: undefined,
|
||||||
onPaymentPaid: undefined,
|
onPaymentPaid: undefined,
|
||||||
onPaymentRefund: undefined,
|
onPaymentRefund: undefined,
|
||||||
|
|
|
@ -451,6 +451,9 @@ export enum FulfillmentStatus {
|
||||||
CANCELED = "CANCELED",
|
CANCELED = "CANCELED",
|
||||||
FULFILLED = "FULFILLED",
|
FULFILLED = "FULFILLED",
|
||||||
REFUNDED = "REFUNDED",
|
REFUNDED = "REFUNDED",
|
||||||
|
REFUNDED_AND_RETURNED = "REFUNDED_AND_RETURNED",
|
||||||
|
REPLACED = "REPLACED",
|
||||||
|
RETURNED = "RETURNED",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum InvoiceErrorCode {
|
export enum InvoiceErrorCode {
|
||||||
|
@ -564,7 +567,6 @@ export enum OrderErrorCode {
|
||||||
CANNOT_CANCEL_ORDER = "CANNOT_CANCEL_ORDER",
|
CANNOT_CANCEL_ORDER = "CANNOT_CANCEL_ORDER",
|
||||||
CANNOT_DELETE = "CANNOT_DELETE",
|
CANNOT_DELETE = "CANNOT_DELETE",
|
||||||
CANNOT_REFUND = "CANNOT_REFUND",
|
CANNOT_REFUND = "CANNOT_REFUND",
|
||||||
CANNOT_REFUND_FULFILLMENT_LINE = "CANNOT_REFUND_FULFILLMENT_LINE",
|
|
||||||
CAPTURE_INACTIVE_PAYMENT = "CAPTURE_INACTIVE_PAYMENT",
|
CAPTURE_INACTIVE_PAYMENT = "CAPTURE_INACTIVE_PAYMENT",
|
||||||
CHANNEL_INACTIVE = "CHANNEL_INACTIVE",
|
CHANNEL_INACTIVE = "CHANNEL_INACTIVE",
|
||||||
DUPLICATED_INPUT_ITEM = "DUPLICATED_INPUT_ITEM",
|
DUPLICATED_INPUT_ITEM = "DUPLICATED_INPUT_ITEM",
|
||||||
|
@ -572,7 +574,7 @@ export enum OrderErrorCode {
|
||||||
GRAPHQL_ERROR = "GRAPHQL_ERROR",
|
GRAPHQL_ERROR = "GRAPHQL_ERROR",
|
||||||
INSUFFICIENT_STOCK = "INSUFFICIENT_STOCK",
|
INSUFFICIENT_STOCK = "INSUFFICIENT_STOCK",
|
||||||
INVALID = "INVALID",
|
INVALID = "INVALID",
|
||||||
INVALID_REFUND_QUANTITY = "INVALID_REFUND_QUANTITY",
|
INVALID_QUANTITY = "INVALID_QUANTITY",
|
||||||
NOT_AVAILABLE_IN_CHANNEL = "NOT_AVAILABLE_IN_CHANNEL",
|
NOT_AVAILABLE_IN_CHANNEL = "NOT_AVAILABLE_IN_CHANNEL",
|
||||||
NOT_EDITABLE = "NOT_EDITABLE",
|
NOT_EDITABLE = "NOT_EDITABLE",
|
||||||
NOT_FOUND = "NOT_FOUND",
|
NOT_FOUND = "NOT_FOUND",
|
||||||
|
@ -607,13 +609,16 @@ export enum OrderEventsEnum {
|
||||||
CONFIRMED = "CONFIRMED",
|
CONFIRMED = "CONFIRMED",
|
||||||
DRAFT_ADDED_PRODUCTS = "DRAFT_ADDED_PRODUCTS",
|
DRAFT_ADDED_PRODUCTS = "DRAFT_ADDED_PRODUCTS",
|
||||||
DRAFT_CREATED = "DRAFT_CREATED",
|
DRAFT_CREATED = "DRAFT_CREATED",
|
||||||
|
DRAFT_CREATED_FROM_REPLACE = "DRAFT_CREATED_FROM_REPLACE",
|
||||||
DRAFT_REMOVED_PRODUCTS = "DRAFT_REMOVED_PRODUCTS",
|
DRAFT_REMOVED_PRODUCTS = "DRAFT_REMOVED_PRODUCTS",
|
||||||
EMAIL_SENT = "EMAIL_SENT",
|
EMAIL_SENT = "EMAIL_SENT",
|
||||||
EXTERNAL_SERVICE_NOTIFICATION = "EXTERNAL_SERVICE_NOTIFICATION",
|
EXTERNAL_SERVICE_NOTIFICATION = "EXTERNAL_SERVICE_NOTIFICATION",
|
||||||
FULFILLMENT_CANCELED = "FULFILLMENT_CANCELED",
|
FULFILLMENT_CANCELED = "FULFILLMENT_CANCELED",
|
||||||
FULFILLMENT_FULFILLED_ITEMS = "FULFILLMENT_FULFILLED_ITEMS",
|
FULFILLMENT_FULFILLED_ITEMS = "FULFILLMENT_FULFILLED_ITEMS",
|
||||||
FULFILLMENT_REFUNDED = "FULFILLMENT_REFUNDED",
|
FULFILLMENT_REFUNDED = "FULFILLMENT_REFUNDED",
|
||||||
|
FULFILLMENT_REPLACED = "FULFILLMENT_REPLACED",
|
||||||
FULFILLMENT_RESTOCKED_ITEMS = "FULFILLMENT_RESTOCKED_ITEMS",
|
FULFILLMENT_RESTOCKED_ITEMS = "FULFILLMENT_RESTOCKED_ITEMS",
|
||||||
|
FULFILLMENT_RETURNED = "FULFILLMENT_RETURNED",
|
||||||
INVOICE_GENERATED = "INVOICE_GENERATED",
|
INVOICE_GENERATED = "INVOICE_GENERATED",
|
||||||
INVOICE_REQUESTED = "INVOICE_REQUESTED",
|
INVOICE_REQUESTED = "INVOICE_REQUESTED",
|
||||||
INVOICE_SENT = "INVOICE_SENT",
|
INVOICE_SENT = "INVOICE_SENT",
|
||||||
|
@ -621,6 +626,7 @@ export enum OrderEventsEnum {
|
||||||
NOTE_ADDED = "NOTE_ADDED",
|
NOTE_ADDED = "NOTE_ADDED",
|
||||||
ORDER_FULLY_PAID = "ORDER_FULLY_PAID",
|
ORDER_FULLY_PAID = "ORDER_FULLY_PAID",
|
||||||
ORDER_MARKED_AS_PAID = "ORDER_MARKED_AS_PAID",
|
ORDER_MARKED_AS_PAID = "ORDER_MARKED_AS_PAID",
|
||||||
|
ORDER_REPLACEMENT_CREATED = "ORDER_REPLACEMENT_CREATED",
|
||||||
OTHER = "OTHER",
|
OTHER = "OTHER",
|
||||||
OVERSOLD_ITEMS = "OVERSOLD_ITEMS",
|
OVERSOLD_ITEMS = "OVERSOLD_ITEMS",
|
||||||
PAYMENT_AUTHORIZED = "PAYMENT_AUTHORIZED",
|
PAYMENT_AUTHORIZED = "PAYMENT_AUTHORIZED",
|
||||||
|
@ -651,6 +657,8 @@ export enum OrderStatus {
|
||||||
DRAFT = "DRAFT",
|
DRAFT = "DRAFT",
|
||||||
FULFILLED = "FULFILLED",
|
FULFILLED = "FULFILLED",
|
||||||
PARTIALLY_FULFILLED = "PARTIALLY_FULFILLED",
|
PARTIALLY_FULFILLED = "PARTIALLY_FULFILLED",
|
||||||
|
PARTIALLY_RETURNED = "PARTIALLY_RETURNED",
|
||||||
|
RETURNED = "RETURNED",
|
||||||
UNCONFIRMED = "UNCONFIRMED",
|
UNCONFIRMED = "UNCONFIRMED",
|
||||||
UNFULFILLED = "UNFULFILLED",
|
UNFULFILLED = "UNFULFILLED",
|
||||||
}
|
}
|
||||||
|
@ -1377,6 +1385,26 @@ export interface OrderRefundProductsInput {
|
||||||
includeShippingCosts?: boolean | null;
|
includeShippingCosts?: boolean | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrderReturnFulfillmentLineInput {
|
||||||
|
fulfillmentLineId: string;
|
||||||
|
quantity: number;
|
||||||
|
replace?: boolean | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderReturnLineInput {
|
||||||
|
orderLineId: string;
|
||||||
|
quantity: number;
|
||||||
|
replace?: boolean | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderReturnProductsInput {
|
||||||
|
orderLines?: OrderReturnLineInput[] | null;
|
||||||
|
fulfillmentLines?: OrderReturnFulfillmentLineInput[] | null;
|
||||||
|
amountToRefund?: any | null;
|
||||||
|
includeShippingCosts?: boolean | null;
|
||||||
|
refund?: boolean | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OrderSettingsUpdateInput {
|
export interface OrderSettingsUpdateInput {
|
||||||
automaticallyConfirmAllNewOrders: boolean;
|
automaticallyConfirmAllNewOrders: boolean;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue