refactor(FE): Refactor export logic for PurchasesPerSupplier report

This commit is contained in:
rstubryan
2026-02-10 11:36:27 +07:00
parent 80763acc53
commit 4f9401ed34
3 changed files with 105 additions and 88 deletions
@@ -0,0 +1,101 @@
'use client';
import ExcelJS from 'exceljs';
import { formatDate, formatCurrency, formatNumber } from '@/lib/helper';
import { LogisticPurchasePerSupplierReport } from '@/types/api/report/logistic-stock';
interface PurchasesPerSupplierExportExcelParams {
data: LogisticPurchasePerSupplierReport[];
}
export const generatePurchasesPerSupplierExcel = async (
params: PurchasesPerSupplierExportExcelParams
): Promise<void> => {
if (!params.data || params.data.length === 0) {
return;
}
const workbook = new ExcelJS.Workbook();
const columns = [
{ header: 'No', key: 'no', width: 5 },
{ header: 'Tanggal Terima', key: 'receiveDate', width: 15 },
{ header: 'Tanggal PO', key: 'poDate', width: 15 },
{ header: 'No. Referensi', key: 'poNumber', width: 15 },
{ header: 'Nama Produk', key: 'productName', width: 30 },
{ header: 'Tujuan', key: 'warehouse', width: 20 },
{ header: 'QTY', key: 'qty', width: 10 },
{ header: 'Harga Beli (Rp)', key: 'unitPrice', width: 18 },
{ header: 'Value Harga Beli (Rp)', key: 'purchaseValue', width: 20 },
{ header: 'Transport (Rp)', key: 'transportUnitPrice', width: 15 },
{ header: 'Value Transport (Rp)', key: 'transportValue', width: 20 },
{ header: 'Jumlah (Rp)', key: 'totalAmount', width: 18 },
{ header: 'Ekspedisi', key: 'expedition', width: 15 },
{ header: 'Surat Jalan', key: 'deliveryNumber', width: 15 },
];
for (const supplierReport of params.data) {
const supplierData = supplierReport.rows;
const supplierName = supplierReport.supplier?.name || 'Unknown Supplier';
const worksheet = workbook.addWorksheet(supplierName.substring(0, 31));
worksheet.columns = columns;
supplierData.forEach((item, index) => {
worksheet.addRow({
no: index + 1,
receiveDate: item.receive_date
? formatDate(item.receive_date, 'DD MMM YYYY')
: '',
poDate: item.po_date ? formatDate(item.po_date, 'DD MMM YYYY') : '',
poNumber: item.po_number || '',
productName: item.product?.name || '',
warehouse: item.warehouse?.name || '',
qty: formatNumber(item.qty || 0),
unitPrice: formatCurrency(item.unit_price || 0),
purchaseValue: formatCurrency(item.purchase_value || 0),
transportUnitPrice: formatCurrency(item.transport_unit_price || 0),
transportValue: formatCurrency(item.transport_value || 0),
totalAmount: formatCurrency(item.total_amount || 0),
expedition: item.expedition || '',
deliveryNumber: item.delivery_number || '',
});
});
if (supplierReport.summary) {
worksheet.addRow({
no: 'Total',
receiveDate: '',
poDate: '',
poNumber: '',
productName: '',
warehouse: '',
qty: formatNumber(supplierReport.summary.total_qty || 0),
unitPrice: '',
purchaseValue: formatCurrency(
supplierReport.summary.total_purchase_value || 0
),
transportUnitPrice: '',
transportValue: formatCurrency(
supplierReport.summary.total_transport_value || 0
),
totalAmount: formatCurrency(supplierReport.summary.total_amount || 0),
expedition: '',
deliveryNumber: '',
});
}
}
const filename = `laporan-pembelian-per-supplier-dicetak-pada-${formatDate(new Date(), 'YYYY-MM-DD-HHmm')}.xlsx`;
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.click();
window.URL.revokeObjectURL(url);
};
@@ -26,9 +26,9 @@ import Button from '@/components/Button';
import Dropdown from '@/components/Dropdown';
import MenuItem from '@/components/menu/MenuItem';
import Menu from '@/components/menu/Menu';
import { generatePurchasesPerSupplierPDF } from '@/components/pages/report/logistic-stock/export/PurchasesPerSupplierExport';
import { generatePurchasesPerSupplierPDF } from '@/components/pages/report/logistic-stock/export/PurchasesPerSupplierExportPDF';
import { generatePurchasesPerSupplierExcel } from '@/components/pages/report/logistic-stock/export/PurchasesPerSupplierExportXLSX';
import toast from 'react-hot-toast';
import * as XLSX from 'xlsx';
import { Icon } from '@iconify/react';
const PurchasesPerSupplierTab = () => {
@@ -355,98 +355,14 @@ const PurchasesPerSupplierTab = () => {
return;
}
const workbook = XLSX.utils.book_new();
allDataForExport.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,
'Tanggal Terima': item.receive_date
? formatDate(item.receive_date, 'DD MMM YYYY')
: '',
'Tanggal PO': item.po_date
? formatDate(item.po_date, 'DD MMM YYYY')
: '',
'No. Referensi': item.po_number || '',
'Nama Produk': item.product?.name || '',
Tujuan: item.warehouse?.name || '',
QTY: item.qty || 0,
'Harga Beli (Rp)': item.unit_price || 0,
'Value Harga Beli (Rp)': item.purchase_value || 0,
'Transport (Rp)': item.transport_unit_price || 0,
'Value Transport (Rp)': item.transport_value || 0,
'Jumlah (Rp)': item.total_amount || 0,
Ekspedisi: item.expedition || '',
'Surat Jalan': item.delivery_number || '',
}));
if (supplierReport.summary) {
excelData.push({
No: 'Total',
'Tanggal Terima': '',
'Tanggal PO': '',
'No. Referensi': '',
'Nama Produk': '',
Tujuan: '',
QTY: supplierReport.summary.total_qty || 0,
'Harga Beli (Rp)': '',
'Value Harga Beli (Rp)':
supplierReport.summary.total_purchase_value || 0,
'Transport (Rp)': '',
'Value Transport (Rp)':
supplierReport.summary.total_transport_value || 0,
'Jumlah (Rp)': supplierReport.summary.total_amount || 0,
Ekspedisi: '',
'Surat Jalan': '',
});
}
const worksheet = XLSX.utils.json_to_sheet(excelData);
const colWidths = [
{ wch: 5 }, // No
{ wch: 15 }, // Tanggal Terima
{ wch: 15 }, // Tanggal PO
{ wch: 15 }, // No. Referensi
{ wch: 30 }, // Nama Produk
{ wch: 20 }, // Tujuan
{ wch: 10 }, // QTY
{ wch: 18 }, // Harga Beli
{ wch: 20 }, // Value Harga Beli
{ wch: 15 }, // Transport
{ wch: 20 }, // Value Transport
{ wch: 18 }, // Jumlah
{ wch: 15 }, // Ekspedisi
{ wch: 15 }, // Surat Jalan
];
worksheet['!cols'] = colWidths;
const sheetName =
supplierName.length > 31
? supplierName.substring(0, 31)
: supplierName;
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
});
const filename = `laporan-pembelian-per-supplier-dicetak-pada-${formatDate(new Date(), 'YYYY-MM-DD-HHmm')}.xlsx`;
XLSX.writeFile(workbook, filename);
await generatePurchasesPerSupplierExcel({ data: allDataForExport });
toast.success('Excel berhasil dibuat dan diunduh.');
} catch {
toast.error('Gagal membuat Excel. Silakan coba lagi.');
} finally {
setIsExcelExportLoading(false);
}
}, [
logisticPurchasePerSupplierExport,
tableFilterState,
areaOptions,
supplierOptions,
]);
}, [logisticPurchasePerSupplierExport]);
const handleExportPdf = useCallback(async () => {
setIsPdfExportLoading(true);