mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 05:22:02 +00:00
Merge branch 'dev/randy' into 'development'
[FEAT/FE] Report Sapronak Calculation per Kandang See merge request mbugroup/lti-web-client!156
This commit is contained in:
@@ -7,18 +7,33 @@ import ClosingDetail from '@/components/pages/closing/ClosingDetail';
|
||||
|
||||
import { ClosingApi } from '@/services/api/closing';
|
||||
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||
import { FlockApi } from '@/services/api/master-data';
|
||||
import { ProjectFlockApi } from '@/services/api/production/project-flock';
|
||||
import { ProjectFlockKandangApi } from '@/services/api/production';
|
||||
|
||||
const ClosingDetailPage = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const closingId = searchParams.get('closingId');
|
||||
const kandangId = searchParams.get('kandangId'); // project flock kandang ID
|
||||
|
||||
const { data: closing, isLoading: isLoadingClosing } = useSWR(
|
||||
closingId,
|
||||
(id: number) => ClosingApi.getGeneralInfo(id)
|
||||
);
|
||||
|
||||
// WORKAROUND - get flock data from closing ID
|
||||
const { data: projectData, isLoading: isLoadingProject } = useSWR(
|
||||
`flock-${closingId}`,
|
||||
() => ProjectFlockApi.getSingle(Number(closingId))
|
||||
);
|
||||
// WORKAROUND - get kandang data from closing ID
|
||||
const { data: kandangData, isLoading: isLoadingKandang } = useSWR(
|
||||
kandangId ? `kandang-${closingId}-${kandangId}` : null,
|
||||
() => ProjectFlockKandangApi.getSingle(Number(kandangId))
|
||||
);
|
||||
|
||||
// const { data: salesData, isLoading: isLoadingSales } = useSWR(
|
||||
// closingId ? `sales-${closingId}` : null,
|
||||
// () => ClosingApi.getPenjualan(Number(closingId))
|
||||
@@ -44,7 +59,11 @@ const ClosingDetailPage = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const isLoading = isLoadingClosing || isLoadingHppEkspedisi;
|
||||
const isLoading =
|
||||
isLoadingClosing ||
|
||||
isLoadingHppEkspedisi ||
|
||||
isLoadingProject ||
|
||||
isLoadingKandang;
|
||||
// const isLoading = isLoadingClosing || isLoadingSales || isLoadingHppEkspedisi;
|
||||
|
||||
return (
|
||||
@@ -61,6 +80,12 @@ const ClosingDetailPage = () => {
|
||||
? hppEkspedisiData.data
|
||||
: undefined
|
||||
}
|
||||
projectData={
|
||||
isResponseSuccess(projectData) ? projectData.data : undefined
|
||||
}
|
||||
kandangData={
|
||||
isResponseSuccess(kandangData) ? kandangData.data : undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -19,12 +19,17 @@ import ClosingOverheadTabContent from '@/components/pages/closing/ClosingOverhea
|
||||
import ClosingFinanceTabContent from '@/components/pages/closing/ClosingFinanceTabContent';
|
||||
import SalesReportTable from '@/components/pages/closing/sale/SalesReportTable';
|
||||
import HppExpeditionReportTable from './hpp-ekspedisi/HppExpeditionReportTable';
|
||||
import ClosingKandangList from '@/components/pages/closing/ClosingKandangList';
|
||||
import { ProjectFlock } from '@/types/api/production/project-flock';
|
||||
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
|
||||
|
||||
interface ClosingDetailProps {
|
||||
id: number;
|
||||
initialValue?: ClosingGeneralInformation;
|
||||
salesData?: BaseClosingSales;
|
||||
hppExpeditionData?: ClosingHppExpedition;
|
||||
projectData?: ProjectFlock;
|
||||
kandangData?: ProjectFlockKandang;
|
||||
}
|
||||
|
||||
const ClosingDetail: React.FC<ClosingDetailProps> = ({
|
||||
@@ -32,6 +37,8 @@ const ClosingDetail: React.FC<ClosingDetailProps> = ({
|
||||
initialValue,
|
||||
salesData,
|
||||
hppExpeditionData,
|
||||
projectData,
|
||||
kandangData,
|
||||
}) => {
|
||||
const [activeTab, setActiveTab] = useState<string>('sapronak');
|
||||
|
||||
@@ -49,6 +56,7 @@ const ClosingDetail: React.FC<ClosingDetailProps> = ({
|
||||
<ClosingSapronakCalculationTabContent
|
||||
closingGeneralInformation={initialValue}
|
||||
projectFlockId={id}
|
||||
projectKandangId={kandangData?.id}
|
||||
/>
|
||||
),
|
||||
},
|
||||
@@ -87,7 +95,9 @@ const ClosingDetail: React.FC<ClosingDetailProps> = ({
|
||||
<section className='w-full max-w-7xl pb-16'>
|
||||
<header className='flex flex-col gap-4'>
|
||||
<Button
|
||||
href='/closing'
|
||||
href={
|
||||
!kandangData ? '/closing' : `/closing/detail/?closingId=${id}`
|
||||
}
|
||||
variant='link'
|
||||
className='w-fit p-0 text-primary'
|
||||
>
|
||||
@@ -98,7 +108,18 @@ const ClosingDetail: React.FC<ClosingDetailProps> = ({
|
||||
<h1 className='text-2xl font-bold text-center'>Detail Closing</h1>
|
||||
</header>
|
||||
|
||||
<ClosingGeneralInformationTable initialValue={initialValue} />
|
||||
<ClosingGeneralInformationTable
|
||||
initialValue={initialValue}
|
||||
projectData={projectData}
|
||||
kandangData={kandangData}
|
||||
/>
|
||||
|
||||
{!kandangData && (
|
||||
<ClosingKandangList
|
||||
initialValue={initialValue}
|
||||
projectData={projectData}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Tabs
|
||||
activeTabId={activeTab}
|
||||
|
||||
@@ -1,12 +1,29 @@
|
||||
import { ClosingGeneralInformation } from '@/types/api/closing';
|
||||
import { ProjectFlock } from '@/types/api/production/project-flock';
|
||||
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
interface ClosingGeneralInformationProps {
|
||||
initialValue?: ClosingGeneralInformation;
|
||||
projectData?: ProjectFlock;
|
||||
kandangData?: ProjectFlockKandang;
|
||||
}
|
||||
|
||||
const ClosingGeneralInformationTable = ({
|
||||
initialValue,
|
||||
projectData,
|
||||
kandangData,
|
||||
}: ClosingGeneralInformationProps) => {
|
||||
const chickinPopulation = useMemo(() => {
|
||||
if (kandangData) {
|
||||
return kandangData?.chickins?.reduce(
|
||||
(acc, chickin) => acc + chickin.usage_qty,
|
||||
0
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
}, [kandangData]);
|
||||
|
||||
return (
|
||||
<div className='w-full my-4 @container'>
|
||||
<div className='flex flex-col @sm:flex-row gap-4'>
|
||||
@@ -17,7 +34,9 @@ const ClosingGeneralInformationTable = ({
|
||||
<tr>
|
||||
<td>Lokasi</td>
|
||||
<td>:</td>
|
||||
<td>{initialValue?.location_name}</td>
|
||||
<td>
|
||||
{initialValue?.location_name ?? projectData?.location?.name}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Periode</td>
|
||||
@@ -27,12 +46,20 @@ const ClosingGeneralInformationTable = ({
|
||||
<tr>
|
||||
<td>Project Flock</td>
|
||||
<td>:</td>
|
||||
<td>{initialValue?.project_flock?.name}</td>
|
||||
<td>
|
||||
{initialValue?.project_flock?.name ??
|
||||
projectData?.flock_name}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Populasi</td>
|
||||
<td>:</td>
|
||||
<td>{initialValue?.population} Ekor</td>
|
||||
<td>
|
||||
{!kandangData
|
||||
? (initialValue?.population ?? 0)
|
||||
: (chickinPopulation ?? 0)}{' '}
|
||||
Ekor
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jenis Project</td>
|
||||
@@ -40,9 +67,13 @@ const ClosingGeneralInformationTable = ({
|
||||
<td>{initialValue?.project_type}</td>
|
||||
</tr>
|
||||
<tr className='table-row @sm:hidden'>
|
||||
<td>Kandang Aktif</td>
|
||||
<td>Kandang {!kandangData && 'Aktif'}</td>
|
||||
<td>:</td>
|
||||
<td>{initialValue?.active_house_count} Kandang</td>
|
||||
<td>
|
||||
{!kandangData
|
||||
? `${initialValue?.active_house_count} Kandang`
|
||||
: kandangData?.kandang?.name}
|
||||
</td>
|
||||
</tr>
|
||||
<tr className='table-row @sm:hidden'>
|
||||
<td>Status Pembayaran Penjualan</td>
|
||||
@@ -69,9 +100,13 @@ const ClosingGeneralInformationTable = ({
|
||||
<table className='table table-zebra table-sm'>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Kandang Aktif</td>
|
||||
<td>Kandang {!kandangData && 'Aktif'}</td>
|
||||
<td>:</td>
|
||||
<td>{initialValue?.active_house_count} Kandang</td>
|
||||
<td>
|
||||
{!kandangData
|
||||
? `${initialValue?.active_house_count} Kandang`
|
||||
: kandangData?.kandang?.name}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Status Pembayaran Penjualan</td>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import Button from '@/components/Button';
|
||||
import { ClosingGeneralInformation } from '@/types/api/closing';
|
||||
import { ProjectFlock } from '@/types/api/production/project-flock';
|
||||
|
||||
const ClosingKandangList = ({
|
||||
initialValue,
|
||||
projectData,
|
||||
}: {
|
||||
initialValue?: ClosingGeneralInformation;
|
||||
projectData?: ProjectFlock;
|
||||
}) => {
|
||||
return (
|
||||
<div className='w-full my-4 @container'>
|
||||
<div className='flex flex-col @sm:flex-row gap-4'>
|
||||
<div className='w-full'>
|
||||
<div className='overflow-x-auto'>
|
||||
<h1 className='font-bold my-4'>Kandang</h1>
|
||||
<div className='flex flex-wrap gap-2 mb-4'>
|
||||
{projectData?.kandangs?.map((kandang) => (
|
||||
<Button
|
||||
key={kandang.id}
|
||||
variant='outline'
|
||||
href={`/closing/detail/?closingId=${initialValue?.flock_id}&kandangId=${kandang.project_flock_kandang_id}`}
|
||||
className='min-w-32'
|
||||
>
|
||||
{kandang.name}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ClosingKandangList;
|
||||
@@ -5,11 +5,13 @@ import { ClosingGeneralInformation } from '@/types/api/closing';
|
||||
|
||||
interface ClosingSapronakCalculationTabContentProps {
|
||||
projectFlockId?: number;
|
||||
projectKandangId?: number;
|
||||
closingGeneralInformation?: ClosingGeneralInformation;
|
||||
}
|
||||
|
||||
const ClosingSapronakCalculationTabContent = ({
|
||||
projectFlockId,
|
||||
projectKandangId,
|
||||
closingGeneralInformation,
|
||||
}: ClosingSapronakCalculationTabContentProps) => {
|
||||
return (
|
||||
@@ -19,6 +21,7 @@ const ClosingSapronakCalculationTabContent = ({
|
||||
<ClosingSapronakCalculationTable
|
||||
closingGeneralInformation={closingGeneralInformation}
|
||||
projectFlockId={projectFlockId}
|
||||
projectKandangId={projectKandangId}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -17,16 +17,18 @@ import { ClosingGeneralInformation } from '@/types/api/closing';
|
||||
|
||||
interface ClosingSapronakCalculationTableProps {
|
||||
projectFlockId: number;
|
||||
projectKandangId?: number;
|
||||
closingGeneralInformation?: ClosingGeneralInformation;
|
||||
}
|
||||
|
||||
const ClosingSapronakCalculationTable = ({
|
||||
projectFlockId,
|
||||
closingGeneralInformation,
|
||||
projectKandangId,
|
||||
}: ClosingSapronakCalculationTableProps) => {
|
||||
const { data: sapronakCalculation, isLoading } = useSWR(
|
||||
`/closing/sapronak-calculation/${projectFlockId}`,
|
||||
() => ClosingApi.getPerhitunganSapronak(projectFlockId),
|
||||
`/closing/sapronak-calculation/${projectFlockId}${projectKandangId ? `/${projectKandangId}` : ''}`,
|
||||
() => ClosingApi.getPerhitunganSapronak(projectFlockId, projectKandangId),
|
||||
{
|
||||
keepPreviousData: true,
|
||||
}
|
||||
@@ -57,11 +59,11 @@ const ClosingSapronakCalculationTable = ({
|
||||
cell: (props) =>
|
||||
props.row.original.qty_in
|
||||
? formatNumber(props.row.original.qty_in as number)
|
||||
: '-',
|
||||
: '0',
|
||||
footer: total
|
||||
? () => (
|
||||
<div className='font-semibold text-gray-900'>
|
||||
{total?.qty_in ? formatNumber(total?.qty_in) : '-'}
|
||||
{total?.qty_in ? formatNumber(total?.qty_in) : '0'}
|
||||
</div>
|
||||
)
|
||||
: '',
|
||||
@@ -72,11 +74,11 @@ const ClosingSapronakCalculationTable = ({
|
||||
cell: (props) =>
|
||||
props.row.original.qty_out
|
||||
? formatNumber(props.row.original.qty_out as number)
|
||||
: '-',
|
||||
: '0',
|
||||
footer: total
|
||||
? () => (
|
||||
<div className='font-semibold text-gray-900'>
|
||||
{total?.qty_out ? formatNumber(total?.qty_out) : '-'}
|
||||
{total?.qty_out ? formatNumber(total?.qty_out) : '0'}
|
||||
</div>
|
||||
)
|
||||
: '',
|
||||
@@ -87,11 +89,11 @@ const ClosingSapronakCalculationTable = ({
|
||||
cell: (props) =>
|
||||
props.row.original.qty_used
|
||||
? formatNumber(props.row.original.qty_used as number)
|
||||
: '-',
|
||||
: '0',
|
||||
footer: total
|
||||
? () => (
|
||||
<div className='font-semibold text-gray-900'>
|
||||
{total?.qty_used ? formatNumber(total?.qty_used) : '-'}
|
||||
{total?.qty_used ? formatNumber(total?.qty_used) : '0'}
|
||||
</div>
|
||||
)
|
||||
: '',
|
||||
@@ -173,14 +175,6 @@ const ClosingSapronakCalculationTable = ({
|
||||
[sapronakCalculation]
|
||||
);
|
||||
|
||||
const pulletColumns = useMemo(
|
||||
() =>
|
||||
isResponseSuccess(sapronakCalculation)
|
||||
? createColumns(sapronakCalculation.data?.pullet?.total)
|
||||
: createColumns(),
|
||||
[sapronakCalculation]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className='flex flex-col gap-4'>
|
||||
{/* Table DOC jika kategori Project Flock Growing */}
|
||||
@@ -200,20 +194,17 @@ const ClosingSapronakCalculationTable = ({
|
||||
<Table<RowSapronakCalculation>
|
||||
data={
|
||||
isResponseSuccess(sapronakCalculation)
|
||||
? ((closingGeneralInformation?.project_category === 'GROWING'
|
||||
? sapronakCalculation.data?.doc?.rows
|
||||
: sapronakCalculation.data?.pullet?.rows) ?? [])
|
||||
? (sapronakCalculation.data?.doc?.rows ?? [])
|
||||
: []
|
||||
}
|
||||
columns={
|
||||
closingGeneralInformation?.project_category === 'GROWING'
|
||||
? docColumns
|
||||
: pulletColumns
|
||||
}
|
||||
columns={docColumns}
|
||||
className={{
|
||||
containerClassName: 'my-4',
|
||||
}}
|
||||
renderFooter={isResponseSuccess(sapronakCalculation)}
|
||||
renderFooter={
|
||||
isResponseSuccess(sapronakCalculation) &&
|
||||
sapronakCalculation.data?.doc?.rows.length > 0
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
@@ -236,7 +227,10 @@ const ClosingSapronakCalculationTable = ({
|
||||
className={{
|
||||
containerClassName: 'my-4',
|
||||
}}
|
||||
renderFooter={isResponseSuccess(sapronakCalculation)}
|
||||
renderFooter={
|
||||
isResponseSuccess(sapronakCalculation) &&
|
||||
sapronakCalculation.data?.ovk?.rows.length > 0
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
@@ -259,7 +253,10 @@ const ClosingSapronakCalculationTable = ({
|
||||
className={{
|
||||
containerClassName: 'my-4',
|
||||
}}
|
||||
renderFooter={isResponseSuccess(sapronakCalculation)}
|
||||
renderFooter={
|
||||
isResponseSuccess(sapronakCalculation) &&
|
||||
sapronakCalculation.data?.pakan?.rows.length > 0
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@@ -96,7 +96,7 @@ const DebtSupplierTab = () => {
|
||||
filterSupplier.length > 0
|
||||
? filterSupplier.map((v) => String(v.value)).join(',')
|
||||
: undefined,
|
||||
filter_by: 'do_date' as const,
|
||||
filter_by: filterDataType?.value || 'do_date',
|
||||
start_date: filterStartDate || undefined,
|
||||
end_date: filterEndDate || undefined,
|
||||
page: currentPage,
|
||||
@@ -109,7 +109,7 @@ const DebtSupplierTab = () => {
|
||||
([, params]) =>
|
||||
FinanceApi.getDebtSupplierReport(
|
||||
params.supplier_ids,
|
||||
params.filter_by,
|
||||
params.filter_by?.toString(),
|
||||
params.start_date,
|
||||
params.end_date,
|
||||
params.page,
|
||||
@@ -448,7 +448,7 @@ const DebtSupplierTab = () => {
|
||||
<Table
|
||||
data={supplierReport.rows}
|
||||
columns={getTableColumns(supplierReport)}
|
||||
pageSize={10}
|
||||
pageSize={supplierReport.rows.length}
|
||||
renderFooter={supplierReport.rows.length > 0}
|
||||
className={{
|
||||
containerClassName: 'w-full',
|
||||
@@ -534,6 +534,7 @@ const DebtSupplierTab = () => {
|
||||
|
||||
<div className='mt-auto'>
|
||||
<DateInput
|
||||
label=' '
|
||||
name='end_date'
|
||||
value={filterEndDate}
|
||||
onChange={(e) => {
|
||||
|
||||
@@ -92,10 +92,11 @@ export class ClosingApiService extends BaseApiService<Closing, null, null> {
|
||||
}
|
||||
|
||||
async getPerhitunganSapronak(
|
||||
id: number
|
||||
id: number,
|
||||
projectKandangId?: number
|
||||
): Promise<BaseApiResponse<ClosingSapronakCalculation> | undefined> {
|
||||
try {
|
||||
const path = `${this.basePath}/${id}/perhitungan_sapronak`;
|
||||
const path = `${this.basePath}/${id}${projectKandangId ? `/${projectKandangId}` : ''}/perhitungan_sapronak`;
|
||||
return await httpClient<BaseApiResponse<ClosingSapronakCalculation>>(
|
||||
path,
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ export class FinanceApiService extends BaseApiService<
|
||||
|
||||
async getDebtSupplierReport(
|
||||
supplier_ids?: string,
|
||||
filter_by?: 'do_date',
|
||||
filter_by?: string,
|
||||
start_date?: string,
|
||||
end_date?: string,
|
||||
page?: number,
|
||||
|
||||
Vendored
-1
@@ -185,7 +185,6 @@ export type ClosingSapronakCalculation = {
|
||||
doc: ClosingSapronakCalculationItem;
|
||||
ovk: ClosingSapronakCalculationItem;
|
||||
pakan: ClosingSapronakCalculationItem;
|
||||
pullet: ClosingSapronakCalculationItem;
|
||||
};
|
||||
|
||||
// ====== OVERHEAD ======
|
||||
|
||||
Reference in New Issue
Block a user