mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-25 07:45:47 +00:00
feat(FE-137): integrate API for daily recording with enhanced data structure and validation
This commit is contained in:
@@ -1,212 +1,167 @@
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { RECORDING_FLAG_OPTIONS } from '@/config/constant';
|
import { RECORDING_FLAG_OPTIONS } from '@/config/constant';
|
||||||
import { Recording } from '@/types/api/production/recording';
|
import {
|
||||||
|
Recording,
|
||||||
|
CreateRecordingPayload,
|
||||||
|
} from '@/types/api/production/recording';
|
||||||
|
|
||||||
export const RecordingFormSchema = Yup.object({
|
export const RecordingFormSchema = Yup.object({
|
||||||
flock: Yup.object({
|
project_flock_kandang: Yup.object({
|
||||||
value: Yup.number().min(1).required(),
|
value: Yup.number().min(1).required(),
|
||||||
label: Yup.string().required(),
|
label: Yup.string().required(),
|
||||||
}).nullable(),
|
}).nullable(),
|
||||||
flock_id: Yup.number()
|
project_flock_kandang_id: Yup.number()
|
||||||
.default(0)
|
.default(0)
|
||||||
.typeError('Flock wajib diisi!')
|
.typeError('Project Flock Kandang wajib diisi!')
|
||||||
.test(
|
.test(
|
||||||
'is-valid-flock',
|
'is-valid-project-flock-kandang',
|
||||||
'Flock wajib diisi!',
|
'Project Flock Kandang wajib diisi!',
|
||||||
(value) => value !== undefined && value !== null && value > 0
|
(value) => value !== undefined && value !== null && value > 0
|
||||||
)
|
)
|
||||||
.required('Flock wajib diisi!'),
|
.required('Project Flock Kandang wajib diisi!'),
|
||||||
location: Yup.object({
|
record_datetime: Yup.date()
|
||||||
value: Yup.number().min(1).required(),
|
.required('Tanggal dan waktu recording wajib diisi')
|
||||||
label: Yup.string().required(),
|
.typeError('Format tanggal dan waktu tidak valid'),
|
||||||
}).nullable(),
|
status: Yup.number()
|
||||||
location_id: Yup.number()
|
.optional()
|
||||||
.default(0)
|
.oneOf([0, 1, 2, 3], 'Status tidak valid')
|
||||||
.typeError('Lokasi wajib diisi!')
|
.typeError('Status harus berupa angka!'),
|
||||||
.test(
|
ontime: Yup.boolean().optional(),
|
||||||
'is-valid-location',
|
body_weights: Yup.array()
|
||||||
'Lokasi wajib diisi!',
|
|
||||||
(value) => value !== undefined && value !== null && value > 0
|
|
||||||
)
|
|
||||||
.required('Lokasi wajib diisi!'),
|
|
||||||
coop: Yup.object({
|
|
||||||
value: Yup.number().min(1).required(),
|
|
||||||
label: Yup.string().required(),
|
|
||||||
}).nullable(),
|
|
||||||
coop_id: Yup.number()
|
|
||||||
.default(0)
|
|
||||||
.typeError('Kandang wajib diisi!')
|
|
||||||
.test(
|
|
||||||
'is-valid-coop',
|
|
||||||
'Kandang wajib diisi!',
|
|
||||||
(value) => value !== undefined && value !== null && value > 0
|
|
||||||
)
|
|
||||||
.required('Kandang wajib diisi!'),
|
|
||||||
recording_date: Yup.date()
|
|
||||||
.required('Tanggal recording wajib diisi')
|
|
||||||
.typeError('Format tanggal tidak valid'),
|
|
||||||
feed_data: Yup.array()
|
|
||||||
.of(
|
.of(
|
||||||
Yup.object({
|
Yup.object({
|
||||||
feed_id: Yup.string().required('Nama pakan wajib diisi!'),
|
weight: Yup.number()
|
||||||
feed_qty: Yup.mixed<number | ''>().notRequired(),
|
|
||||||
feed_stock: Yup.number()
|
|
||||||
.required('Jumlah pakan yang digunakan wajib diisi!')
|
|
||||||
.min(1, 'Jumlah pakan minimal 1!')
|
|
||||||
.typeError('Jumlah pakan yang digunakan harus berupa angka!')
|
|
||||||
.test(
|
|
||||||
'is-not-exceed-qty',
|
|
||||||
'Jumlah pakan yang digunakan tidak boleh melebihi stok tersedia!',
|
|
||||||
function (value) {
|
|
||||||
const { feed_qty } = this.parent;
|
|
||||||
if (value === undefined) return true;
|
|
||||||
if (
|
|
||||||
feed_qty === undefined ||
|
|
||||||
feed_qty === '' ||
|
|
||||||
typeof feed_qty !== 'number'
|
|
||||||
)
|
|
||||||
return true;
|
|
||||||
return value <= feed_qty;
|
|
||||||
}
|
|
||||||
),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.min(1, 'Minimal harus ada 1 data pakan!')
|
|
||||||
.required('Data pakan wajib diisi!'),
|
|
||||||
body_weight: Yup.array()
|
|
||||||
.of(
|
|
||||||
Yup.object({
|
|
||||||
chicken_weight: Yup.number()
|
|
||||||
.required('Berat ayam wajib diisi!')
|
.required('Berat ayam wajib diisi!')
|
||||||
.min(1, 'Berat ayam minimal 1 gram!')
|
.min(1, 'Berat ayam minimal 1 gram!')
|
||||||
.typeError('Berat ayam harus berupa angka!'),
|
.typeError('Berat ayam harus berupa angka!'),
|
||||||
chicken_count: Yup.number()
|
qty: Yup.number()
|
||||||
.required('Jumlah ayam wajib diisi!')
|
.required('Jumlah ayam wajib diisi!')
|
||||||
.min(1, 'Jumlah ayam minimal 1 ekor!')
|
.min(1, 'Jumlah ayam minimal 1 ekor!')
|
||||||
.typeError('Jumlah ayam harus berupa angka!'),
|
.typeError('Jumlah ayam harus berupa angka!')
|
||||||
average_chicken_weight: Yup.number()
|
.default(1),
|
||||||
.required('Rata-rata berat ayam wajib diisi!')
|
notes: Yup.string().optional(),
|
||||||
.min(1, 'Rata-rata berat ayam minimal 1 gram!')
|
|
||||||
.typeError('Rata-rata berat ayam harus berupa angka!'),
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.min(1, 'Minimal harus ada 1 data bobot badan!')
|
.min(1, 'Minimal harus ada 1 data bobot badan!')
|
||||||
.required('Data bobot badan wajib diisi!'),
|
.required('Data bobot badan wajib diisi!'),
|
||||||
vaccination: Yup.array()
|
stocks: Yup.array()
|
||||||
.of(
|
.of(
|
||||||
Yup.object({
|
Yup.object({
|
||||||
vaccine_id: Yup.string().required('Nama vaksin wajib diisi!'),
|
product_warehouse_id: Yup.number()
|
||||||
total_stock: Yup.mixed<number | ''>().notRequired(),
|
.required('Produk wajib diisi!')
|
||||||
used_stock: Yup.number()
|
.min(1, 'Produk wajib diisi!')
|
||||||
.required('Jumlah vaksin yang digunakan wajib diisi!')
|
.typeError('Produk harus berupa angka!'),
|
||||||
.min(1, 'Jumlah vaksin minimal 1!')
|
increase: Yup.number()
|
||||||
.typeError('Jumlah vaksin yang digunakan harus berupa angka!')
|
.optional()
|
||||||
.test(
|
.min(0, 'Penambahan tidak boleh negatif!')
|
||||||
'is-not-exceed-total',
|
.typeError('Penambahan harus berupa angka!'),
|
||||||
'Jumlah vaksin yang digunakan tidak boleh melebihi stok tersedia!',
|
decrease: Yup.number()
|
||||||
function (value) {
|
.optional()
|
||||||
const { total_stock } = this.parent;
|
.min(0, 'Pengurangan tidak boleh negatif!')
|
||||||
if (value === undefined) return true;
|
.typeError('Pengurangan harus berupa angka!'),
|
||||||
if (
|
usage_amount: Yup.number()
|
||||||
total_stock === undefined ||
|
.optional()
|
||||||
total_stock === '' ||
|
.min(0, 'Jumlah penggunaan tidak boleh negatif!')
|
||||||
typeof total_stock !== 'number'
|
.typeError('Jumlah penggunaan harus berupa angka!'),
|
||||||
)
|
notes: Yup.string().optional(),
|
||||||
return true;
|
|
||||||
return value <= total_stock;
|
|
||||||
}
|
|
||||||
),
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.min(1, 'Minimal harus ada 1 data vaksinasi!')
|
.min(1, 'Minimal harus ada 1 data stok!')
|
||||||
.required('Data vaksinasi wajib diisi!'),
|
.required('Data stok wajib diisi!'),
|
||||||
mortality: Yup.array()
|
depletions: Yup.array()
|
||||||
.of(
|
.of(
|
||||||
Yup.object({
|
Yup.object({
|
||||||
condition: Yup.mixed<string>()
|
product_warehouse_id: Yup.number()
|
||||||
|
.required('Produk wajib diisi!')
|
||||||
|
.min(1, 'Produk wajib diisi!')
|
||||||
|
.typeError('Produk harus berupa angka!'),
|
||||||
|
condition: Yup.string()
|
||||||
|
.required('Kondisi depletions wajib diisi!')
|
||||||
.oneOf(
|
.oneOf(
|
||||||
RECORDING_FLAG_OPTIONS.map((opt) => opt.value),
|
RECORDING_FLAG_OPTIONS.map((option) => option.value),
|
||||||
'Kondisi tidak valid!'
|
'Kondisi depletions tidak valid!'
|
||||||
)
|
)
|
||||||
.required('Kondisi wajib diisi!'),
|
.typeError('Kondisi depletions harus berupa teks!')
|
||||||
count: Yup.number()
|
.min(1, 'Kondisi depletions wajib diisi!'),
|
||||||
.required('Jumlah mortalitas wajib diisi!')
|
total: Yup.number()
|
||||||
.min(1, 'Jumlah mortalitas minimal 1 ekor!')
|
.required('Jumlah depletions wajib diisi!')
|
||||||
.typeError('Jumlah mortalitas harus berupa angka!'),
|
.min(1, 'Jumlah depletions minimal 1!')
|
||||||
|
.typeError('Jumlah depletions harus berupa angka!'),
|
||||||
|
notes: Yup.string().optional(),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.min(1, 'Minimal harus ada 1 data mortalitas!')
|
.min(1, 'Minimal harus ada 1 data depletions!')
|
||||||
.required('Data mortalitas wajib diisi!'),
|
.required('Data depletions wajib diisi!'),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const UpdateRecordingFormSchema = RecordingFormSchema;
|
export const UpdateRecordingFormSchema = RecordingFormSchema;
|
||||||
|
|
||||||
export type RecordingFormValues = Yup.InferType<typeof RecordingFormSchema>;
|
export type RecordingFormValues = Yup.InferType<typeof RecordingFormSchema>;
|
||||||
|
|
||||||
|
type RecordingFormData = Partial<Recording> & {
|
||||||
|
body_weights?: CreateRecordingPayload['body_weights'];
|
||||||
|
stocks?: CreateRecordingPayload['stocks'];
|
||||||
|
depletions?: CreateRecordingPayload['depletions'];
|
||||||
|
};
|
||||||
|
|
||||||
export const getRecordingFormInitialValues = (
|
export const getRecordingFormInitialValues = (
|
||||||
initialValues?: Recording
|
initialValues?: RecordingFormData
|
||||||
): RecordingFormValues => ({
|
): RecordingFormValues => ({
|
||||||
flock: initialValues?.flock
|
project_flock_kandang: initialValues?.project_flock_kandang_id
|
||||||
? {
|
? {
|
||||||
value: initialValues.flock.id,
|
value: initialValues.project_flock_kandang_id,
|
||||||
label: initialValues.flock.name,
|
label: `Project Flock Kandang #${initialValues.project_flock_kandang_id}`,
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
flock_id: initialValues?.flock?.id ?? 0,
|
project_flock_kandang_id: initialValues?.project_flock_kandang_id ?? 0,
|
||||||
location: initialValues?.location
|
record_datetime: initialValues?.record_datetime
|
||||||
? {
|
? new Date(initialValues.record_datetime)
|
||||||
value: initialValues.location.id,
|
|
||||||
label: initialValues.location.name,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
location_id: initialValues?.location?.id ?? 0,
|
|
||||||
coop: initialValues?.coop
|
|
||||||
? {
|
|
||||||
value: initialValues.coop.id,
|
|
||||||
label: initialValues.coop.name,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
coop_id: initialValues?.coop?.id ?? 0,
|
|
||||||
recording_date: initialValues?.recording_date
|
|
||||||
? new Date(initialValues.recording_date)
|
|
||||||
: new Date(),
|
: new Date(),
|
||||||
feed_data: initialValues?.feed_data
|
status: initialValues?.status ?? 1,
|
||||||
? initialValues.feed_data.map((feed) => ({
|
ontime: initialValues?.ontime ?? true,
|
||||||
feed_id: feed.feed_name,
|
body_weights: initialValues?.body_weights?.map(
|
||||||
feed_qty: feed.feed_qty,
|
(bw: NonNullable<CreateRecordingPayload['body_weights']>[0]) => ({
|
||||||
feed_stock: feed.feed_stock,
|
weight: bw.weight,
|
||||||
}))
|
qty: bw.qty,
|
||||||
: [
|
notes: bw.notes || '',
|
||||||
{
|
})
|
||||||
feed_id: '',
|
) ?? [
|
||||||
feed_qty: '',
|
|
||||||
feed_stock: 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
body_weight: initialValues?.body_weight ?? [
|
|
||||||
{
|
{
|
||||||
chicken_weight: 0,
|
weight: 0,
|
||||||
chicken_count: 0,
|
qty: 1,
|
||||||
average_chicken_weight: 0,
|
notes: '',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
vaccination: initialValues?.vaccination
|
stocks: initialValues?.stocks?.map(
|
||||||
? initialValues.vaccination.map((vaccine) => ({
|
(stock: NonNullable<CreateRecordingPayload['stocks']>[0]) => ({
|
||||||
vaccine_id: vaccine.vaccine_name,
|
product_warehouse_id: stock.product_warehouse_id,
|
||||||
total_stock: vaccine.total_stock,
|
increase: stock.increase,
|
||||||
used_stock: vaccine.used_stock,
|
decrease: stock.decrease,
|
||||||
}))
|
usage_amount: stock.usage_amount,
|
||||||
: [
|
notes: stock.notes,
|
||||||
{
|
})
|
||||||
vaccine_id: '',
|
) ?? [
|
||||||
total_stock: '',
|
|
||||||
used_stock: 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
mortality: initialValues?.mortality ?? [
|
|
||||||
{
|
{
|
||||||
|
product_warehouse_id: 0,
|
||||||
|
increase: 0,
|
||||||
|
decrease: 0,
|
||||||
|
usage_amount: 0,
|
||||||
|
notes: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
depletions: initialValues?.depletions?.map(
|
||||||
|
(depletion: NonNullable<CreateRecordingPayload['depletions']>[0]) => ({
|
||||||
|
product_warehouse_id: depletion.product_warehouse_id,
|
||||||
|
condition: depletion.condition,
|
||||||
|
total: depletion.total,
|
||||||
|
notes: depletion.notes,
|
||||||
|
})
|
||||||
|
) ?? [
|
||||||
|
{
|
||||||
|
product_warehouse_id: 0,
|
||||||
condition: '',
|
condition: '',
|
||||||
count: 0,
|
total: 0,
|
||||||
|
notes: '',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+39
-47
@@ -1,60 +1,52 @@
|
|||||||
import { BaseMetadata } from '@/types/api/api-general';
|
import { BaseMetadata, User } from '@/types/api/api-general';
|
||||||
import { Location } from '@/types/api/master-data/location';
|
|
||||||
import { Kandang } from '@/types/api/master-data/kandang';
|
export type ProductionMetrics = {
|
||||||
import { Flock } from '@/types/api/master-data/flock';
|
total_depletion: number;
|
||||||
|
cum_depletion_rate: number;
|
||||||
|
daily_gain: number;
|
||||||
|
avg_daily_gain: number;
|
||||||
|
cum_intake: number;
|
||||||
|
fcr_value: number;
|
||||||
|
total_chick: number;
|
||||||
|
daily_depletion_rate: number;
|
||||||
|
cum_depletion: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type BaseRecording = {
|
export type BaseRecording = {
|
||||||
id: number;
|
id: number;
|
||||||
flock: Flock;
|
project_flock_kandang_id: number;
|
||||||
recording_date: string;
|
record_datetime: string;
|
||||||
location: Location;
|
record_date: string;
|
||||||
coop: Kandang;
|
status: number;
|
||||||
feed_data: {
|
ontime: boolean;
|
||||||
feed_name: string;
|
day: number;
|
||||||
feed_qty: number;
|
created_user: User;
|
||||||
feed_stock: number;
|
} & ProductionMetrics;
|
||||||
}[];
|
|
||||||
body_weight: {
|
|
||||||
chicken_weight: number;
|
|
||||||
chicken_count: number;
|
|
||||||
average_chicken_weight: number;
|
|
||||||
}[];
|
|
||||||
vaccination: {
|
|
||||||
vaccine_name: string;
|
|
||||||
total_stock: number;
|
|
||||||
used_stock: number;
|
|
||||||
}[];
|
|
||||||
mortality: {
|
|
||||||
condition: string;
|
|
||||||
count: number;
|
|
||||||
}[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Recording = BaseMetadata & BaseRecording;
|
export type Recording = BaseMetadata & BaseRecording;
|
||||||
|
|
||||||
export type CreateRecordingPayload = {
|
export type CreateRecordingPayload = {
|
||||||
flock_id: number;
|
project_flock_kandang_id: number;
|
||||||
recording_date: string;
|
record_datetime: string;
|
||||||
location_id: number;
|
status?: number;
|
||||||
coop_id: number;
|
ontime?: boolean;
|
||||||
feed_data: {
|
body_weights?: {
|
||||||
feed_id: string;
|
weight: number;
|
||||||
feed_qty: number;
|
qty: number;
|
||||||
feed_stock: number;
|
notes?: string;
|
||||||
}[];
|
}[];
|
||||||
body_weight: {
|
stocks?: {
|
||||||
chicken_weight: number;
|
product_warehouse_id: number;
|
||||||
chicken_count: number;
|
increase?: number;
|
||||||
average_chicken_weight: number;
|
decrease?: number;
|
||||||
|
usage_amount?: number;
|
||||||
|
notes?: string;
|
||||||
}[];
|
}[];
|
||||||
vaccination: {
|
depletions?: {
|
||||||
vaccine_id: string;
|
product_warehouse_id: number;
|
||||||
total_stock: number;
|
|
||||||
used_stock: number;
|
|
||||||
}[];
|
|
||||||
mortality: {
|
|
||||||
condition: string;
|
condition: string;
|
||||||
count: number;
|
total: number;
|
||||||
|
notes?: string;
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user