diff --git a/src/components/pages/expense/ExpenseRealizationContent.tsx b/src/components/pages/expense/ExpenseRealizationContent.tsx
index c69f089f..ccd57ec3 100644
--- a/src/components/pages/expense/ExpenseRealizationContent.tsx
+++ b/src/components/pages/expense/ExpenseRealizationContent.tsx
@@ -16,7 +16,7 @@ import {
} from '@/components/pages/expense/form/ExpenseRequestForm.schema';
import { ExpenseApi } from '@/services/api/expense';
import { isResponseSuccess } from '@/lib/api-helper';
-import { ACCEPTED_FILE_TYPE } from '@/config/constant';
+import { ACCEPTED_FILE_TYPE, S3_PUBLIC_BASE_URL } from '@/config/constant';
interface ExpenseRealizationContentProps {
initialValues?: Expense;
@@ -103,24 +103,32 @@ const ExpenseRealizationContent = ({
initialValues?.realization_docs.length > 0 && (
{initialValues?.realization_docs.map(
- (realizationDocument, realizationDocumentIdx) => (
- -
-
- {realizationDocument.path}{' '}
-
-
-
- )
+ (realizationDocument, realizationDocumentIdx) => {
+ const path = realizationDocument.path.startsWith(
+ '/'
+ )
+ ? realizationDocument.path.slice(1)
+ : realizationDocument.path;
+ const documentUrl = `${S3_PUBLIC_BASE_URL}/${path}`;
+ return (
+ -
+
+ {realizationDocument.path}{' '}
+
+
+
+ );
+ }
)}
)}
@@ -211,7 +219,7 @@ const ExpenseRealizationContent = ({
let expenseGrandTotal = 0;
kandangExpense.pengajuans?.forEach(
- (item) => (expenseGrandTotal += item.price)
+ (item) => (expenseGrandTotal += item.qty * item.price)
);
return (
@@ -273,7 +281,7 @@ const ExpenseRealizationContent = ({
let expenseGrandTotal = 0;
kandangExpense.realisasi?.forEach(
- (item) => (expenseGrandTotal += item.price)
+ (item) => (expenseGrandTotal += item.qty * item.price)
);
return (
diff --git a/src/components/pages/expense/ExpenseRequestContent.tsx b/src/components/pages/expense/ExpenseRequestContent.tsx
index b937c5bc..2b9086e0 100644
--- a/src/components/pages/expense/ExpenseRequestContent.tsx
+++ b/src/components/pages/expense/ExpenseRequestContent.tsx
@@ -27,7 +27,7 @@ import {
UploadRequestDocumentsFormSchema,
UploadRequestDocumentsFormValues,
} from '@/components/pages/expense/form/ExpenseRequestForm.schema';
-import { ACCEPTED_FILE_TYPE } from '@/config/constant';
+import { ACCEPTED_FILE_TYPE, S3_PUBLIC_BASE_URL } from '@/config/constant';
import { ExpenseApi } from '@/services/api/expense';
import { isResponseSuccess } from '@/lib/api-helper';
import { EXPENSE_REQUEST_APPROVAL_LINE } from '@/config/approval-line';
@@ -408,9 +408,13 @@ const ExpenseRequestContent = ({
Kandang |
: |
- {initialValues?.kandangs
- .map((item) => item.name)
- .join(', ')}
+ {initialValues?.kandangs &&
+ initialValues?.kandangs.some((k) => k.name)
+ ? initialValues?.kandangs
+ .filter((item) => item.name)
+ .map((item) => item.name)
+ .join(', ')
+ : '-'}
|
@@ -448,7 +452,14 @@ const ExpenseRequestContent = ({
| Nominal Biaya |
: |
- {formatCurrency(initialValues?.grand_total ?? 0)} |
+
+ {formatCurrency(
+ initialValues?.latest_approval.step_number === 4 ||
+ initialValues?.latest_approval.step_number === 5
+ ? (initialValues?.total_realisasi ?? 0)
+ : (initialValues?.total_pengajuan ?? 0)
+ )}
+ |
| Status Pencairan |
@@ -482,24 +493,32 @@ const ExpenseRequestContent = ({
initialValues?.documents.length > 0 && (
{initialValues?.documents.map(
- (requestDocument, requestDocumentIdx) => (
- -
-
- {requestDocument.path}{' '}
-
-
-
- )
+ (requestDocument, requestDocumentIdx) => {
+ const path = requestDocument.path.startsWith(
+ '/'
+ )
+ ? requestDocument.path.slice(1)
+ : requestDocument.path;
+ const documentUrl = `${S3_PUBLIC_BASE_URL}/${path}`;
+ return (
+ -
+
+ {requestDocument.path}{' '}
+
+
+
+ );
+ }
)}
)}
@@ -558,7 +577,7 @@ const ExpenseRequestContent = ({
let expenseGrandTotal = 0;
kandangExpense.pengajuans?.forEach(
- (item) => (expenseGrandTotal += item.price)
+ (item) => (expenseGrandTotal += item.qty * item.price)
);
return (
@@ -573,7 +592,9 @@ const ExpenseRequestContent = ({
colSpan={5}
className='font-bold text-center text-base-content text-lg'
>
- Biaya {kandangExpense.name}
+ {kandangExpense.kandang_id && kandangExpense.name
+ ? `Biaya ${kandangExpense.name}`
+ : `Biaya ${initialValues?.location.name || 'Umum'}`}
diff --git a/src/components/pages/expense/form/ExpenseKandangsTable.tsx b/src/components/pages/expense/form/ExpenseKandangsTable.tsx
index b3c9f46d..7d7f76ca 100644
--- a/src/components/pages/expense/form/ExpenseKandangsTable.tsx
+++ b/src/components/pages/expense/form/ExpenseKandangsTable.tsx
@@ -20,10 +20,10 @@ interface ExpenseKandangsTableProps {
locationId?: number;
type: 'add' | 'edit' | 'detail';
selectedKandangs: {
- id: number;
- name: string;
+ id?: number;
+ name?: string;
}[];
- onChange: (kandangs: { id: number; name: string }[]) => void;
+ onChange: (kandangs: { id?: number; name?: string }[]) => void;
className?: {
wrapper?: string;
};
@@ -67,7 +67,11 @@ const ExpenseKandangsTable = ({
);
const [sorting, setSorting] = useState([]);
const [rowSelection, setRowSelection] = useState>(
- convertRowSelectionArrToObj(selectedKandangs.map((item) => item.id))
+ convertRowSelectionArrToObj(
+ selectedKandangs
+ .map((item) => item.id)
+ .filter((id): id is number => id !== undefined)
+ )
);
const kandangsColumns: ColumnDef[] = [
diff --git a/src/components/pages/expense/form/ExpenseRealizationForm.schema.ts b/src/components/pages/expense/form/ExpenseRealizationForm.schema.ts
index 77db761c..1f3682ea 100644
--- a/src/components/pages/expense/form/ExpenseRealizationForm.schema.ts
+++ b/src/components/pages/expense/form/ExpenseRealizationForm.schema.ts
@@ -1,6 +1,7 @@
import * as Yup from 'yup';
import { Expense } from '@/types/api/expense';
import { formatDate } from '@/lib/helper';
+import { S3_PUBLIC_BASE_URL } from '@/config/constant';
type ExpenseRealizationFormSchemaType = {
category?: {
@@ -12,7 +13,7 @@ type ExpenseRealizationFormSchemaType = {
label: string;
};
realization_date?: string;
- kandangs?: { id: number; name: string }[];
+ kandangs?: { id?: number; name?: string }[];
supplier?: {
value: number;
label: string;
@@ -20,7 +21,7 @@ type ExpenseRealizationFormSchemaType = {
existing_documents?: { name: string; url: string }[];
documents?: File[];
realizations: {
- kandang_id: number;
+ kandang_id?: number;
cost_items: {
nonstock?: {
value: number;
@@ -49,12 +50,11 @@ export const ExpenseRealizationFormSchema: Yup.ObjectSchema ({
- name: doc.path,
- url: doc.path,
- })),
+ existing_documents: initialValues?.realization_docs?.map((doc) => {
+ const path = doc.path.startsWith('/') ? doc.path.slice(1) : doc.path;
+ return {
+ name: doc.path,
+ url: `${S3_PUBLIC_BASE_URL}/${path}`,
+ };
+ }),
documents: [],
realizations: initialValues?.kandangs
? initialValues.kandangs.map((kandangExpense) => {
diff --git a/src/components/pages/expense/form/ExpenseRealizationForm.tsx b/src/components/pages/expense/form/ExpenseRealizationForm.tsx
index d1c7c5f2..6526b1c1 100644
--- a/src/components/pages/expense/form/ExpenseRealizationForm.tsx
+++ b/src/components/pages/expense/form/ExpenseRealizationForm.tsx
@@ -150,25 +150,10 @@ const ExpenseRealizationForm = ({
formik.setFieldValue('location', val);
formik.setFieldValue('kandangs', []);
- formik.setFieldValue('realizations', []);
- };
- const kandangsChangeHandler = (kandangs: { id: number; name: string }[]) => {
- formik.setFieldTouched('kandangs', true);
- formik.setFieldValue('kandangs', kandangs);
-
- const newRealizations = [...(formik.values.realizations ?? [])];
-
- // add new realizations
- kandangs.forEach((kandangItem) => {
- const isKandangExistInRealization = newRealizations.find(
- (realizationItem) => realizationItem.kandang_id === kandangItem.id
- );
-
- if (isKandangExistInRealization) return;
-
- newRealizations.push({
- kandang_id: kandangItem.id,
+ // Auto-create realization item for location (without kandang)
+ formik.setFieldValue('realizations', [
+ {
cost_items: [
{
nonstock: undefined,
@@ -177,25 +162,57 @@ const ExpenseRealizationForm = ({
notes: '',
},
],
+ },
+ ]);
+ };
+
+ const kandangsChangeHandler = (
+ kandangs: { id?: number; name?: string }[]
+ ) => {
+ formik.setFieldTouched('kandangs', true);
+ formik.setFieldValue('kandangs', kandangs);
+
+ // If no kandangs selected, create realization item for location
+ if (kandangs.length === 0) {
+ formik.setFieldValue('realizations', [
+ {
+ cost_items: [
+ {
+ nonstock: undefined,
+ quantity: undefined,
+ price: undefined,
+ notes: '',
+ },
+ ],
+ },
+ ]);
+ return;
+ }
+
+ // Start with empty array when kandangs are selected
+ const newRealizations: typeof formik.values.realizations = [];
+
+ // add new realizations for each kandang
+ kandangs.forEach((kandangItem) => {
+ if (!kandangItem.id) return;
+
+ const existingRealization = formik.values.realizations?.find(
+ (realizationItem) => realizationItem.kandang_id === kandangItem.id
+ );
+
+ newRealizations.push({
+ kandang_id: kandangItem.id,
+ cost_items: existingRealization?.cost_items || [
+ {
+ nonstock: undefined,
+ quantity: undefined,
+ price: undefined,
+ notes: '',
+ },
+ ],
});
});
- // prune realizations
- const kandangIds = new Set(kandangs.map((kandang) => kandang.id));
- const deletedRealizationsIdx: number[] = [];
-
- newRealizations.forEach((realization, idx) => {
- const isRealizationValid = kandangIds.has(realization.kandang_id);
-
- if (!isRealizationValid) {
- deletedRealizationsIdx.push(idx);
- }
- });
-
- deletedRealizationsIdx.forEach((deletedRealizationIdx) => {
- newRealizations.splice(deletedRealizationIdx, 1);
- });
-
formik.setFieldValue('realizations', newRealizations);
};
@@ -338,7 +355,10 @@ const ExpenseRealizationForm = ({
)}
;
+ supplierId?: number;
+ location?: {
+ value: number;
+ label: string;
+ };
className?: {
wrapper?: string;
};
@@ -25,12 +30,18 @@ interface ExpenseRealizationKandangDetailExpenseProps {
const ExpenseRealizationKandangDetailExpense: React.FC<
ExpenseRealizationKandangDetailExpenseProps
-> = ({ type, formik, className }) => {
+> = ({ type, formik, supplierId, location, className }) => {
const {
setInputValue: setNonstockInputValue,
options: nonstockOptions,
isLoadingOptions: isLoadingNonstockOptions,
- } = useSelect(NonstockApi.basePath, 'id', 'name');
+ } = useSelect(
+ NonstockApi.basePath,
+ 'id',
+ 'name',
+ 'search',
+ supplierId ? { supplier_id: String(supplierId) } : undefined
+ );
const nonstockChangeHandler = (
kandangExpenseIdx: number,
@@ -82,140 +93,159 @@ const ExpenseRealizationKandangDetailExpense: React.FC<
- {formik.values.realizations.length === 0 && (
+ {!formik.values.supplier?.value && (
- Pilih kandang terlebih dahulu!
+ Pilih supplier terlebih dahulu!
)}
- {formik.values.realizations.map((kandangExpense, kandangExpenseIdx) => {
- const kandangName = formik.values.kandangs?.find(
- (kandang) => kandang.id === kandangExpense.kandang_id
- );
+ {formik.values.realizations.length === 0 &&
+ formik.values.supplier?.value && (
+
+
+ Belum ada item biaya. Silakan pilih lokasi terlebih dahulu.
+
+
+ )}
- return (
- kandangName?.name && (
-
-
-
- Biaya {kandangName?.name}
-
+ {formik.values.realizations.length > 0 &&
+ formik.values.supplier?.value &&
+ formik.values.realizations.map(
+ (kandangExpense, kandangExpenseIdx) => {
+ const kandangName = kandangExpense.kandang_id
+ ? formik.values.kandangs?.find(
+ (kandang) => kandang.id === kandangExpense.kandang_id
+ )
+ : null;
-
-
-
-
- | Nonstock |
- Total Kuantitas |
- Harga Satuan |
- Catatan |
-
-
+ return (
+ (kandangName?.name || !kandangExpense.kandang_id) && (
+
+
+
+ {kandangName?.name
+ ? `Biaya ${kandangName.name}`
+ : location?.label
+ ? `Biaya ${location.label}`
+ : 'Biaya Umum'}
+
-
- {kandangExpense.cost_items.map(
- (expenseItem, expenseIdx) => (
-
- |
- {
- nonstockChangeHandler(
- kandangExpenseIdx,
- expenseIdx,
- val
- );
- }}
- options={nonstockOptions}
- isLoading={isLoadingNonstockOptions}
- onInputChange={setNonstockInputValue}
- className={{ wrapper: 'min-w-48' }}
- isDisabled
- />
- |
-
-
-
- |
-
-
-
- Rp
-
- }
- className={{ wrapper: 'min-w-24' }}
- />
- |
-
-
-
- |
+
+
+
+
+ | Nonstock |
+ Total Kuantitas |
+ Harga Satuan |
+ Catatan |
- )
- )}
-
-
+
+
+
+ {kandangExpense.cost_items.map(
+ (expenseItem, expenseIdx) => (
+
+ |
+ {
+ nonstockChangeHandler(
+ kandangExpenseIdx,
+ expenseIdx,
+ val
+ );
+ }}
+ options={nonstockOptions}
+ isLoading={isLoadingNonstockOptions}
+ onInputChange={setNonstockInputValue}
+ className={{ wrapper: 'min-w-48' }}
+ isDisabled
+ />
+ |
+
+
+
+ |
+
+
+
+ Rp
+
+ }
+ className={{ wrapper: 'min-w-24' }}
+ />
+ |
+
+
+
+ |
+
+ )
+ )}
+
+
+
+
-
-
- )
- );
- })}
+ )
+ );
+ }
+ )}
);
diff --git a/src/components/pages/expense/form/ExpenseRequestForm.schema.ts b/src/components/pages/expense/form/ExpenseRequestForm.schema.ts
index 7758df83..71357361 100644
--- a/src/components/pages/expense/form/ExpenseRequestForm.schema.ts
+++ b/src/components/pages/expense/form/ExpenseRequestForm.schema.ts
@@ -1,6 +1,7 @@
import * as Yup from 'yup';
import { Expense } from '@/types/api/expense';
import { formatDate } from '@/lib/helper';
+import { S3_PUBLIC_BASE_URL } from '@/config/constant';
type ExpenseFormSchemaType = {
category?: {
@@ -11,8 +12,9 @@ type ExpenseFormSchemaType = {
value: number;
label: string;
};
+ location_id: number;
transaction_date?: string;
- kandangs?: { id: number; name: string }[];
+ kandangs?: { id?: number; name?: string }[];
supplier?: {
value: number;
label: string;
@@ -21,7 +23,7 @@ type ExpenseFormSchemaType = {
deleted_documents?: number[];
documents?: File[];
expense_nonstocks: {
- kandang_id: number;
+ kandang_id?: number;
cost_items: {
nonstock?: {
value: number;
@@ -46,16 +48,17 @@ export const ExpenseRequestFormSchema: Yup.ObjectSchema =
label: Yup.string().required(),
}).required('Lokasi wajib diisi!'),
+ location_id: Yup.number().min(1).required('Lokasi wajib diisi!'),
+
transaction_date: Yup.string().required('Tanggal transaksi wajib diisi!'),
kandangs: Yup.array()
.of(
Yup.object({
- id: Yup.number().required('Kandang wajib dipilih!'),
- name: Yup.string().required('Kandang wajib dipilih!'),
+ id: Yup.number().optional(),
+ name: Yup.string().optional(),
})
)
- .min(1, 'Kandang wajib dipilih!')
- .required('Kandang wajib dipilih!'),
+ .optional(),
supplier: Yup.object({
value: Yup.number().min(1).required(),
@@ -77,7 +80,7 @@ export const ExpenseRequestFormSchema: Yup.ObjectSchema =
expense_nonstocks: Yup.array()
.of(
Yup.object({
- kandang_id: Yup.number().min(1, 'Wajib memilih kandang!').required(),
+ kandang_id: Yup.number().min(1, 'Wajib memilih kandang!').optional(),
cost_items: Yup.array()
.of(
Yup.object({
@@ -128,6 +131,7 @@ export const getExpenseFormInitialValues = (
label: initialValues.location.name,
}
: undefined,
+ location_id: Number(initialValues?.location.id || 0),
transaction_date: initialValues?.transaction_date
? formatDate(initialValues.transaction_date, 'YYYY-MM-DD')
: undefined,
@@ -141,11 +145,14 @@ export const getExpenseFormInitialValues = (
label: initialValues.supplier.name,
}
: undefined,
- existing_documents: initialValues?.documents?.map((doc) => ({
- id: doc.id,
- name: doc.path,
- url: doc.path,
- })),
+ existing_documents: initialValues?.documents?.map((doc) => {
+ const path = doc.path.startsWith('/') ? doc.path.slice(1) : doc.path;
+ return {
+ id: doc.id,
+ name: doc.path,
+ url: `${S3_PUBLIC_BASE_URL}/${path}`,
+ };
+ }),
deleted_documents: [],
documents: [],
expense_nonstocks: initialValues?.kandangs
diff --git a/src/components/pages/expense/form/ExpenseRequestForm.tsx b/src/components/pages/expense/form/ExpenseRequestForm.tsx
index 71160785..60e55397 100644
--- a/src/components/pages/expense/form/ExpenseRequestForm.tsx
+++ b/src/components/pages/expense/form/ExpenseRequestForm.tsx
@@ -108,18 +108,24 @@ const ExpenseRequestForm = ({
const expensePayload: CreateExpensePayload = {
category: formik.values.category?.value as 'BOP' | 'NON-BOP',
+ location_id: values.location_id as number,
transaction_date: values?.transaction_date as string,
supplier_id: values.supplier?.value as number,
documents: values.documents as File[],
- expense_nonstocks: values.expense_nonstocks.map((expenseNonstock) => ({
- kandang_id: expenseNonstock.kandang_id,
- cost_items: expenseNonstock.cost_items.map((costItem) => ({
- nonstock_id: costItem.nonstock?.value as number,
- quantity: parseFloat(String(costItem.quantity)) as number,
- price: parseFloat(String(costItem.price)) as number,
- notes: costItem.notes ?? '',
- })),
- })),
+ expense_nonstocks: values.expense_nonstocks.map((expenseNonstock) => {
+ const basePayload = {
+ cost_items: expenseNonstock.cost_items.map((costItem) => ({
+ nonstock_id: costItem.nonstock?.value as number,
+ quantity: parseFloat(String(costItem.quantity)) as number,
+ price: parseFloat(String(costItem.price)) as number,
+ notes: costItem.notes ?? '',
+ })),
+ };
+
+ return expenseNonstock.kandang_id
+ ? { ...basePayload, kandang_id: expenseNonstock.kandang_id }
+ : basePayload;
+ }),
};
switch (type) {
@@ -130,19 +136,25 @@ const ExpenseRequestForm = ({
case 'edit':
const expenseUpdatePayload: UpdateExpensePayload = {
category: formik.values.category?.value as 'BOP' | 'NON-BOP',
+ location_id: values.location_id as number,
transaction_date: values?.transaction_date as string,
supplier_id: values.supplier?.value as number,
documents: values.documents as File[],
expense_nonstocks: values.expense_nonstocks.map(
- (expenseNonstock) => ({
- kandang_id: expenseNonstock.kandang_id,
- cost_items: expenseNonstock.cost_items.map((costItem) => ({
- nonstock_id: costItem.nonstock?.value as number,
- quantity: parseFloat(String(costItem.quantity)) as number,
- price: parseFloat(String(costItem.price)) as number,
- notes: costItem.notes ?? '',
- })),
- })
+ (expenseNonstock) => {
+ const basePayload = {
+ cost_items: expenseNonstock.cost_items.map((costItem) => ({
+ nonstock_id: costItem.nonstock?.value as number,
+ quantity: parseFloat(String(costItem.quantity)) as number,
+ price: parseFloat(String(costItem.price)) as number,
+ notes: costItem.notes ?? '',
+ })),
+ };
+
+ return expenseNonstock.kandang_id
+ ? { ...basePayload, kandang_id: expenseNonstock.kandang_id }
+ : basePayload;
+ }
),
};
@@ -179,27 +191,14 @@ const ExpenseRequestForm = ({
formik.setFieldTouched('location', true);
formik.setFieldValue('location', val);
+ const locationId = Array.isArray(val) ? val[0]?.value : val?.value;
+ formik.setFieldValue('location_id', locationId);
+
formik.setFieldValue('kandangs', []);
- formik.setFieldValue('expense_nonstocks', []);
- };
- const kandangsChangeHandler = (kandangs: { id: number; name: string }[]) => {
- formik.setFieldTouched('kandangs', true);
- formik.setFieldValue('kandangs', kandangs);
-
- const newExpenseNonstocks = [...(formik.values.expense_nonstocks ?? [])];
-
- // add new expense_nonstocks
- kandangs.forEach((kandangItem) => {
- const isKandangExistInExpenseNonstocks = newExpenseNonstocks.find(
- (expenseNonstockItem) =>
- expenseNonstockItem.kandang_id === kandangItem.id
- );
-
- if (isKandangExistInExpenseNonstocks) return;
-
- newExpenseNonstocks.push({
- kandang_id: kandangItem.id,
+ // Auto-create expense item for location (without kandang)
+ formik.setFieldValue('expense_nonstocks', [
+ {
cost_items: [
{
nonstock: undefined,
@@ -208,25 +207,56 @@ const ExpenseRequestForm = ({
notes: '',
},
],
+ },
+ ]);
+ };
+
+ const kandangsChangeHandler = (
+ kandangs: { id?: number; name?: string }[]
+ ) => {
+ formik.setFieldTouched('kandangs', true);
+ formik.setFieldValue('kandangs', kandangs);
+
+ // If no kandangs selected, create expense item for location
+ if (kandangs.length === 0) {
+ formik.setFieldValue('expense_nonstocks', [
+ {
+ cost_items: [
+ {
+ nonstock: undefined,
+ quantity: undefined,
+ price: undefined,
+ notes: '',
+ },
+ ],
+ },
+ ]);
+ return;
+ }
+
+ const newExpenseNonstocks: typeof formik.values.expense_nonstocks = [];
+
+ kandangs.forEach((kandangItem) => {
+ if (!kandangItem.id) return;
+
+ const existingExpenseNonstock = formik.values.expense_nonstocks?.find(
+ (expenseNonstockItem) =>
+ expenseNonstockItem.kandang_id === kandangItem.id
+ );
+
+ newExpenseNonstocks.push({
+ kandang_id: kandangItem.id,
+ cost_items: existingExpenseNonstock?.cost_items || [
+ {
+ nonstock: undefined,
+ quantity: undefined,
+ price: undefined,
+ notes: '',
+ },
+ ],
});
});
- // prune expense_nonstocks
- const kandangIds = new Set(kandangs.map((kandang) => kandang.id));
- const deletedExpenseNonstocksIdx: number[] = [];
-
- newExpenseNonstocks.forEach((expenseNonstock, idx) => {
- const isExpenseNonstockValid = kandangIds.has(expenseNonstock.kandang_id);
-
- if (!isExpenseNonstockValid) {
- deletedExpenseNonstocksIdx.push(idx);
- }
- });
-
- deletedExpenseNonstocksIdx.forEach((deletedExpenseNonstockIdx) => {
- newExpenseNonstocks.splice(deletedExpenseNonstockIdx, 1);
- });
-
formik.setFieldValue('expense_nonstocks', newExpenseNonstocks);
};
@@ -454,7 +484,10 @@ const ExpenseRequestForm = ({
)}
;
+ supplierId?: number;
+ location?: {
+ value: number;
+ label: string;
+ };
className?: {
wrapper?: string;
};
@@ -28,12 +33,18 @@ interface ExpenseRequestKandangDetailExpenseProps {
const ExpenseRequestKandangDetailExpense: React.FC<
ExpenseRequestKandangDetailExpenseProps
-> = ({ type, formik, className }) => {
+> = ({ type, formik, supplierId, location, className }) => {
const {
setInputValue: setNonstockInputValue,
options: nonstockOptions,
isLoadingOptions: isLoadingNonstockOptions,
- } = useSelect(NonstockApi.basePath, 'id', 'name');
+ } = useSelect(
+ NonstockApi.basePath,
+ 'id',
+ 'name',
+ 'search',
+ supplierId ? { supplier_id: String(supplierId) } : undefined
+ );
const nonstockChangeHandler = (
kandangExpenseIdx: number,
@@ -113,41 +124,57 @@ const ExpenseRequestKandangDetailExpense: React.FC<
- {(formik.values.expense_nonstocks.length === 0 ||
- !formik.values.supplier?.value) && (
+ {!formik.values.supplier?.value && (
- Pilih kandang terlebih dahulu!
+ Pilih supplier terlebih dahulu!
)}
+ {formik.values.expense_nonstocks.length === 0 &&
+ formik.values.supplier?.value && (
+
+
+ Belum ada item biaya. Silakan pilih lokasi terlebih dahulu.
+
+
+ )}
+
{formik.values.expense_nonstocks.length > 0 &&
formik.values.supplier?.value &&
formik.values.expense_nonstocks.map(
(kandangExpense, kandangExpenseIdx) => {
- const kandangName = formik.values.kandangs?.find(
- (kandang) => kandang.id === kandangExpense.kandang_id
- );
+ const kandangName = kandangExpense.kandang_id
+ ? formik.values.kandangs?.find(
+ (kandang) => kandang.id === kandangExpense.kandang_id
+ )
+ : null;
return (
- kandangName?.name && (
+ (kandangName?.name || !kandangExpense.kandang_id) && (
- Biaya {kandangName?.name}
+ Biaya {kandangName?.name || location?.label || 'Umum'}
- | Nonstock |
- Total Kuantitas |
- Harga Satuan |
+
+ Nonstock
+ |
+
+ Total Kuantitas
+ |
+
+ Harga Satuan
+ |
Catatan |
{type !== 'detail' && Aksi | }
diff --git a/src/components/pages/expense/pdf/ExpensePDF.tsx b/src/components/pages/expense/pdf/ExpensePDF.tsx
index 5b107127..ef1c7d8b 100644
--- a/src/components/pages/expense/pdf/ExpensePDF.tsx
+++ b/src/components/pages/expense/pdf/ExpensePDF.tsx
@@ -219,7 +219,13 @@ const ExpensePDF = ({ expense }: ExpensePDFProps) => {
{ label: 'Lokasi', value: expense?.location.name },
{
label: 'Kandang',
- value: expense?.kandangs.map((item) => item.name).join(', '),
+ value:
+ expense?.kandangs && expense?.kandangs.some((k) => k.name)
+ ? expense?.kandangs
+ .filter((item) => item.name)
+ .map((item) => item.name)
+ .join(', ')
+ : '-',
},
{ label: 'Vendor', value: expense?.supplier.name },
{
@@ -235,7 +241,12 @@ const ExpensePDF = ({ expense }: ExpensePDFProps) => {
{ label: 'Nama Pengaju', value: expense?.created_user.name },
{
label: 'Nominal Biaya',
- value: formatCurrency(expense?.grand_total ?? 0),
+ value: formatCurrency(
+ expense?.latest_approval.step_number === 4 ||
+ expense?.latest_approval.step_number === 5
+ ? (expense?.total_realisasi ?? 0)
+ : (expense?.total_pengajuan ?? 0)
+ ),
},
{
label: 'Nominal Pengajuan',
@@ -326,7 +337,7 @@ const ExpensePDF = ({ expense }: ExpensePDFProps) => {
let expenseRequestTotal = 0;
kandangExpense.pengajuans?.forEach(
- (item) => (expenseRequestTotal += item.price)
+ (item) => (expenseRequestTotal += item.qty * item.price)
);
return (
@@ -335,7 +346,9 @@ const ExpensePDF = ({ expense }: ExpensePDFProps) => {
style={ExpensePDFStyle.kandangExpenseContainer}
>
- {kandangExpense.name}
+ {kandangExpense.kandang_id && kandangExpense.name
+ ? `Biaya ${kandangExpense.name}`
+ : `Biaya ${expense?.location.name || 'Umum'}`}
@@ -484,7 +497,7 @@ const ExpensePDF = ({ expense }: ExpensePDFProps) => {
let expenseRealizationTotal = 0;
kandangExpense.realisasi?.forEach(
- (item) => (expenseRealizationTotal += item.price)
+ (item) => (expenseRealizationTotal += item.qty * item.price)
);
return (
@@ -493,7 +506,9 @@ const ExpensePDF = ({ expense }: ExpensePDFProps) => {
style={ExpensePDFStyle.kandangExpenseContainer}
>
- {kandangExpense.name}
+ {kandangExpense.kandang_id && kandangExpense.name
+ ? `Biaya ${kandangExpense.name}`
+ : `Biaya ${expense?.location.name || 'Umum'}`}
diff --git a/src/config/constant.ts b/src/config/constant.ts
index 48e5a435..01ee6ed9 100644
--- a/src/config/constant.ts
+++ b/src/config/constant.ts
@@ -352,6 +352,9 @@ export const ACCEPTED_FILE_TYPE = {
},
};
+export const S3_PUBLIC_BASE_URL = process.env
+ .NEXT_PUBLIC_S3_PUBLIC_BASE_URL as string;
+
export const FILTER_TYPE_OPTIONS = [
{
label: 'Tanggal Realisasi',
diff --git a/src/services/api/expense.ts b/src/services/api/expense.ts
index 44a855f4..70e0e339 100644
--- a/src/services/api/expense.ts
+++ b/src/services/api/expense.ts
@@ -483,6 +483,7 @@ export class ExpenseApiService extends BaseApiService<
const formData = new FormData();
formData.append('category', payload.category);
+ formData.append('location_id', String(payload.location_id));
formData.append('transaction_date', payload.transaction_date);
formData.append('supplier_id', String(payload.supplier_id));
@@ -505,6 +506,7 @@ export class ExpenseApiService extends BaseApiService<
const formData = new FormData();
formData.append('category', payload.category);
+ formData.append('location_id', String(payload.location_id));
formData.append('transaction_date', payload.transaction_date);
formData.append('supplier_id', String(payload.supplier_id));
diff --git a/src/types/api/expense.d.ts b/src/types/api/expense.d.ts
index a62066ba..12455cc8 100644
--- a/src/types/api/expense.d.ts
+++ b/src/types/api/expense.d.ts
@@ -57,11 +57,12 @@ export type Expense = BaseMetadata & BaseExpense;
export type CreateExpensePayload = {
category: 'BOP' | 'NON-BOP';
+ location_id: number;
transaction_date: string;
supplier_id: number;
documents: File[];
expense_nonstocks: {
- kandang_id: number;
+ kandang_id?: number;
cost_items: {
nonstock_id: number;
quantity: number;
@@ -72,12 +73,13 @@ export type CreateExpensePayload = {
};
export type UpdateExpensePayload = {
+ location_id: number;
category: 'BOP' | 'NON-BOP';
transaction_date: string;
supplier_id: number;
documents: File[];
expense_nonstocks: {
- kandang_id: number;
+ kandang_id?: number;
cost_items: {
nonstock_id: number;
quantity: number;