invoice payments

This commit is contained in:
hamid zarghami
2026-02-24 12:34:04 +03:30
parent 7e17191c1b
commit 0aa70b251e
5 changed files with 172 additions and 3 deletions
+11
View File
@@ -11,6 +11,8 @@ import { NumberFormat } from '@/config/func'
import moment from 'moment-jalaali'
import type { InvoiceItem as ApiInvoiceItem } from './types/InvoiceTypes'
import { Paths } from '@/config/Paths'
import { useGetPaymentInvoice } from '../payment/hooks/usePaymentData'
import InvoicePaymentList from './InvoicePaymentList'
interface TableInvoiceItem extends RowDataType {
id: string
@@ -26,9 +28,11 @@ interface TableInvoiceItem extends RowDataType {
const formatPrice = (num: number) => `${NumberFormat(num)} تومان`
const InvoiceDetail: FC = () => {
const { id } = useParams()
const queryClient = useQueryClient()
const { data, isPending } = useGetInvoiceDetail(id!)
useGetPaymentInvoice(id)
const { mutate: confirmInvoiceItem, isPending: isConfirming } = useConfirmInvoiceItem()
const [confirmingItemId, setConfirmingItemId] = useState<string | null>(null)
const invoice = data?.data
@@ -241,6 +245,8 @@ const InvoiceDetail: FC = () => {
</div>
)}
{/* Notes Section */}
<div className='mt-8 pt-6 border-t border-[#EBEDF5]'>
<div className='text-xs text-[#8C90A3] leading-6 space-y-2'>
@@ -250,6 +256,11 @@ const InvoiceDetail: FC = () => {
</div>
</div>
{/* لیست پرداخت‌ها */}
<div className="mt-8">
<InvoicePaymentList invoiceId={id!} />
</div>
<ModalConfirm
open={!!confirmingItemId}
onClose={() => setConfirmingItemId(null)}
+98
View File
@@ -0,0 +1,98 @@
import { type FC, useState } from 'react'
import Table from '@/components/Table'
import type { RowDataType } from '@/components/types/TableTypes'
import { NumberFormat } from '@/config/func'
import moment from 'moment-jalaali'
import { useGetPaymentInvoice } from '../payment/hooks/usePaymentData'
import type { PaymentItemType } from '../payment/types/Types'
import {
PaymentMethodEnum,
PaymentStatusEnum,
PaymentGatewayEnum,
} from '../payment/enum/Enum'
interface PaymentRowType extends RowDataType {
id: string
amount: string
method: string
gateway: string
status: string
date: string
transactionId: string
description: string
}
const formatPrice = (num: number) => `${NumberFormat(num)} تومان`
const statusLabels: Record<string, string> = {
[PaymentStatusEnum.Pending]: 'در انتظار',
[PaymentStatusEnum.Paid]: 'پرداخت شده',
[PaymentStatusEnum.Failed]: 'ناموفق',
[PaymentStatusEnum.Refunded]: 'مسترد شده',
}
const methodLabels: Record<string, string> = {
[PaymentMethodEnum.Online]: 'آنلاین',
[PaymentMethodEnum.Cash]: 'نقد',
[PaymentMethodEnum.Credit]: 'اعتباری',
}
const gatewayLabels: Record<string, string> = {
[PaymentGatewayEnum.ZarinPal]: 'زرین‌پال',
}
const mapPaymentToRow = (p: PaymentItemType): PaymentRowType => {
const date = p.paidAt || p.failedAt || p.createdAt
return {
id: p.id,
amount: formatPrice(p.amount),
method: methodLabels[p.method as keyof typeof methodLabels] ?? p.method,
gateway: p.gateway ? (gatewayLabels[p.gateway as keyof typeof gatewayLabels] ?? p.gateway) : '-',
status: statusLabels[p.status as keyof typeof statusLabels] ?? p.status,
date: date ? moment(date).format('jYYYY/jMM/jDD - HH:mm') : '-',
transactionId: p.transactionId ?? '-',
description: p.description ?? '-',
}
}
interface InvoicePaymentListProps {
invoiceId: string
}
const InvoicePaymentList: FC<InvoicePaymentListProps> = ({ invoiceId }) => {
const [page, setPage] = useState(1)
const { data, isPending } = useGetPaymentInvoice(invoiceId, page)
const payments = data?.data ?? []
const rows: PaymentRowType[] = payments.map(mapPaymentToRow)
const totalPages = data?.meta?.totalPages ?? 1
const columns = [
{ key: 'amount', title: 'مبلغ' },
{ key: 'method', title: 'روش پرداخت' },
{ key: 'gateway', title: 'درگاه' },
{ key: 'status', title: 'وضعیت' },
{ key: 'date', title: 'تاریخ' },
{ key: 'transactionId', title: 'شناسه تراکنش' },
{ key: 'description', title: 'توضیحات' },
]
return (
<div className="bg-white rounded-2xl p-8">
<div className="text-sm mb-6">لیست پرداختها</div>
<Table<PaymentRowType>
columns={columns}
data={rows}
showHeader={true}
isLoading={isPending}
noDataMessage="پرداختی برای این فاکتور ثبت نشده است."
pagination={{
currentPage: page,
totalPages,
onPageChange: setPage,
}}
/>
</div>
)
}
export default InvoicePaymentList
+12 -1
View File
@@ -1,4 +1,4 @@
import { useMutation } from "@tanstack/react-query";
import { useMutation, useQuery } from "@tanstack/react-query";
import * as api from "../service/PaymentService";
import type { PayInvoiceParamsType } from "../types/Types";
@@ -13,3 +13,14 @@ export const usePayInvoice = () => {
}) => api.payInvoice(invoiceId, params),
});
};
export const useGetPaymentInvoice = (
invoiceId?: string,
page: number = 1,
) => {
return useQuery({
queryKey: ["payment", invoiceId, page],
queryFn: () => api.getPaymentInvoice(invoiceId, page),
enabled: !!invoiceId,
});
};
+24 -1
View File
@@ -1,5 +1,8 @@
import axios from "@/config/axios";
import type { PayInvoiceParamsType } from "../types/Types";
import type {
GetPaymentInvoiceResponseType,
PayInvoiceParamsType,
} from "../types/Types";
export const payInvoice = async (
invoiceId: string,
@@ -11,3 +14,23 @@ export const payInvoice = async (
);
return data;
};
const DEFAULT_PAGE_SIZE = 10;
export const getPaymentInvoice = async (
invoiceId?: string,
page: number = 1,
limit: number = DEFAULT_PAGE_SIZE,
): Promise<GetPaymentInvoiceResponseType> => {
const { data } = await axios.get<GetPaymentInvoiceResponseType>(
`/public/payments`,
{
params: {
invoiceId,
page,
limit,
},
},
);
return data;
};
+27 -1
View File
@@ -1,4 +1,9 @@
import type { PaymentGatewayEnum, PaymentMethodEnum } from "../enum/Enum";
import type { BaseResponse } from "@/shared/types/Types";
import type {
PaymentGatewayEnum,
PaymentMethodEnum,
PaymentStatusEnum,
} from "../enum/Enum";
export type PayInvoiceParamsType = {
amount: number;
@@ -7,3 +12,24 @@ export type PayInvoiceParamsType = {
description: string;
attachments: string[];
};
export type PaymentItemType = {
id: string;
createdAt: string;
deletedAt: string | null;
invoice: string;
creator: string | null;
amount: number;
token: string | null;
method: PaymentMethodEnum | string;
gateway: PaymentGatewayEnum | string | null;
transactionId: string | null;
status: PaymentStatusEnum | string;
verifyResponse: unknown;
paidAt: string | null;
failedAt: string | null;
attachments: string[] | null;
description: string | null;
};
export type GetPaymentInvoiceResponseType = BaseResponse<PaymentItemType[]>;