invoice list
This commit is contained in:
@@ -6,23 +6,22 @@ import Table from '@/components/Table'
|
|||||||
import { Eye, Add } from 'iconsax-react'
|
import { Eye, Add } from 'iconsax-react'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { Paths } from '@/config/Paths'
|
import { Paths } from '@/config/Paths'
|
||||||
import { useGetOrdersInvoiced } from '../order/hooks/useOrderData'
|
|
||||||
import moment from 'moment-jalaali'
|
import moment from 'moment-jalaali'
|
||||||
import type { OrderType } from '../order/types/Types'
|
|
||||||
import type { FilterValues } from '@/components/Filters'
|
import type { FilterValues } from '@/components/Filters'
|
||||||
import { OrderStatusEnum } from '../order/enum/OrderEnum'
|
import { useGetInvoice } from './hooks/useInvoiceData'
|
||||||
|
import type { InvoiceType } from './types/Types'
|
||||||
|
|
||||||
const isInvoiceConfirmed = (status: OrderStatusEnum) =>
|
const isInvoiceConfirmed = (item: InvoiceType) => {
|
||||||
status !== OrderStatusEnum.WAITING_to_CONFIRM_INVOICE &&
|
const items = item.items ?? []
|
||||||
status !== OrderStatusEnum.CREATED &&
|
return items.length > 0 && items.every((i) => !!i.confirmedAt)
|
||||||
status !== OrderStatusEnum.CANCELED
|
}
|
||||||
|
|
||||||
const ProformaInvoice: FC = () => {
|
const ProformaInvoice: FC = () => {
|
||||||
const [activeTab, setActiveTab] = useState<ProformaInvoiceStatusEnum>(ProformaInvoiceStatusEnum.ALL)
|
const [activeTab, setActiveTab] = useState<ProformaInvoiceStatusEnum>(ProformaInvoiceStatusEnum.ALL)
|
||||||
const [page, setPage] = useState(1)
|
const [page, setPage] = useState(1)
|
||||||
const [filters, setFilters] = useState<FilterValues>({})
|
const [filters, setFilters] = useState<FilterValues>({})
|
||||||
|
|
||||||
const { data, isLoading } = useGetOrdersInvoiced(page)
|
const { data, isLoading } = useGetInvoice(page)
|
||||||
|
|
||||||
const meta = data?.meta
|
const meta = data?.meta
|
||||||
|
|
||||||
@@ -30,10 +29,10 @@ const ProformaInvoice: FC = () => {
|
|||||||
const list = data?.data ?? []
|
const list = data?.data ?? []
|
||||||
|
|
||||||
if (activeTab === ProformaInvoiceStatusEnum.CONFIRMED) {
|
if (activeTab === ProformaInvoiceStatusEnum.CONFIRMED) {
|
||||||
return list.filter((o) => isInvoiceConfirmed(o.status))
|
return list.filter((o) => isInvoiceConfirmed(o))
|
||||||
}
|
}
|
||||||
if (activeTab === ProformaInvoiceStatusEnum.NOT_CONFIRMED) {
|
if (activeTab === ProformaInvoiceStatusEnum.NOT_CONFIRMED) {
|
||||||
return list.filter((o) => o.status === OrderStatusEnum.WAITING_to_CONFIRM_INVOICE)
|
return list.filter((o) => !isInvoiceConfirmed(o))
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = list
|
let result = list
|
||||||
@@ -43,7 +42,7 @@ const ProformaInvoice: FC = () => {
|
|||||||
const lower = search.toLowerCase()
|
const lower = search.toLowerCase()
|
||||||
result = result.filter(
|
result = result.filter(
|
||||||
(o) =>
|
(o) =>
|
||||||
String(o.orderNumber).includes(search) ||
|
String(o.invoiceNumber).includes(search) ||
|
||||||
o.user?.firstName?.toLowerCase().includes(lower) ||
|
o.user?.firstName?.toLowerCase().includes(lower) ||
|
||||||
o.user?.lastName?.toLowerCase().includes(lower) ||
|
o.user?.lastName?.toLowerCase().includes(lower) ||
|
||||||
o.user?.phone?.includes(search)
|
o.user?.phone?.includes(search)
|
||||||
@@ -54,7 +53,7 @@ const ProformaInvoice: FC = () => {
|
|||||||
if (dateFilter) {
|
if (dateFilter) {
|
||||||
const filterDate = moment(dateFilter, 'jYYYY/jMM/jDD').format('YYYY-MM-DD')
|
const filterDate = moment(dateFilter, 'jYYYY/jMM/jDD').format('YYYY-MM-DD')
|
||||||
result = result.filter((o) => {
|
result = result.filter((o) => {
|
||||||
const d = o.invoicedAt || o.createdAt
|
const d = o.createdAt
|
||||||
return d && moment(d).format('YYYY-MM-DD') === filterDate
|
return d && moment(d).format('YYYY-MM-DD') === filterDate
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -62,7 +61,7 @@ const ProformaInvoice: FC = () => {
|
|||||||
return result
|
return result
|
||||||
}, [data?.data, activeTab, filters.search, filters.date])
|
}, [data?.data, activeTab, filters.search, filters.date])
|
||||||
|
|
||||||
const getPaymentStatus = (item: OrderType) => {
|
const getPaymentStatus = (item: InvoiceType) => {
|
||||||
const total = Number(item.total) || 0
|
const total = Number(item.total) || 0
|
||||||
const paid = Number(item.paidAmount) || 0
|
const paid = Number(item.paidAmount) || 0
|
||||||
if (total <= 0) return '-'
|
if (total <= 0) return '-'
|
||||||
@@ -71,7 +70,7 @@ const ProformaInvoice: FC = () => {
|
|||||||
return 'پرداخت نشده'
|
return 'پرداخت نشده'
|
||||||
}
|
}
|
||||||
|
|
||||||
const getServiceLabel = (item: OrderType) => {
|
const getServiceLabel = (item: InvoiceType) => {
|
||||||
if (!item.items?.length) return '-'
|
if (!item.items?.length) return '-'
|
||||||
if (item.items.length === 1) return item.items[0].product?.title ?? '-'
|
if (item.items.length === 1) return item.items[0].product?.title ?? '-'
|
||||||
return `${item.items.length} خدمت`
|
return `${item.items.length} خدمت`
|
||||||
@@ -123,9 +122,9 @@ const ProformaInvoice: FC = () => {
|
|||||||
<Table
|
<Table
|
||||||
columns={[
|
columns={[
|
||||||
{
|
{
|
||||||
key: 'orderNumber',
|
key: 'invoiceNumber',
|
||||||
title: 'شماره',
|
title: 'شماره',
|
||||||
render: (item) => item.orderNumber,
|
render: (item) => item.invoiceNumber,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'service',
|
key: 'service',
|
||||||
@@ -136,14 +135,17 @@ const ProformaInvoice: FC = () => {
|
|||||||
key: 'issueDate',
|
key: 'issueDate',
|
||||||
title: 'تاریخ صدور',
|
title: 'تاریخ صدور',
|
||||||
render: (item) =>
|
render: (item) =>
|
||||||
item.invoicedAt
|
item.createdAt
|
||||||
? moment(item.invoicedAt).format('jYYYY/jMM/jDD')
|
? moment(item.createdAt).format('jYYYY/jMM/jDD')
|
||||||
: moment(item.createdAt).format('jYYYY/jMM/jDD'),
|
: '-',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'lastConfirmDate',
|
key: 'lastConfirmDate',
|
||||||
title: 'آخرین مهلت تایید',
|
title: 'آخرین مهلت تایید',
|
||||||
render: () => '-',
|
render: (item) =>
|
||||||
|
item.approvalDeadline
|
||||||
|
? moment(item.approvalDeadline).format('jYYYY/jMM/jDD')
|
||||||
|
: '-',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'total',
|
key: 'total',
|
||||||
@@ -157,7 +159,7 @@ const ProformaInvoice: FC = () => {
|
|||||||
key: 'confirmStatus',
|
key: 'confirmStatus',
|
||||||
title: 'وضعیت تایید',
|
title: 'وضعیت تایید',
|
||||||
render: (item) => {
|
render: (item) => {
|
||||||
const confirmed = isInvoiceConfirmed(item.status)
|
const confirmed = isInvoiceConfirmed(item)
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className={`inline-flex h-6 items-center rounded-full px-2.5 text-xs ${confirmed ? 'bg-green-100 text-green-800' : 'bg-amber-100 text-amber-800'
|
className={`inline-flex h-6 items-center rounded-full px-2.5 text-xs ${confirmed ? 'bg-green-100 text-green-800' : 'bg-amber-100 text-amber-800'
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useMutation, 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";
|
||||||
|
|
||||||
export const useCreateInvoice = () => {
|
export const useCreateInvoice = () => {
|
||||||
@@ -7,7 +7,14 @@ export const useCreateInvoice = () => {
|
|||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: api.createInvoice,
|
mutationFn: api.createInvoice,
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries({ queryKey: ["orders-invoiced"] });
|
queryClient.invalidateQueries({ queryKey: ["invoice"] });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useGetInvoice = (page = 1) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["invoice", page],
|
||||||
|
queryFn: () => api.getInvoice(page),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import axios from "@/config/axios";
|
import axios from "@/config/axios";
|
||||||
import type { CreatePreInvoiceType } from "../types/Types";
|
import type { CreatePreInvoiceType, GetInvoiceResponseType } 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);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getInvoice = async (page = 1): Promise<GetInvoiceResponseType> => {
|
||||||
|
const { data } = await axios.get<GetInvoiceResponseType>("/admin/invoice", {
|
||||||
|
params: { page },
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|||||||
@@ -21,3 +21,87 @@ export type CreatePreInvoiceType = {
|
|||||||
notes?: string;
|
notes?: string;
|
||||||
attachments?: InvoiceAttachmentType[];
|
attachments?: InvoiceAttachmentType[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// API Response Types
|
||||||
|
export type InvoiceUserType = {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
firstName: string | null;
|
||||||
|
lastName: string | null;
|
||||||
|
isActive: boolean;
|
||||||
|
gender: boolean;
|
||||||
|
maxCredit: number;
|
||||||
|
addresse: string | null;
|
||||||
|
phone: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type InvoiceRequestType = {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
user: string;
|
||||||
|
requestNumber: number;
|
||||||
|
status: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type InvoiceProductType = {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
category: string;
|
||||||
|
title: string;
|
||||||
|
desc: string;
|
||||||
|
quantities: number[];
|
||||||
|
linkUrl: string | null;
|
||||||
|
isActive: boolean;
|
||||||
|
images: string[];
|
||||||
|
order: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type InvoiceItemType = {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
invoice: string;
|
||||||
|
product: InvoiceProductType;
|
||||||
|
quantity: number;
|
||||||
|
unitPrice: number;
|
||||||
|
subTotal: number | null;
|
||||||
|
discount: number | null;
|
||||||
|
total: number | null;
|
||||||
|
description: string;
|
||||||
|
confirmedAt: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type InvoiceType = {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
user: InvoiceUserType;
|
||||||
|
request: InvoiceRequestType;
|
||||||
|
invoiceNumber: number;
|
||||||
|
discount: number;
|
||||||
|
subTotal: number;
|
||||||
|
taxAmount: number;
|
||||||
|
total: number;
|
||||||
|
paidAmount: number;
|
||||||
|
balance: number;
|
||||||
|
enableTax: boolean;
|
||||||
|
approvalDeadline: string;
|
||||||
|
attachments: InvoiceAttachmentType[];
|
||||||
|
paymentMethod: string;
|
||||||
|
items: InvoiceItemType[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GetInvoiceResponseType = {
|
||||||
|
statusCode: number;
|
||||||
|
success: boolean;
|
||||||
|
data: InvoiceType[];
|
||||||
|
meta: {
|
||||||
|
total: number;
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
totalPages: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user