Merge pull request #570 from mirumee/feature/invoices

Invoices
This commit is contained in:
Dominik Żegleń 2020-07-08 10:56:17 +02:00 committed by GitHub
commit 820a602e57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 4181 additions and 461 deletions

View file

@ -10,6 +10,7 @@ All notable, unreleased changes to this project will be documented in this file.
- Add background task manager - #574 by @dominik-zeglen
- Handle task failure and fix task duplication - #588 by @dominik-zeglen
- Move fragments to separate directory to avoid circular imports - #592 by @dominik-zeglen
- Add order invoices management - #570 by @orzechdev
## 2.10.0

View file

@ -1461,6 +1461,17 @@
"context": "button",
"string": "Confirm"
},
"src_dot_containers_dot_BackgroundTasks_dot_invoiceGenerateFinishedText": {
"string": "Requested Invoice was generated. It was added to the top of the invoice list on this view. Enjoy!"
},
"src_dot_containers_dot_BackgroundTasks_dot_invoiceGenerateFinishedTitle": {
"context": "invoice generating has finished, header",
"string": "Invoice Generated"
},
"src_dot_containers_dot_BackgroundTasks_dot_invoiceGenerationFailedTitle": {
"context": "dialog header, title",
"string": "Invoice Generation"
},
"src_dot_create": {
"context": "button",
"string": "Create"
@ -2667,6 +2678,40 @@
"context": "order history message",
"string": "Order was cancelled"
},
"src_dot_orders_dot_components_dot_OrderInvoiceEmailSendDialog_dot_1821123638": {
"string": "Are you sure you want to send this invoice: {invoiceNumber} to the customer?"
},
"src_dot_orders_dot_components_dot_OrderInvoiceEmailSendDialog_dot_2166306944": {
"context": "dialog header",
"string": "Send Invoice"
},
"src_dot_orders_dot_components_dot_OrderInvoiceList_dot_24460204": {
"context": "section header",
"string": "Invoices"
},
"src_dot_orders_dot_components_dot_OrderInvoiceList_dot_2489266682": {
"context": "invoice number",
"string": "Invoice no"
},
"src_dot_orders_dot_components_dot_OrderInvoiceList_dot_2739475235": {
"context": "invoice create date prefix",
"string": "created"
},
"src_dot_orders_dot_components_dot_OrderInvoiceList_dot_3340654960": {
"string": "No invoices to be shown"
},
"src_dot_orders_dot_components_dot_OrderInvoiceList_dot_3589949197": {
"context": "invoice number prefix",
"string": "Invoice"
},
"src_dot_orders_dot_components_dot_OrderInvoiceList_dot_4120604650": {
"context": "action for invoice",
"string": "Action"
},
"src_dot_orders_dot_components_dot_OrderInvoiceList_dot_949234851": {
"context": "generate invoice button",
"string": "Generate"
},
"src_dot_orders_dot_components_dot_OrderListPage_dot_2826235371": {
"context": "button",
"string": "Create order"
@ -2841,6 +2886,9 @@
"context": "order line total price",
"string": "Total"
},
"src_dot_orders_dot_views_dot_OrderDetails_dot_1039259580": {
"string": "Were generating the invoice you requested. Please wait a couple of moments"
},
"src_dot_orders_dot_views_dot_OrderDetails_dot_1056718390": {
"string": "Payment successfully captured"
},
@ -2874,6 +2922,12 @@
"src_dot_orders_dot_views_dot_OrderDetails_dot_3367579693": {
"string": "Order successfully updated"
},
"src_dot_orders_dot_views_dot_OrderDetails_dot_4085755992": {
"string": "Invoice email sent"
},
"src_dot_orders_dot_views_dot_OrderDetails_dot_55607988": {
"string": "Invoice is Generating"
},
"src_dot_orders_dot_views_dot_OrderDetails_dot_580490159": {
"context": "window title",
"string": "Order #{orderNumber}"
@ -4016,6 +4070,10 @@
"src_dot_savedChanges": {
"string": "Saved changes"
},
"src_dot_send": {
"context": "button",
"string": "Send"
},
"src_dot_serviceAccounts": {
"context": "service accounts section name",
"string": "Service Accounts"
@ -5105,6 +5163,10 @@
"src_dot_utils_dot_errors_dot_duplicatedInputItem": {
"string": "Cannot add and remove group the same time"
},
"src_dot_utils_dot_errors_dot_emailNotSet": {
"context": "error message",
"string": "Email address is not set"
},
"src_dot_utils_dot_errors_dot_graphqlError": {
"string": "API error"
},
@ -5114,6 +5176,10 @@
"src_dot_utils_dot_errors_dot_invalidPassword": {
"string": "Invalid password"
},
"src_dot_utils_dot_errors_dot_invalidStatus": {
"context": "error message",
"string": "Cannot request an invoice for draft order"
},
"src_dot_utils_dot_errors_dot_noShippingAddress": {
"context": "error message",
"string": "Cannot choose a shipping method for an order without the shipping address"
@ -5122,6 +5188,18 @@
"context": "error message",
"string": "Only draft orders can be edited"
},
"src_dot_utils_dot_errors_dot_notFound": {
"context": "error message",
"string": "Invoice not found"
},
"src_dot_utils_dot_errors_dot_notReady": {
"context": "error message",
"string": "Billing address is not set or invoice is not ready to be send"
},
"src_dot_utils_dot_errors_dot_numberNotSet": {
"context": "error message",
"string": "Number not set for an invoice"
},
"src_dot_utils_dot_errors_dot_outOfScopeGroup": {
"string": "Group is out of your permission scope"
},
@ -5169,6 +5247,10 @@
"src_dot_utils_dot_errors_dot_unknownError": {
"string": "Unknown error"
},
"src_dot_utils_dot_errors_dot_urlNotSet": {
"context": "error message",
"string": "URL not set for an invoice"
},
"src_dot_utils_dot_errors_dot_variantNoDigitalContent": {
"string": "This variant does not have any digital content"
},
@ -5258,6 +5340,10 @@
"context": "dialog header",
"string": "Delete Webhook"
},
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_1368317066": {
"context": "event",
"string": "Invoice deleted"
},
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_1436364351": {
"context": "section header",
"string": "Events"
@ -5270,6 +5356,10 @@
"context": "event",
"string": "All events"
},
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_2862596150": {
"context": "event",
"string": "Invoice sent"
},
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_2899821092": {
"context": "event",
"string": "Product created"
@ -5302,6 +5392,10 @@
"context": "event",
"string": "Changed quantity in checkout"
},
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_4186057882": {
"context": "event",
"string": "Invoice requested"
},
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_4281441551": {
"context": "event",
"string": "Fulfillment created"

828
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -143,7 +143,7 @@
"tsconfig-paths-webpack-plugin": "^3.2.0",
"webpack": "^4.35.3",
"webpack-cli": "^3.3.6",
"webpack-dev-server": "^3.10.1"
"webpack-dev-server": "^3.11.0"
},
"optionalDependencies": {
"fsevents": "^1.2.9"
@ -196,7 +196,6 @@
"check-types": "tsc --noEmit",
"extract-json-messages": "rimraf build/locale && cross-env NODE_ENV=extract babel src 'src/**/*.{ts,tsx}' -o build/dashboard.bundle.js",
"extract-messages": "npm run extract-json-messages && npm run transpile-messages",
"generate-component": "plop --plopfile .plop/plopfile.js",
"heroku-postbuild": "npm run build",
"serve:lhci": "NODE_ENV=production npm run server",
"start": "webpack-dev-server -d",

View file

@ -1957,8 +1957,93 @@ input IntRangeInput {
lte: Int
}
type Invoice implements ObjectWithMetadata & Job & Node {
id: ID!
metadata: [MetadataItem]!
status: JobStatusEnum!
number: String
externalUrl: String
privateMetadata: [MetadataItem]!
privateMeta: [MetaStore]! @deprecated(reason: "Use the `privetaMetadata` field. This field will be removed after 2020-07-31.")
meta: [MetaStore]! @deprecated(reason: "Use the `metadata` field. This field will be removed after 2020-07-31.")
createdAt: DateTime!
updatedAt: DateTime!
url: String
}
type InvoiceCreate {
errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.")
invoiceErrors: [InvoiceError!]!
invoice: Invoice
}
input InvoiceCreateInput {
number: String!
url: String!
}
type InvoiceDelete {
errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.")
invoiceErrors: [InvoiceError!]!
invoice: Invoice
}
type InvoiceError {
field: String
message: String
code: InvoiceErrorCode!
}
enum InvoiceErrorCode {
REQUIRED
NOT_READY
URL_NOT_SET
EMAIL_NOT_SET
NUMBER_NOT_SET
NOT_FOUND
INVALID_STATUS
}
type InvoiceRequest {
errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.")
order: Order
invoiceErrors: [InvoiceError!]!
invoice: Invoice
}
type InvoiceRequestDelete {
errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.")
invoiceErrors: [InvoiceError!]!
invoice: Invoice
}
type InvoiceSendEmail {
errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.")
invoiceErrors: [InvoiceError!]!
invoice: Invoice
}
type InvoiceUpdate {
errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.")
invoiceErrors: [InvoiceError!]!
invoice: Invoice
}
scalar JSONString
interface Job {
status: JobStatusEnum!
createdAt: DateTime!
updatedAt: DateTime!
}
enum JobStatusEnum {
PENDING
SUCCESS
FAILED
DELETED
}
enum LanguageCodeEnum {
AR
AZ
@ -2442,6 +2527,12 @@ type Mutation {
menuItemUpdate(id: ID!, input: MenuItemInput!): MenuItemUpdate
menuItemTranslate(id: ID!, input: NameTranslationInput!, languageCode: LanguageCodeEnum!): MenuItemTranslate
menuItemMove(menu: ID!, moves: [MenuItemMoveInput]!): MenuItemMove
invoiceRequest(number: String, orderId: ID!): InvoiceRequest
invoiceRequestDelete(id: ID!): InvoiceRequestDelete
invoiceCreate(input: InvoiceCreateInput!, orderId: ID!): InvoiceCreate
invoiceDelete(id: ID!): InvoiceDelete
invoiceUpdate(id: ID!, input: UpdateInvoiceInput!): InvoiceUpdate
invoiceSendEmail(id: ID!): InvoiceSendEmail
giftCardActivate(id: ID!): GiftCardActivate
giftCardCreate(input: GiftCardCreateInput!): GiftCardCreate
giftCardDeactivate(id: ID!): GiftCardDeactivate
@ -2589,6 +2680,7 @@ type Order implements Node & ObjectWithMetadata {
lines: [OrderLine]!
actions: [OrderAction]!
availableShippingMethods: [ShippingMethod]
invoices: [Invoice]
number: String
isPaid: Boolean
paymentStatus: PaymentChargeStatusEnum
@ -4769,6 +4861,11 @@ input TranslationInput {
scalar UUID
input UpdateInvoiceInput {
number: String
url: String
}
type UpdateMetadata {
errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.")
metadataErrors: [MetadataError!]!
@ -5251,6 +5348,9 @@ enum WebhookEventTypeEnum {
ORDER_UPDATED
ORDER_CANCELLED
ORDER_FULFILLED
INVOICE_REQUESTED
INVOICE_DELETED
INVOICE_SENT
CUSTOMER_CREATED
PRODUCT_CREATED
CHECKOUT_QUANTITY_CHANGED
@ -5268,6 +5368,9 @@ enum WebhookSampleEventTypeEnum {
ORDER_UPDATED
ORDER_CANCELLED
ORDER_FULFILLED
INVOICE_REQUESTED
INVOICE_DELETED
INVOICE_SENT
CUSTOMER_CREATED
PRODUCT_CREATED
CHECKOUT_QUANTITY_CHANGED

View file

@ -1,21 +1,21 @@
import { IMessageContext } from "@saleor/components/messages";
import useNotifier from "@saleor/hooks/useNotifier";
import { checkOrderInvoicesStatus } from "@saleor/orders/queries";
import ApolloClient from "apollo-client";
import React from "react";
import { useApolloClient } from "react-apollo";
import { IntlShape, useIntl } from "react-intl";
import BackgroundTasksContext from "./context";
import { handleTask, queueCustom } from "./tasks";
import { handleTask, queueCustom, queueInvoiceGenerate } from "./tasks";
import { QueuedTask, Task, TaskData, TaskStatus } from "./types";
export const backgroundTasksRefreshTime = 15 * 1000;
// TODO: Remove underscores when working on #575 or similar PR
export function useBackgroundTasks(
_apolloClient: ApolloClient<any>,
_notify: IMessageContext,
_intl: IntlShape
apolloClient: ApolloClient<any>,
notify: IMessageContext,
intl: IntlShape
) {
const idCounter = React.useRef(0);
const tasks = React.useRef<QueuedTask[]>([]);
@ -64,6 +64,23 @@ export function useBackgroundTasks(
case Task.CUSTOM:
queueCustom(idCounter.current, tasks, data);
break;
case Task.INVOICE_GENERATE:
queueInvoiceGenerate(
idCounter.current,
data.generateInvoice,
tasks,
() =>
apolloClient.query({
fetchPolicy: "network-only",
query: checkOrderInvoicesStatus,
variables: {
id: data.generateInvoice.orderId
}
}),
notify,
intl
);
break;
}
return idCounter.current;

View file

@ -1,4 +1,31 @@
import { QueuedTask, TaskData, TaskStatus } from "./types";
import { IMessageContext } from "@saleor/components/messages";
import { commonMessages } from "@saleor/intl";
import { CheckOrderInvoicesStatus } from "@saleor/orders/types/CheckOrderInvoicesStatus";
import { JobStatusEnum } from "@saleor/types/globalTypes";
import { ApolloQueryResult } from "apollo-client";
import { defineMessages, IntlShape } from "react-intl";
import {
InvoiceGenerateParams,
QueuedTask,
TaskData,
TaskStatus
} from "./types";
export const messages = defineMessages({
invoiceGenerateFinishedText: {
defaultMessage:
"Requested Invoice was generated. It was added to the top of the invoice list on this view. Enjoy!"
},
invoiceGenerateFinishedTitle: {
defaultMessage: "Invoice Generated",
description: "invoice generating has finished, header"
},
invoiceGenerationFailedTitle: {
defaultMessage: "Invoice Generation",
description: "dialog header, title"
}
});
export async function handleTask(task: QueuedTask): Promise<TaskStatus> {
let status = TaskStatus.PENDING;
@ -41,3 +68,47 @@ export function queueCustom(
}
];
}
export function queueInvoiceGenerate(
id: number,
generateInvoice: InvoiceGenerateParams,
tasks: React.MutableRefObject<QueuedTask[]>,
fetch: () => Promise<ApolloQueryResult<CheckOrderInvoicesStatus>>,
notify: IMessageContext,
intl: IntlShape
) {
if (!generateInvoice) {
throw new Error("generateInvoice is required when creating custom task");
}
tasks.current = [
...tasks.current,
{
handle: async () => {
const result = await fetch();
const status = result.data.order.invoices.find(
invoice => invoice.id === generateInvoice.invoiceId
).status;
return status === JobStatusEnum.SUCCESS
? TaskStatus.SUCCESS
: status === JobStatusEnum.PENDING
? TaskStatus.PENDING
: TaskStatus.FAILURE;
},
id,
onCompleted: data =>
data.status === TaskStatus.SUCCESS
? notify({
status: "success",
text: intl.formatMessage(messages.invoiceGenerateFinishedText),
title: intl.formatMessage(messages.invoiceGenerateFinishedTitle)
})
: notify({
text: intl.formatMessage(commonMessages.somethingWentWrong),
title: intl.formatMessage(messages.invoiceGenerationFailedTitle)
}),
onError: handleError,
status: TaskStatus.PENDING
}
];
}

View file

@ -1,11 +1,16 @@
export enum Task {
CUSTOM
CUSTOM,
INVOICE_GENERATE
}
export enum TaskStatus {
FAILURE,
PENDING,
SUCCESS
}
export interface InvoiceGenerateParams {
orderId: string;
invoiceId: string;
}
export interface OnCompletedTaskData {
status: TaskStatus;
@ -21,6 +26,7 @@ export interface QueuedTask {
}
export interface TaskData {
generateInvoice?: InvoiceGenerateParams;
id?: string;
handle?: () => Promise<TaskStatus>;
onCompleted?: OnCompletedTaskFn;

View file

@ -104,3 +104,10 @@ export const webhookErrorFragment = gql`
field
}
`;
export const invoiceErrorFragment = gql`
fragment InvoiceErrorFragment on InvoiceError {
code
field
}
`;

View file

@ -63,11 +63,22 @@ export const fulfillmentFragment = gql`
}
`;
export const invoiceFragment = gql`
fragment InvoiceFragment on Invoice {
id
number
createdAt
url
status
}
`;
export const fragmentOrderDetails = gql`
${fragmentAddress}
${fragmentOrderEvent}
${fragmentOrderLine}
${fulfillmentFragment}
${invoiceFragment}
fragment OrderDetailsFragment on Order {
id
billingAddress {
@ -143,5 +154,8 @@ export const fragmentOrderDetails = gql`
amount
currency
}
invoices {
...InvoiceFragment
}
}
`;

View file

@ -0,0 +1,15 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { InvoiceErrorCode } from "./../../types/globalTypes";
// ====================================================
// GraphQL fragment: InvoiceErrorFragment
// ====================================================
export interface InvoiceErrorFragment {
__typename: "InvoiceError";
code: InvoiceErrorCode;
field: string | null;
}

View file

@ -0,0 +1,18 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL fragment: InvoiceFragment
// ====================================================
export interface InvoiceFragment {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL fragment: OrderDetailsFragment
@ -246,6 +246,15 @@ export interface OrderDetailsFragment_discount {
currency: string;
}
export interface OrderDetailsFragment_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderDetailsFragment {
__typename: "Order";
id: string;
@ -272,4 +281,5 @@ export interface OrderDetailsFragment {
userEmail: string | null;
availableShippingMethods: (OrderDetailsFragment_availableShippingMethods | null)[] | null;
discount: OrderDetailsFragment_discount | null;
invoices: (OrderDetailsFragment_invoices | null)[] | null;
}

View file

@ -141,6 +141,10 @@ export const buttonMessages = defineMessages({
defaultMessage: "Save",
description: "button"
},
send: {
defaultMessage: "Send",
description: "button"
},
show: {
defaultMessage: "Show",
description: "button"

View file

@ -20,6 +20,7 @@ import OrderCustomer from "../OrderCustomer";
import OrderCustomerNote from "../OrderCustomerNote";
import OrderFulfillment from "../OrderFulfillment";
import OrderHistory, { FormData as HistoryFormData } from "../OrderHistory";
import OrderInvoiceList from "../OrderInvoiceList";
import OrderPayment from "../OrderPayment/OrderPayment";
import OrderUnfulfilledItems from "../OrderUnfulfilledItems/OrderUnfulfilledItems";
@ -62,6 +63,9 @@ export interface OrderDetailsPageProps extends UserPermissionProps {
onOrderCancel();
onNoteAdd(data: HistoryFormData);
onProfileView();
onInvoiceClick(invoiceId: string);
onInvoiceGenerate();
onInvoiceSend(invoiceId: string);
}
const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
@ -80,7 +84,10 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
onPaymentRefund,
onPaymentVoid,
onShippingAddressEdit,
onProfileView
onProfileView,
onInvoiceClick,
onInvoiceGenerate,
onInvoiceSend
} = props;
const classes = useStyles(props);
@ -179,6 +186,13 @@ const OrderDetailsPage: React.FC<OrderDetailsPageProps> = props => {
onProfileView={onProfileView}
/>
<CardSpacer />
<OrderInvoiceList
invoices={order?.invoices}
onInvoiceClick={onInvoiceClick}
onInvoiceGenerate={onInvoiceGenerate}
onInvoiceSend={onInvoiceSend}
/>
<CardSpacer />
<OrderCustomerNote note={maybe(() => order.customerNote)} />
</div>
</Grid>

View file

@ -0,0 +1,81 @@
import Button from "@material-ui/core/Button";
import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle";
import ConfirmButton, {
ConfirmButtonTransitionState
} from "@saleor/components/ConfirmButton";
import FormSpacer from "@saleor/components/FormSpacer";
import { InvoiceErrorFragment } from "@saleor/fragments/types/InvoiceErrorFragment";
import { InvoiceFragment } from "@saleor/fragments/types/InvoiceFragment";
import { buttonMessages } from "@saleor/intl";
import { DialogProps } from "@saleor/types";
import getInvoiceErrorMessage from "@saleor/utils/errors/invoice";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
export interface OrderInvoiceEmailSendDialogProps extends DialogProps {
confirmButtonState: ConfirmButtonTransitionState;
errors: InvoiceErrorFragment[];
invoice: InvoiceFragment;
onSend: () => void;
}
const OrderInvoiceEmailSendDialog: React.FC<OrderInvoiceEmailSendDialogProps> = ({
confirmButtonState,
errors,
open,
invoice,
onClose,
onSend
}) => {
const intl = useIntl();
return (
<Dialog onClose={onClose} open={open} fullWidth maxWidth="xs">
<DialogTitle>
{intl.formatMessage({
defaultMessage: "Send Invoice",
description: "dialog header"
})}
</DialogTitle>
<DialogContent>
<DialogContentText>
<FormattedMessage
defaultMessage="Are you sure you want to send this invoice: {invoiceNumber} to the customer?"
values={{
invoiceNumber: <strong>{invoice?.number}</strong>
}}
/>
</DialogContentText>
{errors.length > 0 && (
<>
<FormSpacer />
{errors.map((err, idx) => (
<DialogContentText key={idx} color="error">
{getInvoiceErrorMessage(err, intl)}
</DialogContentText>
))}
</>
)}
</DialogContent>
<DialogActions>
<Button onClick={onClose}>
<FormattedMessage {...buttonMessages.back} />
</Button>
<ConfirmButton
transitionState={confirmButtonState}
color="primary"
variant="contained"
onClick={onSend}
>
<FormattedMessage {...buttonMessages.send} />
</ConfirmButton>
</DialogActions>
</Dialog>
);
};
OrderInvoiceEmailSendDialog.displayName = "OrderInvoiceEmailSendDialog";
export default OrderInvoiceEmailSendDialog;

View file

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

View file

@ -0,0 +1,148 @@
import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import { makeStyles } from "@material-ui/core/styles";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Typography from "@material-ui/core/Typography";
import CardTitle from "@saleor/components/CardTitle";
import Date from "@saleor/components/Date";
import ResponsiveTable from "@saleor/components/ResponsiveTable";
import Skeleton from "@saleor/components/Skeleton";
import TableCellHeader from "@saleor/components/TableCellHeader";
import { InvoiceFragment } from "@saleor/fragments/types/InvoiceFragment";
import { buttonMessages } from "@saleor/intl";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
const useStyles = makeStyles(
() => ({
cardContentTable: {
"&:last-child": {
padding: 0
},
padding: 0
},
colAction: { paddingRight: "0.5rem", width: "auto" },
colNumber: { width: "100%" },
colNumberClickable: {
cursor: "pointer",
width: "100%"
}
}),
{ name: "OrderInvoiceList" }
);
export interface OrderInvoiceListProps {
invoices: InvoiceFragment[];
onInvoiceGenerate: () => void;
onInvoiceClick: (invoiceId: string) => void;
onInvoiceSend: (invoiceId: string) => void;
}
const OrderInvoiceList: React.FC<OrderInvoiceListProps> = props => {
const { invoices, onInvoiceGenerate, onInvoiceClick, onInvoiceSend } = props;
const classes = useStyles(props);
const intl = useIntl();
const generatedInvoices = invoices?.filter(
invoice => invoice.status === "SUCCESS"
);
return (
<Card>
<CardTitle
title={intl.formatMessage({
defaultMessage: "Invoices",
description: "section header"
})}
toolbar={
onInvoiceGenerate && (
<Button color="primary" onClick={onInvoiceGenerate}>
<FormattedMessage
defaultMessage="Generate"
description="generate invoice button"
/>
</Button>
)
}
/>
<CardContent
className={generatedInvoices?.length && classes.cardContentTable}
>
{!generatedInvoices ? (
<Skeleton />
) : !generatedInvoices?.length ? (
<Typography color="textSecondary">
<FormattedMessage defaultMessage="No invoices to be shown" />
</Typography>
) : (
<ResponsiveTable>
<TableHead>
<TableRow>
<TableCellHeader className={classes.colNumber}>
<FormattedMessage
defaultMessage="Invoice no"
description="invoice number"
/>
</TableCellHeader>
{onInvoiceSend && (
<TableCellHeader className={classes.colAction}>
<FormattedMessage
defaultMessage="Action"
description="action for invoice"
/>
</TableCellHeader>
)}
</TableRow>
</TableHead>
<TableBody>
{generatedInvoices.map(invoice => (
<TableRow key={invoice.id}>
<TableCell
className={
onInvoiceClick
? classes.colNumberClickable
: classes.colNumber
}
onClick={() => onInvoiceClick(invoice.id)}
>
<FormattedMessage
defaultMessage="Invoice"
description="invoice number prefix"
/>{" "}
{invoice.number}
<Typography variant="caption">
<FormattedMessage
defaultMessage="created"
description="invoice create date prefix"
/>{" "}
<Date date={invoice.createdAt} plain />
</Typography>
</TableCell>
{onInvoiceSend && (
<TableCell
className={classes.colAction}
onClick={() => onInvoiceSend(invoice.id)}
>
<Button color="primary">
<FormattedMessage {...buttonMessages.send} />
</Button>
</TableCell>
)}
</TableRow>
))}
</TableBody>
</ResponsiveTable>
)}
</CardContent>
</Card>
);
};
OrderInvoiceList.displayName = "OrderInvoiceList";
export default OrderInvoiceList;

View file

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

View file

@ -3,6 +3,8 @@ import React from "react";
import { getMutationProviderData } from "../../misc";
import { PartialMutationProviderOutput } from "../../types";
import {
TypedInvoiceEmailSendMutation,
TypedInvoiceRequestMutation,
TypedOrderAddNoteMutation,
TypedOrderCancelMutation,
TypedOrderCaptureMutation,
@ -20,6 +22,14 @@ import {
TypedOrderUpdateMutation,
TypedOrderVoidMutation
} from "../mutations";
import {
InvoiceEmailSend,
InvoiceEmailSendVariables
} from "../types/InvoiceEmailSend";
import {
InvoiceRequest,
InvoiceRequestVariables
} from "../types/InvoiceRequest";
import { OrderAddNote, OrderAddNoteVariables } from "../types/OrderAddNote";
import { OrderCancel, OrderCancelVariables } from "../types/OrderCancel";
import { OrderCapture, OrderCaptureVariables } from "../types/OrderCapture";
@ -128,6 +138,14 @@ interface OrderOperationsProps {
OrderLineUpdate,
OrderLineUpdateVariables
>;
orderInvoiceRequest: PartialMutationProviderOutput<
InvoiceRequest,
InvoiceRequestVariables
>;
orderInvoiceSend: PartialMutationProviderOutput<
InvoiceEmailSend,
InvoiceEmailSendVariables
>;
}) => React.ReactNode;
onOrderFulfillmentCancel: (data: OrderFulfillmentCancel) => void;
onOrderFulfillmentUpdate: (data: OrderFulfillmentUpdateTracking) => void;
@ -145,6 +163,8 @@ interface OrderOperationsProps {
onOrderLineDelete: (data: OrderLineDelete) => void;
onOrderLinesAdd: (data: OrderLinesAdd) => void;
onOrderLineUpdate: (data: OrderLineUpdate) => void;
onInvoiceRequest: (data: InvoiceRequest) => void;
onInvoiceSend: (data: InvoiceEmailSend) => void;
}
const OrderOperations: React.FC<OrderOperationsProps> = ({
@ -164,7 +184,9 @@ const OrderOperations: React.FC<OrderOperationsProps> = ({
onDraftFinalize,
onOrderFulfillmentCancel,
onOrderFulfillmentUpdate,
onOrderMarkAsPaid
onOrderMarkAsPaid,
onInvoiceRequest,
onInvoiceSend
}) => (
<TypedOrderVoidMutation onCompleted={onOrderVoid}>
{(...orderVoid) => (
@ -233,58 +255,86 @@ const OrderOperations: React.FC<OrderOperationsProps> = ({
>
{(
...markAsPaid
) =>
children({
orderAddNote: getMutationProviderData(
...addNote
),
orderCancel: getMutationProviderData(
...orderCancel
),
orderDraftCancel: getMutationProviderData(
...cancelDraft
),
orderDraftFinalize: getMutationProviderData(
...finalizeDraft
),
orderDraftUpdate: getMutationProviderData(
...updateDraft
),
orderFulfillmentCancel: getMutationProviderData(
...cancelFulfillment
),
orderFulfillmentUpdateTracking: getMutationProviderData(
...updateTrackingNumber
),
orderLineDelete: getMutationProviderData(
...deleteOrderLine
),
orderLineUpdate: getMutationProviderData(
...updateOrderLine
),
orderLinesAdd: getMutationProviderData(
...addOrderLine
),
orderPaymentCapture: getMutationProviderData(
...paymentCapture
),
orderPaymentMarkAsPaid: getMutationProviderData(
...markAsPaid
),
orderPaymentRefund: getMutationProviderData(
...paymentRefund
),
orderShippingMethodUpdate: getMutationProviderData(
...updateShippingMethod
),
orderUpdate: getMutationProviderData(
...update
),
orderVoid: getMutationProviderData(
...orderVoid
)
})
}
) => (
<TypedInvoiceRequestMutation
onCompleted={
onInvoiceRequest
}
>
{(
...invoiceRequest
) => (
<TypedInvoiceEmailSendMutation
onCompleted={
onInvoiceSend
}
>
{(
...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(
...invoiceEmailSend
),
orderLineDelete: getMutationProviderData(
...deleteOrderLine
),
orderLineUpdate: getMutationProviderData(
...updateOrderLine
),
orderLinesAdd: getMutationProviderData(
...addOrderLine
),
orderPaymentCapture: getMutationProviderData(
...paymentCapture
),
orderPaymentMarkAsPaid: getMutationProviderData(
...markAsPaid
),
orderPaymentRefund: getMutationProviderData(
...paymentRefund
),
orderShippingMethodUpdate: getMutationProviderData(
...updateShippingMethod
),
orderUpdate: getMutationProviderData(
...update
),
orderVoid: getMutationProviderData(
...orderVoid
)
}
)
}
</TypedInvoiceEmailSendMutation>
)}
</TypedInvoiceRequestMutation>
)}
</TypedOrderMarkAsPaidMutation>
)}
</TypedOrderDraftCancelMutation>

View file

@ -1,3 +1,4 @@
import { InvoiceFragment } from "@saleor/fragments/types/InvoiceFragment";
import { SearchCustomers_search_edges_node } from "@saleor/searches/types/SearchCustomers";
import { warehouseList } from "@saleor/warehouses/fixtures";
import { MessageDescriptor } from "react-intl";
@ -5,6 +6,7 @@ import { MessageDescriptor } from "react-intl";
import { transformOrderStatus, transformPaymentStatus } from "../misc";
import {
FulfillmentStatus,
JobStatusEnum,
OrderAction,
OrderEventsEnum,
OrderStatus,
@ -914,6 +916,16 @@ export const order = (placeholder: string): OrderDetails_order => ({
}
],
id: "T3JkZXI6OQ==",
invoices: [
{
__typename: "Invoice",
createdAt: "2020-06-22T13:52:05.094636+00:00",
id: "SW52b2ljZTox",
number: "1",
status: JobStatusEnum.SUCCESS,
url: "invoice1"
}
],
lines: [
{
__typename: "OrderLine",
@ -1046,6 +1058,16 @@ export const draftOrder = (placeholder: string): OrderDetails_order => ({
events: [],
fulfillments: [],
id: "T3JkZXI6MjQ=",
invoices: [
{
__typename: "Invoice",
createdAt: "2020-06-22T13:52:05.094636+00:00",
id: "SW52b2ljZTox",
number: "1",
status: JobStatusEnum.SUCCESS,
url: "invoice1"
}
],
lines: [
{
__typename: "OrderLine" as "OrderLine",
@ -1298,3 +1320,42 @@ export const orderLineSearch = (
]
}
];
export const invoices: InvoiceFragment[] = [
{
__typename: "Invoice",
createdAt: "2020-07-02T12:13:56.901097+00:00",
id: "SW52b2ljZTo0",
number: "1/07/2020",
status: JobStatusEnum.PENDING,
url:
"http://localhost:8000/media/invoices/invoice-1/07/2020-order-20-1fef611b-7514-4dc6-aee3-09a8232b1d6a.pdf"
},
{
__typename: "Invoice",
createdAt: "2020-07-02T09:06:17.059412+00:00",
id: "SW52b2ljZToz",
number: "1/07/2020",
status: JobStatusEnum.SUCCESS,
url:
"http://localhost:8000/media/invoices/invoice-1/07/2020-order-20-8df26967-ad21-4075-a446-cef44ae05197.pdf"
},
{
__typename: "Invoice",
createdAt: "2020-07-02T09:05:58.300952+00:00",
id: "SW52b2ljZToy",
number: "1/07/2020",
status: JobStatusEnum.SUCCESS,
url:
"http://localhost:8000/media/invoices/invoice-1/07/2020-order-20-5ebc85e0-e587-4386-8292-9b85839281e6.pdf"
},
{
__typename: "Invoice",
createdAt: "2020-07-02T09:04:27.257562+00:00",
id: "SW52b2ljZTox",
number: "1/07/2020",
status: JobStatusEnum.SUCCESS,
url:
"http://localhost:8000/media/invoices/invoice-1/07/2020-order-20-0e449e10-ef4b-4066-bebe-361f670b6820.pdf"
}
];

View file

@ -1,14 +1,26 @@
import { fragmentAddress } from "@saleor/fragments/address";
import { orderErrorFragment } from "@saleor/fragments/errors";
import {
invoiceErrorFragment,
orderErrorFragment
} from "@saleor/fragments/errors";
import {
fragmentOrderDetails,
fragmentOrderEvent
fragmentOrderEvent,
invoiceFragment
} from "@saleor/fragments/orders";
import makeMutation from "@saleor/hooks/makeMutation";
import gql from "graphql-tag";
import { TypedMutation } from "../mutations";
import { FulfillOrder, FulfillOrderVariables } from "./types/FulfillOrder";
import {
InvoiceEmailSend,
InvoiceEmailSendVariables
} from "./types/InvoiceEmailSend";
import {
InvoiceRequest,
InvoiceRequestVariables
} from "./types/InvoiceRequest";
import { OrderAddNote, OrderAddNoteVariables } from "./types/OrderAddNote";
import { OrderCancel, OrderCancelVariables } from "./types/OrderCancel";
import { OrderCapture, OrderCaptureVariables } from "./types/OrderCapture";
@ -448,3 +460,47 @@ export const useOrderFulfill = makeMutation<
FulfillOrder,
FulfillOrderVariables
>(fulfillOrder);
const invoiceRequestMutation = gql`
${invoiceErrorFragment}
${invoiceFragment}
mutation InvoiceRequest($orderId: ID!) {
invoiceRequest(orderId: $orderId) {
errors: invoiceErrors {
...InvoiceErrorFragment
}
invoice {
...InvoiceFragment
}
order {
id
invoices {
...InvoiceFragment
}
}
}
}
`;
export const TypedInvoiceRequestMutation = TypedMutation<
InvoiceRequest,
InvoiceRequestVariables
>(invoiceRequestMutation);
const invoiceEmailSendMutation = gql`
${invoiceErrorFragment}
${invoiceFragment}
mutation InvoiceEmailSend($id: ID!) {
invoiceSendEmail(id: $id) {
errors: invoiceErrors {
...InvoiceErrorFragment
}
invoice {
...InvoiceFragment
}
}
}
`;
export const TypedInvoiceEmailSendMutation = TypedMutation<
InvoiceEmailSend,
InvoiceEmailSendVariables
>(invoiceEmailSendMutation);

View file

@ -1,5 +1,8 @@
import { fragmentAddress } from "@saleor/fragments/address";
import { fragmentOrderDetails } from "@saleor/fragments/orders";
import {
fragmentOrderDetails,
invoiceFragment
} from "@saleor/fragments/orders";
import makeQuery from "@saleor/hooks/makeQuery";
import makeTopLevelSearch from "@saleor/hooks/makeTopLevelSearch";
import gql from "graphql-tag";
@ -228,3 +231,15 @@ export const useOrderFulfillData = makeQuery<
OrderFulfillData,
OrderFulfillDataVariables
>(orderFulfillData);
export const checkOrderInvoicesStatus = gql`
${invoiceFragment}
query CheckOrderInvoicesStatus($id: ID!) {
order(id: $id) {
id
invoices {
...InvoiceFragment
}
}
}
`;

View file

@ -0,0 +1,32 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL query operation: CheckOrderInvoicesStatus
// ====================================================
export interface CheckOrderInvoicesStatus_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface CheckOrderInvoicesStatus_order {
__typename: "Order";
id: string;
invoices: (CheckOrderInvoicesStatus_order_invoices | null)[] | null;
}
export interface CheckOrderInvoicesStatus {
order: CheckOrderInvoicesStatus_order | null;
}
export interface CheckOrderInvoicesStatusVariables {
id: string;
}

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { OrderFulfillInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { OrderFulfillInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: FulfillOrder
@ -254,6 +254,15 @@ export interface FulfillOrder_orderFulfill_order_discount {
currency: string;
}
export interface FulfillOrder_orderFulfill_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface FulfillOrder_orderFulfill_order {
__typename: "Order";
id: string;
@ -280,6 +289,7 @@ export interface FulfillOrder_orderFulfill_order {
userEmail: string | null;
availableShippingMethods: (FulfillOrder_orderFulfill_order_availableShippingMethods | null)[] | null;
discount: FulfillOrder_orderFulfill_order_discount | null;
invoices: (FulfillOrder_orderFulfill_order_invoices | null)[] | null;
}
export interface FulfillOrder_orderFulfill {

View file

@ -0,0 +1,38 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { InvoiceErrorCode, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: InvoiceEmailSend
// ====================================================
export interface InvoiceEmailSend_invoiceSendEmail_errors {
__typename: "InvoiceError";
code: InvoiceErrorCode;
field: string | null;
}
export interface InvoiceEmailSend_invoiceSendEmail_invoice {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface InvoiceEmailSend_invoiceSendEmail {
__typename: "InvoiceSendEmail";
errors: InvoiceEmailSend_invoiceSendEmail_errors[];
invoice: InvoiceEmailSend_invoiceSendEmail_invoice | null;
}
export interface InvoiceEmailSend {
invoiceSendEmail: InvoiceEmailSend_invoiceSendEmail | null;
}
export interface InvoiceEmailSendVariables {
id: string;
}

View file

@ -0,0 +1,54 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { InvoiceErrorCode, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: InvoiceRequest
// ====================================================
export interface InvoiceRequest_invoiceRequest_errors {
__typename: "InvoiceError";
code: InvoiceErrorCode;
field: string | null;
}
export interface InvoiceRequest_invoiceRequest_invoice {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface InvoiceRequest_invoiceRequest_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface InvoiceRequest_invoiceRequest_order {
__typename: "Order";
id: string;
invoices: (InvoiceRequest_invoiceRequest_order_invoices | null)[] | null;
}
export interface InvoiceRequest_invoiceRequest {
__typename: "InvoiceRequest";
errors: InvoiceRequest_invoiceRequest_errors[];
invoice: InvoiceRequest_invoiceRequest_invoice | null;
order: InvoiceRequest_invoiceRequest_order | null;
}
export interface InvoiceRequest {
invoiceRequest: InvoiceRequest_invoiceRequest | null;
}
export interface InvoiceRequestVariables {
orderId: string;
}

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderCancel
@ -252,6 +252,15 @@ export interface OrderCancel_orderCancel_order_discount {
currency: string;
}
export interface OrderCancel_orderCancel_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderCancel_orderCancel_order {
__typename: "Order";
id: string;
@ -278,6 +287,7 @@ export interface OrderCancel_orderCancel_order {
userEmail: string | null;
availableShippingMethods: (OrderCancel_orderCancel_order_availableShippingMethods | null)[] | null;
discount: OrderCancel_orderCancel_order_discount | null;
invoices: (OrderCancel_orderCancel_order_invoices | null)[] | null;
}
export interface OrderCancel_orderCancel {

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderCapture
@ -252,6 +252,15 @@ export interface OrderCapture_orderCapture_order_discount {
currency: string;
}
export interface OrderCapture_orderCapture_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderCapture_orderCapture_order {
__typename: "Order";
id: string;
@ -278,6 +287,7 @@ export interface OrderCapture_orderCapture_order {
userEmail: string | null;
availableShippingMethods: (OrderCapture_orderCapture_order_availableShippingMethods | null)[] | null;
discount: OrderCapture_orderCapture_order_discount | null;
invoices: (OrderCapture_orderCapture_order_invoices | null)[] | null;
}
export interface OrderCapture_orderCapture {

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, WeightUnitsEnum } from "./../../types/globalTypes";
import { OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum, WeightUnitsEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL query operation: OrderDetails
@ -246,6 +246,15 @@ export interface OrderDetails_order_discount {
currency: string;
}
export interface OrderDetails_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderDetails_order {
__typename: "Order";
id: string;
@ -272,6 +281,7 @@ export interface OrderDetails_order {
userEmail: string | null;
availableShippingMethods: (OrderDetails_order_availableShippingMethods | null)[] | null;
discount: OrderDetails_order_discount | null;
invoices: (OrderDetails_order_invoices | null)[] | null;
}
export interface OrderDetails_shop_countries {

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderDraftCancel
@ -252,6 +252,15 @@ export interface OrderDraftCancel_draftOrderDelete_order_discount {
currency: string;
}
export interface OrderDraftCancel_draftOrderDelete_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderDraftCancel_draftOrderDelete_order {
__typename: "Order";
id: string;
@ -278,6 +287,7 @@ export interface OrderDraftCancel_draftOrderDelete_order {
userEmail: string | null;
availableShippingMethods: (OrderDraftCancel_draftOrderDelete_order_availableShippingMethods | null)[] | null;
discount: OrderDraftCancel_draftOrderDelete_order_discount | null;
invoices: (OrderDraftCancel_draftOrderDelete_order_invoices | null)[] | null;
}
export interface OrderDraftCancel_draftOrderDelete {

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderDraftFinalize
@ -252,6 +252,15 @@ export interface OrderDraftFinalize_draftOrderComplete_order_discount {
currency: string;
}
export interface OrderDraftFinalize_draftOrderComplete_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderDraftFinalize_draftOrderComplete_order {
__typename: "Order";
id: string;
@ -278,6 +287,7 @@ export interface OrderDraftFinalize_draftOrderComplete_order {
userEmail: string | null;
availableShippingMethods: (OrderDraftFinalize_draftOrderComplete_order_availableShippingMethods | null)[] | null;
discount: OrderDraftFinalize_draftOrderComplete_order_discount | null;
invoices: (OrderDraftFinalize_draftOrderComplete_order_invoices | null)[] | null;
}
export interface OrderDraftFinalize_draftOrderComplete {

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { DraftOrderInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { DraftOrderInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderDraftUpdate
@ -252,6 +252,15 @@ export interface OrderDraftUpdate_draftOrderUpdate_order_discount {
currency: string;
}
export interface OrderDraftUpdate_draftOrderUpdate_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderDraftUpdate_draftOrderUpdate_order {
__typename: "Order";
id: string;
@ -278,6 +287,7 @@ export interface OrderDraftUpdate_draftOrderUpdate_order {
userEmail: string | null;
availableShippingMethods: (OrderDraftUpdate_draftOrderUpdate_order_availableShippingMethods | null)[] | null;
discount: OrderDraftUpdate_draftOrderUpdate_order_discount | null;
invoices: (OrderDraftUpdate_draftOrderUpdate_order_invoices | null)[] | null;
}
export interface OrderDraftUpdate_draftOrderUpdate {

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { FulfillmentCancelInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { FulfillmentCancelInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderFulfillmentCancel
@ -252,6 +252,15 @@ export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_discount {
currency: string;
}
export interface OrderFulfillmentCancel_orderFulfillmentCancel_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderFulfillmentCancel_orderFulfillmentCancel_order {
__typename: "Order";
id: string;
@ -278,6 +287,7 @@ export interface OrderFulfillmentCancel_orderFulfillmentCancel_order {
userEmail: string | null;
availableShippingMethods: (OrderFulfillmentCancel_orderFulfillmentCancel_order_availableShippingMethods | null)[] | null;
discount: OrderFulfillmentCancel_orderFulfillmentCancel_order_discount | null;
invoices: (OrderFulfillmentCancel_orderFulfillmentCancel_order_invoices | null)[] | null;
}
export interface OrderFulfillmentCancel_orderFulfillmentCancel {

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { FulfillmentUpdateTrackingInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { FulfillmentUpdateTrackingInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderFulfillmentUpdateTracking
@ -252,6 +252,15 @@ export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_o
currency: string;
}
export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order {
__typename: "Order";
id: string;
@ -278,6 +287,7 @@ export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_o
userEmail: string | null;
availableShippingMethods: (OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_availableShippingMethods | null)[] | null;
discount: OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_discount | null;
invoices: (OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking_order_invoices | null)[] | null;
}
export interface OrderFulfillmentUpdateTracking_orderFulfillmentUpdateTracking {

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderLineDelete
@ -252,6 +252,15 @@ export interface OrderLineDelete_draftOrderLineDelete_order_discount {
currency: string;
}
export interface OrderLineDelete_draftOrderLineDelete_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderLineDelete_draftOrderLineDelete_order {
__typename: "Order";
id: string;
@ -278,6 +287,7 @@ export interface OrderLineDelete_draftOrderLineDelete_order {
userEmail: string | null;
availableShippingMethods: (OrderLineDelete_draftOrderLineDelete_order_availableShippingMethods | null)[] | null;
discount: OrderLineDelete_draftOrderLineDelete_order_discount | null;
invoices: (OrderLineDelete_draftOrderLineDelete_order_invoices | null)[] | null;
}
export interface OrderLineDelete_draftOrderLineDelete {

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { OrderLineInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { OrderLineInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderLineUpdate
@ -252,6 +252,15 @@ export interface OrderLineUpdate_draftOrderLineUpdate_order_discount {
currency: string;
}
export interface OrderLineUpdate_draftOrderLineUpdate_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderLineUpdate_draftOrderLineUpdate_order {
__typename: "Order";
id: string;
@ -278,6 +287,7 @@ export interface OrderLineUpdate_draftOrderLineUpdate_order {
userEmail: string | null;
availableShippingMethods: (OrderLineUpdate_draftOrderLineUpdate_order_availableShippingMethods | null)[] | null;
discount: OrderLineUpdate_draftOrderLineUpdate_order_discount | null;
invoices: (OrderLineUpdate_draftOrderLineUpdate_order_invoices | null)[] | null;
}
export interface OrderLineUpdate_draftOrderLineUpdate {

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { OrderLineCreateInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { OrderLineCreateInput, OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderLinesAdd
@ -252,6 +252,15 @@ export interface OrderLinesAdd_draftOrderLinesCreate_order_discount {
currency: string;
}
export interface OrderLinesAdd_draftOrderLinesCreate_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderLinesAdd_draftOrderLinesCreate_order {
__typename: "Order";
id: string;
@ -278,6 +287,7 @@ export interface OrderLinesAdd_draftOrderLinesCreate_order {
userEmail: string | null;
availableShippingMethods: (OrderLinesAdd_draftOrderLinesCreate_order_availableShippingMethods | null)[] | null;
discount: OrderLinesAdd_draftOrderLinesCreate_order_discount | null;
invoices: (OrderLinesAdd_draftOrderLinesCreate_order_invoices | null)[] | null;
}
export interface OrderLinesAdd_draftOrderLinesCreate {

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderMarkAsPaid
@ -252,6 +252,15 @@ export interface OrderMarkAsPaid_orderMarkAsPaid_order_discount {
currency: string;
}
export interface OrderMarkAsPaid_orderMarkAsPaid_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderMarkAsPaid_orderMarkAsPaid_order {
__typename: "Order";
id: string;
@ -278,6 +287,7 @@ export interface OrderMarkAsPaid_orderMarkAsPaid_order {
userEmail: string | null;
availableShippingMethods: (OrderMarkAsPaid_orderMarkAsPaid_order_availableShippingMethods | null)[] | null;
discount: OrderMarkAsPaid_orderMarkAsPaid_order_discount | null;
invoices: (OrderMarkAsPaid_orderMarkAsPaid_order_invoices | null)[] | null;
}
export interface OrderMarkAsPaid_orderMarkAsPaid {

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderRefund
@ -252,6 +252,15 @@ export interface OrderRefund_orderRefund_order_discount {
currency: string;
}
export interface OrderRefund_orderRefund_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderRefund_orderRefund_order {
__typename: "Order";
id: string;
@ -278,6 +287,7 @@ export interface OrderRefund_orderRefund_order {
userEmail: string | null;
availableShippingMethods: (OrderRefund_orderRefund_order_availableShippingMethods | null)[] | null;
discount: OrderRefund_orderRefund_order_discount | null;
invoices: (OrderRefund_orderRefund_order_invoices | null)[] | null;
}
export interface OrderRefund_orderRefund {

View file

@ -2,7 +2,7 @@
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction } from "./../../types/globalTypes";
import { OrderErrorCode, OrderEventsEmailsEnum, OrderEventsEnum, FulfillmentStatus, PaymentChargeStatusEnum, OrderStatus, OrderAction, JobStatusEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: OrderVoid
@ -252,6 +252,15 @@ export interface OrderVoid_orderVoid_order_discount {
currency: string;
}
export interface OrderVoid_orderVoid_order_invoices {
__typename: "Invoice";
id: string;
number: string | null;
createdAt: any;
url: string | null;
status: JobStatusEnum;
}
export interface OrderVoid_orderVoid_order {
__typename: "Order";
id: string;
@ -278,6 +287,7 @@ export interface OrderVoid_orderVoid_order {
userEmail: string | null;
availableShippingMethods: (OrderVoid_orderVoid_order_availableShippingMethods | null)[] | null;
discount: OrderVoid_orderVoid_order_discount | null;
invoices: (OrderVoid_orderVoid_order_invoices | null)[] | null;
}
export interface OrderVoid_orderVoid {

View file

@ -99,7 +99,8 @@ export type OrderUrlDialog =
| "finalize"
| "mark-paid"
| "refund"
| "void";
| "void"
| "invoice-send";
export type OrderUrlQueryParams = Dialog<OrderUrlDialog> & SingleAction;
export const orderUrl = (id: string, params?: OrderUrlQueryParams) =>
orderPath(encodeURIComponent(id)) + "?" + stringifyQs(params);

View file

@ -1,9 +1,12 @@
import { messages } from "@saleor/containers/BackgroundTasks/tasks";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import React from "react";
import { useIntl } from "react-intl";
import { InvoiceEmailSend } from "../../types/InvoiceEmailSend";
import { InvoiceRequest } from "../../types/InvoiceRequest";
import { OrderAddNote } from "../../types/OrderAddNote";
import { OrderCancel } from "../../types/OrderCancel";
import { OrderCapture } from "../../types/OrderCapture";
@ -42,6 +45,9 @@ interface OrderDetailsMessages {
handlePaymentRefund: (data: OrderRefund) => void;
handleShippingMethodUpdate: (data: OrderShippingMethodUpdate) => void;
handleUpdate: (data: OrderUpdate) => void;
handleInvoiceGeneratePending: (data: InvoiceRequest) => void;
handleInvoiceGenerateFinished: (data: InvoiceRequest) => void;
handleInvoiceSend: (data: InvoiceEmailSend) => void;
}) => React.ReactElement;
id: string;
params: OrderUrlQueryParams;
@ -251,11 +257,51 @@ export const OrderDetailsMessages: React.FC<OrderDetailsMessages> = ({
closeModal();
}
};
const handleInvoiceGeneratePending = (data: InvoiceRequest) => {
const errs = data.invoiceRequest?.errors;
if (errs.length === 0) {
pushMessage({
text: intl.formatMessage({
defaultMessage:
"Were generating the invoice you requested. Please wait a couple of moments"
}),
title: intl.formatMessage({
defaultMessage: "Invoice is Generating"
})
});
closeModal();
}
};
const handleInvoiceGenerateFinished = (data: InvoiceRequest) => {
const errs = data.invoiceRequest?.errors;
if (errs.length === 0) {
pushMessage({
status: "success",
text: intl.formatMessage(messages.invoiceGenerateFinishedText),
title: intl.formatMessage(messages.invoiceGenerateFinishedTitle)
});
closeModal();
}
};
const handleInvoiceSend = (data: InvoiceEmailSend) => {
const errs = data.invoiceSendEmail?.errors;
if (errs.length === 0) {
pushMessage({
text: intl.formatMessage({
defaultMessage: "Invoice email sent"
})
});
closeModal();
}
};
return children({
handleDraftCancel,
handleDraftFinalize,
handleDraftUpdate,
handleInvoiceGenerateFinished,
handleInvoiceGeneratePending,
handleInvoiceSend,
handleNoteAdd,
handleOrderCancel,
handleOrderFulfillmentCancel,

View file

@ -1,9 +1,13 @@
import NotFoundPage from "@saleor/components/NotFoundPage";
import { WindowTitle } from "@saleor/components/WindowTitle";
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
import { Task } from "@saleor/containers/BackgroundTasks/types";
import useBackgroundTask from "@saleor/hooks/useBackgroundTask";
import useNavigator from "@saleor/hooks/useNavigator";
import useUser from "@saleor/hooks/useUser";
import OrderCannotCancelOrderDialog from "@saleor/orders/components/OrderCannotCancelOrderDialog";
import OrderInvoiceEmailSendDialog from "@saleor/orders/components/OrderInvoiceEmailSendDialog";
import { InvoiceRequest } from "@saleor/orders/types/InvoiceRequest";
import useCustomerSearch from "@saleor/searches/useCustomerSearch";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import { useWarehouseList } from "@saleor/warehouses/queries";
@ -17,7 +21,11 @@ import {
transformAddressToForm
} from "../../../misc";
import { productUrl } from "../../../products/urls";
import { FulfillmentStatus, OrderStatus } from "../../../types/globalTypes";
import {
FulfillmentStatus,
JobStatusEnum,
OrderStatus
} from "../../../types/globalTypes";
import OrderAddressEditDialog from "../../components/OrderAddressEditDialog";
import OrderCancelDialog from "../../components/OrderCancelDialog";
import OrderDetailsPage from "../../components/OrderDetailsPage";
@ -103,6 +111,7 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
first: 30
}
});
const { queue } = useBackgroundTask();
const intl = useIntl();
const [openModal, closeModal] = createDialogActionHandlers<
@ -148,6 +157,22 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
onDraftFinalize={orderMessages.handleDraftFinalize}
onDraftCancel={orderMessages.handleDraftCancel}
onOrderMarkAsPaid={orderMessages.handleOrderMarkAsPaid}
onInvoiceRequest={(data: InvoiceRequest) => {
if (
data.invoiceRequest.invoice.status === JobStatusEnum.SUCCESS
) {
orderMessages.handleInvoiceGenerateFinished(data);
} else {
orderMessages.handleInvoiceGeneratePending(data);
queue(Task.INVOICE_GENERATE, {
generateInvoice: {
invoiceId: data.invoiceRequest.invoice.id,
orderId: id
}
});
}
}}
onInvoiceSend={orderMessages.handleInvoiceSend}
>
{({
orderAddNote,
@ -165,7 +190,9 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
orderFulfillmentUpdateTracking,
orderDraftCancel,
orderDraftFinalize,
orderPaymentMarkAsPaid
orderPaymentMarkAsPaid,
orderInvoiceRequest,
orderInvoiceSend
}) => (
<>
{order?.status !== OrderStatus.DRAFT ? (
@ -229,6 +256,21 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
onProfileView={() =>
navigate(customerUrl(order.user.id))
}
onInvoiceClick={id =>
window.open(
order.invoices.find(invoice => invoice.id === id)
?.url,
"_blank"
)
}
onInvoiceGenerate={() =>
orderInvoiceRequest.mutate({
orderId: id
})
}
onInvoiceSend={id =>
openModal("invoice-send", { id })
}
/>
<OrderCannotCancelOrderDialog
onClose={closeModal}
@ -359,6 +401,21 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
}
onClose={closeModal}
/>
<OrderInvoiceEmailSendDialog
confirmButtonState={orderInvoiceSend.opts.status}
errors={
orderInvoiceSend.opts.data?.invoiceSendEmail
.errors || []
}
open={params.action === "invoice-send"}
invoice={order?.invoices?.find(
invoice => invoice.id === params.id
)}
onClose={closeModal}
onSend={() =>
orderInvoiceSend.mutate({ id: params.id })
}
/>
</>
) : (
<>

File diff suppressed because it is too large Load diff

View file

@ -134,6 +134,7 @@ function loadStories() {
require("./stories/orders/OrderPaymentVoidDialog");
require("./stories/orders/OrderProductAddDialog");
require("./stories/orders/OrderShippingMethodEditDialog");
require("./stories/orders/OrderInvoiceList");
// Product types
require("./stories/productTypes/ProductTypeAttributeUnassignDialog");

View file

@ -23,6 +23,9 @@ const props: Omit<OrderDetailsPageProps, "classes"> = {
onBillingAddressEdit: undefined,
onFulfillmentCancel: () => undefined,
onFulfillmentTrackingNumberUpdate: () => undefined,
onInvoiceClick: () => undefined,
onInvoiceGenerate: () => undefined,
onInvoiceSend: () => undefined,
onNoteAdd: undefined,
onOrderCancel: undefined,
onOrderFulfill: undefined,

View file

@ -0,0 +1,23 @@
import OrderInvoiceList, {
OrderInvoiceListProps
} from "@saleor/orders/components/OrderInvoiceList";
import { storiesOf } from "@storybook/react";
import React from "react";
import { invoices } from "../../../orders/fixtures";
import Decorator from "../../Decorator";
const props: OrderInvoiceListProps = {
invoices: undefined,
onInvoiceClick: () => undefined,
onInvoiceGenerate: () => undefined,
onInvoiceSend: () => undefined
};
storiesOf("Orders / OrderInvoiceList", module)
.addDecorator(Decorator)
.add("with invoices", () => (
<OrderInvoiceList {...props} invoices={invoices} />
))
.add("without invoices", () => <OrderInvoiceList {...props} invoices={[]} />)
.add("loading", () => <OrderInvoiceList {...props} />);

View file

@ -380,6 +380,23 @@ export enum FulfillmentStatus {
FULFILLED = "FULFILLED",
}
export enum InvoiceErrorCode {
EMAIL_NOT_SET = "EMAIL_NOT_SET",
INVALID_STATUS = "INVALID_STATUS",
NOT_FOUND = "NOT_FOUND",
NOT_READY = "NOT_READY",
NUMBER_NOT_SET = "NUMBER_NOT_SET",
REQUIRED = "REQUIRED",
URL_NOT_SET = "URL_NOT_SET",
}
export enum JobStatusEnum {
DELETED = "DELETED",
FAILED = "FAILED",
PENDING = "PENDING",
SUCCESS = "SUCCESS",
}
export enum LanguageCodeEnum {
AR = "AR",
AZ = "AZ",
@ -793,6 +810,9 @@ export enum WebhookEventTypeEnum {
CHECKOUT_QUANTITY_CHANGED = "CHECKOUT_QUANTITY_CHANGED",
CUSTOMER_CREATED = "CUSTOMER_CREATED",
FULFILLMENT_CREATED = "FULFILLMENT_CREATED",
INVOICE_DELETED = "INVOICE_DELETED",
INVOICE_REQUESTED = "INVOICE_REQUESTED",
INVOICE_SENT = "INVOICE_SENT",
ORDER_CANCELLED = "ORDER_CANCELLED",
ORDER_CREATED = "ORDER_CREATED",
ORDER_FULFILLED = "ORDER_FULFILLED",

View file

@ -0,0 +1,64 @@
import { InvoiceErrorFragment } from "@saleor/fragments/types/InvoiceErrorFragment";
import { commonMessages } from "@saleor/intl";
import { InvoiceErrorCode } from "@saleor/types/globalTypes";
import { defineMessages, IntlShape } from "react-intl";
import commonErrorMessages from "./common";
const messages = defineMessages({
emailNotSet: {
defaultMessage: "Email address is not set",
description: "error message"
},
invalidStatus: {
defaultMessage: "Cannot request an invoice for draft order",
description: "error message"
},
notFound: {
defaultMessage: "Invoice not found",
description: "error message"
},
notReady: {
defaultMessage:
"Billing address is not set or invoice is not ready to be send",
description: "error message"
},
numberNotSet: {
defaultMessage: "Number not set for an invoice",
description: "error message"
},
urlNotSet: {
defaultMessage: "URL not set for an invoice",
description: "error message"
}
});
function getInvoiceErrorMessage(
err: InvoiceErrorFragment,
intl: IntlShape
): string {
if (err) {
switch (err.code) {
case InvoiceErrorCode.EMAIL_NOT_SET:
return intl.formatMessage(messages.emailNotSet);
case InvoiceErrorCode.INVALID_STATUS:
return intl.formatMessage(messages.invalidStatus);
case InvoiceErrorCode.NOT_FOUND:
return intl.formatMessage(messages.notFound);
case InvoiceErrorCode.NOT_READY:
return intl.formatMessage(messages.notReady);
case InvoiceErrorCode.NUMBER_NOT_SET:
return intl.formatMessage(messages.numberNotSet);
case InvoiceErrorCode.URL_NOT_SET:
return intl.formatMessage(messages.urlNotSet);
case InvoiceErrorCode.REQUIRED:
return intl.formatMessage(commonMessages.requiredField);
default:
return intl.formatMessage(commonErrorMessages.unknownError);
}
}
return undefined;
}
export default getInvoiceErrorMessage;

View file

@ -67,6 +67,18 @@ const WebhookEvents: React.FC<WebhookEventsProps> = ({
[WebhookEventTypeEnum.FULFILLMENT_CREATED]: intl.formatMessage({
defaultMessage: "Fulfillment created",
description: "event"
}),
[WebhookEventTypeEnum.INVOICE_REQUESTED]: intl.formatMessage({
defaultMessage: "Invoice requested",
description: "event"
}),
[WebhookEventTypeEnum.INVOICE_SENT]: intl.formatMessage({
defaultMessage: "Invoice sent",
description: "event"
}),
[WebhookEventTypeEnum.INVOICE_DELETED]: intl.formatMessage({
defaultMessage: "Invoice deleted",
description: "event"
})
};