diff --git a/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.schema.ts b/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.schema.ts index 42ecf48d..8858cf25 100644 --- a/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.schema.ts +++ b/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.schema.ts @@ -1,55 +1,102 @@ import * as Yup from 'yup'; -import { OptionType } from '@/components/input/SelectInput'; -export const InventoryAdjustmentFormSchema = Yup.object({ - product_category: Yup.mixed() - .nullable() - .test( - 'is-valid-option', - 'Kategori Produk wajib diisi!', - (value) => value !== null && value !== undefined - ), +export type InventoryAdjustmentFormSchemaType = { + location: { + value: number; + label: string; + } | null; + location_id: number; + project_flock: { + value: number; + label: string; + } | null; + project_flock_id: number; + kandang: { + value: number; + label: string; + } | null; + kandang_id: number; + project_flock_kandang: { + value: number; + label: string; + } | null; + project_flock_kandang_id: number; + product: { + value: number; + label: string; + } | null; + product_id: number; + transaction_type: string; + transaction_subtype: string; + qty: number | string; + price: number | string; + notes: string; +}; - product_category_id: Yup.number().nullable(), - - product: Yup.mixed() - .nullable() - .test( - 'is-valid-option', - 'Produk wajib diisi!', - (value) => value !== null && value !== undefined - ), - - product_id: Yup.number() - .nullable() - .required('Produk wajib diisi!') - .min(1, 'Produk wajib diisi!'), - - warehouse: Yup.mixed() - .nullable() - .test( - 'is-valid-option', - 'Warehouse wajib diisi!', - (value) => value !== null && value !== undefined - ), - - warehouse_id: Yup.number() - .nullable() - .required('Warehouse wajib diisi!') - .min(1, 'Warehouse wajib diisi!'), - - transaction_type: Yup.string() - .oneOf(['increase', 'decrease'], 'Tipe transaksi tidak valid') - .nullable() - .required('Tipe transaksi wajib diisi'), - - quantity: Yup.number() - .typeError('Kuantitas harus berupa angka') - .min(1, 'Minimal kuantitas adalah 1') - .required('Kuantitas wajib diisi'), - - note: Yup.string().required('Catatan wajib diisi!'), -}); +export const InventoryAdjustmentFormSchema: Yup.ObjectSchema = + Yup.object({ + location: Yup.object({ + value: Yup.number().min(1).required(), + label: Yup.string().required(), + }).nullable(), + location_id: Yup.number() + .min(1, 'Lokasi wajib diisi!') + .required('Lokasi wajib diisi!') + .typeError('Lokasi wajib diisi!'), + project_flock: Yup.object({ + value: Yup.number().min(1).required(), + label: Yup.string().required(), + }).nullable(), + project_flock_id: Yup.number() + .min(1, 'Project flock wajib diisi!') + .required('Project flock wajib diisi!') + .typeError('Project flock wajib diisi!'), + kandang: Yup.object({ + value: Yup.number().min(1).required(), + label: Yup.string().required(), + }).nullable(), + kandang_id: Yup.number() + .min(1, 'Kandang wajib diisi!') + .required('Kandang wajib diisi!') + .typeError('Kandang wajib diisi!'), + project_flock_kandang: Yup.object({ + value: Yup.number().min(1).required(), + label: Yup.string().required(), + }).nullable(), + project_flock_kandang_id: Yup.number() + .default(0) + .typeError('Project Flock Kandang wajib diisi!') + .test( + 'is-valid-project-flock-kandang', + 'Project Flock Kandang wajib diisi!', + (value) => value !== undefined && value !== null && value > 0 + ) + .required('Project Flock Kandang wajib diisi!'), + product: Yup.object({ + value: Yup.number().min(1).required(), + label: Yup.string().required(), + }).nullable(), + product_id: Yup.number() + .min(1, 'Produk wajib diisi!') + .required('Produk wajib diisi!') + .typeError('Produk wajib diisi!'), + transaction_type: Yup.string() + .oneOf( + ['PEMBELIAN', 'PENJUALAN', 'BIAYA', 'RECORDING'], + 'Tipe transaksi tidak valid' + ) + .required('Tipe transaksi wajib diisi'), + transaction_subtype: Yup.string().required('Sub tipe transaksi wajib diisi'), + qty: Yup.number() + .typeError('Kuantitas harus berupa angka') + .min(1, 'Minimal kuantitas adalah 1') + .required('Kuantitas wajib diisi'), + price: Yup.number() + .typeError('Harga harus berupa angka') + .min(0, 'Minimal harga adalah 0') + .required('Harga wajib diisi'), + notes: Yup.string().required('Catatan wajib diisi!'), + }); export type InventoryAdjustmentFormValues = Yup.InferType< typeof InventoryAdjustmentFormSchema diff --git a/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.tsx b/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.tsx index 612fbb20..31b64bed 100644 --- a/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.tsx +++ b/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.tsx @@ -1,6 +1,6 @@ 'use client'; -import { isResponseError } from '@/lib/api-helper'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { InventoryAdjustmentApi } from '@/services/api/inventory'; import { CreateInventoryAdjustmentPayload, @@ -14,11 +14,11 @@ import { InventoryAdjustmentFormSchema, InventoryAdjustmentFormValues, } from '@/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.schema'; +import { LocationApi, ProductApi } from '@/services/api/master-data'; import { - ProductApi, - ProductCategoryApi, - WarehouseApi, -} from '@/services/api/master-data'; + ProjectFlockApi, + ProjectFlockKandangApi, +} from '@/services/api/production'; import Button from '@/components/Button'; import { Icon } from '@iconify/react'; import SelectInput, { @@ -26,13 +26,22 @@ import SelectInput, { useSelect, } from '@/components/input/SelectInput'; import TextInput from '@/components/input/TextInput'; -import { RadioGroup } from '@/components/input/RadioInput'; import TextArea from '@/components/input/TextArea'; import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; import AlertErrorList from '@/components/helper/form/FormErrors'; -import { ProductCategory } from '@/types/api/master-data/product-category'; +import { Location } from '@/types/api/master-data/location'; +import { ProjectFlock } from '@/types/api/production/project-flock'; +import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang'; +import { Kandang } from '@/types/api/master-data/kandang'; import { Product } from '@/types/api/master-data/product'; -import { Warehouse } from '@/types/api/master-data/warehouse'; +import { ProjectFlockKandangLookup } from '@/types/api/production/project-flock'; +import { BaseApiResponse } from '@/types/api/api-general'; +import useSWR from 'swr'; +import { + TRANSACTION_TYPE_OPTIONS, + TRANSACTION_SUBTYPE_OPTIONS, +} from '@/config/constant'; +import NumberInput from '@/components/input/NumberInput'; interface InventoryAdjustmentFormProps { type?: 'add' | 'edit' | 'detail'; @@ -49,8 +58,19 @@ const InventoryAdjustmentForm = ({ InventoryAdjustmentFormErrorMessage, setInventoryAdjustmentFormErrorMessage, ] = useState(''); - const [disabledProduct, setDisabledProduct] = useState(true); - const [quantityLabel, setQuantityLabel] = useState('Tambah Stok'); + const [quantityLabel, setQuantityLabel] = useState('Kuantitas'); + + // Selected States untuk cascading selects + const [selectedLocation, setSelectedLocation] = useState( + null + ); + const [selectedProjectFlock, setSelectedProjectFlock] = + useState(null); + const [selectedKandang, setSelectedKandang] = useState( + null + ); + const [selectedProjectFlockLocationId, setSelectedProjectFlockLocationId] = + useState(''); // Submit Handler const createInventoryAdjustmentHandler = useCallback( @@ -71,34 +91,258 @@ const InventoryAdjustmentForm = ({ [router] ); - const formikInitialValues = useMemo< - Partial - >(() => { - return { - product_id: initialValues?.product_warehouse?.product_id ?? 0, - warehouse_id: initialValues?.product_warehouse?.warehouse_id ?? 0, - product_category: undefined, - product: undefined, - warehouse: undefined, - quantity: initialValues?.increase ?? initialValues?.decrease ?? 0, - transaction_type: undefined, - note: initialValues?.note ?? '', - }; - }, [initialValues]); + // API Data Fetching + const { + setInputValue: setLocationInputValue, + options: locationOptions, + isLoadingOptions: isLoadingLocationOptions, + loadMore: loadMoreLocations, + } = useSelect(LocationApi.basePath, 'id', 'name'); + + const { + setInputValue: setProjectFlockInputValue, + options: projectFlockOptions, + rawData: projectFlocksRawData, + isLoadingOptions: isLoadingProjectFlockOptions, + loadMore: loadMoreProjectFlocks, + } = useSelect( + ProjectFlockApi.basePath, + 'id', + 'flock_name', + 'search', + { + location_id: selectedProjectFlockLocationId, + } + ); + + // Lookup URL untuk mendapatkan project_flock_kandang_id + const projectFlockKandangLookupUrl = useMemo(() => { + if (!selectedProjectFlock || !selectedKandang) return null; + const params = new URLSearchParams({ + project_flock_id: selectedProjectFlock.value.toString(), + kandang_id: selectedKandang.value.toString(), + }); + return `${ProjectFlockApi.basePath}/kandangs/lookup?${params.toString()}`; + }, [selectedProjectFlock, selectedKandang]); + + const { data: projectFlockKandangLookupData } = useSWR( + projectFlockKandangLookupUrl, + projectFlockKandangLookupUrl + ? () => + ProjectFlockApi.getAllFetcher( + projectFlockKandangLookupUrl + ) as Promise> + : null + ); + + const projectFlockKandangLookup = + projectFlockKandangLookupData?.status === 'success' + ? projectFlockKandangLookupData.data + : undefined; + + // Fetch project_flock_kandang detail untuk edit mode saja (tidak perlu untuk detail) + const projectFlockKandangDetailUrl = useMemo(() => { + if (type !== 'edit' || !initialValues?.project_flock_kandang_id) + return null; + return `${ProjectFlockKandangApi.basePath}/${initialValues.project_flock_kandang_id}`; + }, [type, initialValues?.project_flock_kandang_id]); + + const { data: projectFlockKandangDetailData } = useSWR( + projectFlockKandangDetailUrl, + projectFlockKandangDetailUrl + ? () => + ProjectFlockKandangApi.getAllFetcher( + projectFlockKandangDetailUrl + ) as Promise> + : null + ); + + const projectFlockKandangDetail = + projectFlockKandangDetailData?.status === 'success' + ? projectFlockKandangDetailData.data + : undefined; + + // Fetch approved project flock kandangs untuk filter kandang options + const approvedProjectFlockKandangsUrl = useMemo(() => { + const params = new URLSearchParams({ + step_name: 'Disetujui', + limit: '100', + }); + return `${ProjectFlockKandangApi.basePath}?${params.toString()}`; + }, []); + + const { data: approvedProjectFlockKandangsData } = useSWR( + approvedProjectFlockKandangsUrl, + ProjectFlockKandangApi.getAllFetcher + ); + + const approvedProjectFlockKandangs = useMemo(() => { + if (!isResponseSuccess(approvedProjectFlockKandangsData)) return []; + return approvedProjectFlockKandangsData.data; + }, [approvedProjectFlockKandangsData]); + + // Product select dengan filter project_flock_kandang_id - hanya fetch jika project_flock_kandang_id ada + const productUrl = useMemo(() => { + if (!projectFlockKandangLookup?.project_flock_kandang_id) return null; + const params = new URLSearchParams({ + project_flock_kandang_id: + projectFlockKandangLookup.project_flock_kandang_id.toString(), + page: '1', + limit: '10', + }); + return `${ProductApi.basePath}?${params.toString()}`; + }, [projectFlockKandangLookup?.project_flock_kandang_id]); + + const { data: productData, isLoading: isLoadingProductOptions } = useSWR( + productUrl, + productUrl ? ProductApi.getAllFetcher : null + ); + + const productOptions = useMemo(() => { + if (!isResponseSuccess(productData)) return []; + return productData.data.map((p: Product) => ({ + value: p.id, + label: p.name, + })); + }, [productData]); + + const setProductInputValue = useCallback((value: string) => { + // Implementasi search jika diperlukan + }, []); + + const loadMoreProducts = useCallback(() => { + // Implementasi load more jika diperlukan + }, []); + + // Kandang options dari project flock data (filtered by approved status untuk add mode) + const kandangOptions = useMemo(() => { + let options: OptionType[] = []; + + if (selectedProjectFlock && isResponseSuccess(projectFlocksRawData)) { + const data = projectFlocksRawData.data as ProjectFlock[]; + const selectedProjectFlockData = data.find( + (pf) => pf.id === selectedProjectFlock.value + ); + + if (selectedProjectFlockData?.kandangs) { + // Get approved kandang ids untuk project flock yang dipilih + const approvedKandangIds = approvedProjectFlockKandangs + .filter((pfk) => pfk.project_flock_id === selectedProjectFlock.value) + .map((pfk) => pfk.kandang_id); + + const kandangOptions = selectedProjectFlockData.kandangs + .filter((kandang: Kandang) => { + // Untuk add mode, hanya tampilkan kandang yang approved + if (type === 'add') { + return approvedKandangIds.includes(kandang.id); + } + return true; + }) + .map((kandang: Kandang) => ({ + value: kandang.id, + label: kandang.name || '', + })); + options = options.concat(kandangOptions); + } + } + + if (projectFlockKandangDetail && type === 'edit') { + const currentKandang = projectFlockKandangDetail.kandang; + if ( + currentKandang && + !options.find((opt) => opt.value === currentKandang.id) + ) { + options.push({ + value: currentKandang.id, + label: currentKandang.name || '', + }); + } + } + + return options; + }, [ + selectedProjectFlock, + projectFlocksRawData, + projectFlockKandangDetail, + type, + approvedProjectFlockKandangs, + ]); + + // Enhanced options untuk edit/detail + const enhancedLocationOptions = useMemo(() => { + const options = [...locationOptions]; + + if (projectFlockKandangDetail && (type === 'edit' || type === 'detail')) { + const currentLocation = projectFlockKandangDetail.project_flock.location; + if ( + currentLocation && + !options.find((opt) => opt.value === currentLocation.id) + ) { + options.push({ + value: currentLocation.id, + label: currentLocation.name || '', + }); + } + } + + return options; + }, [locationOptions, projectFlockKandangDetail, type]); + + const enhancedProjectFlockOptions = useMemo(() => { + const options = [...projectFlockOptions]; + + if (projectFlockKandangDetail && (type === 'edit' || type === 'detail')) { + const currentProjectFlock = projectFlockKandangDetail.project_flock; + if ( + currentProjectFlock && + !options.find((opt) => opt.value === currentProjectFlock.id) + ) { + options.push({ + value: currentProjectFlock.id, + label: currentProjectFlock.flock_name || '', + }); + } + } + + return options; + }, [projectFlockOptions, projectFlockKandangDetail, type]); + + // Formik Initial Values + const formikInitialValues = useMemo>( + () => ({ + location: null, + location_id: 0, + project_flock: null, + project_flock_id: 0, + kandang: null, + kandang_id: 0, + project_flock_kandang: null, + project_flock_kandang_id: 0, + product: null, + product_id: 0, + transaction_type: '', + transaction_subtype: '', + qty: '', + price: '', + notes: '', + }), + [] + ); // Formik const formik = useFormik({ - enableReinitialize: true, + enableReinitialize: false, initialValues: formikInitialValues as InventoryAdjustmentFormValues, validationSchema: InventoryAdjustmentFormSchema, onSubmit: async (values) => { setInventoryAdjustmentFormErrorMessage(''); const payload: CreateInventoryAdjustmentPayload = { - product_id: values.product_id as number, - warehouse_id: values.warehouse_id as number, - quantity: values.quantity as number, - transaction_type: values.transaction_type as string, - note: values.note, + project_flock_kandang_id: values.project_flock_kandang_id, + product_id: values.product_id, + transaction_subtype: values.transaction_subtype, + qty: Number(values.qty), + price: Number(values.price), + notes: values.notes, }; switch (type) { @@ -109,111 +353,318 @@ const InventoryAdjustmentForm = ({ }, }); - // Fetch Data - const { - setInputValue: setProductCategoryInputValue, - options: productCategoryOptions, - isLoadingOptions: isLoadingProductCategoryOptions, - loadMore: loadMoreProductCategories, - } = useSelect(ProductCategoryApi.basePath, 'id', 'name'); + // Transaction subtype options berdasarkan transaction_type + const transactionSubtypeOptions = useMemo(() => { + const transactionType = formik.values.transaction_type; - const { - setInputValue: setProductInputValue, - options: productOptions, - isLoadingOptions: isLoadingProductOptions, - loadMore: loadMoreProducts, - } = useSelect(ProductApi.basePath, 'id', 'name', 'search', { - product_category_id: formik.values.product_category_id - ? String(formik.values.product_category_id) - : '', - }); + if (transactionType === 'RECORDING') { + return TRANSACTION_SUBTYPE_OPTIONS.RECORDING; + } - const { - setInputValue: setWarehouseInputValue, - options: warehouseOptions, - isLoadingOptions: isLoadingWarehouseOptions, - loadMore: loadMoreWarehouses, - } = useSelect(WarehouseApi.basePath, 'id', 'name'); + return []; + }, [formik.values.transaction_type]); - // Options Handler - const productCategoryChangeHandler = ( - val: OptionType | OptionType[] | null - ) => { - formik.setFieldTouched('product_category_id', true); - formik.setFieldValue('product_category_id', (val as OptionType)?.value); + // Cek apakah subtype readonly (untuk PEMBELIAN/PENJUALAN) + const isTransactionSubtypeReadonly = useMemo(() => { + const transactionType = formik.values.transaction_type; + return transactionType === 'PEMBELIAN' || transactionType === 'PENJUALAN'; + }, [formik.values.transaction_type]); - formik.setFieldValue('product_category', val); + // Update quantity label berdasarkan transaction_subtype + useEffect(() => { + const subtype = formik.values.transaction_subtype; + if ( + subtype === 'RECORDING_STOCK_OUT' || + subtype === 'RECORDING_DEPLETION_OUT' || + subtype === 'MARKETING_OUT' + ) { + setQuantityLabel('Kurangi Stok'); + } else if ( + subtype === 'RECORDING_STOCK_IN' || + subtype === 'RECORDING_DEPLETION_IN' || + subtype === 'RECORDING_EGG_IN' || + subtype === 'PURCHASE_IN' + ) { + setQuantityLabel('Tambah Stok'); + } else { + setQuantityLabel('Kuantitas'); + } + }, [formik.values.transaction_subtype]); - const disabled = (val as OptionType)?.value == null; - setDisabledProduct(disabled); - formik.setFieldValue('product_id', 0); + // Event Handlers + const locationChangeHandler = (val: OptionType | OptionType[] | null) => { + const location = val as OptionType | null; + const locationId = location ? Number(location.value) : 0; + + formik.setFieldTouched('location', true); + formik.setFieldValue('location', location); + formik.setFieldTouched('location_id', true); + formik.setFieldValue('location_id', locationId); + + setSelectedLocation(location); + setSelectedProjectFlockLocationId( + location ? location.value.toString() : '' + ); + + // Reset dependent fields + setSelectedProjectFlock(null); + setSelectedKandang(null); + formik.setFieldValue('project_flock', null); + formik.setFieldValue('project_flock_id', 0); + formik.setFieldValue('kandang', null); + formik.setFieldValue('kandang_id', 0); + formik.setFieldValue('project_flock_kandang', null); + formik.setFieldValue('project_flock_kandang_id', 0); formik.setFieldValue('product', null); - formik.setFieldTouched('product', false); - formik.setFieldTouched('product_id', false); + formik.setFieldValue('product_id', 0); + }; + + const projectFlockChangeHandler = (val: OptionType | OptionType[] | null) => { + const projectFlock = val as OptionType | null; + const projectFlockId = Number(projectFlock?.value); + + formik.setFieldTouched('project_flock', true); + formik.setFieldValue('project_flock', projectFlock); + formik.setFieldTouched('project_flock_id', true); + formik.setFieldValue('project_flock_id', projectFlockId); + + setSelectedProjectFlock(projectFlock); + setSelectedKandang(null); + + // Reset dependent fields + formik.setFieldValue('kandang', null); + formik.setFieldValue('kandang_id', 0); + formik.setFieldValue('project_flock_kandang', null); + formik.setFieldValue('project_flock_kandang_id', 0); + formik.setFieldValue('product', null); + formik.setFieldValue('product_id', 0); + }; + + const kandangChangeHandler = (val: OptionType | OptionType[] | null) => { + const kandang = val as OptionType | null; + const kandangId = Number(kandang?.value); + + formik.setFieldTouched('kandang', true); + formik.setFieldValue('kandang', kandang); + formik.setFieldTouched('kandang_id', true); + formik.setFieldValue('kandang_id', kandangId); + + setSelectedKandang(kandang); + + // Reset product karena kandang berubah + formik.setFieldValue('product', null); + formik.setFieldValue('product_id', 0); + formik.setFieldTouched('project_flock_kandang', true); + formik.setFieldTouched('project_flock_kandang_id', true); }; const productChangeHandler = (val: OptionType | OptionType[] | null) => { + formik.setFieldTouched('product', true); formik.setFieldValue('product', val); - formik.setFieldTouched('product_id', true); - formik.setFieldValue('product_id', (val as OptionType)?.value); + formik.setFieldValue('product_id', (val as OptionType)?.value ?? 0); }; - const warehouseChangeHandler = (val: OptionType | OptionType[] | null) => { - formik.setFieldValue('warehouse', val); + const transactionTypeChangeHandler = ( + val: OptionType | OptionType[] | null + ) => { + const selectedType = (val as OptionType)?.value as string; - formik.setFieldTouched('warehouse_id', true); - formik.setFieldValue('warehouse_id', (val as OptionType)?.value); + formik.setFieldTouched('transaction_type', true); + formik.setFieldValue('transaction_type', selectedType); + + // Reset transaction_subtype + formik.setFieldValue('transaction_subtype', ''); + + // Auto-fill transaction_subtype untuk PEMBELIAN dan PENJUALAN + if (selectedType === 'PEMBELIAN') { + formik.setFieldValue( + 'transaction_subtype', + TRANSACTION_SUBTYPE_OPTIONS.PEMBELIAN.value + ); + } else if (selectedType === 'PENJUALAN') { + formik.setFieldValue( + 'transaction_subtype', + TRANSACTION_SUBTYPE_OPTIONS.PENJUALAN.value + ); + } + }; + + const transactionSubtypeChangeHandler = ( + val: OptionType | OptionType[] | null + ) => { + const selectedSubtype = (val as OptionType)?.value as string; + formik.setFieldTouched('transaction_subtype', true); + formik.setFieldValue('transaction_subtype', selectedSubtype); }; const resetHandler = () => { formik.resetForm(); - setQuantityLabel('Tambah Stok'); - productCategoryChangeHandler(null); - productChangeHandler(null); - warehouseChangeHandler(null); + setQuantityLabel('Kuantitas'); + setSelectedLocation(null); + setSelectedProjectFlock(null); + setSelectedKandang(null); + setSelectedProjectFlockLocationId(''); }; - const { setValues: formikSetValues } = formik; - - // Effect + // Effect - Set project_flock_kandang_id dari lookup useEffect(() => { - if (initialValues?.product_warehouse?.product?.id) { - setDisabledProduct(false); - formik.setFieldValue( - 'product_id', - initialValues.product_warehouse.product.id - ); - formik.setFieldValue('product', { - value: initialValues.product_warehouse.product.id, - label: initialValues.product_warehouse.product.name, - }); - formik.setFieldValue( - 'warehouse_id', - initialValues.product_warehouse.warehouse.id - ); - formik.setFieldValue('warehouse', { - value: initialValues.product_warehouse.warehouse.id, - label: initialValues.product_warehouse.warehouse.name, - }); - formik.setFieldValue( - 'quantity', - initialValues.product_warehouse.quantity - ); - formik.setFieldValue('note', initialValues.note); + if (projectFlockKandangLookup?.project_flock_kandang_id) { + const projectFlockKandangId = + projectFlockKandangLookup.project_flock_kandang_id; + + if (formik.values.project_flock_kandang_id !== projectFlockKandangId) { + formik.setFieldValue('project_flock_kandang_id', projectFlockKandangId); + formik.setFieldValue('project_flock_kandang', { + value: projectFlockKandangId, + label: `${projectFlockKandangLookup.project_flock.flock_name} - ${projectFlockKandangLookup.kandang.name}`, + }); + } } - }, [formik, initialValues, setQuantityLabel, setDisabledProduct]); - useEffect(() => { - formikSetValues(formikInitialValues as InventoryAdjustmentFormValues); - }, [formikSetValues, formikInitialValues]); + }, [projectFlockKandangLookup, formik.values.project_flock_kandang_id]); - // Utils Function - const formatNumber = (value: string) => { - const numericValue = value.replace(/[^0-9.]/g, ''); - const [integer, decimal] = numericValue.split('.'); - const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ','); - return decimal ? `${formattedInteger}.${decimal}` : formattedInteger; - }; + // Effect - Set initial values untuk edit mode (dengan projectFlockKandangDetail) + useEffect(() => { + if (initialValues && type === 'edit') { + const transactionSubtype = initialValues.transaction_subtype; + + // Determine transaction_type dari transaction_subtype + let transactionType = ''; + if (transactionSubtype === 'PURCHASE_IN') { + transactionType = 'PEMBELIAN'; + } else if (transactionSubtype === 'MARKETING_OUT') { + transactionType = 'PENJUALAN'; + } else if (transactionSubtype?.startsWith('RECORDING')) { + transactionType = 'RECORDING'; + } + + // Set lokasi + if (initialValues.location) { + const locationOption = { + value: initialValues.location.id, + label: initialValues.location.name, + }; + setSelectedLocation(locationOption); + setSelectedProjectFlockLocationId(initialValues.location.id.toString()); + } + + // Set project flock + if (initialValues.project_flock) { + const projectFlockOption = { + value: initialValues.project_flock.id, + label: initialValues.project_flock.flock_name, + }; + setSelectedProjectFlock(projectFlockOption); + } + + // Set kandang dari project_flock_kandang jika ada (hanya untuk edit mode) + if (projectFlockKandangDetail) { + const kandangOption = { + value: projectFlockKandangDetail.kandang.id, + label: projectFlockKandangDetail.kandang.name || '', + }; + setSelectedKandang(kandangOption); + } + + formik.setValues({ + location: initialValues.location + ? { + value: initialValues.location.id, + label: initialValues.location.name, + } + : null, + location_id: initialValues.location?.id ?? 0, + project_flock: initialValues.project_flock + ? { + value: initialValues.project_flock.id, + label: initialValues.project_flock.flock_name, + } + : null, + project_flock_id: initialValues.project_flock?.id ?? 0, + kandang: projectFlockKandangDetail?.kandang + ? { + value: projectFlockKandangDetail.kandang.id, + label: projectFlockKandangDetail.kandang.name || '', + } + : null, + kandang_id: projectFlockKandangDetail?.kandang?.id ?? 0, + project_flock_kandang: initialValues.project_flock_kandang_id + ? { + value: initialValues.project_flock_kandang_id, + label: `${initialValues.project_flock?.flock_name || ''} - ${projectFlockKandangDetail?.kandang?.name || ''}`, + } + : null, + project_flock_kandang_id: initialValues.project_flock_kandang_id ?? 0, + product: initialValues.product_warehouse?.product + ? { + value: initialValues.product_warehouse.product.id, + label: initialValues.product_warehouse.product.name, + } + : null, + product_id: initialValues.product_warehouse?.product?.id ?? 0, + transaction_type: transactionType, + transaction_subtype: transactionSubtype, + qty: initialValues.qty ?? '', + price: initialValues.price ?? '', + notes: initialValues.notes ?? '', + }); + } + }, [formik.setValues, initialValues, projectFlockKandangDetail, type]); + + // Effect - Set initial values untuk detail mode (tanpa projectFlockKandangDetail) + useEffect(() => { + if (initialValues && type === 'detail') { + const transactionSubtype = initialValues.transaction_subtype; + + // Determine transaction_type dari transaction_subtype + let transactionType = ''; + if (transactionSubtype === 'PURCHASE_IN') { + transactionType = 'PEMBELIAN'; + } else if (transactionSubtype === 'MARKETING_OUT') { + transactionType = 'PENJUALAN'; + } else if (transactionSubtype?.startsWith('RECORDING')) { + transactionType = 'RECORDING'; + } + + formik.setValues({ + location: initialValues.location + ? { + value: initialValues.location.id, + label: initialValues.location.name, + } + : null, + location_id: initialValues.location?.id ?? 0, + project_flock: initialValues.project_flock + ? { + value: initialValues.project_flock.id, + label: initialValues.project_flock.flock_name, + } + : null, + project_flock_id: initialValues.project_flock?.id ?? 0, + kandang: null, // Tidak perlu kandang untuk detail mode + kandang_id: 0, + project_flock_kandang: initialValues.project_flock_kandang_id + ? { + value: initialValues.project_flock_kandang_id, + label: `${initialValues.project_flock?.flock_name || ''} - Kandang`, + } + : null, + project_flock_kandang_id: initialValues.project_flock_kandang_id ?? 0, + product: initialValues.product_warehouse?.product + ? { + value: initialValues.product_warehouse.product.id, + label: initialValues.product_warehouse.product.name, + } + : null, + product_id: initialValues.product_warehouse?.product?.id ?? 0, + transaction_type: transactionType, + transaction_subtype: transactionSubtype, + qty: initialValues.qty ?? '', + price: initialValues.price ?? '', + notes: initialValues.notes ?? '', + }); + } + }, [formik.setValues, initialValues, type]); // ===== Formik Error List ===== const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); @@ -244,25 +695,60 @@ const InventoryAdjustmentForm = ({ className='w-full mt-8 flex flex-col gap-6' >
- {/* Select Input Product Category */} + {/* Select Input Location */} + {/* Select Input Project Flock */} + + + {/* Select Input Kandang */} + + {/* Select Input Product */} - {/* Select Input Warehouse */} + {/* Select Input Transaction Type */} - - {/* Radio Button Flag Stock */} - { - formik.handleChange(e); - setQuantityLabel( - e.target.value === 'increase' ? 'Tambah Stok' : 'Kurangi Stok' - ); - }} - onBlur={formik.handleBlur} + value={ + formik.values.transaction_type + ? { + value: formik.values.transaction_type, + label: + TRANSACTION_TYPE_OPTIONS.find( + (opt) => opt.value === formik.values.transaction_type + )?.label || '', + } + : null + } + onChange={transactionTypeChangeHandler} + options={TRANSACTION_TYPE_OPTIONS} isError={ formik.touched.transaction_type && Boolean(formik.errors.transaction_type) } errorMessage={formik.errors.transaction_type as string} - color='primary' - required - bottomLabel={ - formik.values.transaction_type == undefined - ? 'Pilih salah satu tipe transaksi' - : undefined - } - disabled={type === 'detail'} + isDisabled={type === 'detail'} + placeholder='Pilih Tipe Transaksi' + isClearable /> - {/* Number Input Stock */} - + opt.value === + formik.values.transaction_subtype + )?.label || '', + } + : null + } + onChange={transactionSubtypeChangeHandler} + options={transactionSubtypeOptions} + isError={ + formik.touched.transaction_subtype && + Boolean(formik.errors.transaction_subtype) + } + errorMessage={formik.errors.transaction_subtype as string} + isDisabled={ + type === 'detail' || + isTransactionSubtypeReadonly || + formik.values.transaction_type === '' + } + placeholder={ + formik.values.transaction_type === '' + ? 'Pilih Tipe Transaksi terlebih dahulu' + : isTransactionSubtypeReadonly + ? 'Otomatis terisi' + : 'Pilih Sub Tipe Transaksi' + } + isClearable + /> + + {/* Number Input Quantity */} + { - const rawValue = e.target.value.replace(/,/g, ''); - const numericValue = parseFloat(rawValue); - if (!isNaN(numericValue)) { - formik.setFieldValue('quantity', numericValue); - } else { - formik.setFieldValue('quantity', 0); - } - }} + name='qty' + value={formik.values.qty} + onChange={formik.handleChange} onBlur={formik.handleBlur} - isError={ - formik.touched.quantity && Boolean(formik.errors.quantity) - } - errorMessage={formik.errors.quantity as string} + isError={formik.touched.qty && Boolean(formik.errors.qty)} + errorMessage={formik.errors.qty as string} readOnly={type === 'detail'} /> - {/* Text Area Input Reason */} -