From def894e5f4a40cf6f67e782615dc69c0f66457f4 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Tue, 10 Feb 2026 11:43:23 +0700 Subject: [PATCH] refactor(FE): Refactor PDF generation for purchases per supplier --- .../export/PurchasesPerSupplierExportPDF.tsx | 309 +++++++++--------- .../tab/PurchasesPerSupplierTab.tsx | 5 +- 2 files changed, 162 insertions(+), 152 deletions(-) diff --git a/src/components/pages/report/logistic-stock/export/PurchasesPerSupplierExportPDF.tsx b/src/components/pages/report/logistic-stock/export/PurchasesPerSupplierExportPDF.tsx index bd6f301a..cc2b7976 100644 --- a/src/components/pages/report/logistic-stock/export/PurchasesPerSupplierExportPDF.tsx +++ b/src/components/pages/report/logistic-stock/export/PurchasesPerSupplierExportPDF.tsx @@ -2,7 +2,6 @@ import { Page, - Text, View, Document, StyleSheet, @@ -15,7 +14,11 @@ import { PdfTable, PdfColumn, PdfTbodyCell, + PdfTfootCell, } from '@/components/helper/pdf/table'; +import { PdfParamBadge } from '@/components/helper/pdf/badge/PdfParamBadge'; +import { PdfStatusBadge } from '@/components/helper/pdf/badge/PdfStatusBadge'; +import { PdfTypography } from '@/components/helper/pdf/typography/PdfTypography'; Font.register({ family: 'Helvetica', @@ -32,53 +35,16 @@ const pdfStyles = StyleSheet.create({ titleSection: { marginBottom: 10, }, - mainTitle: { - fontSize: 14, - fontWeight: 'bold', - marginBottom: 5, - color: '#1f74bf', - }, - supplierTitle: { - fontSize: 12, - fontWeight: 'bold', - marginBottom: 8, - color: '#1f74bf', - }, - badge: { - backgroundColor: '#1f74bf', - color: '#FFFFFF', - padding: 2, - borderRadius: 2, - fontSize: 7, - fontWeight: 'bold', - alignSelf: 'center', - marginRight: 4, - }, - parameterBadge: { - backgroundColor: '#F5F5F5', - color: '#333333', - padding: 4, - borderRadius: 4, - fontSize: 8, - marginRight: 8, - marginBottom: 4, - }, parameterContainer: { flexDirection: 'row', flexWrap: 'wrap', marginBottom: 8, }, - supplierSection: { - marginBottom: 10, - }, - supplierSectionBreak: { - marginBottom: 15, - }, }); interface PurchasesPerSupplierExportParams { data: LogisticPurchasePerSupplierReport[]; - params: { + params?: { area_name?: string; supplier_name?: string; product_name?: string; @@ -92,73 +58,57 @@ interface PurchasesPerSupplierExportParams { }; } -const getParameterText = ( - params: PurchasesPerSupplierExportParams['params'] -) => { - const paramsText = []; - - 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; -}; - -// Helper functions for PdfTable const getTableColumns = (): PdfColumn[] => [ { key: 'no', header: 'No', flex: 0.5, align: 'center' }, - { key: 'receive_date', header: 'Tanggal Terima', flex: 1, align: 'center' }, - { key: 'po_date', header: 'Tanggal PO', flex: 1, align: 'center' }, - { key: 'po_number', header: 'Referensi', flex: 1, align: 'left' }, - { key: 'product', header: 'Produk', flex: 1, align: 'left' }, - { key: 'warehouse', header: 'Tujuan', flex: 1, align: 'left' }, - { key: 'qty', header: 'Qty', flex: 0.8, align: 'right' }, - { key: 'unit_price', header: 'Harga Beli', flex: 1.2, align: 'right' }, + { + key: 'receive_date', + header: 'Tanggal Terima', + flex: 1.2, + align: 'center', + }, + { key: 'po_date', header: 'Tanggal PO', flex: 1.2, align: 'center' }, + { key: 'po_number', header: 'No. Referensi', flex: 1.5, align: 'left' }, + { key: 'product', header: 'Nama Produk', flex: 2, align: 'left' }, + { key: 'warehouse', header: 'Tujuan', flex: 1.5, align: 'left' }, + { key: 'qty', header: 'QTY', flex: 0.8, align: 'right' }, + { key: 'unit_price', header: 'Harga Beli (Rp)', flex: 1.5, align: 'right' }, { key: 'purchase_value', - header: 'Nilai Pembelian', - flex: 1.5, + header: 'Value Harga Beli (Rp)', + flex: 1.8, align: 'right', }, { - key: 'transport_price', - header: 'Biaya Transport', - flex: 1.2, + key: 'transport_unit_price', + header: 'Transport (Rp)', + flex: 1.3, align: 'right', }, - { key: 'total_amount', header: 'Total', flex: 1.5, align: 'right' }, - { key: 'expedition', header: 'Armada', flex: 1.2, align: 'center' }, - { key: 'delivery_number', header: 'Surat Jalan', flex: 1, align: 'left' }, + { + key: 'transport_value', + header: 'Value Transport (Rp)', + flex: 1.8, + align: 'right', + }, + { key: 'total_amount', header: 'Jumlah (Rp)', flex: 1.5, align: 'right' }, + { key: 'expedition', header: 'Ekspedisi', flex: 1.2, align: 'center' }, + { key: 'delivery_number', header: 'Surat Jalan', flex: 1.2, align: 'left' }, ]; const getTableData = ( rows: LogisticPurchasePerSupplierReport['rows'] ): PdfTbodyCell[][] => { return rows.map((item, index) => [ - { key: 'no', value: index + 1, align: 'center' }, + { key: 'no', value: index + 1 }, { key: 'receive_date', - value: formatDate(item.receive_date, 'DD-MMM-YYYY'), - align: 'center', + value: item.receive_date + ? formatDate(item.receive_date, 'DD MMM YY') + : '-', }, { key: 'po_date', - value: formatDate(item.po_date, 'DD-MMM-YYYY'), - align: 'center', + value: item.po_date ? formatDate(item.po_date, 'DD MMM YY') : '-', }, { key: 'po_number', value: item.po_number || '-' }, { key: 'product', value: item.product?.name || '-' }, @@ -175,10 +125,15 @@ const getTableData = ( align: 'right', }, { - key: 'transport_price', + key: 'transport_unit_price', value: formatCurrency(item.transport_unit_price || 0), align: 'right', }, + { + key: 'transport_value', + value: formatCurrency(item.transport_value || 0), + align: 'right', + }, { key: 'total_amount', value: formatCurrency(item.total_amount || 0), @@ -186,82 +141,134 @@ const getTableData = ( }, { key: 'expedition', - value: ( - - {item.expedition || '-'} + value: item.expedition ? ( + + + {item.expedition} + + ) : ( + '-' ), - align: 'center', }, { key: 'delivery_number', value: item.delivery_number || '-' }, ]); }; -const createPDFDocument = ( - supplierReports: LogisticPurchasePerSupplierReport[], - params: PurchasesPerSupplierExportParams['params'] -) => ( - - - {/* Title and Parameters */} - - - Laporan > Rekapitulasi Pembelian Per Supplier - - - - - Jenis Tanggal:{' '} - {params.filter_by === 'received_date' - ? 'Tanggal Terima' - : 'Tanggal PO'} - +const getTableFooter = ( + summary: LogisticPurchasePerSupplierReport['summary'] +): PdfTfootCell[] => [ + { key: 'no', value: 'Total' }, + { key: 'receive_date', value: '' }, + { key: 'po_date', value: '' }, + { key: 'po_number', value: '' }, + { key: 'product', value: '' }, + { key: 'warehouse', value: '' }, + { + key: 'qty', + value: formatNumber(summary?.total_qty || 0), + align: 'right', + }, + { key: 'unit_price', value: '' }, + { + key: 'purchase_value', + value: formatCurrency(summary?.total_purchase_value || 0), + align: 'right', + }, + { key: 'transport_unit_price', value: '' }, + { + key: 'transport_value', + value: formatCurrency(summary?.total_transport_value || 0), + align: 'right', + }, + { + key: 'total_amount', + value: formatCurrency(summary?.total_amount || 0), + align: 'right', + }, + { key: 'expedition', value: '' }, + { key: 'delivery_number', value: '' }, +]; + +const createPDFDocument = (params: PurchasesPerSupplierExportParams) => { + return ( + + {params.data.map((supplierReport, supplierIndex) => ( + + {/* Title and Parameters */} + + + Laporan > Rekapitulasi Pembelian Per Supplier + + + + Jenis Tanggal:{' '} + {params.params?.filter_by === 'received_date' + ? 'Tanggal Terima' + : 'Tanggal PO'} + + + Periode:{' '} + {params.params?.start_date + ? formatDate(params.params.start_date, 'DD MMM YYYY') + : '-'}{' '} + s.d{' '} + {params.params?.end_date + ? formatDate(params.params.end_date, 'DD MMM YYYY') + : '-'} + + + Supplier: {params.params?.supplier_name || 'Semua Supplier'} + + + Area: {params.params?.area_name || 'Semua Area'} + + + Produk: {params.params?.product_name || 'Semua Produk'} + + + Dicetak: {formatDate(new Date(), 'DD MMM YYYY HH:mm')} + + + + {supplierReport.supplier.name} + + {supplierReport.supplier.address && ( + + Alamat: {supplierReport.supplier.address} + + )} - {getParameterText(params).map((param, index) => ( - - {param} - - ))} - - - {/* Supplier Sections */} - {supplierReports.map( - ( - supplierReport: LogisticPurchasePerSupplierReport, - supplierIndex: number - ) => { - return ( - - - {supplierReport.supplier.name} - - - - - ); - } - )} - - -); + {/* Table */} + + + ))} + + ); +}; export const generatePurchasesPerSupplierPDF = async ( - data: LogisticPurchasePerSupplierReport[], - params: PurchasesPerSupplierExportParams['params'] + params: PurchasesPerSupplierExportParams ): Promise => { - const PDFDocument = createPDFDocument(data, params); + const PDFDocument = createPDFDocument(params); try { const blob = await pdf(PDFDocument).toBlob(); diff --git a/src/components/pages/report/logistic-stock/tab/PurchasesPerSupplierTab.tsx b/src/components/pages/report/logistic-stock/tab/PurchasesPerSupplierTab.tsx index 1c5a4f2d..e1659470 100644 --- a/src/components/pages/report/logistic-stock/tab/PurchasesPerSupplierTab.tsx +++ b/src/components/pages/report/logistic-stock/tab/PurchasesPerSupplierTab.tsx @@ -433,7 +433,10 @@ const PurchasesPerSupplierTab = () => { end_date: tableFilterState.end_date || '', }; - await generatePurchasesPerSupplierPDF(allDataForExport, exportParams); + await generatePurchasesPerSupplierPDF({ + data: allDataForExport, + params: exportParams, + }); toast.success('PDF berhasil dibuat dan diunduh.'); } catch { toast.error('Gagal membuat PDF. Silakan coba lagi.');