Introduce fulfillment creation API (#1241)

* Display warehouse name for each fulfillment (#1259)

* Hide no-stocks columns in fulfillment view (#1260)

* Hide no-stocks columns in fulfillment view

* Update tests

* Refactor

* Update tests

* Add fulfillment settings card (#1242)

* Add fulfillment setting card

* Make fulfillment approvement naming consistent

* Fix mutation bug

* Update types

* Trigger CI

* Handle fulfillment acceptance on order details page (#1255)

* Handle fulfillment acceptance on order details page

* Make fulfillment approvement naming consistent

* Update fulfillment schema and its usage

* Render history events regarding waiting fulfillments (#1265)

* Add awaiting for approval fulfillment order event

* Fix warehouse name

* Change fulfillment quantity calculation (#1267)

* Change fulfillment quantity calculation

* Fix warehouse name

* Update messages

* Trigger CI

* Refactor

* Fix refactor

* Fix fulfillment for no variant

* Allow creating fulfillments waiting for acceptance (#1248)

* Fix fulfillment page style and typescript classname types perfomance issue

* Allow creating fulfillments waiting for acceptance

* Make fulfillment approvement naming consistent

* Update schema

* Add tooltip to fulfillment savebar

* Update unpaid fulfillment creation restriction

* Update fulfillment cration restriction

* Update test snapshots

* Add possibility to cancel "waiting" fulfillments (#1288)

* Allow to cancel waiting fulfillments

* Add delete button to fulfillment card

* Update test snapshots

* Handle waiting fulfillments on refund page (#1290)

* Handle waiting fulfillments on refund page

* Trigger CI

* Trigger CI

* Calculate quantity to refund on quantityToFulfill

* Update changelog

* Update snapshots

Co-authored-by: Jakub Majorek <majorek.jakub@gmail.com>
This commit is contained in:
Dawid Tarasiuk 2021-08-20 16:36:05 +02:00 committed by GitHub
parent ab4c897b2a
commit 08637b27fd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
87 changed files with 3193 additions and 1511 deletions

View file

@ -76,6 +76,8 @@ All notable, unreleased changes to this project will be documented in this file.
- Fixed navigation menu items reordering issue - #1239 by @kamilpastuszka
- Fixed issue with modals containing invalid, redundant scrolls #1240 by @kamilpastuszka
- Add text attribute for product and page translations - #1276 by @kamilpastuszka
- Add app dashboard extensions - #1292 by @jwm0
- Introduce fulfillment creation - #1241 by @orzechdev
# 2.11.1

View file

@ -536,6 +536,10 @@
"context": "button",
"string": "Accept"
},
"src_dot_approve": {
"context": "button",
"string": "Approve"
},
"src_dot_apps": {
"context": "apps section name",
"string": "Apps"
@ -1302,6 +1306,10 @@
"context": "order status",
"string": "Cancelled"
},
"src_dot_cannotFullfillUnpaidOrder": {
"context": "disabled option description",
"string": "Cant fulfill until payment is captured"
},
"src_dot_catalog": {
"string": "Catalog"
},
@ -3956,68 +3964,66 @@
"context": "button",
"string": "Finalize"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_1608534452": {
"context": "page header",
"string": "Order no. {orderNumber} - Add Fulfillment"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_2094985970": {
"context": "quantity of fulfilled products",
"string": "Quantity to fulfill"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_2095687440": {
"context": "fulfill order, button",
"string": "Fulfill"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_2588284040": {
"context": "no variant stock in warehouse",
"string": "No Stock"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_3244948255": {
"context": "header",
"string": "Items ready to ship"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_3620521256": {
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_headerOrder": {
"context": "page header",
"string": "Order"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_4046223826": {
"string": "Product name"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_4251997263": {
"context": "checkbox",
"string": "Send shipment details to customer"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_580490159": {
"context": "page header with order number",
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_headerOrderNumber": {
"context": "page header",
"string": "Order #{orderNumber}"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_693960049": {
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_headerOrderNumberAddFulfillment": {
"context": "page header",
"string": "Order no. {orderNumber} - Add Fulfillment"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_itemsReadyToShip": {
"context": "header",
"string": "Items ready to ship"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_noStock": {
"context": "no variant stock in warehouse",
"string": "No Stock"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_productName": {
"context": "name",
"string": "Product name"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_quantityToFulfill": {
"context": "quantity of fulfilled products",
"string": "Quantity to fulfill"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_sentShipmentDetails": {
"context": "checkbox label",
"string": "Send shipment details to customer"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_sku": {
"context": "product's sku",
"string": "SKU"
},
"src_dot_orders_dot_components_dot_OrderFulfilledProductsCard_dot_1119771899": {
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_submitFulfillment": {
"context": "fulfill order, button",
"string": "Fulfill"
},
"src_dot_orders_dot_components_dot_OrderFulfillPage_dot_submitPrepareFulfillment": {
"context": "prepare order fulfillment, button",
"string": "Prepare fulfillment"
},
"src_dot_orders_dot_components_dot_OrderFulfilledProductsCard_dot_addTracking": {
"context": "add tracking button",
"string": "Add tracking"
},
"src_dot_orders_dot_components_dot_OrderFulfilledProductsCard_dot_2211099657": {
"src_dot_orders_dot_components_dot_OrderFulfilledProductsCard_dot_editTracking": {
"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_refund": {
"context": "refund button",
"string": "Refund"
},
"src_dot_orders_dot_components_dot_OrderFulfilledProductsCard_dot_restocked": {
"context": "restocked group",
"string": "Restocked from: "
@ -4026,6 +4032,18 @@
"context": "tracking number",
"string": "Tracking Number: {trackingNumber}"
},
"src_dot_orders_dot_components_dot_OrderFulfillmentApproveDialog_dot_description": {
"context": "dialog description",
"string": "Are you sure you want to approve this fullfillment?"
},
"src_dot_orders_dot_components_dot_OrderFulfillmentApproveDialog_dot_notifyCustomer": {
"context": "checkbox label, fulfillment approval",
"string": "Send shipment details to customer"
},
"src_dot_orders_dot_components_dot_OrderFulfillmentApproveDialog_dot_title": {
"context": "dialog header",
"string": "Approve this fulfillment"
},
"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."
},
@ -4037,24 +4055,25 @@
"context": "dialog header",
"string": "Cancel Fulfillment"
},
"src_dot_orders_dot_components_dot_OrderFulfillmentDialog_dot_2796503714": {
"context": "quantity of fulfilled products",
"string": "Quantity"
"src_dot_orders_dot_components_dot_OrderFulfillmentSettings_dot_1154699654": {
"context": "checkbox label",
"string": "Allow fulfillment without payment"
},
"src_dot_orders_dot_components_dot_OrderFulfillmentDialog_dot_3123761129": {
"context": "dialog header",
"string": "Fulfill Products"
"src_dot_orders_dot_components_dot_OrderFulfillmentSettings_dot_2478368540": {
"context": "checkbox label description",
"string": "All fulfillments will be automatically approved"
},
"src_dot_orders_dot_components_dot_OrderFulfillmentDialog_dot_3252172269": {
"context": "fulfillment group",
"string": "Tracking number"
"src_dot_orders_dot_components_dot_OrderFulfillmentSettings_dot_3336812159": {
"context": "checkbox label",
"string": "Automatically approve all fulfillments"
},
"src_dot_orders_dot_components_dot_OrderFulfillmentDialog_dot_4046223826": {
"string": "Product name"
"src_dot_orders_dot_components_dot_OrderFulfillmentSettings_dot_3666602886": {
"context": "checkbox label description",
"string": "You will be able to fulfill products without capturing payment for the order."
},
"src_dot_orders_dot_components_dot_OrderFulfillmentDialog_dot_693960049": {
"context": "product's sku",
"string": "SKU"
"src_dot_orders_dot_components_dot_OrderFulfillmentSettings_dot_4200951094": {
"context": "section header",
"string": "Fulfillment settings"
},
"src_dot_orders_dot_components_dot_OrderFulfillmentTrackingDialog_dot_3252172269": {
"string": "Tracking number"
@ -4163,6 +4182,10 @@
"context": "order history message",
"string": "Products were added to an order"
},
"src_dot_orders_dot_components_dot_OrderHistory_dot_3854352507": {
"context": "order history message",
"string": "Fulfillment awaits approval"
},
"src_dot_orders_dot_components_dot_OrderHistory_dot_393045022": {
"context": "order history message",
"string": "Invoice no. {invoiceNumber} was updated"
@ -4441,10 +4464,6 @@
"context": "order line total price",
"string": "Total"
},
"src_dot_orders_dot_components_dot_OrderRefundFulfilledProducts_dot_1097582574": {
"context": "section header returned",
"string": "Fulfillment returned"
},
"src_dot_orders_dot_components_dot_OrderRefundFulfilledProducts_dot_1134347598": {
"context": "tabel column header",
"string": "Price"
@ -4464,10 +4483,6 @@
"context": "button",
"string": "Set maximal quantities"
},
"src_dot_orders_dot_components_dot_OrderRefundFulfilledProducts_dot_615325604": {
"context": "section header",
"string": "Fulfillment"
},
"src_dot_orders_dot_components_dot_OrderRefundFulfilledProducts_dot_878013594": {
"context": "tabel column header",
"string": "Total"
@ -4476,6 +4491,18 @@
"context": "error message",
"string": "Improper value"
},
"src_dot_orders_dot_components_dot_OrderRefundFulfilledProducts_dot_fulfillment": {
"context": "section header",
"string": "Fulfillment"
},
"src_dot_orders_dot_components_dot_OrderRefundFulfilledProducts_dot_fulfillmentReturned": {
"context": "section header returned",
"string": "Fulfillment returned"
},
"src_dot_orders_dot_components_dot_OrderRefundFulfilledProducts_dot_fulfillmentWaitingForApproval": {
"context": "section header returned",
"string": "Fulfillment waiting for approval"
},
"src_dot_orders_dot_components_dot_OrderRefundPage_dot_194531545": {
"context": "page header",
"string": "Order no. {orderNumber} - Refund"
@ -4651,6 +4678,10 @@
"context": "section header",
"string": "Fulfilled ({quantity})"
},
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_fulfilledFrom": {
"context": "fulfilled fulfillment, section header",
"string": "Fulfilled from {warehouseName}"
},
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_improperValue": {
"context": "error message",
"string": "Improper value"
@ -4687,6 +4718,10 @@
"context": "section header",
"string": "Unfulfilled"
},
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_OrderReturnRefundItemsCard_dot_waitingForApproval": {
"context": "unapproved fulfillment, section header",
"string": "Waiting for approval ({quantity})"
},
"src_dot_orders_dot_components_dot_OrderReturnPage_dot_appTitle": {
"context": "page header with order number",
"string": "Order #{orderNumber}"
@ -4758,6 +4793,9 @@
"src_dot_orders_dot_views_dot_OrderDetails_dot_3367579693": {
"string": "Order successfully updated"
},
"src_dot_orders_dot_views_dot_OrderDetails_dot_3897044696": {
"string": "Fulfillment successfully approved"
},
"src_dot_orders_dot_views_dot_OrderDetails_dot_4085755992": {
"string": "Invoice email sent"
},

View file

@ -2144,6 +2144,13 @@ type Fulfillment implements Node & ObjectWithMetadata {
warehouse: Warehouse
}
type FulfillmentApprove {
fulfillment: Fulfillment
order: Order
orderErrors: [OrderError!]! @deprecated(reason: "Use errors field instead. This field will be removed in Saleor 4.0.")
errors: [OrderError!]!
}
type FulfillmentCancel {
fulfillment: Fulfillment
order: Order
@ -2184,6 +2191,7 @@ enum FulfillmentStatus {
REPLACED
REFUNDED_AND_RETURNED
CANCELED
WAITING_FOR_APPROVAL
}
type FulfillmentUpdateTracking {
@ -3695,6 +3703,7 @@ type Mutation {
orderConfirm(id: ID!): OrderConfirm
orderFulfill(input: OrderFulfillInput!, order: ID): OrderFulfill
orderFulfillmentCancel(id: ID!, input: FulfillmentCancelInput!): FulfillmentCancel
orderFulfillmentApprove(id: ID!, notifyCustomer: Boolean!): FulfillmentApprove
orderFulfillmentUpdateTracking(id: ID!, input: FulfillmentUpdateTrackingInput!): FulfillmentUpdateTracking
orderFulfillmentRefundProducts(input: OrderRefundProductsInput!, order: ID!): FulfillmentRefundProducts
orderFulfillmentReturnProducts(input: OrderReturnProductsInput!, order: ID!): FulfillmentReturnProducts
@ -4038,6 +4047,7 @@ enum OrderErrorCode {
CANNOT_DELETE
CANNOT_DISCOUNT
CANNOT_REFUND
CANNOT_FULFILL_UNPAID_ORDER
CAPTURE_INACTIVE_PAYMENT
NOT_EDITABLE
FULFILL_ORDER_LINE
@ -4168,6 +4178,7 @@ enum OrderEventsEnum {
FULFILLMENT_REFUNDED
FULFILLMENT_RETURNED
FULFILLMENT_REPLACED
FULFILLMENT_AWAITS_APPROVAL
TRACKING_UPDATED
NOTE_ADDED
OTHER
@ -4226,6 +4237,7 @@ type OrderLine implements Node {
translatedProductName: String!
translatedVariantName: String!
allocations: [Allocation!]
quantityToFulfill: Int!
unitDiscountType: DiscountValueTypeEnum
}
@ -6146,6 +6158,8 @@ type Shop {
phonePrefixes: [String]!
headerText: String
includeTaxesInPrices: Boolean!
fulfillmentAutoApprove: Boolean!
fulfillmentAllowUnpaid: Boolean!
displayGrossPrices: Boolean!
chargeTaxesOnShipping: Boolean!
trackInventoryByDefault: Boolean
@ -6204,6 +6218,8 @@ input ShopSettingsInput {
trackInventoryByDefault: Boolean
defaultWeightUnit: WeightUnitsEnum
automaticFulfillmentDigitalProducts: Boolean
fulfillmentAutoApprove: Boolean
fulfillmentAllowUnpaid: Boolean
defaultDigitalMaxDownloads: Int
defaultDigitalUrlValidDays: Int
defaultMailSenderName: String

View file

@ -0,0 +1,23 @@
import { Tooltip } from "@material-ui/core";
import React from "react";
interface ButtonTooltipDecoratorProps {
tooltip?: string;
}
export const ButtonTooltipDecorator: React.FC<ButtonTooltipDecoratorProps> = ({
tooltip,
children
}) => {
if (tooltip) {
return (
<Tooltip title={tooltip} placement="top">
<span>{children}</span>
</Tooltip>
);
}
return <>{children}</>;
};
ButtonTooltipDecorator.displayName = "ButtonTooltipDecorator";
export default ButtonTooltipDecorator;

View file

@ -29,7 +29,8 @@ export const useStyles = makeStyles(
textContainer: {
marginLeft: theme.spacing(1),
display: "flex",
flexDirection: "column"
flexDirection: "column",
width: "100%"
},
dotVertical: {
marginTop: theme.spacing(1)

View file

@ -81,6 +81,7 @@ export const fragmentOrderLine = gql`
productSku
quantity
quantityFulfilled
quantityToFulfill
unitDiscount {
amount
currency
@ -200,6 +201,7 @@ export const fragmentOrderDetails = gql`
...OrderLineFragment
}
number
isPaid
paymentStatus
shippingAddress {
...AddressFragment
@ -280,3 +282,10 @@ export const fragmentOrderSettings = gql`
automaticallyConfirmAllNewOrders
}
`;
export const fragmentShopOrderSettings = gql`
fragment ShopOrderSettingsFragment on Shop {
fulfillmentAutoApprove
fulfillmentAllowUnpaid
}
`;

View file

@ -72,6 +72,7 @@ export interface FulfillmentFragment_lines_orderLine {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: FulfillmentFragment_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;

View file

@ -216,6 +216,7 @@ export interface OrderDetailsFragment_fulfillments_lines_orderLine {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDetailsFragment_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -311,6 +312,7 @@ export interface OrderDetailsFragment_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDetailsFragment_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -483,6 +485,7 @@ export interface OrderDetailsFragment {
fulfillments: (OrderDetailsFragment_fulfillments | null)[];
lines: (OrderDetailsFragment_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderDetailsFragment_shippingAddress | null;
shippingMethod: OrderDetailsFragment_shippingMethod | null;
@ -500,5 +503,4 @@ export interface OrderDetailsFragment {
availableShippingMethods: (OrderDetailsFragment_availableShippingMethods | null)[] | null;
invoices: (OrderDetailsFragment_invoices | null)[] | null;
channel: OrderDetailsFragment_channel;
isPaid: boolean;
}

View file

@ -72,6 +72,7 @@ export interface OrderLineFragment {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderLineFragment_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;

View file

@ -0,0 +1,14 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL fragment: ShopOrderSettingsFragment
// ====================================================
export interface ShopOrderSettingsFragment {
__typename: "Shop";
fulfillmentAutoApprove: boolean;
fulfillmentAllowUnpaid: boolean;
}

View file

@ -121,6 +121,10 @@ export const commonMessages = defineMessages({
time: {
defaultMessage: "Time",
description: "independent of any particular day, eg. 11:35"
},
cannotFullfillUnpaidOrder: {
defaultMessage: "Cant fulfill until payment is captured",
description: "disabled option description"
}
});
@ -139,6 +143,10 @@ export const buttonMessages = defineMessages({
defaultMessage: "Accept",
description: "button"
},
approve: {
defaultMessage: "Approve",
description: "button"
},
back: {
defaultMessage: "Back",
description: "button"

View file

@ -23,7 +23,10 @@ import { defineMessages, useIntl } from "react-intl";
import { maybe } from "../../../misc";
import { OrderStatus } from "../../../types/globalTypes";
import { OrderDetails_order } from "../../types/OrderDetails";
import {
OrderDetails_order,
OrderDetails_shop
} from "../../types/OrderDetails";
import OrderCustomer from "../OrderCustomer";
import OrderCustomerNote from "../OrderCustomerNote";
import OrderDraftDetails from "../OrderDraftDetails/OrderDraftDetails";
@ -54,6 +57,7 @@ const useStyles = makeStyles(
export interface OrderDetailsPageProps extends UserPermissionProps {
order: OrderDetails_order;
shop: OrderDetails_shop;
shippingMethods?: Array<{
id: string;
name: string;
@ -69,6 +73,7 @@ export interface OrderDetailsPageProps extends UserPermissionProps {
onShippingMethodEdit?: () => void;
onBack();
onBillingAddressEdit();
onFulfillmentApprove(id: string);
onFulfillmentCancel(id: string);
onFulfillmentTrackingNumberUpdate(id: string);
onOrderFulfill();
@ -107,10 +112,12 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
const {
disabled,
order,
shop,
saveButtonBarState,
userPermissions,
onBack,
onBillingAddressEdit,
onFulfillmentApprove,
onFulfillmentCancel,
onFulfillmentTrackingNumberUpdate,
onNoteAdd,
@ -146,8 +153,12 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
const canCancel = order?.status !== OrderStatus.CANCELED;
const canEditAddresses = order?.status !== OrderStatus.CANCELED;
const canFulfill = order?.status !== OrderStatus.CANCELED;
const notAllowedToFulfillUnpaid =
shop?.fulfillmentAutoApprove &&
!shop?.fulfillmentAllowUnpaid &&
!order?.isPaid;
const unfulfilled = (order?.lines || []).filter(
line => line.quantityFulfilled < line.quantity
line => line.quantityToFulfill > 0
);
const handleSubmit = async (data: MetadataFormData) => {
@ -229,7 +240,8 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
<div data-test-id="orderFulfillment">
{!isOrderUnconfirmed ? (
<OrderUnfulfilledProductsCard
canFulfill={canFulfill}
showFulfillmentAction={canFulfill}
notAllowedToFulfillUnpaid={notAllowedToFulfillUnpaid}
lines={unfulfilled}
onFulfill={onOrderFulfill}
/>
@ -249,7 +261,8 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
<React.Fragment key={fulfillment.id}>
<OrderFulfilledProductsCard
fulfillment={fulfillment}
orderNumber={order.number}
fulfillmentAllowUnpaid={shop?.fulfillmentAllowUnpaid}
order={order}
onOrderFulfillmentCancel={() =>
onFulfillmentCancel(fulfillment.id)
}
@ -257,6 +270,9 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
onFulfillmentTrackingNumberUpdate(fulfillment.id)
}
onRefund={onPaymentRefund}
onOrderFulfillmentApprove={() =>
onFulfillmentApprove(fulfillment.id)
}
/>
</React.Fragment>
))}

View file

@ -9,6 +9,7 @@ import {
Typography
} from "@material-ui/core";
import { CSSProperties } from "@material-ui/styles";
import { drawerWidthExpanded } from "@saleor/components/AppLayout/consts";
import CardTitle from "@saleor/components/CardTitle";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import Container from "@saleor/components/Container";
@ -19,8 +20,10 @@ import ResponsiveTable from "@saleor/components/ResponsiveTable";
import Savebar from "@saleor/components/Savebar";
import Skeleton from "@saleor/components/Skeleton";
import TableCellAvatar from "@saleor/components/TableCellAvatar";
import { ShopOrderSettingsFragment } from "@saleor/fragments/types/ShopOrderSettingsFragment";
import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment";
import useFormset, { FormsetData } from "@saleor/hooks/useFormset";
import { commonMessages } from "@saleor/intl";
import { Backlink } from "@saleor/macaw-ui";
import { makeStyles } from "@saleor/macaw-ui";
import { renderCollection } from "@saleor/misc";
@ -29,29 +32,17 @@ import {
OrderFulfillData_order,
OrderFulfillData_order_lines
} from "@saleor/orders/types/OrderFulfillData";
import {
OrderErrorCode,
OrderFulfillStockInput
} from "@saleor/types/globalTypes";
import { getToFulfillOrderLines } from "@saleor/orders/utils/data";
import { isStockError } from "@saleor/orders/utils/data";
import { OrderFulfillStockInput } from "@saleor/types/globalTypes";
import { update } from "@saleor/utils/lists";
import classNames from "classnames";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
type ClassKey =
| "actionBar"
| "table"
| "colName"
| "colQuantity"
| "colQuantityHeader"
| "colQuantityTotal"
| "colSku"
| "error"
| "full"
| "quantityInnerInput"
| "quantityInnerInputNoRemaining"
| "remainingQuantity";
const useStyles = makeStyles<OrderFulfillPageProps, ClassKey>(
import { messages } from "./messages";
const useStyles = makeStyles(
theme => {
const inputPadding: CSSProperties = {
paddingBottom: theme.spacing(2),
@ -59,14 +50,9 @@ const useStyles = makeStyles<OrderFulfillPageProps, ClassKey>(
};
return {
[theme.breakpoints.up("lg")]: {
colName: {
width: ({ warehouses }) => (warehouses?.length > 3 ? 250 : "auto")
}
},
[theme.breakpoints.only("md")]: {
colName: {
width: ({ warehouses }) => (warehouses?.length > 2 ? 250 : "auto")
container: {
[theme.breakpoints.up("md")]: {
width: `calc(100vw - ${drawerWidthExpanded}px)`
}
},
actionBar: {
@ -74,7 +60,15 @@ const useStyles = makeStyles<OrderFulfillPageProps, ClassKey>(
paddingLeft: `calc(${theme.spacing(2)} + 2px)`
},
colName: {
width: 250
width: 250,
[theme.breakpoints.up("lg")]: {
width: ({ warehouses }: OrderFulfillPageProps) =>
warehouses?.length > 3 ? 250 : "auto"
},
[theme.breakpoints.only("md")]: {
width: ({ warehouses }: OrderFulfillPageProps) =>
warehouses?.length > 2 ? 250 : "auto"
}
},
colQuantity: {
textAlign: "right",
@ -131,6 +125,7 @@ export interface OrderFulfillPageProps {
order: OrderFulfillData_order;
saveButtonBar: ConfirmButtonTransitionState;
warehouses: WarehouseFragment[];
shopSettings?: ShopOrderSettingsFragment;
onBack: () => void;
onSubmit: (data: OrderFulfillSubmitData) => void;
}
@ -139,10 +134,6 @@ const initialFormData: OrderFulfillFormData = {
sendInfo: true
};
function getRemainingQuantity(line: OrderFulfillData_order_lines): number {
return line.quantity - line.quantityFulfilled;
}
const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
const {
loading,
@ -150,6 +141,7 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
order,
saveButtonBar,
warehouses,
shopSettings,
onBack,
onSubmit
} = props;
@ -161,23 +153,21 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
null,
OrderFulfillStockInput[]
>(
order?.lines
.filter(line => getRemainingQuantity(line) > 0)
.map(line => ({
data: null,
id: line.id,
label: line.variant.attributes
.map(attribute =>
attribute.values
.map(attributeValue => attributeValue.name)
.join(" , ")
)
.join(" / "),
value: line.variant.stocks.map(stock => ({
quantity: 0,
warehouse: stock.warehouse.id
}))
getToFulfillOrderLines(order?.lines).map(line => ({
data: null,
id: line.id,
label: line.variant?.attributes
.map(attribute =>
attribute.values
.map(attributeValue => attributeValue.name)
.join(" , ")
)
.join(" / "),
value: line.variant?.stocks?.map(stock => ({
quantity: 0,
warehouse: stock.warehouse.id
}))
}))
);
const handleSubmit = (formData: OrderFulfillFormData) =>
@ -186,110 +176,71 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
items: formsetData
});
const notAllowedToFulfillUnpaid =
shopSettings?.fulfillmentAutoApprove &&
!shopSettings?.fulfillmentAllowUnpaid &&
!order?.isPaid;
const shouldEnableSave = () => {
if (!order || loading) {
return false;
}
const isAtLeastOneFulfilled = formsetData.some(({ value }) =>
value.some(({ quantity }) => quantity > 0)
if (notAllowedToFulfillUnpaid) {
return false;
}
const isAtLeastOneFulfilled = formsetData?.some(({ value }) =>
value?.some(({ quantity }) => quantity > 0)
);
const areProperlyFulfilled = formsetData.every(({ id, value }) => {
const areProperlyFulfilled = formsetData?.every(({ id, value }) => {
const { lines } = order;
const { quantity, quantityFulfilled } = lines.find(
const { quantityToFulfill } = lines.find(
({ id: lineId }) => lineId === id
);
const remainingQuantity = quantity - quantityFulfilled;
const formQuantityFulfilled = value.reduce(
const formQuantityFulfilled = value?.reduce(
(result, { quantity }) => result + quantity,
0
);
return formQuantityFulfilled <= remainingQuantity;
return formQuantityFulfilled <= quantityToFulfill;
});
return isAtLeastOneFulfilled && areProperlyFulfilled;
};
const isStockError = (
overfulfill: boolean,
formsetStock: { quantity: number },
availableQuantity: number,
warehouse: WarehouseFragment,
line: OrderFulfillData_order_lines,
errors: FulfillOrder_orderFulfill_errors[]
) => {
if (overfulfill) {
return true;
}
const isQuantityLargerThanAvailable =
line.variant.trackInventory && formsetStock.quantity > availableQuantity;
const isError = !!errors?.find(
err =>
err.warehouse === warehouse.id &&
err.orderLines.find((id: string) => id === line.id) &&
err.code === OrderErrorCode.INSUFFICIENT_STOCK
);
return isQuantityLargerThanAvailable || isError;
};
return (
<Container>
<Container className={classes.container}>
<Backlink onClick={onBack}>
{order?.number
? intl.formatMessage(
{
defaultMessage: "Order #{orderNumber}",
description: "page header with order number"
},
{
orderNumber: order.number
}
)
: intl.formatMessage({
defaultMessage: "Order",
description: "page header"
})}
? intl.formatMessage(messages.headerOrderNumber, {
orderNumber: order.number
})
: intl.formatMessage(messages.headerOrder)}
</Backlink>
<PageHeader
title={intl.formatMessage(
{
defaultMessage: "Order no. {orderNumber} - Add Fulfillment",
description: "page header"
},
{
orderNumber: order?.number
}
)}
title={intl.formatMessage(messages.headerOrderNumberAddFulfillment, {
orderNumber: order?.number
})}
/>
<Form initial={initialFormData} onSubmit={handleSubmit}>
{({ change, data, submit }) => (
<>
<Card>
<CardTitle
title={intl.formatMessage({
defaultMessage: "Items ready to ship",
description: "header"
})}
title={intl.formatMessage(messages.itemsReadyToShip)}
/>
<ResponsiveTable className={classes.table}>
<TableHead>
<TableRow>
<TableCell className={classes.colName}>
<FormattedMessage defaultMessage="Product name" />
<FormattedMessage {...messages.productName} />
</TableCell>
<TableCell className={classes.colSku}>
<FormattedMessage
defaultMessage="SKU"
description="product's sku"
/>
<FormattedMessage {...messages.sku} />
</TableCell>
{warehouses?.map(warehouse => (
<TableCell
@ -303,16 +254,13 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
</TableCell>
))}
<TableCell className={classes.colQuantityTotal}>
<FormattedMessage
defaultMessage="Quantity to fulfill"
description="quantity of fulfilled products"
/>
<FormattedMessage {...messages.quantityToFulfill} />
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{renderCollection(
order?.lines.filter(line => getRemainingQuantity(line) > 0),
getToFulfillOrderLines(order?.lines),
(line: OrderFulfillData_order_lines, lineIndex) => {
if (!line) {
return (
@ -339,10 +287,10 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
);
}
const remainingQuantity = getRemainingQuantity(line);
const remainingQuantity = line.quantityToFulfill;
const quantityToFulfill = formsetData[
lineIndex
].value.reduce(
].value?.reduce(
(quantityToFulfill, lineInput) =>
quantityToFulfill + (lineInput.quantity || 0),
0
@ -357,20 +305,20 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
>
{line.productName}
<Typography color="textSecondary" variant="caption">
{line.variant.attributes
.map(attribute =>
{line.variant?.attributes
?.map(attribute =>
attribute.values
.map(attributeValue => attributeValue.name)
.join(", ")
)
.join(" / ")}
?.join(" / ")}
</Typography>
</TableCellAvatar>
<TableCell className={classes.colSku}>
{line.variant.sku}
{line.variant?.sku}
</TableCell>
{warehouses?.map(warehouse => {
const warehouseStock = line.variant.stocks.find(
const warehouseStock = line.variant?.stocks?.find(
stock => stock.warehouse.id === warehouse.id
);
const formsetStock = formsetData[
@ -388,10 +336,7 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
classes.error
)}
>
<FormattedMessage
defaultMessage="No Stock"
description="no variant stock in warehouse"
/>
<FormattedMessage {...messages.noStock} />
</TableCell>
);
}
@ -491,27 +436,30 @@ const OrderFulfillPage: React.FC<OrderFulfillPageProps> = props => {
)}
</TableBody>
</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>
{shopSettings?.fulfillmentAutoApprove && (
<CardActions className={classes.actionBar}>
<ControlledCheckbox
checked={data.sendInfo}
label={intl.formatMessage(messages.sentShipmentDetails)}
name="sendInfo"
onChange={change}
/>
</CardActions>
)}
</Card>
<Savebar
disabled={!shouldEnableSave()}
labels={{
confirm: intl.formatMessage({
defaultMessage: "Fulfill",
description: "fulfill order, button"
})
confirm: shopSettings?.fulfillmentAutoApprove
? intl.formatMessage(messages.submitFulfillment)
: intl.formatMessage(messages.submitPrepareFulfillment)
}}
state={saveButtonBar}
tooltips={{
confirm:
notAllowedToFulfillUnpaid &&
intl.formatMessage(commonMessages.cannotFullfillUnpaidOrder)
}}
onSubmit={submit}
onCancel={onBack}
/>

View file

@ -7,6 +7,7 @@ import { warehouseList } from "@saleor/warehouses/fixtures";
export const orderToFulfill: OrderFulfillData_order = {
__typename: "Order",
id: "T3JkZXI6Mg==",
isPaid: true,
lines: [
{
__typename: "OrderLine",
@ -16,6 +17,7 @@ export const orderToFulfill: OrderFulfillData_order = {
productName: "T-Shirt",
quantity: 3,
quantityFulfilled: 1,
quantityToFulfill: 2,
variant: {
__typename: "ProductVariant",
id: "UHJvZHVjdFZhcmlhbnQ6Mjk2",
@ -78,6 +80,7 @@ export const orderToFulfill: OrderFulfillData_order = {
productName: "Lemon Juice",
quantity: 4,
quantityFulfilled: 0,
quantityToFulfill: 4,
variant: {
__typename: "ProductVariant",
id: "UHJvZHVjdFZhcmlhbnQ6MTgx",
@ -133,6 +136,7 @@ export const orderToFulfill: OrderFulfillData_order = {
productName: "Orange Juice",
quantity: 3,
quantityFulfilled: 2,
quantityToFulfill: 1,
variant: {
__typename: "ProductVariant",
id: "UHJvZHVjdFZhcmlhbnQ6MTgy",

View file

@ -0,0 +1,48 @@
import { defineMessages } from "react-intl";
export const messages = defineMessages({
headerOrder: {
defaultMessage: "Order",
description: "page header"
},
headerOrderNumber: {
defaultMessage: "Order #{orderNumber}",
description: "page header"
},
headerOrderNumberAddFulfillment: {
defaultMessage: "Order no. {orderNumber} - Add Fulfillment",
description: "page header"
},
submitFulfillment: {
defaultMessage: "Fulfill",
description: "fulfill order, button"
},
submitPrepareFulfillment: {
defaultMessage: "Prepare fulfillment",
description: "prepare order fulfillment, button"
},
itemsReadyToShip: {
defaultMessage: "Items ready to ship",
description: "header"
},
productName: {
defaultMessage: "Product name",
description: "name"
},
sku: {
defaultMessage: "SKU",
description: "product's sku"
},
quantityToFulfill: {
defaultMessage: "Quantity to fulfill",
description: "quantity of fulfilled products"
},
noStock: {
defaultMessage: "No Stock",
description: "no variant stock in warehouse"
},
sentShipmentDetails: {
defaultMessage: "Send shipment details to customer",
description: "checkbox label"
}
});

View file

@ -1,25 +1,35 @@
import { Button, CardActions } from "@material-ui/core";
import { Button, CardActions, Typography } from "@material-ui/core";
import { buttonMessages, commonMessages } from "@saleor/intl";
import { FulfillmentStatus } from "@saleor/types/globalTypes";
import React from "react";
import { FormattedMessage } from "react-intl";
import { actionButtonsMessages } from "./messages";
interface AcionButtonsProps {
status: FulfillmentStatus;
trackingNumber?: string;
orderIsPaid?: boolean;
fulfillmentAllowUnpaid: boolean;
onTrackingCodeAdd();
onRefund();
onApprove();
}
const statusesToShow = [
FulfillmentStatus.FULFILLED,
FulfillmentStatus.RETURNED
FulfillmentStatus.RETURNED,
FulfillmentStatus.WAITING_FOR_APPROVAL
];
const ActionButtons: React.FC<AcionButtonsProps> = ({
status,
onTrackingCodeAdd,
trackingNumber,
onRefund
orderIsPaid,
fulfillmentAllowUnpaid,
onTrackingCodeAdd,
onRefund,
onApprove
}) => {
const hasTrackingNumber = !!trackingNumber;
@ -27,14 +37,28 @@ const ActionButtons: React.FC<AcionButtonsProps> = ({
return null;
}
if (status === FulfillmentStatus.WAITING_FOR_APPROVAL) {
const cannotFulfill = !orderIsPaid && !fulfillmentAllowUnpaid;
return (
<CardActions>
<Button color="primary" onClick={onApprove} disabled={cannotFulfill}>
<FormattedMessage {...buttonMessages.approve} />
</Button>
{cannotFulfill && (
<Typography color="error" variant="caption">
<FormattedMessage {...commonMessages.cannotFullfillUnpaidOrder} />
</Typography>
)}
</CardActions>
);
}
if (status === FulfillmentStatus.RETURNED) {
return (
<CardActions>
<Button color="primary" onClick={onRefund}>
<FormattedMessage
defaultMessage="Refund"
description="refund button"
/>
<FormattedMessage {...actionButtonsMessages.refund} />
</Button>
</CardActions>
);
@ -43,19 +67,13 @@ const ActionButtons: React.FC<AcionButtonsProps> = ({
return hasTrackingNumber ? (
<CardActions>
<Button color="primary" onClick={onTrackingCodeAdd}>
<FormattedMessage
defaultMessage="Edit tracking"
description="edit tracking button"
/>
<FormattedMessage {...actionButtonsMessages.editTracking} />
</Button>
</CardActions>
) : (
<CardActions>
<Button color="primary" onClick={onTrackingCodeAdd}>
<FormattedMessage
defaultMessage="Add tracking"
description="add tracking button"
/>
<FormattedMessage {...actionButtonsMessages.addTracking} />
</Button>
</CardActions>
);

View file

@ -4,10 +4,11 @@ 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 { useIntl } from "react-intl";
import { FormattedMessage } from "react-intl";
import { OrderDetails_order_fulfillments } from "../../types/OrderDetails";
import { extraInfoMessages } from "./messages";
const useStyles = makeStyles(
theme => ({
@ -24,21 +25,6 @@ const useStyles = makeStyles(
{ 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 {
@ -63,8 +49,8 @@ const ExtraInfoLines: React.FC<ExtraInfoLinesProps> = ({ fulfillment }) => {
<>
{intl.formatMessage(
status === FulfillmentStatus.RETURNED
? messages.restocked
: messages.fulfilled
? extraInfoMessages.restocked
: extraInfoMessages.fulfilled
)}
<Typography
className={classNames(classes.infoLabel, {
@ -81,7 +67,7 @@ const ExtraInfoLines: React.FC<ExtraInfoLinesProps> = ({ fulfillment }) => {
<Typography color="textSecondary" variant="body2">
{trackingNumber && (
<FormattedMessage
defaultMessage="Tracking Number: {trackingNumber}"
{...extraInfoMessages.tracking}
values={{
trackingNumber: (
<Typography

View file

@ -1,13 +1,13 @@
import { Card, TableBody } from "@material-ui/core";
import CardMenu from "@saleor/components/CardMenu";
import { Card, IconButton, TableBody } from "@material-ui/core";
import CardSpacer from "@saleor/components/CardSpacer";
import ResponsiveTable from "@saleor/components/ResponsiveTable";
import { OrderDetailsFragment } from "@saleor/fragments/types/OrderDetailsFragment";
import TrashIcon from "@saleor/icons/Trash";
import { makeStyles } from "@saleor/macaw-ui";
import { mergeRepeatedOrderLines } from "@saleor/orders/utils/data";
import React from "react";
import { useIntl } from "react-intl";
import { maybe, renderCollection } from "../../../misc";
import { renderCollection } from "../../../misc";
import { FulfillmentStatus } from "../../../types/globalTypes";
import { OrderDetails_order_fulfillments } from "../../types/OrderDetails";
import TableHeader from "../OrderProductsCardElements/OrderProductsCardHeader";
@ -17,9 +17,15 @@ import ActionButtons from "./ActionButtons";
import ExtraInfoLines from "./ExtraInfoLines";
const useStyles = makeStyles(
() => ({
theme => ({
table: {
tableLayout: "fixed"
},
deleteIcon: {
height: 40,
paddingRight: 0,
paddingLeft: theme.spacing(1),
width: 40
}
}),
{ name: "OrderFulfillment" }
@ -27,36 +33,42 @@ const useStyles = makeStyles(
interface OrderFulfilledProductsCardProps {
fulfillment: OrderDetails_order_fulfillments;
orderNumber?: string;
fulfillmentAllowUnpaid: boolean;
order?: OrderDetailsFragment;
onOrderFulfillmentApprove: () => void;
onOrderFulfillmentCancel: () => void;
onTrackingCodeAdd: () => void;
onRefund: () => void;
}
const statusesToMergeLines = [
FulfillmentStatus.REFUNDED,
FulfillmentStatus.REFUNDED_AND_RETURNED,
FulfillmentStatus.RETURNED,
FulfillmentStatus.REPLACED
];
const cancelableStatuses = [
FulfillmentStatus.FULFILLED,
FulfillmentStatus.WAITING_FOR_APPROVAL
];
const OrderFulfilledProductsCard: React.FC<OrderFulfilledProductsCardProps> = props => {
const {
fulfillment,
orderNumber,
fulfillmentAllowUnpaid,
order,
onOrderFulfillmentApprove,
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);
}
@ -72,21 +84,17 @@ const OrderFulfilledProductsCard: React.FC<OrderFulfilledProductsCardProps> = pr
lines={fulfillment?.lines}
fulfillmentOrder={fulfillment?.fulfillmentOrder}
status={fulfillment?.status}
orderNumber={orderNumber}
warehouseName={fulfillment?.warehouse?.name}
orderNumber={order?.number}
toolbar={
maybe(() => fulfillment.status) === FulfillmentStatus.FULFILLED && (
<CardMenu
menuItems={[
{
label: intl.formatMessage({
defaultMessage: "Cancel Fulfillment",
description: "button"
}),
onSelect: onOrderFulfillmentCancel,
testId: "cancelFulfillmentButton"
}
]}
/>
cancelableStatuses.includes(fulfillment?.status) && (
<IconButton
className={classes.deleteIcon}
onClick={onOrderFulfillmentCancel}
data-test-id="cancelFulfillmentButton"
>
<TrashIcon />
</IconButton>
)
}
/>
@ -102,8 +110,11 @@ const OrderFulfilledProductsCard: React.FC<OrderFulfilledProductsCardProps> = pr
<ActionButtons
status={fulfillment?.status}
trackingNumber={fulfillment?.trackingNumber}
orderIsPaid={order?.isPaid}
fulfillmentAllowUnpaid={fulfillmentAllowUnpaid}
onTrackingCodeAdd={onTrackingCodeAdd}
onRefund={onRefund}
onApprove={onOrderFulfillmentApprove}
/>
</Card>
<CardSpacer />

View file

@ -0,0 +1,31 @@
import { defineMessages } from "react-intl";
export const actionButtonsMessages = defineMessages({
refund: {
defaultMessage: "Refund",
description: "refund button"
},
editTracking: {
defaultMessage: "Edit tracking",
description: "edit tracking button"
},
addTracking: {
defaultMessage: "Add tracking",
description: "add tracking button"
}
});
export const extraInfoMessages = defineMessages({
fulfilled: {
defaultMessage: "Fulfilled from: ",
description: "fulfillment group"
},
restocked: {
defaultMessage: "Restocked from: ",
description: "restocked group"
},
tracking: {
defaultMessage: "Tracking Number: {trackingNumber}",
description: "tracking number"
}
});

View file

@ -0,0 +1,92 @@
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle
} from "@material-ui/core";
import ConfirmButton, {
ConfirmButtonTransitionState
} from "@saleor/components/ConfirmButton";
import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
import Form from "@saleor/components/Form";
import FormSpacer from "@saleor/components/FormSpacer";
import { OrderErrorFragment } from "@saleor/fragments/types/OrderErrorFragment";
import { buttonMessages } from "@saleor/intl";
import getOrderErrorMessage from "@saleor/utils/errors/order";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { messages } from "./messages";
export interface OrderFulfillmentAcceptDialogFormData {
notifyCustomer: boolean;
}
export interface OrderFulfillmentAcceptDialogProps {
confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[];
open: boolean;
onClose();
onConfirm(data: OrderFulfillmentAcceptDialogFormData);
}
const OrderFulfillmentAcceptDialog: React.FC<OrderFulfillmentAcceptDialogProps> = props => {
const { confirmButtonState, errors, open, onConfirm, onClose } = props;
const intl = useIntl();
return (
<Dialog onClose={onClose} open={open} fullWidth maxWidth="sm">
<Form initial={{ notifyCustomer: true }} onSubmit={onConfirm}>
{({ change, data, submit }) => (
<>
<DialogTitle>
<FormattedMessage {...messages.title} />
</DialogTitle>
<DialogContent>
<DialogContentText>
<FormattedMessage {...messages.description} />
</DialogContentText>
<ControlledCheckbox
data-test="notify-customer"
name={
"notifyCustomer" as keyof OrderFulfillmentAcceptDialogFormData
}
label={intl.formatMessage(messages.notifyCustomer)}
checked={data.notifyCustomer}
onChange={change}
/>
{errors.length > 0 && (
<>
<FormSpacer />
{errors.map((err, index) => (
<DialogContentText color="error" key={index}>
{getOrderErrorMessage(err, intl)}
</DialogContentText>
))}
</>
)}
</DialogContent>
<DialogActions>
<Button onClick={onClose}>
<FormattedMessage {...buttonMessages.cancel} />
</Button>
<ConfirmButton
data-test="submit"
transitionState={confirmButtonState}
variant="contained"
onClick={submit}
>
<FormattedMessage {...buttonMessages.approve} />
</ConfirmButton>
</DialogActions>
</>
)}
</Form>
</Dialog>
);
};
OrderFulfillmentAcceptDialog.displayName = "OrderFulfillmentAcceptDialog";
export default OrderFulfillmentAcceptDialog;

View file

@ -0,0 +1,2 @@
export { default } from "./OrderFulfillmentApproveDialog";
export * from "./OrderFulfillmentApproveDialog";

View file

@ -0,0 +1,16 @@
import { defineMessages } from "react-intl";
export const messages = defineMessages({
title: {
defaultMessage: "Approve this fulfillment",
description: "dialog header"
},
description: {
defaultMessage: "Are you sure you want to approve this fullfillment?",
description: "dialog description"
},
notifyCustomer: {
defaultMessage: "Send shipment details to customer",
description: "checkbox label, fulfillment approval"
}
});

View file

@ -1,247 +0,0 @@
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
TableBody,
TableCell,
TableHead,
TableRow,
TextField
} from "@material-ui/core";
import ConfirmButton, {
ConfirmButtonTransitionState
} from "@saleor/components/ConfirmButton";
import Form from "@saleor/components/Form";
import { FormSpacer } from "@saleor/components/FormSpacer";
import ResponsiveTable from "@saleor/components/ResponsiveTable";
import TableCellAvatar from "@saleor/components/TableCellAvatar";
import { AVATAR_MARGIN } from "@saleor/components/TableCellAvatar/Avatar";
import { OrderErrorFragment } from "@saleor/fragments/types/OrderErrorFragment";
import { buttonMessages } from "@saleor/intl";
import { makeStyles } from "@saleor/macaw-ui";
import { getFormErrors } from "@saleor/utils/errors";
import getOrderErrorMessage from "@saleor/utils/errors/order";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { maybe } from "../../../misc";
import { OrderDetails_order_lines } from "../../types/OrderDetails";
export interface FormData {
lines: number[];
trackingNumber: string;
}
const useStyles = makeStyles(
theme => ({
colName: {
width: "auto"
},
colNameLabel: {
marginLeft: AVATAR_MARGIN
},
colQuantity: {
textAlign: "right",
width: 150
},
colQuantityContent: {
alignItems: "center",
display: "inline-flex"
},
colSku: {
width: 120
},
quantityInput: {
width: 100
},
remainingQuantity: {
marginLeft: theme.spacing(),
paddingTop: 14
},
table: {
tableLayout: "fixed"
}
}),
{ name: "OrderFulfillmentDialog" }
);
export interface OrderFulfillmentDialogProps {
confirmButtonState: ConfirmButtonTransitionState;
errors: OrderErrorFragment[];
open: boolean;
lines: OrderDetails_order_lines[];
onClose();
onSubmit(data: FormData);
}
const OrderFulfillmentDialog: React.FC<OrderFulfillmentDialogProps> = props => {
const { confirmButtonState, errors, open, lines, onClose, onSubmit } = props;
const classes = useStyles(props);
const intl = useIntl();
const formFields = ["trackingNumber"];
const formErrors = getFormErrors(formFields, errors);
return (
<Dialog onClose={onClose} open={open}>
<Form
initial={{
lines: maybe(
() =>
lines.map(
product => product.quantity - product.quantityFulfilled
),
[]
),
trackingNumber: ""
}}
onSubmit={onSubmit}
>
{({ data, change }) => {
const handleQuantityChange = (
productIndex: number,
event: React.ChangeEvent<any>
) => {
const newData = data.lines;
newData[productIndex] = event.target.value;
change({
target: {
name: "lines",
value: newData
}
} as any);
};
return (
<>
<DialogTitle>
<FormattedMessage
defaultMessage="Fulfill Products"
description="dialog header"
/>
</DialogTitle>
<ResponsiveTable className={classes.table}>
<TableHead>
<TableRow>
<TableCell className={classes.colName}>
<span className={classes.colNameLabel}>
<FormattedMessage defaultMessage="Product name" />
</span>
</TableCell>
<TableCell className={classes.colSku}>
<FormattedMessage
defaultMessage="SKU"
description="product's sku"
/>
</TableCell>
<TableCell className={classes.colQuantity}>
<FormattedMessage
defaultMessage="Quantity"
description="quantity of fulfilled products"
/>
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{lines.map((product, productIndex) => {
const remainingQuantity =
product.quantity - product.quantityFulfilled;
return (
<TableRow key={product.id}>
<TableCellAvatar
className={classes.colName}
thumbnail={maybe(() => product.thumbnail.url)}
>
{product.productName}
</TableCellAvatar>
<TableCell className={classes.colSku}>
{product.productSku}
</TableCell>
<TableCell className={classes.colQuantity}>
<div className={classes.colQuantityContent}>
<TextField
type="number"
inputProps={{
max: remainingQuantity.toString(),
style: { textAlign: "right" }
}}
className={classes.quantityInput}
value={data.lines[productIndex]}
onChange={event =>
handleQuantityChange(productIndex, event)
}
error={
!!formErrors.trackingNumber ||
remainingQuantity < data.lines[productIndex]
}
helperText={getOrderErrorMessage(
formErrors.trackingNumber,
intl
)}
/>
<div className={classes.remainingQuantity}>
/ {remainingQuantity}
</div>
</div>
</TableCell>
</TableRow>
);
})}
</TableBody>
</ResponsiveTable>
<DialogContent>
<FormSpacer />
<TextField
error={!!formErrors.trackingNumber}
fullWidth
helperText={getOrderErrorMessage(
formErrors.trackingNumber,
intl
)}
label={intl.formatMessage({
defaultMessage: "Tracking number",
description: "fulfillment group"
})}
name="trackingNumber"
value={data.trackingNumber}
onChange={change}
/>
{errors.length > 0 && (
<>
<FormSpacer />
{errors
.filter(err => !formFields.includes(err.field))
.map((err, index) => (
<DialogContentText color="error" key={index}>
{getOrderErrorMessage(err, intl)}
</DialogContentText>
))}
</>
)}
</DialogContent>
<DialogActions>
<Button onClick={onClose}>
<FormattedMessage {...buttonMessages.back} />
</Button>
<ConfirmButton
transitionState={confirmButtonState}
color="primary"
variant="contained"
type="submit"
>
<FormattedMessage {...buttonMessages.confirm} />
</ConfirmButton>
</DialogActions>
</>
);
}}
</Form>
</Dialog>
);
};
OrderFulfillmentDialog.displayName = "OrderFulfillmentDialog";
export default OrderFulfillmentDialog;

View file

@ -1,2 +0,0 @@
export { default } from "./OrderFulfillmentDialog";
export * from "./OrderFulfillmentDialog";

View file

@ -0,0 +1,80 @@
import { Card, CardContent, Typography } from "@material-ui/core";
import CardTitle from "@saleor/components/CardTitle";
import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
import FormSpacer from "@saleor/components/FormSpacer";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { OrderSettingsFormData } from "../OrderSettingsPage/form";
export interface OrderFulfillmentSettingsProps {
data: OrderSettingsFormData;
disabled: boolean;
onChange: (event: React.ChangeEvent<any>) => void;
}
const OrderFulfillmentSettings: React.FC<OrderFulfillmentSettingsProps> = ({
data,
disabled,
onChange
}) => {
const intl = useIntl();
return (
<Card data-test="OrderFulfillmentSettings">
<CardTitle
title={intl.formatMessage({
defaultMessage: "Fulfillment settings",
description: "section header"
})}
/>
<CardContent>
<ControlledCheckbox
name={"fulfillmentAutoApprove" as keyof OrderSettingsFormData}
label={
<>
<FormattedMessage
defaultMessage="Automatically approve all fulfillments"
description="checkbox label"
/>
<Typography variant="caption">
<FormattedMessage
defaultMessage="All fulfillments will be automatically approved"
description="checkbox label description"
/>
</Typography>
</>
}
checked={data.fulfillmentAutoApprove}
onChange={onChange}
disabled={disabled}
data-test="fulfillmentAutoApproveCheckbox"
/>
<FormSpacer />
<ControlledCheckbox
name={"fulfillmentAllowUnpaid" as keyof OrderSettingsFormData}
label={
<>
<FormattedMessage
defaultMessage="Allow fulfillment without payment"
description="checkbox label"
/>
<Typography variant="caption">
<FormattedMessage
defaultMessage="You will be able to fulfill products without capturing payment for the order."
description="checkbox label description"
/>
</Typography>
</>
}
checked={data.fulfillmentAllowUnpaid}
onChange={onChange}
disabled={disabled}
data-test="fulfillmentAllowUnpaidCheckbox"
/>
</CardContent>
</Card>
);
};
OrderFulfillmentSettings.displayName = "OrderFulfillmentSettings";
export default OrderFulfillmentSettings;

View file

@ -0,0 +1,2 @@
export { default } from "./OrderFulfillmentSettings";
export * from "./OrderFulfillmentSettings";

View file

@ -142,6 +142,11 @@ export const getEventMessage = (
sentBy: event.user ? event.user.email : null
}
);
case OrderEventsEnum.FULFILLMENT_AWAITS_APPROVAL:
return intl.formatMessage({
defaultMessage: "Fulfillment awaits approval",
description: "order history message"
});
case OrderEventsEnum.FULFILLMENT_FULFILLED_ITEMS:
return intl.formatMessage(
{

View file

@ -72,7 +72,7 @@ const TableLine: React.FC<TableLineProps> = ({
isOrderLine = false
}) => {
const classes = useStyles({});
const { quantity, quantityFulfilled } = lineData as OrderDetails_order_lines;
const { quantity, quantityToFulfill } = lineData as OrderDetails_order_lines;
if (!lineData) {
return <Skeleton />;
@ -85,9 +85,7 @@ const TableLine: React.FC<TableLineProps> = ({
} as OrderDetails_order_fulfillments_lines)
: (lineData as OrderDetails_order_fulfillments_lines);
const quantityToDisplay = isOrderLine
? quantity - quantityFulfilled
: quantity;
const quantityToDisplay = isOrderLine ? quantityToFulfill : quantity;
return (
<TableRow className={classes.clickableRow} hover key={line.id}>

View file

@ -18,11 +18,11 @@ import { FormsetChange } from "@saleor/hooks/useFormset";
import { makeStyles } from "@saleor/macaw-ui";
import { renderCollection } from "@saleor/misc";
import { OrderRefundData_order_fulfillments } from "@saleor/orders/types/OrderRefundData";
import { FulfillmentStatus } from "@saleor/types/globalTypes";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { OrderRefundFormData } from "../OrderRefundPage/form";
import { getTitle } from "./messages";
const useStyles = makeStyles(
theme => {
@ -93,15 +93,7 @@ const OrderRefundFulfilledProducts: React.FC<OrderRefundFulfilledProductsProps>
<CardTitle
title={
<>
{fulfillment.status === FulfillmentStatus.RETURNED
? intl.formatMessage({
defaultMessage: "Fulfillment returned",
description: "section header returned"
})
: intl.formatMessage({
defaultMessage: "Fulfillment",
description: "section header"
})}
{getTitle(fulfillment.status, intl)}
{fulfillment && (
<Typography className={classes.orderNumber} variant="body1">
{`#${orderNumber}-${fulfillment?.fulfillmentOrder}`}

View file

@ -0,0 +1,31 @@
import { FulfillmentStatus } from "@saleor/types/globalTypes";
import { defineMessages, IntlShape } from "react-intl";
export const messages = defineMessages({
fulfillment: {
defaultMessage: "Fulfillment",
description: "section header"
},
fulfillmentReturned: {
defaultMessage: "Fulfillment returned",
description: "section header returned"
},
fulfillmentWaitingForApproval: {
defaultMessage: "Fulfillment waiting for approval",
description: "section header returned"
}
});
export const getTitle = (
fulfillmentStatus: FulfillmentStatus,
intl: IntlShape
) => {
switch (fulfillmentStatus) {
case FulfillmentStatus.RETURNED:
return intl.formatMessage(messages.fulfillmentReturned);
case FulfillmentStatus.WAITING_FOR_APPROVAL:
return intl.formatMessage(messages.fulfillmentWaitingForApproval);
default:
return intl.formatMessage(messages.fulfillment);
}
};

View file

@ -26,7 +26,8 @@ import OrderRefundForm, {
export const refundFulfilledStatuses = [
FulfillmentStatus.FULFILLED,
FulfillmentStatus.RETURNED
FulfillmentStatus.RETURNED,
FulfillmentStatus.WAITING_FOR_APPROVAL
];
export interface OrderRefundPageProps {
@ -51,7 +52,7 @@ const OrderRefundPage: React.FC<OrderRefundPageProps> = props => {
const intl = useIntl();
const unfulfilledLines = order?.lines.filter(
line => line.quantity !== line.quantityFulfilled
line => line.quantityToFulfill > 0
);
const fulfilledFulfillemnts =

View file

@ -34,7 +34,7 @@ export const orderToRefund = (placeholder: string): OrderRefundData_order => ({
id: "diufhdsif",
productName: "Milk",
quantity: 19,
quantityFulfilled: 3,
quantityToFulfill: 16,
thumbnail: {
__typename: "Image",
url: placeholder
@ -53,7 +53,7 @@ export const orderToRefund = (placeholder: string): OrderRefundData_order => ({
id: "fdsfdfdsf",
productName: "Coffee",
quantity: 13,
quantityFulfilled: 5,
quantityToFulfill: 8,
thumbnail: {
__typename: "Image",
url: placeholder

View file

@ -78,7 +78,7 @@ function useOrderRefundForm(
const form = useForm(getOrderRefundPageFormData(defaultType));
const refundedProductQuantities = useFormset<null, string>(
order?.lines
.filter(line => line.quantityFulfilled !== line.quantity)
.filter(line => line.quantityToFulfill > 0)
.map(line => ({
data: null,
id: line.id,
@ -132,7 +132,7 @@ function useOrderRefundForm(
data: null,
id: line.id,
label: null,
value: (line.quantity - line.quantityFulfilled).toString()
value: line.quantityToFulfill.toString()
};
});
refundedProductQuantities.set(newQuantities);

View file

@ -148,7 +148,7 @@ const OrderRefundUnfulfilledProducts: React.FC<OrderRefundUnfulfilledProductsPro
const selectedLineQuantity = data.refundedProductQuantities.find(
refundedLine => refundedLine.id === line.id
);
const lineQuantity = line?.quantity - line?.quantityFulfilled;
const lineQuantity = line?.quantityToFulfill;
const isError =
Number(selectedLineQuantity?.value) > lineQuantity ||
Number(selectedLineQuantity?.value) < 0;

View file

@ -6,14 +6,24 @@ import { makeStyles } from "@saleor/macaw-ui";
import { FulfillmentStatus } from "@saleor/types/globalTypes";
import camelCase from "lodash/camelCase";
import React from "react";
import { FormattedMessage } from "react-intl";
import { defineMessages } from "react-intl";
import { useIntl } from "react-intl";
const useStyles = makeStyles(
theme => ({
title: {
width: "100%",
display: "flex"
},
orderNumber: {
display: "inline",
marginLeft: theme.spacing(1)
},
warehouseName: {
float: "right",
color: theme.palette.text.secondary,
margin: `auto ${theme.spacing(1)} auto auto`
}
}),
{ name: "CardTitle" }
@ -44,9 +54,17 @@ const messages = defineMessages({
defaultMessage: "Returned ({quantity})",
description: "refunded fulfillment, section header"
},
waitingForApproval: {
defaultMessage: "Waiting for approval ({quantity})",
description: "unapproved fulfillment, section header"
},
unfulfilled: {
defaultMessage: "Unfulfilled",
description: "section header"
},
fulfilledFrom: {
defaultMessage: "Fulfilled from {warehouseName}",
description: "fulfilled fulfillment, section header"
}
});
@ -62,6 +80,7 @@ interface CardTitleProps {
status: CardTitleStatus;
toolbar?: React.ReactNode;
orderNumber?: string;
warehouseName?: string;
withStatus?: boolean;
}
@ -77,6 +96,8 @@ const selectStatus = (status: CardTitleStatus) => {
return StatusType.NEUTRAL;
case FulfillmentStatus.REFUNDED_AND_RETURNED:
return StatusType.NEUTRAL;
case FulfillmentStatus.WAITING_FOR_APPROVAL:
return StatusType.ALERT;
case FulfillmentStatus.CANCELED:
return StatusType.ERROR;
default:
@ -89,6 +110,7 @@ const CardTitle: React.FC<CardTitleProps> = ({
fulfillmentOrder,
status,
orderNumber = "",
warehouseName,
withStatus = false,
toolbar
}) => {
@ -108,7 +130,7 @@ const CardTitle: React.FC<CardTitleProps> = ({
);
const title = (
<>
<div className={classes.title}>
{intl.formatMessage(messageForStatus, {
fulfillmentName,
quantity: totalQuantity
@ -116,7 +138,17 @@ const CardTitle: React.FC<CardTitleProps> = ({
<Typography className={classes.orderNumber} variant="body1">
{fulfillmentName}
</Typography>
</>
{!!warehouseName && (
<Typography className={classes.warehouseName} variant="caption">
<FormattedMessage
{...messages.fulfilledFrom}
values={{
warehouseName
}}
/>
</Typography>
)}
</div>
);
return (

View file

@ -1,4 +1,7 @@
import { orderSettings as orderSettingsFixture } from "@saleor/orders/fixtures";
import {
orderSettings as orderSettingsFixture,
shopOrderSettings as shopOrderSettingsFixture
} from "@saleor/orders/fixtures";
import { storiesOf } from "@storybook/react";
import React from "react";
@ -6,7 +9,8 @@ import Decorator from "../../../storybook/Decorator";
import OrderSettings, { OrderSettingsPageProps } from ".";
const props: OrderSettingsPageProps = {
data: orderSettingsFixture,
orderSettings: orderSettingsFixture,
shop: shopOrderSettingsFixture,
disabled: false,
onBack: () => undefined,
onSubmit: () => undefined,
@ -17,5 +21,10 @@ storiesOf("Views / Orders / Order settings", module)
.addDecorator(Decorator)
.add("default", () => <OrderSettings {...props} />)
.add("loading", () => (
<OrderSettings {...props} disabled={true} data={undefined} />
<OrderSettings
{...props}
disabled={true}
orderSettings={undefined}
shop={undefined}
/>
));

View file

@ -5,17 +5,20 @@ import Grid from "@saleor/components/Grid";
import PageHeader from "@saleor/components/PageHeader";
import Savebar from "@saleor/components/Savebar";
import { OrderSettingsFragment } from "@saleor/fragments/types/OrderSettingsFragment";
import { ShopOrderSettingsFragment } from "@saleor/fragments/types/ShopOrderSettingsFragment";
import { SubmitPromise } from "@saleor/hooks/useForm";
import { sectionNames } from "@saleor/intl";
import { Backlink } from "@saleor/macaw-ui";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import OrderFulfillmentSettings from "../OrderFulfillmentSettings";
import OrderSettings from "../OrderSettings/OrderSettings";
import OrderSettingsForm, { OrderSettingsFormData } from "./form";
export interface OrderSettingsPageProps {
data: OrderSettingsFragment;
orderSettings: OrderSettingsFragment;
shop: ShopOrderSettingsFragment;
disabled: boolean;
saveButtonBarState: ConfirmButtonTransitionState;
onBack: () => void;
@ -23,11 +26,22 @@ export interface OrderSettingsPageProps {
}
const OrderSettingsPage: React.FC<OrderSettingsPageProps> = props => {
const { data, disabled, saveButtonBarState, onBack, onSubmit } = props;
const {
orderSettings,
shop,
disabled,
saveButtonBarState,
onBack,
onSubmit
} = props;
const intl = useIntl();
return (
<OrderSettingsForm orderSettings={data} onSubmit={onSubmit}>
<OrderSettingsForm
orderSettings={orderSettings}
shop={shop}
onSubmit={onSubmit}
>
{({ data, submit, hasChanged, change }) => (
<Container>
<Backlink onClick={onBack}>
@ -46,6 +60,12 @@ const OrderSettingsPage: React.FC<OrderSettingsPageProps> = props => {
</Typography>
</div>
<OrderSettings data={data} disabled={disabled} onChange={change} />
<div />
<OrderFulfillmentSettings
data={data}
disabled={disabled}
onChange={change}
/>
</Grid>
<Savebar
onCancel={onBack}

View file

@ -1,10 +1,13 @@
import { OrderSettingsFragment } from "@saleor/fragments/types/OrderSettingsFragment";
import { ShopOrderSettingsFragment } from "@saleor/fragments/types/ShopOrderSettingsFragment";
import useForm, { FormChange, SubmitPromise } from "@saleor/hooks/useForm";
import handleFormSubmit from "@saleor/utils/handlers/handleFormSubmit";
import React from "react";
export interface OrderSettingsFormData {
automaticallyConfirmAllNewOrders: boolean;
fulfillmentAutoApprove: boolean;
fulfillmentAllowUnpaid: boolean;
}
export interface UseOrderSettingsFormResult {
@ -17,26 +20,31 @@ export interface UseOrderSettingsFormResult {
export interface OrderSettingsFormProps {
children: (props: UseOrderSettingsFormResult) => React.ReactNode;
orderSettings: OrderSettingsFragment;
shop: ShopOrderSettingsFragment;
onSubmit: (data: OrderSettingsFormData) => SubmitPromise;
}
function getOrderSeettingsFormData(
orderSettings: OrderSettingsFragment
orderSettings: OrderSettingsFragment,
shop: ShopOrderSettingsFragment
): OrderSettingsFormData {
return {
automaticallyConfirmAllNewOrders:
orderSettings?.automaticallyConfirmAllNewOrders
orderSettings?.automaticallyConfirmAllNewOrders,
fulfillmentAutoApprove: shop?.fulfillmentAutoApprove,
fulfillmentAllowUnpaid: shop?.fulfillmentAllowUnpaid
};
}
function useOrderSettingsForm(
orderSettings: OrderSettingsFragment,
shop: ShopOrderSettingsFragment,
onSubmit: (data: OrderSettingsFormData) => SubmitPromise
): UseOrderSettingsFormResult {
const [changed, setChanged] = React.useState(false);
const triggerChange = () => setChanged(true);
const form = useForm(getOrderSeettingsFormData(orderSettings));
const form = useForm(getOrderSeettingsFormData(orderSettings, shop));
const handleChange: FormChange = (event, cb) => {
form.change(event, cb);
@ -60,9 +68,10 @@ function useOrderSettingsForm(
const OrderSettingsForm: React.FC<OrderSettingsFormProps> = ({
children,
orderSettings,
shop,
onSubmit
}) => {
const props = useOrderSettingsForm(orderSettings, onSubmit);
const props = useOrderSettingsForm(orderSettings, shop, onSubmit);
return <form onSubmit={props.submit}>{children(props)}</form>;
};

View file

@ -1,6 +1,13 @@
import { Button, Card, CardActions, TableBody } from "@material-ui/core";
import {
Button,
Card,
CardActions,
TableBody,
Typography
} from "@material-ui/core";
import CardSpacer from "@saleor/components/CardSpacer";
import ResponsiveTable from "@saleor/components/ResponsiveTable";
import { commonMessages } from "@saleor/intl";
import { makeStyles } from "@saleor/macaw-ui";
import { renderCollection } from "@saleor/misc";
import React from "react";
@ -21,13 +28,19 @@ const useStyles = makeStyles(
);
interface OrderUnfulfilledProductsCardProps {
canFulfill: boolean;
showFulfillmentAction: boolean;
notAllowedToFulfillUnpaid: boolean;
lines: OrderDetails_order_lines[];
onFulfill: () => void;
}
const OrderUnfulfilledProductsCard: React.FC<OrderUnfulfilledProductsCardProps> = props => {
const { canFulfill, lines, onFulfill } = props;
const {
showFulfillmentAction,
notAllowedToFulfillUnpaid,
lines,
onFulfill
} = props;
const classes = useStyles({});
if (!lines.length) {
@ -46,11 +59,23 @@ const OrderUnfulfilledProductsCard: React.FC<OrderUnfulfilledProductsCardProps>
))}
</TableBody>
</ResponsiveTable>
{canFulfill && (
{showFulfillmentAction && (
<CardActions>
<Button variant="text" color="primary" onClick={onFulfill}>
<Button
variant="text"
color="primary"
onClick={onFulfill}
disabled={notAllowedToFulfillUnpaid}
>
<FormattedMessage defaultMessage="Fulfill" description="button" />
</Button>
{notAllowedToFulfillUnpaid && (
<Typography color="error" variant="caption">
<FormattedMessage
{...commonMessages.cannotFullfillUnpaidOrder}
/>
</Typography>
)}
</CardActions>
)}
</Card>

View file

@ -11,6 +11,7 @@ import {
TypedOrderDraftCancelMutation,
TypedOrderDraftFinalizeMutation,
TypedOrderDraftUpdateMutation,
TypedOrderFulfillmentApproveMutation,
TypedOrderFulfillmentCancelMutation,
TypedOrderFulfillmentUpdateTrackingMutation,
TypedOrderLineDeleteMutation,
@ -44,6 +45,10 @@ import {
OrderDraftUpdate,
OrderDraftUpdateVariables
} from "../types/OrderDraftUpdate";
import {
OrderFulfillmentApprove,
OrderFulfillmentApproveVariables
} from "../types/OrderFulfillmentApprove";
import {
OrderFulfillmentCancel,
OrderFulfillmentCancelVariables
@ -83,6 +88,10 @@ interface OrderOperationsProps {
OrderCancel,
OrderCancelVariables
>;
orderFulfillmentApprove: PartialMutationProviderOutput<
OrderFulfillmentApprove,
OrderFulfillmentApproveVariables
>;
orderFulfillmentCancel: PartialMutationProviderOutput<
OrderFulfillmentCancel,
OrderFulfillmentCancelVariables
@ -141,6 +150,7 @@ interface OrderOperationsProps {
InvoiceEmailSendVariables
>;
}) => React.ReactNode;
onOrderFulfillmentApprove: (data: OrderFulfillmentApprove) => void;
onOrderFulfillmentCancel: (data: OrderFulfillmentCancel) => void;
onOrderFulfillmentUpdate: (data: OrderFulfillmentUpdateTracking) => void;
onOrderCancel: (data: OrderCancel) => void;
@ -174,6 +184,7 @@ const OrderOperations: React.FC<OrderOperationsProps> = ({
onUpdate,
onDraftCancel,
onDraftFinalize,
onOrderFulfillmentApprove,
onOrderFulfillmentCancel,
onOrderFulfillmentUpdate,
onOrderMarkAsPaid,
@ -210,121 +221,138 @@ const OrderOperations: React.FC<OrderOperationsProps> = ({
onCompleted={onOrderLineUpdate}
>
{(...updateOrderLine) => (
<TypedOrderFulfillmentCancelMutation
<TypedOrderFulfillmentApproveMutation
onCompleted={
onOrderFulfillmentCancel
onOrderFulfillmentApprove
}
>
{(...cancelFulfillment) => (
<TypedOrderFulfillmentUpdateTrackingMutation
{(...approveFulfillment) => (
<TypedOrderFulfillmentCancelMutation
onCompleted={
onOrderFulfillmentUpdate
onOrderFulfillmentCancel
}
>
{(...updateTrackingNumber) => (
<TypedOrderDraftFinalizeMutation
{(...cancelFulfillment) => (
<TypedOrderFulfillmentUpdateTrackingMutation
onCompleted={
onDraftFinalize
onOrderFulfillmentUpdate
}
>
{(...finalizeDraft) => (
<TypedOrderDraftCancelMutation
{(
...updateTrackingNumber
) => (
<TypedOrderDraftFinalizeMutation
onCompleted={
onDraftCancel
onDraftFinalize
}
>
{(...cancelDraft) => (
<TypedOrderMarkAsPaidMutation
{(...finalizeDraft) => (
<TypedOrderDraftCancelMutation
onCompleted={
onOrderMarkAsPaid
onDraftCancel
}
>
{(
...markAsPaid
...cancelDraft
) => (
<TypedInvoiceRequestMutation
<TypedOrderMarkAsPaidMutation
onCompleted={
onInvoiceRequest
onOrderMarkAsPaid
}
>
{(
...invoiceRequest
...markAsPaid
) => (
<TypedInvoiceEmailSendMutation
<TypedInvoiceRequestMutation
onCompleted={
onInvoiceSend
onInvoiceRequest
}
>
{(
...invoiceEmailSend
) =>
children({
orderAddNote: getMutationProviderData(
...addNote
),
orderCancel: getMutationProviderData(
...orderCancel
),
orderDraftCancel: getMutationProviderData(
...cancelDraft
),
orderDraftFinalize: getMutationProviderData(
...finalizeDraft
),
orderDraftUpdate: getMutationProviderData(
...updateDraft
),
orderFulfillmentCancel: getMutationProviderData(
...cancelFulfillment
),
orderFulfillmentUpdateTracking: getMutationProviderData(
...updateTrackingNumber
),
orderInvoiceRequest: getMutationProviderData(
...invoiceRequest
),
orderInvoiceSend: getMutationProviderData(
...invoiceRequest
) => (
<TypedInvoiceEmailSendMutation
onCompleted={
onInvoiceSend
}
>
{(
...invoiceEmailSend
),
orderLineDelete: getMutationProviderData(
...deleteOrderLine
),
orderLineUpdate: getMutationProviderData(
...updateOrderLine
),
orderLinesAdd: getMutationProviderData(
...addOrderLine
),
orderPaymentCapture: getMutationProviderData(
...paymentCapture
),
orderPaymentMarkAsPaid: getMutationProviderData(
...markAsPaid
),
orderShippingMethodUpdate: getMutationProviderData(
...updateShippingMethod
),
orderUpdate: getMutationProviderData(
...update
),
orderVoid: getMutationProviderData(
...orderVoid
)
})
}
</TypedInvoiceEmailSendMutation>
) =>
children(
{
orderAddNote: getMutationProviderData(
...addNote
),
orderCancel: getMutationProviderData(
...orderCancel
),
orderDraftCancel: getMutationProviderData(
...cancelDraft
),
orderDraftFinalize: getMutationProviderData(
...finalizeDraft
),
orderDraftUpdate: getMutationProviderData(
...updateDraft
),
orderFulfillmentApprove: getMutationProviderData(
...approveFulfillment
),
orderFulfillmentCancel: getMutationProviderData(
...cancelFulfillment
),
orderFulfillmentUpdateTracking: getMutationProviderData(
...updateTrackingNumber
),
orderInvoiceRequest: getMutationProviderData(
...invoiceRequest
),
orderInvoiceSend: getMutationProviderData(
...invoiceEmailSend
),
orderLineDelete: getMutationProviderData(
...deleteOrderLine
),
orderLineUpdate: getMutationProviderData(
...updateOrderLine
),
orderLinesAdd: getMutationProviderData(
...addOrderLine
),
orderPaymentCapture: getMutationProviderData(
...paymentCapture
),
orderPaymentMarkAsPaid: getMutationProviderData(
...markAsPaid
),
orderShippingMethodUpdate: getMutationProviderData(
...updateShippingMethod
),
orderUpdate: getMutationProviderData(
...update
),
orderVoid: getMutationProviderData(
...orderVoid
)
}
)
}
</TypedInvoiceEmailSendMutation>
)}
</TypedInvoiceRequestMutation>
)}
</TypedInvoiceRequestMutation>
</TypedOrderMarkAsPaidMutation>
)}
</TypedOrderMarkAsPaidMutation>
</TypedOrderDraftCancelMutation>
)}
</TypedOrderDraftCancelMutation>
</TypedOrderDraftFinalizeMutation>
)}
</TypedOrderDraftFinalizeMutation>
</TypedOrderFulfillmentUpdateTrackingMutation>
)}
</TypedOrderFulfillmentUpdateTrackingMutation>
</TypedOrderFulfillmentCancelMutation>
)}
</TypedOrderFulfillmentCancelMutation>
</TypedOrderFulfillmentApproveMutation>
)}
</TypedOrderLineUpdateMutation>
)}

View file

@ -1,6 +1,7 @@
import { ShopInfo_shop_countries } from "@saleor/components/Shop/types/ShopInfo";
import { InvoiceFragment } from "@saleor/fragments/types/InvoiceFragment";
import { OrderSettingsFragment } from "@saleor/fragments/types/OrderSettingsFragment";
import { ShopOrderSettingsFragment } from "@saleor/fragments/types/ShopOrderSettingsFragment";
import { SearchCustomers_search_edges_node } from "@saleor/searches/types/SearchCustomers";
import { warehouseList } from "@saleor/warehouses/fixtures";
import { MessageDescriptor } from "react-intl";
@ -13,12 +14,28 @@ import {
OrderEventsEmailsEnum,
OrderEventsEnum,
OrderStatus,
PaymentChargeStatusEnum
PaymentChargeStatusEnum,
WeightUnitsEnum
} from "../types/globalTypes";
import { OrderDetails_order } from "./types/OrderDetails";
import { OrderDetails_order, OrderDetails_shop } from "./types/OrderDetails";
import { OrderList_orders_edges_node } from "./types/OrderList";
import { SearchOrderVariant_search_edges_node } from "./types/SearchOrderVariant";
export const countries: ShopInfo_shop_countries[] = [
{ __typename: "CountryDisplay", code: "AF", country: "Afghanistan" },
{ __typename: "CountryDisplay", code: "AX", country: "Åland Islands" },
{ __typename: "CountryDisplay", code: "AL", country: "Albania" },
{ __typename: "CountryDisplay", code: "DZ", country: "Algeria" },
{ __typename: "CountryDisplay", code: "AS", country: "American Samoa" }
];
export const shop: OrderDetails_shop = {
__typename: "Shop",
countries,
defaultWeightUnit: WeightUnitsEnum.KG,
fulfillmentAllowUnpaid: true,
fulfillmentAutoApprove: true
};
export const clients: SearchCustomers_search_edges_node[] = [
{
__typename: "User" as "User",
@ -1024,6 +1041,7 @@ export const order = (placeholder: string): OrderDetails_order => ({
productSku: "5-1337",
quantity: 2,
quantityFulfilled: 2,
quantityToFulfill: 0,
thumbnail: {
__typename: "Image" as "Image",
url: placeholder
@ -1092,6 +1110,7 @@ export const order = (placeholder: string): OrderDetails_order => ({
productSku: "5-1337",
quantity: 2,
quantityFulfilled: 2,
quantityToFulfill: 0,
thumbnail: {
__typename: "Image" as "Image",
url: placeholder
@ -1167,6 +1186,7 @@ export const order = (placeholder: string): OrderDetails_order => ({
productSku: "59-1337",
quantity: 3,
quantityFulfilled: 0,
quantityToFulfill: 3,
thumbnail: {
__typename: "Image" as "Image",
url: placeholder
@ -1220,6 +1240,7 @@ export const order = (placeholder: string): OrderDetails_order => ({
productSku: "5-1337",
quantity: 2,
quantityFulfilled: 2,
quantityToFulfill: 0,
thumbnail: {
__typename: "Image" as "Image",
url: placeholder
@ -1405,6 +1426,7 @@ export const draftOrder = (placeholder: string): OrderDetails_order => ({
productSku: "58-1338",
quantity: 2,
quantityFulfilled: 0,
quantityToFulfill: 2,
thumbnail: {
__typename: "Image" as "Image",
url: placeholder
@ -1458,6 +1480,7 @@ export const draftOrder = (placeholder: string): OrderDetails_order => ({
productSku: "15-1337",
quantity: 2,
quantityFulfilled: 0,
quantityToFulfill: 2,
thumbnail: {
__typename: "Image" as "Image",
url: placeholder
@ -1588,13 +1611,6 @@ export const variants = [
{ id: "p7", name: "Product 5: variant 2", sku: "14345", stockQuantity: 11 }
];
export const prefixes = ["01", "02", "41", "49"];
export const countries: ShopInfo_shop_countries[] = [
{ __typename: "CountryDisplay", code: "AF", country: "Afghanistan" },
{ __typename: "CountryDisplay", code: "AX", country: "Åland Islands" },
{ __typename: "CountryDisplay", code: "AL", country: "Albania" },
{ __typename: "CountryDisplay", code: "DZ", country: "Algeria" },
{ __typename: "CountryDisplay", code: "AS", country: "American Samoa" }
];
export const shippingMethods = [
{ country: "whole world", id: "s1", name: "DHL", price: {} },
{ country: "Afghanistan", id: "s2", name: "UPS" }
@ -1897,3 +1913,9 @@ export const orderSettings: OrderSettingsFragment = {
__typename: "OrderSettings",
automaticallyConfirmAllNewOrders: true
};
export const shopOrderSettings: ShopOrderSettingsFragment = {
__typename: "Shop",
fulfillmentAutoApprove: true,
fulfillmentAllowUnpaid: true
};

View file

@ -1,12 +1,14 @@
import {
invoiceErrorFragment,
orderErrorFragment,
orderSettingsErrorFragment
orderSettingsErrorFragment,
shopErrorFragment
} from "@saleor/fragments/errors";
import {
fragmentOrderDetails,
fragmentOrderEvent,
fragmentOrderSettings,
fragmentShopOrderSettings,
fulfillmentFragment,
invoiceFragment
} from "@saleor/fragments/orders";
@ -63,6 +65,10 @@ import {
OrderDraftUpdate,
OrderDraftUpdateVariables
} from "./types/OrderDraftUpdate";
import {
OrderFulfillmentApprove,
OrderFulfillmentApproveVariables
} from "./types/OrderFulfillmentApprove";
import {
OrderFulfillmentCancel,
OrderFulfillmentCancelVariables
@ -461,6 +467,25 @@ export const TypedOrderFulfillmentUpdateTrackingMutation = TypedMutation<
OrderFulfillmentUpdateTrackingVariables
>(orderFulfillmentUpdateTrackingMutation);
const orderFulfillmentApproveMutation = gql`
${fragmentOrderDetails}
${orderErrorFragment}
mutation OrderFulfillmentApprove($id: ID!, $notifyCustomer: Boolean!) {
orderFulfillmentApprove(id: $id, notifyCustomer: $notifyCustomer) {
errors {
...OrderErrorFragment
}
order {
...OrderDetailsFragment
}
}
}
`;
export const TypedOrderFulfillmentApproveMutation = TypedMutation<
OrderFulfillmentApprove,
OrderFulfillmentApproveVariables
>(orderFulfillmentApproveMutation);
const orderFulfillmentCancelMutation = gql`
${fragmentOrderDetails}
${orderErrorFragment}
@ -734,9 +759,14 @@ export const TypedInvoiceEmailSendMutation = TypedMutation<
const orderSettingsUpdateMutation = gql`
${fragmentOrderSettings}
${fragmentShopOrderSettings}
${orderSettingsErrorFragment}
mutation OrderSettingsUpdate($input: OrderSettingsUpdateInput!) {
orderSettingsUpdate(input: $input) {
${shopErrorFragment}
mutation OrderSettingsUpdate(
$orderSettingsInput: OrderSettingsUpdateInput!
$shopSettingsInput: ShopSettingsInput!
) {
orderSettingsUpdate(input: $orderSettingsInput) {
errors {
...OrderSettingsErrorFragment
}
@ -744,6 +774,14 @@ const orderSettingsUpdateMutation = gql`
...OrderSettingsFragment
}
}
shopSettingsUpdate(input: $shopSettingsInput) {
errors {
...ShopErrorFragment
}
shop {
...ShopOrderSettingsFragment
}
}
}
`;
export const useOrderSettingsUpdateMutation = makeMutation<

View file

@ -2,9 +2,11 @@ import { fragmentAddress } from "@saleor/fragments/address";
import {
fragmentOrderDetails,
fragmentOrderSettings,
fragmentRefundOrderLine
fragmentRefundOrderLine,
fragmentShopOrderSettings
} from "@saleor/fragments/orders";
import { fragmentMoney } from "@saleor/fragments/products";
import { warehouseFragment } from "@saleor/fragments/warehouses";
import makeQuery from "@saleor/hooks/makeQuery";
import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch";
import gql from "graphql-tag";
@ -19,6 +21,7 @@ import {
OrderFulfillData,
OrderFulfillDataVariables
} from "./types/OrderFulfillData";
import { OrderFulfillSettings } from "./types/OrderFulfillSettings";
import { OrderList, OrderListVariables } from "./types/OrderList";
import {
OrderRefundData,
@ -150,6 +153,8 @@ export const orderDetailsQuery = gql`
country
}
defaultWeightUnit
fulfillmentAllowUnpaid
fulfillmentAutoApprove
}
}
`;
@ -217,9 +222,11 @@ export const useOrderVariantSearch = makeTopLevelSearch<
>(searchOrderVariant);
const orderFulfillData = gql`
${warehouseFragment}
query OrderFulfillData($orderId: ID!) {
order(id: $orderId) {
id
isPaid
lines {
id
isShippingRequired
@ -232,6 +239,7 @@ const orderFulfillData = gql`
}
}
quantityFulfilled
quantityToFulfill
variant {
id
name
@ -245,7 +253,7 @@ const orderFulfillData = gql`
stocks {
id
warehouse {
id
...WarehouseFragment
}
quantity
quantityAllocated
@ -265,12 +273,29 @@ export const useOrderFulfillData = makeQuery<
OrderFulfillDataVariables
>(orderFulfillData);
export const orderFulfillSettingsQuery = gql`
${fragmentShopOrderSettings}
query OrderFulfillSettings {
shop {
...ShopOrderSettingsFragment
}
}
`;
export const useOrderFulfillSettingsQuery = makeQuery<
OrderFulfillSettings,
never
>(orderFulfillSettingsQuery);
export const orderSettingsQuery = gql`
${fragmentOrderSettings}
${fragmentShopOrderSettings}
query OrderSettings {
orderSettings {
...OrderSettingsFragment
}
shop {
...ShopOrderSettingsFragment
}
}
`;
export const useOrderSettingsQuery = makeQuery<OrderSettings, never>(
@ -299,7 +324,7 @@ const orderRefundData = gql`
}
lines {
...RefundOrderLineFragment
quantityFulfilled
quantityToFulfill
}
fulfillments {
id

View file

@ -225,6 +225,7 @@ export interface FulfillOrder_orderFulfill_order_fulfillments_lines_orderLine {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: FulfillOrder_orderFulfill_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -320,6 +321,7 @@ export interface FulfillOrder_orderFulfill_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: FulfillOrder_orderFulfill_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -492,6 +494,7 @@ export interface FulfillOrder_orderFulfill_order {
fulfillments: (FulfillOrder_orderFulfill_order_fulfillments | null)[];
lines: (FulfillOrder_orderFulfill_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: FulfillOrder_orderFulfill_order_shippingAddress | null;
shippingMethod: FulfillOrder_orderFulfill_order_shippingMethod | null;
@ -509,7 +512,6 @@ export interface FulfillOrder_orderFulfill_order {
availableShippingMethods: (FulfillOrder_orderFulfill_order_availableShippingMethods | null)[] | null;
invoices: (FulfillOrder_orderFulfill_order_invoices | null)[] | null;
channel: FulfillOrder_orderFulfill_order_channel;
isPaid: boolean;
}
export interface FulfillOrder_orderFulfill {

View file

@ -223,6 +223,7 @@ export interface OrderCancel_orderCancel_order_fulfillments_lines_orderLine {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderCancel_orderCancel_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderCancel_orderCancel_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderCancel_orderCancel_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderCancel_orderCancel_order {
fulfillments: (OrderCancel_orderCancel_order_fulfillments | null)[];
lines: (OrderCancel_orderCancel_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderCancel_orderCancel_order_shippingAddress | null;
shippingMethod: OrderCancel_orderCancel_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderCancel_orderCancel_order {
availableShippingMethods: (OrderCancel_orderCancel_order_availableShippingMethods | null)[] | null;
invoices: (OrderCancel_orderCancel_order_invoices | null)[] | null;
channel: OrderCancel_orderCancel_order_channel;
isPaid: boolean;
}
export interface OrderCancel_orderCancel {

View file

@ -223,6 +223,7 @@ export interface OrderCapture_orderCapture_order_fulfillments_lines_orderLine {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderCapture_orderCapture_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderCapture_orderCapture_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderCapture_orderCapture_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderCapture_orderCapture_order {
fulfillments: (OrderCapture_orderCapture_order_fulfillments | null)[];
lines: (OrderCapture_orderCapture_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderCapture_orderCapture_order_shippingAddress | null;
shippingMethod: OrderCapture_orderCapture_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderCapture_orderCapture_order {
availableShippingMethods: (OrderCapture_orderCapture_order_availableShippingMethods | null)[] | null;
invoices: (OrderCapture_orderCapture_order_invoices | null)[] | null;
channel: OrderCapture_orderCapture_order_channel;
isPaid: boolean;
}
export interface OrderCapture_orderCapture {

View file

@ -223,6 +223,7 @@ export interface OrderConfirm_orderConfirm_order_fulfillments_lines_orderLine {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderConfirm_orderConfirm_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderConfirm_orderConfirm_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderConfirm_orderConfirm_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderConfirm_orderConfirm_order {
fulfillments: (OrderConfirm_orderConfirm_order_fulfillments | null)[];
lines: (OrderConfirm_orderConfirm_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderConfirm_orderConfirm_order_shippingAddress | null;
shippingMethod: OrderConfirm_orderConfirm_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderConfirm_orderConfirm_order {
availableShippingMethods: (OrderConfirm_orderConfirm_order_availableShippingMethods | null)[] | null;
invoices: (OrderConfirm_orderConfirm_order_invoices | null)[] | null;
channel: OrderConfirm_orderConfirm_order_channel;
isPaid: boolean;
}
export interface OrderConfirm_orderConfirm {

View file

@ -216,6 +216,7 @@ export interface OrderDetails_order_fulfillments_lines_orderLine {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDetails_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -311,6 +312,7 @@ export interface OrderDetails_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDetails_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -483,6 +485,7 @@ export interface OrderDetails_order {
fulfillments: (OrderDetails_order_fulfillments | null)[];
lines: (OrderDetails_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderDetails_order_shippingAddress | null;
shippingMethod: OrderDetails_order_shippingMethod | null;
@ -500,7 +503,6 @@ export interface OrderDetails_order {
availableShippingMethods: (OrderDetails_order_availableShippingMethods | null)[] | null;
invoices: (OrderDetails_order_invoices | null)[] | null;
channel: OrderDetails_order_channel;
isPaid: boolean;
}
export interface OrderDetails_shop_countries {
@ -513,6 +515,8 @@ export interface OrderDetails_shop {
__typename: "Shop";
countries: OrderDetails_shop_countries[];
defaultWeightUnit: WeightUnitsEnum | null;
fulfillmentAllowUnpaid: boolean;
fulfillmentAutoApprove: boolean;
}
export interface OrderDetails {

View file

@ -223,6 +223,7 @@ export interface OrderDiscountAdd_orderDiscountAdd_order_fulfillments_lines_orde
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDiscountAdd_orderDiscountAdd_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderDiscountAdd_orderDiscountAdd_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDiscountAdd_orderDiscountAdd_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderDiscountAdd_orderDiscountAdd_order {
fulfillments: (OrderDiscountAdd_orderDiscountAdd_order_fulfillments | null)[];
lines: (OrderDiscountAdd_orderDiscountAdd_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderDiscountAdd_orderDiscountAdd_order_shippingAddress | null;
shippingMethod: OrderDiscountAdd_orderDiscountAdd_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderDiscountAdd_orderDiscountAdd_order {
availableShippingMethods: (OrderDiscountAdd_orderDiscountAdd_order_availableShippingMethods | null)[] | null;
invoices: (OrderDiscountAdd_orderDiscountAdd_order_invoices | null)[] | null;
channel: OrderDiscountAdd_orderDiscountAdd_order_channel;
isPaid: boolean;
}
export interface OrderDiscountAdd_orderDiscountAdd {

View file

@ -223,6 +223,7 @@ export interface OrderDiscountDelete_orderDiscountDelete_order_fulfillments_line
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDiscountDelete_orderDiscountDelete_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderDiscountDelete_orderDiscountDelete_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDiscountDelete_orderDiscountDelete_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderDiscountDelete_orderDiscountDelete_order {
fulfillments: (OrderDiscountDelete_orderDiscountDelete_order_fulfillments | null)[];
lines: (OrderDiscountDelete_orderDiscountDelete_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderDiscountDelete_orderDiscountDelete_order_shippingAddress | null;
shippingMethod: OrderDiscountDelete_orderDiscountDelete_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderDiscountDelete_orderDiscountDelete_order {
availableShippingMethods: (OrderDiscountDelete_orderDiscountDelete_order_availableShippingMethods | null)[] | null;
invoices: (OrderDiscountDelete_orderDiscountDelete_order_invoices | null)[] | null;
channel: OrderDiscountDelete_orderDiscountDelete_order_channel;
isPaid: boolean;
}
export interface OrderDiscountDelete_orderDiscountDelete {

View file

@ -223,6 +223,7 @@ export interface OrderDiscountUpdate_orderDiscountUpdate_order_fulfillments_line
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDiscountUpdate_orderDiscountUpdate_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderDiscountUpdate_orderDiscountUpdate_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDiscountUpdate_orderDiscountUpdate_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderDiscountUpdate_orderDiscountUpdate_order {
fulfillments: (OrderDiscountUpdate_orderDiscountUpdate_order_fulfillments | null)[];
lines: (OrderDiscountUpdate_orderDiscountUpdate_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderDiscountUpdate_orderDiscountUpdate_order_shippingAddress | null;
shippingMethod: OrderDiscountUpdate_orderDiscountUpdate_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderDiscountUpdate_orderDiscountUpdate_order {
availableShippingMethods: (OrderDiscountUpdate_orderDiscountUpdate_order_availableShippingMethods | null)[] | null;
invoices: (OrderDiscountUpdate_orderDiscountUpdate_order_invoices | null)[] | null;
channel: OrderDiscountUpdate_orderDiscountUpdate_order_channel;
isPaid: boolean;
}
export interface OrderDiscountUpdate_orderDiscountUpdate {

View file

@ -223,6 +223,7 @@ export interface OrderDraftCancel_draftOrderDelete_order_fulfillments_lines_orde
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDraftCancel_draftOrderDelete_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderDraftCancel_draftOrderDelete_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDraftCancel_draftOrderDelete_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderDraftCancel_draftOrderDelete_order {
fulfillments: (OrderDraftCancel_draftOrderDelete_order_fulfillments | null)[];
lines: (OrderDraftCancel_draftOrderDelete_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderDraftCancel_draftOrderDelete_order_shippingAddress | null;
shippingMethod: OrderDraftCancel_draftOrderDelete_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderDraftCancel_draftOrderDelete_order {
availableShippingMethods: (OrderDraftCancel_draftOrderDelete_order_availableShippingMethods | null)[] | null;
invoices: (OrderDraftCancel_draftOrderDelete_order_invoices | null)[] | null;
channel: OrderDraftCancel_draftOrderDelete_order_channel;
isPaid: boolean;
}
export interface OrderDraftCancel_draftOrderDelete {

View file

@ -223,6 +223,7 @@ export interface OrderDraftFinalize_draftOrderComplete_order_fulfillments_lines_
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDraftFinalize_draftOrderComplete_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderDraftFinalize_draftOrderComplete_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDraftFinalize_draftOrderComplete_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderDraftFinalize_draftOrderComplete_order {
fulfillments: (OrderDraftFinalize_draftOrderComplete_order_fulfillments | null)[];
lines: (OrderDraftFinalize_draftOrderComplete_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderDraftFinalize_draftOrderComplete_order_shippingAddress | null;
shippingMethod: OrderDraftFinalize_draftOrderComplete_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderDraftFinalize_draftOrderComplete_order {
availableShippingMethods: (OrderDraftFinalize_draftOrderComplete_order_availableShippingMethods | null)[] | null;
invoices: (OrderDraftFinalize_draftOrderComplete_order_invoices | null)[] | null;
channel: OrderDraftFinalize_draftOrderComplete_order_channel;
isPaid: boolean;
}
export interface OrderDraftFinalize_draftOrderComplete {

View file

@ -223,6 +223,7 @@ export interface OrderDraftUpdate_draftOrderUpdate_order_fulfillments_lines_orde
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDraftUpdate_draftOrderUpdate_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderDraftUpdate_draftOrderUpdate_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderDraftUpdate_draftOrderUpdate_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderDraftUpdate_draftOrderUpdate_order {
fulfillments: (OrderDraftUpdate_draftOrderUpdate_order_fulfillments | null)[];
lines: (OrderDraftUpdate_draftOrderUpdate_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderDraftUpdate_draftOrderUpdate_order_shippingAddress | null;
shippingMethod: OrderDraftUpdate_draftOrderUpdate_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderDraftUpdate_draftOrderUpdate_order {
availableShippingMethods: (OrderDraftUpdate_draftOrderUpdate_order_availableShippingMethods | null)[] | null;
invoices: (OrderDraftUpdate_draftOrderUpdate_order_invoices | null)[] | null;
channel: OrderDraftUpdate_draftOrderUpdate_order_channel;
isPaid: boolean;
}
export interface OrderDraftUpdate_draftOrderUpdate {

View file

@ -32,6 +32,7 @@ export interface OrderFulfillData_order_lines_variant_attributes {
export interface OrderFulfillData_order_lines_variant_stocks_warehouse {
__typename: "Warehouse";
id: string;
name: string;
}
export interface OrderFulfillData_order_lines_variant_stocks {
@ -65,6 +66,7 @@ export interface OrderFulfillData_order_lines {
quantity: number;
allocations: OrderFulfillData_order_lines_allocations[] | null;
quantityFulfilled: number;
quantityToFulfill: number;
variant: OrderFulfillData_order_lines_variant | null;
thumbnail: OrderFulfillData_order_lines_thumbnail | null;
}
@ -72,6 +74,7 @@ export interface OrderFulfillData_order_lines {
export interface OrderFulfillData_order {
__typename: "Order";
id: string;
isPaid: boolean;
lines: (OrderFulfillData_order_lines | null)[];
number: string | null;
}

View file

@ -0,0 +1,18 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL query operation: OrderFulfillSettings
// ====================================================
export interface OrderFulfillSettings_shop {
__typename: "Shop";
fulfillmentAutoApprove: boolean;
fulfillmentAllowUnpaid: boolean;
}
export interface OrderFulfillSettings {
shop: OrderFulfillSettings_shop;
}

View file

@ -0,0 +1,528 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
import { OrderErrorCode, AddressTypeEnum, OrderDiscountType, DiscountValueTypeEnum, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderFulfillmentApprove
// ====================================================
export interface OrderFulfillmentApprove_orderFulfillmentApprove_errors {
__typename: "OrderError";
code: OrderErrorCode;
field: string | null;
addressType: AddressTypeEnum | null;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_metadata {
__typename: "MetadataItem";
key: string;
value: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_privateMetadata {
__typename: "MetadataItem";
key: string;
value: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_billingAddress_country {
__typename: "CountryDisplay";
code: string;
country: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_billingAddress {
__typename: "Address";
city: string;
cityArea: string;
companyName: string;
country: OrderFulfillmentApprove_orderFulfillmentApprove_order_billingAddress_country;
countryArea: string;
firstName: string;
id: string;
lastName: string;
phone: string | null;
postalCode: string;
streetAddress1: string;
streetAddress2: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_discounts_amount {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_discounts {
__typename: "OrderDiscount";
id: string;
type: OrderDiscountType;
calculationMode: DiscountValueTypeEnum;
value: any;
reason: string | null;
amount: OrderFulfillmentApprove_orderFulfillmentApprove_order_discounts_amount;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_events_discount_amount {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_events_discount_oldAmount {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_events_discount {
__typename: "OrderEventDiscountObject";
valueType: DiscountValueTypeEnum;
value: any;
reason: string | null;
amount: OrderFulfillmentApprove_orderFulfillmentApprove_order_events_discount_amount | null;
oldValueType: DiscountValueTypeEnum | null;
oldValue: any | null;
oldAmount: OrderFulfillmentApprove_orderFulfillmentApprove_order_events_discount_oldAmount | null;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_events_relatedOrder {
__typename: "Order";
id: string;
number: string | null;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_events_user {
__typename: "User";
id: string;
email: string;
firstName: string;
lastName: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_events_lines_discount_amount {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_events_lines_discount_oldAmount {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_events_lines_discount {
__typename: "OrderEventDiscountObject";
valueType: DiscountValueTypeEnum;
value: any;
reason: string | null;
amount: OrderFulfillmentApprove_orderFulfillmentApprove_order_events_lines_discount_amount | null;
oldValueType: DiscountValueTypeEnum | null;
oldValue: any | null;
oldAmount: OrderFulfillmentApprove_orderFulfillmentApprove_order_events_lines_discount_oldAmount | null;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_events_lines_orderLine {
__typename: "OrderLine";
id: string;
productName: string;
variantName: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_events_lines {
__typename: "OrderEventOrderLineObject";
quantity: number | null;
itemName: string | null;
discount: OrderFulfillmentApprove_orderFulfillmentApprove_order_events_lines_discount | null;
orderLine: OrderFulfillmentApprove_orderFulfillmentApprove_order_events_lines_orderLine | null;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_events {
__typename: "OrderEvent";
id: string;
amount: number | null;
shippingCostsIncluded: boolean | null;
date: any | null;
email: string | null;
emailType: OrderEventsEmailsEnum | null;
invoiceNumber: string | null;
discount: OrderFulfillmentApprove_orderFulfillmentApprove_order_events_discount | null;
relatedOrder: OrderFulfillmentApprove_orderFulfillmentApprove_order_events_relatedOrder | null;
message: string | null;
quantity: number | null;
transactionReference: string | null;
type: OrderEventsEnum | null;
user: OrderFulfillmentApprove_orderFulfillmentApprove_order_events_user | null;
lines: (OrderFulfillmentApprove_orderFulfillmentApprove_order_events_lines | null)[] | null;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_variant {
__typename: "ProductVariant";
id: string;
quantityAvailable: number;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_unitDiscount {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_undiscountedUnitPrice_gross {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_undiscountedUnitPrice_net {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_undiscountedUnitPrice {
__typename: "TaxedMoney";
currency: string;
gross: OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_undiscountedUnitPrice_gross;
net: OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_undiscountedUnitPrice_net;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_unitPrice_gross {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_unitPrice_net {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_unitPrice {
__typename: "TaxedMoney";
gross: OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_unitPrice_gross;
net: OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_unitPrice_net;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_thumbnail {
__typename: "Image";
url: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine {
__typename: "OrderLine";
id: string;
isShippingRequired: boolean;
variant: OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_variant | null;
productName: string;
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
unitDiscountType: DiscountValueTypeEnum | null;
undiscountedUnitPrice: OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_undiscountedUnitPrice;
unitPrice: OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_unitPrice;
thumbnail: OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine_thumbnail | null;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines {
__typename: "FulfillmentLine";
id: string;
quantity: number;
orderLine: OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines_orderLine | null;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_warehouse {
__typename: "Warehouse";
id: string;
name: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments {
__typename: "Fulfillment";
id: string;
lines: (OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_lines | null)[] | null;
fulfillmentOrder: number;
status: FulfillmentStatus;
trackingNumber: string;
warehouse: OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments_warehouse | null;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_variant {
__typename: "ProductVariant";
id: string;
quantityAvailable: number;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_unitDiscount {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_undiscountedUnitPrice_gross {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_undiscountedUnitPrice_net {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_undiscountedUnitPrice {
__typename: "TaxedMoney";
currency: string;
gross: OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_undiscountedUnitPrice_gross;
net: OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_undiscountedUnitPrice_net;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_unitPrice_gross {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_unitPrice_net {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_unitPrice {
__typename: "TaxedMoney";
gross: OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_unitPrice_gross;
net: OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_unitPrice_net;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_thumbnail {
__typename: "Image";
url: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_lines {
__typename: "OrderLine";
id: string;
isShippingRequired: boolean;
variant: OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_variant | null;
productName: string;
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
unitDiscountType: DiscountValueTypeEnum | null;
undiscountedUnitPrice: OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_undiscountedUnitPrice;
unitPrice: OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_unitPrice;
thumbnail: OrderFulfillmentApprove_orderFulfillmentApprove_order_lines_thumbnail | null;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_shippingAddress_country {
__typename: "CountryDisplay";
code: string;
country: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_shippingAddress {
__typename: "Address";
city: string;
cityArea: string;
companyName: string;
country: OrderFulfillmentApprove_orderFulfillmentApprove_order_shippingAddress_country;
countryArea: string;
firstName: string;
id: string;
lastName: string;
phone: string | null;
postalCode: string;
streetAddress1: string;
streetAddress2: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_shippingMethod {
__typename: "ShippingMethod";
id: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_shippingPrice_gross {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_shippingPrice {
__typename: "TaxedMoney";
gross: OrderFulfillmentApprove_orderFulfillmentApprove_order_shippingPrice_gross;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_subtotal_gross {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_subtotal_net {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_subtotal {
__typename: "TaxedMoney";
gross: OrderFulfillmentApprove_orderFulfillmentApprove_order_subtotal_gross;
net: OrderFulfillmentApprove_orderFulfillmentApprove_order_subtotal_net;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_total_gross {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_total_net {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_total_tax {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_total {
__typename: "TaxedMoney";
gross: OrderFulfillmentApprove_orderFulfillmentApprove_order_total_gross;
net: OrderFulfillmentApprove_orderFulfillmentApprove_order_total_net;
tax: OrderFulfillmentApprove_orderFulfillmentApprove_order_total_tax;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_totalAuthorized {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_totalCaptured {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_undiscountedTotal_net {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_undiscountedTotal_gross {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_undiscountedTotal {
__typename: "TaxedMoney";
net: OrderFulfillmentApprove_orderFulfillmentApprove_order_undiscountedTotal_net;
gross: OrderFulfillmentApprove_orderFulfillmentApprove_order_undiscountedTotal_gross;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_user {
__typename: "User";
id: string;
email: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_availableShippingMethods_price {
__typename: "Money";
amount: number;
currency: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_availableShippingMethods {
__typename: "ShippingMethod";
id: string;
name: string;
price: OrderFulfillmentApprove_orderFulfillmentApprove_order_availableShippingMethods_price | null;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order_channel {
__typename: "Channel";
isActive: boolean;
id: string;
name: string;
currencyCode: string;
slug: string;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove_order {
__typename: "Order";
id: string;
metadata: (OrderFulfillmentApprove_orderFulfillmentApprove_order_metadata | null)[];
privateMetadata: (OrderFulfillmentApprove_orderFulfillmentApprove_order_privateMetadata | null)[];
billingAddress: OrderFulfillmentApprove_orderFulfillmentApprove_order_billingAddress | null;
isShippingRequired: boolean;
canFinalize: boolean;
created: any;
customerNote: string;
discounts: OrderFulfillmentApprove_orderFulfillmentApprove_order_discounts[] | null;
events: (OrderFulfillmentApprove_orderFulfillmentApprove_order_events | null)[] | null;
fulfillments: (OrderFulfillmentApprove_orderFulfillmentApprove_order_fulfillments | null)[];
lines: (OrderFulfillmentApprove_orderFulfillmentApprove_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderFulfillmentApprove_orderFulfillmentApprove_order_shippingAddress | null;
shippingMethod: OrderFulfillmentApprove_orderFulfillmentApprove_order_shippingMethod | null;
shippingMethodName: string | null;
shippingPrice: OrderFulfillmentApprove_orderFulfillmentApprove_order_shippingPrice;
status: OrderStatus;
subtotal: OrderFulfillmentApprove_orderFulfillmentApprove_order_subtotal;
total: OrderFulfillmentApprove_orderFulfillmentApprove_order_total;
actions: (OrderAction | null)[];
totalAuthorized: OrderFulfillmentApprove_orderFulfillmentApprove_order_totalAuthorized;
totalCaptured: OrderFulfillmentApprove_orderFulfillmentApprove_order_totalCaptured;
undiscountedTotal: OrderFulfillmentApprove_orderFulfillmentApprove_order_undiscountedTotal;
user: OrderFulfillmentApprove_orderFulfillmentApprove_order_user | null;
userEmail: string | null;
availableShippingMethods: (OrderFulfillmentApprove_orderFulfillmentApprove_order_availableShippingMethods | null)[] | null;
invoices: (OrderFulfillmentApprove_orderFulfillmentApprove_order_invoices | null)[] | null;
channel: OrderFulfillmentApprove_orderFulfillmentApprove_order_channel;
}
export interface OrderFulfillmentApprove_orderFulfillmentApprove {
__typename: "FulfillmentApprove";
errors: OrderFulfillmentApprove_orderFulfillmentApprove_errors[];
order: OrderFulfillmentApprove_orderFulfillmentApprove_order | null;
}
export interface OrderFulfillmentApprove {
orderFulfillmentApprove: OrderFulfillmentApprove_orderFulfillmentApprove | null;
}
export interface OrderFulfillmentApproveVariables {
id: string;
notifyCustomer: boolean;
}

View file

@ -223,6 +223,7 @@ export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_fulfillment
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderFulfillmentCancel_orderFulfillmentCancel_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderFulfillmentCancel_orderFulfillmentCancel_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderFulfillmentCancel_orderFulfillmentCancel_order {
fulfillments: (OrderFulfillmentCancel_orderFulfillmentCancel_order_fulfillments | null)[];
lines: (OrderFulfillmentCancel_orderFulfillmentCancel_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderFulfillmentCancel_orderFulfillmentCancel_order_shippingAddress | null;
shippingMethod: OrderFulfillmentCancel_orderFulfillmentCancel_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderFulfillmentCancel_orderFulfillmentCancel_order {
availableShippingMethods: (OrderFulfillmentCancel_orderFulfillmentCancel_order_availableShippingMethods | null)[] | null;
invoices: (OrderFulfillmentCancel_orderFulfillmentCancel_order_invoices | null)[] | null;
channel: OrderFulfillmentCancel_orderFulfillmentCancel_order_channel;
isPaid: boolean;
}
export interface OrderFulfillmentCancel_orderFulfillmentCancel {

View file

@ -79,6 +79,7 @@ export interface OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_f
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_fulfillment_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_o
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -413,6 +415,7 @@ export interface OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_o
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -585,6 +588,7 @@ export interface OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_o
fulfillments: (OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_fulfillments | null)[];
lines: (OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_shippingAddress | null;
shippingMethod: OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_shippingMethod | null;
@ -602,7 +606,6 @@ export interface OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_o
availableShippingMethods: (OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_availableShippingMethods | null)[] | null;
invoices: (OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_invoices | null)[] | null;
channel: OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts_order_channel;
isPaid: boolean;
}
export interface OrderFulfillmentRefundProducts_orderFulfillmentRefundProducts {

View file

@ -223,6 +223,7 @@ export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_o
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_o
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_o
fulfillments: (OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_fulfillments | null)[];
lines: (OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_shippingAddress | null;
shippingMethod: OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_o
availableShippingMethods: (OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_availableShippingMethods | null)[] | null;
invoices: (OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_invoices | null)[] | null;
channel: OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_channel;
isPaid: boolean;
}
export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking {

View file

@ -223,6 +223,7 @@ export interface OrderLineDelete_orderLineDelete_order_fulfillments_lines_orderL
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderLineDelete_orderLineDelete_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderLineDelete_orderLineDelete_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderLineDelete_orderLineDelete_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderLineDelete_orderLineDelete_order {
fulfillments: (OrderLineDelete_orderLineDelete_order_fulfillments | null)[];
lines: (OrderLineDelete_orderLineDelete_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderLineDelete_orderLineDelete_order_shippingAddress | null;
shippingMethod: OrderLineDelete_orderLineDelete_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderLineDelete_orderLineDelete_order {
availableShippingMethods: (OrderLineDelete_orderLineDelete_order_availableShippingMethods | null)[] | null;
invoices: (OrderLineDelete_orderLineDelete_order_invoices | null)[] | null;
channel: OrderLineDelete_orderLineDelete_order_channel;
isPaid: boolean;
}
export interface OrderLineDelete_orderLineDelete {

View file

@ -223,6 +223,7 @@ export interface OrderLineDiscountRemove_orderLineDiscountRemove_order_fulfillme
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderLineDiscountRemove_orderLineDiscountRemove_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderLineDiscountRemove_orderLineDiscountRemove_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderLineDiscountRemove_orderLineDiscountRemove_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderLineDiscountRemove_orderLineDiscountRemove_order {
fulfillments: (OrderLineDiscountRemove_orderLineDiscountRemove_order_fulfillments | null)[];
lines: (OrderLineDiscountRemove_orderLineDiscountRemove_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderLineDiscountRemove_orderLineDiscountRemove_order_shippingAddress | null;
shippingMethod: OrderLineDiscountRemove_orderLineDiscountRemove_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderLineDiscountRemove_orderLineDiscountRemove_order {
availableShippingMethods: (OrderLineDiscountRemove_orderLineDiscountRemove_order_availableShippingMethods | null)[] | null;
invoices: (OrderLineDiscountRemove_orderLineDiscountRemove_order_invoices | null)[] | null;
channel: OrderLineDiscountRemove_orderLineDiscountRemove_order_channel;
isPaid: boolean;
}
export interface OrderLineDiscountRemove_orderLineDiscountRemove {

View file

@ -223,6 +223,7 @@ export interface OrderLineDiscountUpdate_orderLineDiscountUpdate_order_fulfillme
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderLineDiscountUpdate_orderLineDiscountUpdate_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderLineDiscountUpdate_orderLineDiscountUpdate_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderLineDiscountUpdate_orderLineDiscountUpdate_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderLineDiscountUpdate_orderLineDiscountUpdate_order {
fulfillments: (OrderLineDiscountUpdate_orderLineDiscountUpdate_order_fulfillments | null)[];
lines: (OrderLineDiscountUpdate_orderLineDiscountUpdate_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderLineDiscountUpdate_orderLineDiscountUpdate_order_shippingAddress | null;
shippingMethod: OrderLineDiscountUpdate_orderLineDiscountUpdate_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderLineDiscountUpdate_orderLineDiscountUpdate_order {
availableShippingMethods: (OrderLineDiscountUpdate_orderLineDiscountUpdate_order_availableShippingMethods | null)[] | null;
invoices: (OrderLineDiscountUpdate_orderLineDiscountUpdate_order_invoices | null)[] | null;
channel: OrderLineDiscountUpdate_orderLineDiscountUpdate_order_channel;
isPaid: boolean;
}
export interface OrderLineDiscountUpdate_orderLineDiscountUpdate {

View file

@ -223,6 +223,7 @@ export interface OrderLineUpdate_orderLineUpdate_order_fulfillments_lines_orderL
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderLineUpdate_orderLineUpdate_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderLineUpdate_orderLineUpdate_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderLineUpdate_orderLineUpdate_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderLineUpdate_orderLineUpdate_order {
fulfillments: (OrderLineUpdate_orderLineUpdate_order_fulfillments | null)[];
lines: (OrderLineUpdate_orderLineUpdate_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderLineUpdate_orderLineUpdate_order_shippingAddress | null;
shippingMethod: OrderLineUpdate_orderLineUpdate_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderLineUpdate_orderLineUpdate_order {
availableShippingMethods: (OrderLineUpdate_orderLineUpdate_order_availableShippingMethods | null)[] | null;
invoices: (OrderLineUpdate_orderLineUpdate_order_invoices | null)[] | null;
channel: OrderLineUpdate_orderLineUpdate_order_channel;
isPaid: boolean;
}
export interface OrderLineUpdate_orderLineUpdate {

View file

@ -223,6 +223,7 @@ export interface OrderLinesAdd_orderLinesCreate_order_fulfillments_lines_orderLi
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderLinesAdd_orderLinesCreate_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderLinesAdd_orderLinesCreate_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderLinesAdd_orderLinesCreate_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderLinesAdd_orderLinesCreate_order {
fulfillments: (OrderLinesAdd_orderLinesCreate_order_fulfillments | null)[];
lines: (OrderLinesAdd_orderLinesCreate_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderLinesAdd_orderLinesCreate_order_shippingAddress | null;
shippingMethod: OrderLinesAdd_orderLinesCreate_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderLinesAdd_orderLinesCreate_order {
availableShippingMethods: (OrderLinesAdd_orderLinesCreate_order_availableShippingMethods | null)[] | null;
invoices: (OrderLinesAdd_orderLinesCreate_order_invoices | null)[] | null;
channel: OrderLinesAdd_orderLinesCreate_order_channel;
isPaid: boolean;
}
export interface OrderLinesAdd_orderLinesCreate {

View file

@ -223,6 +223,7 @@ export interface OrderMarkAsPaid_orderMarkAsPaid_order_fulfillments_lines_orderL
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderMarkAsPaid_orderMarkAsPaid_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderMarkAsPaid_orderMarkAsPaid_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderMarkAsPaid_orderMarkAsPaid_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderMarkAsPaid_orderMarkAsPaid_order {
fulfillments: (OrderMarkAsPaid_orderMarkAsPaid_order_fulfillments | null)[];
lines: (OrderMarkAsPaid_orderMarkAsPaid_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderMarkAsPaid_orderMarkAsPaid_order_shippingAddress | null;
shippingMethod: OrderMarkAsPaid_orderMarkAsPaid_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderMarkAsPaid_orderMarkAsPaid_order {
availableShippingMethods: (OrderMarkAsPaid_orderMarkAsPaid_order_availableShippingMethods | null)[] | null;
invoices: (OrderMarkAsPaid_orderMarkAsPaid_order_invoices | null)[] | null;
channel: OrderMarkAsPaid_orderMarkAsPaid_order_channel;
isPaid: boolean;
}
export interface OrderMarkAsPaid_orderMarkAsPaid {

View file

@ -223,6 +223,7 @@ export interface OrderRefund_orderRefund_order_fulfillments_lines_orderLine {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderRefund_orderRefund_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderRefund_orderRefund_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderRefund_orderRefund_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderRefund_orderRefund_order {
fulfillments: (OrderRefund_orderRefund_order_fulfillments | null)[];
lines: (OrderRefund_orderRefund_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderRefund_orderRefund_order_shippingAddress | null;
shippingMethod: OrderRefund_orderRefund_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderRefund_orderRefund_order {
availableShippingMethods: (OrderRefund_orderRefund_order_availableShippingMethods | null)[] | null;
invoices: (OrderRefund_orderRefund_order_invoices | null)[] | null;
channel: OrderRefund_orderRefund_order_channel;
isPaid: boolean;
}
export interface OrderRefund_orderRefund {

View file

@ -60,7 +60,7 @@ export interface OrderRefundData_order_lines {
quantity: number;
unitPrice: OrderRefundData_order_lines_unitPrice;
thumbnail: OrderRefundData_order_lines_thumbnail | null;
quantityFulfilled: number;
quantityToFulfill: number;
}
export interface OrderRefundData_order_fulfillments_lines_orderLine_unitPrice_gross {

View file

@ -12,6 +12,13 @@ export interface OrderSettings_orderSettings {
automaticallyConfirmAllNewOrders: boolean;
}
export interface OrderSettings_shop {
__typename: "Shop";
fulfillmentAutoApprove: boolean;
fulfillmentAllowUnpaid: boolean;
}
export interface OrderSettings {
orderSettings: OrderSettings_orderSettings | null;
shop: OrderSettings_shop;
}

View file

@ -3,7 +3,7 @@
// @generated
// This file was automatically generated and should not be edited.
import { OrderSettingsUpdateInput, OrderSettingsErrorCode } from "./../../types/globalTypes";
import { OrderSettingsUpdateInput, ShopSettingsInput, OrderSettingsErrorCode, ShopErrorCode } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderSettingsUpdate
@ -26,10 +26,30 @@ export interface OrderSettingsUpdate_orderSettingsUpdate {
orderSettings: OrderSettingsUpdate_orderSettingsUpdate_orderSettings | null;
}
export interface OrderSettingsUpdate_shopSettingsUpdate_errors {
__typename: "ShopError";
code: ShopErrorCode;
field: string | null;
}
export interface OrderSettingsUpdate_shopSettingsUpdate_shop {
__typename: "Shop";
fulfillmentAutoApprove: boolean;
fulfillmentAllowUnpaid: boolean;
}
export interface OrderSettingsUpdate_shopSettingsUpdate {
__typename: "ShopSettingsUpdate";
errors: OrderSettingsUpdate_shopSettingsUpdate_errors[];
shop: OrderSettingsUpdate_shopSettingsUpdate_shop | null;
}
export interface OrderSettingsUpdate {
orderSettingsUpdate: OrderSettingsUpdate_orderSettingsUpdate | null;
shopSettingsUpdate: OrderSettingsUpdate_shopSettingsUpdate | null;
}
export interface OrderSettingsUpdateVariables {
input: OrderSettingsUpdateInput;
orderSettingsInput: OrderSettingsUpdateInput;
shopSettingsInput: ShopSettingsInput;
}

View file

@ -285,6 +285,7 @@ export interface OrderShippingMethodUpdate_orderUpdateShipping_order_fulfillment
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderShippingMethodUpdate_orderUpdateShipping_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -380,6 +381,7 @@ export interface OrderShippingMethodUpdate_orderUpdateShipping_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderShippingMethodUpdate_orderUpdateShipping_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -503,6 +505,7 @@ export interface OrderShippingMethodUpdate_orderUpdateShipping_order {
fulfillments: (OrderShippingMethodUpdate_orderUpdateShipping_order_fulfillments | null)[];
lines: (OrderShippingMethodUpdate_orderUpdateShipping_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderShippingMethodUpdate_orderUpdateShipping_order_shippingAddress | null;
status: OrderStatus;
@ -515,7 +518,6 @@ export interface OrderShippingMethodUpdate_orderUpdateShipping_order {
userEmail: string | null;
invoices: (OrderShippingMethodUpdate_orderUpdateShipping_order_invoices | null)[] | null;
channel: OrderShippingMethodUpdate_orderUpdateShipping_order_channel;
isPaid: boolean;
}
export interface OrderShippingMethodUpdate_orderUpdateShipping {

View file

@ -223,6 +223,7 @@ export interface OrderUpdate_orderUpdate_order_fulfillments_lines_orderLine {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderUpdate_orderUpdate_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderUpdate_orderUpdate_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderUpdate_orderUpdate_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderUpdate_orderUpdate_order {
fulfillments: (OrderUpdate_orderUpdate_order_fulfillments | null)[];
lines: (OrderUpdate_orderUpdate_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderUpdate_orderUpdate_order_shippingAddress | null;
shippingMethod: OrderUpdate_orderUpdate_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderUpdate_orderUpdate_order {
availableShippingMethods: (OrderUpdate_orderUpdate_order_availableShippingMethods | null)[] | null;
invoices: (OrderUpdate_orderUpdate_order_invoices | null)[] | null;
channel: OrderUpdate_orderUpdate_order_channel;
isPaid: boolean;
}
export interface OrderUpdate_orderUpdate {

View file

@ -223,6 +223,7 @@ export interface OrderVoid_orderVoid_order_fulfillments_lines_orderLine {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderVoid_orderVoid_order_fulfillments_lines_orderLine_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -318,6 +319,7 @@ export interface OrderVoid_orderVoid_order_lines {
productSku: string;
quantity: number;
quantityFulfilled: number;
quantityToFulfill: number;
unitDiscount: OrderVoid_orderVoid_order_lines_unitDiscount;
unitDiscountValue: any;
unitDiscountReason: string | null;
@ -490,6 +492,7 @@ export interface OrderVoid_orderVoid_order {
fulfillments: (OrderVoid_orderVoid_order_fulfillments | null)[];
lines: (OrderVoid_orderVoid_order_lines | null)[];
number: string | null;
isPaid: boolean;
paymentStatus: PaymentChargeStatusEnum;
shippingAddress: OrderVoid_orderVoid_order_shippingAddress | null;
shippingMethod: OrderVoid_orderVoid_order_shippingMethod | null;
@ -507,7 +510,6 @@ export interface OrderVoid_orderVoid_order {
availableShippingMethods: (OrderVoid_orderVoid_order_availableShippingMethods | null)[] | null;
invoices: (OrderVoid_orderVoid_order_invoices | null)[] | null;
channel: OrderVoid_orderVoid_order_channel;
isPaid: boolean;
}
export interface OrderVoid_orderVoid {

View file

@ -97,6 +97,7 @@ export const orderPath = (id: string) => urlJoin(orderSectionUrl, id);
export type OrderUrlDialog =
| "add-order-line"
| "approve-fulfillment"
| "cancel"
| "cancel-fulfillment"
| "capture"

View file

@ -22,7 +22,9 @@ import {
getRefundedLinesPriceSum,
getReplacedProductsAmount,
getReturnSelectedProductsAmount,
getWarehousesFromOrderLines,
mergeRepeatedOrderLines,
OrderLineWithStockWarehouses,
OrderWithTotalAndTotalCaptured
} from "./data";
@ -67,6 +69,77 @@ const orderBase: OrderDetails_order = {
}
};
describe("Get warehouses used in order", () => {
it("is able to calculate number of used warehouses from order", () => {
const lines: OrderLineWithStockWarehouses[] = [
{
variant: {
stocks: [
{
warehouse: {
__typename: "Warehouse",
id: "warehouse-1",
name: "Warehouse 1"
}
},
{
warehouse: {
__typename: "Warehouse",
id: "warehouse-2",
name: "Warehouse 2"
}
}
]
}
},
{
variant: {
stocks: [
{
warehouse: {
__typename: "Warehouse",
id: "warehouse-1",
name: "Warehouse 1"
}
},
{
warehouse: {
__typename: "Warehouse",
id: "warehouse-2",
name: "Warehouse 2"
}
}
]
}
},
{
variant: {
stocks: [
{
warehouse: {
__typename: "Warehouse",
id: "warehouse-2",
name: "Warehouse 2"
}
},
{
warehouse: {
__typename: "Warehouse",
id: "warehouse-3",
name: "Warehouse 3"
}
}
]
}
}
];
const orderWarehouses = getWarehousesFromOrderLines(lines);
expect(orderWarehouses.length).toBe(3);
});
});
describe("Get previously refunded price", () => {
it("is able to calculate refunded price from order", () => {
const order: OrderWithTotalAndTotalCaptured = {
@ -98,7 +171,7 @@ describe("Get refunded lines price sum", () => {
id: "1",
productName: "Milk 1",
quantity: 1,
quantityFulfilled: 1,
quantityToFulfill: 0,
thumbnail: undefined,
unitPrice: {
__typename: "TaxedMoney",
@ -114,7 +187,7 @@ describe("Get refunded lines price sum", () => {
id: "2",
productName: "Milk 2",
quantity: 2,
quantityFulfilled: 2,
quantityToFulfill: 0,
thumbnail: undefined,
unitPrice: {
__typename: "TaxedMoney",
@ -130,7 +203,7 @@ describe("Get refunded lines price sum", () => {
id: "3",
productName: "Milk 3",
quantity: 4,
quantityFulfilled: 4,
quantityToFulfill: 0,
thumbnail: undefined,
unitPrice: {
__typename: "TaxedMoney",
@ -464,6 +537,7 @@ describe("Get the total value of all replaced products", () => {
productSku: "lake-tunes-mp3",
quantity: 2,
quantityFulfilled: 2,
quantityToFulfill: 0,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -518,6 +592,7 @@ describe("Get the total value of all replaced products", () => {
productSku: "lake-tunes-mp3",
quantity: 10,
quantityFulfilled: 2,
quantityToFulfill: 8,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -572,6 +647,7 @@ describe("Get the total value of all replaced products", () => {
productSku: "29810068",
quantity: 6,
quantityFulfilled: 1,
quantityToFulfill: 5,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -632,6 +708,7 @@ describe("Get the total value of all replaced products", () => {
productSku: "lake-tunes-mp3",
quantity: 20,
quantityFulfilled: 6,
quantityToFulfill: 14,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -691,6 +768,7 @@ describe("Get the total value of all replaced products", () => {
productSku: "lake-tunes-mp3",
quantity: 25,
quantityFulfilled: 8,
quantityToFulfill: 17,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -750,6 +828,7 @@ describe("Get the total value of all replaced products", () => {
productSku: "29810068",
quantity: 10,
quantityFulfilled: 3,
quantityToFulfill: 7,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -809,6 +888,7 @@ describe("Get the total value of all replaced products", () => {
productSku: "lake-tunes-mp3",
quantity: 20,
quantityFulfilled: 6,
quantityToFulfill: 14,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -868,6 +948,7 @@ describe("Get the total value of all replaced products", () => {
productSku: "lake-tunes-mp3",
quantity: 25,
quantityFulfilled: 8,
quantityToFulfill: 17,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -1061,6 +1142,7 @@ describe("Get the total value of all selected products", () => {
productSku: "lake-tunes-mp3",
quantity: 2,
quantityFulfilled: 2,
quantityToFulfill: 0,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -1115,6 +1197,7 @@ describe("Get the total value of all selected products", () => {
productSku: "lake-tunes-mp3",
quantity: 10,
quantityFulfilled: 2,
quantityToFulfill: 8,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -1169,6 +1252,7 @@ describe("Get the total value of all selected products", () => {
productSku: "29810068",
quantity: 6,
quantityFulfilled: 1,
quantityToFulfill: 5,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -1229,6 +1313,7 @@ describe("Get the total value of all selected products", () => {
productSku: "lake-tunes-mp3",
quantity: 20,
quantityFulfilled: 6,
quantityToFulfill: 14,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -1288,6 +1373,7 @@ describe("Get the total value of all selected products", () => {
productSku: "lake-tunes-mp3",
quantity: 25,
quantityFulfilled: 8,
quantityToFulfill: 17,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -1347,6 +1433,7 @@ describe("Get the total value of all selected products", () => {
productSku: "29810068",
quantity: 10,
quantityFulfilled: 3,
quantityToFulfill: 7,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -1531,6 +1618,7 @@ describe("Merge repeated order lines of fulfillment lines", () => {
productSku: "lake-tunes-mp3",
quantity: 2,
quantityFulfilled: 2,
quantityToFulfill: 0,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -1590,6 +1678,7 @@ describe("Merge repeated order lines of fulfillment lines", () => {
productSku: "lake-tunes-mp3",
quantity: 2,
quantityFulfilled: 2,
quantityToFulfill: 0,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",
@ -1649,6 +1738,7 @@ describe("Merge repeated order lines of fulfillment lines", () => {
productSku: "29810068",
quantity: 3,
quantityFulfilled: 1,
quantityToFulfill: 2,
undiscountedUnitPrice: {
__typename: "TaxedMoney",
currency: "USD",

View file

@ -1,5 +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 {
LineItemData,
@ -9,11 +11,13 @@ import {
getAllOrderFulfilledLines,
getById
} from "../components/OrderReturnPage/utils";
import { FulfillOrder_orderFulfill_errors } from "../types/FulfillOrder";
import {
OrderDetails_order,
OrderDetails_order_fulfillments_lines,
OrderDetails_order_lines
} from "../types/OrderDetails";
import { OrderFulfillData_order_lines } from "../types/OrderFulfillData";
import {
OrderRefundData_order,
OrderRefundData_order_fulfillments,
@ -25,6 +29,32 @@ export type OrderWithTotalAndTotalCaptured = Pick<
"total" | "totalCaptured"
>;
export interface OrderLineWithStockWarehouses {
variant?: {
stocks: Array<{ warehouse: WarehouseFragment }>;
};
}
export function getToFulfillOrderLines(lines?: OrderFulfillData_order_lines[]) {
return lines?.filter(line => line.quantityToFulfill > 0) || [];
}
export function getWarehousesFromOrderLines<
T extends OrderLineWithStockWarehouses
>(lines?: T[]) {
return lines?.reduce(
(warehouses, line) =>
line.variant?.stocks?.reduce(
(warehouses, stock) =>
warehouses.some(getById(stock.warehouse.id))
? warehouses
: [...warehouses, stock.warehouse],
warehouses
),
[] as WarehouseFragment[]
);
}
export function getPreviouslyRefundedPrice(
order: OrderWithTotalAndTotalCaptured
): IMoney {
@ -208,3 +238,28 @@ export function mergeRepeatedOrderLines(
return prev;
}, Array<OrderDetails_order_fulfillments_lines>());
}
export const isStockError = (
overfulfill: boolean,
formsetStock: { quantity: number },
availableQuantity: number,
warehouse: WarehouseFragment,
line: OrderFulfillData_order_lines,
errors: FulfillOrder_orderFulfill_errors[]
) => {
if (overfulfill) {
return true;
}
const isQuantityLargerThanAvailable =
line.variant.trackInventory && formsetStock.quantity > availableQuantity;
const isError = !!errors?.find(
err =>
err.warehouse === warehouse.id &&
err.orderLines.find((id: string) => id === line.id) &&
err.code === OrderErrorCode.INSUFFICIENT_STOCK
);
return isQuantityLargerThanAvailable || isError;
};

View file

@ -1,6 +1,7 @@
import messages from "@saleor/containers/BackgroundTasks/messages";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import { OrderFulfillmentApprove } from "@saleor/orders/types/OrderFulfillmentApprove";
import getOrderErrorMessage from "@saleor/utils/errors/order";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import React from "react";
@ -32,6 +33,7 @@ interface OrderDetailsMessages {
handleDraftUpdate: (data: OrderDraftUpdate) => void;
handleNoteAdd: (data: OrderAddNote) => void;
handleOrderCancel: (data: OrderCancel) => void;
handleOrderFulfillmentApprove: (data: OrderFulfillmentApprove) => void;
handleOrderFulfillmentCancel: (data: OrderFulfillmentCancel) => void;
handleOrderFulfillmentUpdate: (
data: OrderFulfillmentUpdateTracking
@ -215,6 +217,18 @@ export const OrderDetailsMessages: React.FC<OrderDetailsMessages> = ({
);
}
};
const handleOrderFulfillmentApprove = (data: OrderFulfillmentApprove) => {
const errs = data.orderFulfillmentApprove?.errors;
if (errs.length === 0) {
pushMessage({
status: "success",
text: intl.formatMessage({
defaultMessage: "Fulfillment successfully approved"
})
});
closeModal();
}
};
const handleOrderFulfillmentCancel = (data: OrderFulfillmentCancel) => {
const errs = data.orderFulfillmentCancel?.errors;
if (errs.length === 0) {
@ -299,6 +313,7 @@ export const OrderDetailsMessages: React.FC<OrderDetailsMessages> = ({
handleInvoiceSend,
handleNoteAdd,
handleOrderCancel,
handleOrderFulfillmentApprove,
handleOrderFulfillmentCancel,
handleOrderFulfillmentUpdate,
handleOrderLineDelete,

View file

@ -2,7 +2,13 @@ import { WindowTitle } from "@saleor/components/WindowTitle";
import useNavigator from "@saleor/hooks/useNavigator";
import useUser from "@saleor/hooks/useUser";
import OrderCannotCancelOrderDialog from "@saleor/orders/components/OrderCannotCancelOrderDialog";
import OrderFulfillmentApproveDialog from "@saleor/orders/components/OrderFulfillmentApproveDialog";
import OrderInvoiceEmailSendDialog from "@saleor/orders/components/OrderInvoiceEmailSendDialog";
import {
OrderFulfillmentApprove,
OrderFulfillmentApproveVariables
} from "@saleor/orders/types/OrderFulfillmentApprove";
import { PartialMutationProviderOutput } from "@saleor/types";
import { mapEdgesToItems } from "@saleor/utils/maps";
import { useWarehouseList } from "@saleor/warehouses/queries";
import React from "react";
@ -39,6 +45,10 @@ interface OrderNormalDetailsProps {
orderPaymentMarkAsPaid: any;
orderVoid: any;
orderPaymentCapture: any;
orderFulfillmentApprove: PartialMutationProviderOutput<
OrderFulfillmentApprove,
OrderFulfillmentApproveVariables
>;
orderFulfillmentCancel: any;
orderFulfillmentUpdateTracking: any;
orderInvoiceSend: any;
@ -59,6 +69,7 @@ export const OrderNormalDetails: React.FC<OrderNormalDetailsProps> = ({
orderPaymentMarkAsPaid,
orderVoid,
orderPaymentCapture,
orderFulfillmentApprove,
orderFulfillmentCancel,
orderFulfillmentUpdateTracking,
orderInvoiceSend,
@ -68,6 +79,7 @@ export const OrderNormalDetails: React.FC<OrderNormalDetailsProps> = ({
closeModal
}) => {
const order = data?.order;
const shop = data?.shop;
const navigate = useNavigator();
const { user } = useUser();
@ -108,6 +120,7 @@ export const OrderNormalDetails: React.FC<OrderNormalDetailsProps> = ({
}
onBack={handleBack}
order={order}
shop={shop}
saveButtonBarState={getMutationState(
updateMetadataOpts.called || updatePrivateMetadataOpts.called,
updateMetadataOpts.loading || updatePrivateMetadataOpts.loading,
@ -124,6 +137,14 @@ export const OrderNormalDetails: React.FC<OrderNormalDetailsProps> = ({
userPermissions={user?.userPermissions || []}
onOrderCancel={() => openModal("cancel")}
onOrderFulfill={() => navigate(orderFulfillUrl(id))}
onFulfillmentApprove={fulfillmentId =>
navigate(
orderUrl(id, {
action: "approve-fulfillment",
id: fulfillmentId
})
)
}
onFulfillmentCancel={fulfillmentId =>
navigate(
orderUrl(id, {
@ -219,6 +240,21 @@ export const OrderNormalDetails: React.FC<OrderNormalDetailsProps> = ({
})
}
/>
<OrderFulfillmentApproveDialog
confirmButtonState={orderFulfillmentApprove.opts.status}
errors={
orderFulfillmentApprove.opts.data?.orderFulfillmentApprove.errors ||
[]
}
open={params.action === "approve-fulfillment"}
onConfirm={({ notifyCustomer }) =>
orderFulfillmentApprove.mutate({
id: params.id,
notifyCustomer
})
}
onClose={closeModal}
/>
<OrderFulfillmentCancelDialog
confirmButtonState={orderFulfillmentCancel.opts.status}
errors={

View file

@ -3,9 +3,15 @@ import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
import useNavigator from "@saleor/hooks/useNavigator";
import useUser from "@saleor/hooks/useUser";
import OrderCannotCancelOrderDialog from "@saleor/orders/components/OrderCannotCancelOrderDialog";
import OrderFulfillmentApproveDialog from "@saleor/orders/components/OrderFulfillmentApproveDialog";
import OrderInvoiceEmailSendDialog from "@saleor/orders/components/OrderInvoiceEmailSendDialog";
import {
OrderFulfillmentApprove,
OrderFulfillmentApproveVariables
} from "@saleor/orders/types/OrderFulfillmentApprove";
import { OrderDiscountProvider } from "@saleor/products/components/OrderDiscountProviders/OrderDiscountProvider";
import { OrderLineDiscountProvider } from "@saleor/products/components/OrderDiscountProviders/OrderLineDiscountProvider";
import { PartialMutationProviderOutput } from "@saleor/types";
import { mapEdgesToItems } from "@saleor/utils/maps";
import { useWarehouseList } from "@saleor/warehouses/queries";
import React from "react";
@ -49,6 +55,10 @@ interface OrderUnconfirmedDetailsProps {
orderPaymentMarkAsPaid: any;
orderVoid: any;
orderPaymentCapture: any;
orderFulfillmentApprove: PartialMutationProviderOutput<
OrderFulfillmentApprove,
OrderFulfillmentApproveVariables
>;
orderFulfillmentCancel: any;
orderFulfillmentUpdateTracking: any;
orderInvoiceSend: any;
@ -73,6 +83,7 @@ export const OrderUnconfirmedDetails: React.FC<OrderUnconfirmedDetailsProps> = (
orderPaymentMarkAsPaid,
orderVoid,
orderPaymentCapture,
orderFulfillmentApprove,
orderFulfillmentCancel,
orderFulfillmentUpdateTracking,
orderInvoiceSend,
@ -82,6 +93,7 @@ export const OrderUnconfirmedDetails: React.FC<OrderUnconfirmedDetailsProps> = (
closeModal
}) => {
const order = data.order;
const shop = data.shop;
const navigate = useNavigator();
const { user } = useUser();
@ -131,6 +143,7 @@ export const OrderUnconfirmedDetails: React.FC<OrderUnconfirmedDetailsProps> = (
}
onBack={handleBack}
order={order}
shop={shop}
onOrderLineAdd={() => openModal("add-order-line")}
onOrderLineChange={(id, data) =>
orderLineUpdate.mutate({
@ -156,6 +169,14 @@ export const OrderUnconfirmedDetails: React.FC<OrderUnconfirmedDetailsProps> = (
userPermissions={user?.userPermissions || []}
onOrderCancel={() => openModal("cancel")}
onOrderFulfill={() => navigate(orderFulfillUrl(id))}
onFulfillmentApprove={fulfillmentId =>
navigate(
orderUrl(id, {
action: "approve-fulfillment",
id: fulfillmentId
})
)
}
onFulfillmentCancel={fulfillmentId =>
navigate(
orderUrl(id, {
@ -292,6 +313,21 @@ export const OrderUnconfirmedDetails: React.FC<OrderUnconfirmedDetailsProps> = (
})
}
/>
<OrderFulfillmentApproveDialog
confirmButtonState={orderFulfillmentApprove.opts.status}
errors={
orderFulfillmentApprove.opts.data?.orderFulfillmentApprove.errors ||
[]
}
open={params.action === "approve-fulfillment"}
onConfirm={({ notifyCustomer }) =>
orderFulfillmentApprove.mutate({
id: params.id,
notifyCustomer
})
}
onClose={closeModal}
/>
<OrderFulfillmentCancelDialog
confirmButtonState={orderFulfillmentCancel.opts.status}
errors={

View file

@ -121,6 +121,9 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
onOrderLineDelete={orderMessages.handleOrderLineDelete}
onOrderLinesAdd={orderMessages.handleOrderLinesAdd}
onOrderLineUpdate={orderMessages.handleOrderLineUpdate}
onOrderFulfillmentApprove={
orderMessages.handleOrderFulfillmentApprove
}
onOrderFulfillmentCancel={
orderMessages.handleOrderFulfillmentCancel
}
@ -158,6 +161,7 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
orderVoid,
orderShippingMethodUpdate,
orderUpdate,
orderFulfillmentApprove,
orderFulfillmentCancel,
orderFulfillmentUpdateTracking,
orderDraftCancel,
@ -179,6 +183,7 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
orderPaymentMarkAsPaid={orderPaymentMarkAsPaid}
orderVoid={orderVoid}
orderPaymentCapture={orderPaymentCapture}
orderFulfillmentApprove={orderFulfillmentApprove}
orderFulfillmentCancel={orderFulfillmentCancel}
orderFulfillmentUpdateTracking={
orderFulfillmentUpdateTracking
@ -224,6 +229,7 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
orderPaymentMarkAsPaid={orderPaymentMarkAsPaid}
orderVoid={orderVoid}
orderPaymentCapture={orderPaymentCapture}
orderFulfillmentApprove={orderFulfillmentApprove}
orderFulfillmentCancel={orderFulfillmentCancel}
orderFulfillmentUpdateTracking={
orderFulfillmentUpdateTracking

View file

@ -3,10 +3,12 @@ import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import OrderFulfillPage from "@saleor/orders/components/OrderFulfillPage";
import { useOrderFulfill } from "@saleor/orders/mutations";
import { useOrderFulfillData } from "@saleor/orders/queries";
import {
useOrderFulfillData,
useOrderFulfillSettingsQuery
} from "@saleor/orders/queries";
import { orderUrl } from "@saleor/orders/urls";
import { mapEdgesToItems } from "@saleor/utils/maps";
import { useWarehouseList } from "@saleor/warehouses/queries";
import { getWarehousesFromOrderLines } from "@saleor/orders/utils/data";
import React from "react";
import { useIntl } from "react-intl";
@ -18,6 +20,12 @@ const OrderFulfill: React.FC<OrderFulfillProps> = ({ orderId }) => {
const navigate = useNavigator();
const notify = useNotifier();
const intl = useIntl();
const {
data: settings,
loading: settingsLoading
} = useOrderFulfillSettingsQuery({});
const { data, loading } = useOrderFulfillData({
displayLoader: true,
variables: {
@ -25,12 +33,7 @@ const OrderFulfill: React.FC<OrderFulfillProps> = ({ orderId }) => {
}
});
const { data: warehouseData, loading: warehousesLoading } = useWarehouseList({
displayLoader: true,
variables: {
first: 20
}
});
const orderLinesWarehouses = getWarehousesFromOrderLines(data?.order?.lines);
const [fulfillOrder, fulfillOrderOpts] = useOrderFulfill({
onCompleted: data => {
@ -68,7 +71,7 @@ const OrderFulfill: React.FC<OrderFulfillProps> = ({ orderId }) => {
}
/>
<OrderFulfillPage
loading={loading || warehousesLoading || fulfillOrderOpts.loading}
loading={loading || settingsLoading || fulfillOrderOpts.loading}
errors={fulfillOrderOpts.data?.orderFulfill.errors}
onBack={() => navigate(orderUrl(orderId))}
onSubmit={formData =>
@ -79,7 +82,8 @@ const OrderFulfill: React.FC<OrderFulfillProps> = ({ orderId }) => {
orderLineId: line.id,
stocks: line.value
})),
notifyCustomer: formData.sendInfo
notifyCustomer:
settings?.shop?.fulfillmentAutoApprove && formData.sendInfo
},
orderId
}
@ -87,7 +91,8 @@ const OrderFulfill: React.FC<OrderFulfillProps> = ({ orderId }) => {
}
order={data?.order}
saveButtonBar="default"
warehouses={mapEdgesToItems(warehouseData?.warehouses)}
warehouses={orderLinesWarehouses}
shopSettings={settings?.shop}
/>
</>
);

View file

@ -22,10 +22,20 @@ export const OrderSettings: React.FC = () => {
orderSettingsUpdateOpts
] = useOrderSettingsUpdateMutation({});
const handleSubmit = async (data: OrderSettingsFormData) => {
const handleSubmit = async ({
automaticallyConfirmAllNewOrders,
fulfillmentAutoApprove,
fulfillmentAllowUnpaid
}: OrderSettingsFormData) => {
const result = await orderSettingsUpdate({
variables: {
input: data
orderSettingsInput: {
automaticallyConfirmAllNewOrders
},
shopSettingsInput: {
fulfillmentAutoApprove,
fulfillmentAllowUnpaid
}
}
});
@ -49,7 +59,8 @@ export const OrderSettings: React.FC = () => {
return (
<OrderSettingsPage
data={data?.orderSettings}
orderSettings={data?.orderSettings}
shop={data?.shop}
disabled={loading || orderSettingsUpdateOpts.loading}
onSubmit={handleSubmit}
onBack={handleBack}

File diff suppressed because it is too large Load diff

View file

@ -116,7 +116,6 @@ function loadStories() {
require("./stories/orders/OrderDraftListPage");
require("./stories/orders/OrderDraftPage/OrderDraftPage");
require("./stories/orders/OrderFulfillmentCancelDialog");
require("./stories/orders/OrderFulfillmentDialog");
require("./stories/orders/OrderFulfillmentTrackingDialog");
require("./stories/orders/OrderHistory");
require("./stories/orders/OrderListPage");

View file

@ -6,7 +6,10 @@ import React from "react";
import OrderDetailsPage, {
OrderDetailsPageProps
} from "../../../orders/components/OrderDetailsPage";
import { order as orderFixture } from "../../../orders/fixtures";
import {
order as orderFixture,
shop as shopFixture
} from "../../../orders/fixtures";
import {
FulfillmentStatus,
OrderStatus,
@ -20,6 +23,7 @@ const props: Omit<OrderDetailsPageProps, "classes"> = {
disabled: false,
onBack: () => undefined,
onBillingAddressEdit: undefined,
onFulfillmentApprove: () => undefined,
onFulfillmentCancel: () => undefined,
onFulfillmentTrackingNumberUpdate: () => undefined,
onInvoiceClick: () => undefined,
@ -38,6 +42,7 @@ const props: Omit<OrderDetailsPageProps, "classes"> = {
onShippingAddressEdit: undefined,
onSubmit: () => undefined,
order,
shop: shopFixture,
saveButtonBarState: "default",
userPermissions: adminUserPermissions
};

View file

@ -1,44 +0,0 @@
import placeholderImage from "@assets/images/placeholder60x60.png";
import { OrderErrorCode } from "@saleor/types/globalTypes";
import { storiesOf } from "@storybook/react";
import React from "react";
import OrderFulfillmentDialog, {
OrderFulfillmentDialogProps
} from "../../../orders/components/OrderFulfillmentDialog";
import { order as orderFixture } from "../../../orders/fixtures";
import Decorator from "../../Decorator";
const order = orderFixture(placeholderImage);
const props: Omit<OrderFulfillmentDialogProps, "classes"> = {
confirmButtonState: "default",
errors: [],
lines: order.lines,
onClose: undefined,
onSubmit: undefined,
open: true
};
storiesOf("Orders / OrderFulfillmentDialog", module)
.addDecorator(Decorator)
.add("default", () => <OrderFulfillmentDialog {...props} />)
.add("errors", () => (
<OrderFulfillmentDialog
{...props}
errors={[
{
__typename: "OrderError",
code: OrderErrorCode.FULFILL_ORDER_LINE,
field: null,
addressType: null
},
{
__typename: "OrderError",
code: OrderErrorCode.INVALID,
field: "trackingNumber",
addressType: null
}
]}
/>
));

View file

@ -480,6 +480,7 @@ export enum FulfillmentStatus {
REFUNDED_AND_RETURNED = "REFUNDED_AND_RETURNED",
REPLACED = "REPLACED",
RETURNED = "RETURNED",
WAITING_FOR_APPROVAL = "WAITING_FOR_APPROVAL",
}
export enum GiftCardErrorCode {
@ -1388,6 +1389,7 @@ export enum OrderErrorCode {
CANNOT_CANCEL_ORDER = "CANNOT_CANCEL_ORDER",
CANNOT_DELETE = "CANNOT_DELETE",
CANNOT_DISCOUNT = "CANNOT_DISCOUNT",
CANNOT_FULFILL_UNPAID_ORDER = "CANNOT_FULFILL_UNPAID_ORDER",
CANNOT_REFUND = "CANNOT_REFUND",
CAPTURE_INACTIVE_PAYMENT = "CAPTURE_INACTIVE_PAYMENT",
CHANNEL_INACTIVE = "CHANNEL_INACTIVE",
@ -1434,6 +1436,7 @@ export enum OrderEventsEnum {
DRAFT_CREATED_FROM_REPLACE = "DRAFT_CREATED_FROM_REPLACE",
EMAIL_SENT = "EMAIL_SENT",
EXTERNAL_SERVICE_NOTIFICATION = "EXTERNAL_SERVICE_NOTIFICATION",
FULFILLMENT_AWAITS_APPROVAL = "FULFILLMENT_AWAITS_APPROVAL",
FULFILLMENT_CANCELED = "FULFILLMENT_CANCELED",
FULFILLMENT_FULFILLED_ITEMS = "FULFILLMENT_FULFILLED_ITEMS",
FULFILLMENT_REFUNDED = "FULFILLMENT_REFUNDED",
@ -2709,6 +2712,8 @@ export interface ShopSettingsInput {
trackInventoryByDefault?: boolean | null;
defaultWeightUnit?: WeightUnitsEnum | null;
automaticFulfillmentDigitalProducts?: boolean | null;
fulfillmentAutoApprove?: boolean | null;
fulfillmentAllowUnpaid?: boolean | null;
defaultDigitalMaxDownloads?: number | null;
defaultDigitalUrlValidDays?: number | null;
defaultMailSenderName?: string | null;