Queue invoice status check

This commit is contained in:
Dawid Tarasiuk 2020-06-26 19:06:48 +02:00
parent 18603cd97a
commit c88572356f
7 changed files with 181 additions and 9 deletions

View file

@ -1,21 +1,21 @@
import { IMessageContext } from "@saleor/components/messages"; import { IMessageContext } from "@saleor/components/messages";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import { checkOrderInvoicesStatus } from "@saleor/orders/queries";
import ApolloClient from "apollo-client"; import ApolloClient from "apollo-client";
import React from "react"; import React from "react";
import { useApolloClient } from "react-apollo"; import { useApolloClient } from "react-apollo";
import { IntlShape, useIntl } from "react-intl"; import { IntlShape, useIntl } from "react-intl";
import BackgroundTasksContext from "./context"; import BackgroundTasksContext from "./context";
import { handleTask, queueCustom } from "./tasks"; import { handleTask, queueCustom, queueInvoiceGenerate } from "./tasks";
import { QueuedTask, Task, TaskData, TaskStatus } from "./types"; import { QueuedTask, Task, TaskData, TaskStatus } from "./types";
export const backgroundTasksRefreshTime = 15 * 1000; export const backgroundTasksRefreshTime = 15 * 1000;
// TODO: Remove underscores when working on #575 or similar PR
export function useBackgroundTasks( export function useBackgroundTasks(
_apolloClient: ApolloClient<any>, apolloClient: ApolloClient<any>,
_notify: IMessageContext, notify: IMessageContext,
_intl: IntlShape intl: IntlShape
) { ) {
const idCounter = React.useRef(0); const idCounter = React.useRef(0);
const tasks = React.useRef<QueuedTask[]>([]); const tasks = React.useRef<QueuedTask[]>([]);
@ -64,6 +64,23 @@ export function useBackgroundTasks(
case Task.CUSTOM: case Task.CUSTOM:
queueCustom(idCounter.current, tasks, data); queueCustom(idCounter.current, tasks, data);
break; 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; 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> { export async function handleTask(task: QueuedTask): Promise<TaskStatus> {
let status = TaskStatus.PENDING; let status = TaskStatus.PENDING;
@ -41,3 +68,46 @@ 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({
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 { export enum Task {
CUSTOM CUSTOM,
INVOICE_GENERATE
} }
export enum TaskStatus { export enum TaskStatus {
FAILURE, FAILURE,
PENDING, PENDING,
SUCCESS SUCCESS
} }
export interface InvoiceGenerateParams {
orderId: string;
invoiceId: string;
}
export interface OnCompletedTaskData { export interface OnCompletedTaskData {
status: TaskStatus; status: TaskStatus;
@ -21,6 +26,7 @@ export interface QueuedTask {
} }
export interface TaskData { export interface TaskData {
generateInvoice?: InvoiceGenerateParams;
id?: string; id?: string;
handle?: () => Promise<TaskStatus>; handle?: () => Promise<TaskStatus>;
onCompleted?: OnCompletedTaskFn; onCompleted?: OnCompletedTaskFn;

View file

@ -228,3 +228,15 @@ export const useOrderFulfillData = makeQuery<
OrderFulfillData, OrderFulfillData,
OrderFulfillDataVariables OrderFulfillDataVariables
>(orderFulfillData); >(orderFulfillData);
export const checkOrderInvoicesStatus = gql`
${fragmentInvoice}
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

@ -1,3 +1,4 @@
import { messages } from "@saleor/containers/BackgroundTasks/tasks";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
@ -45,6 +46,7 @@ interface OrderDetailsMessages {
handleShippingMethodUpdate: (data: OrderShippingMethodUpdate) => void; handleShippingMethodUpdate: (data: OrderShippingMethodUpdate) => void;
handleUpdate: (data: OrderUpdate) => void; handleUpdate: (data: OrderUpdate) => void;
handleInvoiceGeneratePending: (data: InvoiceRequest) => void; handleInvoiceGeneratePending: (data: InvoiceRequest) => void;
handleInvoiceGenerateFinished: (data: InvoiceRequest) => void;
handleInvoiceSend: (data: InvoiceEmailSend) => void; handleInvoiceSend: (data: InvoiceEmailSend) => void;
}) => React.ReactElement; }) => React.ReactElement;
id: string; id: string;
@ -270,6 +272,16 @@ export const OrderDetailsMessages: React.FC<OrderDetailsMessages> = ({
closeModal(); closeModal();
} }
}; };
const handleInvoiceGenerateFinished = (data: InvoiceRequest) => {
const errs = data.invoiceRequest?.errors;
if (errs.length === 0) {
pushMessage({
text: intl.formatMessage(messages.invoiceGenerateFinishedText),
title: intl.formatMessage(messages.invoiceGenerateFinishedTitle)
});
closeModal();
}
};
const handleInvoiceSend = (data: InvoiceEmailSend) => { const handleInvoiceSend = (data: InvoiceEmailSend) => {
const errs = data.invoiceSendEmail?.errors; const errs = data.invoiceSendEmail?.errors;
if (errs.length === 0) { if (errs.length === 0) {
@ -286,6 +298,7 @@ export const OrderDetailsMessages: React.FC<OrderDetailsMessages> = ({
handleDraftCancel, handleDraftCancel,
handleDraftFinalize, handleDraftFinalize,
handleDraftUpdate, handleDraftUpdate,
handleInvoiceGenerateFinished,
handleInvoiceGeneratePending, handleInvoiceGeneratePending,
handleInvoiceSend, handleInvoiceSend,
handleNoteAdd, handleNoteAdd,

View file

@ -1,10 +1,13 @@
import NotFoundPage from "@saleor/components/NotFoundPage"; import NotFoundPage from "@saleor/components/NotFoundPage";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; 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 useNavigator from "@saleor/hooks/useNavigator";
import useUser from "@saleor/hooks/useUser"; import useUser from "@saleor/hooks/useUser";
import OrderCannotCancelOrderDialog from "@saleor/orders/components/OrderCannotCancelOrderDialog"; import OrderCannotCancelOrderDialog from "@saleor/orders/components/OrderCannotCancelOrderDialog";
import OrderInvoiceEmailSendDialog from "@saleor/orders/components/OrderInvoiceEmailSendDialog"; import OrderInvoiceEmailSendDialog from "@saleor/orders/components/OrderInvoiceEmailSendDialog";
import { InvoiceRequest } from "@saleor/orders/types/InvoiceRequest";
import useCustomerSearch from "@saleor/searches/useCustomerSearch"; import useCustomerSearch from "@saleor/searches/useCustomerSearch";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import { useWarehouseList } from "@saleor/warehouses/queries"; import { useWarehouseList } from "@saleor/warehouses/queries";
@ -18,7 +21,11 @@ import {
transformAddressToForm, transformAddressToForm,
} from "../../../misc"; } from "../../../misc";
import { productUrl } from "../../../products/urls"; import { productUrl } from "../../../products/urls";
import { FulfillmentStatus, OrderStatus } from "../../../types/globalTypes"; import {
FulfillmentStatus,
JobStatusEnum,
OrderStatus,
} from "../../../types/globalTypes";
import OrderAddressEditDialog from "../../components/OrderAddressEditDialog"; import OrderAddressEditDialog from "../../components/OrderAddressEditDialog";
import OrderCancelDialog from "../../components/OrderCancelDialog"; import OrderCancelDialog from "../../components/OrderCancelDialog";
import OrderDetailsPage from "../../components/OrderDetailsPage"; import OrderDetailsPage from "../../components/OrderDetailsPage";
@ -104,6 +111,7 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
first: 30, first: 30,
}, },
}); });
const { queue } = useBackgroundTask();
const intl = useIntl(); const intl = useIntl();
const [openModal, closeModal] = createDialogActionHandlers< const [openModal, closeModal] = createDialogActionHandlers<
@ -149,7 +157,21 @@ export const OrderDetails: React.FC<OrderDetailsProps> = ({ id, params }) => {
onDraftFinalize={orderMessages.handleDraftFinalize} onDraftFinalize={orderMessages.handleDraftFinalize}
onDraftCancel={orderMessages.handleDraftCancel} onDraftCancel={orderMessages.handleDraftCancel}
onOrderMarkAsPaid={orderMessages.handleOrderMarkAsPaid} onOrderMarkAsPaid={orderMessages.handleOrderMarkAsPaid}
onInvoiceRequest={orderMessages.handleInvoiceGeneratePending} onInvoiceRequest={(data: InvoiceRequest) => {
if (
data.invoiceRequest.invoice.status === JobStatusEnum.SUCCESS
) {
orderMessages.handleInvoiceGenerateFinished(data);
} else {
orderMessages.handleInvoiceGeneratePending(data);
queue(Task.INVOICE_GENERATE, {
params: {
invoiceId: data.invoiceRequest.invoice.id,
orderId: id,
},
});
}
}}
onInvoiceSend={orderMessages.handleInvoiceSend} onInvoiceSend={orderMessages.handleInvoiceSend}
> >
{({ {({