update invoice
This commit is contained in:
@@ -54,6 +54,7 @@ export const Paths = {
|
|||||||
list: '/invoice/list',
|
list: '/invoice/list',
|
||||||
create: '/invoice/create',
|
create: '/invoice/create',
|
||||||
detail: '/invoice/',
|
detail: '/invoice/',
|
||||||
|
update: '/invoice/update/',
|
||||||
},
|
},
|
||||||
newOrder: '/new-order',
|
newOrder: '/new-order',
|
||||||
orderDetails: '/order/',
|
orderDetails: '/order/',
|
||||||
|
|||||||
@@ -40,13 +40,13 @@ const CreateInvoice: FC = () => {
|
|||||||
const [items, setItems] = useState<CreatePreInvoiceItemType[]>([createEmptyItem()]);
|
const [items, setItems] = useState<CreatePreInvoiceItemType[]>([createEmptyItem()]);
|
||||||
const [attachmentFiles, setAttachmentFiles] = useState<File[]>([]);
|
const [attachmentFiles, setAttachmentFiles] = useState<File[]>([]);
|
||||||
|
|
||||||
const formik = useFormik<Pick<CreatePreInvoiceType, "userId" | "enableTax" | "approvalDeadline" | "paymentMethod" | "notes">>({
|
const formik = useFormik<Pick<CreatePreInvoiceType, "userId" | "enableTax" | "approvalDeadline" | "paymentMethod" | "description">>({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
userId: "",
|
userId: "",
|
||||||
enableTax: false,
|
enableTax: false,
|
||||||
approvalDeadline: "",
|
approvalDeadline: "",
|
||||||
paymentMethod: "",
|
paymentMethod: "",
|
||||||
notes: "",
|
description: "",
|
||||||
},
|
},
|
||||||
validationSchema: Yup.object({
|
validationSchema: Yup.object({
|
||||||
userId: !requestId
|
userId: !requestId
|
||||||
@@ -87,7 +87,7 @@ const CreateInvoice: FC = () => {
|
|||||||
enableTax: values.enableTax,
|
enableTax: values.enableTax,
|
||||||
approvalDeadline: moment(values.approvalDeadline, 'jYYYY/jMM/jDD').format('YYYY-MM-DD'),
|
approvalDeadline: moment(values.approvalDeadline, 'jYYYY/jMM/jDD').format('YYYY-MM-DD'),
|
||||||
...(values.paymentMethod ? { paymentMethod: values.paymentMethod } : {}),
|
...(values.paymentMethod ? { paymentMethod: values.paymentMethod } : {}),
|
||||||
notes: values.notes,
|
description: values.description,
|
||||||
...(attachments.length ? { attachments } : {}),
|
...(attachments.length ? { attachments } : {}),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -243,10 +243,10 @@ const CreateInvoice: FC = () => {
|
|||||||
<Textarea
|
<Textarea
|
||||||
label="توضیحات"
|
label="توضیحات"
|
||||||
placeholder="توضیحات پیش فاکتور را وارد کنید..."
|
placeholder="توضیحات پیش فاکتور را وارد کنید..."
|
||||||
value={formik.values.notes}
|
value={formik.values.description}
|
||||||
onChange={(e) => formik.setFieldValue("notes", e.target.value)}
|
onChange={(e) => formik.setFieldValue("description", e.target.value)}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
name="notes"
|
name="description"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -179,9 +179,11 @@ const ProformaInvoice: FC = () => {
|
|||||||
key: 'actions',
|
key: 'actions',
|
||||||
title: '',
|
title: '',
|
||||||
render: (item) => (
|
render: (item) => (
|
||||||
<Link to={Paths.perfomaInvoice.detail + item.id}>
|
<div className='flex gap-2 items-center'>
|
||||||
<Eye size={20} color='#8C90A3' />
|
<Link to={Paths.perfomaInvoice.update + item.id}>
|
||||||
</Link>
|
<Eye size={20} color='#8C90A3' />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
|||||||
@@ -0,0 +1,315 @@
|
|||||||
|
import { useEffect, useState, type FC } from "react";
|
||||||
|
import Button from "@/components/Button";
|
||||||
|
import { TickSquare } from "iconsax-react";
|
||||||
|
import { toast } from "@/shared/toast";
|
||||||
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
|
import { Paths } from "@/config/Paths";
|
||||||
|
import { extractErrorMessage } from "@/config/func";
|
||||||
|
import { useFormik } from "formik";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import type { CreatePreInvoiceItemType, UpdatePreInvoiceType } from "./types/Types";
|
||||||
|
import InvoiceItemRow from "./components/InvoiceItemRow";
|
||||||
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
|
import UploadBox from "@/components/UploadBox";
|
||||||
|
import Textarea from "@/components/Textarea";
|
||||||
|
import DatePickerComponent from "@/components/DatePicker";
|
||||||
|
import { useGetInvoiceDetail, useUpdateInvoice } from "./hooks/useInvoiceData";
|
||||||
|
import { useMultiUpload } from "../uploader/hooks/useUploader";
|
||||||
|
import moment from "moment-jalaali";
|
||||||
|
|
||||||
|
const createEmptyItem = (): CreatePreInvoiceItemType => ({
|
||||||
|
productId: "",
|
||||||
|
quantity: 1,
|
||||||
|
unitPrice: 0,
|
||||||
|
discount: 0,
|
||||||
|
description: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const UpdateInvoice: FC = () => {
|
||||||
|
const { id } = useParams<{ id: string }>();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const { data: invoiceData, isLoading: isLoadingInvoice } =
|
||||||
|
useGetInvoiceDetail(id);
|
||||||
|
const { mutate: submitUpdate, isPending } = useUpdateInvoice();
|
||||||
|
const multiUpload = useMultiUpload();
|
||||||
|
|
||||||
|
const invoice = invoiceData?.data;
|
||||||
|
|
||||||
|
const [items, setItems] = useState<CreatePreInvoiceItemType[]>([
|
||||||
|
createEmptyItem(),
|
||||||
|
]);
|
||||||
|
const [attachmentFiles, setAttachmentFiles] = useState<File[]>([]);
|
||||||
|
|
||||||
|
const formik = useFormik<
|
||||||
|
Pick<
|
||||||
|
UpdatePreInvoiceType,
|
||||||
|
"enableTax" | "approvalDeadline" | "paymentMethod" | "description"
|
||||||
|
>
|
||||||
|
>({
|
||||||
|
initialValues: {
|
||||||
|
enableTax: false,
|
||||||
|
approvalDeadline: "",
|
||||||
|
paymentMethod: "",
|
||||||
|
description: "",
|
||||||
|
},
|
||||||
|
validationSchema: Yup.object({
|
||||||
|
approvalDeadline: Yup.string().required("مهلت تایید اجباری است."),
|
||||||
|
}),
|
||||||
|
onSubmit: async (values) => {
|
||||||
|
const validItems = items.filter(
|
||||||
|
(i) => i.productId && i.quantity > 0 && i.unitPrice >= 0
|
||||||
|
);
|
||||||
|
|
||||||
|
if (validItems.length === 0) {
|
||||||
|
toast(
|
||||||
|
"حداقل یک آیتم با محصول، تعداد و مبلغ واحد معتبر اضافه کنید.",
|
||||||
|
"error"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const attachments: { type: string; url: string }[] =
|
||||||
|
invoice?.attachments?.map((a) => ({ type: a.type, url: a.url })) ?? [];
|
||||||
|
|
||||||
|
if (attachmentFiles.length) {
|
||||||
|
const uploadResult = await multiUpload.mutateAsync(attachmentFiles);
|
||||||
|
uploadResult?.data?.forEach((item) => {
|
||||||
|
attachments.push({
|
||||||
|
type: "uploads_attach",
|
||||||
|
url: item.url,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const params: UpdatePreInvoiceType = {
|
||||||
|
items: validItems.map((i) => ({
|
||||||
|
...(i.id ? { id: i.id } : {}),
|
||||||
|
productId: i.productId,
|
||||||
|
quantity: i.quantity,
|
||||||
|
unitPrice: i.unitPrice,
|
||||||
|
discount: i.discount || 0,
|
||||||
|
description: i.description || "",
|
||||||
|
})),
|
||||||
|
enableTax: values.enableTax,
|
||||||
|
approvalDeadline: moment(
|
||||||
|
values.approvalDeadline,
|
||||||
|
"jYYYY/jMM/jDD"
|
||||||
|
).format("YYYY-MM-DD"),
|
||||||
|
...(values.paymentMethod ? { paymentMethod: values.paymentMethod } : {}),
|
||||||
|
description: values.description,
|
||||||
|
...(attachments.length ? { attachments } : {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
|
submitUpdate(
|
||||||
|
{ id, params },
|
||||||
|
{
|
||||||
|
onSuccess: () => {
|
||||||
|
toast("پیش فاکتور با موفقیت ویرایش شد", "success");
|
||||||
|
navigate(Paths.perfomaInvoice.list);
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast(extractErrorMessage(error), "error");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (invoice) {
|
||||||
|
formik.setValues({
|
||||||
|
enableTax: invoice.enableTax ?? false,
|
||||||
|
approvalDeadline: invoice.approvalDeadline
|
||||||
|
? moment(invoice.approvalDeadline).format("jYYYY/jMM/jDD")
|
||||||
|
: "",
|
||||||
|
paymentMethod: invoice.paymentMethod ?? "",
|
||||||
|
description: invoice.description ?? "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const mappedItems: CreatePreInvoiceItemType[] =
|
||||||
|
invoice.items?.length > 0
|
||||||
|
? invoice.items.map((i) => ({
|
||||||
|
id: i.id,
|
||||||
|
productId: i.product?.id ?? "",
|
||||||
|
quantity: i.quantity ?? 1,
|
||||||
|
unitPrice: i.unitPrice ?? 0,
|
||||||
|
discount: i.discount ?? 0,
|
||||||
|
description: i.description ?? "",
|
||||||
|
}))
|
||||||
|
: [createEmptyItem()];
|
||||||
|
|
||||||
|
setItems(mappedItems);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [invoice]);
|
||||||
|
|
||||||
|
const handleItemChange = (
|
||||||
|
index: number,
|
||||||
|
field: keyof CreatePreInvoiceItemType,
|
||||||
|
value: string | number
|
||||||
|
) => {
|
||||||
|
const next = [...items];
|
||||||
|
next[index] = { ...next[index], [field]: value };
|
||||||
|
setItems(next);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addItem = (currentIndex: number) => {
|
||||||
|
const current = items[currentIndex];
|
||||||
|
const hasProduct = !!current?.productId;
|
||||||
|
const hasQuantity = (current?.quantity ?? 0) > 0;
|
||||||
|
const hasUnitPrice = (current?.unitPrice ?? 0) > 0;
|
||||||
|
|
||||||
|
if (!hasProduct || !hasQuantity || !hasUnitPrice) {
|
||||||
|
toast("لطفاً محصول، تعداد و مبلغ واحد را وارد کنید.", "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setItems([...items, createEmptyItem()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeItem = (index: number) => {
|
||||||
|
if (items.length <= 1) return;
|
||||||
|
setItems(items.filter((_, i) => i !== index));
|
||||||
|
};
|
||||||
|
|
||||||
|
const totalAmount = items.reduce(
|
||||||
|
(sum, i) => sum + (i.quantity || 0) * (i.unitPrice || 0) - (i.discount || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isLoadingInvoice || !invoice) {
|
||||||
|
return (
|
||||||
|
<div className="mt-5 flex items-center justify-center min-h-[200px]">
|
||||||
|
<div className="text-[#888888]">در حال بارگذاری...</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mt-5">
|
||||||
|
<div className="justify-between items-center flex">
|
||||||
|
<h1 className="text-lg font-light">
|
||||||
|
ویرایش پیش فاکتور #{invoice.invoiceNumber}
|
||||||
|
</h1>
|
||||||
|
<Button
|
||||||
|
className="w-fit px-5"
|
||||||
|
onClick={() => formik.handleSubmit()}
|
||||||
|
isLoading={isPending || multiUpload.isPending}
|
||||||
|
>
|
||||||
|
<div className="flex gap-2 items-center">
|
||||||
|
<TickSquare size={20} color="black" />
|
||||||
|
<div>ذخیره تغییرات</div>
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-white rounded-3xl p-6 mt-8">
|
||||||
|
<div className="font-light">اطلاعات پیش فاکتور</div>
|
||||||
|
|
||||||
|
<div className="mt-6 rowTwoInput">
|
||||||
|
<div className="opacity-70">
|
||||||
|
<div className="text-[13px] text-[#888888] mb-1.5">مشتری</div>
|
||||||
|
<div className="text-[15px]">
|
||||||
|
{invoice.user?.firstName && invoice.user?.lastName
|
||||||
|
? `${invoice.user.firstName} ${invoice.user.lastName}`
|
||||||
|
: invoice.user?.phone ?? "-"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-6">
|
||||||
|
{items.map((item, index) => (
|
||||||
|
<InvoiceItemRow
|
||||||
|
key={index}
|
||||||
|
item={item}
|
||||||
|
index={index}
|
||||||
|
onChange={handleItemChange}
|
||||||
|
onAdd={() => addItem(index)}
|
||||||
|
onRemove={() => removeItem(index)}
|
||||||
|
canRemove={items.length > 1}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-6 flex gap-2 items-center">
|
||||||
|
<Checkbox
|
||||||
|
id="enableTax"
|
||||||
|
checked={formik.values.enableTax}
|
||||||
|
onCheckedChange={(checked) =>
|
||||||
|
formik.setFieldValue("enableTax", !!checked)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="enableTax"
|
||||||
|
className="text-[13px] cursor-pointer select-none"
|
||||||
|
>
|
||||||
|
مالیات بر ارزش افزوده (۱۰ درصد)
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="rowTwoInput mt-6">
|
||||||
|
<DatePickerComponent
|
||||||
|
label="مهلت تایید"
|
||||||
|
placeholder="انتخاب تاریخ"
|
||||||
|
defaultValue={formik.values.approvalDeadline || undefined}
|
||||||
|
onChange={(date) => {
|
||||||
|
formik.setFieldValue("approvalDeadline", date);
|
||||||
|
formik.setFieldTouched("approvalDeadline", true);
|
||||||
|
}}
|
||||||
|
error_text={
|
||||||
|
formik.errors.approvalDeadline && formik.touched.approvalDeadline
|
||||||
|
? formik.errors.approvalDeadline
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-6">
|
||||||
|
<Textarea
|
||||||
|
label="روش پرداخت"
|
||||||
|
name="paymentMethod"
|
||||||
|
placeholder="روش پرداخت"
|
||||||
|
value={formik.values.paymentMethod}
|
||||||
|
onChange={(e) => formik.setFieldValue("paymentMethod", e.target.value)}
|
||||||
|
onBlur={formik.handleBlur}
|
||||||
|
error_text={
|
||||||
|
formik.errors.paymentMethod && formik.touched.paymentMethod
|
||||||
|
? formik.errors.paymentMethod
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-6">
|
||||||
|
<Textarea
|
||||||
|
label="توضیحات"
|
||||||
|
placeholder="توضیحات پیش فاکتور را وارد کنید..."
|
||||||
|
value={formik.values.description}
|
||||||
|
onChange={(e) => formik.setFieldValue("description", e.target.value)}
|
||||||
|
onBlur={formik.handleBlur}
|
||||||
|
name="description"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-6">
|
||||||
|
<UploadBox
|
||||||
|
isMultiple
|
||||||
|
label="فایل ضمیمه"
|
||||||
|
onChange={setAttachmentFiles}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-6 bg-[#F5F7FC] h-12 px-4 flex justify-between items-center rounded-xl">
|
||||||
|
<div className="text-[#888888] text-[13px]">مبلغ کل:</div>
|
||||||
|
<div className="font-semibold text-[13px]">
|
||||||
|
{totalAmount.toLocaleString("fa-IR")} تومان
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UpdateInvoice;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import * as api from "../service/InvoiceService";
|
import * as api from "../service/InvoiceService";
|
||||||
|
import type { UpdatePreInvoiceType } from "../types/Types";
|
||||||
|
|
||||||
export const useCreateInvoice = () => {
|
export const useCreateInvoice = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@@ -18,3 +19,28 @@ export const useGetInvoice = (page = 1) => {
|
|||||||
queryFn: () => api.getInvoice(page),
|
queryFn: () => api.getInvoice(page),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useGetInvoiceDetail = (id: string | undefined) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["invoice", id],
|
||||||
|
queryFn: () => api.getInvoiceById(id!),
|
||||||
|
enabled: !!id,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateInvoice = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({
|
||||||
|
id,
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
params: UpdatePreInvoiceType;
|
||||||
|
}) => api.updateInvoice(id, params),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["invoice"] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import axios from "@/config/axios";
|
import axios from "@/config/axios";
|
||||||
import type { CreatePreInvoiceType, GetInvoiceResponseType } from "../types/Types";
|
import type {
|
||||||
|
CreatePreInvoiceType,
|
||||||
|
GetInvoiceResponseType,
|
||||||
|
InvoiceType,
|
||||||
|
UpdatePreInvoiceType,
|
||||||
|
} from "../types/Types";
|
||||||
|
|
||||||
export const createInvoice = async (params: CreatePreInvoiceType) => {
|
export const createInvoice = async (params: CreatePreInvoiceType) => {
|
||||||
const { data } = await axios.post("/admin/invoice", params);
|
const { data } = await axios.post("/admin/invoice", params);
|
||||||
@@ -12,3 +17,13 @@ export const getInvoice = async (page = 1): Promise<GetInvoiceResponseType> => {
|
|||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getInvoiceById = async (id: string) => {
|
||||||
|
const { data } = await axios.get<{ data: InvoiceType }>(`/admin/invoice/${id}`);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateInvoice = async (id: string, params: UpdatePreInvoiceType) => {
|
||||||
|
const { data } = await axios.patch(`/admin/invoice/${id}`, params);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export type CreatePreInvoiceItemType = {
|
export type CreatePreInvoiceItemType = {
|
||||||
|
id?: string;
|
||||||
productId: string;
|
productId: string;
|
||||||
quantity: number;
|
quantity: number;
|
||||||
unitPrice: number;
|
unitPrice: number;
|
||||||
@@ -12,13 +13,23 @@ export type InvoiceAttachmentType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type CreatePreInvoiceType = {
|
export type CreatePreInvoiceType = {
|
||||||
|
id?: string;
|
||||||
requestId?: string;
|
requestId?: string;
|
||||||
userId?: string;
|
userId?: string;
|
||||||
items: CreatePreInvoiceItemType[];
|
items: CreatePreInvoiceItemType[];
|
||||||
enableTax: boolean;
|
enableTax: boolean;
|
||||||
approvalDeadline: string;
|
approvalDeadline: string;
|
||||||
paymentMethod?: string;
|
paymentMethod?: string;
|
||||||
notes?: string;
|
description?: string;
|
||||||
|
attachments?: InvoiceAttachmentType[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UpdatePreInvoiceType = {
|
||||||
|
items: CreatePreInvoiceItemType[];
|
||||||
|
enableTax: boolean;
|
||||||
|
approvalDeadline: string;
|
||||||
|
paymentMethod?: string;
|
||||||
|
description?: string;
|
||||||
attachments?: InvoiceAttachmentType[];
|
attachments?: InvoiceAttachmentType[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -91,6 +102,7 @@ export type InvoiceType = {
|
|||||||
approvalDeadline: string;
|
approvalDeadline: string;
|
||||||
attachments: InvoiceAttachmentType[];
|
attachments: InvoiceAttachmentType[];
|
||||||
paymentMethod: string;
|
paymentMethod: string;
|
||||||
|
description?: string;
|
||||||
items: InvoiceItemType[];
|
items: InvoiceItemType[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import CreateProduct from "@/pages/product/Create";
|
|||||||
import CreateFeature from "@/pages/Features/Create";
|
import CreateFeature from "@/pages/Features/Create";
|
||||||
import PrintService from "@/pages/service/PrintService";
|
import PrintService from "@/pages/service/PrintService";
|
||||||
import DetailPerfomaInvoice from "@/pages/invoice/DetailPerfomaInvoice";
|
import DetailPerfomaInvoice from "@/pages/invoice/DetailPerfomaInvoice";
|
||||||
|
import UpdateInvoice from "@/pages/invoice/Update";
|
||||||
import AnnouncementList from "@/pages/annoncement/List";
|
import AnnouncementList from "@/pages/annoncement/List";
|
||||||
import AnnouncementUpdate from "@/pages/annoncement/Update";
|
import AnnouncementUpdate from "@/pages/annoncement/Update";
|
||||||
import AnnouncementCreate from "@/pages/annoncement/Create";
|
import AnnouncementCreate from "@/pages/annoncement/Create";
|
||||||
@@ -63,6 +64,7 @@ const MainRouter: FC = () => {
|
|||||||
<Route path={Paths.perfomaInvoice.list} element={<ProformaInvoice />} />
|
<Route path={Paths.perfomaInvoice.list} element={<ProformaInvoice />} />
|
||||||
<Route path={Paths.perfomaInvoice.create} element={<CreateInvoice />} />
|
<Route path={Paths.perfomaInvoice.create} element={<CreateInvoice />} />
|
||||||
<Route path={Paths.perfomaInvoice.detail + ":id"} element={<DetailPerfomaInvoice />} />
|
<Route path={Paths.perfomaInvoice.detail + ":id"} element={<DetailPerfomaInvoice />} />
|
||||||
|
<Route path={Paths.perfomaInvoice.update + ":id"} element={<UpdateInvoice />} />
|
||||||
<Route path={Paths.requests.list} element={<RequestList />} />
|
<Route path={Paths.requests.list} element={<RequestList />} />
|
||||||
<Route path={Paths.requests.detail + ":id"} element={<RequestDetail />} />
|
<Route path={Paths.requests.detail + ":id"} element={<RequestDetail />} />
|
||||||
<Route path={Paths.product.list} element={<ProductList />} />
|
<Route path={Paths.product.list} element={<ProductList />} />
|
||||||
|
|||||||
Reference in New Issue
Block a user