mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
feat(FE): Validate quantity against available stock
This commit is contained in:
@@ -46,6 +46,7 @@ import {
|
||||
TRANSACTION_SUBTYPE_OPTIONS,
|
||||
} from '@/config/constant';
|
||||
import NumberInput from '@/components/input/NumberInput';
|
||||
import { formatNumber } from '@/lib/helper';
|
||||
|
||||
interface InventoryAdjustmentFormProps {
|
||||
type?: 'add' | 'detail';
|
||||
@@ -62,6 +63,7 @@ const InventoryAdjustmentForm = ({
|
||||
setInventoryAdjustmentFormErrorMessage,
|
||||
] = useState('');
|
||||
const [quantityLabel, setQuantityLabel] = useState('Kuantitas');
|
||||
const [quantityError, setQuantityError] = useState<string>('');
|
||||
|
||||
const [selectedLocation, setSelectedLocation] = useState<OptionType | null>(
|
||||
null
|
||||
@@ -211,6 +213,25 @@ const InventoryAdjustmentForm = ({
|
||||
: [];
|
||||
}, [productWarehouses]);
|
||||
|
||||
// Get available quantity from selected product
|
||||
const selectedProductQuantity = useMemo(() => {
|
||||
if (!selectedProduct) return 0;
|
||||
const product = productOptions.find(
|
||||
(opt) => opt.value === selectedProduct.value
|
||||
);
|
||||
return product?.quantity ?? 0;
|
||||
}, [selectedProduct, productOptions]);
|
||||
|
||||
// Check if current transaction subtype reduces stock
|
||||
const isStockOutSubtype = useMemo(() => {
|
||||
const subtype = selectedTransactionSubtype?.value;
|
||||
return (
|
||||
subtype === 'RECORDING_STOCK_OUT' ||
|
||||
subtype === 'RECORDING_DEPLETION_OUT' ||
|
||||
subtype === 'MARKETING_OUT'
|
||||
);
|
||||
}, [selectedTransactionSubtype]);
|
||||
|
||||
const selectedProductFlags = useMemo(() => {
|
||||
if (!selectedProduct) return [];
|
||||
const product = productOptions.find(
|
||||
@@ -372,6 +393,28 @@ const InventoryAdjustmentForm = ({
|
||||
}
|
||||
}, [selectedTransactionSubtype]);
|
||||
|
||||
// Validate quantity against available stock
|
||||
useEffect(() => {
|
||||
const qty = Number(formik.values.qty);
|
||||
if (
|
||||
isStockOutSubtype &&
|
||||
selectedProduct &&
|
||||
qty > 0 &&
|
||||
qty > selectedProductQuantity
|
||||
) {
|
||||
setQuantityError(
|
||||
`Kuantitas ${formatNumber(qty)} melebihi stok tersedia (${formatNumber(selectedProductQuantity)})`
|
||||
);
|
||||
} else {
|
||||
setQuantityError('');
|
||||
}
|
||||
}, [
|
||||
formik.values.qty,
|
||||
isStockOutSubtype,
|
||||
selectedProduct,
|
||||
selectedProductQuantity,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedTransactionType?.value === 'RECORDING' && selectedProduct) {
|
||||
setSelectedTransactionSubtype(null);
|
||||
@@ -804,11 +847,18 @@ const InventoryAdjustmentForm = ({
|
||||
value={formik.values.qty}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
isError={formik.touched.qty && Boolean(formik.errors.qty)}
|
||||
errorMessage={formik.errors.qty as string}
|
||||
isError={
|
||||
(formik.touched.qty && Boolean(formik.errors.qty)) ||
|
||||
Boolean(quantityError)
|
||||
}
|
||||
errorMessage={(formik.errors.qty as string) || quantityError}
|
||||
readOnly={type === 'detail'}
|
||||
bottomLabel={
|
||||
selectedProduct
|
||||
? `Kuantitas: ${formatNumber(selectedProductQuantity)}`
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Number Input Price */}
|
||||
<NumberInput
|
||||
required
|
||||
@@ -856,7 +906,7 @@ const InventoryAdjustmentForm = ({
|
||||
type='submit'
|
||||
color='primary'
|
||||
isLoading={formik.isSubmitting}
|
||||
disabled={formik.isSubmitting}
|
||||
disabled={formik.isSubmitting || Boolean(quantityError)}
|
||||
className='px-4 w-full sm:w-auto'
|
||||
>
|
||||
Submit
|
||||
|
||||
Reference in New Issue
Block a user