mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-25 15:55:48 +00:00
feat(FE-364): Add PDF export for purchases per supplier
This commit is contained in:
@@ -0,0 +1,493 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Page,
|
||||||
|
Text,
|
||||||
|
View,
|
||||||
|
Document,
|
||||||
|
StyleSheet,
|
||||||
|
Font,
|
||||||
|
pdf,
|
||||||
|
} from '@react-pdf/renderer';
|
||||||
|
import { LogisticPurchasePerSupplierReport } from '@/types/api/report/logistic-stock';
|
||||||
|
import { formatDate, formatNumber } from '@/lib/helper';
|
||||||
|
|
||||||
|
Font.register({
|
||||||
|
family: 'Helvetica',
|
||||||
|
src: 'helvetica',
|
||||||
|
});
|
||||||
|
|
||||||
|
const pdfStyles = StyleSheet.create({
|
||||||
|
page: {
|
||||||
|
fontSize: 10,
|
||||||
|
fontFamily: 'Helvetica',
|
||||||
|
padding: 20,
|
||||||
|
backgroundColor: '#FFFFFF',
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
logo: {
|
||||||
|
width: 120,
|
||||||
|
height: 30,
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
companyInfo: {
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: 4,
|
||||||
|
color: '#1f74bf',
|
||||||
|
},
|
||||||
|
address: {
|
||||||
|
fontSize: 8,
|
||||||
|
color: '#666666',
|
||||||
|
maxWidth: 400,
|
||||||
|
marginBottom: 10,
|
||||||
|
},
|
||||||
|
divider: {
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: '#000000',
|
||||||
|
borderBottomStyle: 'solid',
|
||||||
|
marginBottom: 15,
|
||||||
|
},
|
||||||
|
titleSection: {
|
||||||
|
marginBottom: 10,
|
||||||
|
},
|
||||||
|
mainTitle: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: 5,
|
||||||
|
color: '#1f74bf',
|
||||||
|
},
|
||||||
|
parameterSection: {
|
||||||
|
fontSize: 9,
|
||||||
|
color: '#666666',
|
||||||
|
marginBottom: 15,
|
||||||
|
},
|
||||||
|
supplierTitle: {
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: 8,
|
||||||
|
color: '#1f74bf',
|
||||||
|
},
|
||||||
|
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: 8,
|
||||||
|
},
|
||||||
|
tableCellLast: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
},
|
||||||
|
tableCellHeader: {
|
||||||
|
flex: 1,
|
||||||
|
borderRightWidth: 1,
|
||||||
|
borderRightColor: '#000000',
|
||||||
|
borderRightStyle: 'solid',
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
backgroundColor: '#F5F5F5',
|
||||||
|
},
|
||||||
|
tableCellHeaderCenter: {
|
||||||
|
flex: 1,
|
||||||
|
borderRightWidth: 1,
|
||||||
|
borderRightColor: '#000000',
|
||||||
|
borderRightStyle: 'solid',
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
backgroundColor: '#F5F5F5',
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
tableCellHeaderRight: {
|
||||||
|
flex: 1,
|
||||||
|
borderRightWidth: 1,
|
||||||
|
borderRightColor: '#000000',
|
||||||
|
borderRightStyle: 'solid',
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
backgroundColor: '#F5F5F5',
|
||||||
|
textAlign: 'right',
|
||||||
|
},
|
||||||
|
tableCellHeaderRightLast: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
backgroundColor: '#F5F5F5',
|
||||||
|
textAlign: 'right',
|
||||||
|
},
|
||||||
|
tableCellHeaderLast: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
backgroundColor: '#F5F5F5',
|
||||||
|
},
|
||||||
|
tableCellHeaderCenterLast: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
backgroundColor: '#F5F5F5',
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
tableCellRight: {
|
||||||
|
flex: 1,
|
||||||
|
borderRightWidth: 1,
|
||||||
|
borderRightColor: '#000000',
|
||||||
|
borderRightStyle: 'solid',
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
textAlign: 'right',
|
||||||
|
},
|
||||||
|
tableCellCenter: {
|
||||||
|
flex: 1,
|
||||||
|
borderRightWidth: 1,
|
||||||
|
borderRightColor: '#000000',
|
||||||
|
borderRightStyle: 'solid',
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
tableCellRightLast: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
textAlign: 'right',
|
||||||
|
},
|
||||||
|
tableCellCenterLast: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
tableBorderBottom: {
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: '#000000',
|
||||||
|
borderBottomStyle: 'solid',
|
||||||
|
},
|
||||||
|
totalRow: {
|
||||||
|
backgroundColor: '#F5F5F5',
|
||||||
|
borderTopWidth: 1,
|
||||||
|
borderTopColor: '#000000',
|
||||||
|
borderTopStyle: 'solid',
|
||||||
|
},
|
||||||
|
totalCell: {
|
||||||
|
flex: 1,
|
||||||
|
borderRightWidth: 1,
|
||||||
|
borderRightColor: '#000000',
|
||||||
|
borderRightStyle: 'solid',
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
totalCellRight: {
|
||||||
|
flex: 1,
|
||||||
|
borderRightWidth: 1,
|
||||||
|
borderRightColor: '#000000',
|
||||||
|
borderRightStyle: 'solid',
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
textAlign: 'right',
|
||||||
|
},
|
||||||
|
totalCellRightLast: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
textAlign: 'right',
|
||||||
|
},
|
||||||
|
totalCellLast: {
|
||||||
|
flex: 1,
|
||||||
|
padding: 4,
|
||||||
|
fontSize: 8,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
supplierSection: {
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
supplierSectionBreak: {
|
||||||
|
marginBottom: 25,
|
||||||
|
},
|
||||||
|
badge: {
|
||||||
|
backgroundColor: '#1f74bf',
|
||||||
|
color: '#FFFFFF',
|
||||||
|
padding: 2,
|
||||||
|
borderRadius: 2,
|
||||||
|
fontSize: 7,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
alignSelf: 'flex-start',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
interface PurchasesPerSupplierExportParams {
|
||||||
|
data: LogisticPurchasePerSupplierReport['rows'];
|
||||||
|
params: {
|
||||||
|
area_name?: string;
|
||||||
|
supplier_name?: string;
|
||||||
|
product_name?: string;
|
||||||
|
product_category_name?: string;
|
||||||
|
received_date?: string;
|
||||||
|
po_date?: string;
|
||||||
|
start_date?: string;
|
||||||
|
end_date?: string;
|
||||||
|
sort_by?: string;
|
||||||
|
filter_by?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GroupedSupplierData {
|
||||||
|
id: number;
|
||||||
|
supplier: LogisticPurchasePerSupplierReport['rows'][number]['supplier'];
|
||||||
|
items: LogisticPurchasePerSupplierReport['rows'][number][];
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupDataBySupplier = (
|
||||||
|
data: LogisticPurchasePerSupplierReport['rows']
|
||||||
|
): GroupedSupplierData[] => {
|
||||||
|
const groups: {
|
||||||
|
[key: number]: GroupedSupplierData;
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
data.forEach((item) => {
|
||||||
|
const supplierId = item.supplier?.id;
|
||||||
|
if (supplierId && !groups[supplierId]) {
|
||||||
|
groups[supplierId] = {
|
||||||
|
id: supplierId,
|
||||||
|
supplier: item.supplier,
|
||||||
|
items: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (groups[supplierId]) {
|
||||||
|
groups[supplierId].items.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Object.values(groups) as GroupedSupplierData[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const getParameterText = (
|
||||||
|
params: PurchasesPerSupplierExportParams['params']
|
||||||
|
) => {
|
||||||
|
const paramsText = [];
|
||||||
|
|
||||||
|
if (params.filter_by === 'received_date') {
|
||||||
|
paramsText.push('Tanggal Terima');
|
||||||
|
} else if (params.filter_by === 'po_date') {
|
||||||
|
paramsText.push('Tanggal PO');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.supplier_name) {
|
||||||
|
paramsText.push(`Supplier: ${params.supplier_name}`);
|
||||||
|
} else {
|
||||||
|
paramsText.push('Semua Supplier');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.start_date && params.end_date) {
|
||||||
|
const startDate = formatDate(params.start_date, 'DD MMM YYYY');
|
||||||
|
const endDate = formatDate(params.end_date, 'DD MMM YYYY');
|
||||||
|
paramsText.push(`Periode: ${startDate} - ${endDate}`);
|
||||||
|
} else if (params.start_date) {
|
||||||
|
const startDate = formatDate(params.start_date, 'DD MMM YYYY');
|
||||||
|
paramsText.push(`Tanggal: ${startDate}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentDate = formatDate(new Date(), 'DD MMM YYYY HH:mm');
|
||||||
|
paramsText.push(`Dicetak: ${currentDate}`);
|
||||||
|
|
||||||
|
return paramsText.join(' | ');
|
||||||
|
};
|
||||||
|
|
||||||
|
const createPDFDocument = (
|
||||||
|
groupedData: GroupedSupplierData[],
|
||||||
|
params: PurchasesPerSupplierExportParams['params']
|
||||||
|
) => (
|
||||||
|
<Document>
|
||||||
|
<Page size='A3' orientation='landscape' style={pdfStyles.page}>
|
||||||
|
{/* Title and Parameters */}
|
||||||
|
<View style={pdfStyles.titleSection}>
|
||||||
|
<Text style={pdfStyles.mainTitle}>
|
||||||
|
Laporan > Rekapitulasi Pembelian Per Supplier
|
||||||
|
</Text>
|
||||||
|
<Text style={pdfStyles.parameterSection}>
|
||||||
|
Jenis Tanggal:{' '}
|
||||||
|
{params.filter_by === 'received_date'
|
||||||
|
? 'Tanggal Terima'
|
||||||
|
: 'Tanggal PO'}{' '}
|
||||||
|
| {getParameterText(params)}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Supplier Sections */}
|
||||||
|
{groupedData.map(
|
||||||
|
(supplierGroup: GroupedSupplierData, supplierIndex: number) => {
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
key={supplierGroup.id}
|
||||||
|
style={[
|
||||||
|
pdfStyles.supplierSection,
|
||||||
|
supplierIndex < groupedData.length - 1
|
||||||
|
? pdfStyles.supplierSectionBreak
|
||||||
|
: {},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Text style={pdfStyles.supplierTitle}>
|
||||||
|
{supplierGroup.supplier.name}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<View style={pdfStyles.table}>
|
||||||
|
{/* Table Header */}
|
||||||
|
<View style={[pdfStyles.tableRow, pdfStyles.tableHeader]}>
|
||||||
|
<View style={[pdfStyles.tableCellHeader, { flex: 0.5 }]}>
|
||||||
|
<Text>No</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellHeader}>
|
||||||
|
<Text>Tanggal Terima</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellHeader}>
|
||||||
|
<Text>Tanggal PO</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellHeader}>
|
||||||
|
<Text>Referensi</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellHeader}>
|
||||||
|
<Text>Produk</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellHeader}>
|
||||||
|
<Text>Tujuan</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 0.8 }]}>
|
||||||
|
<Text>Qty</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
||||||
|
<Text>Harga Beli</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.5 }]}>
|
||||||
|
<Text>Nilai Pembelian</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
||||||
|
<Text>Biaya Transport</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.5 }]}>
|
||||||
|
<Text>Total</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCellHeader, { flex: 1.2 }]}>
|
||||||
|
<Text>Armada</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellHeaderLast}>
|
||||||
|
<Text>Surat Jalan</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Table Body */}
|
||||||
|
{supplierGroup.items.map(
|
||||||
|
(
|
||||||
|
item: LogisticPurchasePerSupplierReport['rows'][number],
|
||||||
|
index: number
|
||||||
|
) => (
|
||||||
|
<View
|
||||||
|
key={index}
|
||||||
|
style={[
|
||||||
|
pdfStyles.tableRow,
|
||||||
|
index < supplierGroup.items.length - 1
|
||||||
|
? pdfStyles.tableBorderBottom
|
||||||
|
: {},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<View style={[pdfStyles.tableCell, { flex: 0.5 }]}>
|
||||||
|
<Text>{index + 1}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCell}>
|
||||||
|
<Text>
|
||||||
|
{formatDate(item.receive_date, 'DD-MMM-YYYY')}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCell}>
|
||||||
|
<Text>{formatDate(item.po_date, 'DD-MMM-YYYY')}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCell}>
|
||||||
|
<Text>{item.po_number || '-'}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCell}>
|
||||||
|
<Text>{item.product?.name || '-'}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCell}>
|
||||||
|
<Text>{item.warehouse?.name || '-'}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCellRight, { flex: 0.8 }]}>
|
||||||
|
<Text>{formatNumber(item.qty || 0)}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
||||||
|
<Text>{formatNumber(item.unit_price || 0)}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCellRight, { flex: 1.5 }]}>
|
||||||
|
<Text>{formatNumber(item.purchase_value || 0)}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
||||||
|
<Text>
|
||||||
|
{formatNumber(item.transport_unit_price || 0)}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCellRight, { flex: 1.5 }]}>
|
||||||
|
<Text>{formatNumber(item.total_amount || 0)}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCell, { flex: 1.2 }]}>
|
||||||
|
<View style={pdfStyles.badge}>
|
||||||
|
<Text>{item.expedition || '-'}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={pdfStyles.tableCellLast}>
|
||||||
|
<Text>{item.delivery_number || '-'}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</Page>
|
||||||
|
</Document>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const generatePurchasesPerSupplierPDF = async (
|
||||||
|
data: LogisticPurchasePerSupplierReport['rows'],
|
||||||
|
params: PurchasesPerSupplierExportParams['params']
|
||||||
|
): Promise<void> => {
|
||||||
|
const groupedData = groupDataBySupplier(data);
|
||||||
|
const PDFDocument = createPDFDocument(groupedData, params);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const blob = await pdf(PDFDocument).toBlob();
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = `laporan-pembelian-per-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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import Button from '@/components/Button';
|
|||||||
import Dropdown from '@/components/Dropdown';
|
import Dropdown from '@/components/Dropdown';
|
||||||
import MenuItem from '@/components/menu/MenuItem';
|
import MenuItem from '@/components/menu/MenuItem';
|
||||||
import Menu from '@/components/menu/Menu';
|
import Menu from '@/components/menu/Menu';
|
||||||
|
import { generatePurchasesPerSupplierPDF } from '@/components/pages/report/logistic-stock/export/PurchasesPerSupplierExport';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
|
||||||
interface Totals {
|
interface Totals {
|
||||||
totalQty: number;
|
totalQty: number;
|
||||||
@@ -34,6 +36,9 @@ interface Totals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PurchasesPerSupplierTab = () => {
|
const PurchasesPerSupplierTab = () => {
|
||||||
|
// ===== STATE MANAGEMENT =====
|
||||||
|
const [isPdfExportLoading, setIsPdfExportLoading] = useState(false);
|
||||||
|
|
||||||
// ===== PAGINATION STATE =====
|
// ===== PAGINATION STATE =====
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [pageSize, setPageSize] = useState(10);
|
const [pageSize, setPageSize] = useState(10);
|
||||||
@@ -247,13 +252,121 @@ const PurchasesPerSupplierTab = () => {
|
|||||||
? purchasePerSupplier.meta
|
? purchasePerSupplier.meta
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const { data: allDataForExport } = useSWR(
|
||||||
|
isSubmitted
|
||||||
|
? () => {
|
||||||
|
const params = {
|
||||||
|
area_id: tableFilterState.area_id
|
||||||
|
? Number(tableFilterState.area_id)
|
||||||
|
: undefined,
|
||||||
|
supplier_id: tableFilterState.supplier_id
|
||||||
|
? Number(tableFilterState.supplier_id)
|
||||||
|
: undefined,
|
||||||
|
product_id: tableFilterState.product_id
|
||||||
|
? Number(tableFilterState.product_id)
|
||||||
|
: undefined,
|
||||||
|
product_category_id: tableFilterState.product_category_id
|
||||||
|
? Number(tableFilterState.product_category_id)
|
||||||
|
: undefined,
|
||||||
|
received_date:
|
||||||
|
tableFilterState.filter_by === 'received_date'
|
||||||
|
? tableFilterState.start_date || undefined
|
||||||
|
: undefined,
|
||||||
|
po_date:
|
||||||
|
tableFilterState.filter_by === 'po_date'
|
||||||
|
? tableFilterState.start_date || undefined
|
||||||
|
: undefined,
|
||||||
|
start_date: tableFilterState.start_date || undefined,
|
||||||
|
end_date: tableFilterState.end_date || undefined,
|
||||||
|
sort_by: tableFilterState.sort_by || undefined,
|
||||||
|
filter_by: tableFilterState.filter_by || undefined,
|
||||||
|
limit: 10000,
|
||||||
|
page: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
return ['logistic-purchase-report-export', params];
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
([, params]) =>
|
||||||
|
LogisticApi.getLogisticStockReport(
|
||||||
|
params.area_id,
|
||||||
|
params.supplier_id,
|
||||||
|
params.product_id,
|
||||||
|
params.product_category_id,
|
||||||
|
params.received_date,
|
||||||
|
params.po_date,
|
||||||
|
params.start_date,
|
||||||
|
params.end_date,
|
||||||
|
params.sort_by,
|
||||||
|
params.filter_by,
|
||||||
|
params.page,
|
||||||
|
params.limit
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const allExportData: LogisticPurchasePerSupplierReport['rows'] = useMemo(
|
||||||
|
() =>
|
||||||
|
isResponseSuccess(allDataForExport)
|
||||||
|
? (allDataForExport?.data
|
||||||
|
?.rows as LogisticPurchasePerSupplierReport['rows']) || []
|
||||||
|
: [],
|
||||||
|
[allDataForExport]
|
||||||
|
);
|
||||||
|
|
||||||
const handleExportExcel = useCallback(() => {
|
const handleExportExcel = useCallback(() => {
|
||||||
alert('Export to Excel functionality to be implemented.');
|
toast.error('Export to Excel functionality will be implemented.');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleExportPdf = useCallback(() => {
|
const handleExportPdf = useCallback(async () => {
|
||||||
alert('Export to PDF functionality to be implemented.');
|
if (allExportData.length === 0) {
|
||||||
}, []);
|
toast.error('Tidak ada data untuk diekspor.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsPdfExportLoading(true);
|
||||||
|
try {
|
||||||
|
const exportParams = {
|
||||||
|
area_name: tableFilterState.area_id
|
||||||
|
? areaOptions.find(
|
||||||
|
(opt) => opt.value === Number(tableFilterState.area_id)
|
||||||
|
)?.label || ''
|
||||||
|
: 'Semua Area',
|
||||||
|
supplier_name: tableFilterState.supplier_id
|
||||||
|
? supplierOptions.find(
|
||||||
|
(opt) => opt.value === Number(tableFilterState.supplier_id)
|
||||||
|
)?.label || ''
|
||||||
|
: 'Semua Supplier',
|
||||||
|
product_name: tableFilterState.product_id
|
||||||
|
? productOptions.find(
|
||||||
|
(opt) => opt.value === Number(tableFilterState.product_id)
|
||||||
|
)?.label || ''
|
||||||
|
: 'Semua Produk',
|
||||||
|
product_category_name: tableFilterState.product_category_id
|
||||||
|
? productCategoryOptions.find(
|
||||||
|
(opt) =>
|
||||||
|
opt.value === Number(tableFilterState.product_category_id)
|
||||||
|
)?.label || ''
|
||||||
|
: 'Semua Kategori Produk',
|
||||||
|
filter_by: tableFilterState.filter_by || 'received_date',
|
||||||
|
start_date: tableFilterState.start_date || '',
|
||||||
|
end_date: tableFilterState.end_date || '',
|
||||||
|
};
|
||||||
|
|
||||||
|
await generatePurchasesPerSupplierPDF(allExportData, exportParams);
|
||||||
|
toast.success('PDF berhasil dibuat dan diunduh.');
|
||||||
|
} catch {
|
||||||
|
toast.error('Gagal membuat PDF. Silakan coba lagi.');
|
||||||
|
} finally {
|
||||||
|
setIsPdfExportLoading(false);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
allExportData,
|
||||||
|
tableFilterState,
|
||||||
|
areaOptions,
|
||||||
|
supplierOptions,
|
||||||
|
productOptions,
|
||||||
|
productCategoryOptions,
|
||||||
|
]);
|
||||||
|
|
||||||
// ===== PAGINATION HANDLERS =====
|
// ===== PAGINATION HANDLERS =====
|
||||||
const handlePageChange = (page: number) => {
|
const handlePageChange = (page: number) => {
|
||||||
@@ -483,7 +596,11 @@ const PurchasesPerSupplierTab = () => {
|
|||||||
Reset
|
Reset
|
||||||
</Button>
|
</Button>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={<Button color='success'>Export</Button>}
|
trigger={
|
||||||
|
<Button color='success' isLoading={isPdfExportLoading}>
|
||||||
|
Export
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
align='end'
|
align='end'
|
||||||
>
|
>
|
||||||
<Menu className='w-32'>
|
<Menu className='w-32'>
|
||||||
|
|||||||
Reference in New Issue
Block a user