mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE): Refactor PDF generation for purchases per supplier
This commit is contained in:
+158
-151
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
Page,
|
Page,
|
||||||
Text,
|
|
||||||
View,
|
View,
|
||||||
Document,
|
Document,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
@@ -15,7 +14,11 @@ import {
|
|||||||
PdfTable,
|
PdfTable,
|
||||||
PdfColumn,
|
PdfColumn,
|
||||||
PdfTbodyCell,
|
PdfTbodyCell,
|
||||||
|
PdfTfootCell,
|
||||||
} from '@/components/helper/pdf/table';
|
} 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({
|
Font.register({
|
||||||
family: 'Helvetica',
|
family: 'Helvetica',
|
||||||
@@ -32,53 +35,16 @@ const pdfStyles = StyleSheet.create({
|
|||||||
titleSection: {
|
titleSection: {
|
||||||
marginBottom: 10,
|
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: {
|
parameterContainer: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
marginBottom: 8,
|
marginBottom: 8,
|
||||||
},
|
},
|
||||||
supplierSection: {
|
|
||||||
marginBottom: 10,
|
|
||||||
},
|
|
||||||
supplierSectionBreak: {
|
|
||||||
marginBottom: 15,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
interface PurchasesPerSupplierExportParams {
|
interface PurchasesPerSupplierExportParams {
|
||||||
data: LogisticPurchasePerSupplierReport[];
|
data: LogisticPurchasePerSupplierReport[];
|
||||||
params: {
|
params?: {
|
||||||
area_name?: string;
|
area_name?: string;
|
||||||
supplier_name?: string;
|
supplier_name?: string;
|
||||||
product_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[] => [
|
const getTableColumns = (): PdfColumn[] => [
|
||||||
{ key: 'no', header: 'No', flex: 0.5, align: 'center' },
|
{ 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: 'receive_date',
|
||||||
{ key: 'po_number', header: 'Referensi', flex: 1, align: 'left' },
|
header: 'Tanggal Terima',
|
||||||
{ key: 'product', header: 'Produk', flex: 1, align: 'left' },
|
flex: 1.2,
|
||||||
{ key: 'warehouse', header: 'Tujuan', flex: 1, align: 'left' },
|
align: 'center',
|
||||||
{ key: 'qty', header: 'Qty', flex: 0.8, align: 'right' },
|
},
|
||||||
{ key: 'unit_price', header: 'Harga Beli', flex: 1.2, align: 'right' },
|
{ 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',
|
key: 'purchase_value',
|
||||||
header: 'Nilai Pembelian',
|
header: 'Value Harga Beli (Rp)',
|
||||||
flex: 1.5,
|
flex: 1.8,
|
||||||
align: 'right',
|
align: 'right',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'transport_price',
|
key: 'transport_unit_price',
|
||||||
header: 'Biaya Transport',
|
header: 'Transport (Rp)',
|
||||||
flex: 1.2,
|
flex: 1.3,
|
||||||
align: 'right',
|
align: 'right',
|
||||||
},
|
},
|
||||||
{ key: 'total_amount', header: 'Total', flex: 1.5, align: 'right' },
|
{
|
||||||
{ key: 'expedition', header: 'Armada', flex: 1.2, align: 'center' },
|
key: 'transport_value',
|
||||||
{ key: 'delivery_number', header: 'Surat Jalan', flex: 1, align: 'left' },
|
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 = (
|
const getTableData = (
|
||||||
rows: LogisticPurchasePerSupplierReport['rows']
|
rows: LogisticPurchasePerSupplierReport['rows']
|
||||||
): PdfTbodyCell[][] => {
|
): PdfTbodyCell[][] => {
|
||||||
return rows.map((item, index) => [
|
return rows.map((item, index) => [
|
||||||
{ key: 'no', value: index + 1, align: 'center' },
|
{ key: 'no', value: index + 1 },
|
||||||
{
|
{
|
||||||
key: 'receive_date',
|
key: 'receive_date',
|
||||||
value: formatDate(item.receive_date, 'DD-MMM-YYYY'),
|
value: item.receive_date
|
||||||
align: 'center',
|
? formatDate(item.receive_date, 'DD MMM YY')
|
||||||
|
: '-',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'po_date',
|
key: 'po_date',
|
||||||
value: formatDate(item.po_date, 'DD-MMM-YYYY'),
|
value: item.po_date ? formatDate(item.po_date, 'DD MMM YY') : '-',
|
||||||
align: 'center',
|
|
||||||
},
|
},
|
||||||
{ key: 'po_number', value: item.po_number || '-' },
|
{ key: 'po_number', value: item.po_number || '-' },
|
||||||
{ key: 'product', value: item.product?.name || '-' },
|
{ key: 'product', value: item.product?.name || '-' },
|
||||||
@@ -175,10 +125,15 @@ const getTableData = (
|
|||||||
align: 'right',
|
align: 'right',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'transport_price',
|
key: 'transport_unit_price',
|
||||||
value: formatCurrency(item.transport_unit_price || 0),
|
value: formatCurrency(item.transport_unit_price || 0),
|
||||||
align: 'right',
|
align: 'right',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'transport_value',
|
||||||
|
value: formatCurrency(item.transport_value || 0),
|
||||||
|
align: 'right',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'total_amount',
|
key: 'total_amount',
|
||||||
value: formatCurrency(item.total_amount || 0),
|
value: formatCurrency(item.total_amount || 0),
|
||||||
@@ -186,82 +141,134 @@ const getTableData = (
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'expedition',
|
key: 'expedition',
|
||||||
value: (
|
value: item.expedition ? (
|
||||||
<View style={pdfStyles.badge}>
|
<View style={{ alignItems: 'center' }}>
|
||||||
<Text>{item.expedition || '-'}</Text>
|
<PdfStatusBadge
|
||||||
|
backgroundColor='#DBEAFE'
|
||||||
|
textColor='#1E40AF'
|
||||||
|
borderColor='#60A5FA'
|
||||||
|
>
|
||||||
|
{item.expedition}
|
||||||
|
</PdfStatusBadge>
|
||||||
</View>
|
</View>
|
||||||
|
) : (
|
||||||
|
'-'
|
||||||
),
|
),
|
||||||
align: 'center',
|
|
||||||
},
|
},
|
||||||
{ key: 'delivery_number', value: item.delivery_number || '-' },
|
{ key: 'delivery_number', value: item.delivery_number || '-' },
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const createPDFDocument = (
|
const getTableFooter = (
|
||||||
supplierReports: LogisticPurchasePerSupplierReport[],
|
summary: LogisticPurchasePerSupplierReport['summary']
|
||||||
params: PurchasesPerSupplierExportParams['params']
|
): PdfTfootCell[] => [
|
||||||
) => (
|
{ key: 'no', value: 'Total' },
|
||||||
<Document>
|
{ key: 'receive_date', value: '' },
|
||||||
<Page size='A3' orientation='landscape' style={pdfStyles.page}>
|
{ key: 'po_date', value: '' },
|
||||||
{/* Title and Parameters */}
|
{ key: 'po_number', value: '' },
|
||||||
<View style={pdfStyles.titleSection}>
|
{ key: 'product', value: '' },
|
||||||
<Text style={pdfStyles.mainTitle}>
|
{ key: 'warehouse', value: '' },
|
||||||
Laporan > Rekapitulasi Pembelian Per Supplier
|
{
|
||||||
</Text>
|
key: 'qty',
|
||||||
<View style={pdfStyles.parameterContainer}>
|
value: formatNumber(summary?.total_qty || 0),
|
||||||
<View style={pdfStyles.parameterBadge}>
|
align: 'right',
|
||||||
<Text>
|
},
|
||||||
Jenis Tanggal:{' '}
|
{ key: 'unit_price', value: '' },
|
||||||
{params.filter_by === 'received_date'
|
{
|
||||||
? 'Tanggal Terima'
|
key: 'purchase_value',
|
||||||
: 'Tanggal PO'}
|
value: formatCurrency(summary?.total_purchase_value || 0),
|
||||||
</Text>
|
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 (
|
||||||
|
<Document>
|
||||||
|
{params.data.map((supplierReport, supplierIndex) => (
|
||||||
|
<Page
|
||||||
|
key={supplierIndex}
|
||||||
|
size='A3'
|
||||||
|
orientation='landscape'
|
||||||
|
style={pdfStyles.page}
|
||||||
|
>
|
||||||
|
{/* Title and Parameters */}
|
||||||
|
<View style={pdfStyles.titleSection}>
|
||||||
|
<PdfTypography size='h1' variant='primary'>
|
||||||
|
Laporan > Rekapitulasi Pembelian Per Supplier
|
||||||
|
</PdfTypography>
|
||||||
|
<View style={pdfStyles.parameterContainer}>
|
||||||
|
<PdfParamBadge>
|
||||||
|
Jenis Tanggal:{' '}
|
||||||
|
{params.params?.filter_by === 'received_date'
|
||||||
|
? 'Tanggal Terima'
|
||||||
|
: 'Tanggal PO'}
|
||||||
|
</PdfParamBadge>
|
||||||
|
<PdfParamBadge>
|
||||||
|
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')
|
||||||
|
: '-'}
|
||||||
|
</PdfParamBadge>
|
||||||
|
<PdfParamBadge>
|
||||||
|
Supplier: {params.params?.supplier_name || 'Semua Supplier'}
|
||||||
|
</PdfParamBadge>
|
||||||
|
<PdfParamBadge>
|
||||||
|
Area: {params.params?.area_name || 'Semua Area'}
|
||||||
|
</PdfParamBadge>
|
||||||
|
<PdfParamBadge>
|
||||||
|
Produk: {params.params?.product_name || 'Semua Produk'}
|
||||||
|
</PdfParamBadge>
|
||||||
|
<PdfParamBadge>
|
||||||
|
Dicetak: {formatDate(new Date(), 'DD MMM YYYY HH:mm')}
|
||||||
|
</PdfParamBadge>
|
||||||
|
</View>
|
||||||
|
<PdfTypography size='h2' variant='primary'>
|
||||||
|
{supplierReport.supplier.name}
|
||||||
|
</PdfTypography>
|
||||||
|
{supplierReport.supplier.address && (
|
||||||
|
<PdfTypography size='label'>
|
||||||
|
Alamat: {supplierReport.supplier.address}
|
||||||
|
</PdfTypography>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
{getParameterText(params).map((param, index) => (
|
|
||||||
<View key={index} style={pdfStyles.parameterBadge}>
|
|
||||||
<Text>{param}</Text>
|
|
||||||
</View>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* Supplier Sections */}
|
{/* Table */}
|
||||||
{supplierReports.map(
|
<PdfTable
|
||||||
(
|
columns={getTableColumns()}
|
||||||
supplierReport: LogisticPurchasePerSupplierReport,
|
data={getTableData(supplierReport.rows)}
|
||||||
supplierIndex: number
|
footer={
|
||||||
) => {
|
supplierReport.summary
|
||||||
return (
|
? getTableFooter(supplierReport.summary)
|
||||||
<View
|
: undefined
|
||||||
key={supplierReport.supplier.id}
|
}
|
||||||
style={[
|
/>
|
||||||
pdfStyles.supplierSection,
|
</Page>
|
||||||
supplierIndex < supplierReports.length - 1
|
))}
|
||||||
? pdfStyles.supplierSectionBreak
|
</Document>
|
||||||
: {},
|
);
|
||||||
]}
|
};
|
||||||
>
|
|
||||||
<Text style={pdfStyles.supplierTitle}>
|
|
||||||
{supplierReport.supplier.name}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<PdfTable
|
|
||||||
columns={getTableColumns()}
|
|
||||||
data={getTableData(supplierReport.rows)}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</Page>
|
|
||||||
</Document>
|
|
||||||
);
|
|
||||||
|
|
||||||
export const generatePurchasesPerSupplierPDF = async (
|
export const generatePurchasesPerSupplierPDF = async (
|
||||||
data: LogisticPurchasePerSupplierReport[],
|
params: PurchasesPerSupplierExportParams
|
||||||
params: PurchasesPerSupplierExportParams['params']
|
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const PDFDocument = createPDFDocument(data, params);
|
const PDFDocument = createPDFDocument(params);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const blob = await pdf(PDFDocument).toBlob();
|
const blob = await pdf(PDFDocument).toBlob();
|
||||||
|
|||||||
@@ -433,7 +433,10 @@ const PurchasesPerSupplierTab = () => {
|
|||||||
end_date: tableFilterState.end_date || '',
|
end_date: tableFilterState.end_date || '',
|
||||||
};
|
};
|
||||||
|
|
||||||
await generatePurchasesPerSupplierPDF(allDataForExport, exportParams);
|
await generatePurchasesPerSupplierPDF({
|
||||||
|
data: allDataForExport,
|
||||||
|
params: exportParams,
|
||||||
|
});
|
||||||
toast.success('PDF berhasil dibuat dan diunduh.');
|
toast.success('PDF berhasil dibuat dan diunduh.');
|
||||||
} catch {
|
} catch {
|
||||||
toast.error('Gagal membuat PDF. Silakan coba lagi.');
|
toast.error('Gagal membuat PDF. Silakan coba lagi.');
|
||||||
|
|||||||
Reference in New Issue
Block a user