mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-25 15:55:48 +00:00
refactor(FE-355,356,257): Use API summary per_weight_range for HPP
reports
This commit is contained in:
@@ -9,7 +9,11 @@ import {
|
|||||||
Font,
|
Font,
|
||||||
pdf,
|
pdf,
|
||||||
} from '@react-pdf/renderer';
|
} from '@react-pdf/renderer';
|
||||||
import { HppPerKandangReport } from '@/types/api/report/hpp-per-kandang';
|
import {
|
||||||
|
HppPerKandangReport,
|
||||||
|
HppPerKandangRow,
|
||||||
|
HppPerKandangPerWeightRange,
|
||||||
|
} from '@/types/api/report/hpp-per-kandang';
|
||||||
import { formatDate, formatNumber, formatCurrency } from '@/lib/helper';
|
import { formatDate, formatNumber, formatCurrency } from '@/lib/helper';
|
||||||
|
|
||||||
Font.register({
|
Font.register({
|
||||||
@@ -148,74 +152,6 @@ interface HppPerKandangExportParams {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const rekapitulasiData = (data: HppPerKandangReport['rows']) => {
|
|
||||||
const groups: { [key: string]: HppPerKandangReport['rows'] } = {};
|
|
||||||
|
|
||||||
data.forEach((item) => {
|
|
||||||
const key = `${item.weight_range.weight_min}-${item.weight_range.weight_max}`;
|
|
||||||
if (!groups[key]) {
|
|
||||||
groups[key] = [];
|
|
||||||
}
|
|
||||||
groups[key].push(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
return Object.entries(groups)
|
|
||||||
.map(([key, items]) => ({
|
|
||||||
weight_min: items[0].weight_range.weight_min,
|
|
||||||
weight_max: items[0].weight_range.weight_max,
|
|
||||||
items,
|
|
||||||
total_remaining_chicken_birds: items.reduce(
|
|
||||||
(sum, item) => sum + item.remaining_chicken_birds,
|
|
||||||
0
|
|
||||||
),
|
|
||||||
total_remaining_chicken_weight_kg: items.reduce(
|
|
||||||
(sum, item) => sum + item.remaining_chicken_weight_kg,
|
|
||||||
0
|
|
||||||
),
|
|
||||||
average_weight_kg:
|
|
||||||
items.reduce((sum, item) => sum + item.remaining_chicken_weight_kg, 0) /
|
|
||||||
items.reduce((sum, item) => sum + item.remaining_chicken_birds, 0),
|
|
||||||
total_hpp_rp: items.reduce((sum, item) => sum + item.hpp_rp, 0),
|
|
||||||
total_remaining_value_rp: items.reduce(
|
|
||||||
(sum, item) => sum + item.remaining_value_rp,
|
|
||||||
0
|
|
||||||
),
|
|
||||||
total_egg_production_pieces: items.reduce(
|
|
||||||
(sum, item) => sum + (item.egg_production_pieces || 0),
|
|
||||||
0
|
|
||||||
),
|
|
||||||
total_egg_production_kg: items.reduce(
|
|
||||||
(sum, item) => sum + (item.egg_production_kg || 0),
|
|
||||||
0
|
|
||||||
),
|
|
||||||
total_egg_value_rp: items.reduce(
|
|
||||||
(sum, item) => sum + (item.egg_value_rp || 0),
|
|
||||||
0
|
|
||||||
),
|
|
||||||
average_egg_hpp_rp_per_kg:
|
|
||||||
items.reduce((sum, item) => sum + (item.egg_hpp_rp_per_kg || 0), 0) /
|
|
||||||
items.length,
|
|
||||||
average_doc_price_rp:
|
|
||||||
items.reduce((sum, item) => sum + item.average_doc_price_rp, 0) /
|
|
||||||
items.length,
|
|
||||||
all_feed_suppliers: [
|
|
||||||
...new Set(
|
|
||||||
items.flatMap(
|
|
||||||
(item) => item.feed_suppliers?.map((s) => s.alias || s.name) || []
|
|
||||||
)
|
|
||||||
),
|
|
||||||
],
|
|
||||||
all_doc_suppliers: [
|
|
||||||
...new Set(
|
|
||||||
items.flatMap(
|
|
||||||
(item) => item.doc_suppliers?.map((s) => s.alias || s.name) || []
|
|
||||||
)
|
|
||||||
),
|
|
||||||
],
|
|
||||||
}))
|
|
||||||
.sort((a, b) => a.weight_min - b.weight_min);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getParameterText = (params: HppPerKandangExportParams['params']) => {
|
const getParameterText = (params: HppPerKandangExportParams['params']) => {
|
||||||
const paramsText = [];
|
const paramsText = [];
|
||||||
|
|
||||||
@@ -260,7 +196,7 @@ const createPDFDocument = (
|
|||||||
data: HppPerKandangExportParams['data'],
|
data: HppPerKandangExportParams['data'],
|
||||||
params: HppPerKandangExportParams['params']
|
params: HppPerKandangExportParams['params']
|
||||||
) => {
|
) => {
|
||||||
const rekapitulasiByWeightRange = rekapitulasiData(data.rows);
|
const rekapitulasiByWeightRange = data.summary?.per_weight_range || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Document>
|
<Document>
|
||||||
@@ -328,7 +264,8 @@ const createPDFDocument = (
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Table Body - Rekapitulasi */}
|
{/* Table Body - Rekapitulasi */}
|
||||||
{rekapitulasiByWeightRange.map((group, index) => (
|
{rekapitulasiByWeightRange.map(
|
||||||
|
(group: HppPerKandangPerWeightRange, index: number) => (
|
||||||
<View
|
<View
|
||||||
key={index}
|
key={index}
|
||||||
style={[
|
style={[
|
||||||
@@ -339,60 +276,69 @@ const createPDFDocument = (
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<View style={[pdfStyles.tableCellCenter, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellCenter, { flex: 1.2 }]}>
|
||||||
<Text>
|
<Text>{group.label}</Text>
|
||||||
{group.weight_min.toFixed(2)} -{' '}
|
</View>
|
||||||
{group.weight_max.toFixed(2)}
|
<View style={[pdfStyles.tableCellRight, { flex: 1 }]}>
|
||||||
</Text>
|
<Text>{formatNumber(group.remaining_chicken_birds)}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellRight, { flex: 1 }]}>
|
||||||
<Text>
|
<Text>
|
||||||
{formatNumber(group.total_remaining_chicken_birds)}
|
{formatNumber(group.remaining_chicken_weight_kg)}
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1 }]}>
|
|
||||||
<Text>
|
|
||||||
{formatNumber(group.total_remaining_chicken_weight_kg)}
|
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
||||||
<Text>{formatNumber(group.average_weight_kg)}</Text>
|
<Text>{formatNumber(group.avg_weight_kg)}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellRight, { flex: 1 }]}>
|
||||||
<Text>{formatNumber(group.total_egg_production_pieces)}</Text>
|
<Text>-</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellRight, { flex: 1 }]}>
|
||||||
<Text>{formatNumber(group.total_egg_production_kg)}</Text>
|
<Text>-</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1.5 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1.5 }]}>
|
||||||
<Text>{group.all_feed_suppliers.join(' | ')}</Text>
|
<Text>
|
||||||
|
{group.feed_suppliers
|
||||||
|
?.map(
|
||||||
|
(s: { alias?: string; name: string }) =>
|
||||||
|
s.alias || s.name
|
||||||
|
)
|
||||||
|
.join(' | ') || '-'}
|
||||||
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1.2 }]}>
|
||||||
<Text>{group.all_doc_suppliers.join(' | ')}</Text>
|
<Text>
|
||||||
|
{group.doc_suppliers
|
||||||
|
?.map(
|
||||||
|
(s: { alias?: string; name: string }) =>
|
||||||
|
s.alias || s.name
|
||||||
|
)
|
||||||
|
.join(' | ') || '-'}
|
||||||
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
||||||
<Text>{formatCurrency(group.average_doc_price_rp)}</Text>
|
<Text>{formatCurrency(group.average_doc_price_rp)}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
||||||
<Text>{formatCurrency(group.total_egg_value_rp)}</Text>
|
<Text>-</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellRight, { flex: 1 }]}>
|
||||||
<Text>
|
<Text>
|
||||||
{formatCurrency(
|
{formatCurrency(
|
||||||
group.total_remaining_chicken_birds > 0
|
group.remaining_chicken_birds > 0
|
||||||
? group.total_hpp_rp /
|
? group.hpp_rp / group.remaining_chicken_birds
|
||||||
group.total_remaining_chicken_birds
|
|
||||||
: 0
|
: 0
|
||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
||||||
<Text>{formatCurrency(group.average_egg_hpp_rp_per_kg)}</Text>
|
<Text>-</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
||||||
<Text>{formatCurrency(group.total_remaining_value_rp)}</Text>
|
<Text>{formatCurrency(group.remaining_value_rp)}</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
))}
|
)
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@@ -451,7 +397,7 @@ const createPDFDocument = (
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Table Body - Detail Per Kandang */}
|
{/* Table Body - Detail Per Kandang */}
|
||||||
{data.rows.map((item, index) => (
|
{data.rows.map((item: HppPerKandangRow, index: number) => (
|
||||||
<View
|
<View
|
||||||
key={index}
|
key={index}
|
||||||
style={[
|
style={[
|
||||||
@@ -491,14 +437,20 @@ const createPDFDocument = (
|
|||||||
<View style={[pdfStyles.tableCell, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1.2 }]}>
|
||||||
<Text>
|
<Text>
|
||||||
{item.feed_suppliers
|
{item.feed_suppliers
|
||||||
?.map((s) => s.alias || s.name)
|
?.map(
|
||||||
|
(s: { alias?: string; name: string }) =>
|
||||||
|
s.alias || s.name
|
||||||
|
)
|
||||||
.join(' | ')}
|
.join(' | ')}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
||||||
<Text>
|
<Text>
|
||||||
{item.doc_suppliers
|
{item.doc_suppliers
|
||||||
?.map((s) => s.alias || s.name)
|
?.map(
|
||||||
|
(s: { alias?: string; name: string }) =>
|
||||||
|
s.alias || s.name
|
||||||
|
)
|
||||||
.join(' | ')}
|
.join(' | ')}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -15,7 +15,11 @@ import { SaleReportApi } from '@/services/api/report/marketing-sale';
|
|||||||
import Table from '@/components/Table';
|
import Table from '@/components/Table';
|
||||||
import { ColumnDef, Row } from '@tanstack/react-table';
|
import { ColumnDef, Row } from '@tanstack/react-table';
|
||||||
import { formatCurrency, formatNumber } from '@/lib/helper';
|
import { formatCurrency, formatNumber } from '@/lib/helper';
|
||||||
import { HppPerKandangReport } from '@/types/api/report/hpp-per-kandang';
|
import {
|
||||||
|
HppPerKandangReport,
|
||||||
|
HppPerKandangRow,
|
||||||
|
HppPerKandangPerWeightRange,
|
||||||
|
} from '@/types/api/report/hpp-per-kandang';
|
||||||
import { isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseSuccess } from '@/lib/api-helper';
|
||||||
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
import { useTableFilter } from '@/services/hooks/useTableFilter';
|
||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
@@ -225,6 +229,17 @@ const HppPerKandangTab = () => {
|
|||||||
? hppPerKandang.data.summary
|
? hppPerKandang.data.summary
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const summaryTotal =
|
||||||
|
isResponseSuccess(hppPerKandang) && hppPerKandang?.data?.summary?.total
|
||||||
|
? hppPerKandang.data.summary.total
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const perWeightRangeSummary =
|
||||||
|
isResponseSuccess(hppPerKandang) &&
|
||||||
|
hppPerKandang?.data?.summary?.per_weight_range
|
||||||
|
? hppPerKandang.data.summary.per_weight_range
|
||||||
|
: [];
|
||||||
|
|
||||||
const period =
|
const period =
|
||||||
isResponseSuccess(hppPerKandang) && hppPerKandang?.data?.period
|
isResponseSuccess(hppPerKandang) && hppPerKandang?.data?.period
|
||||||
? hppPerKandang.data.period
|
? hppPerKandang.data.period
|
||||||
@@ -271,25 +286,49 @@ const HppPerKandangTab = () => {
|
|||||||
|
|
||||||
// ===== TABLE COLUMNS DEFINITION =====
|
// ===== TABLE COLUMNS DEFINITION =====
|
||||||
const totals: Totals = useMemo(() => {
|
const totals: Totals = useMemo(() => {
|
||||||
return {
|
if (summaryTotal && perWeightRangeSummary.length > 0) {
|
||||||
total_hpp_rp:
|
const totalAverageDocPrice =
|
||||||
data.length > 0
|
perWeightRangeSummary.reduce(
|
||||||
? data.reduce((acc, item) => acc + (item.hpp_rp || 0), 0)
|
(acc: number, item: HppPerKandangPerWeightRange) =>
|
||||||
: 0,
|
acc + (item.average_doc_price_rp || 0),
|
||||||
total_average_doc_price_rp:
|
|
||||||
data.length > 0
|
|
||||||
? data.reduce(
|
|
||||||
(acc, item) => acc + (item.average_doc_price_rp || 0),
|
|
||||||
0
|
0
|
||||||
) / data.length
|
) / perWeightRangeSummary.length;
|
||||||
: 0,
|
|
||||||
|
return {
|
||||||
|
total_hpp_rp: perWeightRangeSummary.reduce(
|
||||||
|
(acc: number, item: HppPerKandangPerWeightRange) =>
|
||||||
|
acc + (item.hpp_rp || 0),
|
||||||
|
0
|
||||||
|
),
|
||||||
|
total_average_doc_price_rp: totalAverageDocPrice,
|
||||||
};
|
};
|
||||||
}, [summary]);
|
}
|
||||||
|
|
||||||
|
if (data.length > 0) {
|
||||||
|
return {
|
||||||
|
total_hpp_rp: data.reduce(
|
||||||
|
(acc: number, item: HppPerKandangRow) => acc + (item.hpp_rp || 0),
|
||||||
|
0
|
||||||
|
),
|
||||||
|
total_average_doc_price_rp:
|
||||||
|
data.reduce(
|
||||||
|
(acc: number, item: HppPerKandangRow) =>
|
||||||
|
acc + (item.average_doc_price_rp || 0),
|
||||||
|
0
|
||||||
|
) / data.length,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
total_hpp_rp: 0,
|
||||||
|
total_average_doc_price_rp: 0,
|
||||||
|
};
|
||||||
|
}, [summaryTotal, perWeightRangeSummary, data]);
|
||||||
|
|
||||||
const allFeedSuppliers = useMemo(() => {
|
const allFeedSuppliers = useMemo(() => {
|
||||||
const suppliers = new Set<string>();
|
const suppliers = new Set<string>();
|
||||||
data.forEach((item) => {
|
data.forEach((item: HppPerKandangRow) => {
|
||||||
item.feed_suppliers?.forEach((s) => {
|
item.feed_suppliers?.forEach((s: { alias?: string; name: string }) => {
|
||||||
suppliers.add(s.alias || s.name);
|
suppliers.add(s.alias || s.name);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -298,8 +337,8 @@ const HppPerKandangTab = () => {
|
|||||||
|
|
||||||
const allDocSuppliers = useMemo(() => {
|
const allDocSuppliers = useMemo(() => {
|
||||||
const suppliers = new Set<string>();
|
const suppliers = new Set<string>();
|
||||||
data.forEach((item) => {
|
data.forEach((item: HppPerKandangRow) => {
|
||||||
item.doc_suppliers?.forEach((s) => {
|
item.doc_suppliers?.forEach((s: { alias?: string; name: string }) => {
|
||||||
suppliers.add(s.alias || s.name);
|
suppliers.add(s.alias || s.name);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -327,7 +366,7 @@ const HppPerKandangTab = () => {
|
|||||||
const summary = allDataForExport.summary;
|
const summary = allDataForExport.summary;
|
||||||
|
|
||||||
const excelData: { [key: string]: string | number }[] = allExportData.map(
|
const excelData: { [key: string]: string | number }[] = allExportData.map(
|
||||||
(item, index) => ({
|
(item: HppPerKandangRow, index: number) => ({
|
||||||
No: index + 1,
|
No: index + 1,
|
||||||
Kandang: item.kandang?.name || '',
|
Kandang: item.kandang?.name || '',
|
||||||
'Rentang Bobot': item.weight_range
|
'Rentang Bobot': item.weight_range
|
||||||
@@ -339,10 +378,13 @@ const HppPerKandangTab = () => {
|
|||||||
'Produksi Telur (Butir)': item.egg_production_pieces || 0,
|
'Produksi Telur (Butir)': item.egg_production_pieces || 0,
|
||||||
'Produksi Telur (KG)': item.egg_production_kg || 0,
|
'Produksi Telur (KG)': item.egg_production_kg || 0,
|
||||||
'Feed (Supplier)':
|
'Feed (Supplier)':
|
||||||
item.feed_suppliers?.map((s) => s.alias || s.name).join(' | ') ||
|
item.feed_suppliers
|
||||||
'',
|
?.map((s: { alias?: string; name: string }) => s.alias || s.name)
|
||||||
|
.join(' | ') || '',
|
||||||
'DOC (Supplier)':
|
'DOC (Supplier)':
|
||||||
item.doc_suppliers?.map((s) => s.alias || s.name).join(' | ') || '',
|
item.doc_suppliers
|
||||||
|
?.map((s: { alias?: string; name: string }) => s.alias || s.name)
|
||||||
|
.join(' | ') || '',
|
||||||
'Rata-Rata Harga DOC (RP)': item.average_doc_price_rp || 0,
|
'Rata-Rata Harga DOC (RP)': item.average_doc_price_rp || 0,
|
||||||
'Nilai Nominal Telur (RP)': item.egg_value_rp || 0,
|
'Nilai Nominal Telur (RP)': item.egg_value_rp || 0,
|
||||||
'HPP Ayam (RP)': item.hpp_rp || 0,
|
'HPP Ayam (RP)': item.hpp_rp || 0,
|
||||||
@@ -588,7 +630,11 @@ const HppPerKandangTab = () => {
|
|||||||
accessorKey: 'feed_suppliers',
|
accessorKey: 'feed_suppliers',
|
||||||
cell: (props) => {
|
cell: (props) => {
|
||||||
const suppliers = props.row.original.feed_suppliers;
|
const suppliers = props.row.original.feed_suppliers;
|
||||||
return suppliers?.map((s) => s.alias || s.name).join(' | ') || '-';
|
return (
|
||||||
|
suppliers
|
||||||
|
?.map((s: { alias?: string; name: string }) => s.alias || s.name)
|
||||||
|
.join(' | ') || '-'
|
||||||
|
);
|
||||||
},
|
},
|
||||||
footer: () => (
|
footer: () => (
|
||||||
<div className='font-semibold text-gray-900'>
|
<div className='font-semibold text-gray-900'>
|
||||||
@@ -602,7 +648,11 @@ const HppPerKandangTab = () => {
|
|||||||
accessorKey: 'doc_suppliers',
|
accessorKey: 'doc_suppliers',
|
||||||
cell: (props) => {
|
cell: (props) => {
|
||||||
const suppliers = props.row.original.doc_suppliers;
|
const suppliers = props.row.original.doc_suppliers;
|
||||||
return suppliers?.map((s) => s.alias || s.name).join(' | ') || '-';
|
return (
|
||||||
|
suppliers
|
||||||
|
?.map((s: { alias?: string; name: string }) => s.alias || s.name)
|
||||||
|
.join(' | ') || '-'
|
||||||
|
);
|
||||||
},
|
},
|
||||||
footer: () => (
|
footer: () => (
|
||||||
<div className='font-semibold text-gray-900'>
|
<div className='font-semibold text-gray-900'>
|
||||||
|
|||||||
Reference in New Issue
Block a user