fix(FE): remove dummy data and integrate live API for closing finance and fixing closing UI when given data is null

This commit is contained in:
randy-ar
2025-12-17 14:22:15 +07:00
parent b02b458034
commit bb80e9e9c6
8 changed files with 409 additions and 2871 deletions
@@ -136,381 +136,370 @@ const ClosingFinanceTable = ({
return ( return (
<div className='flex flex-col gap-4'> <div className='flex flex-col gap-4'>
{isResponseSuccess(finance) && ( <>
<> <Card
<Card variant='bordered'
variant='bordered' className={{
className={{ wrapper: 'w-full',
wrapper: 'w-full', }}
}} >
> <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> {isResponseSuccess(finance)
{formatTitleCase( ? formatTitleCase(
finance.data.profit_loss.data.summary.gross_profit.label || finance.data.profit_loss.data.summary.gross_profit
'-' .label || '-'
)} )
</div> : 'Laba Rugi Brutto'}
<div className='text-lg font-bold'>
{formatCurrency(
finance.data.profit_loss.data.summary.gross_profit.amount
)}
</div>
</div> </div>
<div className='flex flex-col gap-1'> <div className='text-lg font-bold'>
<div> {isResponseSuccess(finance)
{formatTitleCase( ? formatCurrency(
finance.data.profit_loss.data.summary.net_profit.label || finance.data.profit_loss.data.summary.gross_profit.amount
'-' )
)} : '-'}
</div>
<div className='text-lg font-bold'>
{formatCurrency(
finance.data.profit_loss.data.summary.net_profit.amount
)}
</div>
</div> </div>
</div> </div>
</Card> <div className='flex flex-col gap-1'>
<Card <div>
title={finance.data.hpp_purchases.title} {isResponseSuccess(finance)
variant='bordered' ? formatTitleCase(
collapsible finance.data.profit_loss.data.summary.net_profit.label ||
className={{ '-'
wrapper: 'w-full', )
}} : 'Laba Rugi Netto'}
> </div>
<div className='mt-6 p-0 mb-0'> <div className='text-lg font-bold'>
<Table<HppTableRow> {isResponseSuccess(finance)
data={hppTableData} ? formatCurrency(
columns={[ finance.data.profit_loss.data.summary.net_profit.amount
{ )
header: 'No.', : '-'}
enableSorting: false, </div>
accessorFn: (item, index) => { </div>
if (item.isGroupHeader) return '-'; </div>
// Calculate row number excluding group headers </Card>
const dataRowsBefore = hppTableData <Card
.slice(0, index) title={
.filter((row) => !row.isGroupHeader).length; isResponseSuccess(finance)
return dataRowsBefore + 1; ? finance.data.hpp_purchases.title
: 'HPP Purchases'
}
variant='bordered'
collapsible
className={{
wrapper: 'w-full',
}}
>
<div className='mt-6 p-0 mb-0'>
<Table<HppTableRow>
data={hppTableData}
columns={[
{
header: 'No.',
enableSorting: false,
accessorFn: (item, index) => {
if (item.isGroupHeader) return '-';
const dataRowsBefore = hppTableData
.slice(0, index)
.filter((row) => !row.isGroupHeader).length;
return dataRowsBefore + 1;
},
footer: (props) => {
return 'HPP';
},
},
{
header: 'Type',
enableSorting: false,
accessorFn: (item) => formatTitleCase(item.type || '-'),
},
{
header: 'Budgeting',
enableSorting: false,
columns: [
{
header: 'Rp/Ekor',
id: 'budgeting_rp_per_bird',
enableSorting: false,
accessorFn: (item) =>
formatCurrency(item.budgeting?.rp_per_bird || 0),
footer: (props) => {
return props.column.id === 'budgeting_rp_per_bird' &&
isResponseSuccess(finance)
? formatCurrency(
finance.data.hpp_purchases.summary_hpp.budgeting
.rp_per_bird || 0
)
: '-';
},
}, },
footer: (props) => { {
return 'HPP'; header: 'Rp/Kg',
id: 'budgeting_rp_per_kg',
enableSorting: false,
accessorFn: (item) =>
formatCurrency(item.budgeting?.rp_per_kg || 0),
footer: (props) => {
return props.column.id === 'budgeting_rp_per_kg' &&
isResponseSuccess(finance)
? formatCurrency(
finance.data.hpp_purchases.summary_hpp.budgeting
.rp_per_kg || 0
)
: '-';
},
}, },
}, {
{ header: 'Jumlah (Rp)',
header: 'Type', id: 'budgeting_amount',
enableSorting: false, enableSorting: false,
accessorFn: (item) => formatTitleCase(item.type || '-'), accessorFn: (item) =>
}, formatCurrency(item.budgeting?.amount || 0),
{ footer: (props) => {
header: 'Budgeting', return props.column.id === 'budgeting_amount' &&
enableSorting: false, isResponseSuccess(finance)
columns: [ ? formatCurrency(
{ finance.data.hpp_purchases.summary_hpp.budgeting
header: 'Rp/Ekor', .amount || 0
id: 'budgeting_rp_per_bird', )
enableSorting: false, : '-';
accessorFn: (item) =>
formatCurrency(item.budgeting?.rp_per_bird || 0),
footer: (props) => {
return props.column.id === 'budgeting_rp_per_bird'
? formatCurrency(
finance.data.hpp_purchases.hpp.reduce(
(total, hpp) =>
total +
(finance.data.hpp_purchases.summary_hpp
.budgeting.rp_per_bird || 0),
0
)
)
: '-';
},
}, },
{ },
header: 'Rp/Kg', ],
id: 'budgeting_rp_per_kg', },
enableSorting: false, {
accessorFn: (item) => header: 'Realization',
formatCurrency(item.budgeting?.rp_per_kg || 0), enableSorting: false,
footer: (props) => { columns: [
return props.column.id === 'budgeting_rp_per_kg' {
? formatCurrency( header: 'Rp/Ekor',
finance.data.hpp_purchases.hpp.reduce( id: 'realization_rp_per_bird',
(total, hpp) => enableSorting: false,
total + accessorFn: (item) =>
(finance.data.hpp_purchases.summary_hpp formatCurrency(item.realization?.rp_per_bird || 0),
.budgeting.rp_per_kg || 0), footer: (props) => {
0 return props.column.id === 'realization_rp_per_bird' &&
) isResponseSuccess(finance)
) ? formatCurrency(
: '-'; finance.data.hpp_purchases.summary_hpp.realization
}, .rp_per_bird || 0
)
: '-';
}, },
{ },
header: 'Jumlah (Rp)', {
id: 'budgeting_amount', header: 'Rp/Kg',
enableSorting: false, id: 'realization_rp_per_kg',
accessorFn: (item) => enableSorting: false,
formatCurrency(item.budgeting?.amount || 0), accessorFn: (item) =>
footer: (props) => { formatCurrency(item.realization?.rp_per_kg || 0),
return props.column.id === 'budgeting_amount' footer: (props) => {
? formatCurrency( return props.column.id === 'realization_rp_per_kg' &&
finance.data.hpp_purchases.hpp.reduce( isResponseSuccess(finance)
(total, hpp) => ? formatCurrency(
total + finance.data.hpp_purchases.summary_hpp.realization
(finance.data.hpp_purchases.summary_hpp .rp_per_kg || 0
.budgeting.amount || 0), )
0 : '-';
)
)
: '-';
},
}, },
], },
}, {
{ header: 'Jumlah (Rp)',
header: 'Realization', id: 'realization_amount',
enableSorting: false, enableSorting: false,
columns: [ accessorFn: (item) =>
{ formatCurrency(item.realization?.amount || 0),
header: 'Rp/Ekor', footer: (props) => {
id: 'realization_rp_per_bird', return props.column.id === 'realization_amount' &&
enableSorting: false, isResponseSuccess(finance)
accessorFn: (item) => ? formatCurrency(
formatCurrency(item.realization?.rp_per_bird || 0), finance.data.hpp_purchases.summary_hpp.realization
footer: (props) => { .amount || 0
return props.column.id === 'realization_rp_per_bird' )
? formatCurrency( : '-';
finance.data.hpp_purchases.hpp.reduce(
(total, hpp) =>
total +
(finance.data.hpp_purchases.summary_hpp
.realization.rp_per_bird || 0),
0
)
)
: '-';
},
}, },
{ },
header: 'Rp/Kg', ],
id: 'realization_rp_per_kg', },
enableSorting: false, ]}
accessorFn: (item) => renderCustomRow={(row) => {
formatCurrency(item.realization?.rp_per_kg || 0), const rowData = row.original;
footer: (props) => { if (rowData.isGroupHeader) {
return props.column.id === 'realization_rp_per_kg' return (
? formatCurrency( <tr
finance.data.hpp_purchases.hpp.reduce( key={row.id}
(total, hpp) => className={TABLE_DEFAULT_STYLING.bodyRowClassName}
total + >
(finance.data.hpp_purchases.summary_hpp <td
.realization.rp_per_kg || 0), className={TABLE_DEFAULT_STYLING.bodyColumnClassName}
0 ></td>
) <td
) colSpan={7}
: '-'; className={TABLE_DEFAULT_STYLING.bodyColumnClassName}
}, >
}, <div className='font-bold'>
{ {formatTitleCase(rowData.group_name ?? '-')}
header: 'Jumlah (Rp)', </div>
id: 'realization_amount', </td>
enableSorting: false, </tr>
accessorFn: (item) => );
formatCurrency(item.realization?.amount || 0), }
footer: (props) => { return null;
return props.column.id === 'realization_amount' }}
? formatCurrency( renderFooter={isResponseSuccess(finance)}
finance.data.hpp_purchases.hpp.reduce( />
(total, hpp) => </div>
total + </Card>
(finance.data.hpp_purchases.summary_hpp <Card
.realization.amount || 0), title={
0 isResponseSuccess(finance)
) ? finance.data.profit_loss.title
) : 'Profit/Loss'
: '-'; }
}, variant='bordered'
}, collapsible
], className={{
}, wrapper: 'w-full',
]} }}
renderCustomRow={(row) => { >
const rowData = row.original; <div className='mt-6 p-0 mb-0'>
if (rowData.isGroupHeader) { <Table<ProfitLossTableRow>
data={profitLossTableData}
columns={[
{
header: 'Type',
enableSorting: false,
accessorFn: (item) => item.type,
cell: (item) => (
<div className='ps-6'>
{formatTitleCase(item.row.original.type || '-')}
</div>
),
footer: (item) => (
<div className='font-bold'>
{isResponseSuccess(finance)
? formatTitleCase(
finance.data.profit_loss.data.summary.net_profit
.label || '-'
)
: '-'}
</div>
),
},
{
header: 'Rp/Ekor',
enableSorting: false,
accessorFn: (item) => formatCurrency(item.rp_per_bird || 0),
footer: (item) => (
<div className='font-bold'>
{isResponseSuccess(finance)
? formatCurrency(
finance.data.profit_loss.data.summary.net_profit
.rp_per_bird || 0
)
: formatCurrency(0)}
</div>
),
},
{
header: 'Rp/Kg',
enableSorting: false,
accessorFn: (item) => formatCurrency(item.rp_per_kg || 0),
footer: (item) => (
<div className='font-bold'>
{isResponseSuccess(finance)
? formatCurrency(
finance.data.profit_loss.data.summary.net_profit
.rp_per_kg || 0
)
: formatCurrency(0)}
</div>
),
},
{
header: 'Jumlah (Rp)',
enableSorting: false,
accessorFn: (item) => formatCurrency(item.amount || 0),
footer: (item) => (
<div className='font-bold'>
{isResponseSuccess(finance)
? formatCurrency(
finance.data.profit_loss.data.summary.net_profit
.amount || 0
)
: formatCurrency(0)}
</div>
),
},
]}
renderCustomRow={(row) => {
const rowData = row.original;
if (rowData.isGroupHeader) {
if (rowData.amount) {
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} className={TABLE_DEFAULT_STYLING.bodyColumnClassName}
></td> >
<div className='font-bold'>
{formatTitleCase(rowData.label ?? '-')}
</div>
</td>
<td <td
colSpan={7}
className={TABLE_DEFAULT_STYLING.bodyColumnClassName} 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>
); );
} }
return null; return (
}} <tr
renderFooter key={row.id}
/> className={TABLE_DEFAULT_STYLING.bodyRowClassName}
</div> >
</Card> <td
<Card colSpan={4}
title={finance.data.profit_loss.title} className={TABLE_DEFAULT_STYLING.bodyColumnClassName}
variant='bordered'
collapsible
className={{
wrapper: 'w-full',
}}
>
<div className='mt-6 p-0 mb-0'>
<Table<ProfitLossTableRow>
data={profitLossTableData}
columns={[
{
header: 'Type',
enableSorting: false,
accessorFn: (item) => item.type,
cell: (item) => (
<div className='ps-6'>
{formatTitleCase(item.row.original.type || '-')}
</div>
),
footer: (item) => (
<div className='font-bold'>
{formatTitleCase(
finance.data.profit_loss.data.summary.net_profit
.label || '-'
)}
</div>
),
},
{
header: 'Rp/Ekor',
enableSorting: false,
accessorFn: (item) => formatCurrency(item.rp_per_bird || 0),
footer: (item) => (
<div className='font-bold'>
{formatCurrency(
finance.data.profit_loss.data.summary.net_profit
.rp_per_bird || 0
)}
</div>
),
},
{
header: 'Rp/Kg',
enableSorting: false,
accessorFn: (item) => formatCurrency(item.rp_per_kg || 0),
footer: (item) => (
<div className='font-bold'>
{formatCurrency(
finance.data.profit_loss.data.summary.net_profit
.rp_per_kg || 0
)}
</div>
),
},
{
header: 'Jumlah (Rp)',
enableSorting: false,
accessorFn: (item) => formatCurrency(item.amount || 0),
footer: (item) => (
<div className='font-bold'>
{formatCurrency(
finance.data.profit_loss.data.summary.net_profit
.amount || 0
)}
</div>
),
},
]}
renderCustomRow={(row) => {
const rowData = row.original;
if (rowData.isGroupHeader) {
if (rowData.amount) {
return (
<tr
key={row.id}
className={TABLE_DEFAULT_STYLING.footerRowClassName}
>
<td
className={
TABLE_DEFAULT_STYLING.bodyColumnClassName
}
>
<div className='font-bold'>
{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 (
<tr
key={row.id}
className={TABLE_DEFAULT_STYLING.bodyRowClassName}
> >
<td <div className='font-bold'>
colSpan={4} {formatTitleCase(rowData.group_name ?? '-')}
className={TABLE_DEFAULT_STYLING.bodyColumnClassName} </div>
> </td>
<div className='font-bold'> </tr>
{formatTitleCase(rowData.group_name ?? '-')} );
</div> }
</td> return null;
</tr> }}
); className={{
} paginationClassName: 'hidden',
return null; }}
}} renderFooter={isResponseSuccess(finance)}
className={{ />
paginationClassName: 'hidden', </div>
}} </Card>
renderFooter </>
/>
</div>
</Card>
</>
)}
</div> </div>
); );
}; };
@@ -154,66 +154,74 @@ const ClosingSapronakCalculationTable = ({
return ( return (
<div className='flex flex-col gap-4'> <div className='flex flex-col gap-4'>
{isResponseSuccess(sapronakCalculation) && ( <Card
<> title='DOC Broiler'
<Card collapsible
title='DOC Broiler' defaultCollapsed={false}
collapsible className={{
defaultCollapsed={false} wrapper: 'w-full',
className={{ body: 'p-4 shadow',
wrapper: 'w-full', }}
body: 'p-4 shadow', >
}} <Table<RowSapronakCalculation>
> data={
<Table<RowSapronakCalculation> isResponseSuccess(sapronakCalculation)
data={sapronakCalculation.data?.doc_broiler.rows ?? []} ? (sapronakCalculation.data?.doc_broiler.rows ?? [])
columns={docBroilerColumns} : []
className={{ }
containerClassName: 'my-4', columns={docBroilerColumns}
}} className={{
renderFooter containerClassName: 'my-4',
/> }}
</Card> renderFooter={isResponseSuccess(sapronakCalculation)}
/>
</Card>
<Card <Card
title='OVK' title='OVK'
variant='bordered' variant='bordered'
collapsible collapsible
defaultCollapsed={true} defaultCollapsed={true}
className={{ className={{
wrapper: 'w-full', wrapper: 'w-full',
}} }}
> >
<Table<RowSapronakCalculation> <Table<RowSapronakCalculation>
data={sapronakCalculation.data?.ovk.rows ?? []} data={
columns={ovkColumns} isResponseSuccess(sapronakCalculation)
className={{ ? (sapronakCalculation.data?.ovk.rows ?? [])
containerClassName: 'my-4', : []
}} }
renderFooter columns={ovkColumns}
/> className={{
</Card> containerClassName: 'my-4',
}}
renderFooter={isResponseSuccess(sapronakCalculation)}
/>
</Card>
<Card <Card
title='Pakan' title='Pakan'
variant='bordered' variant='bordered'
collapsible collapsible
defaultCollapsed={true} defaultCollapsed={true}
className={{ className={{
wrapper: 'w-full', wrapper: 'w-full',
}} }}
> >
<Table<RowSapronakCalculation> <Table<RowSapronakCalculation>
data={sapronakCalculation.data?.pakan.rows ?? []} data={
columns={pakanColumns} isResponseSuccess(sapronakCalculation)
className={{ ? (sapronakCalculation.data?.pakan.rows ?? [])
containerClassName: 'my-4', : []
}} }
renderFooter columns={pakanColumns}
/> className={{
</Card> containerClassName: 'my-4',
</> }}
)} renderFooter={isResponseSuccess(sapronakCalculation)}
/>
</Card>
</div> </div>
); );
}; };
File diff suppressed because it is too large Load Diff
-185
View File
@@ -1,185 +0,0 @@
/**
* Dummy data for ClosingFinance
* Generated from: closing_keuangan.json
*
* This file is auto-generated. Do not edit manually.
*/
import { ClosingFinance } from '../../types/api/closing';
import { BaseApiResponse } from '@/types/api/api-general';
const DUMMY_DATA: ClosingFinance = {
project_flock_id: 1,
period: 1,
project_type: 'LAYING',
volume_base: {
total_birds: 254435,
total_weight_kg: 499961,
},
hpp_purchases: {
title: 'Pembelian HPP Budgeting dan HPP Realisasi',
hpp: [
{
group_name: 'hpp dan pengeluaran',
data: [
{
type: 'Pembelian PULLET LAYER',
budgeting: {
rp_per_bird: 7458.82,
rp_per_kg: 3795.866,
amount: 1897784868,
},
realization: {
rp_per_bird: 7292.414,
rp_per_kg: 3711.18,
amount: 1855445430,
},
},
{
type: 'Pembelian OVK',
budgeting: {
rp_per_bird: 385.681,
rp_per_kg: 196.277,
amount: 98130789,
},
realization: {
rp_per_bird: 424.097,
rp_per_kg: 215.827,
amount: 107905006,
},
},
{
type: 'Pembelian Pakan',
budgeting: {
rp_per_bird: 23002.545,
rp_per_kg: 11706.218,
amount: 5852652652,
},
realization: {
rp_per_bird: 25193.973,
rp_per_kg: 12821.457,
amount: 6410228456,
},
},
],
},
{
group_name: 'hpp dan bahan baku',
data: [
{
type: 'Pengeluaran Overhead',
budgeting: {
rp_per_bird: 6165.894,
rp_per_kg: 3137.883,
amount: 1568819297,
},
realization: {
rp_per_bird: 5975.831,
rp_per_kg: 3041.158,
amount: 1520460611,
},
},
{
type: 'Beban Ekspedisi',
budgeting: {
rp_per_bird: 304.218,
rp_per_kg: 154.819,
amount: 77403605,
},
realization: {
rp_per_bird: 237.466,
rp_per_kg: 120.849,
amount: 60419779,
},
},
],
},
],
summary_hpp: {
label: 'HPP',
budgeting: {
rp_per_bird: 37317.158,
rp_per_kg: 18991.064,
amount: 9494791211,
},
realization: {
rp_per_bird: 39123.781,
rp_per_kg: 19910.472,
amount: 9954459282,
},
},
},
profit_loss: {
title: 'Laba Rugi Perusahaan',
data: {
penjualan: [
{
type: 'Penjualan Telur dan Ayam Afkir',
rp_per_bird: 37551.535,
rp_per_kg: 19110.34,
amount: 9554424729,
},
],
pembelian: [
{
type: 'Pembelian Sapronak Supplier',
rp_per_bird: 27629.158,
rp_per_kg: 14060.746,
amount: 7029824870,
},
{
type: 'Pengeluaran Overhead',
rp_per_bird: 5975.831,
rp_per_kg: 3041.158,
amount: 1520460611,
},
{
type: 'Beban Ekspedisi',
rp_per_bird: 237.466,
rp_per_kg: 120.849,
amount: 60419779,
},
],
summary: {
gross_profit: {
label: 'LABA RUGI BRUTTO',
rp_per_bird: 9922.376,
rp_per_kg: 5049.594,
amount: 2524599859,
},
sub_total: {
label: 'SUB TOTAL',
rp_per_bird: 3709.079,
rp_per_kg: 1887.586,
amount: 943719469,
},
net_profit: {
label: 'LABA RUGI NETTO',
rp_per_bird: 3709.079,
rp_per_kg: 1887.586,
amount: 943719469,
},
},
},
},
};
/**
* Get dummy ClosingFinance data
* @param id - Optional ID parameter
* @returns Promise with BaseApiResponse containing ClosingFinance
*/
export async function dummyGetOneClosingFinance(
id?: number
): Promise<BaseApiResponse<ClosingFinance>> {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
code: 200,
status: 'success',
message: 'Data retrieved successfully',
data: DUMMY_DATA,
});
}, 500);
});
}
-388
View File
@@ -1,388 +0,0 @@
import { format } from 'date-fns';
import { Area } from '@/types/api/master-data/area';
import { Location } from '@/types/api/master-data/location';
import { Kandang } from '@/types/api/master-data/kandang';
import { Warehouse } from '@/types/api/master-data/warehouse';
import { ProductWarehouse } from '@/types/api/inventory/product-warehouse';
import {
BaseMarketing,
Marketing,
BaseSalesOrder,
BaseDeliveryOrder,
BaseDelivery,
} from '@/types/api/marketing/marketing';
import {
CreatedUser,
BaseApproval,
BaseMetadata,
} from '@/types/api/api-general';
import { Product } from '@/types/api/master-data/product';
import { Customer } from '@/types/api/master-data/customer';
import { Uom } from '@/types/api/master-data/uom';
import { ProductCategory } from '@/types/api/master-data/product-category';
import { Supplier } from '@/types/api/master-data/supplier';
// Waktu saat ini untuk created_at/updated_at
const now = format(new Date(), 'yyyy-MM-dd HH:mm:ss');
const today = format(new Date(), 'yyyy-MM-dd');
const tomorrow = format(
new Date().setDate(new Date().getDate() + 1),
'yyyy-MM-dd'
);
// ======================
// 👤 Created User & Helper Data
// ======================
export const createdUser: CreatedUser = {
id: 1,
id_user: 1,
email: 'admin@example.com',
name: 'Admin Utama',
};
const dummyProductBase: Product = {
id: 101,
name: 'Pakan Ayam Premium',
brand: 'Brand Hebat',
sku: 'PAK-001',
product_price: 15000,
selling_price: 18000,
tax: 0.1,
expiry_period: 365,
uom: { id: 1, name: 'Sak' } as Uom,
product_category: { id: 1, name: 'Pakan' } as ProductCategory,
suppliers: [{ id: 1, name: 'Supplier A' } as Supplier],
flags: ['PAKAN'],
created_user: createdUser,
created_at: now,
updated_at: now,
};
// ======================
// 📍 Area Dummy
// ======================
export const dummyAreas: Area[] = [
{
id: 1,
name: 'Bandung Barat',
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 2,
name: 'Cimahi Utara',
created_user: createdUser,
created_at: now,
updated_at: now,
},
];
// ======================
// 🏢 Location Dummy
// ======================
export const dummyLocations: Location[] = [
{
id: 1,
name: 'Gudang A',
address: 'Jl. Sukajadi No. 12',
area: dummyAreas[0],
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 2,
name: 'Gudang B',
address: 'Jl. Setiabudi No. 45',
area: dummyAreas[1],
created_user: createdUser,
created_at: now,
updated_at: now,
},
];
// ======================
// 🐔 Kandang Dummy
// ======================
export const dummyKandangs: Kandang[] = [
{
id: 1,
name: 'Kandang Ayam Layer 1',
status: 'AKTIF',
capacity: 500,
location: dummyLocations[0],
pic: createdUser,
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 2,
name: 'Kandang Ayam Broiler 2',
status: 'NONAKTIF',
capacity: 300,
location: dummyLocations[1],
pic: createdUser,
created_user: createdUser,
created_at: now,
updated_at: now,
},
];
// ======================
// 🏭 Warehouse Dummy
// ======================
export const dummyWarehouses: Warehouse[] = [
{
id: 1,
type: 'AREA',
name: 'Gudang Wilayah Bandung Barat',
area: dummyAreas[0],
created_user: createdUser,
created_at: now,
updated_at: now,
} as Warehouse,
{
id: 2,
type: 'LOKASI',
name: 'Gudang Produksi Sukajadi',
area: dummyAreas[0],
location: { ...dummyLocations[0], area: dummyAreas[0] },
created_user: createdUser,
created_at: now,
updated_at: now,
} as Warehouse,
{
id: 3,
type: 'KANDANG',
name: 'Gudang Kandang Layer 1',
area: dummyAreas[0],
location: { ...dummyLocations[0], area: dummyAreas[0] },
kandang: {
...dummyKandangs[0],
location: dummyLocations[0],
pic: createdUser,
},
created_user: createdUser,
created_at: now,
updated_at: now,
} as Warehouse,
];
// ======================
// 📦 Product Warehouse Dummy
// ======================
export const dummyProductWarehouses: ProductWarehouse[] = [
{
id: 1,
product_id: 101,
warehouse_id: 1,
quantity: 1000,
product: dummyProductBase,
warehouse: dummyWarehouses[0],
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 2,
product_id: 102,
warehouse_id: 2,
quantity: 500,
product: {
...dummyProductBase,
id: 102,
name: 'Vitamin Ayam Super',
sku: 'VIT-002',
flags: ['VITAMIN'],
selling_price: 25000,
},
warehouse: dummyWarehouses[1],
created_user: createdUser,
created_at: now,
updated_at: now,
},
];
// ======================
// 💼 Marketing Dummy
// ======================
// Helper untuk Sales Order (SO) Item
const soItem1: BaseSalesOrder = {
vehicle_number: 'B 1234 ABC',
id: 101,
marketing_id: 1,
product_warehouse_id: 1,
qty: 100,
unit_price: 18000, // Harga jual
avg_weight: 1.0,
total_weight: 100 * 1.0,
total_price: 100 * 18000,
product_warehouse: dummyProductWarehouses[0] as ProductWarehouse,
};
const soItem2: BaseSalesOrder = {
vehicle_number: 'D 5678 EFG',
id: 102,
marketing_id: 2,
product_warehouse_id: 2,
qty: 50,
unit_price: 25000,
avg_weight: 0.5,
total_weight: 50 * 0.5,
total_price: 50 * 25000,
product_warehouse: dummyProductWarehouses[1] as ProductWarehouse,
};
// Helper untuk Delivery Item (DO) Detail
const doDelivery1: BaseDelivery[] = [
{
product_warehouse: dummyProductWarehouses[0] as ProductWarehouse,
qty: soItem1.qty,
unit_price: soItem1.unit_price,
total_weight: soItem1.total_weight,
avg_weight: soItem1.avg_weight,
total_price: soItem1.total_price,
vehicle_number: 'B 1234 ABC',
},
];
const doDelivery2: BaseDelivery[] = [
{
product_warehouse: dummyProductWarehouses[1] as ProductWarehouse,
qty: soItem2.qty,
unit_price: soItem2.unit_price,
total_weight: soItem2.total_weight,
avg_weight: soItem2.avg_weight,
total_price: soItem2.total_price,
vehicle_number: 'D 5678 EFG',
},
];
// Helper untuk Delivery Order (DO) Header
const deliveryOrder1: BaseDeliveryOrder[] = [
{
id: 1,
marketing_id: 3,
do_number: 'DO-003-2025',
delivery_date: tomorrow,
warehouse: dummyWarehouses[0],
deliveries: doDelivery1,
},
];
export const dummyMarketings: Marketing[] = [
// 1. Pengajuan Order (Langkah Pertama/Awal)
{
id: 1,
status: 'DRAFT',
// name: 'SO-001-2025', // `name` is not part of BaseMarketing
so_number: 'SO-001-2025',
so_date: today,
customer: {
id: 1,
name: 'PT Maju Jaya',
pic_id: 1,
pic: createdUser,
type: 'Distributor',
address: 'Jl. Merdeka No. 1',
phone: '081212121212',
email: 'contact@majujaya.com',
account_number: '1234567890',
created_user: createdUser,
created_at: now,
updated_at: now,
} as Customer,
sales_person: createdUser,
notes: 'Pengajuan Order Awal, menunggu persetujuan harga.',
latest_approval: {
step_number: 1,
step_name: 'Pengajuan Order',
action: 'CREATED',
action_by: createdUser,
action_at: now,
} as BaseApproval,
sales_order: [soItem1],
delivery_order: [],
created_user: createdUser,
created_at: now,
updated_at: now,
} as Marketing,
// 2. Sales Order (Disetujui dan Siap DO)
{
id: 2,
status: 'APPROVED',
// name: 'SO-002-2025', // `name` is not part of BaseMarketing
so_number: 'SO-002-2025',
so_date: today,
customer: {
id: 2,
name: 'CV Sumber Sehat',
pic_id: 2,
pic: createdUser,
type: 'Retail',
address: 'Jl. Cihampelas No. 5',
phone: '082222222222',
email: 'info@sumbersehat.com',
account_number: '9876543210',
created_user: createdUser,
created_at: now,
updated_at: now,
} as Customer,
sales_person: createdUser,
notes: 'Sales Order telah disetujui oleh Supervisor.',
latest_approval: {
id: 2,
step_number: 2,
step_name: 'Sales Order',
action: 'APPROVED',
action_by: createdUser,
action_at: now,
} as BaseApproval,
sales_order: [soItem2],
delivery_order: [], // Belum ada pengiriman (DO) yang dibuat
created_user: createdUser,
created_at: now,
updated_at: now,
} as Marketing,
// 3. Delivery Order (Proses Pengiriman telah dibuat)
{
id: 3,
status: 'DELIVERED', // Asumsi status DELIVERED berarti DO sudah selesai/terbuat
// name: 'SO-003-2025', // `name` is not part of BaseMarketing
so_number: 'SO-003-2025',
so_date: today,
customer: {
id: 3,
name: 'UD Ternak Sejahtera',
pic_id: 3,
pic: createdUser,
type: 'Reseller',
address: 'Jl. Pasteur No. 88',
phone: '083333333333',
email: 'halo@ternaksejahtera.com',
account_number: '1122334455',
created_user: createdUser,
created_at: now,
updated_at: now,
} as Customer,
sales_person: createdUser,
notes: 'Pengiriman barang telah berhasil dilakukan.',
latest_approval: {
id: 3,
step_number: 3,
step_name: 'Delivery Order',
action: 'COMPLETED',
action_by: createdUser,
action_at: now,
} as BaseApproval,
sales_order: [soItem1, soItem2],
delivery_order: deliveryOrder1, // DO sudah terbuat
created_user: createdUser,
created_at: now,
updated_at: now,
} as Marketing,
];
-621
View File
@@ -1,621 +0,0 @@
/**
* Dummy Data untuk Report Expense API
*
* File ini berisi dummy data untuk testing Report Expense API sebelum backend siap.
*
* Struktur data mengikuti tipe yang didefinisikan di @/types/api/report/report-expense.d.ts
*
* @example
* // Menggunakan getAllFetcher dengan SWR:
* import useSWR from 'swr';
* import { ReportExpenseApi } from '@/services/api/report';
*
* const { data, error, isLoading } = useSWR(
* ReportExpenseApi.basePath,
* ReportExpenseApi.getAllFetcher
* );
*
* if (data?.status === 'success') {
* console.log(data.data); // Array of ReportExpense objects
* }
*
* @see {@link /home/sweetpotet/Documents/projects/lti-web-client/src/types/api/report/report-expense.d.ts}
*/
import { format } from 'date-fns';
import {
Pengajuan,
Realisasi,
ReportExpense,
} from '@/types/api/report/report-expense';
import { BaseApiResponse, CreatedUser } from '@/types/api/api-general';
import { Supplier } from '@/types/api/master-data/supplier';
import { Location } from '@/types/api/master-data/location';
import { Nonstock } from '@/types/api/master-data/nonstock';
import { Kandang } from '@/types/api/master-data/kandang';
// Waktu saat ini untuk created_at/updated_at
const now = format(new Date(), 'yyyy-MM-dd HH:mm:ss');
const today = format(new Date(), 'yyyy-MM-dd');
const yesterday = format(
new Date(new Date().setDate(new Date().getDate() - 1)),
'yyyy-MM-dd'
);
const lastWeek = format(
new Date(new Date().setDate(new Date().getDate() - 7)),
'yyyy-MM-dd'
);
const lastMonth = format(
new Date(new Date().setMonth(new Date().getMonth() - 1)),
'yyyy-MM-dd'
);
// ======================
// 👤 Created User
// ======================
const createdUser: CreatedUser = {
id: 1,
id_user: 1,
email: 'admin@example.com',
name: 'Admin Utama',
};
// ======================
// 🏢 Supplier Dummy Data
// ======================
const dummySuppliers: Supplier[] = [
{
id: 1,
name: 'PT. Mitra Pakan Sejahtera',
alias: 'MPS',
pic: 'Budi Santoso',
type: 'Pakan',
category: 'Supplier Utama',
hatchery: '-',
phone: '022-1234567',
email: 'info@mitrapakan.com',
address: 'Jl. Raya Industri No. 123, Bandung',
npwp: '01.234.567.8-901.000',
account_number: '1234567890',
due_date: 30,
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 2,
name: 'CV. Sumber Ternak Jaya',
alias: 'STJ',
pic: 'Siti Rahayu',
type: 'DOC',
category: 'Supplier Utama',
hatchery: 'Hatchery Jaya',
phone: '021-9876543',
email: 'contact@sumberternak.com',
address: 'Jl. Peternakan No. 45, Jakarta',
npwp: '02.345.678.9-012.000',
account_number: '0987654321',
due_date: 45,
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 3,
name: 'PT. Agro Veteriner Indonesia',
alias: 'AVI',
pic: 'Dr. Ahmad Fauzi',
type: 'OVK',
category: 'Supplier Utama',
hatchery: '-',
phone: '031-5555666',
email: 'sales@agroveteriner.co.id',
address: 'Jl. Kesehatan Hewan No. 78, Surabaya',
npwp: '03.456.789.0-123.000',
account_number: '5678901234',
due_date: 60,
created_user: createdUser,
created_at: now,
updated_at: now,
},
];
// ======================
// 📍 Location Dummy Data
// ======================
const dummyLocations: Location[] = [
{
id: 1,
name: 'Farm Sukajadi',
address: 'Jl. Sukajadi No. 100, Bandung',
area: {
id: 1,
name: 'Bandung Barat',
},
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 2,
name: 'Farm Cihampelas',
address: 'Jl. Cihampelas No. 200, Bandung',
area: {
id: 1,
name: 'Bandung Barat',
},
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 3,
name: 'Farm Pasteur',
address: 'Jl. Pasteur No. 300, Bandung',
area: {
id: 2,
name: 'Bandung Timur',
},
created_user: createdUser,
created_at: now,
updated_at: now,
},
];
// ======================
// 📦 Nonstock Dummy Data
// ======================
const dummyNonstocks: Nonstock[] = [
{
id: 1,
name: 'Listrik',
uom_id: 1,
uom: { id: 1, name: 'kWh' },
suppliers: [],
flags: [],
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 2,
name: 'Air',
uom_id: 2,
uom: { id: 2, name: 'm³' },
suppliers: [],
flags: [],
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 3,
name: 'Bahan Bakar',
uom_id: 3,
uom: { id: 3, name: 'Liter' },
suppliers: [],
flags: [],
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 4,
name: 'Pemeliharaan Kandang',
uom_id: 4,
uom: { id: 4, name: 'Unit' },
suppliers: [],
flags: [],
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 5,
name: 'Transportasi',
uom_id: 5,
uom: { id: 5, name: 'Trip' },
suppliers: [],
flags: [],
created_user: createdUser,
created_at: now,
updated_at: now,
},
];
// ======================
// 🏠 Kandang Dummy Data
// ======================
const dummyKandangs: Kandang[] = [
{
id: 1,
name: 'Kandang A1',
status: 'Aktif',
location: dummyLocations[0],
capacity: 5000,
pic: {
id_user: 1,
id: 1,
name: 'Budi Kandang',
email: 'budi@example.com',
},
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 2,
name: 'Kandang B1',
status: 'Aktif',
location: dummyLocations[1],
capacity: 4000,
pic: {
id_user: 2,
id: 2,
name: 'Siti Kandang',
email: 'siti@example.com',
},
created_user: createdUser,
created_at: now,
updated_at: now,
},
{
id: 3,
name: 'Kandang C1',
status: 'Aktif',
location: dummyLocations[2],
capacity: 6000,
pic: {
id_user: 3,
id: 3,
name: 'Ahmad Kandang',
email: 'ahmad@example.com',
},
created_user: createdUser,
created_at: now,
updated_at: now,
},
];
// ======================
// 📋 Pengajuan Dummy Data
// ======================
const dummyPengajuans: Pengajuan[] = [
{
id: 1,
expense_id: 1,
project_flock_kandang_id: 1,
kandang_id: 1,
nonstock_id: 1,
qty: 1000,
price: 1500,
notes: 'Pengajuan biaya listrik bulan ini',
nonstock: dummyNonstocks[0],
created_at: now,
},
{
id: 2,
expense_id: 2,
project_flock_kandang_id: 2,
kandang_id: 2,
nonstock_id: 2,
qty: 500,
price: 5000,
notes: 'Pengajuan biaya air bulan ini',
nonstock: dummyNonstocks[1],
created_at: now,
},
{
id: 3,
expense_id: 3,
project_flock_kandang_id: 3,
kandang_id: 3,
nonstock_id: 3,
qty: 200,
price: 15000,
notes: 'Pengajuan biaya bahan bakar',
nonstock: dummyNonstocks[2],
created_at: now,
},
{
id: 4,
expense_id: 4,
project_flock_kandang_id: 1,
kandang_id: 1,
nonstock_id: 4,
qty: 1,
price: 5000000,
notes: 'Pengajuan biaya pemeliharaan kandang',
nonstock: dummyNonstocks[3],
created_at: now,
},
{
id: 5,
expense_id: 5,
project_flock_kandang_id: 2,
kandang_id: 2,
nonstock_id: 5,
qty: 10,
price: 500000,
notes: 'Pengajuan biaya transportasi',
nonstock: dummyNonstocks[4],
created_at: now,
},
];
// ======================
// 💰 Realisasi Dummy Data
// ======================
const dummyRealisasis: Realisasi[] = [
{
id: 1,
expense_nonstock_id: 1,
qty: 950,
price: 1500,
notes: 'Realisasi biaya listrik aktual',
nonstock: dummyNonstocks[0],
created_at: now,
},
{
id: 2,
expense_nonstock_id: 2,
qty: 480,
price: 5000,
notes: 'Realisasi biaya air aktual',
nonstock: dummyNonstocks[1],
created_at: now,
},
{
id: 3,
expense_nonstock_id: 3,
qty: 195,
price: 15000,
notes: 'Realisasi biaya bahan bakar aktual',
nonstock: dummyNonstocks[2],
created_at: now,
},
{
id: 4,
expense_nonstock_id: 4,
qty: 1,
price: 4800000,
notes: 'Realisasi biaya pemeliharaan kandang',
nonstock: dummyNonstocks[3],
created_at: now,
},
{
id: 5,
expense_nonstock_id: 5,
qty: 9,
price: 500000,
notes: 'Realisasi biaya transportasi',
nonstock: dummyNonstocks[4],
created_at: now,
},
];
// ======================
// 📊 Report Expense Dummy Data
// ======================
export const dummyReportExpenses: ReportExpense[] = [
{
id: 1,
reference_number: 'EXP-2025-001',
po_number: 'PO-2025-001',
category: 'Utilitas',
supplier: dummySuppliers[0],
realization_date: today,
transaction_date: yesterday,
pengajuan: dummyPengajuans[0],
realisasi: dummyRealisasis[0],
kandang: dummyKandangs[0],
created_at: now,
updated_at: now,
created_user: createdUser,
latest_approval: {
id: 1,
step_number: 1,
step_name: 'Manager Approval',
action: 'PENDING',
notes: '',
action_by: createdUser,
action_at: now,
},
},
{
id: 2,
reference_number: 'EXP-2025-002',
po_number: 'PO-2025-002',
category: 'Utilitas',
supplier: dummySuppliers[0],
realization_date: today,
transaction_date: yesterday,
pengajuan: dummyPengajuans[1],
realisasi: dummyRealisasis[1],
kandang: dummyKandangs[1],
created_at: now,
updated_at: now,
created_user: createdUser,
latest_approval: {
id: 2,
step_number: 2,
step_name: 'Finance Approval',
action: 'APPROVED',
notes: 'Disetujui oleh finance',
action_by: createdUser,
action_at: now,
},
},
{
id: 3,
reference_number: 'EXP-2025-003',
po_number: 'PO-2025-003',
category: 'Operasional',
supplier: dummySuppliers[1],
realization_date: lastWeek,
transaction_date: lastWeek,
pengajuan: dummyPengajuans[2],
realisasi: dummyRealisasis[2],
kandang: dummyKandangs[2],
created_at: lastWeek,
updated_at: lastWeek,
created_user: createdUser,
latest_approval: {
id: 3,
step_number: 3,
step_name: 'Director Approval',
action: 'APPROVED',
notes: 'Disetujui oleh direktur',
action_by: createdUser,
action_at: lastWeek,
},
},
{
id: 4,
reference_number: 'EXP-2025-004',
po_number: 'PO-2025-004',
category: 'Maintenance',
supplier: dummySuppliers[2],
realization_date: today,
transaction_date: yesterday,
pengajuan: dummyPengajuans[3],
realisasi: dummyRealisasis[3],
kandang: dummyKandangs[0],
created_at: now,
updated_at: now,
created_user: createdUser,
latest_approval: {
id: 4,
step_number: 1,
step_name: 'Manager Approval',
action: 'REJECTED',
notes: 'Biaya terlalu tinggi, perlu revisi',
action_by: createdUser,
action_at: now,
},
},
{
id: 5,
reference_number: 'EXP-2025-005',
po_number: 'PO-2025-005',
category: 'Operasional',
supplier: dummySuppliers[1],
realization_date: yesterday,
transaction_date: lastWeek,
pengajuan: dummyPengajuans[4],
realisasi: dummyRealisasis[4],
kandang: dummyKandangs[1],
created_at: lastWeek,
updated_at: yesterday,
created_user: createdUser,
latest_approval: {
id: 5,
step_number: 2,
step_name: 'Finance Approval',
action: 'PENDING',
notes: '',
action_by: createdUser,
action_at: yesterday,
},
},
{
id: 6,
reference_number: 'EXP-2025-006',
po_number: 'PO-2025-006',
category: 'Utilitas',
supplier: dummySuppliers[0],
realization_date: lastMonth,
transaction_date: lastMonth,
pengajuan: {
id: 6,
expense_id: 6,
project_flock_kandang_id: 3,
kandang_id: 3,
nonstock_id: 1,
qty: 1200,
price: 1500,
notes: 'Pengajuan biaya listrik bulan lalu',
nonstock: dummyNonstocks[0],
created_at: lastMonth,
},
realisasi: {
id: 6,
expense_nonstock_id: 6,
qty: 1150,
price: 1500,
notes: 'Realisasi biaya listrik bulan lalu',
nonstock: dummyNonstocks[0],
created_at: lastMonth,
},
kandang: dummyKandangs[2],
created_at: lastMonth,
updated_at: lastMonth,
created_user: createdUser,
latest_approval: {
id: 6,
step_number: 3,
step_name: 'Director Approval',
action: 'APPROVED',
notes: 'Selesai diproses',
action_by: createdUser,
action_at: lastMonth,
},
},
];
// ======================
// 🔧 Fetcher Functions
// ======================
/**
* Dummy fetcher untuk mendapatkan semua data report expense
* @returns Promise dengan BaseApiResponse berisi array ReportExpense
*/
export async function dummyGetAllFetcher(): Promise<
BaseApiResponse<ReportExpense[]>
> {
// Simulasi delay network
await new Promise((resolve) => setTimeout(resolve, 500));
return {
code: 200,
status: 'success',
message: 'Data report expense berhasil diambil',
data: dummyReportExpenses,
meta: {
page: 1,
limit: 10,
total_results: dummyReportExpenses.length,
total_pages: 1,
},
};
}
/**
* Dummy fetcher untuk mendapatkan single data report expense berdasarkan ID
* @param id - ID dari report expense yang ingin diambil
* @returns Promise dengan BaseApiResponse berisi single ReportExpense
*/
export async function dummyGetSingle(
id: number
): Promise<BaseApiResponse<ReportExpense>> {
// Simulasi delay network
await new Promise((resolve) => setTimeout(resolve, 300));
const reportExpense = dummyReportExpenses.find((item) => item.id === id);
if (!reportExpense) {
return {
code: 404,
status: 'error',
message: `Report expense dengan ID ${id} tidak ditemukan`,
};
}
return {
code: 200,
status: 'success',
message: 'Data report expense berhasil diambil',
data: reportExpense,
};
}
+4 -96
View File
@@ -11,56 +11,13 @@ import {
ClosingSapronakCalculation, ClosingSapronakCalculation,
} from '@/types/api/closing'; } from '@/types/api/closing';
import { BaseApiResponse } from '@/types/api/api-general'; import { BaseApiResponse } from '@/types/api/api-general';
import {
dummyGetAllFetcher,
dummyGetSingle,
dummyGetAllIncomingSapronakFetcher,
dummyGetAllOutgoingSapronakFetcher,
dummyGetGeneralInfo,
dummyGetPerhitunganSapronak,
dummyGetOverhead,
} from '@/dummy/closing.dummy';
import { httpClient, httpClientFetcher } from '@/services/http/client'; import { httpClient, httpClientFetcher } from '@/services/http/client';
import { ClosingSales } from '@/types/api/closing'; import { ClosingSales } from '@/types/api/closing';
import { dummyGetOneClosingFinance } from '@/dummy/json/closing-finance.dummy';
export class ClosingApiService extends BaseApiService<Closing, null, null> { export class ClosingApiService extends BaseApiService<Closing, null, null> {
constructor(basePath: string) { constructor(basePath: string) {
super(basePath); super(basePath);
} }
async getAllFetcher(endpoint: string): Promise<BaseApiResponse<Closing[]>> {
// TODO: Remove this block when backend is ready
// return await dummyGetAllFetcher();
// Uncomment this when backend is ready
return await httpClientFetcher<BaseApiResponse<Closing[]>>(endpoint);
}
async getSingle(id: number): Promise<BaseApiResponse<Closing> | undefined> {
// TODO: Remove this block when backend is ready
// try {
// return await dummyGetSingle(id);
// } catch (error) {
// if (axios.isAxiosError<BaseApiResponse<Closing>>(error)) {
// return error.response?.data;
// }
// return undefined;
// }
// Uncomment this when backend is ready
try {
const getSinglePath = `${this.basePath}/${id}`;
const getSingleRes =
await httpClient<BaseApiResponse<Closing>>(getSinglePath);
return getSingleRes;
} catch (error) {
if (axios.isAxiosError<BaseApiResponse<Closing>>(error)) {
}
return undefined;
}
}
async getPenjualan( async getPenjualan(
id: number id: number
): Promise<BaseApiResponse<ClosingSales> | undefined> { ): Promise<BaseApiResponse<ClosingSales> | undefined> {
@@ -81,10 +38,6 @@ export class ClosingApiService extends BaseApiService<Closing, null, null> {
async getAllIncomingSapronakFetcher( async getAllIncomingSapronakFetcher(
endpoint: string endpoint: string
): Promise<BaseApiResponse<ClosingIncomingSapronak[]>> { ): Promise<BaseApiResponse<ClosingIncomingSapronak[]>> {
// TODO: Remove this block when backend is ready
// return await dummyGetAllIncomingSapronakFetcher();
// Uncomment this when backend is ready
return await httpClientFetcher<BaseApiResponse<ClosingIncomingSapronak[]>>( return await httpClientFetcher<BaseApiResponse<ClosingIncomingSapronak[]>>(
endpoint endpoint
); );
@@ -93,31 +46,14 @@ export class ClosingApiService extends BaseApiService<Closing, null, null> {
async getAllOutgoingSapronakFetcher( async getAllOutgoingSapronakFetcher(
endpoint: string endpoint: string
): Promise<BaseApiResponse<ClosingOutgoingSapronak[]>> { ): Promise<BaseApiResponse<ClosingOutgoingSapronak[]>> {
// TODO: Remove this block when backend is ready return await httpClientFetcher<BaseApiResponse<ClosingOutgoingSapronak[]>>(
return await dummyGetAllOutgoingSapronakFetcher(); endpoint
);
// Uncomment this when backend is ready
// return await httpClientFetcher<BaseApiResponse<ClosingOutgoingSapronak[]>>(
// endpoint
// );
} }
async getGeneralInfo( async getGeneralInfo(
id: number id: number
): Promise<BaseApiResponse<ClosingGeneralInformation> | undefined> { ): Promise<BaseApiResponse<ClosingGeneralInformation> | undefined> {
// TODO: Remove this block when backend is ready
// try {
// return await dummyGetGeneralInfo(id);
// } catch (error) {
// if (
// axios.isAxiosError<BaseApiResponse<ClosingGeneralInformation>>(error)
// ) {
// return error.response?.data;
// }
// return undefined;
// }
// Uncomment this when backend is ready
try { try {
const getGeneralInfoPath = `${this.basePath}/${id}`; const getGeneralInfoPath = `${this.basePath}/${id}`;
const getGeneralInfoRes = const getGeneralInfoRes =
@@ -138,19 +74,6 @@ export class ClosingApiService extends BaseApiService<Closing, null, null> {
async getPerhitunganSapronak( async getPerhitunganSapronak(
id: number id: number
): Promise<BaseApiResponse<ClosingSapronakCalculation> | undefined> { ): Promise<BaseApiResponse<ClosingSapronakCalculation> | undefined> {
// TODO: Remove this block when backend is ready
// try {
// return await dummyGetPerhitunganSapronak(id);
// } catch (error) {
// if (
// axios.isAxiosError<BaseApiResponse<ClosingSapronakCalculation>>(error)
// ) {
// return error.response?.data;
// }
// return undefined;
// }
// Uncomment this when backend is ready
try { try {
const path = `${this.basePath}/${id}/perhitungan_sapronak`; const path = `${this.basePath}/${id}/perhitungan_sapronak`;
return await httpClient<BaseApiResponse<ClosingSapronakCalculation>>( return await httpClient<BaseApiResponse<ClosingSapronakCalculation>>(
@@ -172,17 +95,6 @@ export class ClosingApiService extends BaseApiService<Closing, null, null> {
async getOverhead( async getOverhead(
id: number id: number
): Promise<BaseApiResponse<ClosingOverhead> | undefined> { ): Promise<BaseApiResponse<ClosingOverhead> | undefined> {
// TODO: Remove this block when backend is ready
// try {
// return await dummyGetOverhead(id);
// } catch (error) {
// if (axios.isAxiosError<BaseApiResponse<ClosingOverhead>>(error)) {
// return error.response?.data;
// }
// return undefined;
// }
// Uncomment this when backend is ready
try { try {
const path = `${this.basePath}/${id}/overhead`; const path = `${this.basePath}/${id}/overhead`;
return await httpClient<BaseApiResponse<ClosingOverhead>>(path, { return await httpClient<BaseApiResponse<ClosingOverhead>>(path, {
@@ -199,12 +111,8 @@ export class ClosingApiService extends BaseApiService<Closing, null, null> {
async getFinance( async getFinance(
id: number id: number
): Promise<BaseApiResponse<ClosingFinance> | undefined> { ): Promise<BaseApiResponse<ClosingFinance> | undefined> {
// TODO: Remove this block when backend is ready
// return dummyGetOneClosingFinance(id);
// Uncomment this when backend is ready
try { try {
const path = `${this.basePath}/${id}/finance`; const path = `${this.basePath}/${id}/keuangan`;
return await httpClient<BaseApiResponse<ClosingFinance>>(path, { return await httpClient<BaseApiResponse<ClosingFinance>>(path, {
method: 'GET', method: 'GET',
}); });
-37
View File
@@ -1,5 +1,3 @@
import { dummyMarketings } from '@/dummy/marketing.dummy';
import { sleep } from '@/lib/helper';
import { BaseApiService } from '@/services/api/base'; import { BaseApiService } from '@/services/api/base';
import { httpClient } from '@/services/http/client'; import { httpClient } from '@/services/http/client';
import { BaseApiResponse } from '@/types/api/api-general'; import { BaseApiResponse } from '@/types/api/api-general';
@@ -31,41 +29,6 @@ export class SalesOrderService extends BaseApiService<
super(basePath); super(basePath);
} }
// /**
// * Override: Mengambil semua data Marketing dari dummyMarketings
// */
// async getAllFetcher(endpoint: string): Promise<BaseApiResponse<Marketing[]>> {
// // Simulasi delay jaringan
// await sleep(500);
// // Filter data marketing yang valid (jika menggunakan BaseMarketing[])
// const data = dummyMarketings as Marketing[];
// return createDummyResponse<Marketing[]>(data);
// }
// /**
// * Override: Mengambil satu data Marketing berdasarkan ID dari dummyMarketings
// */
// async getSingle(id: number): Promise<BaseApiResponse<Marketing> | undefined> {
// // Simulasi delay jaringan
// await sleep(300);
// const foundData = dummyMarketings.find((m) => m.id == id);
// if (foundData) {
// // Data ditemukan, kembalikan respons sukses
// return createDummyResponse<Marketing>(foundData as Marketing);
// } else {
// // Data tidak ditemukan, simulasi respons error
// return {
// code: 404,
// status: 'error',
// message: 'Marketing data not found (MOCK)',
// };
// }
// }
/** /**
* Approve single marketing data * Approve single marketing data
*/ */