refactor(FE): Filter products by available stock and format qty

This commit is contained in:
rstubryan
2026-01-23 13:21:12 +07:00
parent 1d29f62bf2
commit 1b3dd34add
@@ -18,6 +18,7 @@ import {
Movement, Movement,
} from '@/types/api/inventory/movement'; } from '@/types/api/inventory/movement';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { formatNumber } from '@/lib/helper';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { import {
MovementFormSchema, MovementFormSchema,
@@ -740,12 +741,32 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
return ( return (
formik.values.products formik.values.products
?.filter((p) => p.product) ?.filter((p) => p.product)
.map((p) => ({ .map((p) => {
value: p.product_id, const totalQtyUsed =
label: (p.product as OptionType)?.label, formik.values.deliveries?.reduce((total, d) => {
})) ?? [] const productQty = d.products.reduce((sum, deliveryProduct) => {
if (deliveryProduct.product_id === p.product_id) {
return sum + (Number(deliveryProduct.product_qty) || 0);
}
return sum;
}, 0);
return total + productQty;
}, 0) || 0;
const availableQty = Number(p.product_qty) - totalQtyUsed;
if (availableQty > 0) {
return {
value: p.product_id,
label: (p.product as OptionType)?.label,
};
}
return null;
})
.filter((option) => option !== null) ?? []
); );
}, [formik.values.products]); }, [formik.values.products, formik.values.deliveries]);
const getAvailableStock = useCallback( const getAvailableStock = useCallback(
(productId: number) => { (productId: number) => {
@@ -769,10 +790,10 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
const remainingStock = availableStock - requestedQty; const remainingStock = availableStock - requestedQty;
if (requestedQty > 0) { if (requestedQty > 0) {
return `Sisa: ${remainingStock.toLocaleString('en-US')}`; return `Sisa: ${formatNumber(remainingStock)}`;
} }
return `Tersedia: ${availableStock.toLocaleString('en-US')}`; return `Tersedia: ${formatNumber(availableStock)}`;
}, },
[formik.values.products, getAvailableStock, type] [formik.values.products, getAvailableStock, type]
); );
@@ -792,12 +813,9 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
if (!relatedProduct) return undefined; if (!relatedProduct) return undefined;
const totalQtyUsed = const totalQtyUsed =
formik.values.deliveries?.reduce((total, d, dIdx) => { formik.values.deliveries?.reduce((total, d) => {
const productQty = d.products.reduce((sum, p, pIdx) => { const productQty = d.products.reduce((sum, p) => {
if ( if (p.product_id === deliveryProduct.product_id) {
p.product_id === deliveryProduct.product_id &&
!(dIdx === deliveryIdx && pIdx === productIdx)
) {
return sum + (Number(p.product_qty) || 0); return sum + (Number(p.product_qty) || 0);
} }
return sum; return sum;
@@ -806,7 +824,10 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
}, 0) || 0; }, 0) || 0;
const availableQty = Number(relatedProduct.product_qty) - totalQtyUsed; const availableQty = Number(relatedProduct.product_qty) - totalQtyUsed;
return `Tersedia: ${availableQty.toLocaleString('en-US')}`;
const displayQty = availableQty > 0 ? availableQty : 0;
return `Tersedia: ${formatNumber(displayQty)}`;
}, },
[formik.values.deliveries, formik.values.products, type] [formik.values.deliveries, formik.values.products, type]
); );
@@ -856,7 +877,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
const requestedQty = Number(product.product_qty) || 0; const requestedQty = Number(product.product_qty) || 0;
if (requestedQty > availableStock) { if (requestedQty > availableStock) {
return `Qty melebihi stok tersedia! Maksimal: ${availableStock.toLocaleString('en-US')}`; return `Qty melebihi stok tersedia! Maksimal: ${formatNumber(availableStock)}`;
} }
return null; return null;