fix: adjust stock, depletion, and egg select input

This commit is contained in:
ValdiANS
2026-05-02 17:04:59 +07:00
parent ff92073d19
commit 28a1852de8
3 changed files with 107 additions and 69 deletions
@@ -5,6 +5,7 @@ import {
CreateLayingRecordingPayload, CreateLayingRecordingPayload,
CreateEggPayload, CreateEggPayload,
} from '@/types/api/production/recording'; } from '@/types/api/production/recording';
import { getProductWarehouseOptionLabel } from '@/lib/product-warehouse';
type RecordingGrowingFormSchemaType = { type RecordingGrowingFormSchemaType = {
record_date: string; record_date: string;
@@ -29,11 +30,19 @@ type RecordingGrowingFormSchemaType = {
} | null; } | null;
project_flock_kandang_id: number; project_flock_kandang_id: number;
stocks: { stocks: {
product_warehouse_id: number; product_warehouse_id:
| {
value: number;
label: string;
}
| undefined;
qty: number | string; qty: number | string;
}[]; }[];
depletions: { depletions: {
product_warehouse_id?: number; product_warehouse_id?: {
value: number;
label: string;
};
source_product_warehouse_id?: number; source_product_warehouse_id?: number;
qty?: number | string; qty?: number | string;
}[]; }[];
@@ -41,34 +50,48 @@ type RecordingGrowingFormSchemaType = {
type RecordingLayingFormSchemaType = RecordingGrowingFormSchemaType & { type RecordingLayingFormSchemaType = RecordingGrowingFormSchemaType & {
eggs: { eggs: {
product_warehouse_id?: number; product_warehouse_id?: {
value: number;
label: string;
};
qty?: number | string; qty?: number | string;
weight?: number | string; weight?: number | string;
}[]; }[];
}; };
export type StockSchema = { export type StockSchema = {
product_warehouse_id: number; product_warehouse_id: {
value: number;
label: string;
};
qty: number | string; qty: number | string;
}; };
export type DepletionSchema = { export type DepletionSchema = {
product_warehouse_id?: number; product_warehouse_id?: {
value: number;
label: string;
};
source_product_warehouse_id?: number; source_product_warehouse_id?: number;
qty?: number | string; qty?: number | string;
}; };
export type EggSchema = { export type EggSchema = {
product_warehouse_id?: number; product_warehouse_id?: {
value: number;
label: string;
};
qty?: number | string; qty?: number | string;
weight?: number | string; weight?: number | string;
}; };
const StockObjectSchema: Yup.ObjectSchema<StockSchema> = Yup.object({ const StockObjectSchema: Yup.ObjectSchema<StockSchema> = Yup.object({
product_warehouse_id: Yup.number() product_warehouse_id: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
})
.required('Produk wajib diisi!') .required('Produk wajib diisi!')
.min(1, 'Produk wajib diisi!') .typeError('Produk wajib diisi!'),
.typeError('Produk harus berupa angka!'),
qty: Yup.number() qty: Yup.number()
.required('Jumlah penggunaan wajib diisi!') .required('Jumlah penggunaan wajib diisi!')
.moreThan(0, 'Jumlah penggunaan harus lebih dari 0!') .moreThan(0, 'Jumlah penggunaan harus lebih dari 0!')
@@ -76,7 +99,10 @@ const StockObjectSchema: Yup.ObjectSchema<StockSchema> = Yup.object({
}); });
const DepletionObjectSchema: Yup.ObjectSchema<DepletionSchema> = Yup.object({ const DepletionObjectSchema: Yup.ObjectSchema<DepletionSchema> = Yup.object({
product_warehouse_id: Yup.number() product_warehouse_id: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
})
.optional() .optional()
.typeError('Depletions harus berupa angka!'), .typeError('Depletions harus berupa angka!'),
source_product_warehouse_id: Yup.number() source_product_warehouse_id: Yup.number()
@@ -88,7 +114,10 @@ const DepletionObjectSchema: Yup.ObjectSchema<DepletionSchema> = Yup.object({
}); });
const EggObjectSchema: Yup.ObjectSchema<EggSchema> = Yup.object({ const EggObjectSchema: Yup.ObjectSchema<EggSchema> = Yup.object({
product_warehouse_id: Yup.number() product_warehouse_id: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
})
.optional() .optional()
.typeError('Kondisi telur harus berupa angka!'), .typeError('Kondisi telur harus berupa angka!'),
qty: Yup.number().optional().typeError('Jumlah telur harus berupa angka!'), qty: Yup.number().optional().typeError('Jumlah telur harus berupa angka!'),
@@ -248,14 +277,17 @@ export const getRecordingGrowingFormInitialValues = (
initialValues?.project_flock?.project_flock_kandang_id ?? initialValues?.project_flock?.project_flock_kandang_id ??
0, 0,
stocks: initialValues?.stocks?.map((stock) => ({ stocks: initialValues?.stocks?.map((stock) => ({
product_warehouse_id: stock.product_warehouse_id, product_warehouse_id: {
value: stock.product_warehouse_id,
label: getProductWarehouseOptionLabel(stock.product_warehouse),
},
qty: qty:
(stock as { qty?: number; usage_amount?: number }).qty || (stock as { qty?: number; usage_amount?: number }).qty ||
(stock as { qty?: number; usage_amount?: number }).usage_amount || (stock as { qty?: number; usage_amount?: number }).usage_amount ||
'', '',
})) ?? [ })) ?? [
{ {
product_warehouse_id: 0, product_warehouse_id: undefined,
qty: '', qty: '',
}, },
], ],
@@ -263,13 +295,16 @@ export const getRecordingGrowingFormInitialValues = (
( (
depletion: NonNullable<CreateGrowingRecordingPayload['depletions']>[0] depletion: NonNullable<CreateGrowingRecordingPayload['depletions']>[0]
) => ({ ) => ({
product_warehouse_id: depletion.product_warehouse_id, product_warehouse_id: {
value: Number(depletion.product_warehouse_id ?? 0),
label: getProductWarehouseOptionLabel(depletion.product_warehouse),
},
source_product_warehouse_id: depletion.source_product_warehouse_id, source_product_warehouse_id: depletion.source_product_warehouse_id,
qty: depletion.qty, qty: depletion.qty,
}) })
) ?? [ ) ?? [
{ {
product_warehouse_id: 0, product_warehouse_id: undefined,
qty: '', qty: '',
}, },
], ],
@@ -281,12 +316,15 @@ export const getRecordingLayingFormInitialValues = (
...getRecordingGrowingFormInitialValues(initialValues), ...getRecordingGrowingFormInitialValues(initialValues),
eggs: initialValues?.eggs?.map((egg: CreateEggPayload) => ({ eggs: initialValues?.eggs?.map((egg: CreateEggPayload) => ({
product_warehouse_id: egg.product_warehouse_id, product_warehouse_id: {
value: Number(egg.product_warehouse_id ?? 0),
label: getProductWarehouseOptionLabel(egg.product_warehouse),
},
qty: egg.qty, qty: egg.qty,
weight: egg.weight, weight: egg.weight,
})) ?? [ })) ?? [
{ {
product_warehouse_id: 0, product_warehouse_id: undefined,
qty: '', qty: '',
weight: '', weight: '',
}, },
@@ -522,7 +522,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
? values.depletions ? values.depletions
?.filter((d) => d.product_warehouse_id && d.qty) ?.filter((d) => d.product_warehouse_id && d.qty)
.map((depletion) => ({ .map((depletion) => ({
product_warehouse_id: depletion.product_warehouse_id!, product_warehouse_id: depletion.product_warehouse_id?.value ?? 0,
...(depletion.source_product_warehouse_id && { ...(depletion.source_product_warehouse_id && {
source_product_warehouse_id: source_product_warehouse_id:
depletion.source_product_warehouse_id, depletion.source_product_warehouse_id,
@@ -533,13 +533,13 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
const stocks = recordingRestriction.canEditStock const stocks = recordingRestriction.canEditStock
? (values.stocks ?? []) ? (values.stocks ?? [])
.filter((s) => s.product_warehouse_id && s.qty) .filter((s) => s.product_warehouse_id?.value && s.qty)
.map((stock) => ({ .map((stock) => ({
// In migration mode, product_warehouse_id field holds product.id; // In migration mode, product_warehouse_id field holds product.id;
// send it as product_id so the backend auto-creates the warehouse entry. // send it as product_id so the backend auto-creates the warehouse entry.
...(isMigrationMode ...(isMigrationMode
? { product_id: stock.product_warehouse_id } ? { product_id: stock.product_warehouse_id?.value }
: { product_warehouse_id: stock.product_warehouse_id }), : { product_warehouse_id: stock.product_warehouse_id?.value }),
qty: Number(stock.qty) || 0, qty: Number(stock.qty) || 0,
})) }))
: []; : [];
@@ -561,9 +561,9 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
const createLayingPayload = useCallback( const createLayingPayload = useCallback(
(values: RecordingLayingFormValues) => { (values: RecordingLayingFormValues) => {
const depletions = values.depletions const depletions = values.depletions
?.filter((d) => d.product_warehouse_id && d.qty) ?.filter((d) => d.product_warehouse_id?.value && d.qty)
.map((depletion) => ({ .map((depletion) => ({
product_warehouse_id: depletion.product_warehouse_id!, product_warehouse_id: depletion.product_warehouse_id?.value ?? 0,
...(depletion.source_product_warehouse_id && { ...(depletion.source_product_warehouse_id && {
source_product_warehouse_id: depletion.source_product_warehouse_id, source_product_warehouse_id: depletion.source_product_warehouse_id,
}), }),
@@ -573,7 +573,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
const eggs = values.eggs const eggs = values.eggs
?.filter((e) => e.product_warehouse_id && e.qty && e.weight) ?.filter((e) => e.product_warehouse_id && e.qty && e.weight)
.map((egg) => ({ .map((egg) => ({
product_warehouse_id: egg.product_warehouse_id!, product_warehouse_id: egg.product_warehouse_id?.value ?? 0,
qty: Number(egg.qty) || 0, qty: Number(egg.qty) || 0,
weight: weight:
typeof egg.weight === 'number' typeof egg.weight === 'number'
@@ -583,11 +583,11 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
const stocks = recordingRestriction.canEditStock const stocks = recordingRestriction.canEditStock
? values.stocks ? values.stocks
.filter((s) => s.product_warehouse_id && s.qty) .filter((s) => s.product_warehouse_id?.value && s.qty)
.map((stock) => ({ .map((stock) => ({
...(isMigrationMode ...(isMigrationMode
? { product_id: stock.product_warehouse_id } ? { product_id: stock.product_warehouse_id?.value }
: { product_warehouse_id: stock.product_warehouse_id }), : { product_warehouse_id: stock.product_warehouse_id?.value }),
qty: Number(stock.qty) || 0, qty: Number(stock.qty) || 0,
})) }))
: []; : [];
@@ -1283,8 +1283,12 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
// product_warehouse object returned by the API. // product_warehouse object returned by the API.
if (isMigrationMode && type === 'edit' && initialValues?.stocks?.length) { if (isMigrationMode && type === 'edit' && initialValues?.stocks?.length) {
baseValues.stocks = initialValues.stocks.map((stock) => ({ baseValues.stocks = initialValues.stocks.map((stock) => ({
product_warehouse_id: product_warehouse_id: {
stock.product_warehouse?.product_id ?? stock.product_warehouse_id, value: Number(
stock.product_warehouse?.product_id ?? stock.product_warehouse_id
),
label: getProductWarehouseOptionLabel(stock.product_warehouse),
},
qty: stock.usage_amount ?? '', qty: stock.usage_amount ?? '',
})); }));
} }
@@ -1438,8 +1442,12 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
formik.setFieldValue( formik.setFieldValue(
'stocks', 'stocks',
initialValues.stocks.map((stock) => ({ initialValues.stocks.map((stock) => ({
product_warehouse_id: product_warehouse_id: {
stock.product_warehouse?.product_id ?? stock.product_warehouse_id, value: Number(
stock.product_warehouse?.product_id ?? stock.product_warehouse_id
),
label: getProductWarehouseOptionLabel(stock.product_warehouse),
},
qty: stock.usage_amount ?? '', qty: stock.usage_amount ?? '',
})) }))
); );
@@ -1462,7 +1470,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
(stockIdx: number) => { (stockIdx: number) => {
if ((type as 'add' | 'edit' | 'detail') === 'detail') return null; if ((type as 'add' | 'edit' | 'detail') === 'detail') return null;
const stock = formik.values.stocks?.[stockIdx]; const stock = formik.values.stocks?.[stockIdx];
if (!stock || !stock.product_warehouse_id) return null; if (!stock || !stock.product_warehouse_id?.value) return null;
return null; return null;
}, },
[formik.values.stocks, type] [formik.values.stocks, type]
@@ -1492,13 +1500,17 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
const getStockUsageAdornment = useCallback( const getStockUsageAdornment = useCallback(
(stockIdx: number) => { (stockIdx: number) => {
const stock = formik.values.stocks?.[stockIdx]; const stock = formik.values.stocks?.[stockIdx];
if (!stock || !stock.product_warehouse_id) return null; if (!stock || !stock.product_warehouse_id?.value) return null;
const isDetail = (type as 'add' | 'edit' | 'detail') === 'detail'; const isDetail = (type as 'add' | 'edit' | 'detail') === 'detail';
const availableStock = getAvailableStock(stock.product_warehouse_id); const availableStock = getAvailableStock(
stock.product_warehouse_id.value
);
const requestedUsage = Number(stock.qty) || 0; const requestedUsage = Number(stock.qty) || 0;
const remainingStock = availableStock - requestedUsage; const remainingStock = availableStock - requestedUsage;
const { pendingQty } = getStockPendingInfo(stock.product_warehouse_id); const { pendingQty } = getStockPendingInfo(
stock.product_warehouse_id.value
);
if (isDetail) { if (isDetail) {
if (pendingQty > 0) { if (pendingQty > 0) {
@@ -1605,10 +1617,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
return ( return (
idx !== currentIdx && idx !== currentIdx &&
s.product_warehouse_id && s.product_warehouse_id &&
s.product_warehouse_id !== 0 s.product_warehouse_id.value !== 0
); );
}) })
.map((s) => s.product_warehouse_id) || []; .map((s) => s.product_warehouse_id?.value) || [];
return unifiedStockProducts.filter( return unifiedStockProducts.filter(
(opt) => !selectedProductIds.includes(Number(opt.value)) (opt) => !selectedProductIds.includes(Number(opt.value))
@@ -1625,10 +1637,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
return ( return (
idx !== currentIdx && idx !== currentIdx &&
d.product_warehouse_id && d.product_warehouse_id &&
d.product_warehouse_id !== 0 d.product_warehouse_id.value !== 0
); );
}) })
.map((d) => d.product_warehouse_id) || []; .map((d) => d.product_warehouse_id?.value) || [];
return depletionProducts.filter( return depletionProducts.filter(
(opt) => !selectedProductIds.includes(Number(opt.value)) (opt) => !selectedProductIds.includes(Number(opt.value))
@@ -1645,10 +1657,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
return ( return (
idx !== currentIdx && idx !== currentIdx &&
e.product_warehouse_id && e.product_warehouse_id &&
e.product_warehouse_id !== 0 e.product_warehouse_id.value !== 0
); );
}) })
.map((e) => e.product_warehouse_id) || []; .map((e) => e.product_warehouse_id?.value) || [];
return eggProducts.filter( return eggProducts.filter(
(opt) => !selectedProductIds.includes(Number(opt.value)) (opt) => !selectedProductIds.includes(Number(opt.value))
@@ -1694,7 +1706,9 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
isError: touchedField && Boolean(errorField?.[column]), isError: touchedField && Boolean(errorField?.[column]),
errorMessage: errorMessage:
touchedField && errorField?.[column] touchedField && errorField?.[column]
? (errorField[column] as string) ? errorField[column] instanceof Object
? (errorField[column] as OptionType)?.label
: (errorField[column] as string)
: '', : '',
}; };
}; };
@@ -2901,20 +2915,15 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
<td> <td>
<SelectInput <SelectInput
required required
key={`stock-product-${idx}-${stock.product_warehouse_id}`} key={`stock-product-${idx}-${stock.product_warehouse_id?.value}`}
value={ value={stock.product_warehouse_id}
unifiedStockProducts.find(
(product) =>
product.value === stock.product_warehouse_id
) || null
}
onInputChange={setStockInputValue} onInputChange={setStockInputValue}
onChange={(selectedOption) => { onChange={(selectedOption) => {
const option = const option =
selectedOption as OptionType | null; selectedOption as OptionType | null;
formik.setFieldValue( formik.setFieldValue(
`stocks.${idx}.product_warehouse_id`, `stocks.${idx}.product_warehouse_id`,
option?.value || 0 option
); );
}} }}
options={getAvailableStockProductOptions(idx)} options={getAvailableStockProductOptions(idx)}
@@ -2950,9 +2959,9 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
} }
isClearable={type !== 'detail'} isClearable={type !== 'detail'}
inputPrefix={ inputPrefix={
stock.product_warehouse_id stock.product_warehouse_id?.value
? getProductFlagBadgeAdornment( ? getProductFlagBadgeAdornment(
stock.product_warehouse_id stock.product_warehouse_id.value
) )
: undefined : undefined
} }
@@ -2988,7 +2997,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
inputSuffix={ inputSuffix={
stock.product_warehouse_id stock.product_warehouse_id
? getProductUomSuffix( ? getProductUomSuffix(
stock.product_warehouse_id, stock.product_warehouse_id.value,
'stock' 'stock'
) )
: null : null
@@ -3181,19 +3190,13 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
)} )}
<td> <td>
<SelectInput <SelectInput
value={ value={depletion.product_warehouse_id}
depletionProducts.find(
(product) =>
product.value ===
depletion.product_warehouse_id
) || null
}
onChange={(selectedOption) => { onChange={(selectedOption) => {
const option = const option =
selectedOption as OptionType | null; selectedOption as OptionType | null;
formik.setFieldValue( formik.setFieldValue(
`depletions.${idx}.product_warehouse_id`, `depletions.${idx}.product_warehouse_id`,
option?.value || 0 option
); );
}} }}
options={getAvailableDepletionProductOptions(idx)} options={getAvailableDepletionProductOptions(idx)}
@@ -3256,7 +3259,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
inputSuffix={ inputSuffix={
depletion.product_warehouse_id depletion.product_warehouse_id
? getProductUomSuffix( ? getProductUomSuffix(
depletion.product_warehouse_id, depletion.product_warehouse_id.value,
'depletion' 'depletion'
) )
: null : null
@@ -3434,18 +3437,13 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
)} )}
<td> <td>
<SelectInput <SelectInput
value={ value={egg.product_warehouse_id}
eggProducts.find(
(product) =>
product.value === egg.product_warehouse_id
) || null
}
onChange={(selectedOption) => { onChange={(selectedOption) => {
const option = const option =
selectedOption as OptionType | null; selectedOption as OptionType | null;
formik.setFieldValue( formik.setFieldValue(
`eggs.${idx}.product_warehouse_id`, `eggs.${idx}.product_warehouse_id`,
option?.value || 0 option
); );
}} }}
options={getAvailableEggProductOptions(idx)} options={getAvailableEggProductOptions(idx)}
+2
View File
@@ -117,6 +117,7 @@ export type CreateGrowingRecordingPayload = {
product_warehouse_id?: number; product_warehouse_id?: number;
source_product_warehouse_id?: number; source_product_warehouse_id?: number;
qty?: number; qty?: number;
product_warehouse?: ProductWarehouse;
}[]; }[];
}; };
@@ -124,6 +125,7 @@ export type CreateEggPayload = {
product_warehouse_id?: number; product_warehouse_id?: number;
qty?: number; qty?: number;
weight?: number; weight?: number;
product_warehouse?: ProductWarehouse;
}; };
export type CreateLayingRecordingPayload = CreateGrowingRecordingPayload & { export type CreateLayingRecordingPayload = CreateGrowingRecordingPayload & {