mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
feat(FE): adding closing finance per kandang
This commit is contained in:
@@ -3,54 +3,11 @@ import Table, { TABLE_DEFAULT_STYLING } from '@/components/Table';
|
|||||||
import { isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseSuccess } from '@/lib/api-helper';
|
||||||
import { formatCurrency, formatTitleCase } from '@/lib/helper';
|
import { formatCurrency, formatTitleCase } from '@/lib/helper';
|
||||||
import { ClosingApi } from '@/services/api/closing';
|
import { ClosingApi } from '@/services/api/closing';
|
||||||
import {
|
import { HppItem, ProfitLossItem } from '@/types/api/closing';
|
||||||
DataSummarySubTotal,
|
|
||||||
HppPurchaseData,
|
|
||||||
ProfitLossDataAmount,
|
|
||||||
} from '@/types/api/closing';
|
|
||||||
import { useSearchParams } from 'next/navigation';
|
import { useSearchParams } from 'next/navigation';
|
||||||
|
import { useMemo } from 'react';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
|
|
||||||
type HppTableRow =
|
|
||||||
| (HppPurchaseData & {
|
|
||||||
group_name: string;
|
|
||||||
group_index: number;
|
|
||||||
isGroupHeader?: boolean;
|
|
||||||
})
|
|
||||||
| {
|
|
||||||
group_name: string;
|
|
||||||
group_index: number;
|
|
||||||
isGroupHeader: true;
|
|
||||||
type?: never;
|
|
||||||
budgeting?: never;
|
|
||||||
realization?: never;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: string;
|
|
||||||
group_name: string;
|
|
||||||
group_index: number;
|
|
||||||
isGroupHeader: false;
|
|
||||||
budgeting?: { rp_per_bird: number; rp_per_kg: number; amount: number };
|
|
||||||
realization?: { rp_per_bird: number; rp_per_kg: number; amount: number };
|
|
||||||
};
|
|
||||||
|
|
||||||
type ProfitLossTableRow =
|
|
||||||
| (DataSummarySubTotal & {
|
|
||||||
type: string;
|
|
||||||
group_name: string;
|
|
||||||
group_index: number;
|
|
||||||
isGroupHeader?: boolean;
|
|
||||||
})
|
|
||||||
| {
|
|
||||||
group_name: string;
|
|
||||||
group_index: number;
|
|
||||||
isGroupHeader: true;
|
|
||||||
type?: never;
|
|
||||||
rp_per_bird?: never;
|
|
||||||
rp_per_kg?: never;
|
|
||||||
amount?: never;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ClosingFinanceTable = ({
|
const ClosingFinanceTable = ({
|
||||||
projectFlockId,
|
projectFlockId,
|
||||||
}: {
|
}: {
|
||||||
@@ -68,167 +25,60 @@ const ClosingFinanceTable = ({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const staticHppRows: Array<{
|
const hppTableData: HppItem[] = useMemo(() => {
|
||||||
group_name: string;
|
if (isResponseSuccess(finance)) {
|
||||||
type: string;
|
const customItems = {
|
||||||
group_index: number;
|
label: 'HPP dan Pengeluaran',
|
||||||
}> = [
|
code: 'custom_row',
|
||||||
{
|
} as HppItem;
|
||||||
group_name: 'HPP dan Pengeluaran',
|
const purchases = finance.data.hpp.items.filter(
|
||||||
type: 'Pembelian PAKAN',
|
(item) => item.category === 'purchase'
|
||||||
group_index: 0,
|
);
|
||||||
},
|
const totalBudgeting = {
|
||||||
{
|
label: 'HPP dan Bahan Baku',
|
||||||
group_name: 'HPP dan Pengeluaran',
|
code: 'custom_row',
|
||||||
type: 'Pembelian STARTER',
|
} as HppItem;
|
||||||
group_index: 0,
|
const overheads = finance.data.hpp.items.filter(
|
||||||
},
|
(item) => item.category === 'overhead'
|
||||||
{
|
);
|
||||||
group_name: 'HPP dan Pengeluaran',
|
return [customItems, ...purchases, totalBudgeting, ...overheads];
|
||||||
type: 'Pembelian DOC',
|
}
|
||||||
group_index: 0,
|
return [];
|
||||||
},
|
}, []);
|
||||||
{
|
|
||||||
group_name: 'HPP dan Pengeluaran',
|
|
||||||
type: 'Pembelian PULLET',
|
|
||||||
group_index: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
group_name: 'HPP dan Pengeluaran',
|
|
||||||
type: 'Pembelian LAYER',
|
|
||||||
group_index: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
group_name: 'HPP dan Bahan Baku',
|
|
||||||
type: 'Pengeluaran Overhead',
|
|
||||||
group_index: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
group_name: 'HPP dan Bahan Baku',
|
|
||||||
type: 'Beban Ekspedisi',
|
|
||||||
group_index: 1,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const hppTableData: HppTableRow[] = [
|
const profitLossTableData: ProfitLossItem[] = useMemo(() => {
|
||||||
{
|
if (isResponseSuccess(finance)) {
|
||||||
group_name: 'HPP dan Pengeluaran',
|
const incomes = finance.data.profit_loss.items.filter(
|
||||||
group_index: 0,
|
(item) => item.type === 'income'
|
||||||
isGroupHeader: true as const,
|
);
|
||||||
},
|
const purchases = finance.data.profit_loss.items.filter(
|
||||||
...staticHppRows
|
(item) => item.type === 'purchase'
|
||||||
.filter((row) => row.group_index === 0)
|
);
|
||||||
.map((staticRow) => {
|
const overheads = finance.data.profit_loss.items.filter(
|
||||||
const apiData = isResponseSuccess(finance)
|
(item) => item.type === 'overhead'
|
||||||
? finance.data.hpp_purchases.hpp
|
);
|
||||||
.find((g) => g.group_name === staticRow.group_name)
|
const grossProfit = {
|
||||||
?.data.find((d) => d.type === staticRow.type)
|
label: 'LABA RUGI BRUTO',
|
||||||
: null;
|
code: 'custom_row',
|
||||||
|
type: 'gross_profit',
|
||||||
return {
|
rp_per_bird:
|
||||||
group_name: staticRow.group_name,
|
finance.data.profit_loss.summary.gross_profit.rp_per_bird ?? 0,
|
||||||
group_index: staticRow.group_index,
|
rp_per_kg: finance.data.profit_loss.summary.gross_profit.rp_per_kg ?? 0,
|
||||||
type: staticRow.type,
|
amount: finance.data.profit_loss.summary.gross_profit.amount ?? 0,
|
||||||
budgeting: apiData?.budgeting || {
|
} as ProfitLossItem;
|
||||||
rp_per_bird: 0,
|
const subtotal = {
|
||||||
rp_per_kg: 0,
|
label: 'Subtotal',
|
||||||
amount: 0,
|
code: 'custom_row',
|
||||||
},
|
type: 'subtotal',
|
||||||
realization: apiData?.realization || {
|
rp_per_bird:
|
||||||
rp_per_bird: 0,
|
finance.data.profit_loss.summary.sub_total.rp_per_bird ?? 0,
|
||||||
rp_per_kg: 0,
|
rp_per_kg: finance.data.profit_loss.summary.sub_total.rp_per_kg ?? 0,
|
||||||
amount: 0,
|
amount: finance.data.profit_loss.summary.sub_total.amount ?? 0,
|
||||||
},
|
} as ProfitLossItem;
|
||||||
isGroupHeader: false as const,
|
return [...incomes, ...purchases, grossProfit, ...overheads, subtotal];
|
||||||
};
|
}
|
||||||
}),
|
return [];
|
||||||
{
|
}, []);
|
||||||
group_name: 'HPP dan Bahan Baku',
|
|
||||||
group_index: 1,
|
|
||||||
isGroupHeader: true as const,
|
|
||||||
},
|
|
||||||
...staticHppRows
|
|
||||||
.filter((row) => row.group_index === 1)
|
|
||||||
.map((staticRow) => {
|
|
||||||
const apiData = isResponseSuccess(finance)
|
|
||||||
? finance.data.hpp_purchases.hpp
|
|
||||||
.find((g) => g.group_name === staticRow.group_name)
|
|
||||||
?.data.find((d) => d.type === staticRow.type)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return {
|
|
||||||
group_name: staticRow.group_name,
|
|
||||||
group_index: staticRow.group_index,
|
|
||||||
type: staticRow.type,
|
|
||||||
budgeting: apiData?.budgeting || {
|
|
||||||
rp_per_bird: 0,
|
|
||||||
rp_per_kg: 0,
|
|
||||||
amount: 0,
|
|
||||||
},
|
|
||||||
realization: apiData?.realization || {
|
|
||||||
rp_per_bird: 0,
|
|
||||||
rp_per_kg: 0,
|
|
||||||
amount: 0,
|
|
||||||
},
|
|
||||||
isGroupHeader: false as const,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
group_name: 'HPP',
|
|
||||||
group_index: 2,
|
|
||||||
isGroupHeader: true as const,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const profitLossTableData: ProfitLossTableRow[] = isResponseSuccess(finance)
|
|
||||||
? [
|
|
||||||
// Pembelian group
|
|
||||||
...finance.data.profit_loss.data.pembelian.map((item) => ({
|
|
||||||
label: 'Pembelian',
|
|
||||||
group_name: 'Pembelian',
|
|
||||||
group_index: 1,
|
|
||||||
type: item.type,
|
|
||||||
rp_per_bird: item.rp_per_bird,
|
|
||||||
rp_per_kg: item.rp_per_kg,
|
|
||||||
amount: item.amount,
|
|
||||||
isGroupHeader: false as const,
|
|
||||||
})),
|
|
||||||
{
|
|
||||||
label: finance.data.profit_loss.data.summary.gross_profit.label,
|
|
||||||
group_name: 'Penjualan',
|
|
||||||
group_index: 0,
|
|
||||||
isGroupHeader: true as const,
|
|
||||||
type: finance.data.profit_loss.data.summary.gross_profit.label,
|
|
||||||
rp_per_bird:
|
|
||||||
finance.data.profit_loss.data.summary.gross_profit.rp_per_bird,
|
|
||||||
rp_per_kg:
|
|
||||||
finance.data.profit_loss.data.summary.gross_profit.rp_per_kg,
|
|
||||||
amount: finance.data.profit_loss.data.summary.gross_profit.amount,
|
|
||||||
},
|
|
||||||
// Penjualan group
|
|
||||||
...finance.data.profit_loss.data.penjualan.map((item) => ({
|
|
||||||
label: 'Penjualan',
|
|
||||||
group_name: 'Penjualan',
|
|
||||||
group_index: 0,
|
|
||||||
type: item.type,
|
|
||||||
rp_per_bird: item.rp_per_bird,
|
|
||||||
rp_per_kg: item.rp_per_kg,
|
|
||||||
amount: item.amount,
|
|
||||||
isGroupHeader: false as const,
|
|
||||||
})),
|
|
||||||
{
|
|
||||||
label: finance.data.profit_loss.data.summary.sub_total.label,
|
|
||||||
group_name: 'Pembelian',
|
|
||||||
group_index: 1,
|
|
||||||
isGroupHeader: true as const,
|
|
||||||
type: finance.data.profit_loss.data.summary.sub_total.label,
|
|
||||||
rp_per_bird:
|
|
||||||
finance.data.profit_loss.data.summary.sub_total.rp_per_bird,
|
|
||||||
rp_per_kg: finance.data.profit_loss.data.summary.sub_total.rp_per_kg,
|
|
||||||
amount: finance.data.profit_loss.data.summary.sub_total.amount,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-4'>
|
<div className='flex flex-col gap-4'>
|
||||||
@@ -241,47 +91,30 @@ const ClosingFinanceTable = ({
|
|||||||
>
|
>
|
||||||
<div className='grid grid-cols-2 gap-6'>
|
<div className='grid grid-cols-2 gap-6'>
|
||||||
<div className='flex flex-col gap-1'>
|
<div className='flex flex-col gap-1'>
|
||||||
<div>
|
<div>Laba Rugi Brutto</div>
|
||||||
{isResponseSuccess(finance)
|
|
||||||
? formatTitleCase(
|
|
||||||
finance.data.profit_loss.data.summary.gross_profit
|
|
||||||
.label || '-'
|
|
||||||
)
|
|
||||||
: 'Laba Rugi Brutto'}
|
|
||||||
</div>
|
|
||||||
<div className='text-lg font-bold'>
|
<div className='text-lg font-bold'>
|
||||||
{isResponseSuccess(finance)
|
{isResponseSuccess(finance)
|
||||||
? formatCurrency(
|
? formatCurrency(
|
||||||
finance.data.profit_loss.data.summary.gross_profit.amount
|
finance.data.profit_loss.summary.gross_profit.amount
|
||||||
)
|
)
|
||||||
: '-'}
|
: '-'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex flex-col gap-1'>
|
<div className='flex flex-col gap-1'>
|
||||||
<div>
|
<div>Laba Rugi Netto</div>
|
||||||
{isResponseSuccess(finance)
|
|
||||||
? formatTitleCase(
|
|
||||||
finance.data.profit_loss.data.summary.net_profit.label ||
|
|
||||||
'-'
|
|
||||||
)
|
|
||||||
: 'Laba Rugi Netto'}
|
|
||||||
</div>
|
|
||||||
<div className='text-lg font-bold'>
|
<div className='text-lg font-bold'>
|
||||||
{isResponseSuccess(finance)
|
{isResponseSuccess(finance)
|
||||||
? formatCurrency(
|
? formatCurrency(
|
||||||
finance.data.profit_loss.data.summary.net_profit.amount
|
finance.data.profit_loss.summary.net_profit.amount
|
||||||
)
|
)
|
||||||
: '-'}
|
: '-'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
{JSON.stringify(finance)}
|
||||||
<Card
|
<Card
|
||||||
title={
|
title='HPP Purchases'
|
||||||
isResponseSuccess(finance)
|
|
||||||
? finance.data.hpp_purchases.title
|
|
||||||
: 'HPP Purchases'
|
|
||||||
}
|
|
||||||
variant='bordered'
|
variant='bordered'
|
||||||
collapsible
|
collapsible
|
||||||
className={{
|
className={{
|
||||||
@@ -289,7 +122,7 @@ const ClosingFinanceTable = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className='mt-6 p-0 mb-0'>
|
<div className='mt-6 p-0 mb-0'>
|
||||||
<Table<HppTableRow>
|
<Table<HppItem>
|
||||||
data={hppTableData}
|
data={hppTableData}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
columns={[
|
columns={[
|
||||||
@@ -297,10 +130,10 @@ const ClosingFinanceTable = ({
|
|||||||
header: 'No.',
|
header: 'No.',
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
accessorFn: (item, index) => {
|
accessorFn: (item, index) => {
|
||||||
if (item.isGroupHeader) return '-';
|
if (item.code === 'custom_row') return '-';
|
||||||
const dataRowsBefore = hppTableData
|
const dataRowsBefore = hppTableData
|
||||||
.slice(0, index)
|
.slice(0, index)
|
||||||
.filter((row) => !row.isGroupHeader).length;
|
.filter((row) => row.code !== 'custom_row').length;
|
||||||
return dataRowsBefore + 1;
|
return dataRowsBefore + 1;
|
||||||
},
|
},
|
||||||
footer: (props) => {
|
footer: (props) => {
|
||||||
@@ -310,7 +143,7 @@ const ClosingFinanceTable = ({
|
|||||||
{
|
{
|
||||||
header: 'Jenis',
|
header: 'Jenis',
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
accessorFn: (item) => formatTitleCase(item.type || '-'),
|
accessorFn: (item) => formatTitleCase(item.label || '-'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Budgeting',
|
header: 'Budgeting',
|
||||||
@@ -326,7 +159,7 @@ const ClosingFinanceTable = ({
|
|||||||
return props.column.id === 'budgeting_rp_per_bird' &&
|
return props.column.id === 'budgeting_rp_per_bird' &&
|
||||||
isResponseSuccess(finance)
|
isResponseSuccess(finance)
|
||||||
? formatCurrency(
|
? formatCurrency(
|
||||||
finance.data.hpp_purchases.summary_hpp?.budgeting
|
finance.data.hpp.summary?.budgeting
|
||||||
?.rp_per_bird || 0
|
?.rp_per_bird || 0
|
||||||
)
|
)
|
||||||
: '-';
|
: '-';
|
||||||
@@ -342,8 +175,8 @@ const ClosingFinanceTable = ({
|
|||||||
return props.column.id === 'budgeting_rp_per_kg' &&
|
return props.column.id === 'budgeting_rp_per_kg' &&
|
||||||
isResponseSuccess(finance)
|
isResponseSuccess(finance)
|
||||||
? formatCurrency(
|
? formatCurrency(
|
||||||
finance.data.hpp_purchases.summary_hpp?.budgeting
|
finance.data.hpp.summary?.budgeting?.rp_per_kg ||
|
||||||
?.rp_per_kg || 0
|
0
|
||||||
)
|
)
|
||||||
: '-';
|
: '-';
|
||||||
},
|
},
|
||||||
@@ -358,8 +191,7 @@ const ClosingFinanceTable = ({
|
|||||||
return props.column.id === 'budgeting_amount' &&
|
return props.column.id === 'budgeting_amount' &&
|
||||||
isResponseSuccess(finance)
|
isResponseSuccess(finance)
|
||||||
? formatCurrency(
|
? formatCurrency(
|
||||||
finance.data.hpp_purchases.summary_hpp?.budgeting
|
finance.data.hpp.summary?.budgeting?.amount || 0
|
||||||
?.amount || 0
|
|
||||||
)
|
)
|
||||||
: '-';
|
: '-';
|
||||||
},
|
},
|
||||||
@@ -380,8 +212,8 @@ const ClosingFinanceTable = ({
|
|||||||
return props.column.id === 'realization_rp_per_bird' &&
|
return props.column.id === 'realization_rp_per_bird' &&
|
||||||
isResponseSuccess(finance)
|
isResponseSuccess(finance)
|
||||||
? formatCurrency(
|
? formatCurrency(
|
||||||
finance.data.hpp_purchases.summary_hpp
|
finance.data.hpp.summary?.realization
|
||||||
?.realization?.rp_per_bird || 0
|
?.rp_per_bird || 0
|
||||||
)
|
)
|
||||||
: '-';
|
: '-';
|
||||||
},
|
},
|
||||||
@@ -396,8 +228,8 @@ const ClosingFinanceTable = ({
|
|||||||
return props.column.id === 'realization_rp_per_kg' &&
|
return props.column.id === 'realization_rp_per_kg' &&
|
||||||
isResponseSuccess(finance)
|
isResponseSuccess(finance)
|
||||||
? formatCurrency(
|
? formatCurrency(
|
||||||
finance.data.hpp_purchases.summary_hpp
|
finance.data.hpp.summary?.realization
|
||||||
?.realization?.rp_per_kg || 0
|
?.rp_per_kg || 0
|
||||||
)
|
)
|
||||||
: '-';
|
: '-';
|
||||||
},
|
},
|
||||||
@@ -412,8 +244,7 @@ const ClosingFinanceTable = ({
|
|||||||
return props.column.id === 'realization_amount' &&
|
return props.column.id === 'realization_amount' &&
|
||||||
isResponseSuccess(finance)
|
isResponseSuccess(finance)
|
||||||
? formatCurrency(
|
? formatCurrency(
|
||||||
finance.data.hpp_purchases.summary_hpp
|
finance.data.hpp.summary?.realization?.amount || 0
|
||||||
?.realization?.amount || 0
|
|
||||||
)
|
)
|
||||||
: '-';
|
: '-';
|
||||||
},
|
},
|
||||||
@@ -423,7 +254,7 @@ const ClosingFinanceTable = ({
|
|||||||
]}
|
]}
|
||||||
renderCustomRow={(row) => {
|
renderCustomRow={(row) => {
|
||||||
const rowData = row.original;
|
const rowData = row.original;
|
||||||
if (rowData.isGroupHeader) {
|
if (rowData.code === 'custom_row') {
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={row.id}
|
key={row.id}
|
||||||
@@ -437,7 +268,7 @@ const ClosingFinanceTable = ({
|
|||||||
className={TABLE_DEFAULT_STYLING.bodyColumnClassName}
|
className={TABLE_DEFAULT_STYLING.bodyColumnClassName}
|
||||||
>
|
>
|
||||||
<div className='font-bold'>
|
<div className='font-bold'>
|
||||||
{formatTitleCase(rowData.group_name ?? '-')}
|
{formatTitleCase(rowData.label ?? '-')}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -450,11 +281,7 @@ const ClosingFinanceTable = ({
|
|||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
<Card
|
<Card
|
||||||
title={
|
title='Profit/Loss'
|
||||||
isResponseSuccess(finance)
|
|
||||||
? finance.data.profit_loss.title
|
|
||||||
: 'Profit/Loss'
|
|
||||||
}
|
|
||||||
variant='bordered'
|
variant='bordered'
|
||||||
collapsible
|
collapsible
|
||||||
className={{
|
className={{
|
||||||
@@ -462,39 +289,32 @@ const ClosingFinanceTable = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className='mt-6 p-0 mb-0'>
|
<div className='mt-6 p-0 mb-0'>
|
||||||
<Table<ProfitLossTableRow>
|
<Table<ProfitLossItem>
|
||||||
data={profitLossTableData}
|
data={profitLossTableData}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
columns={[
|
columns={[
|
||||||
{
|
{
|
||||||
header: 'Jenis',
|
header: 'Jenis',
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
accessorFn: (item) => item.type,
|
accessorFn: (item) => item.label,
|
||||||
cell: (item) => (
|
cell: (item) => (
|
||||||
<div className=''>
|
<div className=''>
|
||||||
{formatTitleCase(item.row.original.type || '-')}
|
{formatTitleCase(item.row.original.label || '-')}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
footer: (item) => (
|
footer: () => (
|
||||||
<div className='font-bold uppercase'>
|
<div className='font-bold uppercase'>LABA RUGI NETTO</div>
|
||||||
{isResponseSuccess(finance)
|
|
||||||
? formatTitleCase(
|
|
||||||
finance.data.profit_loss.data.summary.net_profit
|
|
||||||
.label || '-'
|
|
||||||
)
|
|
||||||
: '-'}
|
|
||||||
</div>
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Rp/Ekor',
|
header: 'Rp/Ekor',
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
accessorFn: (item) => formatCurrency(item.rp_per_bird || 0),
|
accessorFn: (item) => formatCurrency(item.rp_per_bird || 0),
|
||||||
footer: (item) => (
|
footer: () => (
|
||||||
<div className='font-bold'>
|
<div className='font-bold'>
|
||||||
{isResponseSuccess(finance)
|
{isResponseSuccess(finance)
|
||||||
? formatCurrency(
|
? formatCurrency(
|
||||||
finance.data.profit_loss.data.summary.net_profit
|
finance.data.profit_loss.summary.net_profit
|
||||||
.rp_per_bird || 0
|
.rp_per_bird || 0
|
||||||
)
|
)
|
||||||
: formatCurrency(0)}
|
: formatCurrency(0)}
|
||||||
@@ -505,11 +325,11 @@ const ClosingFinanceTable = ({
|
|||||||
header: 'Rp/Kg',
|
header: 'Rp/Kg',
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
accessorFn: (item) => formatCurrency(item.rp_per_kg || 0),
|
accessorFn: (item) => formatCurrency(item.rp_per_kg || 0),
|
||||||
footer: (item) => (
|
footer: () => (
|
||||||
<div className='font-bold'>
|
<div className='font-bold'>
|
||||||
{isResponseSuccess(finance)
|
{isResponseSuccess(finance)
|
||||||
? formatCurrency(
|
? formatCurrency(
|
||||||
finance.data.profit_loss.data.summary.net_profit
|
finance.data.profit_loss.summary.net_profit
|
||||||
.rp_per_kg || 0
|
.rp_per_kg || 0
|
||||||
)
|
)
|
||||||
: formatCurrency(0)}
|
: formatCurrency(0)}
|
||||||
@@ -520,11 +340,11 @@ const ClosingFinanceTable = ({
|
|||||||
header: 'Jumlah (Rp)',
|
header: 'Jumlah (Rp)',
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
accessorFn: (item) => formatCurrency(item.amount || 0),
|
accessorFn: (item) => formatCurrency(item.amount || 0),
|
||||||
footer: (item) => (
|
footer: () => (
|
||||||
<div className='font-bold'>
|
<div className='font-bold'>
|
||||||
{isResponseSuccess(finance)
|
{isResponseSuccess(finance)
|
||||||
? formatCurrency(
|
? formatCurrency(
|
||||||
finance.data.profit_loss.data.summary.net_profit
|
finance.data.profit_loss.summary.net_profit
|
||||||
.amount || 0
|
.amount || 0
|
||||||
)
|
)
|
||||||
: formatCurrency(0)}
|
: formatCurrency(0)}
|
||||||
@@ -534,55 +354,30 @@ const ClosingFinanceTable = ({
|
|||||||
]}
|
]}
|
||||||
renderCustomRow={(row) => {
|
renderCustomRow={(row) => {
|
||||||
const rowData = row.original;
|
const rowData = row.original;
|
||||||
if (rowData.isGroupHeader) {
|
if (rowData.code === 'custom_row') {
|
||||||
if (rowData.amount) {
|
|
||||||
return (
|
|
||||||
<tr
|
|
||||||
key={row.id}
|
|
||||||
className={TABLE_DEFAULT_STYLING.footerRowClassName}
|
|
||||||
>
|
|
||||||
<td
|
|
||||||
className={TABLE_DEFAULT_STYLING.bodyColumnClassName}
|
|
||||||
>
|
|
||||||
<div className='font-bold ps-6 uppercase'>
|
|
||||||
{formatTitleCase(rowData.label ?? '-')}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className={TABLE_DEFAULT_STYLING.bodyColumnClassName}
|
|
||||||
>
|
|
||||||
<div className='font-bold'>
|
|
||||||
{formatCurrency(rowData.rp_per_bird ?? 0)}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className={TABLE_DEFAULT_STYLING.bodyColumnClassName}
|
|
||||||
>
|
|
||||||
<div className='font-bold'>
|
|
||||||
{formatCurrency(rowData.rp_per_kg ?? 0)}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className={TABLE_DEFAULT_STYLING.bodyColumnClassName}
|
|
||||||
>
|
|
||||||
<div className='font-bold'>
|
|
||||||
{formatCurrency(rowData.amount ?? 0)}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={row.id}
|
key={row.id}
|
||||||
className={TABLE_DEFAULT_STYLING.bodyRowClassName}
|
className={TABLE_DEFAULT_STYLING.footerRowClassName}
|
||||||
>
|
>
|
||||||
<td
|
<td className={TABLE_DEFAULT_STYLING.bodyColumnClassName}>
|
||||||
colSpan={4}
|
<div className='font-bold ps-6 uppercase'>
|
||||||
className={TABLE_DEFAULT_STYLING.bodyColumnClassName}
|
{formatTitleCase(rowData.label ?? '-')}
|
||||||
>
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className={TABLE_DEFAULT_STYLING.bodyColumnClassName}>
|
||||||
<div className='font-bold'>
|
<div className='font-bold'>
|
||||||
{formatTitleCase(rowData.group_name ?? '-')}
|
{formatCurrency(rowData.rp_per_bird ?? 0)}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className={TABLE_DEFAULT_STYLING.bodyColumnClassName}>
|
||||||
|
<div className='font-bold'>
|
||||||
|
{formatCurrency(rowData.rp_per_kg ?? 0)}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className={TABLE_DEFAULT_STYLING.bodyColumnClassName}>
|
||||||
|
<div className='font-bold'>
|
||||||
|
{formatCurrency(rowData.amount ?? 0)}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
Vendored
+32
-47
@@ -219,64 +219,30 @@ export type ClosingSales = BaseMetadata & BaseClosingSales;
|
|||||||
|
|
||||||
// ====== FINANCE ======
|
// ====== FINANCE ======
|
||||||
export interface ClosingFinance {
|
export interface ClosingFinance {
|
||||||
project_flock_id: number;
|
hpp: ClosingFinanceHpp;
|
||||||
period: number;
|
|
||||||
project_type: string;
|
|
||||||
volume_base: ClosingFinanceVolumeBase;
|
|
||||||
hpp_purchases: ClosingFinanceHppPurchases;
|
|
||||||
profit_loss: ClosingFinanceProfitLoss;
|
profit_loss: ClosingFinanceProfitLoss;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClosingFinanceProfitLoss {
|
export interface ClosingFinanceHpp {
|
||||||
title: string;
|
items: HppItem[];
|
||||||
data: ProfitLossData;
|
summary: HppSummary;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClosingFinanceHppPurchases {
|
export interface HppItem {
|
||||||
title: string;
|
id: number;
|
||||||
hpp: GroupHppPurchase[];
|
category: string;
|
||||||
summary_hpp: HppPurchasesSummary;
|
code: string;
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClosingFinanceVolumeBase {
|
|
||||||
total_birds: number;
|
|
||||||
total_weight_kg: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProfitLossData {
|
|
||||||
penjualan: ProfitLossDataAmount[];
|
|
||||||
pembelian: ProfitLossDataAmount[];
|
|
||||||
summary: ProfitLossDataSummary;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GroupHppPurchase {
|
|
||||||
group_name: string;
|
|
||||||
data: HppPurchaseData[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProfitLossDataSummary {
|
|
||||||
gross_profit: DataSummarySubTotal;
|
|
||||||
sub_total: DataSummarySubTotal;
|
|
||||||
net_profit: DataSummarySubTotal;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProfitLossDataAmount {
|
|
||||||
type: string;
|
|
||||||
rp_per_bird: number;
|
|
||||||
rp_per_kg: number;
|
|
||||||
amount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HppPurchasesSummary {
|
|
||||||
label: string;
|
label: string;
|
||||||
budgeting: HppPurchaseDataAmount;
|
budgeting: HppPurchaseDataAmount;
|
||||||
realization: HppPurchaseDataAmount;
|
realization: HppPurchaseDataAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HppPurchaseData {
|
export interface HppSummary {
|
||||||
type: string;
|
label: string;
|
||||||
budgeting: HppPurchaseDataAmount;
|
budgeting: HppPurchaseDataAmount;
|
||||||
realization: HppPurchaseDataAmount;
|
realization: HppPurchaseDataAmount;
|
||||||
|
egg_budgeting: HppPurchaseDataAmount;
|
||||||
|
egg_realization: HppPurchaseDataAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HppPurchaseDataAmount {
|
export interface HppPurchaseDataAmount {
|
||||||
@@ -285,8 +251,27 @@ export interface HppPurchaseDataAmount {
|
|||||||
amount: number;
|
amount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DataSummarySubTotal {
|
export interface ClosingFinanceProfitLoss {
|
||||||
|
items: ProfitLossItem[];
|
||||||
|
summary: ProfitLossSummary;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProfitLossItem {
|
||||||
|
code: string;
|
||||||
label: string;
|
label: string;
|
||||||
|
type: string;
|
||||||
|
rp_per_bird: number;
|
||||||
|
rp_per_kg: number;
|
||||||
|
amount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProfitLossSummary {
|
||||||
|
gross_profit: ProfitLossAmount;
|
||||||
|
sub_total: ProfitLossAmount;
|
||||||
|
net_profit: ProfitLossAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProfitLossAmount {
|
||||||
rp_per_bird: number;
|
rp_per_bird: number;
|
||||||
rp_per_kg: number;
|
rp_per_kg: number;
|
||||||
amount: number;
|
amount: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user