From 593d771f713fab71b83b74c82b5430580b60fba5 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Mon, 16 Feb 2026 10:42:04 +0330 Subject: [PATCH] perfoma invoice --- .env | 3 +- src/pages/invoice/ProformaInvoice.tsx | 157 ++++++++++++++++++------ src/pages/order/hooks/useOrderData.ts | 7 ++ src/pages/order/service/OrderService.ts | 19 ++- 4 files changed, 140 insertions(+), 46 deletions(-) diff --git a/.env b/.env index 3575df2..27a1dae 100644 --- a/.env +++ b/.env @@ -1,3 +1,4 @@ -VITE_API_BASE_URL = 'http://10.86.60.88:4000' +VITE_API_BASE_URL = 'https://negareh-api.dev.danakcorp.com' +# VITE_API_BASE_URL = 'http://10.86.60.88:4000' VITE_TOKEN_NAME = 'negareh_at' VITE_REFRESH_TOKEN_NAME = 'negareh_art' diff --git a/src/pages/invoice/ProformaInvoice.tsx b/src/pages/invoice/ProformaInvoice.tsx index 9376248..4710782 100644 --- a/src/pages/invoice/ProformaInvoice.tsx +++ b/src/pages/invoice/ProformaInvoice.tsx @@ -1,30 +1,95 @@ import Tabs from '@/components/Tabs' -import { useState, type FC } from 'react' +import { useMemo, useState, type FC } from 'react' import { ProformaInvoiceStatusEnum } from './enum/InvoiceEnum' import Filters from '@/components/Filters' import Table from '@/components/Table' import { Eye } from 'iconsax-react' import { Link } from 'react-router-dom' import { Paths } from '@/config/Paths' +import { useGetOrdersInvoiced } from '../order/hooks/useOrderData' +import moment from 'moment-jalaali' +import type { OrderType } from '../order/types/Types' +import type { FilterValues } from '@/components/Filters' +import { OrderStatusEnum } from '../order/enum/OrderEnum' + +const isInvoiceConfirmed = (status: OrderStatusEnum) => + status !== OrderStatusEnum.WAITING_to_CONFIRM_INVOICE && + status !== OrderStatusEnum.CREATED && + status !== OrderStatusEnum.CANCELED const ProformaInvoice: FC = () => { + const [activeTab, setActiveTab] = useState(ProformaInvoiceStatusEnum.ALL) + const [page, setPage] = useState(1) + const [filters, setFilters] = useState({}) - const [activeTab, setactiveTab] = useState(ProformaInvoiceStatusEnum.ALL) + const { data, isLoading } = useGetOrdersInvoiced(page) + + const meta = data?.meta + + const filteredData = useMemo(() => { + const list = data?.data ?? [] + + if (activeTab === ProformaInvoiceStatusEnum.CONFIRMED) { + return list.filter((o) => isInvoiceConfirmed(o.status)) + } + if (activeTab === ProformaInvoiceStatusEnum.NOT_CONFIRMED) { + return list.filter((o) => o.status === OrderStatusEnum.WAITING_to_CONFIRM_INVOICE) + } + + let result = list + + const search = (filters.search ?? '').trim() + if (search) { + const lower = search.toLowerCase() + result = result.filter( + (o) => + String(o.orderNumber).includes(search) || + o.user?.firstName?.toLowerCase().includes(lower) || + o.user?.lastName?.toLowerCase().includes(lower) || + o.user?.phone?.includes(search) + ) + } + + const dateFilter = filters.date + if (dateFilter) { + const filterDate = moment(dateFilter, 'jYYYY/jMM/jDD').format('YYYY-MM-DD') + result = result.filter((o) => { + const d = o.invoicedAt || o.createdAt + return d && moment(d).format('YYYY-MM-DD') === filterDate + }) + } + + return result + }, [data?.data, activeTab, filters.search, filters.date]) + + const getPaymentStatus = (item: OrderType) => { + const total = Number(item.total) || 0 + const paid = Number(item.paidAmount) || 0 + if (total <= 0) return '-' + if (paid >= total) return 'پرداخت شده' + if (paid > 0) return 'پرداخت جزئی' + return 'پرداخت نشده' + } + + const getServiceLabel = (item: OrderType) => { + if (!item.items?.length) return '-' + if (item.items.length === 1) return item.items[0].product?.title ?? '-' + return `${item.items.length} خدمت` + } return (
-

- پیش فاکتورها -

+

پیش فاکتورها

+
setactiveTab(tab as ProformaInvoiceStatusEnum)} + onTabChange={(tab) => setActiveTab(tab as ProformaInvoiceStatusEnum)} />
@@ -34,7 +99,7 @@ const ProformaInvoice: FC = () => { { type: 'input', name: 'search', - placeholder: 'جستجو', + placeholder: 'جستجو (شماره سفارش / مشتری)', }, { type: 'date', @@ -42,7 +107,7 @@ const ProformaInvoice: FC = () => { placeholder: 'تاریخ', }, ]} - onChange={() => { }} + onChange={setFilters} />
@@ -50,65 +115,79 @@ const ProformaInvoice: FC = () => { item.orderNumber, }, { key: 'service', title: 'خدمت', + render: (item) => getServiceLabel(item), }, { key: 'issueDate', title: 'تاریخ صدور', + render: (item) => + item.invoicedAt + ? moment(item.invoicedAt).format('jYYYY/jMM/jDD') + : moment(item.createdAt).format('jYYYY/jMM/jDD'), }, { key: 'lastConfirmDate', title: 'آخرین مهلت تایید', + render: () => '-', }, { key: 'total', title: 'مجموع', + render: (item) => + item.total + ? Number(item.total).toLocaleString('fa-IR') + ' ریال' + : '-', }, { key: 'confirmStatus', title: 'وضعیت تایید', + render: (item) => { + const confirmed = isInvoiceConfirmed(item.status) + return ( + + {confirmed ? 'تایید شده' : 'تایید نشده'} + + ) + }, }, { key: 'paymentStatus', title: 'وضعیت پرداخت', + render: (item) => getPaymentStatus(item), }, { key: 'actions', title: '', - render: () => { - return ( - - - - ) - } - } - ]} - data={[ - { - id: 1, - service: 'خدمت 1', - issueDate: '2021-01-01', - lastConfirmDate: '2021-01-01', - total: 100000, - confirmStatus: 'تایید شده', - paymentStatus: 'پرداخت شده', - }, - { - id: 2, - service: 'خدمت 2', - issueDate: '2021-01-01', - lastConfirmDate: '2021-01-01', - total: 100000, - confirmStatus: 'تایید شده', - paymentStatus: 'پرداخت شده', + render: (item) => ( + + + + ), }, ]} + data={filteredData} + isLoading={isLoading} + noDataMessage='پیش فاکتوری یافت نشد.' + pagination={ + meta && meta.totalPages > 1 + ? { + currentPage: meta.page, + totalPages: meta.totalPages, + onPageChange: setPage, + } + : undefined + } /> diff --git a/src/pages/order/hooks/useOrderData.ts b/src/pages/order/hooks/useOrderData.ts index cb7b71d..2c586e0 100644 --- a/src/pages/order/hooks/useOrderData.ts +++ b/src/pages/order/hooks/useOrderData.ts @@ -9,6 +9,13 @@ export const useGetOrders = () => { }); }; +export const useGetOrdersInvoiced = (page: number = 1) => { + return useQuery({ + queryKey: ["orders-invoiced", page], + queryFn: () => api.getOrdersInvoiced(page), + }); +}; + export const useGetRequests = () => { return useQuery({ queryKey: ["requests"], diff --git a/src/pages/order/service/OrderService.ts b/src/pages/order/service/OrderService.ts index 466a0bc..52765c2 100644 --- a/src/pages/order/service/OrderService.ts +++ b/src/pages/order/service/OrderService.ts @@ -17,6 +17,13 @@ export const getOrders = async () => { return data; }; +export const getOrdersInvoiced = async (page: number = 1) => { + const { data } = await axios.get( + `/admin/orders/invoiced?page=${page}`, + ); + return data; +}; + export const getRequests = async () => { const { data } = await axios.get(`/admin/orders/request`); return data; @@ -24,14 +31,14 @@ export const getRequests = async () => { export const getOrderDetail = async (id: string) => { const { data } = await axios.get( - `/admin/orders/${id}` + `/admin/orders/${id}`, ); return data; }; export const getTickets = async (orderId: string) => { const { data } = await axios.get( - `/admin/ticket/order/${orderId}` + `/admin/ticket/order/${orderId}`, ); return data; }; @@ -39,7 +46,7 @@ export const getTickets = async (orderId: string) => { export const addTicket = async (ticketId: string, params: AddTicketType) => { const { data } = await axios.post( `/admin/ticket/order/item/${ticketId}`, - params + params, ); return data; }; @@ -51,7 +58,7 @@ export const submitOrder = async (params: CreateFinalOrderType) => { export const updateOrder = async ( orderId: string, - params: CreateFinalOrderType + params: CreateFinalOrderType, ) => { const { data } = await axios.patch(`/admin/orders/${orderId}`, params); return data; @@ -64,14 +71,14 @@ export const getProducts = async () => { export const getAttributes = async (productId?: number) => { const { data } = await axios.get( - `/admin/entity/${productId}/field` + `/admin/entity/${productId}/field`, ); return data; }; export const getOrderItem = async (itemId?: number) => { const { data } = await axios.get( - `/admin/orders/item/${itemId}` + `/admin/orders/item/${itemId}`, ); return data; };