From 457d50c251d384c8a175a7a0ab73c0c279250f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Szyma=C5=84ski?= Date: Thu, 9 Sep 2021 12:59:37 +0200 Subject: [PATCH] Modify order return page to handle waiting fulfillments (#1349) * Modify return page to show quantityToFulfill * Include calculation of waiting items on refunds * Cleanups * Fix return option * Fix tests, cleanup * Refactor getProductsAmountValues * Fix unfulfilled max quantity selection * Count waiting fulfillments when choosing if replace is possible * Trigger deploy * Fix empty unfulfilled line display when no lines presnt on return --- .../components/OrderDetailsPage/utils.ts | 9 ++- .../OrderRefundReturnAmount/utils.ts | 43 +++++++---- .../OrderReturnPage/OrderReturnPage.tsx | 37 ++++++++-- .../ReturnItemsCard.tsx | 6 +- .../components/OrderReturnPage/form.tsx | 71 +++++++++++++------ .../components/OrderReturnPage/utils.tsx | 21 ++++-- src/orders/utils/data.test.ts | 3 + src/orders/utils/data.ts | 47 ++++++++++-- src/orders/views/OrderReturn/utils.tsx | 7 +- 9 files changed, 187 insertions(+), 57 deletions(-) diff --git a/src/orders/components/OrderDetailsPage/utils.ts b/src/orders/components/OrderDetailsPage/utils.ts index 62dda66f8..a5af67ee3 100644 --- a/src/orders/components/OrderDetailsPage/utils.ts +++ b/src/orders/components/OrderDetailsPage/utils.ts @@ -2,7 +2,8 @@ import { OrderDetails_order } from "@saleor/orders/types/OrderDetails"; import { getFulfilledFulfillemnts, - getUnfulfilledLines + getUnfulfilledLines, + getWaitingFulfillments } from "../OrderReturnPage/utils"; export const hasAnyItemsReplaceable = (order?: OrderDetails_order) => { @@ -12,9 +13,13 @@ export const hasAnyItemsReplaceable = (order?: OrderDetails_order) => { const hasAnyUnfulfilledItems = getUnfulfilledLines(order).length > 0; + const hasAnyWaitingLines = getWaitingFulfillments(order).length > 0; + const hasAnyFulfilmentsToReturn = getFulfilledFulfillemnts(order).length > 0; - return hasAnyUnfulfilledItems || hasAnyFulfilmentsToReturn; + return ( + hasAnyUnfulfilledItems || hasAnyFulfilmentsToReturn || hasAnyWaitingLines + ); }; export interface ConditionalItem { diff --git a/src/orders/components/OrderRefundReturnAmount/utils.ts b/src/orders/components/OrderRefundReturnAmount/utils.ts index 7a89ec46c..5b0b4b997 100644 --- a/src/orders/components/OrderRefundReturnAmount/utils.ts +++ b/src/orders/components/OrderRefundReturnAmount/utils.ts @@ -40,12 +40,19 @@ const getShipmentCost = (order: OrderRefundData_order) => const getMaxRefund = (order: OrderRefundData_order) => order?.totalCaptured; -export const getProductsAmountValues = ( - order: OrderRefundData_order, - fulfilledItemsQuantities: FormsetData, - unfulfilledItemsQuantities: FormsetData, - shipmentCosts -): OrderRefundAmountValuesProps => { +export const getProductsAmountValues = ({ + order, + fulfilledItemsQuantities, + waitingItemsQuantities, + unfulfilledItemsQuantities, + refundShipmentCosts +}: { + order: OrderRefundData_order; + fulfilledItemsQuantities: FormsetData; + waitingItemsQuantities: FormsetData; + unfulfilledItemsQuantities: FormsetData; + refundShipmentCosts: any; +}): OrderRefundAmountValuesProps => { const authorizedAmount = getAuthorizedAmount(order); const shipmentCost = getShipmentCost(order); @@ -55,17 +62,22 @@ export const getProductsAmountValues = ( order?.lines, unfulfilledItemsQuantities as FormsetData ); + const waitingLinesSum = getAllFulfillmentLinesPriceSum( + order?.fulfillments, + waitingItemsQuantities as FormsetData + ); const allFulfillmentLinesSum = getAllFulfillmentLinesPriceSum( order?.fulfillments, fulfilledItemsQuantities as FormsetData ); - const allLinesSum = refundedLinesSum + allFulfillmentLinesSum; + const allLinesSum = + refundedLinesSum + allFulfillmentLinesSum + waitingLinesSum; const calculatedTotalAmount = getCalculatedTotalAmount({ allLinesSum, maxRefund, previouslyRefunded, shipmentCost, - shipmentCosts + shipmentCosts: refundShipmentCosts }); const selectedProductsValue = authorizedAmount?.currency && { @@ -150,6 +162,7 @@ export const getReturnProductsAmountValues = ( const { fulfilledItemsQuantities, + waitingItemsQuantities, unfulfilledItemsQuantities, refundShipmentCosts } = formData; @@ -175,12 +188,13 @@ export const getReturnProductsAmountValues = ( }; return { - ...getProductsAmountValues( + ...getProductsAmountValues({ order, fulfilledItemsQuantities, + waitingItemsQuantities, unfulfilledItemsQuantities, refundShipmentCosts - ), + }), refundTotalAmount, replacedProductsValue, selectedProductsValue @@ -195,9 +209,10 @@ export const getRefundProductsAmountValues = ( refundedProductQuantities }: OrderRefundFormData ) => - getProductsAmountValues( + getProductsAmountValues({ order, - refundedFulfilledProductQuantities, - refundedProductQuantities, + fulfilledItemsQuantities: refundedFulfilledProductQuantities, + waitingItemsQuantities: [], + unfulfilledItemsQuantities: refundedProductQuantities, refundShipmentCosts - ); + }); diff --git a/src/orders/components/OrderReturnPage/OrderReturnPage.tsx b/src/orders/components/OrderReturnPage/OrderReturnPage.tsx index 066ba2dbe..a4c276fba 100644 --- a/src/orders/components/OrderReturnPage/OrderReturnPage.tsx +++ b/src/orders/components/OrderReturnPage/OrderReturnPage.tsx @@ -16,8 +16,9 @@ import OrderRefundForm, { OrderRefundSubmitData } from "./form"; import ItemsCard from "./OrderReturnRefundItemsCard/ReturnItemsCard"; import { getFulfilledFulfillemnts, - getParsedFulfiledLines, - getUnfulfilledLines + getParsedLines, + getUnfulfilledLines, + getWaitingFulfillments } from "./utils"; const messages = defineMessages({ @@ -46,10 +47,15 @@ const OrderRefundPage: React.FC = props => { return ( {({ data, handlers, change, submit }) => { - const { fulfilledItemsQuantities, unfulfilledItemsQuantities } = data; + const { + fulfilledItemsQuantities, + waitingItemsQuantities, + unfulfilledItemsQuantities + } = data; const hasAnyItemsSelected = fulfilledItemsQuantities.some(({ value }) => !!value) || + waitingItemsQuantities.some(({ value }) => !!value) || unfulfilledItemsQuantities.some(({ value }) => !!value); return ( @@ -83,6 +89,27 @@ const OrderRefundPage: React.FC = props => { )} + {renderCollection( + getWaitingFulfillments(order), + ({ id, lines }) => ( + + + + + ) + )} {renderCollection( getFulfilledFulfillemnts(order), ({ id, lines }) => ( @@ -91,11 +118,11 @@ const OrderRefundPage: React.FC = props => { errors={errors} order={order} fulfilmentId={id} - lines={getParsedFulfiledLines(lines)} + lines={getParsedLines(lines)} itemsQuantities={data.fulfilledItemsQuantities} itemsSelections={data.itemsToBeReplaced} onChangeQuantity={handlers.changeFulfiledItemsQuantity} - onSetMaxQuantity={handlers.handleSetMaximalFulfiledItemsQuantities( + onSetMaxQuantity={handlers.handleSetMaximalItemsQuantities( id )} onChangeSelected={handlers.changeItemsToBeReplaced} diff --git a/src/orders/components/OrderReturnPage/OrderReturnRefundItemsCard/ReturnItemsCard.tsx b/src/orders/components/OrderReturnPage/OrderReturnRefundItemsCard/ReturnItemsCard.tsx index accf53aad..802e0699d 100644 --- a/src/orders/components/OrderReturnPage/OrderReturnRefundItemsCard/ReturnItemsCard.tsx +++ b/src/orders/components/OrderReturnPage/OrderReturnRefundItemsCard/ReturnItemsCard.tsx @@ -163,7 +163,7 @@ const ItemsCard: React.FC = ({ line => { const { quantity, - quantityFulfilled, + quantityToFulfill, id, thumbnail, unitPrice, @@ -175,9 +175,7 @@ const ItemsCard: React.FC = ({ .isRefunded; const isReplacable = !!variant && !isRefunded; const isReturnable = !!variant; - const lineQuantity = fulfilmentId - ? quantity - : quantity - quantityFulfilled; + const lineQuantity = fulfilmentId ? quantity : quantityToFulfill; const isSelected = itemsSelections.find(getById(id))?.value; const currentQuantity = itemsQuantities.find(getById(id))?.value; const anyLineWithoutVariant = lines.some( diff --git a/src/orders/components/OrderReturnPage/form.tsx b/src/orders/components/OrderReturnPage/form.tsx index 8fc520bad..5c5655915 100644 --- a/src/orders/components/OrderReturnPage/form.tsx +++ b/src/orders/components/OrderReturnPage/form.tsx @@ -39,15 +39,17 @@ export interface OrderReturnData { export interface OrderReturnHandlers { changeFulfiledItemsQuantity: FormsetChange; + changeWaitingItemsQuantity: FormsetChange; changeUnfulfiledItemsQuantity: FormsetChange; changeItemsToBeReplaced: FormsetChange; - handleSetMaximalFulfiledItemsQuantities; + handleSetMaximalItemsQuantities; handleSetMaximalUnfulfiledItemsQuantities; } export interface OrderReturnFormData extends OrderReturnData { itemsToBeReplaced: FormsetReplacementData; fulfilledItemsQuantities: FormsetQuantityData; + waitingItemsQuantities: FormsetQuantityData; unfulfilledItemsQuantities: FormsetQuantityData; } @@ -109,10 +111,27 @@ function useOrderReturnForm( return refundedFulfilmentsItems.concat(fulfilledFulfillmentsItems); }; + const getItemsWaiting = () => { + const commonOptions = { + initialValue: 0, + isFulfillment: true + }; + + return getParsedLineDataForFulfillmentStatus( + order, + FulfillmentStatus.WAITING_FOR_APPROVAL, + commonOptions + ); + }; + const fulfiledItemsQuatities = useFormset( getItemsFulfilled() ); + const waitingItemsQuantities = useFormset( + getItemsWaiting() + ); + const getItemsToBeReplaced = () => { if (!order) { return []; @@ -134,10 +153,17 @@ function useOrderReturnForm( { initialValue: false, isFulfillment: true } ); + const waitingFulfillmentsItems = getParsedLineDataForFulfillmentStatus( + order, + FulfillmentStatus.WAITING_FOR_APPROVAL, + { initialValue: false, isFulfillment: true } + ); + return [ ...orderLinesItems, ...refundedFulfilmentsItems, - ...fulfilledFulfillmentsItems + ...fulfilledFulfillmentsItems, + ...waitingFulfillmentsItems ]; }; @@ -149,7 +175,7 @@ function useOrderReturnForm( const newQuantities: FormsetQuantityData = unfulfiledItemsQuantites.data.map( ({ id }) => { const line = order.lines.find(getById(id)); - const initialValue = line.quantity - line.quantityFulfilled; + const initialValue = line.quantityToFulfill; return getLineItem(line, { initialValue }); } @@ -159,32 +185,34 @@ function useOrderReturnForm( unfulfiledItemsQuantites.set(newQuantities); }; - const handleSetMaximalFulfiledItemsQuantities = ( - fulfillmentId: string - ) => () => { - const { lines } = order.fulfillments.find(getById(fulfillmentId)); + const handleSetMaximalItemsQuantities = (fulfillmentId: string) => () => { + const fulfillment = order.fulfillments.find(getById(fulfillmentId)); - const newQuantities: FormsetQuantityData = fulfiledItemsQuatities.data.map( - item => { - const line = lines.find(getById(item.id)); + const quantities = + fulfillment.status === FulfillmentStatus.WAITING_FOR_APPROVAL + ? waitingItemsQuantities + : fulfiledItemsQuatities; - if (!line) { - return item; - } + const newQuantities: FormsetQuantityData = quantities.data.map(item => { + const line = fulfillment.lines.find(getById(item.id)); - return getLineItem(line, { - initialValue: line.quantity, - isRefunded: item.data.isRefunded - }); + if (!line) { + return item; } - ); + + return getLineItem(line, { + initialValue: line.quantity, + isRefunded: item.data.isRefunded + }); + }); triggerChange(); - fulfiledItemsQuatities.set(newQuantities); + quantities.set(newQuantities); }; const data: OrderReturnFormData = { fulfilledItemsQuantities: fulfiledItemsQuatities.data, + waitingItemsQuantities: waitingItemsQuantities.data, itemsToBeReplaced: itemsToBeReplaced.data, unfulfilledItemsQuantities: unfulfiledItemsQuantites.data, ...form.data @@ -208,11 +236,14 @@ function useOrderReturnForm( changeFulfiledItemsQuantity: handleHandlerChange( fulfiledItemsQuatities.change ), + changeWaitingItemsQuantity: handleHandlerChange( + waitingItemsQuantities.change + ), changeItemsToBeReplaced: handleHandlerChange(itemsToBeReplaced.change), changeUnfulfiledItemsQuantity: handleHandlerChange( unfulfiledItemsQuantites.change ), - handleSetMaximalFulfiledItemsQuantities, + handleSetMaximalItemsQuantities, handleSetMaximalUnfulfiledItemsQuantities }, hasChanged, diff --git a/src/orders/components/OrderReturnPage/utils.tsx b/src/orders/components/OrderReturnPage/utils.tsx index cc8b074ac..c38a29d23 100644 --- a/src/orders/components/OrderReturnPage/utils.tsx +++ b/src/orders/components/OrderReturnPage/utils.tsx @@ -14,7 +14,7 @@ const fulfiledStatuses = [ ]; export const getOrderUnfulfilledLines = (order: OrderDetails_order) => - order?.lines.filter(line => line.quantityFulfilled !== line.quantity) || []; + order?.lines.filter(line => line.quantityToFulfill > 0) || []; export const getFulfilledFulfillment = fulfillment => fulfiledStatuses.includes(fulfillment.status); @@ -22,12 +22,23 @@ export const getFulfilledFulfillment = fulfillment => export const getFulfilledFulfillemnts = (order?: OrderDetails_order) => order?.fulfillments.filter(getFulfilledFulfillment) || []; +export const getWaitingFulfillments = (order: OrderDetails_order) => + order?.fulfillments.filter( + f => f.status === FulfillmentStatus.WAITING_FOR_APPROVAL + ) || []; + export const getUnfulfilledLines = (order?: OrderDetails_order) => - order?.lines.filter(line => line.quantity !== line.quantityFulfilled) || []; + order?.lines.filter(line => line.quantityToFulfill > 0) || []; export const getAllOrderFulfilledLines = (order?: OrderDetails_order) => getFulfilledFulfillemnts(order).reduce( - (result, { lines }) => [...result, ...getParsedFulfiledLines(lines)], + (result, { lines }) => [...result, ...getParsedLines(lines)], + [] + ); + +export const getAllOrderWaitingLines = (order?: OrderDetails_order) => + getWaitingFulfillments(order).reduce( + (result, { lines }) => [...result, ...getParsedLines(lines)], [] ); @@ -77,11 +88,11 @@ export const getParsedLinesOfFulfillments = ( fullfillments: OrderDetails_order_fulfillments[] ) => fullfillments.reduce( - (result, { lines }) => [...result, ...getParsedFulfiledLines(lines)], + (result, { lines }) => [...result, ...getParsedLines(lines)], [] ); -export const getParsedFulfiledLines = ( +export const getParsedLines = ( lines: OrderDetailsFragment_fulfillments_lines[] ) => lines.map(({ id, quantity, orderLine }) => ({ diff --git a/src/orders/utils/data.test.ts b/src/orders/utils/data.test.ts index 52f60276e..e963674f0 100644 --- a/src/orders/utils/data.test.ts +++ b/src/orders/utils/data.test.ts @@ -1522,6 +1522,8 @@ describe("Get the total value of all selected products", () => { } ]; + const waitingItemsQuantities: FormsetData = []; + const itemsToBeReplaced: FormsetData = [ { data: { isFulfillment: false, isRefunded: false }, @@ -1591,6 +1593,7 @@ describe("Get the total value of all selected products", () => { }, { itemsToBeReplaced, + waitingItemsQuantities, unfulfilledItemsQuantities, fulfilledItemsQuantities } diff --git a/src/orders/utils/data.ts b/src/orders/utils/data.ts index 3923a84a7..1dd8a57c2 100644 --- a/src/orders/utils/data.ts +++ b/src/orders/utils/data.ts @@ -1,7 +1,7 @@ import { IMoney, subtractMoney } from "@saleor/components/Money"; import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment"; import { FormsetData } from "@saleor/hooks/useFormset"; -import { OrderErrorCode } from "@saleor/types/globalTypes"; +import { FulfillmentStatus, OrderErrorCode } from "@saleor/types/globalTypes"; import { LineItemData, @@ -9,6 +9,7 @@ import { } from "../components/OrderReturnPage/form"; import { getAllOrderFulfilledLines, + getAllOrderWaitingLines, getById } from "../components/OrderReturnPage/utils"; import { FulfillOrder_orderFulfill_errors } from "../types/FulfillOrder"; @@ -80,16 +81,33 @@ const getItemPriceAndQuantity = ({ return { selectedQuantity, unitPrice }; }; +const getFulfillmentByFulfillmentLineId = (order, fulfillmentLineId) => { + for (const fulfillment of order.fulfillments) { + if (fulfillment.lines.find(getById(fulfillmentLineId))) { + return fulfillment; + } + } +}; + const selectItemPriceAndQuantity = ( order: OrderDetails_order, { fulfilledItemsQuantities, + waitingItemsQuantities, unfulfilledItemsQuantities }: Partial, id: string, isFulfillment: boolean -) => - isFulfillment +) => { + const fulfillment = getFulfillmentByFulfillmentLineId(order, id); + if (fulfillment?.status === FulfillmentStatus.WAITING_FOR_APPROVAL) { + return getItemPriceAndQuantity({ + id, + itemsQuantities: waitingItemsQuantities, + orderLines: getAllOrderWaitingLines(order) + }); + } + return isFulfillment ? getItemPriceAndQuantity({ id, itemsQuantities: fulfilledItemsQuantities, @@ -100,12 +118,14 @@ const selectItemPriceAndQuantity = ( itemsQuantities: unfulfilledItemsQuantities, orderLines: order.lines }); +}; export const getReplacedProductsAmount = ( order: OrderDetails_order, { itemsToBeReplaced, unfulfilledItemsQuantities, + waitingItemsQuantities, fulfilledItemsQuantities }: Partial ) => { @@ -124,7 +144,11 @@ export const getReplacedProductsAmount = ( const { unitPrice, selectedQuantity } = selectItemPriceAndQuantity( order, - { fulfilledItemsQuantities, unfulfilledItemsQuantities }, + { + fulfilledItemsQuantities, + waitingItemsQuantities, + unfulfilledItemsQuantities + }, id, isFulfillment ); @@ -137,7 +161,12 @@ export const getReplacedProductsAmount = ( export const getReturnSelectedProductsAmount = ( order: OrderDetails_order, - { itemsToBeReplaced, unfulfilledItemsQuantities, fulfilledItemsQuantities } + { + itemsToBeReplaced, + waitingItemsQuantities, + unfulfilledItemsQuantities, + fulfilledItemsQuantities + } ) => { if (!order) { return 0; @@ -155,7 +184,13 @@ export const getReturnSelectedProductsAmount = ( orderLines: getAllOrderFulfilledLines(order) }); - return unfulfilledItemsValue + fulfiledItemsValue; + const waitingItemsValue = getPartialProductsValue({ + itemsQuantities: waitingItemsQuantities, + itemsToBeReplaced, + orderLines: getAllOrderWaitingLines(order) + }); + + return unfulfilledItemsValue + fulfiledItemsValue + waitingItemsValue; }; const getPartialProductsValue = ({ diff --git a/src/orders/views/OrderReturn/utils.tsx b/src/orders/views/OrderReturn/utils.tsx index cc3c4ba7e..dee4e610b 100644 --- a/src/orders/views/OrderReturn/utils.tsx +++ b/src/orders/views/OrderReturn/utils.tsx @@ -24,6 +24,7 @@ class ReturnFormDataParser { public getParsedData = (): OrderReturnProductsInput => { const { fulfilledItemsQuantities, + waitingItemsQuantities, unfulfilledItemsQuantities, refundShipmentCosts } = this.formData; @@ -32,6 +33,10 @@ class ReturnFormDataParser { OrderReturnFulfillmentLineInput >(fulfilledItemsQuantities, "fulfillmentLineId"); + const waitingLines = this.getParsedLineData< + OrderReturnFulfillmentLineInput + >(waitingItemsQuantities, "fulfillmentLineId"); + const orderLines = this.getParsedLineData( unfulfilledItemsQuantities, "orderLineId" @@ -39,7 +44,7 @@ class ReturnFormDataParser { return { amountToRefund: this.getAmountToRefund(), - fulfillmentLines, + fulfillmentLines: fulfillmentLines.concat(waitingLines), includeShippingCosts: refundShipmentCosts, orderLines, refund: this.getShouldRefund(orderLines, fulfillmentLines)