diff --git a/src/components/pages/report/finance/FinanceTabs.tsx b/src/components/pages/report/finance/FinanceTabs.tsx index 7a970c76..0990065a 100644 --- a/src/components/pages/report/finance/FinanceTabs.tsx +++ b/src/components/pages/report/finance/FinanceTabs.tsx @@ -2,6 +2,7 @@ import Tabs from '@/components/Tabs'; import CustomerPaymentTab from '@/components/pages/report/finance/tab/CustomerPaymentTab'; +import DebtSupplier from '@/components/pages/report/finance/tab/DebtSupplier'; const FinanceTabs = () => { const tabs = [ @@ -11,6 +12,12 @@ const FinanceTabs = () => { content: , }, + { + id: '2', + label: 'Rekapitulasi Hutang Ke Supplier', + + content: , + }, ]; return ( diff --git a/src/components/pages/report/finance/export/DebtSupllierExportPDF.tsx b/src/components/pages/report/finance/export/DebtSupllierExportPDF.tsx new file mode 100644 index 00000000..42d27847 --- /dev/null +++ b/src/components/pages/report/finance/export/DebtSupllierExportPDF.tsx @@ -0,0 +1,363 @@ +'use client'; + +import { + Page, + Text, + View, + Document, + StyleSheet, + Font, + pdf, +} from '@react-pdf/renderer'; + +import { formatDate, formatCurrency, formatNumber } from '@/lib/helper'; +import { DebtSupplier } from '@/types/api/report/debt-supplier'; + +Font.register({ + family: 'Helvetica', + src: 'helvetica', +}); + +const pdfStyles = StyleSheet.create({ + page: { + fontSize: 10, + fontFamily: 'Helvetica', + padding: 20, + backgroundColor: '#FFFFFF', + }, + titleSection: { + marginBottom: 10, + }, + mainTitle: { + fontSize: 14, + fontWeight: 'bold', + marginBottom: 5, + color: '#1f74bf', + }, + supplierTitle: { + fontSize: 12, + fontWeight: 'bold', + marginBottom: 8, + color: '#1f74bf', + }, + supplierInfo: { + fontSize: 9, + marginBottom: 5, + color: '#333333', + }, + table: { + borderWidth: 1, + borderColor: '#000000', + marginBottom: 15, + }, + tableRow: { + flexDirection: 'row', + }, + tableHeader: { + backgroundColor: '#F5F5F5', + }, + tableCell: { + flex: 1, + borderRightWidth: 1, + borderRightColor: '#000000', + borderRightStyle: 'solid', + padding: 4, + fontSize: 7, + textAlign: 'left', + }, + tableCellNo: { + flex: 0.5, + borderRightWidth: 1, + borderRightColor: '#000000', + borderRightStyle: 'solid', + padding: 4, + fontSize: 7, + textAlign: 'center', + }, + tableCellLast: { + flex: 1, + padding: 4, + fontSize: 7, + }, + tableCellHeader: { + flex: 1, + borderRightWidth: 1, + borderRightColor: '#000000', + borderRightStyle: 'solid', + padding: 4, + fontSize: 7, + fontWeight: 'bold', + backgroundColor: '#F5F5F5', + borderBottomWidth: 1, + borderBottomColor: '#000000', + borderBottomStyle: 'solid', + paddingVertical: 12, + textAlign: 'center', + }, + tableCellHeaderRight: { + flex: 1, + borderRightWidth: 1, + borderRightColor: '#000000', + borderRightStyle: 'solid', + padding: 4, + fontSize: 7, + fontWeight: 'bold', + backgroundColor: '#F5F5F5', + textAlign: 'right', + borderBottomWidth: 1, + borderBottomColor: '#000000', + borderBottomStyle: 'solid', + paddingVertical: 12, + }, + tableCellRight: { + flex: 1, + borderRightWidth: 1, + borderRightColor: '#000000', + borderRightStyle: 'solid', + padding: 4, + fontSize: 7, + textAlign: 'right', + }, + tableCellCenter: { + flex: 1, + borderRightWidth: 1, + borderRightColor: '#000000', + borderRightStyle: 'solid', + padding: 4, + fontSize: 7, + textAlign: 'center', + }, + tableBorderBottom: { + borderBottomWidth: 1, + borderBottomColor: '#000000', + borderBottomStyle: 'solid', + }, + summaryRow: { + backgroundColor: '#F0F0F0', + fontWeight: 'bold', + }, +}); + +interface DebtSupplierExportPDFParams { + data: DebtSupplier[]; +} + +const createPDFDocument = (params: DebtSupplierExportPDFParams) => { + return ( + + {params.data.map((supplierReport, supplierIndex) => ( + + {/* Title and Supplier Info */} + + + Laporan > Hutang Supplier + + + {supplierReport.supplier.name} + + + + {/* Table */} + + {/* Table Header */} + + + No + + + No. PR + + + No. PO + + + Tgl PR + + + Tgl PO + + + Aging + + + Area + + + Gudang + + + Tgl Jatuh Tempo + + + Status JT + + + Total Harga + + + Pembayaran + + + Hutang + + + Status + + + No. Perjalanan + + + + {/* Table Body */} + {supplierReport.rows.map((item, index) => ( + + + {index + 1} + + + {item.pr_number || '-'} + + + {item.po_number || '-'} + + + + {item.pr_date ? formatDate(item.pr_date, 'DD MMM YY') : '-'} + + + + + {item.po_date ? formatDate(item.po_date, 'DD MMM YY') : '-'} + + + + {formatNumber(item.aging)} Hari + + + {item.area?.name || '-'} + + + {item.warehouse?.name || '-'} + + + + {item.due_date + ? formatDate(item.due_date, 'DD MMM YY') + : '-'} + + + + {item.due_status || '-'} + + + {formatCurrency(item.total_price)} + + + {formatCurrency(item.payment_price)} + + + {formatCurrency(item.debt_price)} + + + {item.status || '-'} + + + {item.travel_number || '-'} + + + ))} + + {/* Summary Row */} + {supplierReport.total && ( + + + Total + + + + + + + + + + + + + + + {formatNumber(supplierReport.total.aging)} Hari + + + + + + + + + + + + + + + + {formatCurrency(supplierReport.total.total_price)} + + + + + {formatCurrency(supplierReport.total.payment_price)} + + + + {formatCurrency(supplierReport.total.debt_price)} + + + + + + + + + )} + + + ))} + + ); +}; + +export const generateDebtSupplierPDF = async ( + params: DebtSupplierExportPDFParams +): Promise => { + const PDFDocument = createPDFDocument(params); + + try { + const blob = await pdf(PDFDocument).toBlob(); + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = `laporan-hutang-supplier-${formatDate(new Date(), 'YYYY-MM-DD-HHmm')}.pdf`; + + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + } catch (error) { + throw error; + } +}; diff --git a/src/components/pages/report/finance/export/DebtSupplierExportXLSX.tsx b/src/components/pages/report/finance/export/DebtSupplierExportXLSX.tsx new file mode 100644 index 00000000..820ba7ec --- /dev/null +++ b/src/components/pages/report/finance/export/DebtSupplierExportXLSX.tsx @@ -0,0 +1,101 @@ +'use client'; + +import * as XLSX from 'xlsx'; +import { formatDate, formatCurrency, formatNumber } from '@/lib/helper'; +import { DebtSupplier } from '@/types/api/report/debt-supplier'; + +interface DebtSupplierExportExcelParams { + data: DebtSupplier[]; +} + +export const generateDebtSupplierExcel = ( + params: DebtSupplierExportExcelParams +): void => { + if (!params.data || params.data.length === 0) { + return; + } + + const workbook = XLSX.utils.book_new(); + + params.data.forEach((supplierReport) => { + const supplierData = supplierReport.rows; + const supplierName = supplierReport.supplier.name || 'Unknown Supplier'; + + const excelData: { [key: string]: string | number }[] = supplierData.map( + (item, index) => ({ + No: index + 1, + 'Nomor PR': item.pr_number || '', + 'Nomor PO': item.po_number || '', + 'Tanggal PR': item.pr_date + ? formatDate(item.pr_date, 'DD MMM YYYY') + : '', + 'Tanggal PO': item.po_date + ? formatDate(item.po_date, 'DD MMM YYYY') + : '', + 'Aging (Hari)': formatNumber(item.aging || 0), + Area: item.area?.name || '', + Gudang: item.warehouse?.name || '', + 'Tanggal Jatuh Tempo': item.due_date + ? formatDate(item.due_date, 'DD MMM YYYY') + : '', + 'Status Jatuh Tempo': item.due_status || '', + 'Total Harga': formatCurrency(item.total_price || 0), + 'Harga Pembayaran': formatCurrency(item.payment_price || 0), + 'Harga Hutang': formatCurrency(item.debt_price || 0), + Status: item.status || '', + 'Nomor Perjalanan': item.travel_number || '', + }) + ); + + if (supplierReport.total) { + excelData.push({ + No: 'Total', + 'Nomor PR': '', + 'Nomor PO': '', + 'Tanggal PR': '', + 'Tanggal PO': '', + 'Aging (Hari)': formatNumber(supplierReport.total.aging || 0), + Area: '', + Gudang: '', + 'Tanggal Jatuh Tempo': '', + 'Status Jatuh Tempo': '', + 'Total Harga': formatCurrency(supplierReport.total.total_price || 0), + 'Harga Pembayaran': formatCurrency( + supplierReport.total.payment_price || 0 + ), + 'Harga Hutang': formatCurrency(supplierReport.total.debt_price || 0), + Status: '', + 'Nomor Perjalanan': '', + }); + } + + const worksheet = XLSX.utils.json_to_sheet(excelData); + + const colWidths = [ + { wch: 5 }, // No + { wch: 15 }, // Nomor PR + { wch: 15 }, // Nomor PO + { wch: 15 }, // Tanggal PR + { wch: 15 }, // Tanggal PO + { wch: 12 }, // Aging + { wch: 15 }, // Area + { wch: 15 }, // Gudang + { wch: 18 }, // Tanggal Jatuh Tempo + { wch: 18 }, // Status Jatuh Tempo + { wch: 15 }, // Total Harga + { wch: 15 }, // Harga Pembayaran + { wch: 15 }, // Harga Hutang + { wch: 12 }, // Status + { wch: 15 }, // Nomor Perjalanan + ]; + worksheet['!cols'] = colWidths; + + const sheetName = + supplierName.length > 31 ? supplierName.substring(0, 31) : supplierName; + XLSX.utils.book_append_sheet(workbook, worksheet, sheetName); + }); + + const filename = `laporan-hutang-supplier-${formatDate(new Date(), 'YYYY-MM-DD-HHmm')}.xlsx`; + + XLSX.writeFile(workbook, filename); +}; diff --git a/src/components/pages/report/finance/tab/DebtSupplier.tsx b/src/components/pages/report/finance/tab/DebtSupplier.tsx new file mode 100644 index 00000000..c62d66c2 --- /dev/null +++ b/src/components/pages/report/finance/tab/DebtSupplier.tsx @@ -0,0 +1,587 @@ +import Button from '@/components/Button'; +import Card from '@/components/Card'; +import Dropdown from '@/components/Dropdown'; +import DateInput from '@/components/input/DateInput'; +import SelectInput, { + OptionType, + useSelect, +} from '@/components/input/SelectInput'; +import Menu from '@/components/menu/Menu'; +import MenuItem from '@/components/menu/MenuItem'; +import Modal, { useModal } from '@/components/Modal'; +import Table from '@/components/Table'; +import { isResponseSuccess } from '@/lib/api-helper'; +import { formatCurrency, formatDate, formatNumber } from '@/lib/helper'; +import { SupplierApi } from '@/services/api/master-data'; +import { FinanceApi } from '@/services/api/report/finance-report'; +import { DebtRow, DebtSupplier } from '@/types/api/report/debt-supplier'; +import { generateDebtSupplierExcel } from '@/components/pages/report/finance/export/DebtSupplierExportXLSX'; +import { generateDebtSupplierPDF } from '@/components/pages/report/finance/export/DebtSupllierExportPDF'; +import { Icon } from '@iconify/react'; +import { ColumnDef } from '@tanstack/react-table'; +import { useCallback, useMemo, useState } from 'react'; +import toast from 'react-hot-toast'; +import useSWR from 'swr'; + +const DebtSupplierTab = () => { + // ===== STATE MANAGEMENT ===== + const [isPdfExportLoading, setIsPdfExportLoading] = useState(false); + const [isExcelExportLoading, setIsExcelExportLoading] = useState(false); + const isAnyExportLoading = isPdfExportLoading || isExcelExportLoading; + + // ===== PAGINATION STATE ===== + const [currentPage, setCurrentPage] = useState(1); + const [pageSize, setPageSize] = useState(10); + + // ===== SUBMISSION STATE ===== + const [isSubmitted, setIsSubmitted] = useState(false); + + // ===== FILTER STATE ===== + const [filterSupplier, setFilterSupplier] = useState([]); + const [filterStartDate, setFilterStartDate] = useState(''); + const [filterEndDate, setFilterEndDate] = useState(''); + const [filterErrors, setFilterErrors] = useState>({}); + + const filterModal = useModal(); + + const { options: supplierOptions, isLoadingOptions: isLoadingSuppliers } = + useSelect(SupplierApi.basePath, 'id', 'name', '', { + limit: 'limit', + }); + + const dataTypeOptions = useMemo( + () => [ + { value: 'do_date', label: 'Tanggal Terima' }, + { value: 'po_date', label: 'Tanggal PO' }, + ], + [] + ); + + // ===== FILTER HANDLERS ===== + const handleResetFilters = useCallback(() => { + setIsSubmitted(false); + setFilterSupplier([]); + setFilterStartDate(''); + setFilterEndDate(''); + setFilterErrors({}); + }, []); + + const handleApplyFilters = useCallback(() => { + const errors: Record = {}; + + if (!filterStartDate) { + errors.start_date = 'Tanggal mulai wajib diisi'; + } + if (!filterEndDate) { + errors.end_date = 'Tanggal akhir wajib diisi'; + } + + setFilterErrors(errors); + + if (Object.keys(errors).length === 0) { + setIsSubmitted(true); + setCurrentPage(1); + filterModal.closeModal(); + } + }, [filterModal, filterStartDate, filterEndDate]); + + // ===== DATA FETCHING ===== + // const { data: debtSupplier, isLoading } = useSWR( + // isSubmitted + // ? () => { + // const params = { + // supplier_id: + // filterSupplier.length > 0 + // ? filterSupplier.map((v) => String(v.value)).join(',') + // : undefined, + // filter_by: 'do_date' as const, + // start_date: filterStartDate || undefined, + // end_date: filterEndDate || undefined, + // page: currentPage, + // limit: pageSize, + // }; + + // return ['debt-supplier-report', params]; + // } + // : null, + // ([, params]) => + // FinanceApi.getDebtSupplierReport( + // params.supplier_id, + // params.filter_by, + // params.start_date, + // params.end_date, + // params.page, + // params.limit + // ) + // ); + const { data: debtSupplier, isLoading } = useSWR(FinanceApi.basePath, () => + FinanceApi.getDebtSupplierReport() + ); + + const data: DebtSupplier[] = useMemo( + () => + isResponseSuccess(debtSupplier) + ? (debtSupplier?.data as unknown as DebtSupplier[]) || [] + : [], + [debtSupplier] + ); + const meta = + isResponseSuccess(debtSupplier) && debtSupplier?.meta + ? debtSupplier.meta + : null; + + // ===== EXPORT DATA FETCHER ===== + const debtSupplierExport = useCallback(async (): Promise< + DebtSupplier[] | null + > => { + const params = { + supplier_id: + filterSupplier.length > 0 + ? filterSupplier.map((v) => String(v.value)).join(',') + : undefined, + filter_by: 'do_date' as const, + start_date: filterStartDate || undefined, + end_date: filterEndDate || undefined, + limit: 100, + page: 1, + }; + + const response = await FinanceApi.getDebtSupplierReport( + params.supplier_id, + params.filter_by, + params.start_date, + params.end_date, + params.page, + params.limit + ); + + return isResponseSuccess(response) + ? (response.data as unknown as DebtSupplier[]) + : null; + }, [filterSupplier, filterStartDate, filterEndDate]); + + // ===== EXPORT HANDLERS ===== + const handleExportExcel = useCallback(async () => { + setIsExcelExportLoading(true); + try { + const allDataForExport = await debtSupplierExport(); + + if ( + !allDataForExport || + !Array.isArray(allDataForExport) || + allDataForExport.length === 0 + ) { + toast.error('Tidak ada data untuk diekspor.'); + return; + } + + generateDebtSupplierExcel({ data: allDataForExport }); + toast.success('Excel berhasil dibuat dan diunduh.'); + } catch { + toast.error('Gagal membuat Excel. Silakan coba lagi.'); + } finally { + setIsExcelExportLoading(false); + } + }, [debtSupplierExport]); + + const handleExportPdf = useCallback(async () => { + setIsPdfExportLoading(true); + try { + const allDataForExport = await debtSupplierExport(); + + if ( + !allDataForExport || + !Array.isArray(allDataForExport) || + allDataForExport.length === 0 + ) { + toast.error('Tidak ada data untuk diekspor.'); + return; + } + + await generateDebtSupplierPDF({ data: allDataForExport }); + toast.success('PDF berhasil dibuat dan diunduh.'); + } catch { + toast.error('Gagal membuat PDF. Silakan coba lagi.'); + } finally { + setIsPdfExportLoading(false); + } + }, [debtSupplierExport]); + + // ===== PAGINATION HANDLERS ===== + const handlePageChange = (page: number) => { + setCurrentPage(page); + }; + + const handleRowChange = (pageSize: number) => { + setPageSize(pageSize); + }; + + const handleNextPage = () => { + if (meta && currentPage < meta.total_pages) { + setCurrentPage(currentPage + 1); + } + }; + + const handlePrevPage = () => { + if (currentPage > 1) { + setCurrentPage(currentPage - 1); + } + }; + + const getTableColumns = (supplier: DebtSupplier): ColumnDef[] => [ + { + id: 'no', + header: 'No', + cell: (props) => props.row.index + 1, + }, + { + id: 'pr_number', + header: 'Nomor PR', + accessorKey: 'pr_number', + cell: (props) => { + const value = props.row.original.pr_number; + return value || '-'; + }, + }, + { + id: 'po_number', + header: 'Nomor PO', + accessorKey: 'po_number', + cell: (props) => { + const value = props.row.original.po_number; + return value || '-'; + }, + }, + { + id: 'pr_date', + header: 'Tanggal PR', + accessorKey: 'pr_date', + cell: (props) => { + const value = props.row.original.pr_date; + return formatDate(value, 'DD MMM YYYY'); + }, + }, + { + id: 'po_date', + header: 'Tanggal PO', + accessorKey: 'po_date', + cell: (props) => { + const value = props.row.original.po_date; + return formatDate(value, 'DD MMM YYYY'); + }, + }, + { + id: 'aging', + header: 'Aging', + accessorKey: 'aging', + cell: (props) => { + const value = props.row.original.aging; + return
{formatNumber(value)} Hari
; + }, + footer: () => { + const value = supplier.total.aging; + return
{formatNumber(value)} Hari
; + }, + }, + { + id: 'area', + header: 'Area', + accessorKey: 'area', + cell: (props) => { + const value = props.row.original.area?.name; + return value || '-'; + }, + }, + { + id: 'warehouse', + header: 'Gudang', + accessorKey: 'warehouse', + cell: (props) => { + const value = props.row.original.warehouse?.name; + return value || '-'; + }, + }, + { + id: 'due_date', + header: 'Tanggal Jatuh Tempo', + accessorKey: 'due_date', + cell: (props) => { + const value = props.row.original.due_date; + return formatDate(value, 'DD MMM YYYY'); + }, + }, + { + id: 'due_status', + header: 'Status Jatuh Tempo', + accessorKey: 'due_status', + cell: (props) => { + const value = props.row.original.due_status; + return value || '-'; + }, + }, + { + id: 'total_price', + header: 'Total Harga', + accessorKey: 'total_price', + cell: (props) => { + const value = props.row.original.total_price; + return
{formatCurrency(value)}
; + }, + footer: () => { + const value = supplier.total.total_price; + return
{formatCurrency(value)}
; + }, + }, + { + id: 'payment_price', + header: 'Harga Pembayaran', + accessorKey: 'payment_price', + cell: (props) => { + const value = props.row.original.payment_price; + return
{formatCurrency(value)}
; + }, + footer: () => { + const value = supplier.total.payment_price; + return
{formatCurrency(value)}
; + }, + }, + { + id: 'debt_price', + header: 'Harga Hutang', + accessorKey: 'debt_price', + cell: (props) => { + const value = props.row.original.debt_price; + return ( +
+ {formatCurrency(value)} +
+ ); + }, + footer: () => { + const value = supplier.total.debt_price; + return ( +
+ {formatCurrency(value)} +
+ ); + }, + }, + { + id: 'status', + header: 'Status', + accessorKey: 'status', + cell: (props) => { + const value = props.row.original.status; + return value || '-'; + }, + }, + { + id: 'travel_number', + header: 'Nomor Perjalanan', + accessorKey: 'travel_number', + cell: (props) => { + const value = props.row.original.travel_number; + return value || '-'; + }, + }, + ]; + return ( + <> +
+ +
+ + + + + Export + + } + align='end' + > + + + + + +
+
+ + {/* {!isSubmitted ? ( +
+ Silakan klik tombol Filter untuk mengatur filter dan menampilkan + data. +
+ ) : isLoading ? ( +
+ +
+ ) : data.length === 0 ? ( +
+ Tidak ada data yang dapat ditampilkan... +
+ ) : ( */} + {data.map((supplierReport) => { + return ( + + 0} + className={{ + containerClassName: 'w-full', + tableWrapperClassName: 'overflow-x-auto mt-4', + tableClassName: 'w-full table-auto text-sm', + headerRowClassName: 'border-b border-b-gray-200 bg-gray-50', + headerColumnClassName: + 'px-4 py-3 text-xs font-semibold text-gray-700 text-left border border-gray-200', + bodyRowClassName: + 'hover:bg-gray-50 transition-colors border-b border-l border-r border-b-gray-200 border-l-gray-200 border-r-gray-200', + bodyColumnClassName: + 'px-4 py-3 text-xs text-gray-900 whitespace-nowrap', + tableFooterClassName: + 'bg-gray-100 font-semibold border border-gray-200', + footerRowClassName: 'border-t-2 border-gray-300', + footerColumnClassName: + 'px-4 py-3 text-xs text-gray-900 whitespace-nowrap', + paginationClassName: 'hidden', + }} + /> + + ); + })} + + + {/* Filter Modal */} + +
+ {/* Modal Header */} +
+
+ +

Filter Data

+
+ +
+
+
+
+ { + setFilterStartDate(e.target.value); + setFilterErrors((prev) => ({ ...prev, start_date: '' })); + }} + className={{ wrapper: 'w-full' }} + /> + {filterErrors.start_date && ( +

+ {filterErrors.start_date} +

+ )} +
+ +
+ { + setFilterEndDate(e.target.value); + setFilterErrors((prev) => ({ ...prev, end_date: '' })); + }} + className={{ wrapper: 'w-full' }} + /> + {filterErrors.end_date && ( +

+ {filterErrors.end_date} +

+ )} +
+
+ +
+ { + setFilterSupplier( + Array.isArray(val) ? val : val ? [val] : [] + ); + }} + isLoading={isLoadingSuppliers} + isClearable + className={{ wrapper: 'w-full' }} + /> +
+ +
+ +
+
+ + {/* Action Buttons */} +
+ + +
+
+
+ + ); +}; + +export default DebtSupplierTab; diff --git a/src/dummy/report/debt.supllier.dummy.json b/src/dummy/report/debt.supllier.dummy.json new file mode 100644 index 00000000..6afaa870 --- /dev/null +++ b/src/dummy/report/debt.supllier.dummy.json @@ -0,0 +1,168 @@ +[ + { + "supplier": { + "id": 1, + "name": "INDOVETRACO MAKMUR ABADI (IMA)" + }, + "rows": [ + { + "pr_number": "PR-MBU-02145", + "po_number": "PO-MBU-02145", + "pr_date": "2025-11-03", + "po_date": "2025-11-05", + "aging": 68, + "area": { + "id": 101, + "name": "Banten 1" + }, + "warehouse": { + "id": 201, + "name": "Gudang Area Banten" + }, + "due_date": "2025-12-03", + "due_status": "Sudah Jatuh Tempo", + "total_price": 8658000, + "payment_price": 0, + "debt_price": -8658000, + "status": "Belum Lunas", + "travel_number": "-" + } + ], + "total": { + "aging": 68, + "total_price": 8658000, + "payment_price": 0, + "debt_price": -8658000 + } + }, + { + "supplier": { + "id": 2, + "name": "MANDIRI BERLIAN UNGGAS (MANBU)" + }, + "rows": [ + { + "pr_number": "PR-MBU-01980", + "po_number": "PO-MBU-01980", + "pr_date": "2025-08-20", + "po_date": "2025-09-18", + "aging": 143, + "area": { + "id": 101, + "name": "Banten 1" + }, + "warehouse": { + "id": 202, + "name": "GUDANG CIANGSANA 5 (P16)" + }, + "due_date": "2025-08-21", + "due_status": "Sudah Jatuh Tempo", + "total_price": 266700000, + "payment_price": 0, + "debt_price": -267245000, + "status": "Belum Lunas", + "travel_number": "-" + }, + { + "pr_number": "PR-MBU-01981", + "po_number": "PO-MBU-01981", + "pr_date": "2025-08-21", + "po_date": "2025-09-18", + "aging": 142, + "area": { + "id": 102, + "name": "Priangan Timur 2" + }, + "warehouse": { + "id": 203, + "name": "GUDANG SINGAPARNA 1 P.7" + }, + "due_date": "2025-08-22", + "due_status": "Sudah Jatuh Tempo", + "total_price": 157480000, + "payment_price": 0, + "debt_price": -424725000, + "status": "Belum Lunas", + "travel_number": "-" + } + ], + "total": { + "aging": 143, + "total_price": 424180000, + "payment_price": 0, + "debt_price": -692465000 + } + }, + { + "supplier": { + "id": 3, + "name": "SUMBER PROTEIN JAYA" + }, + "rows": [ + { + "pr_number": "PR-SPJ-00551", + "po_number": "PO-SPJ-00551", + "pr_date": "2025-12-01", + "po_date": "2025-12-02", + "aging": 39, + "area": { + "id": 103, + "name": "Jawa Tengah" + }, + "warehouse": { + "id": 204, + "name": "Gudang Solo" + }, + "due_date": "2026-01-01", + "due_status": "Mendekati Jatuh Tempo", + "total_price": 45000000, + "payment_price": 15000000, + "debt_price": -30000000, + "status": "Belum Lunas", + "travel_number": "SJ-001/XII" + } + ], + "total": { + "aging": 39, + "total_price": 45000000, + "payment_price": 15000000, + "debt_price": -30000000 + } + }, + { + "supplier": { + "id": 4, + "name": "CHAROEN POKPHAND INDONESIA" + }, + "rows": [ + { + "pr_number": "PR-CPI-0992", + "po_number": "PO-CPI-0992", + "pr_date": "2025-11-15", + "po_date": "2025-11-16", + "aging": 56, + "area": { + "id": 104, + "name": "Jawa Timur" + }, + "warehouse": { + "id": 205, + "name": "Gudang Surabaya" + }, + "due_date": "2025-12-15", + "due_status": "Sudah Jatuh Tempo", + "total_price": 125000000, + "payment_price": 0, + "debt_price": -125000000, + "status": "Belum Lunas", + "travel_number": "-" + } + ], + "total": { + "aging": 56, + "total_price": 125000000, + "payment_price": 0, + "debt_price": -125000000 + } + } +] \ No newline at end of file diff --git a/src/dummy/report/debt.supllier.dummy.ts b/src/dummy/report/debt.supllier.dummy.ts new file mode 100644 index 00000000..63b87aef --- /dev/null +++ b/src/dummy/report/debt.supllier.dummy.ts @@ -0,0 +1,35 @@ +/** + * Dummy data for DebtSupplier[] + * Generated from: debt.supllier.dummy.json + * + * This file is auto-generated. Do not edit manually. + */ + +import { DebtSupplier } from '../../types/api/report/debt-supplier'; +import { BaseApiResponse } from '@/types/api/api-general'; +import dummyData from './debt.supllier.dummy.json'; + +/** + * Get dummy DebtSupplier[] data + * @returns Promise with BaseApiResponse containing DebtSupplier[] + */ +export async function getDebtSupllierDummy(): Promise< + BaseApiResponse +> { + return new Promise((resolve) => { + setTimeout(() => { + resolve({ + code: 200, + status: 'success', + message: 'Data retrieved successfully', + meta: { + total_pages: 1, + page: 1, + limit: 10, + total_results: dummyData.length, + }, + data: dummyData as unknown as DebtSupplier[], + }); + }, 500); + }); +} diff --git a/src/services/api/report/finance-report.ts b/src/services/api/report/finance-report.ts index e0acb6b0..5dfb78bb 100644 --- a/src/services/api/report/finance-report.ts +++ b/src/services/api/report/finance-report.ts @@ -1,6 +1,8 @@ +import { getDebtSupllierDummy } from '@/dummy/report/debt.supllier.dummy'; import { BaseApiService } from '@/services/api/base'; import { BaseApiResponse } from '@/types/api/api-general'; import { CustomerPaymentReport } from '@/types/api/report/customer-payment'; +import { DebtSupplier } from '@/types/api/report/debt-supplier'; export class FinanceApiService extends BaseApiService< CustomerPaymentReport, @@ -36,6 +38,31 @@ export class FinanceApiService extends BaseApiService< } ); } + + async getDebtSupplierReport( + supplier_id?: string, + filter_by?: 'do_date', + start_date?: string, + end_date?: string, + page?: number, + limit?: number + ): Promise | undefined> { + return (await getDebtSupllierDummy()) as BaseApiResponse; + return await this.customRequest>( + `debt-supplier`, + { + method: 'GET', + params: { + supplier_id: supplier_id, + filter_by: filter_by, + start_date: start_date, + end_date: end_date, + page: page, + limit: limit, + }, + } + ); + } } export const FinanceApi = new FinanceApiService('reports'); diff --git a/src/types/api/report/debt-supplier.d.ts b/src/types/api/report/debt-supplier.d.ts new file mode 100644 index 00000000..f7342501 --- /dev/null +++ b/src/types/api/report/debt-supplier.d.ts @@ -0,0 +1,34 @@ +import { BaseMetadata } from '@/types/api/api-general'; +import { Area } from '@/types/api/master-data/area'; +import { Supplier } from '@/types/api/master-data/supplier'; +import { Warehouse } from '@/types/api/master-data/warehouse'; + +export type DebtSupplier = BaseMetadata & { + supplier: Supplier; + rows: DebtRow[]; + total: DebtTotal; +}; + +export type DebtRow = { + pr_number: string; + po_number: string; + pr_date: string; + po_date: string; + aging: number; + area: Area; + warehouse: Warehouse; + due_date: string; + due_status: string; + total_price: number; + payment_price: number; + debt_price: number; + status: string; + travel_number: string; +}; + +export type DebtTotal = { + aging: number; + total_price: number; + payment_price: number; + debt_price: number; +};