Move fulfillment warehouse selection to fulfilll page (#2199)
* Move order fulfillment warehouse selection to fulfill page * Use modal to select warehouse on fulfill order page * Remove tracking number input from fulfill order page * Update visual structure of fulfill order page * Fix fulfill order page styles * Update order fulfill utils
This commit is contained in:
parent
804e14768b
commit
2c97b2da41
28 changed files with 1432 additions and 2060 deletions
|
@ -2602,6 +2602,10 @@
|
|||
"context": "header",
|
||||
"string": "Edit Media"
|
||||
},
|
||||
"Ila7WO": {
|
||||
"context": "change warehouse dialog description",
|
||||
"string": "Choose warehouse from which you want to fulfill {productName}"
|
||||
},
|
||||
"ImTelT": {
|
||||
"context": "card subtitle",
|
||||
"string": "Select warehouses that will be used in this channel. You can assign warehouses to multiple channels."
|
||||
|
@ -2642,6 +2646,10 @@
|
|||
"J0UdxG": {
|
||||
"string": "Skip pricing for now"
|
||||
},
|
||||
"J0lNnk": {
|
||||
"context": "column label",
|
||||
"string": "Warehouse"
|
||||
},
|
||||
"J3uE0t": {
|
||||
"context": "section header",
|
||||
"string": "Attribute Values"
|
||||
|
@ -3628,10 +3636,6 @@
|
|||
"context": "product field",
|
||||
"string": "Charge Taxes"
|
||||
},
|
||||
"QWCh6/": {
|
||||
"context": "change warehouse dialog description",
|
||||
"string": "Choose warehouse you want to fulfill this order from"
|
||||
},
|
||||
"QY7FSs": {
|
||||
"context": "button",
|
||||
"string": "create product type"
|
||||
|
@ -3660,10 +3664,6 @@
|
|||
"context": "years after label",
|
||||
"string": "years after issue"
|
||||
},
|
||||
"QfKQx3": {
|
||||
"context": "warehouse label when multiple products are unavailable",
|
||||
"string": "{productCount} products are unavailable at this location"
|
||||
},
|
||||
"QiN4hv": {
|
||||
"context": "active",
|
||||
"string": "Active"
|
||||
|
@ -4369,6 +4369,10 @@
|
|||
"W5SK5c": {
|
||||
"string": "Select content type"
|
||||
},
|
||||
"W5hb5H": {
|
||||
"context": "warehouse input",
|
||||
"string": "Warehouse"
|
||||
},
|
||||
"W8i2Ez": {
|
||||
"context": "product field",
|
||||
"string": "Name"
|
||||
|
@ -5692,6 +5696,10 @@
|
|||
"context": "button",
|
||||
"string": "Set as default billing address"
|
||||
},
|
||||
"hLSgWj": {
|
||||
"context": "warehouse label number available of products",
|
||||
"string": "{productCount} available at this location"
|
||||
},
|
||||
"hLUYBt": {
|
||||
"context": "payment status",
|
||||
"string": "Pending"
|
||||
|
@ -6571,10 +6579,6 @@
|
|||
"oYGfnY": {
|
||||
"string": "ZIP / Postal code"
|
||||
},
|
||||
"oiaUni": {
|
||||
"context": "Support text under page header",
|
||||
"string": "Fulfilling from {warehouseName}"
|
||||
},
|
||||
"oiuwOl": {
|
||||
"context": "button",
|
||||
"string": "Assign"
|
||||
|
@ -7622,10 +7626,6 @@
|
|||
"context": "ProductTypeDeleteWarningDialog title",
|
||||
"string": "Delete product {selectedTypesCount,plural,one{type} other{types}}"
|
||||
},
|
||||
"x4WAC7": {
|
||||
"context": "warehouse label when one product is unavailable",
|
||||
"string": "{productName} is unavailable at this location"
|
||||
},
|
||||
"x8V/xS": {
|
||||
"context": "attribute visibility in storefront",
|
||||
"string": "Public"
|
||||
|
@ -7923,10 +7923,6 @@
|
|||
"context": "attribute type",
|
||||
"string": "Content Attribute"
|
||||
},
|
||||
"zbrHAw": {
|
||||
"context": "Tracking number input label",
|
||||
"string": "Tracking number"
|
||||
},
|
||||
"zjHH6b": {
|
||||
"context": "sale start date",
|
||||
"string": "Started"
|
||||
|
|
|
@ -79,6 +79,7 @@ export const fragmentOrderLine = gql`
|
|||
quantity
|
||||
warehouse {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
variant {
|
||||
|
@ -342,9 +343,11 @@ export const fragmentOrderFulfillLine = gql`
|
|||
productName
|
||||
quantity
|
||||
allocations {
|
||||
id
|
||||
quantity
|
||||
warehouse {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
quantityFulfilled
|
||||
|
|
|
@ -1227,6 +1227,7 @@ export const OrderLineFragmentDoc = gql`
|
|||
quantity
|
||||
warehouse {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
variant {
|
||||
|
@ -1474,9 +1475,11 @@ export const OrderFulfillLineFragmentDoc = gql`
|
|||
productName
|
||||
quantity
|
||||
allocations {
|
||||
id
|
||||
quantity
|
||||
warehouse {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
quantityFulfilled
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
|||
import { MockedProvider, MockedResponse } from "@apollo/client/testing";
|
||||
import { allPermissions } from "@saleor/hooks/makeQuery";
|
||||
import { order, warehouseSearch } from "@saleor/orders/fixtures";
|
||||
import { fulfillOrderLine, warehouseSearch } from "@saleor/orders/fixtures";
|
||||
import { searchWarehouses } from "@saleor/searches/useWarehouseSearch";
|
||||
import Decorator from "@saleor/storybook/Decorator";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
|
@ -10,8 +10,8 @@ import OrderChangeWarehouseDialog, { OrderChangeWarehouseDialogProps } from ".";
|
|||
|
||||
const props: OrderChangeWarehouseDialogProps = {
|
||||
open: true,
|
||||
lines: order("abc").lines,
|
||||
currentWarehouse: null,
|
||||
line: fulfillOrderLine("abc"),
|
||||
currentWarehouseId: null,
|
||||
onConfirm: () => null,
|
||||
onClose: () => null,
|
||||
};
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
} from "@material-ui/core";
|
||||
import Debounce from "@saleor/components/Debounce";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import { OrderLineFragment, WarehouseFragment } from "@saleor/graphql";
|
||||
import { OrderFulfillLineFragment, WarehouseFragment } from "@saleor/graphql";
|
||||
import { buttonMessages } from "@saleor/intl";
|
||||
import {
|
||||
Button,
|
||||
|
@ -25,7 +25,7 @@ import {
|
|||
SearchIcon,
|
||||
useElementScroll,
|
||||
} from "@saleor/macaw-ui";
|
||||
import { isLineAvailableInWarehouse } from "@saleor/orders/utils/data";
|
||||
import { getLineAvailableQuantityInWarehouse } from "@saleor/orders/utils/data";
|
||||
import useWarehouseSearch from "@saleor/searches/useWarehouseSearch";
|
||||
import { mapEdgesToItems } from "@saleor/utils/maps";
|
||||
import React from "react";
|
||||
|
@ -37,16 +37,16 @@ import { useStyles } from "./styles";
|
|||
|
||||
export interface OrderChangeWarehouseDialogProps {
|
||||
open: boolean;
|
||||
lines: OrderLineFragment[];
|
||||
currentWarehouse: WarehouseFragment;
|
||||
line: OrderFulfillLineFragment;
|
||||
currentWarehouseId: string;
|
||||
onConfirm: (warehouse: WarehouseFragment) => void;
|
||||
onClose();
|
||||
}
|
||||
|
||||
export const OrderChangeWarehouseDialog: React.FC<OrderChangeWarehouseDialogProps> = ({
|
||||
open,
|
||||
lines,
|
||||
currentWarehouse,
|
||||
line,
|
||||
currentWarehouseId,
|
||||
onConfirm,
|
||||
onClose,
|
||||
}) => {
|
||||
|
@ -63,10 +63,10 @@ export const OrderChangeWarehouseDialog: React.FC<OrderChangeWarehouseDialogProp
|
|||
>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (currentWarehouse?.id) {
|
||||
setSelectedWarehouseId(currentWarehouse.id);
|
||||
if (currentWarehouseId) {
|
||||
setSelectedWarehouseId(currentWarehouseId);
|
||||
}
|
||||
}, [currentWarehouse]);
|
||||
}, [currentWarehouseId]);
|
||||
|
||||
const { result: warehousesOpts, loadMore, search } = useWarehouseSearch({
|
||||
variables: {
|
||||
|
@ -103,7 +103,12 @@ export const OrderChangeWarehouseDialog: React.FC<OrderChangeWarehouseDialogProp
|
|||
</DialogHeader>
|
||||
|
||||
<DialogContent className={classes.container}>
|
||||
<FormattedMessage {...messages.dialogDescription} />
|
||||
<FormattedMessage
|
||||
{...messages.dialogDescription}
|
||||
values={{
|
||||
productName: line?.productName,
|
||||
}}
|
||||
/>
|
||||
<Debounce debounceFn={search}>
|
||||
{debounceSearchChange => {
|
||||
const handleSearchChange = (
|
||||
|
@ -144,15 +149,19 @@ export const OrderChangeWarehouseDialog: React.FC<OrderChangeWarehouseDialogProp
|
|||
|
||||
<DialogTable ref={setAnchor}>
|
||||
{filteredWarehouses ? (
|
||||
<RadioGroup value={selectedWarehouseId} onChange={handleChange}>
|
||||
<RadioGroup
|
||||
value={selectedWarehouseId}
|
||||
onChange={handleChange}
|
||||
className={classes.tableBody}
|
||||
>
|
||||
{filteredWarehouses.map(warehouse => {
|
||||
const unavailableLines = lines?.filter(
|
||||
line => !isLineAvailableInWarehouse(line, warehouse),
|
||||
const lineQuantityInWarehouse = getLineAvailableQuantityInWarehouse(
|
||||
line,
|
||||
warehouse,
|
||||
);
|
||||
const someLinesUnavailable = unavailableLines?.length > 0;
|
||||
return (
|
||||
<TableRow key={warehouse.id}>
|
||||
<TableCell>
|
||||
<TableCell className={classes.tableCell}>
|
||||
<FormControlLabel
|
||||
value={warehouse.id}
|
||||
control={<Radio color="primary" />}
|
||||
|
@ -161,28 +170,20 @@ export const OrderChangeWarehouseDialog: React.FC<OrderChangeWarehouseDialogProp
|
|||
<span className={classes.warehouseName}>
|
||||
{warehouse.name}
|
||||
</span>
|
||||
{someLinesUnavailable && (
|
||||
<Typography className={classes.supportText}>
|
||||
{unavailableLines.length === 1
|
||||
? intl.formatMessage(
|
||||
messages.productUnavailable,
|
||||
{
|
||||
productName:
|
||||
unavailableLines[0].productName,
|
||||
},
|
||||
)
|
||||
: intl.formatMessage(
|
||||
messages.multipleProductsUnavailable,
|
||||
{ productCount: unavailableLines.length },
|
||||
)}
|
||||
<FormattedMessage
|
||||
{...messages.productAvailability}
|
||||
values={{
|
||||
productCount: lineQuantityInWarehouse,
|
||||
}}
|
||||
/>
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
{currentWarehouse?.id === warehouse?.id && (
|
||||
{currentWarehouseId === warehouse?.id && (
|
||||
<Typography className={classes.helpText}>
|
||||
{intl.formatMessage(messages.currentSelection)}
|
||||
<FormattedMessage {...messages.currentSelection} />
|
||||
</Typography>
|
||||
)}
|
||||
</TableCell>
|
||||
|
|
|
@ -7,8 +7,9 @@ export const changeWarehouseDialogMessages = defineMessages({
|
|||
description: "change warehouse dialog title",
|
||||
},
|
||||
dialogDescription: {
|
||||
defaultMessage: "Choose warehouse you want to fulfill this order from",
|
||||
id: "QWCh6/",
|
||||
defaultMessage:
|
||||
"Choose warehouse from which you want to fulfill {productName}",
|
||||
id: "Ila7WO",
|
||||
description: "change warehouse dialog description",
|
||||
},
|
||||
searchFieldPlaceholder: {
|
||||
|
@ -21,15 +22,10 @@ export const changeWarehouseDialogMessages = defineMessages({
|
|||
id: "Epm41J",
|
||||
description: "change warehouse dialog warehouse list label",
|
||||
},
|
||||
productUnavailable: {
|
||||
defaultMessage: "{productName} is unavailable at this location",
|
||||
id: "x4WAC7",
|
||||
description: "warehouse label when one product is unavailable",
|
||||
},
|
||||
multipleProductsUnavailable: {
|
||||
defaultMessage: "{productCount} products are unavailable at this location",
|
||||
id: "QfKQx3",
|
||||
description: "warehouse label when multiple products are unavailable",
|
||||
productAvailability: {
|
||||
defaultMessage: "{productCount} available at this location",
|
||||
id: "hLSgWj",
|
||||
description: "warehouse label number available of products",
|
||||
},
|
||||
currentSelection: {
|
||||
defaultMessage: "currently selected",
|
||||
|
|
|
@ -41,6 +41,15 @@ export const useStyles = makeStyles(
|
|||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
},
|
||||
tableBody: {
|
||||
display: "table",
|
||||
width: "100%",
|
||||
},
|
||||
tableCell: {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
},
|
||||
}),
|
||||
{ name: "OrderChangeWarehouseDialog" },
|
||||
);
|
||||
|
|
|
@ -19,7 +19,6 @@ import {
|
|||
OrderDetailsFragment,
|
||||
OrderDetailsQuery,
|
||||
OrderStatus,
|
||||
WarehouseFragment,
|
||||
} from "@saleor/graphql";
|
||||
import { SubmitPromise } from "@saleor/hooks/useForm";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
|
@ -70,7 +69,6 @@ export interface OrderDetailsPageProps {
|
|||
}>;
|
||||
disabled: boolean;
|
||||
saveButtonBarState: ConfirmButtonTransitionState;
|
||||
selectedWarehouse?: WarehouseFragment;
|
||||
onOrderLineAdd?: () => void;
|
||||
onOrderLineChange?: (
|
||||
id: string,
|
||||
|
@ -96,7 +94,6 @@ export interface OrderDetailsPageProps {
|
|||
onInvoiceClick(invoiceId: string);
|
||||
onInvoiceGenerate();
|
||||
onInvoiceSend(invoiceId: string);
|
||||
onWarehouseChange?();
|
||||
onSubmit(data: MetadataFormData): SubmitPromise;
|
||||
}
|
||||
|
||||
|
@ -124,7 +121,6 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
|
|||
order,
|
||||
shop,
|
||||
saveButtonBarState,
|
||||
selectedWarehouse,
|
||||
onBillingAddressEdit,
|
||||
onFulfillmentApprove,
|
||||
onFulfillmentCancel,
|
||||
|
@ -146,7 +142,6 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
|
|||
onOrderLineChange,
|
||||
onOrderLineRemove,
|
||||
onShippingMethodEdit,
|
||||
onWarehouseChange,
|
||||
onSubmit,
|
||||
} = props;
|
||||
const classes = useStyles(props);
|
||||
|
@ -268,8 +263,6 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
|
|||
notAllowedToFulfillUnpaid={notAllowedToFulfillUnpaid}
|
||||
lines={unfulfilled}
|
||||
onFulfill={onOrderFulfill}
|
||||
onWarehouseChange={onWarehouseChange}
|
||||
selectedWarehouse={selectedWarehouse}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
import { TableCell, TableRow, TextField, Typography } from "@material-ui/core";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import TableCellAvatar from "@saleor/components/TableCellAvatar";
|
||||
import {
|
||||
OrderFulfillLineFragment,
|
||||
OrderFulfillStockInput,
|
||||
} from "@saleor/graphql";
|
||||
import { OrderFulfillLineFragment } from "@saleor/graphql";
|
||||
import { FormsetChange, FormsetData } from "@saleor/hooks/useFormset";
|
||||
import { Tooltip, WarningIcon } from "@saleor/macaw-ui";
|
||||
import {
|
||||
ChevronIcon,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
WarningIcon,
|
||||
} from "@saleor/macaw-ui";
|
||||
import {
|
||||
getAttributesCaption,
|
||||
getOrderLineAvailableQuantity,
|
||||
getWarehouseStock,
|
||||
OrderFulfillLineFormData,
|
||||
} from "@saleor/orders/utils/data";
|
||||
import classNames from "classnames";
|
||||
import React from "react";
|
||||
|
@ -22,13 +25,19 @@ import { useStyles } from "./styles";
|
|||
interface OrderFulfillLineProps {
|
||||
line: OrderFulfillLineFragment;
|
||||
lineIndex: number;
|
||||
warehouseId: string;
|
||||
formsetData: FormsetData<null, OrderFulfillStockInput[]>;
|
||||
formsetChange: FormsetChange<OrderFulfillStockInput[]>;
|
||||
formsetData: FormsetData<null, OrderFulfillLineFormData[]>;
|
||||
formsetChange: FormsetChange<OrderFulfillLineFormData[]>;
|
||||
onWarehouseChange: () => void;
|
||||
}
|
||||
|
||||
export const OrderFulfillLine: React.FC<OrderFulfillLineProps> = props => {
|
||||
const { line, lineIndex, warehouseId, formsetData, formsetChange } = props;
|
||||
const {
|
||||
line,
|
||||
lineIndex,
|
||||
formsetData,
|
||||
formsetChange,
|
||||
onWarehouseChange,
|
||||
} = props;
|
||||
const classes = useStyles();
|
||||
const intl = useIntl();
|
||||
|
||||
|
@ -37,14 +46,19 @@ export const OrderFulfillLine: React.FC<OrderFulfillLineProps> = props => {
|
|||
const lineFormQuantity = isPreorder
|
||||
? 0
|
||||
: formsetData[lineIndex]?.value?.[0]?.quantity;
|
||||
const lineFormWarehouse = formsetData[lineIndex]?.value?.[0]?.warehouse;
|
||||
|
||||
const overfulfill = lineFormQuantity > line.quantityToFulfill;
|
||||
const warehouseStock = getWarehouseStock(line?.variant?.stocks, warehouseId);
|
||||
|
||||
const warehouseStock = getWarehouseStock(
|
||||
line?.variant?.stocks,
|
||||
lineFormWarehouse?.id,
|
||||
);
|
||||
const availableQuantity = getOrderLineAvailableQuantity(line, warehouseStock);
|
||||
|
||||
const isStockExceeded = lineFormQuantity > availableQuantity;
|
||||
|
||||
if (!line) {
|
||||
if (!line || !lineFormWarehouse) {
|
||||
return (
|
||||
<TableRow key={lineIndex}>
|
||||
<TableCellAvatar className={classes.colName}>
|
||||
|
@ -59,6 +73,9 @@ export const OrderFulfillLine: React.FC<OrderFulfillLineProps> = props => {
|
|||
<TableCell className={classes.colStock}>
|
||||
<Skeleton />
|
||||
</TableCell>
|
||||
<TableCell className={classes.colWarehouse}>
|
||||
<Skeleton />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
|
@ -116,7 +133,7 @@ export const OrderFulfillLine: React.FC<OrderFulfillLineProps> = props => {
|
|||
formsetChange(line.id, [
|
||||
{
|
||||
quantity: parseInt(event.target.value, 10),
|
||||
warehouse: warehouseId,
|
||||
warehouse: lineFormWarehouse,
|
||||
},
|
||||
])
|
||||
}
|
||||
|
@ -141,6 +158,20 @@ export const OrderFulfillLine: React.FC<OrderFulfillLineProps> = props => {
|
|||
<TableCell className={classes.colStock} key="total">
|
||||
{isPreorder || isDeletedVariant ? undefined : availableQuantity}
|
||||
</TableCell>
|
||||
<TableCell className={classes.colWarehouse}>
|
||||
<IconButton
|
||||
onClick={onWarehouseChange}
|
||||
className={classes.warehouseButton}
|
||||
data-test-id="select-warehouse-button"
|
||||
>
|
||||
<div className={classes.warehouseButtonContent}>
|
||||
<div className={classes.warehouseButtonContentText}>
|
||||
{lineFormWarehouse?.name ?? <Skeleton />}
|
||||
</div>
|
||||
<ChevronIcon />
|
||||
</div>
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -12,4 +12,9 @@ export const messages = defineMessages({
|
|||
id: "8vQGO0",
|
||||
description: "tooltip content when line's variant has been deleted",
|
||||
},
|
||||
warehouse: {
|
||||
defaultMessage: "Warehouse",
|
||||
id: "W5hb5H",
|
||||
description: "warehouse input",
|
||||
},
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@ export const useStyles = makeStyles(
|
|||
width: 180,
|
||||
},
|
||||
colName: {
|
||||
width: 250,
|
||||
width: 220,
|
||||
},
|
||||
colQuantity: {
|
||||
textAlign: "right",
|
||||
|
@ -16,7 +16,11 @@ export const useStyles = makeStyles(
|
|||
colSku: {
|
||||
textAlign: "right",
|
||||
textOverflow: "ellipsis",
|
||||
width: 150,
|
||||
width: 100,
|
||||
},
|
||||
colWarehouse: {
|
||||
width: 200,
|
||||
textAlign: "right",
|
||||
},
|
||||
warningIcon: {
|
||||
color: theme.palette.saleor.warning.mid,
|
||||
|
@ -42,6 +46,23 @@ export const useStyles = makeStyles(
|
|||
color: theme.palette.text.secondary,
|
||||
whiteSpace: "nowrap",
|
||||
},
|
||||
warehouseButton: {
|
||||
padding: theme.spacing(1.5),
|
||||
width: "100%",
|
||||
justifyContent: "right",
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
},
|
||||
warehouseButtonContent: {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
cursor: "pointer",
|
||||
},
|
||||
warehouseButtonContentText: {
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
},
|
||||
}),
|
||||
{ name: "OrderFulfillLine" },
|
||||
);
|
||||
|
|
|
@ -8,24 +8,21 @@ import { orderToFulfill } from "./fixtures";
|
|||
import OrderFulfillPage, { OrderFulfillPageProps } from "./OrderFulfillPage";
|
||||
|
||||
const props: OrderFulfillPageProps = {
|
||||
params: {},
|
||||
errors: [],
|
||||
loading: false,
|
||||
onSubmit: () => undefined,
|
||||
order: orderToFulfill,
|
||||
saveButtonBar: "default",
|
||||
warehouse: warehouseList[0],
|
||||
openModal: () => undefined,
|
||||
closeModal: () => undefined,
|
||||
};
|
||||
|
||||
storiesOf("Views / Orders / Fulfill order", module)
|
||||
.addDecorator(Decorator)
|
||||
.add("default", () => <OrderFulfillPage {...props} />)
|
||||
.add("loading", () => (
|
||||
<OrderFulfillPage
|
||||
{...props}
|
||||
loading={true}
|
||||
order={undefined}
|
||||
warehouse={undefined}
|
||||
/>
|
||||
<OrderFulfillPage {...props} loading={true} order={undefined} />
|
||||
))
|
||||
.add("error", () => (
|
||||
<OrderFulfillPage
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@material-ui/core";
|
||||
import { Backlink } from "@saleor/components/Backlink";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Container from "@saleor/components/Container";
|
||||
import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
|
||||
import Form from "@saleor/components/Form";
|
||||
import { Grid } from "@saleor/components/Grid";
|
||||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||
import Savebar from "@saleor/components/Savebar";
|
||||
|
@ -24,7 +23,6 @@ import {
|
|||
OrderFulfillLineFragment,
|
||||
OrderFulfillStockInput,
|
||||
ShopOrderSettingsFragment,
|
||||
WarehouseFragment,
|
||||
} from "@saleor/graphql";
|
||||
import { SubmitPromise } from "@saleor/hooks/useForm";
|
||||
import useFormset, { FormsetData } from "@saleor/hooks/useFormset";
|
||||
|
@ -32,10 +30,17 @@ import useNavigator from "@saleor/hooks/useNavigator";
|
|||
import { commonMessages } from "@saleor/intl";
|
||||
import { ConfirmButtonTransitionState } from "@saleor/macaw-ui";
|
||||
import { renderCollection } from "@saleor/misc";
|
||||
import { orderUrl } from "@saleor/orders/urls";
|
||||
import OrderChangeWarehouseDialog from "@saleor/orders/components/OrderChangeWarehouseDialog";
|
||||
import {
|
||||
OrderFulfillUrlDialog,
|
||||
OrderFulfillUrlQueryParams,
|
||||
orderUrl,
|
||||
} from "@saleor/orders/urls";
|
||||
import {
|
||||
getAttributesCaption,
|
||||
getLineAllocationWithHighestQuantity,
|
||||
getToFulfillOrderLines,
|
||||
OrderFulfillLineFormData,
|
||||
} from "@saleor/orders/utils/data";
|
||||
import classNames from "classnames";
|
||||
import React from "react";
|
||||
|
@ -48,37 +53,42 @@ import { useStyles } from "./styles";
|
|||
|
||||
interface OrderFulfillFormData {
|
||||
sendInfo: boolean;
|
||||
trackingNumber: string;
|
||||
allowStockToBeExceeded: boolean;
|
||||
}
|
||||
export interface OrderFulfillSubmitData extends OrderFulfillFormData {
|
||||
items: FormsetData<null, OrderFulfillStockInput[]>;
|
||||
}
|
||||
export interface OrderFulfillPageProps {
|
||||
params: OrderFulfillUrlQueryParams;
|
||||
loading: boolean;
|
||||
errors: FulfillOrderMutation["orderFulfill"]["errors"];
|
||||
order: OrderFulfillDataQuery["order"];
|
||||
saveButtonBar: ConfirmButtonTransitionState;
|
||||
warehouse: WarehouseFragment;
|
||||
shopSettings?: ShopOrderSettingsFragment;
|
||||
onSubmit: (data: OrderFulfillSubmitData) => SubmitPromise;
|
||||
openModal: (
|
||||
action: OrderFulfillUrlDialog,
|
||||
params?: OrderFulfillUrlQueryParams,
|
||||
) => void;
|
||||
closeModal: () => void;
|
||||
}
|
||||
|
||||
const initialFormData: OrderFulfillFormData = {
|
||||
sendInfo: true,
|
||||
trackingNumber: "",
|
||||
allowStockToBeExceeded: false,
|
||||
};
|
||||
|
||||
const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
|
||||
const {
|
||||
params,
|
||||
loading,
|
||||
errors,
|
||||
order,
|
||||
saveButtonBar,
|
||||
warehouse,
|
||||
shopSettings,
|
||||
onSubmit,
|
||||
openModal,
|
||||
closeModal,
|
||||
} = props;
|
||||
|
||||
const intl = useIntl();
|
||||
|
@ -87,10 +97,15 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
|
|||
|
||||
const { change: formsetChange, data: formsetData } = useFormset<
|
||||
null,
|
||||
OrderFulfillStockInput[]
|
||||
OrderFulfillLineFormData[]
|
||||
>(
|
||||
(getToFulfillOrderLines(order?.lines) as OrderFulfillLineFragment[]).map(
|
||||
line => ({
|
||||
line => {
|
||||
const highestQuantityAllocation = getLineAllocationWithHighestQuantity(
|
||||
line,
|
||||
);
|
||||
|
||||
return {
|
||||
data: null,
|
||||
id: line.id,
|
||||
label: getAttributesCaption(line?.variant?.attributes),
|
||||
|
@ -99,10 +114,11 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
|
|||
: [
|
||||
{
|
||||
quantity: line.quantityToFulfill,
|
||||
warehouse: warehouse?.id,
|
||||
warehouse: highestQuantityAllocation?.warehouse,
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -122,7 +138,15 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
|
|||
return onSubmit({
|
||||
...formData,
|
||||
allowStockToBeExceeded,
|
||||
items: formsetData.filter(item => !!item.value),
|
||||
items: formsetData
|
||||
.filter(item => !!item.value)
|
||||
.map(item => ({
|
||||
...item,
|
||||
value: item.value.map(value => ({
|
||||
quantity: value.quantity,
|
||||
warehouse: value.warehouse.id,
|
||||
})),
|
||||
})),
|
||||
});
|
||||
};
|
||||
React.useEffect(() => {
|
||||
|
@ -166,6 +190,7 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
|
|||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Container>
|
||||
<Backlink href={orderUrl(order?.id)}>
|
||||
{order?.number
|
||||
|
@ -179,12 +204,6 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
|
|||
orderNumber: order?.number,
|
||||
})}
|
||||
/>
|
||||
<Typography className={classes.warehouseLabel}>
|
||||
<FormattedMessage
|
||||
{...messages.fulfillingFrom}
|
||||
values={{ warehouseName: warehouse?.name }}
|
||||
/>
|
||||
</Typography>
|
||||
<Form
|
||||
confirmLeave
|
||||
initial={initialFormData}
|
||||
|
@ -197,12 +216,11 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
|
|||
>
|
||||
{({ change, data, submit }) => (
|
||||
<>
|
||||
<Grid>
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={intl.formatMessage(messages.itemsReadyToShip)}
|
||||
/>
|
||||
{warehouse ? (
|
||||
{order ? (
|
||||
<ResponsiveTable className={classes.table}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
|
@ -223,50 +241,58 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
|
|||
<TableCell className={classes.colStock}>
|
||||
<FormattedMessage {...messages.stock} />
|
||||
</TableCell>
|
||||
<TableCell className={classes.colWarehouse}>
|
||||
<FormattedMessage {...messages.warehouse} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{renderCollection(
|
||||
getToFulfillOrderLines(order?.lines),
|
||||
getToFulfillOrderLines(order.lines),
|
||||
(line: OrderFulfillLineFragment, lineIndex) => (
|
||||
<OrderFulfillLine
|
||||
key={line.id}
|
||||
line={line}
|
||||
lineIndex={lineIndex}
|
||||
warehouseId={warehouse?.id}
|
||||
formsetData={formsetData}
|
||||
formsetChange={formsetChange}
|
||||
onWarehouseChange={() =>
|
||||
openModal("change-warehouse", {
|
||||
lineId: line.id,
|
||||
warehouseId:
|
||||
formsetData[lineIndex]?.value?.[0]?.warehouse
|
||||
.id,
|
||||
})
|
||||
}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</TableBody>
|
||||
</ResponsiveTable>
|
||||
) : (
|
||||
<CardContent>
|
||||
<Skeleton />
|
||||
</CardContent>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
<Card className={classes.shipmentInformationCard}>
|
||||
<Typography className={classes.supportHeader}>
|
||||
<FormattedMessage {...messages.shipmentInformation} />
|
||||
</Typography>
|
||||
<TextField
|
||||
value={data.trackingNumber}
|
||||
name="trackingNumber"
|
||||
label={intl.formatMessage(messages.trackingNumber)}
|
||||
fullWidth
|
||||
onChange={change}
|
||||
/>
|
||||
<CardSpacer />
|
||||
|
||||
{shopSettings?.fulfillmentAutoApprove && (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={intl.formatMessage(messages.shipmentInformation)}
|
||||
/>
|
||||
<CardContent>
|
||||
<ControlledCheckbox
|
||||
checked={data.sendInfo}
|
||||
label={intl.formatMessage(messages.sentShipmentDetails)}
|
||||
name="sendInfo"
|
||||
onChange={change}
|
||||
/>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Savebar
|
||||
disabled={!shouldEnableSave()}
|
||||
|
@ -279,7 +305,9 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
|
|||
tooltips={{
|
||||
confirm:
|
||||
notAllowedToFulfillUnpaid &&
|
||||
intl.formatMessage(commonMessages.cannotFullfillUnpaidOrder),
|
||||
intl.formatMessage(
|
||||
commonMessages.cannotFullfillUnpaidOrder,
|
||||
),
|
||||
}}
|
||||
onSubmit={submit}
|
||||
onCancel={() => navigate(orderUrl(order?.id))}
|
||||
|
@ -288,7 +316,6 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
|
|||
open={displayStockExceededDialog}
|
||||
lines={order?.lines}
|
||||
formsetData={formsetData}
|
||||
warehouseId={warehouse?.id}
|
||||
confirmButtonState={saveButtonBar}
|
||||
onSubmit={submit}
|
||||
onClose={() => setDisplayStockExceededDialog(false)}
|
||||
|
@ -297,6 +324,25 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
|
|||
)}
|
||||
</Form>
|
||||
</Container>
|
||||
<OrderChangeWarehouseDialog
|
||||
open={params.action === "change-warehouse"}
|
||||
line={order?.lines.find(line => line.id === params.lineId)}
|
||||
currentWarehouseId={params.warehouseId}
|
||||
onConfirm={warehouse => {
|
||||
const lineFormQuantity = formsetData.find(
|
||||
item => item.id === params.lineId,
|
||||
)?.value?.[0]?.quantity;
|
||||
|
||||
formsetChange(params.lineId, [
|
||||
{
|
||||
quantity: lineFormQuantity,
|
||||
warehouse,
|
||||
},
|
||||
]);
|
||||
}}
|
||||
onClose={closeModal}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -71,14 +71,9 @@ export const messages = defineMessages({
|
|||
id: "lF+VJQ",
|
||||
description: "Shipment information card header",
|
||||
},
|
||||
trackingNumber: {
|
||||
defaultMessage: "Tracking number",
|
||||
id: "zbrHAw",
|
||||
description: "Tracking number input label",
|
||||
},
|
||||
fulfillingFrom: {
|
||||
defaultMessage: "Fulfilling from {warehouseName}",
|
||||
id: "oiaUni",
|
||||
description: "Support text under page header",
|
||||
warehouse: {
|
||||
defaultMessage: "Warehouse",
|
||||
id: "J0lNnk",
|
||||
description: "column label",
|
||||
},
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ export const useStyles = makeStyles(
|
|||
width: 180,
|
||||
},
|
||||
colName: {
|
||||
width: 250,
|
||||
width: 220,
|
||||
},
|
||||
colQuantity: {
|
||||
textAlign: "right",
|
||||
|
@ -19,7 +19,11 @@ export const useStyles = makeStyles(
|
|||
colSku: {
|
||||
textAlign: "right",
|
||||
textOverflow: "ellipsis",
|
||||
width: 150,
|
||||
width: 100,
|
||||
},
|
||||
colWarehouse: {
|
||||
textAlign: "right",
|
||||
width: 200,
|
||||
},
|
||||
table: {
|
||||
"&&": {
|
||||
|
@ -41,9 +45,6 @@ export const useStyles = makeStyles(
|
|||
lineHeight: "160%",
|
||||
marginBottom: theme.spacing(2),
|
||||
},
|
||||
warehouseLabel: {
|
||||
marginBottom: theme.spacing(4),
|
||||
},
|
||||
}),
|
||||
{ name: "OrderFulfillPage" },
|
||||
);
|
||||
|
|
|
@ -14,7 +14,7 @@ import { renderCollection } from "@saleor/misc";
|
|||
import {
|
||||
getFulfillmentFormsetQuantity,
|
||||
getOrderLineAvailableQuantity,
|
||||
OrderFulfillStockInputFormsetData,
|
||||
OrderFulfillStockFormsetData,
|
||||
} from "@saleor/orders/utils/data";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
@ -26,8 +26,7 @@ import { useStyles } from "./styles";
|
|||
export interface OrderFulfillStockExceededDialogProps {
|
||||
lines: Array<FulfillmentFragment["lines"][0] | OrderFulfillLineFragment>;
|
||||
open: boolean;
|
||||
formsetData: OrderFulfillStockInputFormsetData;
|
||||
warehouseId: string;
|
||||
formsetData: OrderFulfillStockFormsetData;
|
||||
confirmButtonState: ConfirmButtonTransitionState;
|
||||
onSubmit();
|
||||
onClose();
|
||||
|
@ -38,7 +37,6 @@ const OrderFulfillStockExceededDialog: React.FC<OrderFulfillStockExceededDialogP
|
|||
lines,
|
||||
open,
|
||||
formsetData,
|
||||
warehouseId,
|
||||
confirmButtonState,
|
||||
onClose,
|
||||
onSubmit,
|
||||
|
@ -49,8 +47,10 @@ const OrderFulfillStockExceededDialog: React.FC<OrderFulfillStockExceededDialogP
|
|||
|
||||
const exceededLines = lines?.filter(el => {
|
||||
const line = "orderLine" in el ? el.orderLine : el;
|
||||
const lineFormWarehouse = formsetData?.find(item => item.id === el.id)
|
||||
?.value?.[0]?.warehouse;
|
||||
const stock = line.variant?.stocks.find(
|
||||
stock => stock.warehouse.id === warehouseId,
|
||||
stock => stock.warehouse.id === lineFormWarehouse?.id,
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -91,14 +91,20 @@ const OrderFulfillStockExceededDialog: React.FC<OrderFulfillStockExceededDialogP
|
|||
)}
|
||||
|
||||
<TableBody>
|
||||
{renderCollection(exceededLines, line => (
|
||||
{renderCollection(exceededLines, line => {
|
||||
const lineFormWarehouse = formsetData?.find(
|
||||
item => item.id === line.id,
|
||||
)?.value?.[0]?.warehouse;
|
||||
|
||||
return (
|
||||
<OrderFulfillStockExceededDialogLine
|
||||
key={line?.id}
|
||||
line={line}
|
||||
formsetData={formsetData}
|
||||
warehouseId={warehouseId}
|
||||
warehouseId={lineFormWarehouse?.id}
|
||||
/>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</ResponsiveTable>
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
getAttributesCaption,
|
||||
getFulfillmentFormsetQuantity,
|
||||
getOrderLineAvailableQuantity,
|
||||
OrderFulfillStockInputFormsetData,
|
||||
OrderFulfillStockFormsetData,
|
||||
} from "@saleor/orders/utils/data";
|
||||
import React from "react";
|
||||
|
||||
|
@ -14,23 +14,24 @@ import { useStyles } from "../OrderFulfillStockExceededDialog/styles";
|
|||
export interface OrderFulfillStockExceededDialogLineProps {
|
||||
line: OrderFulfillLineFragment | FulfillmentFragment["lines"][0];
|
||||
warehouseId: string;
|
||||
formsetData: OrderFulfillStockInputFormsetData;
|
||||
formsetData: OrderFulfillStockFormsetData;
|
||||
}
|
||||
|
||||
const OrderFulfillStockExceededDialogLine: React.FC<OrderFulfillStockExceededDialogLineProps> = props => {
|
||||
const { line: genericLine, warehouseId, formsetData } = props;
|
||||
|
||||
const line = "orderLine" in genericLine ? genericLine.orderLine : genericLine;
|
||||
const classes = useStyles(props);
|
||||
|
||||
const stock = line?.variant?.stocks.find(
|
||||
stock => stock.warehouse.id === warehouseId,
|
||||
);
|
||||
|
||||
if (!genericLine) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const line = "orderLine" in genericLine ? genericLine.orderLine : genericLine;
|
||||
|
||||
const stock = line?.variant?.stocks.find(
|
||||
stock => stock.warehouse.id === warehouseId,
|
||||
);
|
||||
|
||||
return (
|
||||
<TableRow key={line?.id}>
|
||||
<TableCellAvatar
|
||||
|
|
|
@ -2,10 +2,8 @@ import { Card, CardActions, TableBody, Typography } from "@material-ui/core";
|
|||
import { Button } from "@saleor/components/Button";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import { OrderLineFragment, WarehouseFragment } from "@saleor/graphql";
|
||||
import { OrderLineFragment } from "@saleor/graphql";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { ChevronIcon, IconButton } from "@saleor/macaw-ui";
|
||||
import { renderCollection } from "@saleor/misc";
|
||||
import React from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
@ -20,8 +18,6 @@ interface OrderUnfulfilledProductsCardProps {
|
|||
notAllowedToFulfillUnpaid: boolean;
|
||||
lines: OrderLineFragment[];
|
||||
onFulfill: () => void;
|
||||
selectedWarehouse: WarehouseFragment;
|
||||
onWarehouseChange: () => null;
|
||||
}
|
||||
|
||||
const OrderUnfulfilledProductsCard: React.FC<OrderUnfulfilledProductsCardProps> = props => {
|
||||
|
@ -30,8 +26,6 @@ const OrderUnfulfilledProductsCard: React.FC<OrderUnfulfilledProductsCardProps>
|
|||
notAllowedToFulfillUnpaid,
|
||||
lines,
|
||||
onFulfill,
|
||||
selectedWarehouse,
|
||||
onWarehouseChange,
|
||||
} = props;
|
||||
const classes = useStyles();
|
||||
|
||||
|
@ -47,18 +41,6 @@ const OrderUnfulfilledProductsCard: React.FC<OrderUnfulfilledProductsCardProps>
|
|||
withStatus
|
||||
status="unfulfilled"
|
||||
className={classes.cardTitle}
|
||||
toolbar={
|
||||
<IconButton
|
||||
onClick={onWarehouseChange}
|
||||
className={classes.toolbarButton}
|
||||
data-test-id="select-warehouse-button"
|
||||
>
|
||||
<div className={classes.toolbarButtonContent}>
|
||||
<div>{selectedWarehouse?.name ?? <Skeleton />}</div>
|
||||
<ChevronIcon />
|
||||
</div>
|
||||
</IconButton>
|
||||
}
|
||||
/>
|
||||
<ResponsiveTable className={classes.table}>
|
||||
<TableHeader />
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
OrderDetailsQuery,
|
||||
OrderEventsEmailsEnum,
|
||||
OrderEventsEnum,
|
||||
OrderFulfillLineFragment,
|
||||
OrderListQuery,
|
||||
OrderSettingsFragment,
|
||||
OrderStatus,
|
||||
|
@ -1078,6 +1079,7 @@ export const order = (placeholder: string): OrderDetailsFragment => ({
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1186,6 +1188,7 @@ export const order = (placeholder: string): OrderDetailsFragment => ({
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1302,6 +1305,7 @@ export const order = (placeholder: string): OrderDetailsFragment => ({
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1395,6 +1399,7 @@ export const order = (placeholder: string): OrderDetailsFragment => ({
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1628,6 +1633,7 @@ export const draftOrder = (placeholder: string): OrderDetailsFragment => ({
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1721,6 +1727,7 @@ export const draftOrder = (placeholder: string): OrderDetailsFragment => ({
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1869,6 +1876,7 @@ export const draftOrder = (placeholder: string): OrderDetailsFragment => ({
|
|||
user: null,
|
||||
userEmail: null,
|
||||
});
|
||||
|
||||
export const flatOrders = orders.map(order => ({
|
||||
...order,
|
||||
orderStatus: transformOrderStatus(order.status, {
|
||||
|
@ -1878,6 +1886,70 @@ export const flatOrders = orders.map(order => ({
|
|||
formatMessage: (message: MessageDescriptor) => message.defaultMessage,
|
||||
} as any),
|
||||
}));
|
||||
|
||||
export const fulfillOrderLine = (
|
||||
placeholderImage: string,
|
||||
): OrderFulfillLineFragment => ({
|
||||
__typename: "OrderLine",
|
||||
id: "T3JkZXJMaW5lOjIz",
|
||||
isShippingRequired: false,
|
||||
productName: "Williams, Garcia and Walker (XS)",
|
||||
quantity: 2,
|
||||
quantityFulfilled: 2,
|
||||
quantityToFulfill: 0,
|
||||
allocations: [
|
||||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id: "V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
},
|
||||
quantity: 1,
|
||||
__typename: "Allocation",
|
||||
},
|
||||
],
|
||||
thumbnail: {
|
||||
__typename: "Image" as "Image",
|
||||
url: placeholderImage,
|
||||
},
|
||||
variant: {
|
||||
__typename: "ProductVariant",
|
||||
id: "dsfsfuhb",
|
||||
name: "Williams, Garcia and Walker (XS)",
|
||||
sku: "5-1337",
|
||||
attributes: [],
|
||||
trackInventory: true,
|
||||
preorder: null,
|
||||
stocks: [
|
||||
{
|
||||
id: "stock_test_id1",
|
||||
warehouse: {
|
||||
name: "stock_warehouse1",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjc4OGUyMGRlLTlmYTAtNDI5My1iZDk2LWUwM2RjY2RhMzc0ZQ==",
|
||||
__typename: "Warehouse",
|
||||
},
|
||||
quantity: 166,
|
||||
quantityAllocated: 0,
|
||||
__typename: "Stock",
|
||||
},
|
||||
{
|
||||
id: "stock_test_id2",
|
||||
warehouse: {
|
||||
name: "stock_warehouse2",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjczYzI0OGNmLTliNzAtNDlmMi1hMDRlLTM4ZTYxMmQ5MDYwMQ==",
|
||||
__typename: "Warehouse",
|
||||
},
|
||||
quantity: 166,
|
||||
quantityAllocated: 0,
|
||||
__typename: "Stock",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
export const variants = [
|
||||
{ id: "p1", name: "Product 1: variant 1", sku: "12345", stockQuantity: 3 },
|
||||
{ id: "p2", name: "Product 1: variant 2", sku: "12346", stockQuantity: 1 },
|
||||
|
|
|
@ -126,7 +126,11 @@ export type OrderUrlDialog =
|
|||
|
||||
export type OrderUrlQueryParams = Dialog<OrderUrlDialog> & SingleAction;
|
||||
|
||||
export type OrderFulfillUrlQueryParams = Partial<{ warehouse: string }>;
|
||||
export type OrderFulfillUrlFiltersType = "warehouseId" | "lineId";
|
||||
export type OrderFulfillUrlFilters = Filters<OrderFulfillUrlFiltersType>;
|
||||
export type OrderFulfillUrlDialog = "change-warehouse";
|
||||
export type OrderFulfillUrlQueryParams = Dialog<OrderFulfillUrlDialog> &
|
||||
OrderFulfillUrlFilters;
|
||||
|
||||
export const orderUrl = (id: string, params?: OrderUrlQueryParams) =>
|
||||
orderPath(encodeURIComponent(id)) + "?" + stringifyQs(params);
|
||||
|
|
|
@ -525,6 +525,7 @@ describe("Get the total value of all replaced products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -619,6 +620,7 @@ describe("Get the total value of all replaced products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -713,6 +715,7 @@ describe("Get the total value of all replaced products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -813,6 +816,7 @@ describe("Get the total value of all replaced products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -912,6 +916,7 @@ describe("Get the total value of all replaced products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1011,6 +1016,7 @@ describe("Get the total value of all replaced products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1110,6 +1116,7 @@ describe("Get the total value of all replaced products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1209,6 +1216,7 @@ describe("Get the total value of all replaced products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1442,6 +1450,7 @@ describe("Get the total value of all selected products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1536,6 +1545,7 @@ describe("Get the total value of all selected products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1630,6 +1640,7 @@ describe("Get the total value of all selected products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1730,6 +1741,7 @@ describe("Get the total value of all selected products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1829,6 +1841,7 @@ describe("Get the total value of all selected products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -1928,6 +1941,7 @@ describe("Get the total value of all selected products", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -2155,6 +2169,7 @@ describe("Merge repeated order lines of fulfillment lines", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -2254,6 +2269,7 @@ describe("Merge repeated order lines of fulfillment lines", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
@ -2353,6 +2369,7 @@ describe("Merge repeated order lines of fulfillment lines", () => {
|
|||
{
|
||||
id: "allocation_test_id",
|
||||
warehouse: {
|
||||
name: "US Warehouse",
|
||||
id:
|
||||
"V2FyZWhvdXNlOjk1NWY0ZDk2LWRmNTAtNGY0Zi1hOTM4LWM5MTYzYTA4YTViNg==",
|
||||
__typename: "Warehouse",
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
FulfillmentStatus,
|
||||
OrderDetailsFragment,
|
||||
OrderFulfillLineFragment,
|
||||
OrderFulfillStockInput,
|
||||
OrderLineFragment,
|
||||
OrderLineStockDataFragment,
|
||||
OrderRefundDataQuery,
|
||||
|
@ -328,12 +327,17 @@ export const getOrderLineAvailableQuantity = (
|
|||
return availableQuantity;
|
||||
};
|
||||
|
||||
export type OrderFulfillStockInputFormsetData = Array<
|
||||
Pick<FormsetData<null, OrderFulfillStockInput[]>[0], "id" | "value">
|
||||
export interface OrderFulfillLineFormData {
|
||||
quantity: number;
|
||||
warehouse: WarehouseFragment;
|
||||
}
|
||||
|
||||
export type OrderFulfillStockFormsetData = Array<
|
||||
Pick<FormsetData<null, OrderFulfillLineFormData[]>[0], "id" | "value">
|
||||
>;
|
||||
|
||||
export const getFulfillmentFormsetQuantity = (
|
||||
formsetData: OrderFulfillStockInputFormsetData,
|
||||
formsetData: OrderFulfillStockFormsetData,
|
||||
line: OrderLineStockDataFragment,
|
||||
) => formsetData?.find(getById(line.id))?.value?.[0]?.quantity;
|
||||
|
||||
|
@ -343,9 +347,9 @@ export const getWarehouseStock = (
|
|||
) => stocks?.find(stock => stock.warehouse.id === warehouseId);
|
||||
|
||||
export const isLineAvailableInWarehouse = (
|
||||
line: OrderLineStockDataFragment,
|
||||
line: OrderFulfillLineFragment | OrderLineStockDataFragment,
|
||||
warehouse: WarehouseFragment,
|
||||
) => {
|
||||
): boolean => {
|
||||
if (!line?.variant?.stocks) {
|
||||
return false;
|
||||
}
|
||||
|
@ -356,17 +360,59 @@ export const isLineAvailableInWarehouse = (
|
|||
return false;
|
||||
};
|
||||
|
||||
export const transformFuflillmentLinesToStockInputFormsetData = (
|
||||
export const getLineAvailableQuantityInWarehouse = (
|
||||
line: OrderFulfillLineFragment,
|
||||
warehouse: WarehouseFragment,
|
||||
): number => {
|
||||
if (!line?.variant?.stocks) {
|
||||
return 0;
|
||||
}
|
||||
const stock = getWarehouseStock(line.variant.stocks, warehouse.id);
|
||||
if (stock) {
|
||||
return getOrderLineAvailableQuantity(line, stock);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
export const getLineAllocationWithHighestQuantity = (
|
||||
line: OrderFulfillLineFragment,
|
||||
): OrderFulfillLineFragment["allocations"][number] | undefined =>
|
||||
line.allocations.reduce((prevAllocation, allocation) => {
|
||||
if (!prevAllocation || prevAllocation.quantity < allocation.quantity) {
|
||||
return allocation;
|
||||
}
|
||||
return prevAllocation;
|
||||
}, null);
|
||||
|
||||
export const getWarehouseWithHighestAvailableQuantity = (
|
||||
lines?: OrderLineFragment[],
|
||||
): WarehouseFragment | undefined => {
|
||||
let highestAvailableQuantity = 0;
|
||||
|
||||
return lines?.reduce(
|
||||
(selectedWarehouse, line) =>
|
||||
line.allocations.reduce((warehouse, allocation) => {
|
||||
if (allocation.quantity > highestAvailableQuantity) {
|
||||
highestAvailableQuantity = allocation.quantity;
|
||||
return allocation.warehouse;
|
||||
}
|
||||
return warehouse;
|
||||
}, selectedWarehouse),
|
||||
null as WarehouseFragment,
|
||||
);
|
||||
};
|
||||
|
||||
export const transformFuflillmentLinesToStockFormsetData = (
|
||||
lines: FulfillmentFragment["lines"],
|
||||
warehouseId: string,
|
||||
): OrderFulfillStockInputFormsetData =>
|
||||
warehouse: WarehouseFragment,
|
||||
): OrderFulfillStockFormsetData =>
|
||||
lines?.map(line => ({
|
||||
data: null,
|
||||
id: line.orderLine.id,
|
||||
value: [
|
||||
{
|
||||
quantity: line.quantity,
|
||||
warehouse: warehouseId,
|
||||
warehouse,
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
|
|
@ -9,17 +9,15 @@ import {
|
|||
OrderUpdateMutationVariables,
|
||||
useCustomerAddressesQuery,
|
||||
useWarehouseListQuery,
|
||||
WarehouseFragment,
|
||||
} from "@saleor/graphql";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import OrderCannotCancelOrderDialog from "@saleor/orders/components/OrderCannotCancelOrderDialog";
|
||||
import OrderChangeWarehouseDialog from "@saleor/orders/components/OrderChangeWarehouseDialog";
|
||||
import { OrderCustomerAddressesEditDialogOutput } from "@saleor/orders/components/OrderCustomerAddressesEditDialog/types";
|
||||
import OrderFulfillmentApproveDialog from "@saleor/orders/components/OrderFulfillmentApproveDialog";
|
||||
import OrderFulfillStockExceededDialog from "@saleor/orders/components/OrderFulfillStockExceededDialog";
|
||||
import OrderInvoiceEmailSendDialog from "@saleor/orders/components/OrderInvoiceEmailSendDialog";
|
||||
import { getById } from "@saleor/orders/components/OrderReturnPage/utils";
|
||||
import { transformFuflillmentLinesToStockInputFormsetData } from "@saleor/orders/utils/data";
|
||||
import { transformFuflillmentLinesToStockFormsetData } from "@saleor/orders/utils/data";
|
||||
import { PartialMutationProviderOutput } from "@saleor/types";
|
||||
import { mapEdgesToItems } from "@saleor/utils/maps";
|
||||
import React from "react";
|
||||
|
@ -48,7 +46,6 @@ import {
|
|||
OrderUrlQueryParams,
|
||||
} from "../../../urls";
|
||||
import { isAnyAddressEditModalOpen } from "../OrderDraftDetails";
|
||||
import { useDefaultWarehouse } from "./useDefaultWarehouse";
|
||||
|
||||
interface OrderNormalDetailsProps {
|
||||
id: string;
|
||||
|
@ -107,10 +104,7 @@ export const OrderNormalDetails: React.FC<OrderNormalDetailsProps> = ({
|
|||
const shop = data?.shop;
|
||||
const navigate = useNavigator();
|
||||
|
||||
const {
|
||||
data: warehousesData,
|
||||
loading: warehousesLoading,
|
||||
} = useWarehouseListQuery({
|
||||
const { data: warehousesData } = useWarehouseListQuery({
|
||||
displayLoader: true,
|
||||
variables: {
|
||||
first: 30,
|
||||
|
@ -119,15 +113,6 @@ export const OrderNormalDetails: React.FC<OrderNormalDetailsProps> = ({
|
|||
|
||||
const warehouses = mapEdgesToItems(warehousesData?.warehouses);
|
||||
|
||||
const [fulfillmentWarehouse, setFulfillmentWarehouse] = React.useState<
|
||||
WarehouseFragment
|
||||
>(null);
|
||||
|
||||
useDefaultWarehouse({ warehouses, order, setter: setFulfillmentWarehouse }, [
|
||||
warehousesData,
|
||||
warehousesLoading,
|
||||
]);
|
||||
|
||||
const {
|
||||
data: customerAddresses,
|
||||
loading: customerAddressesLoading,
|
||||
|
@ -206,11 +191,8 @@ export const OrderNormalDetails: React.FC<OrderNormalDetailsProps> = ({
|
|||
],
|
||||
)}
|
||||
shippingMethods={data?.order?.shippingMethods || []}
|
||||
selectedWarehouse={fulfillmentWarehouse}
|
||||
onOrderCancel={() => openModal("cancel")}
|
||||
onOrderFulfill={() =>
|
||||
navigate(orderFulfillUrl(id, { warehouse: fulfillmentWarehouse?.id }))
|
||||
}
|
||||
onOrderFulfill={() => navigate(orderFulfillUrl(id))}
|
||||
onFulfillmentApprove={fulfillmentId =>
|
||||
navigate(
|
||||
orderUrl(id, {
|
||||
|
@ -255,7 +237,6 @@ export const OrderNormalDetails: React.FC<OrderNormalDetailsProps> = ({
|
|||
})
|
||||
}
|
||||
onInvoiceSend={id => openModal("invoice-send", { id })}
|
||||
onWarehouseChange={() => openModal("change-warehouse")}
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
<OrderCannotCancelOrderDialog
|
||||
|
@ -336,12 +317,11 @@ export const OrderNormalDetails: React.FC<OrderNormalDetailsProps> = ({
|
|||
/>
|
||||
<OrderFulfillStockExceededDialog
|
||||
lines={currentApproval?.fulfillment.lines}
|
||||
formsetData={transformFuflillmentLinesToStockInputFormsetData(
|
||||
formsetData={transformFuflillmentLinesToStockFormsetData(
|
||||
currentApproval?.fulfillment.lines,
|
||||
currentApproval?.fulfillment.warehouse?.id,
|
||||
currentApproval?.fulfillment.warehouse,
|
||||
)}
|
||||
open={stockExceeded}
|
||||
warehouseId={currentApproval?.fulfillment.warehouse?.id}
|
||||
onClose={() => setStockExceeded(false)}
|
||||
confirmButtonState="default"
|
||||
onSubmit={() => {
|
||||
|
@ -391,13 +371,6 @@ export const OrderNormalDetails: React.FC<OrderNormalDetailsProps> = ({
|
|||
}
|
||||
onClose={closeModal}
|
||||
/>
|
||||
<OrderChangeWarehouseDialog
|
||||
open={params.action === "change-warehouse"}
|
||||
lines={order?.lines}
|
||||
currentWarehouse={fulfillmentWarehouse}
|
||||
onConfirm={warehouse => setFulfillmentWarehouse(warehouse)}
|
||||
onClose={closeModal}
|
||||
/>
|
||||
<OrderInvoiceEmailSendDialog
|
||||
confirmButtonState={orderInvoiceSend.opts.status}
|
||||
errors={orderInvoiceSend.opts.data?.invoiceSendEmail.errors || []}
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
import { OrderDetailsFragment, WarehouseFragment } from "@saleor/graphql";
|
||||
import {
|
||||
getToFulfillOrderLines,
|
||||
isLineAvailableInWarehouse,
|
||||
} from "@saleor/orders/utils/data";
|
||||
import React from "react";
|
||||
|
||||
export interface UseDefaultWarehouseOpts {
|
||||
warehouses: WarehouseFragment[];
|
||||
order: OrderDetailsFragment;
|
||||
setter: React.Dispatch<React.SetStateAction<WarehouseFragment>>;
|
||||
}
|
||||
|
||||
interface WarehousesAvailibility {
|
||||
warehouse: WarehouseFragment;
|
||||
linesAvailable: number;
|
||||
}
|
||||
|
||||
export function useDefaultWarehouse(
|
||||
{ warehouses, order, setter }: UseDefaultWarehouseOpts,
|
||||
deps: unknown[],
|
||||
) {
|
||||
React.useEffect(() => {
|
||||
const warehousesAvailability: WarehousesAvailibility[] = warehouses?.map(
|
||||
warehouse => {
|
||||
if (!order?.lines) {
|
||||
return undefined;
|
||||
}
|
||||
const linesToFulfill = getToFulfillOrderLines(order.lines);
|
||||
|
||||
const linesAvailable = linesToFulfill.filter(line =>
|
||||
isLineAvailableInWarehouse(line, warehouse),
|
||||
).length;
|
||||
|
||||
return {
|
||||
warehouse,
|
||||
linesAvailable,
|
||||
};
|
||||
},
|
||||
);
|
||||
const defaultWarehouse = order?.lines
|
||||
? warehousesAvailability?.reduce((prev, curr) =>
|
||||
curr.linesAvailable > prev.linesAvailable ? curr : prev,
|
||||
).warehouse
|
||||
: undefined;
|
||||
setter(defaultWarehouse);
|
||||
}, [order, ...deps]);
|
||||
}
|
|
@ -2,9 +2,7 @@ import { WindowTitle } from "@saleor/components/WindowTitle";
|
|||
import {
|
||||
useFulfillOrderMutation,
|
||||
useOrderFulfillDataQuery,
|
||||
useOrderFulfillmentUpdateTrackingMutation,
|
||||
useOrderFulfillSettingsQuery,
|
||||
useWarehouseDetailsQuery,
|
||||
} from "@saleor/graphql";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
|
@ -12,7 +10,13 @@ import { getMutationErrors } from "@saleor/misc";
|
|||
import OrderFulfillPage, {
|
||||
OrderFulfillSubmitData,
|
||||
} from "@saleor/orders/components/OrderFulfillPage";
|
||||
import { OrderFulfillUrlQueryParams, orderUrl } from "@saleor/orders/urls";
|
||||
import {
|
||||
orderFulfillUrl,
|
||||
OrderFulfillUrlDialog,
|
||||
OrderFulfillUrlQueryParams,
|
||||
orderUrl,
|
||||
} from "@saleor/orders/urls";
|
||||
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
|
@ -26,6 +30,11 @@ const OrderFulfill: React.FC<OrderFulfillProps> = ({ orderId, params }) => {
|
|||
const notify = useNotifier();
|
||||
const intl = useIntl();
|
||||
|
||||
const [openModal, closeModal] = createDialogActionHandlers<
|
||||
OrderFulfillUrlDialog,
|
||||
OrderFulfillUrlQueryParams
|
||||
>(navigate, params => orderFulfillUrl(orderId, params), params);
|
||||
|
||||
const {
|
||||
data: settings,
|
||||
loading: settingsLoading,
|
||||
|
@ -38,8 +47,6 @@ const OrderFulfill: React.FC<OrderFulfillProps> = ({ orderId, params }) => {
|
|||
},
|
||||
});
|
||||
|
||||
const [updateTracking] = useOrderFulfillmentUpdateTrackingMutation();
|
||||
|
||||
const [fulfillOrder, fulfillOrderOpts] = useFulfillOrderMutation({
|
||||
onCompleted: data => {
|
||||
if (data.orderFulfill.errors.length === 0) {
|
||||
|
@ -56,12 +63,6 @@ const OrderFulfill: React.FC<OrderFulfillProps> = ({ orderId, params }) => {
|
|||
},
|
||||
});
|
||||
|
||||
const { data: warehouseData } = useWarehouseDetailsQuery({
|
||||
variables: {
|
||||
id: params?.warehouse,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<WindowTitle
|
||||
|
@ -85,6 +86,7 @@ const OrderFulfill: React.FC<OrderFulfillProps> = ({ orderId, params }) => {
|
|||
}
|
||||
/>
|
||||
<OrderFulfillPage
|
||||
params={params}
|
||||
loading={loading || settingsLoading || fulfillOrderOpts.loading}
|
||||
errors={fulfillOrderOpts.data?.orderFulfill.errors}
|
||||
onSubmit={async (formData: OrderFulfillSubmitData) => {
|
||||
|
@ -105,27 +107,13 @@ const OrderFulfill: React.FC<OrderFulfillProps> = ({ orderId, params }) => {
|
|||
},
|
||||
});
|
||||
|
||||
const fulfillments = res?.data?.orderFulfill?.order?.fulfillments;
|
||||
if (fulfillments && formData.trackingNumber) {
|
||||
updateTracking({
|
||||
variables: {
|
||||
id: fulfillments[fulfillments.length - 1].id,
|
||||
input: {
|
||||
...(formData?.trackingNumber && {
|
||||
trackingNumber: formData.trackingNumber,
|
||||
}),
|
||||
notifyCustomer:
|
||||
settings?.shop?.fulfillmentAutoApprove && formData.sendInfo,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
return getMutationErrors(res);
|
||||
}}
|
||||
order={data?.order}
|
||||
saveButtonBar={fulfillOrderOpts.status}
|
||||
warehouse={warehouseData?.warehouse}
|
||||
shopSettings={settings?.shop}
|
||||
openModal={openModal}
|
||||
closeModal={closeModal}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -20,7 +20,6 @@ const order = orderFixture(placeholderImage);
|
|||
|
||||
const props: Omit<OrderDetailsPageProps, "classes"> = {
|
||||
disabled: false,
|
||||
selectedWarehouse: undefined,
|
||||
onBillingAddressEdit: undefined,
|
||||
onFulfillmentApprove: () => undefined,
|
||||
onFulfillmentCancel: () => undefined,
|
||||
|
@ -39,7 +38,6 @@ const props: Omit<OrderDetailsPageProps, "classes"> = {
|
|||
onProductClick: undefined,
|
||||
onProfileView: () => undefined,
|
||||
onShippingAddressEdit: undefined,
|
||||
onWarehouseChange: undefined,
|
||||
onSubmit: () => undefined,
|
||||
order,
|
||||
shop: shopFixture,
|
||||
|
|
Loading…
Reference in a new issue