Compare commits

...

4 Commits

Author SHA1 Message Date
rstubryan 3b9bd3c5bd Revert "refactor(FE): Prevent adding recordings for kandangs in transition"
This reverts commit 9dc30c1f58.
2026-03-09 03:50:33 +07:00
rstubryan 9dc30c1f58 refactor(FE): Prevent adding recordings for kandangs in transition 2026-03-09 03:35:03 +07:00
rstubryan 671fd72141 refactor(FE): Make stock fields optional during transition to laying 2026-03-09 03:32:44 +07:00
rstubryan d236138aa7 refactor(FE): Update recording editability logic and extend
BaseRecording type
2026-03-09 03:18:41 +07:00
4 changed files with 72 additions and 38 deletions
@@ -105,11 +105,11 @@ const RowOptionsMenu = ({
}; };
const isRecordingEditable = (recording: Recording) => { const isRecordingEditable = (recording: Recording) => {
if ( if (recording.project_flock?.project_flock_category === 'GROWING') {
recording.executed_at && if (recording.transfer_executed) {
recording.project_flock?.project_flock_category === 'GROWING' return false;
) { }
return false; return recording.population_can_change === true;
} }
return true; return true;
}; };
@@ -29,8 +29,8 @@ type RecordingGrowingFormSchemaType = {
} | null; } | null;
project_flock_kandang_id: number; project_flock_kandang_id: number;
stocks: { stocks: {
product_warehouse_id: number; product_warehouse_id?: number;
qty: number | string; qty?: number | string;
}[]; }[];
depletions: { depletions: {
product_warehouse_id?: number; product_warehouse_id?: number;
@@ -73,6 +73,18 @@ const StockObjectSchema: Yup.ObjectSchema<StockSchema> = Yup.object({
.typeError('Jumlah penggunaan harus berupa angka!'), .typeError('Jumlah penggunaan harus berupa angka!'),
}); });
const OptionalStockObjectSchema: Yup.ObjectSchema<{
product_warehouse_id?: number;
qty?: number | string;
}> = Yup.object({
product_warehouse_id: Yup.number()
.optional()
.typeError('Produk harus berupa angka!'),
qty: Yup.number()
.optional()
.typeError('Jumlah penggunaan harus berupa angka!'),
});
const DepletionObjectSchema: Yup.ObjectSchema<DepletionSchema> = Yup.object({ const DepletionObjectSchema: Yup.ObjectSchema<DepletionSchema> = Yup.object({
product_warehouse_id: Yup.number() product_warehouse_id: Yup.number()
.optional() .optional()
@@ -90,7 +102,9 @@ const EggObjectSchema: Yup.ObjectSchema<EggSchema> = Yup.object({
weight: Yup.number().optional().typeError('Berat telur harus berupa angka!'), weight: Yup.number().optional().typeError('Berat telur harus berupa angka!'),
}); });
export const RecordingGrowingFormSchema: Yup.ObjectSchema<RecordingGrowingFormSchemaType> = export const RecordingGrowingFormSchema = (
isTransitioningToLaying = false
): Yup.ObjectSchema<RecordingGrowingFormSchemaType> =>
Yup.object({ Yup.object({
record_date: Yup.string() record_date: Yup.string()
.required('Tanggal recording wajib diisi!') .required('Tanggal recording wajib diisi!')
@@ -150,20 +164,24 @@ export const RecordingGrowingFormSchema: Yup.ObjectSchema<RecordingGrowingFormSc
return true; return true;
} }
), ),
stocks: Yup.array() stocks: isTransitioningToLaying
.of(StockObjectSchema) ? Yup.array().of(OptionalStockObjectSchema).default([])
.min(1, 'Minimal harus ada 1 data stok!') : Yup.array()
.required('Data stok wajib diisi!'), .of(StockObjectSchema)
.min(1, 'Minimal harus ada 1 data stok!')
.required('Data stok wajib diisi!'),
depletions: Yup.array().of(DepletionObjectSchema).default([]), depletions: Yup.array().of(DepletionObjectSchema).default([]),
}); });
export const RecordingLayingFormSchema: Yup.ObjectSchema<RecordingLayingFormSchemaType> = export const RecordingLayingFormSchema: Yup.ObjectSchema<RecordingLayingFormSchemaType> =
RecordingGrowingFormSchema.shape({ RecordingGrowingFormSchema().shape({
eggs: Yup.array().of(EggObjectSchema).default([]), eggs: Yup.array().of(EggObjectSchema).default([]),
}); });
export const UpdateRecordingGrowingFormSchema = export const UpdateRecordingGrowingFormSchema = (
RecordingGrowingFormSchema.shape({ isTransitioningToLaying = false
) =>
RecordingGrowingFormSchema(isTransitioningToLaying).shape({
location_id: Yup.number().nullable().optional(), location_id: Yup.number().nullable().optional(),
project_flock_id: Yup.number().nullable().optional(), project_flock_id: Yup.number().nullable().optional(),
kandang_id: Yup.number().nullable().optional(), kandang_id: Yup.number().nullable().optional(),
@@ -193,10 +211,13 @@ export const UpdateRecordingLayingFormSchema = RecordingLayingFormSchema.shape({
.required('Project Flock Kandang wajib diisi!'), .required('Project Flock Kandang wajib diisi!'),
}); });
export type RecordingGrowingFormValues = Yup.InferType< type RecordingGrowingFormSchemaFn = ReturnType<
typeof RecordingGrowingFormSchema typeof RecordingGrowingFormSchema
>; >;
export type RecordingGrowingFormValues =
Yup.InferType<RecordingGrowingFormSchemaFn>;
export type RecordingLayingFormValues = Yup.InferType< export type RecordingLayingFormValues = Yup.InferType<
typeof RecordingLayingFormSchema typeof RecordingLayingFormSchema
>; >;
@@ -273,11 +273,11 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
}, []); }, []);
const isRecordingEditable = useCallback((recording?: Recording) => { const isRecordingEditable = useCallback((recording?: Recording) => {
if ( if (recording?.project_flock?.project_flock_category === 'GROWING') {
recording?.executed_at && if (recording?.transfer_executed) {
recording?.project_flock?.project_flock_category === 'GROWING' return false;
) { }
return false; return recording?.population_can_change === true;
} }
return true; return true;
}, []); }, []);
@@ -591,6 +591,14 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
projectFlockKandangLookup?.project_flock?.category === 'GROWING' || projectFlockKandangLookup?.project_flock?.category === 'GROWING' ||
projectFlockKandangDetail?.project_flock?.category === 'GROWING'; projectFlockKandangDetail?.project_flock?.category === 'GROWING';
const isTransitioningToLaying = useMemo(() => {
if (!isGrowingCategory) return false;
return (
initialValues?.population_can_change === true ||
initialValues?.transfer_executed === true
);
}, [initialValues, isGrowingCategory]);
const recordingApprovalLines = useMemo(() => { const recordingApprovalLines = useMemo(() => {
if (isLayingCategory) { if (isLayingCategory) {
return LAYING_RECORDING_APPROVAL_LINE; return LAYING_RECORDING_APPROVAL_LINE;
@@ -951,8 +959,8 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
} else { } else {
schema = schema =
type === 'edit' type === 'edit'
? UpdateRecordingGrowingFormSchema ? UpdateRecordingGrowingFormSchema(isTransitioningToLaying)
: RecordingGrowingFormSchema; : RecordingGrowingFormSchema(isTransitioningToLaying);
} }
return schema.clone().concat( return schema.clone().concat(
Yup.object().shape({ Yup.object().shape({
@@ -2333,21 +2341,25 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
)} )}
<th> <th>
Persediaan Persediaan
<span {!isTransitioningToLaying && (
className='tooltip tooltip-error tooltip-bottom ' <span
data-tip='required' className='tooltip tooltip-error tooltip-bottom '
> data-tip='required'
<span className='text-error'>*</span> >
</span> <span className='text-error'>*</span>
</span>
)}
</th> </th>
<th> <th>
Jumlah Pakai Jumlah Pakai
<span {!isTransitioningToLaying && (
className='tooltip tooltip-error tooltip-bottom ' <span
data-tip='required' className='tooltip tooltip-error tooltip-bottom '
> data-tip='required'
<span className='text-error'>*</span> >
</span> <span className='text-error'>*</span>
</span>
)}
</th> </th>
{(type as 'add' | 'edit' | 'detail') !== 'detail' && ( {(type as 'add' | 'edit' | 'detail') !== 'detail' && (
<th>Action</th> <th>Action</th>
@@ -2382,7 +2394,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
)} )}
<td> <td>
<SelectInput <SelectInput
required required={!isTransitioningToLaying}
key={`stock-product-${idx}-${stock.product_warehouse_id}`} key={`stock-product-${idx}-${stock.product_warehouse_id}`}
value={ value={
unifiedStockProducts.find( unifiedStockProducts.find(
@@ -2440,7 +2452,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
<td> <td>
<div className='flex flex-col gap-1'> <div className='flex flex-col gap-1'>
<NumberInput <NumberInput
required required={!isTransitioningToLaying}
name={`stocks.${idx}.qty`} name={`stocks.${idx}.qty`}
value={stock.qty ?? ''} value={stock.qty ?? ''}
onChange={handleStockUsageQtyChangeWrapper(idx)} onChange={handleStockUsageQtyChangeWrapper(idx)}
+2 -1
View File
@@ -49,7 +49,8 @@ export type BaseRecording = {
project_flock: ProjectFlock; project_flock: ProjectFlock;
record_datetime: string; record_datetime: string;
day: number; day: number;
executed_at: string; population_can_change: boolean;
transfer_executed: boolean;
} & ProductionMetrics; } & ProductionMetrics;
export type RecordingDepletion = { export type RecordingDepletion = {