Create fulfillment page
This commit is contained in:
parent
9812277e9a
commit
a5c1c9d544
2 changed files with 91 additions and 27 deletions
|
@ -1,20 +1,19 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import Card from "@material-ui/core/Card";
|
import Card from "@material-ui/core/Card";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import CardActions from "@material-ui/core/CardActions";
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
import TableBody from "@material-ui/core/TableBody";
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
import TableHead from "@material-ui/core/TableHead";
|
import TableHead from "@material-ui/core/TableHead";
|
||||||
import TableRow from "@material-ui/core/TableRow";
|
import TableRow from "@material-ui/core/TableRow";
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@material-ui/core/TextField";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
|
||||||
import useFormset, { FormsetData } from "@saleor/hooks/useFormset";
|
import useFormset, { FormsetData } from "@saleor/hooks/useFormset";
|
||||||
import { StockInput } from "@saleor/types/globalTypes";
|
import { StockInput } from "@saleor/types/globalTypes";
|
||||||
import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment";
|
import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment";
|
||||||
import TableCellAvatar, {
|
import TableCellAvatar from "@saleor/components/TableCellAvatar";
|
||||||
AVATAR_MARGIN
|
|
||||||
} from "@saleor/components/TableCellAvatar";
|
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
||||||
|
@ -24,18 +23,21 @@ import { OrderFulfillData_order } from "@saleor/orders/types/OrderFulfillData";
|
||||||
import CardTitle from "@saleor/components/CardTitle";
|
import CardTitle from "@saleor/components/CardTitle";
|
||||||
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||||
import makeStyles from "@material-ui/core/styles/makeStyles";
|
import makeStyles from "@material-ui/core/styles/makeStyles";
|
||||||
|
import { update } from "@saleor/utils/lists";
|
||||||
|
import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
|
actionBar: {
|
||||||
|
flexDirection: "row",
|
||||||
|
paddingLeft: theme.spacing(2) + 2
|
||||||
|
},
|
||||||
colName: {
|
colName: {
|
||||||
width: 300
|
width: 300
|
||||||
},
|
},
|
||||||
colNameLabel: {
|
|
||||||
marginLeft: AVATAR_MARGIN
|
|
||||||
},
|
|
||||||
colQuantity: {
|
colQuantity: {
|
||||||
textAlign: "right",
|
textAlign: "right",
|
||||||
width: 200
|
width: 210
|
||||||
},
|
},
|
||||||
colQuantityContent: {
|
colQuantityContent: {
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
|
@ -52,12 +54,17 @@ const useStyles = makeStyles(
|
||||||
error: {
|
error: {
|
||||||
color: theme.palette.error.main
|
color: theme.palette.error.main
|
||||||
},
|
},
|
||||||
|
full: {
|
||||||
|
fontWeight: 600
|
||||||
|
},
|
||||||
|
quantityInnerInput: {
|
||||||
|
padding: "16px 0 14px 12px"
|
||||||
|
},
|
||||||
quantityInput: {
|
quantityInput: {
|
||||||
width: "4rem"
|
width: 100
|
||||||
},
|
},
|
||||||
remainingQuantity: {
|
remainingQuantity: {
|
||||||
marginLeft: theme.spacing(),
|
marginLeft: theme.spacing()
|
||||||
paddingTop: 14
|
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
"&&": {
|
"&&": {
|
||||||
|
@ -98,7 +105,10 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = ({
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const classes = useStyles({});
|
const classes = useStyles({});
|
||||||
|
|
||||||
const { change, data: formsetData } = useFormset<null, StockInput[]>(
|
const { change: formsetChange, data: formsetData } = useFormset<
|
||||||
|
null,
|
||||||
|
StockInput[]
|
||||||
|
>(
|
||||||
order?.lines.map(line => ({
|
order?.lines.map(line => ({
|
||||||
data: null,
|
data: null,
|
||||||
id: line.id,
|
id: line.id,
|
||||||
|
@ -149,9 +159,7 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = ({
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell className={classes.colName}>
|
<TableCell className={classes.colName}>
|
||||||
<span className={classes.colNameLabel}>
|
|
||||||
<FormattedMessage defaultMessage="Product name" />
|
<FormattedMessage defaultMessage="Product name" />
|
||||||
</span>
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={classes.colSku}>
|
<TableCell className={classes.colSku}>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
@ -179,6 +187,14 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = ({
|
||||||
{order?.lines.map((line, lineIndex) => {
|
{order?.lines.map((line, lineIndex) => {
|
||||||
const remainingQuantity =
|
const remainingQuantity =
|
||||||
line.quantity - line.quantityFulfilled;
|
line.quantity - line.quantityFulfilled;
|
||||||
|
const quantityToFulfill = formsetData[
|
||||||
|
lineIndex
|
||||||
|
].value.reduce(
|
||||||
|
(quantityToFulfill, lineInput) =>
|
||||||
|
quantityToFulfill + lineInput.quantity,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
const overfulfill = remainingQuantity < quantityToFulfill;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow key={line.id}>
|
<TableRow key={line.id}>
|
||||||
|
@ -187,6 +203,15 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = ({
|
||||||
thumbnail={line?.thumbnail?.url}
|
thumbnail={line?.thumbnail?.url}
|
||||||
>
|
>
|
||||||
{line.productName}
|
{line.productName}
|
||||||
|
<Typography color="textSecondary" variant="caption">
|
||||||
|
{line.variant.attributes
|
||||||
|
.map(attribute =>
|
||||||
|
attribute.values
|
||||||
|
.map(attributeValue => attributeValue.name)
|
||||||
|
.join(", ")
|
||||||
|
)
|
||||||
|
.join(" / ")}
|
||||||
|
</Typography>
|
||||||
</TableCellAvatar>
|
</TableCellAvatar>
|
||||||
<TableCell className={classes.colSku}>
|
<TableCell className={classes.colSku}>
|
||||||
{line.variant.sku}
|
{line.variant.sku}
|
||||||
|
@ -195,6 +220,10 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = ({
|
||||||
const warehouseStock = line.variant.stocks.find(
|
const warehouseStock = line.variant.stocks.find(
|
||||||
stock => stock.warehouse.id === warehouse.id
|
stock => stock.warehouse.id === warehouse.id
|
||||||
);
|
);
|
||||||
|
const formsetStock = formsetData[
|
||||||
|
lineIndex
|
||||||
|
].value.find(line => line.warehouse === warehouse.id);
|
||||||
|
|
||||||
if (!warehouseStock) {
|
if (!warehouseStock) {
|
||||||
return (
|
return (
|
||||||
<TableCell
|
<TableCell
|
||||||
|
@ -217,19 +246,32 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = ({
|
||||||
<TextField
|
<TextField
|
||||||
type="number"
|
type="number"
|
||||||
inputProps={{
|
inputProps={{
|
||||||
|
className: classes.quantityInnerInput,
|
||||||
max: warehouseStock.quantity,
|
max: warehouseStock.quantity,
|
||||||
|
min: 0,
|
||||||
style: { textAlign: "right" }
|
style: { textAlign: "right" }
|
||||||
}}
|
}}
|
||||||
className={classes.quantityInput}
|
className={classes.quantityInput}
|
||||||
value={
|
value={formsetStock.quantity}
|
||||||
formsetData[lineIndex].value[0].quantity
|
onChange={event =>
|
||||||
|
formsetChange(
|
||||||
|
line.id,
|
||||||
|
update(
|
||||||
|
{
|
||||||
|
quantity: parseInt(
|
||||||
|
event.target.value,
|
||||||
|
10
|
||||||
|
),
|
||||||
|
warehouse: warehouse.id
|
||||||
|
},
|
||||||
|
formsetData[lineIndex].value,
|
||||||
|
(a, b) => a.warehouse === b.warehouse
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
onChange={event => undefined}
|
|
||||||
error={
|
error={
|
||||||
remainingQuantity <
|
overfulfill ||
|
||||||
formsetData[lineIndex].value[0]
|
formsetStock.quantity >
|
||||||
.quantity ||
|
|
||||||
formsetData[lineIndex].value[0].quantity >
|
|
||||||
warehouseStock.quantity
|
warehouseStock.quantity
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -241,10 +283,15 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = ({
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<TableCell className={classes.colQuantityTotal}>
|
<TableCell className={classes.colQuantityTotal}>
|
||||||
{formsetData[lineIndex].value.reduce(
|
<span
|
||||||
(acc, stock) => acc + stock.quantity,
|
className={classNames({
|
||||||
0
|
[classes.error]: overfulfill,
|
||||||
)}{" "}
|
[classes.full]:
|
||||||
|
remainingQuantity <= quantityToFulfill
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{quantityToFulfill}
|
||||||
|
</span>{" "}
|
||||||
/ {remainingQuantity}
|
/ {remainingQuantity}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
@ -252,9 +299,26 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = ({
|
||||||
})}
|
})}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</ResponsiveTable>
|
</ResponsiveTable>
|
||||||
|
<CardActions className={classes.actionBar}>
|
||||||
|
<ControlledCheckbox
|
||||||
|
checked={data.sendInfo}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Send shipment details to customer",
|
||||||
|
description: "checkbox"
|
||||||
|
})}
|
||||||
|
name="sendInfo"
|
||||||
|
onChange={change}
|
||||||
|
/>
|
||||||
|
</CardActions>
|
||||||
</Card>
|
</Card>
|
||||||
<SaveButtonBar
|
<SaveButtonBar
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
labels={{
|
||||||
|
save: intl.formatMessage({
|
||||||
|
defaultMessage: "Fulfill",
|
||||||
|
description: "fulfill order, button"
|
||||||
|
})
|
||||||
|
}}
|
||||||
state={saveButtonBar}
|
state={saveButtonBar}
|
||||||
onSave={submit}
|
onSave={submit}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
|
|
|
@ -54,7 +54,7 @@ const useStyles = makeStyles(
|
||||||
width: 120
|
width: 120
|
||||||
},
|
},
|
||||||
quantityInput: {
|
quantityInput: {
|
||||||
width: "4rem"
|
width: 100
|
||||||
},
|
},
|
||||||
remainingQuantity: {
|
remainingQuantity: {
|
||||||
marginLeft: theme.spacing(),
|
marginLeft: theme.spacing(),
|
||||||
|
|
Loading…
Reference in a new issue