mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
Merge branch 'fix/debt-supplier-and-project-flock' into 'development'
[FIX/FE] Refactor data response debt supplier and fix Floating Action Button Project Flock See merge request mbugroup/lti-web-client!166
This commit is contained in:
@@ -39,8 +39,8 @@ const FloatingActionsButton = ({
|
|||||||
// Jika tidak ada baris yang dipilih, jangan tampilkan FAB
|
// Jika tidak ada baris yang dipilih, jangan tampilkan FAB
|
||||||
const positionStyles =
|
const positionStyles =
|
||||||
selectedRowIds.length > 0
|
selectedRowIds.length > 0
|
||||||
? 'bottom-[10%] opacity-100'
|
? 'bottom-[5%] opacity-100'
|
||||||
: 'bottom-[-10%] opacity-0';
|
: 'bottom-[-5%] opacity-0';
|
||||||
|
|
||||||
// Helper untuk menentukan gaya warna tombol approval
|
// Helper untuk menentukan gaya warna tombol approval
|
||||||
const getApprovalColor = (action: 'APPROVED' | 'REJECTED') => {
|
const getApprovalColor = (action: 'APPROVED' | 'REJECTED') => {
|
||||||
@@ -60,7 +60,7 @@ const FloatingActionsButton = ({
|
|||||||
// Container utama FAB
|
// Container utama FAB
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
`absolute ${positionStyles} inset-x-1/2 -translate-x-1/2 z-50`,
|
`fixed ${positionStyles} inset-x-1/2 -translate-x-1/2 z-50`,
|
||||||
'mx-auto w-full max-w-sm sm:mx-0 bg-base-300 p-4 rounded-xl shadow-md transition-all duration-300 transform',
|
'mx-auto w-full max-w-sm sm:mx-0 bg-base-300 p-4 rounded-xl shadow-md transition-all duration-300 transform',
|
||||||
'bg-slate-950 backdrop-blur-md'
|
'bg-slate-950 backdrop-blur-md'
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { useTableFilter } from '@/services/hooks/useTableFilter';
|
|||||||
import { Kandang } from '@/types/api/master-data/kandang';
|
import { Kandang } from '@/types/api/master-data/kandang';
|
||||||
import { ProjectFlock } from '@/types/api/production/project-flock';
|
import { ProjectFlock } from '@/types/api/production/project-flock';
|
||||||
import { Icon } from '@iconify/react';
|
import { Icon } from '@iconify/react';
|
||||||
import { CellContext, SortingState } from '@tanstack/react-table';
|
import { CellContext, ColumnDef, SortingState } from '@tanstack/react-table';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { ChangeEventHandler, useEffect, useMemo, useState } from 'react';
|
import { ChangeEventHandler, useEffect, useMemo, useState } from 'react';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
@@ -27,84 +27,6 @@ import useSWR from 'swr';
|
|||||||
|
|
||||||
import RequirePermission from '@/components/helper/RequirePermission';
|
import RequirePermission from '@/components/helper/RequirePermission';
|
||||||
|
|
||||||
const RowOptionsMenu = ({
|
|
||||||
type = 'dropdown',
|
|
||||||
props,
|
|
||||||
deleteClickHandler,
|
|
||||||
}: {
|
|
||||||
type: 'dropdown' | 'collapse';
|
|
||||||
props: CellContext<ProjectFlock, unknown>;
|
|
||||||
deleteClickHandler: () => void;
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
tabIndex={type == 'dropdown' ? 0 : undefined}
|
|
||||||
className={cn(
|
|
||||||
{
|
|
||||||
'dropdown-content': type === 'dropdown',
|
|
||||||
'mt-2': type === 'collapse',
|
|
||||||
},
|
|
||||||
'p-2.5 mr-2 bg-base-100 rounded-box z-10 border border-black/10 shadow'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className='flex flex-col gap-1'>
|
|
||||||
<RequirePermission permissions='lti.production.project_flocks.detail'>
|
|
||||||
<Button
|
|
||||||
href={`/production/project-flock/detail?projectFlockId=${props.row.original.id}`}
|
|
||||||
variant='ghost'
|
|
||||||
color='primary'
|
|
||||||
className='justify-start text-sm'
|
|
||||||
>
|
|
||||||
<Icon icon='mdi:eye-outline' width={16} height={16} />
|
|
||||||
Detail
|
|
||||||
</Button>
|
|
||||||
</RequirePermission>
|
|
||||||
{props.row.original.approval.step_name === 'Aktif' && (
|
|
||||||
<RequirePermission permissions='lti.production.chickins.create'>
|
|
||||||
<Button
|
|
||||||
href={`/production/project-flock/chickin/add?projectFlockId=${props.row.original.id}`}
|
|
||||||
variant='ghost'
|
|
||||||
color='success'
|
|
||||||
className='justify-start text-sm'
|
|
||||||
>
|
|
||||||
<Icon icon='mdi:home-import-outline' width={16} height={16} />
|
|
||||||
Chickin
|
|
||||||
</Button>
|
|
||||||
</RequirePermission>
|
|
||||||
)}
|
|
||||||
{props.row.original.approval.step_name === 'Pengajuan' && (
|
|
||||||
<RequirePermission permissions='lti.production.project_flocks.update'>
|
|
||||||
<Button
|
|
||||||
href={`/production/project-flock/detail/edit?projectFlockId=${props.row.original.id}`}
|
|
||||||
variant='ghost'
|
|
||||||
color='warning'
|
|
||||||
className='justify-start text-sm'
|
|
||||||
>
|
|
||||||
<Icon icon='mdi:pencil-outline' width={16} height={16} />
|
|
||||||
Edit
|
|
||||||
</Button>
|
|
||||||
</RequirePermission>
|
|
||||||
)}
|
|
||||||
<RequirePermission permissions='lti.production.project_flocks.delete'>
|
|
||||||
<Button
|
|
||||||
onClick={deleteClickHandler}
|
|
||||||
variant='ghost'
|
|
||||||
color='error'
|
|
||||||
className='text-error hover:text-inherit justify-start text-sm'
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon='material-symbols:delete-outline-rounded'
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
Delete
|
|
||||||
</Button>
|
|
||||||
</RequirePermission>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
||||||
const {
|
const {
|
||||||
state: tableFilterState,
|
state: tableFilterState,
|
||||||
@@ -149,8 +71,6 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
|||||||
);
|
);
|
||||||
const [periodInputValue, setPeriodInputValue] = useState<number | null>(null);
|
const [periodInputValue, setPeriodInputValue] = useState<number | null>(null);
|
||||||
const [sorting, setSorting] = useState<SortingState>([]);
|
const [sorting, setSorting] = useState<SortingState>([]);
|
||||||
const [selectedProjectFlock, setSelectedProjectFlock] =
|
|
||||||
useState<ProjectFlock>();
|
|
||||||
const deleteModal = useModal();
|
const deleteModal = useModal();
|
||||||
const confirmModal = useModal();
|
const confirmModal = useModal();
|
||||||
const [approvalAction, setApprovalAction] = useState<'APPROVED' | 'REJECTED'>(
|
const [approvalAction, setApprovalAction] = useState<'APPROVED' | 'REJECTED'>(
|
||||||
@@ -221,10 +141,6 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
|||||||
: [];
|
: [];
|
||||||
|
|
||||||
// ====== HANDLER ======
|
// ====== HANDLER ======
|
||||||
const pageSizeChangeHandler = (val: OptionType | OptionType[] | null) => {
|
|
||||||
const newVal = val as OptionType;
|
|
||||||
setPageSize(newVal.value as number);
|
|
||||||
};
|
|
||||||
const confirmationModalDeleteClickHandler = async () => {
|
const confirmationModalDeleteClickHandler = async () => {
|
||||||
setIsDeleteLoading(true);
|
setIsDeleteLoading(true);
|
||||||
|
|
||||||
@@ -292,12 +208,146 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
|||||||
const canApprove = useMemo(() => {
|
const canApprove = useMemo(() => {
|
||||||
if (!selectedSingleRow || isApproveLoading) return false;
|
if (!selectedSingleRow || isApproveLoading) return false;
|
||||||
|
|
||||||
const isPengajuan = selectedSingleRow.approval.step_number == 1;
|
const isPengajuan = selectedSingleRow.approval?.step_number == 1;
|
||||||
const isNotRejected = selectedSingleRow.approval.action != 'REJECTED';
|
const isNotRejected = selectedSingleRow.approval?.action != 'REJECTED';
|
||||||
|
|
||||||
return isPengajuan && isNotRejected;
|
return isPengajuan && isNotRejected;
|
||||||
}, [selectedSingleRow, isApproveLoading]);
|
}, [selectedSingleRow, isApproveLoading]);
|
||||||
|
|
||||||
|
// ====== COLUMNS ======
|
||||||
|
const columns = useMemo<ColumnDef<ProjectFlock>[]>(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
id: 'select',
|
||||||
|
header: ({ table }) => {
|
||||||
|
const allRows = table.getRowModel().rows;
|
||||||
|
const selectableRows = allRows;
|
||||||
|
|
||||||
|
const allSelected =
|
||||||
|
selectableRows.every((row) => row.getIsSelected()) &&
|
||||||
|
selectableRows.length != 0;
|
||||||
|
|
||||||
|
const someSelected =
|
||||||
|
selectableRows.some((row) => row.getIsSelected()) && !allSelected;
|
||||||
|
|
||||||
|
const toggleSelectableRows = () => {
|
||||||
|
const shouldSelect = !allSelected;
|
||||||
|
selectableRows.forEach((row) => row.toggleSelected(shouldSelect));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='w-full flex flex-row justify-center'>
|
||||||
|
<CheckboxInput
|
||||||
|
name='allRow'
|
||||||
|
checked={allSelected}
|
||||||
|
indeterminate={someSelected}
|
||||||
|
onChange={toggleSelectableRows}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<CheckboxInput
|
||||||
|
name='row'
|
||||||
|
checked={row.getIsSelected()}
|
||||||
|
disabled={!row.getCanSelect()}
|
||||||
|
indeterminate={row.getIsSomeSelected()}
|
||||||
|
onChange={row.getToggleSelectedHandler()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
accessorKey: 'flock_name',
|
||||||
|
header: 'Flock',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'area.name',
|
||||||
|
header: 'Area',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'location.name',
|
||||||
|
header: 'Lokasi',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'fcr.name',
|
||||||
|
header: 'FCR',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'category',
|
||||||
|
header: 'Kategori',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'approval.step_name',
|
||||||
|
header: 'Status',
|
||||||
|
cell: (props) => {
|
||||||
|
const approval = props.row.original.approval;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Badge
|
||||||
|
variant='soft'
|
||||||
|
className={{
|
||||||
|
badge: 'rounded-lg px-2 w-full flex flex-row justify-start',
|
||||||
|
}}
|
||||||
|
color={
|
||||||
|
approval?.step_number == 1
|
||||||
|
? 'neutral'
|
||||||
|
: approval?.step_number == 2
|
||||||
|
? 'success'
|
||||||
|
: 'error'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon='mdi:circle'
|
||||||
|
width={12}
|
||||||
|
height={12}
|
||||||
|
color={
|
||||||
|
approval?.step_number == 1
|
||||||
|
? 'neutral'
|
||||||
|
: approval?.step_number == 2
|
||||||
|
? 'success'
|
||||||
|
: 'error'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{approval?.step_name}
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Kandang',
|
||||||
|
cell: (props) => {
|
||||||
|
const kandang = props.row.original.kandangs;
|
||||||
|
if (kandang) {
|
||||||
|
const kandangNames = kandang.map((k: Kandang) => k.name);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{kandangNames.length > 0
|
||||||
|
? kandangNames.join(', ')
|
||||||
|
: 'Tidak ada'}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'period',
|
||||||
|
header: 'Periode',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'created_at',
|
||||||
|
header: 'Dibuat pada',
|
||||||
|
cell: (props) =>
|
||||||
|
formatDate(props.row.original.created_at, 'MMM DD, YYYY'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className='min-h-screen w-full p-4'>
|
<div className='min-h-screen w-full p-4'>
|
||||||
@@ -320,7 +370,7 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
|||||||
<div className='ms-auto w-full sm:w-auto'>
|
<div className='ms-auto w-full sm:w-auto'>
|
||||||
<DebouncedTextInput
|
<DebouncedTextInput
|
||||||
name='search'
|
name='search'
|
||||||
placeholder='Cari Area'
|
placeholder='Cari Project Flock'
|
||||||
value={tableFilterState.search}
|
value={tableFilterState.search}
|
||||||
onChange={searchChangeHandler}
|
onChange={searchChangeHandler}
|
||||||
className={{
|
className={{
|
||||||
@@ -382,160 +432,18 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
|||||||
type='number'
|
type='number'
|
||||||
label='Periode'
|
label='Periode'
|
||||||
placeholder='Masukan periode'
|
placeholder='Masukan periode'
|
||||||
value={periodInputValue ?? ''}
|
value={periodInputValue?.toString() ?? ''}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setPeriodInputValue(parseInt(e.target.value));
|
setPeriodInputValue(parseInt(e.target.value));
|
||||||
updateFilter('periodFilter', e.target.value);
|
updateFilter('periodFilter', e.target.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<SelectInput
|
|
||||||
label='Baris'
|
|
||||||
options={ROWS_OPTIONS}
|
|
||||||
value={{
|
|
||||||
label: String(tableFilterState.pageSize),
|
|
||||||
value: tableFilterState.pageSize,
|
|
||||||
}}
|
|
||||||
onChange={pageSizeChangeHandler}
|
|
||||||
className={{ wrapper: 'max-w-28' }}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Table<ProjectFlock>
|
<Table<ProjectFlock>
|
||||||
data={isResponseSuccess(projectFlocks) ? projectFlocks?.data : []}
|
data={isResponseSuccess(projectFlocks) ? projectFlocks?.data : []}
|
||||||
columns={[
|
columns={columns}
|
||||||
{
|
|
||||||
id: 'select',
|
|
||||||
header: ({ table }) => {
|
|
||||||
const allRows = table.getRowModel().rows;
|
|
||||||
const selectableRows = allRows;
|
|
||||||
|
|
||||||
const allSelected =
|
|
||||||
selectableRows.every((row) => row.getIsSelected()) &&
|
|
||||||
selectableRows.length != 0;
|
|
||||||
|
|
||||||
const someSelected =
|
|
||||||
selectableRows.some((row) => row.getIsSelected()) &&
|
|
||||||
!allSelected;
|
|
||||||
|
|
||||||
const toggleSelectableRows = () => {
|
|
||||||
const shouldSelect = !allSelected;
|
|
||||||
selectableRows.forEach((row) =>
|
|
||||||
row.toggleSelected(shouldSelect)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='w-full flex flex-row justify-center'>
|
|
||||||
<CheckboxInput
|
|
||||||
name='allRow'
|
|
||||||
checked={allSelected}
|
|
||||||
indeterminate={someSelected}
|
|
||||||
onChange={toggleSelectableRows}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
cell: ({ row }) => {
|
|
||||||
return (
|
|
||||||
<CheckboxInput
|
|
||||||
name='row'
|
|
||||||
checked={row.getIsSelected()}
|
|
||||||
disabled={!row.getCanSelect()}
|
|
||||||
indeterminate={row.getIsSomeSelected()}
|
|
||||||
onChange={row.getToggleSelectedHandler()}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
accessorKey: 'flock_name',
|
|
||||||
header: 'Flock',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'area.name',
|
|
||||||
header: 'Area',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'location.name',
|
|
||||||
header: 'Lokasi',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'fcr.name',
|
|
||||||
header: 'FCR',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'category',
|
|
||||||
header: 'Kategori',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'approval.step_name',
|
|
||||||
header: 'Status',
|
|
||||||
cell: (props) => {
|
|
||||||
const approval = props.row.original.approval;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Badge
|
|
||||||
variant='soft'
|
|
||||||
className={{
|
|
||||||
badge:
|
|
||||||
'rounded-lg px-2 w-full flex flex-row justify-start',
|
|
||||||
}}
|
|
||||||
color={
|
|
||||||
approval.step_number == 1
|
|
||||||
? 'neutral'
|
|
||||||
: approval.step_number == 2
|
|
||||||
? 'success'
|
|
||||||
: 'error'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon='mdi:circle'
|
|
||||||
width={12}
|
|
||||||
height={12}
|
|
||||||
color={
|
|
||||||
approval.step_number == 1
|
|
||||||
? 'neutral'
|
|
||||||
: approval.step_number == 2
|
|
||||||
? 'success'
|
|
||||||
: 'error'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{approval.step_name}
|
|
||||||
</Badge>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
header: 'Kandang',
|
|
||||||
cell: (props) => {
|
|
||||||
const kandang = props.row.original.kandangs;
|
|
||||||
if (kandang) {
|
|
||||||
const kandangNames = kandang.map((k: Kandang) => k.name);
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{kandangNames.length > 0
|
|
||||||
? kandangNames.join(', ')
|
|
||||||
: 'Tidak ada'}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return '-';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'period',
|
|
||||||
header: 'Periode',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'created_at',
|
|
||||||
header: 'Dibuat pada',
|
|
||||||
cell: (props) =>
|
|
||||||
formatDate(props.row.original.created_at, 'MMM DD, YYYY'),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
pageSize={tableFilterState.pageSize}
|
pageSize={tableFilterState.pageSize}
|
||||||
page={
|
page={
|
||||||
isResponseSuccess(projectFlocks) ? projectFlocks?.meta?.page : 0
|
isResponseSuccess(projectFlocks) ? projectFlocks?.meta?.page : 0
|
||||||
@@ -545,7 +453,12 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
|||||||
? projectFlocks?.meta?.total_results
|
? projectFlocks?.meta?.total_results
|
||||||
: 0
|
: 0
|
||||||
}
|
}
|
||||||
onPageChange={setPage}
|
onPageChange={(page) => {
|
||||||
|
setPage(page);
|
||||||
|
}}
|
||||||
|
onPageSizeChange={(pageSize) => {
|
||||||
|
setPageSize(pageSize);
|
||||||
|
}}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
sorting={sorting}
|
sorting={sorting}
|
||||||
setSorting={setSorting}
|
setSorting={setSorting}
|
||||||
@@ -553,9 +466,9 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
|
|||||||
setRowSelection={setRowSelection}
|
setRowSelection={setRowSelection}
|
||||||
className={{
|
className={{
|
||||||
containerClassName: cn({
|
containerClassName: cn({
|
||||||
'mb-20':
|
'mb-40':
|
||||||
isResponseSuccess(projectFlocks) &&
|
isResponseSuccess(projectFlocks) &&
|
||||||
projectFlocks?.data?.length === 0,
|
projectFlocks?.data?.length > 0,
|
||||||
}),
|
}),
|
||||||
tableWrapperClassName: 'overflow-x-auto min-h-full!',
|
tableWrapperClassName: 'overflow-x-auto min-h-full!',
|
||||||
tableClassName: 'font-inter w-full table-auto min-h-full!',
|
tableClassName: 'font-inter w-full table-auto min-h-full!',
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => {
|
|||||||
{/* Title and Supplier Info */}
|
{/* Title and Supplier Info */}
|
||||||
<View style={pdfStyles.titleSection}>
|
<View style={pdfStyles.titleSection}>
|
||||||
<Text style={pdfStyles.mainTitle}>
|
<Text style={pdfStyles.mainTitle}>
|
||||||
Laporan > Hutang Supplier
|
Laporan > Rekapitulasi Hutang ke Supplier
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={pdfStyles.supplierTitle}>
|
<Text style={pdfStyles.supplierTitle}>
|
||||||
{supplierReport.supplier.name}
|
{supplierReport.supplier.name}
|
||||||
@@ -169,19 +169,19 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => {
|
|||||||
<View style={[pdfStyles.tableCellHeader, { flex: 0.5 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 0.5 }]}>
|
||||||
<Text>No</Text>
|
<Text>No</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 1.5 }]}>
|
||||||
<Text>No. PR</Text>
|
<Text>No. PR</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 1.5 }]}>
|
||||||
<Text>No. PO</Text>
|
<Text>No. PO</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
||||||
<Text>Tgl PR</Text>
|
<Text>Tgl Terima</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
||||||
<Text>Tgl PO</Text>
|
<Text>Tgl PO</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 0.8 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 0.6 }]}>
|
||||||
<Text>Aging</Text>
|
<Text>Aging</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
||||||
@@ -194,15 +194,15 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => {
|
|||||||
<Text>Tgl Jatuh Tempo</Text>
|
<Text>Tgl Jatuh Tempo</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
||||||
<Text>Status JT</Text>
|
<Text>Status Jatuh Tempo</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.5 }]}>
|
||||||
<Text>Total Harga</Text>
|
<Text>Total Harga</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.5 }]}>
|
||||||
<Text>Pembayaran</Text>
|
<Text>Pembayaran</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.2 }]}>
|
<View style={[pdfStyles.tableCellHeaderRight, { flex: 1.5 }]}>
|
||||||
<Text>Hutang</Text>
|
<Text>Hutang</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellHeader, { flex: 1 }]}>
|
||||||
@@ -227,23 +227,31 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => {
|
|||||||
<View style={[pdfStyles.tableCellNo, { flex: 0.5 }]}>
|
<View style={[pdfStyles.tableCellNo, { flex: 0.5 }]}>
|
||||||
<Text>{index + 1}</Text>
|
<Text>{index + 1}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1.5 }]}>
|
||||||
<Text>{item.pr_number || '-'}</Text>
|
<Text>{item.pr_number || '-'}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1.5 }]}>
|
||||||
<Text>{item.po_number || '-'}</Text>
|
<Text>{item.po_number || '-'}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellCenter, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellCenter, { flex: 1 }]}>
|
||||||
<Text>
|
<Text>
|
||||||
{item.pr_date ? formatDate(item.pr_date, 'DD MMM YY') : '-'}
|
{item.received_date
|
||||||
|
? item.received_date != '-'
|
||||||
|
? formatDate(item.received_date, 'DD MMM YY')
|
||||||
|
: '-'
|
||||||
|
: '-'}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellCenter, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellCenter, { flex: 1 }]}>
|
||||||
<Text>
|
<Text>
|
||||||
{item.po_date ? formatDate(item.po_date, 'DD MMM YY') : '-'}
|
{item.po_date
|
||||||
|
? item.po_date != '-'
|
||||||
|
? formatDate(item.po_date, 'DD MMM YY')
|
||||||
|
: '-'
|
||||||
|
: '-'}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellCenter, { flex: 0.8 }]}>
|
<View style={[pdfStyles.tableCellCenter, { flex: 0.6 }]}>
|
||||||
<Text>{formatNumber(item.aging)} Hari</Text>
|
<Text>{formatNumber(item.aging)} Hari</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
||||||
@@ -255,20 +263,43 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => {
|
|||||||
<View style={[pdfStyles.tableCellCenter, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellCenter, { flex: 1 }]}>
|
||||||
<Text>
|
<Text>
|
||||||
{item.due_date
|
{item.due_date
|
||||||
? formatDate(item.due_date, 'DD MMM YY')
|
? item.due_date != '-'
|
||||||
|
? formatDate(item.due_date, 'DD MMM YY')
|
||||||
|
: '-'
|
||||||
: '-'}
|
: '-'}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
||||||
<Text>{item.due_status || '-'}</Text>
|
<Text>{item.due_status || '-'}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
<View
|
||||||
|
style={[
|
||||||
|
pdfStyles.tableCellRight,
|
||||||
|
{
|
||||||
|
flex: 1.5,
|
||||||
|
color: item.total_price < 0 ? 'red' : 'black',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
<Text>{formatCurrency(item.total_price)}</Text>
|
<Text>{formatCurrency(item.total_price)}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
<View
|
||||||
|
style={[
|
||||||
|
pdfStyles.tableCellRight,
|
||||||
|
{
|
||||||
|
flex: 1.5,
|
||||||
|
color: item.payment_price < 0 ? 'red' : 'black',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
<Text>{formatCurrency(item.payment_price)}</Text>
|
<Text>{formatCurrency(item.payment_price)}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
<View
|
||||||
|
style={[
|
||||||
|
pdfStyles.tableCellRight,
|
||||||
|
{ flex: 1.5, color: item.debt_price < 0 ? 'red' : 'black' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
<Text>{formatCurrency(item.debt_price)}</Text>
|
<Text>{formatCurrency(item.debt_price)}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
||||||
@@ -286,7 +317,10 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => {
|
|||||||
<View style={[pdfStyles.tableCellNo, { flex: 0.5 }]}>
|
<View style={[pdfStyles.tableCellNo, { flex: 0.5 }]}>
|
||||||
<Text>Total</Text>
|
<Text>Total</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1.5 }]}>
|
||||||
|
<Text></Text>
|
||||||
|
</View>
|
||||||
|
<View style={[pdfStyles.tableCell, { flex: 1.5 }]}>
|
||||||
<Text></Text>
|
<Text></Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
||||||
@@ -295,10 +329,7 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => {
|
|||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
||||||
<Text></Text>
|
<Text></Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCellCenter, { flex: 0.6 }]}>
|
||||||
<Text></Text>
|
|
||||||
</View>
|
|
||||||
<View style={[pdfStyles.tableCellCenter, { flex: 0.8 }]}>
|
|
||||||
<Text>{formatNumber(supplierReport.total.aging)} Hari</Text>
|
<Text>{formatNumber(supplierReport.total.aging)} Hari</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
||||||
@@ -313,17 +344,46 @@ const createPDFDocument = (params: DebtSupplierExportPDFParams) => {
|
|||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
||||||
<Text></Text>
|
<Text></Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
<View
|
||||||
|
style={[
|
||||||
|
pdfStyles.tableCellRight,
|
||||||
|
{
|
||||||
|
flex: 1.5,
|
||||||
|
color:
|
||||||
|
supplierReport.total.total_price < 0 ? 'red' : 'black',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
<Text>
|
<Text>
|
||||||
{formatCurrency(supplierReport.total.total_price)}
|
{formatCurrency(supplierReport.total.total_price)}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
<View
|
||||||
|
style={[
|
||||||
|
pdfStyles.tableCellRight,
|
||||||
|
{
|
||||||
|
flex: 1.5,
|
||||||
|
color:
|
||||||
|
supplierReport.total.payment_price < 0
|
||||||
|
? 'red'
|
||||||
|
: 'black',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
<Text>
|
<Text>
|
||||||
{formatCurrency(supplierReport.total.payment_price)}
|
{formatCurrency(supplierReport.total.payment_price)}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCellRight, { flex: 1.2 }]}>
|
<View
|
||||||
|
style={[
|
||||||
|
pdfStyles.tableCellRight,
|
||||||
|
{
|
||||||
|
flex: 1.5,
|
||||||
|
color:
|
||||||
|
supplierReport.total.debt_price < 0 ? 'red' : 'black',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
<Text>{formatCurrency(supplierReport.total.debt_price)}</Text>
|
<Text>{formatCurrency(supplierReport.total.debt_price)}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
<View style={[pdfStyles.tableCell, { flex: 1 }]}>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import * as XLSX from 'xlsx';
|
import * as XLSX from 'xlsx';
|
||||||
import { formatDate, formatCurrency, formatNumber } from '@/lib/helper';
|
import { formatDate } from '@/lib/helper';
|
||||||
import { DebtSupplier } from '@/types/api/report/debt-supplier';
|
import { DebtSupplier } from '@/types/api/report/debt-supplier';
|
||||||
|
|
||||||
interface DebtSupplierExportExcelParams {
|
interface DebtSupplierExportExcelParams {
|
||||||
@@ -26,22 +26,28 @@ export const generateDebtSupplierExcel = (
|
|||||||
No: index + 1,
|
No: index + 1,
|
||||||
'Nomor PR': item.pr_number || '',
|
'Nomor PR': item.pr_number || '',
|
||||||
'Nomor PO': item.po_number || '',
|
'Nomor PO': item.po_number || '',
|
||||||
'Tanggal PR': item.pr_date
|
'Tanggal Terima': item.received_date
|
||||||
? formatDate(item.pr_date, 'DD MMM YYYY')
|
? item.received_date != '-'
|
||||||
: '',
|
? formatDate(item.received_date, 'MM/DD/YYYY')
|
||||||
|
: '-'
|
||||||
|
: '-',
|
||||||
'Tanggal PO': item.po_date
|
'Tanggal PO': item.po_date
|
||||||
? formatDate(item.po_date, 'DD MMM YYYY')
|
? item.po_date != '-'
|
||||||
: '',
|
? formatDate(item.po_date, 'MM/DD/YYYY')
|
||||||
'Aging (Hari)': formatNumber(item.aging || 0),
|
: '-'
|
||||||
|
: '-',
|
||||||
|
'Aging (Hari)': item.aging || 0,
|
||||||
Area: item.area?.name || '',
|
Area: item.area?.name || '',
|
||||||
Gudang: item.warehouse?.name || '',
|
Gudang: item.warehouse?.name || '',
|
||||||
'Tanggal Jatuh Tempo': item.due_date
|
'Tanggal Jatuh Tempo': item.due_date
|
||||||
? formatDate(item.due_date, 'DD MMM YYYY')
|
? item.due_date != '-'
|
||||||
: '',
|
? formatDate(item.due_date, 'MM/DD/YYYY')
|
||||||
|
: '-'
|
||||||
|
: '-',
|
||||||
'Status Jatuh Tempo': item.due_status || '',
|
'Status Jatuh Tempo': item.due_status || '',
|
||||||
'Total Harga': formatCurrency(item.total_price || 0),
|
'Total Harga': item.total_price || 0,
|
||||||
'Harga Pembayaran': formatCurrency(item.payment_price || 0),
|
'Harga Pembayaran': item.payment_price || 0,
|
||||||
'Harga Hutang': formatCurrency(item.debt_price || 0),
|
'Harga Hutang': item.debt_price || 0,
|
||||||
Status: item.status || '',
|
Status: item.status || '',
|
||||||
'Nomor Perjalanan': item.travel_number || '',
|
'Nomor Perjalanan': item.travel_number || '',
|
||||||
})
|
})
|
||||||
@@ -52,18 +58,16 @@ export const generateDebtSupplierExcel = (
|
|||||||
No: 'Total',
|
No: 'Total',
|
||||||
'Nomor PR': '',
|
'Nomor PR': '',
|
||||||
'Nomor PO': '',
|
'Nomor PO': '',
|
||||||
'Tanggal PR': '',
|
'Tanggal Terima': '',
|
||||||
'Tanggal PO': '',
|
'Tanggal PO': '',
|
||||||
'Aging (Hari)': formatNumber(supplierReport.total.aging || 0),
|
'Aging (Hari)': supplierReport.total.aging || 0,
|
||||||
Area: '',
|
Area: '',
|
||||||
Gudang: '',
|
Gudang: '',
|
||||||
'Tanggal Jatuh Tempo': '',
|
'Tanggal Jatuh Tempo': '',
|
||||||
'Status Jatuh Tempo': '',
|
'Status Jatuh Tempo': '',
|
||||||
'Total Harga': formatCurrency(supplierReport.total.total_price || 0),
|
'Total Harga': supplierReport.total.total_price || 0,
|
||||||
'Harga Pembayaran': formatCurrency(
|
'Harga Pembayaran': supplierReport.total.payment_price || 0,
|
||||||
supplierReport.total.payment_price || 0
|
'Harga Hutang': supplierReport.total.debt_price || 0,
|
||||||
),
|
|
||||||
'Harga Hutang': formatCurrency(supplierReport.total.debt_price || 0),
|
|
||||||
Status: '',
|
Status: '',
|
||||||
'Nomor Perjalanan': '',
|
'Nomor Perjalanan': '',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ const DebtSupplierTab = () => {
|
|||||||
|
|
||||||
const dataTypeOptions = useMemo(
|
const dataTypeOptions = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{ value: 'do_date', label: 'Tanggal Terima' },
|
{ value: 'received_date', label: 'Tanggal Terima' },
|
||||||
{ value: 'po_date', label: 'Tanggal PO' },
|
{ value: 'po_date', label: 'Tanggal PO' },
|
||||||
],
|
],
|
||||||
[]
|
[]
|
||||||
@@ -96,7 +96,7 @@ const DebtSupplierTab = () => {
|
|||||||
filterSupplier.length > 0
|
filterSupplier.length > 0
|
||||||
? filterSupplier.map((v) => String(v.value)).join(',')
|
? filterSupplier.map((v) => String(v.value)).join(',')
|
||||||
: undefined,
|
: undefined,
|
||||||
filter_by: filterDataType?.value || 'do_date',
|
filter_by: filterDataType?.value || 'received_date',
|
||||||
start_date: filterStartDate || undefined,
|
start_date: filterStartDate || undefined,
|
||||||
end_date: filterEndDate || undefined,
|
end_date: filterEndDate || undefined,
|
||||||
page: currentPage,
|
page: currentPage,
|
||||||
@@ -141,7 +141,7 @@ const DebtSupplierTab = () => {
|
|||||||
filterSupplier.length > 0
|
filterSupplier.length > 0
|
||||||
? filterSupplier.map((v) => String(v.value)).join(',')
|
? filterSupplier.map((v) => String(v.value)).join(',')
|
||||||
: undefined,
|
: undefined,
|
||||||
filter_by: 'do_date' as const,
|
filter_by: 'received_date' as const,
|
||||||
start_date: filterStartDate || undefined,
|
start_date: filterStartDate || undefined,
|
||||||
end_date: filterEndDate || undefined,
|
end_date: filterEndDate || undefined,
|
||||||
date_type: filterDataType ? filterDataType.value : undefined,
|
date_type: filterDataType ? filterDataType.value : undefined,
|
||||||
@@ -256,12 +256,16 @@ const DebtSupplierTab = () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'pr_date',
|
id: 'received_date',
|
||||||
header: 'Tanggal PR',
|
header: 'Tanggal Terima',
|
||||||
accessorKey: 'pr_date',
|
accessorKey: 'received_date',
|
||||||
cell: (props) => {
|
cell: (props) => {
|
||||||
const value = props.row.original.pr_date;
|
const value = props.row.original.received_date;
|
||||||
return formatDate(value, 'DD MMM YYYY');
|
return value
|
||||||
|
? value != '-'
|
||||||
|
? formatDate(value, 'DD MMM YYYY')
|
||||||
|
: '-'
|
||||||
|
: '-';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -270,7 +274,11 @@ const DebtSupplierTab = () => {
|
|||||||
accessorKey: 'po_date',
|
accessorKey: 'po_date',
|
||||||
cell: (props) => {
|
cell: (props) => {
|
||||||
const value = props.row.original.po_date;
|
const value = props.row.original.po_date;
|
||||||
return formatDate(value, 'DD MMM YYYY');
|
return value
|
||||||
|
? value != '-'
|
||||||
|
? formatDate(value, 'DD MMM YYYY')
|
||||||
|
: '-'
|
||||||
|
: '-';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -310,7 +318,11 @@ const DebtSupplierTab = () => {
|
|||||||
accessorKey: 'due_date',
|
accessorKey: 'due_date',
|
||||||
cell: (props) => {
|
cell: (props) => {
|
||||||
const value = props.row.original.due_date;
|
const value = props.row.original.due_date;
|
||||||
return formatDate(value, 'DD MMM YYYY');
|
return value
|
||||||
|
? value != '-'
|
||||||
|
? formatDate(value, 'DD MMM YYYY')
|
||||||
|
: '-'
|
||||||
|
: '-';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -328,11 +340,19 @@ const DebtSupplierTab = () => {
|
|||||||
accessorKey: 'total_price',
|
accessorKey: 'total_price',
|
||||||
cell: (props) => {
|
cell: (props) => {
|
||||||
const value = props.row.original.total_price;
|
const value = props.row.original.total_price;
|
||||||
return <div className='text-right'>{formatCurrency(value)}</div>;
|
return (
|
||||||
|
<div className={`text-right ${value < 0 ? 'text-red-500' : ''}`}>
|
||||||
|
{formatCurrency(value)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
footer: () => {
|
footer: () => {
|
||||||
const value = supplier.total.total_price;
|
const value = supplier.total.total_price;
|
||||||
return <div className='text-right'>{formatCurrency(value)}</div>;
|
return (
|
||||||
|
<div className={`text-right ${value < 0 ? 'text-red-500' : ''}`}>
|
||||||
|
{formatCurrency(value)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -341,11 +361,19 @@ const DebtSupplierTab = () => {
|
|||||||
accessorKey: 'payment_price',
|
accessorKey: 'payment_price',
|
||||||
cell: (props) => {
|
cell: (props) => {
|
||||||
const value = props.row.original.payment_price;
|
const value = props.row.original.payment_price;
|
||||||
return <div className='text-right'>{formatCurrency(value)}</div>;
|
return (
|
||||||
|
<div className={`text-right ${value < 0 ? 'text-red-500' : ''}`}>
|
||||||
|
{formatCurrency(value)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
footer: () => {
|
footer: () => {
|
||||||
const value = supplier.total.payment_price;
|
const value = supplier.total.payment_price;
|
||||||
return <div className='text-right'>{formatCurrency(value)}</div>;
|
return (
|
||||||
|
<div className={`text-right ${value < 0 ? 'text-red-500' : ''}`}>
|
||||||
|
{formatCurrency(value)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -392,7 +420,7 @@ const DebtSupplierTab = () => {
|
|||||||
<>
|
<>
|
||||||
<div className='w-full p-0 sm:p-4 flex flex-col gap-4'>
|
<div className='w-full p-0 sm:p-4 flex flex-col gap-4'>
|
||||||
<Card
|
<Card
|
||||||
subtitle='Laporan > Kontrol Hutang Supplier'
|
subtitle='Laporan > Rekapitulasi Hutang ke Supplier'
|
||||||
className={{ wrapper: 'w-full', body: 'p-1!' }}
|
className={{ wrapper: 'w-full', body: 'p-1!' }}
|
||||||
>
|
>
|
||||||
<div className='mb-4 flex justify-end gap-2 [&_button]:px-4'>
|
<div className='mb-4 flex justify-end gap-2 [&_button]:px-4'>
|
||||||
|
|||||||
@@ -0,0 +1,292 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"supplier": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "PT CHAROEN POKPHAND INDONESIA Tbk",
|
||||||
|
"alias": "CPI",
|
||||||
|
"category": "SAPRONAK"
|
||||||
|
},
|
||||||
|
"initial_balance": -9680000,
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"pr_number": "PR-TEST-202501-01",
|
||||||
|
"po_number": "PO-TEST-202501-01",
|
||||||
|
"po_date": "2025-01-15",
|
||||||
|
"received_date": "2025-01-15",
|
||||||
|
"aging": 0,
|
||||||
|
"area": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Bandung"
|
||||||
|
},
|
||||||
|
"warehouse": {
|
||||||
|
"id": 3,
|
||||||
|
"name": "Gudang Kandang Bandung 1",
|
||||||
|
"type": "KANDANG",
|
||||||
|
"area": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Bandung"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"due_date": "2025-02-14",
|
||||||
|
"due_status": "Sudah Jatuh Tempo",
|
||||||
|
"total_price": 5610000,
|
||||||
|
"payment_price": 0,
|
||||||
|
"debt_price": -5610000,
|
||||||
|
"status": "Belum Lunas",
|
||||||
|
"travel_number": "-",
|
||||||
|
"balance": -15290000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pr_number": "PR-TEST-202501-02",
|
||||||
|
"po_number": "PO-TEST-202501-02",
|
||||||
|
"po_date": "2025-01-15",
|
||||||
|
"received_date": "2025-01-15",
|
||||||
|
"aging": 0,
|
||||||
|
"area": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Bandung"
|
||||||
|
},
|
||||||
|
"warehouse": {
|
||||||
|
"id": 4,
|
||||||
|
"name": "Gudang Kandang Bandung 2",
|
||||||
|
"type": "KANDANG",
|
||||||
|
"area": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Bandung"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"due_date": "2025-02-14",
|
||||||
|
"due_status": "Sudah Jatuh Tempo",
|
||||||
|
"total_price": 5035000,
|
||||||
|
"payment_price": 0,
|
||||||
|
"debt_price": -5035000,
|
||||||
|
"status": "Belum Lunas",
|
||||||
|
"travel_number": "-",
|
||||||
|
"balance": -20325000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pr_number": "INIT-90001",
|
||||||
|
"po_number": "SALDO-AWAL",
|
||||||
|
"po_date": "-",
|
||||||
|
"received_date": "2026-01-05",
|
||||||
|
"aging": 0,
|
||||||
|
"due_date": "-",
|
||||||
|
"due_status": "-",
|
||||||
|
"total_price": 0,
|
||||||
|
"payment_price": -10000000,
|
||||||
|
"debt_price": -30325000,
|
||||||
|
"status": "Pembayaran",
|
||||||
|
"travel_number": "-",
|
||||||
|
"balance": -30325000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pr_number": "PR-LTI-9001",
|
||||||
|
"po_number": "PO-LTI-9001",
|
||||||
|
"po_date": "2026-01-10",
|
||||||
|
"received_date": "2026-01-10",
|
||||||
|
"aging": 2,
|
||||||
|
"area": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Bandung"
|
||||||
|
},
|
||||||
|
"warehouse": {
|
||||||
|
"id": 3,
|
||||||
|
"name": "Gudang Kandang Bandung 1",
|
||||||
|
"type": "KANDANG",
|
||||||
|
"area": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Bandung"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"due_date": "2026-02-09",
|
||||||
|
"due_status": "Mendekati Jatuh Tempo",
|
||||||
|
"total_price": 52500000,
|
||||||
|
"payment_price": 2000000,
|
||||||
|
"debt_price": -50500000,
|
||||||
|
"status": "Belum Lunas",
|
||||||
|
"travel_number": "SJ-9001",
|
||||||
|
"balance": -82825000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pr_number": "PAY-OUT-90001",
|
||||||
|
"po_number": "PO-LTI-9001",
|
||||||
|
"po_date": "-",
|
||||||
|
"received_date": "2026-01-10",
|
||||||
|
"aging": 0,
|
||||||
|
"due_date": "-",
|
||||||
|
"due_status": "-",
|
||||||
|
"total_price": 0,
|
||||||
|
"payment_price": 2000000,
|
||||||
|
"debt_price": -80825000,
|
||||||
|
"status": "Pembayaran",
|
||||||
|
"travel_number": "-",
|
||||||
|
"balance": -80825000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pr_number": "PR-LTI-0001",
|
||||||
|
"po_number": "PO-LTI-0001",
|
||||||
|
"po_date": "2026-01-10",
|
||||||
|
"received_date": "2026-01-10",
|
||||||
|
"aging": 2,
|
||||||
|
"area": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Bandung"
|
||||||
|
},
|
||||||
|
"warehouse": {
|
||||||
|
"id": 3,
|
||||||
|
"name": "Gudang Kandang Bandung 1",
|
||||||
|
"type": "KANDANG",
|
||||||
|
"area": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Bandung"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"due_date": "2026-02-09",
|
||||||
|
"due_status": "Mendekati Jatuh Tempo",
|
||||||
|
"total_price": 52500000,
|
||||||
|
"payment_price": 1800000,
|
||||||
|
"debt_price": -50700000,
|
||||||
|
"status": "Belum Lunas",
|
||||||
|
"travel_number": "3232",
|
||||||
|
"balance": -133325000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pr_number": "PAY-OUT-00003",
|
||||||
|
"po_number": "PO-LTI-0001",
|
||||||
|
"po_date": "-",
|
||||||
|
"received_date": "2026-01-10",
|
||||||
|
"aging": 0,
|
||||||
|
"due_date": "-",
|
||||||
|
"due_status": "-",
|
||||||
|
"total_price": 0,
|
||||||
|
"payment_price": 2000000,
|
||||||
|
"debt_price": -131325000,
|
||||||
|
"status": "Pembayaran",
|
||||||
|
"travel_number": "-",
|
||||||
|
"balance": -131325000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pr_number": "PAY-OUT-90002",
|
||||||
|
"po_number": "2323",
|
||||||
|
"po_date": "-",
|
||||||
|
"received_date": "2026-01-11",
|
||||||
|
"aging": 0,
|
||||||
|
"due_date": "-",
|
||||||
|
"due_status": "-",
|
||||||
|
"total_price": 0,
|
||||||
|
"payment_price": 200000,
|
||||||
|
"debt_price": -131125000,
|
||||||
|
"status": "Pembayaran",
|
||||||
|
"travel_number": "-",
|
||||||
|
"balance": -131125000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pr_number": "PAY-OUT-00002",
|
||||||
|
"po_number": "2323",
|
||||||
|
"po_date": "-",
|
||||||
|
"received_date": "2026-01-11",
|
||||||
|
"aging": 0,
|
||||||
|
"due_date": "-",
|
||||||
|
"due_status": "-",
|
||||||
|
"total_price": 0,
|
||||||
|
"payment_price": 200000,
|
||||||
|
"debt_price": -130925000,
|
||||||
|
"status": "Pembayaran",
|
||||||
|
"travel_number": "-",
|
||||||
|
"balance": -130925000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pr_number": "INIT-00001",
|
||||||
|
"po_number": "PO-LTI-0001",
|
||||||
|
"po_date": "-",
|
||||||
|
"received_date": "2026-01-11",
|
||||||
|
"aging": 0,
|
||||||
|
"due_date": "-",
|
||||||
|
"due_status": "-",
|
||||||
|
"total_price": 0,
|
||||||
|
"payment_price": -200000,
|
||||||
|
"debt_price": -131125000,
|
||||||
|
"status": "Pembayaran",
|
||||||
|
"travel_number": "-",
|
||||||
|
"balance": -131125000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pr_number": "PR-LTI-9002",
|
||||||
|
"po_number": "PO-LTI-9002",
|
||||||
|
"po_date": "2026-01-12",
|
||||||
|
"received_date": "2026-01-12",
|
||||||
|
"aging": 0,
|
||||||
|
"area": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Bandung"
|
||||||
|
},
|
||||||
|
"warehouse": {
|
||||||
|
"id": 3,
|
||||||
|
"name": "Gudang Kandang Bandung 1",
|
||||||
|
"type": "KANDANG",
|
||||||
|
"area": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Bandung"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"due_date": "2026-02-11",
|
||||||
|
"due_status": "Mendekati Jatuh Tempo",
|
||||||
|
"total_price": 30000000,
|
||||||
|
"payment_price": 5000000,
|
||||||
|
"debt_price": -25000000,
|
||||||
|
"status": "Belum Lunas",
|
||||||
|
"travel_number": "SJ-9002",
|
||||||
|
"balance": -161125000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pr_number": "PAY-OUT-90003",
|
||||||
|
"po_number": "PO-LTI-9002",
|
||||||
|
"po_date": "-",
|
||||||
|
"received_date": "2026-01-12",
|
||||||
|
"aging": 0,
|
||||||
|
"due_date": "-",
|
||||||
|
"due_status": "-",
|
||||||
|
"total_price": 0,
|
||||||
|
"payment_price": 5000000,
|
||||||
|
"debt_price": -156125000,
|
||||||
|
"status": "Pembayaran",
|
||||||
|
"travel_number": "-",
|
||||||
|
"balance": -156125000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pr_number": "PR-LTI-0002",
|
||||||
|
"po_number": "PO-LTI-0002",
|
||||||
|
"po_date": "2026-01-12",
|
||||||
|
"received_date": "2026-01-12",
|
||||||
|
"aging": 0,
|
||||||
|
"area": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Bandung"
|
||||||
|
},
|
||||||
|
"warehouse": {
|
||||||
|
"id": 4,
|
||||||
|
"name": "Gudang Kandang Bandung 2",
|
||||||
|
"type": "KANDANG",
|
||||||
|
"area": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Bandung"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"due_date": "2026-02-11",
|
||||||
|
"due_status": "Mendekati Jatuh Tempo",
|
||||||
|
"total_price": 45000000,
|
||||||
|
"payment_price": 0,
|
||||||
|
"debt_price": -45000000,
|
||||||
|
"status": "Belum Lunas",
|
||||||
|
"travel_number": "232",
|
||||||
|
"balance": -201125000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": {
|
||||||
|
"aging": 2,
|
||||||
|
"total_price": 190645000,
|
||||||
|
"payment_price": 8800000,
|
||||||
|
"debt_price": -181845000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Dummy data for DebtSupplier
|
||||||
|
* Generated from: debt-supplier.dummy.json
|
||||||
|
*
|
||||||
|
* This file is auto-generated. Do not edit manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { DebtSupplier } from '../../types/api/report/debt-supplier';
|
||||||
|
import { BaseApiResponse } from '@/types/api/api-general';
|
||||||
|
import dummyData from './debt-supplier.dummy.json';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get dummy DebtSupplier data
|
||||||
|
* @returns Promise with BaseApiResponse containing DebtSupplier
|
||||||
|
*/
|
||||||
|
export async function getDummyDebtSupplier(): Promise<
|
||||||
|
BaseApiResponse<DebtSupplier[]> | undefined
|
||||||
|
> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve({
|
||||||
|
code: 200,
|
||||||
|
status: 'success',
|
||||||
|
message: 'Data retrieved successfully',
|
||||||
|
data: dummyData as unknown as DebtSupplier[],
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
+14
-13
@@ -1,19 +1,26 @@
|
|||||||
import { BaseMetadata } from '@/types/api/api-general';
|
|
||||||
import { Area } from '@/types/api/master-data/area';
|
import { Area } from '@/types/api/master-data/area';
|
||||||
import { Supplier } from '@/types/api/master-data/supplier';
|
import { Supplier } from '@/types/api/master-data/supplier';
|
||||||
import { Warehouse } from '@/types/api/master-data/warehouse';
|
import { Warehouse } from '@/types/api/master-data/warehouse';
|
||||||
|
|
||||||
export type DebtSupplier = BaseMetadata & {
|
export interface DebtSupplier {
|
||||||
supplier: Supplier;
|
supplier: Supplier;
|
||||||
|
initial_balance: number;
|
||||||
rows: DebtRow[];
|
rows: DebtRow[];
|
||||||
total: DebtTotal;
|
total: DebtTotal;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type DebtRow = {
|
export interface DebtTotal {
|
||||||
|
aging: number;
|
||||||
|
total_price: number;
|
||||||
|
payment_price: number;
|
||||||
|
debt_price: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DebtRow {
|
||||||
pr_number: string;
|
pr_number: string;
|
||||||
po_number: string;
|
po_number: string;
|
||||||
pr_date: string;
|
|
||||||
po_date: string;
|
po_date: string;
|
||||||
|
received_date: string;
|
||||||
aging: number;
|
aging: number;
|
||||||
area: Area;
|
area: Area;
|
||||||
warehouse: Warehouse;
|
warehouse: Warehouse;
|
||||||
@@ -24,11 +31,5 @@ export type DebtRow = {
|
|||||||
debt_price: number;
|
debt_price: number;
|
||||||
status: string;
|
status: string;
|
||||||
travel_number: string;
|
travel_number: string;
|
||||||
};
|
balance: number;
|
||||||
|
}
|
||||||
export type DebtTotal = {
|
|
||||||
aging: number;
|
|
||||||
total_price: number;
|
|
||||||
payment_price: number;
|
|
||||||
debt_price: number;
|
|
||||||
};
|
|
||||||
|
|||||||
Reference in New Issue
Block a user