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.tsx b/src/components/pages/expense/form/ExpenseRealizationForm.tsx index d1c7c5f2..d1c6353e 100644 --- a/src/components/pages/expense/form/ExpenseRealizationForm.tsx +++ b/src/components/pages/expense/form/ExpenseRealizationForm.tsx @@ -153,7 +153,9 @@ const ExpenseRealizationForm = ({ formik.setFieldValue('realizations', []); }; - const kandangsChangeHandler = (kandangs: { id: number; name: string }[]) => { + const kandangsChangeHandler = ( + kandangs: { id?: number; name?: string }[] + ) => { formik.setFieldTouched('kandangs', true); formik.setFieldValue('kandangs', kandangs); @@ -161,6 +163,8 @@ const ExpenseRealizationForm = ({ // add new realizations kandangs.forEach((kandangItem) => { + if (!kandangItem.id) return; + const isKandangExistInRealization = newRealizations.find( (realizationItem) => realizationItem.kandang_id === kandangItem.id ); @@ -181,7 +185,11 @@ const ExpenseRealizationForm = ({ }); // prune realizations - const kandangIds = new Set(kandangs.map((kandang) => kandang.id)); + const kandangIds = new Set( + kandangs + .map((kandang) => kandang.id) + .filter((id): id is number => id !== undefined) + ); const deletedRealizationsIdx: number[] = []; newRealizations.forEach((realization, idx) => { diff --git a/src/components/pages/expense/form/ExpenseRequestForm.schema.ts b/src/components/pages/expense/form/ExpenseRequestForm.schema.ts index 134da3be..4a4c921b 100644 --- a/src/components/pages/expense/form/ExpenseRequestForm.schema.ts +++ b/src/components/pages/expense/form/ExpenseRequestForm.schema.ts @@ -13,7 +13,7 @@ type ExpenseFormSchemaType = { }; location_id: number; transaction_date?: string; - kandangs?: { id: number; name: string }[]; + kandangs?: { id?: number; name?: string }[]; supplier?: { value: number; label: string; @@ -22,7 +22,7 @@ type ExpenseFormSchemaType = { deleted_documents?: number[]; documents?: File[]; expense_nonstocks: { - kandang_id: number; + kandang_id?: number | null; cost_items: { nonstock?: { value: number; @@ -53,12 +53,11 @@ export const ExpenseRequestFormSchema: Yup.ObjectSchema = 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(), @@ -80,7 +79,10 @@ 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!') + .nullable() + .optional(), cost_items: Yup.array() .of( Yup.object({ diff --git a/src/components/pages/expense/form/ExpenseRequestForm.tsx b/src/components/pages/expense/form/ExpenseRequestForm.tsx index 10c222eb..e8ad0843 100644 --- a/src/components/pages/expense/form/ExpenseRequestForm.tsx +++ b/src/components/pages/expense/form/ExpenseRequestForm.tsx @@ -113,7 +113,7 @@ const ExpenseRequestForm = ({ supplier_id: values.supplier?.value as number, documents: values.documents as File[], expense_nonstocks: values.expense_nonstocks.map((expenseNonstock) => ({ - kandang_id: expenseNonstock.kandang_id, + kandang_id: expenseNonstock.kandang_id ?? null, cost_items: expenseNonstock.cost_items.map((costItem) => ({ nonstock_id: costItem.nonstock?.value as number, quantity: parseFloat(String(costItem.quantity)) as number, @@ -137,7 +137,7 @@ const ExpenseRequestForm = ({ documents: values.documents as File[], expense_nonstocks: values.expense_nonstocks.map( (expenseNonstock) => ({ - kandang_id: expenseNonstock.kandang_id, + kandang_id: expenseNonstock.kandang_id ?? null, cost_items: expenseNonstock.cost_items.map((costItem) => ({ nonstock_id: costItem.nonstock?.value as number, quantity: parseFloat(String(costItem.quantity)) as number, @@ -185,26 +185,11 @@ const ExpenseRequestForm = ({ 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', [ + { + kandang_id: null, cost_items: [ { nonstock: undefined, @@ -213,25 +198,57 @@ 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', [ + { + kandang_id: null, + 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); }; @@ -462,6 +479,7 @@ const ExpenseRequestForm = ({ type={type} formik={formik} supplierId={formik.values.supplier?.value as number} + location={formik.values.location} className={{ wrapper: 'col-span-12', }} diff --git a/src/components/pages/expense/form/ExpenseRequestKandangDetailExpense.tsx b/src/components/pages/expense/form/ExpenseRequestKandangDetailExpense.tsx index abe7bc24..e219870e 100644 --- a/src/components/pages/expense/form/ExpenseRequestKandangDetailExpense.tsx +++ b/src/components/pages/expense/form/ExpenseRequestKandangDetailExpense.tsx @@ -22,6 +22,10 @@ interface ExpenseRequestKandangDetailExpenseProps { type?: 'add' | 'edit' | 'detail'; formik: FormikContextType; supplierId?: number; + location?: { + value: number; + label: string; + }; className?: { wrapper?: string; }; @@ -29,7 +33,7 @@ interface ExpenseRequestKandangDetailExpenseProps { const ExpenseRequestKandangDetailExpense: React.FC< ExpenseRequestKandangDetailExpenseProps -> = ({ type, formik, supplierId, className }) => { +> = ({ type, formik, supplierId, location, className }) => { const { setInputValue: setNonstockInputValue, options: nonstockOptions, @@ -120,32 +124,42 @@ 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'}
diff --git a/src/types/api/expense.d.ts b/src/types/api/expense.d.ts index ff7ead09..36657d90 100644 --- a/src/types/api/expense.d.ts +++ b/src/types/api/expense.d.ts @@ -62,7 +62,7 @@ export type CreateExpensePayload = { supplier_id: number; documents: File[]; expense_nonstocks: { - kandang_id: number; + kandang_id: number | null; cost_items: { nonstock_id: number; quantity: number; @@ -79,7 +79,7 @@ export type UpdateExpensePayload = { supplier_id: number; documents: File[]; expense_nonstocks: { - kandang_id: number; + kandang_id: number | null; cost_items: { nonstock_id: number; quantity: number;