mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE-207,212): update PurchaseRequestForm schema and validation, enforce required fields and improve data handling for purchase items
This commit is contained in:
@@ -1,62 +1,106 @@
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { Supplier } from '@/types/api/master-data/supplier';
|
import { Purchase } from '@/types/api/purchase/purchase';
|
||||||
import { Warehouse } from '@/types/api/master-data/warehouse';
|
|
||||||
import { CreatePurchaseRequestPayload } from '@/types/api/purchase/purchase';
|
|
||||||
import { Product } from '@/types/api/master-data/product';
|
|
||||||
import { ProductWarehouse } from '@/types/api/inventory/product-warehouse';
|
|
||||||
|
|
||||||
export const PurchaseRequestFormSchema = Yup.object({
|
type PurchaseRequestFormSchemaType = {
|
||||||
supplier: Yup.object({
|
supplier?: {
|
||||||
value: Yup.number().min(1).required(),
|
value: number;
|
||||||
label: Yup.string().required(),
|
label: string;
|
||||||
}).nullable(),
|
} | null;
|
||||||
supplier_id: Yup.number()
|
supplier_id: number;
|
||||||
.required('Supplier wajib diisi!')
|
credit_term: number | string;
|
||||||
.min(1, 'Supplier wajib diisi!')
|
notes: string | null;
|
||||||
.typeError('Supplier wajib diisi!'),
|
purchase_items: {
|
||||||
credit_term: Yup.number()
|
warehouse?: {
|
||||||
.required('Termin kredit wajib diisi!')
|
value: number;
|
||||||
.min(1, 'Termin kredit tidak boleh negatif!')
|
label: string;
|
||||||
.typeError('Termin kredit harus berupa angka!'),
|
} | null;
|
||||||
notes: Yup.string().optional().nullable(),
|
warehouse_id: number;
|
||||||
purchase_items: Yup.array()
|
product?: {
|
||||||
.of(
|
value: number;
|
||||||
Yup.object({
|
label: string;
|
||||||
warehouse: Yup.object({
|
} | null;
|
||||||
value: Yup.number().min(1).required(),
|
product_id: number;
|
||||||
label: Yup.string().required(),
|
product_warehouse?: {
|
||||||
}).nullable(),
|
value: number;
|
||||||
warehouse_id: Yup.number()
|
label: string;
|
||||||
.required('Warehouse wajib diisi!')
|
} | null;
|
||||||
.min(1, 'Warehouse wajib diisi!')
|
product_warehouse_id: number;
|
||||||
.typeError('Warehouse harus berupa angka!'),
|
sub_qty: number | string;
|
||||||
product: Yup.object({
|
}[];
|
||||||
value: Yup.number().min(1).required(),
|
};
|
||||||
label: Yup.string().required(),
|
|
||||||
}).nullable(),
|
export type PurchaseItemSchema = {
|
||||||
product_id: Yup.number()
|
warehouse?: {
|
||||||
.required('Produk wajib diisi!')
|
value: number;
|
||||||
.min(1, 'Produk wajib diisi!')
|
label: string;
|
||||||
.typeError('Produk harus berupa angka!'),
|
} | null;
|
||||||
product_warehouse: Yup.object({
|
warehouse_id: number;
|
||||||
value: Yup.number().min(1).required(),
|
product?: {
|
||||||
label: Yup.string().required(),
|
value: number;
|
||||||
}).nullable(),
|
label: string;
|
||||||
product_warehouse_id: Yup.number().optional().nullable(),
|
} | null;
|
||||||
sub_qty: Yup.number()
|
product_id: number;
|
||||||
.required('Sub Qty wajib diisi!')
|
product_warehouse?: {
|
||||||
.min(0.001, 'Sub Qty tidak boleh negatif!')
|
value: number;
|
||||||
.typeError('Sub Qty harus berupa angka!'),
|
label: string;
|
||||||
price: Yup.number()
|
} | null;
|
||||||
.required('Harga wajib diisi!')
|
product_warehouse_id: number;
|
||||||
.min(0, 'Harga tidak boleh negatif!')
|
sub_qty: number | string;
|
||||||
.typeError('Harga harus berupa angka!'),
|
};
|
||||||
})
|
|
||||||
)
|
const PurchaseItemObjectSchema: Yup.ObjectSchema<PurchaseItemSchema> =
|
||||||
.min(1, 'Minimal harus ada 1 item pembelian!')
|
Yup.object({
|
||||||
.required('Item pembelian wajib diisi!')
|
warehouse: Yup.object({
|
||||||
.typeError('Item pembelian wajib diisi!'),
|
value: Yup.number().min(1).required(),
|
||||||
});
|
label: Yup.string().required(),
|
||||||
|
}).nullable(),
|
||||||
|
warehouse_id: Yup.number()
|
||||||
|
.required('Warehouse wajib diisi!')
|
||||||
|
.min(1, 'Warehouse wajib diisi!')
|
||||||
|
.typeError('Warehouse harus berupa angka!'),
|
||||||
|
product: Yup.object({
|
||||||
|
value: Yup.number().min(1).required(),
|
||||||
|
label: Yup.string().required(),
|
||||||
|
}).nullable(),
|
||||||
|
product_id: Yup.number()
|
||||||
|
.required('Produk wajib diisi!')
|
||||||
|
.min(1, 'Produk wajib diisi!')
|
||||||
|
.typeError('Produk harus berupa angka!'),
|
||||||
|
product_warehouse: Yup.object({
|
||||||
|
value: Yup.number().min(1).required(),
|
||||||
|
label: Yup.string().required(),
|
||||||
|
}).nullable(),
|
||||||
|
product_warehouse_id: Yup.number()
|
||||||
|
.required('Product Warehouse wajib diisi!')
|
||||||
|
.min(0.001, 'Product Warehouse tidak boleh negatif!')
|
||||||
|
.typeError('Product Warehouse harus berupa angka!'),
|
||||||
|
sub_qty: Yup.number()
|
||||||
|
.required('Sub Qty wajib diisi!')
|
||||||
|
.min(0.001, 'Sub Qty tidak boleh negatif!')
|
||||||
|
.typeError('Sub Qty harus berupa angka!'),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const PurchaseRequestFormSchema: Yup.ObjectSchema<PurchaseRequestFormSchemaType> =
|
||||||
|
Yup.object({
|
||||||
|
supplier: Yup.object({
|
||||||
|
value: Yup.number().min(1).required(),
|
||||||
|
label: Yup.string().required(),
|
||||||
|
}).nullable(),
|
||||||
|
supplier_id: Yup.number()
|
||||||
|
.required('Supplier wajib diisi!')
|
||||||
|
.min(1, 'Supplier wajib diisi!')
|
||||||
|
.typeError('Supplier wajib diisi!'),
|
||||||
|
credit_term: Yup.number()
|
||||||
|
.required('Termin kredit wajib diisi!')
|
||||||
|
.min(1, 'Termin kredit tidak boleh negatif!')
|
||||||
|
.typeError('Termin kredit harus berupa angka!'),
|
||||||
|
notes: Yup.string().nullable().default(null),
|
||||||
|
purchase_items: Yup.array()
|
||||||
|
.of(PurchaseItemObjectSchema)
|
||||||
|
.min(1, 'Minimal harus ada 1 item pembelian!')
|
||||||
|
.required('Item pembelian wajib diisi!')
|
||||||
|
.typeError('Item pembelian wajib diisi!'),
|
||||||
|
});
|
||||||
|
|
||||||
export const UpdatePurchaseRequestFormSchema = PurchaseRequestFormSchema;
|
export const UpdatePurchaseRequestFormSchema = PurchaseRequestFormSchema;
|
||||||
|
|
||||||
@@ -64,20 +108,8 @@ export type PurchaseRequestFormValues = Yup.InferType<
|
|||||||
typeof PurchaseRequestFormSchema
|
typeof PurchaseRequestFormSchema
|
||||||
>;
|
>;
|
||||||
|
|
||||||
type PurchaseRequestFormData = {
|
|
||||||
supplier?: Supplier;
|
|
||||||
supplier_id?: number;
|
|
||||||
credit_term?: number;
|
|
||||||
notes?: string | null;
|
|
||||||
purchase_items?: (CreatePurchaseRequestPayload['purchase_items'][0] & {
|
|
||||||
warehouse?: Warehouse;
|
|
||||||
product?: Product;
|
|
||||||
product_warehouse?: ProductWarehouse;
|
|
||||||
})[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPurchaseRequestFormInitialValues = (
|
export const getPurchaseRequestFormInitialValues = (
|
||||||
initialValues?: PurchaseRequestFormData
|
initialValues?: Purchase
|
||||||
): PurchaseRequestFormValues => ({
|
): PurchaseRequestFormValues => ({
|
||||||
supplier: initialValues?.supplier
|
supplier: initialValues?.supplier
|
||||||
? {
|
? {
|
||||||
@@ -85,45 +117,8 @@ export const getPurchaseRequestFormInitialValues = (
|
|||||||
label: initialValues.supplier.name,
|
label: initialValues.supplier.name,
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
supplier_id: initialValues?.supplier_id ?? 0,
|
supplier_id: initialValues?.supplier?.id ?? 0,
|
||||||
credit_term: initialValues?.credit_term ?? 1,
|
credit_term: initialValues?.credit_term ?? '',
|
||||||
notes: initialValues?.notes ?? '',
|
notes: initialValues?.notes ?? null,
|
||||||
purchase_items: initialValues?.purchase_items?.map(
|
purchase_items: [],
|
||||||
(item: NonNullable<PurchaseRequestFormData['purchase_items']>[0]) => ({
|
|
||||||
warehouse: item.warehouse
|
|
||||||
? {
|
|
||||||
value: item.warehouse.id,
|
|
||||||
label: item.warehouse.name,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
warehouse_id: item.warehouse_id,
|
|
||||||
product: item.product
|
|
||||||
? {
|
|
||||||
value: item.product.id,
|
|
||||||
label: item.product.name,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
product_id: item.product_id,
|
|
||||||
product_warehouse: item.product_warehouse
|
|
||||||
? {
|
|
||||||
value: item.product_warehouse.id,
|
|
||||||
label: item.product_warehouse.product.name,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
product_warehouse_id: item.product_warehouse_id || null,
|
|
||||||
sub_qty: item.sub_qty,
|
|
||||||
price: item.price,
|
|
||||||
})
|
|
||||||
) ?? [
|
|
||||||
{
|
|
||||||
warehouse: null,
|
|
||||||
warehouse_id: 0,
|
|
||||||
product: null,
|
|
||||||
product_id: 0,
|
|
||||||
product_warehouse: null,
|
|
||||||
product_warehouse_id: null,
|
|
||||||
sub_qty: 0,
|
|
||||||
price: 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -142,19 +142,32 @@ const PurchaseRequestForm = ({
|
|||||||
validateOnBlur: true,
|
validateOnBlur: true,
|
||||||
onSubmit: async (values) => {
|
onSubmit: async (values) => {
|
||||||
const payload: CreatePurchaseRequestPayload = {
|
const payload: CreatePurchaseRequestPayload = {
|
||||||
supplier_id: values.supplier_id || 0,
|
supplier_id:
|
||||||
credit_term: values.credit_term || 0,
|
typeof values.supplier_id === 'string'
|
||||||
|
? parseInt(values.supplier_id) || 0
|
||||||
|
: values.supplier_id || 0,
|
||||||
|
credit_term:
|
||||||
|
typeof values.credit_term === 'string'
|
||||||
|
? parseInt(values.credit_term) || 0
|
||||||
|
: values.credit_term || 0,
|
||||||
notes: values.notes || '',
|
notes: values.notes || '',
|
||||||
purchase_items: (values.purchase_items || []).map((item) => ({
|
purchase_items: (values.purchase_items || []).map((item) => ({
|
||||||
warehouse_id: item.warehouse_id || 0,
|
warehouse_id:
|
||||||
product_id: item.product_id || 0,
|
typeof item.warehouse_id === 'string'
|
||||||
product_warehouse_id: item.product_warehouse_id || undefined,
|
? parseInt(item.warehouse_id) || 0
|
||||||
sub_qty: item.sub_qty || 0,
|
: item.warehouse_id || 0,
|
||||||
total_qty: item.total_qty || 0,
|
product_id:
|
||||||
price:
|
typeof item.product_id === 'string'
|
||||||
typeof item.price === 'number'
|
? parseInt(item.product_id) || 0
|
||||||
? item.price
|
: item.product_id || 0,
|
||||||
: parseFloat(item.price) || 0,
|
product_warehouse_id:
|
||||||
|
typeof item.product_warehouse_id === 'string'
|
||||||
|
? parseInt(item.product_warehouse_id) || 0
|
||||||
|
: item.product_warehouse_id || 0,
|
||||||
|
sub_qty:
|
||||||
|
typeof item.sub_qty === 'string'
|
||||||
|
? parseFloat(item.sub_qty) || 0
|
||||||
|
: item.sub_qty || 0,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -193,14 +206,12 @@ const PurchaseRequestForm = ({
|
|||||||
...(formik.values.purchase_items || []),
|
...(formik.values.purchase_items || []),
|
||||||
{
|
{
|
||||||
warehouse: null,
|
warehouse: null,
|
||||||
warehouse_id: 0,
|
warehouse_id: '',
|
||||||
product: null,
|
product: null,
|
||||||
product_id: 0,
|
product_id: '',
|
||||||
product_warehouse: null,
|
product_warehouse: null,
|
||||||
product_warehouse_id: null,
|
product_warehouse_id: null,
|
||||||
sub_qty: 0,
|
sub_qty: '',
|
||||||
total_qty: 0,
|
|
||||||
price: 0,
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
formik.setFieldValue('purchase_items', newPurchaseItems);
|
formik.setFieldValue('purchase_items', newPurchaseItems);
|
||||||
@@ -285,12 +296,11 @@ const PurchaseRequestForm = ({
|
|||||||
type='number'
|
type='number'
|
||||||
placeholder='Masukkan Supplier ID'
|
placeholder='Masukkan Supplier ID'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
required
|
required
|
||||||
label='Jatuh tempo (hari)'
|
label='Jatuh tempo (hari)'
|
||||||
name='credit_term'
|
name='credit_term'
|
||||||
value={formik.values.credit_term}
|
value={formik.values.credit_term || ''}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
isError={
|
isError={
|
||||||
@@ -303,6 +313,28 @@ const PurchaseRequestForm = ({
|
|||||||
placeholder='Masukkan Credit Term'
|
placeholder='Masukkan Credit Term'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
required
|
||||||
|
label='Area'
|
||||||
|
name='area_id'
|
||||||
|
onChange={(e) => {}}
|
||||||
|
onBlur={formik.handleBlur}
|
||||||
|
readOnly={type === 'detail'}
|
||||||
|
type='number'
|
||||||
|
placeholder='Pilih Area'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
required
|
||||||
|
label='Lokasi'
|
||||||
|
name='location_id'
|
||||||
|
onChange={(e) => {}}
|
||||||
|
onBlur={formik.handleBlur}
|
||||||
|
readOnly={type === 'detail'}
|
||||||
|
type='number'
|
||||||
|
placeholder='Pilih Lokasi'
|
||||||
|
/>
|
||||||
|
|
||||||
<div className={type === 'detail' ? 'col-span-1' : 'col-span-2'}>
|
<div className={type === 'detail' ? 'col-span-1' : 'col-span-2'}>
|
||||||
<TextInput
|
<TextInput
|
||||||
label='Notes'
|
label='Notes'
|
||||||
@@ -356,29 +388,19 @@ const PurchaseRequestForm = ({
|
|||||||
</th>
|
</th>
|
||||||
)}
|
)}
|
||||||
<th>
|
<th>
|
||||||
Warehouse ID
|
Gudang
|
||||||
<span className='text-error'>*</span>
|
<span className='text-error'>*</span>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Product ID
|
Item
|
||||||
<span className='text-error'>*</span>
|
<span className='text-error'>*</span>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Product Warehouse ID
|
Jumlah
|
||||||
<span className='text-error'>*</span>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
Sub Qty
|
|
||||||
<span className='text-error'>*</span>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
Total Qty
|
|
||||||
<span className='text-error'>*</span>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
Price
|
|
||||||
<span className='text-error'>*</span>
|
<span className='text-error'>*</span>
|
||||||
</th>
|
</th>
|
||||||
|
<th>Estimasi Harga</th>
|
||||||
|
<th>Satuan</th>
|
||||||
{type !== 'detail' && <th>Action</th>}
|
{type !== 'detail' && <th>Action</th>}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -410,7 +432,7 @@ const PurchaseRequestForm = ({
|
|||||||
<TextInput
|
<TextInput
|
||||||
required
|
required
|
||||||
name={`purchase_items.${idx}.warehouse_id`}
|
name={`purchase_items.${idx}.warehouse_id`}
|
||||||
value={item.warehouse_id}
|
value={item.warehouse_id || ''}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handlePurchaseItemChange(
|
handlePurchaseItemChange(
|
||||||
idx,
|
idx,
|
||||||
@@ -420,28 +442,7 @@ const PurchaseRequestForm = ({
|
|||||||
}
|
}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
type='number'
|
type='number'
|
||||||
placeholder='Warehouse ID'
|
placeholder='Masukkan Warehouse ID'
|
||||||
readOnly={type === 'detail'}
|
|
||||||
className={{
|
|
||||||
wrapper: 'min-w-24',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<TextInput
|
|
||||||
required
|
|
||||||
name={`purchase_items.${idx}.product_id`}
|
|
||||||
value={item.product_id}
|
|
||||||
onChange={(e) =>
|
|
||||||
handlePurchaseItemChange(
|
|
||||||
idx,
|
|
||||||
'product_id',
|
|
||||||
e.target.value
|
|
||||||
)
|
|
||||||
}
|
|
||||||
onBlur={formik.handleBlur}
|
|
||||||
type='number'
|
|
||||||
placeholder='Product ID'
|
|
||||||
readOnly={type === 'detail'}
|
readOnly={type === 'detail'}
|
||||||
className={{
|
className={{
|
||||||
wrapper: 'min-w-24',
|
wrapper: 'min-w-24',
|
||||||
@@ -472,7 +473,7 @@ const PurchaseRequestForm = ({
|
|||||||
<TextInput
|
<TextInput
|
||||||
required
|
required
|
||||||
name={`purchase_items.${idx}.sub_qty`}
|
name={`purchase_items.${idx}.sub_qty`}
|
||||||
value={item.sub_qty}
|
value={item.sub_qty || ''}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handlePurchaseItemChange(
|
handlePurchaseItemChange(
|
||||||
idx,
|
idx,
|
||||||
@@ -482,28 +483,7 @@ const PurchaseRequestForm = ({
|
|||||||
}
|
}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
type='number'
|
type='number'
|
||||||
placeholder='Sub Qty'
|
placeholder='Masukkan kuantitas'
|
||||||
readOnly={type === 'detail'}
|
|
||||||
className={{
|
|
||||||
wrapper: 'min-w-24',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<TextInput
|
|
||||||
required
|
|
||||||
name={`purchase_items.${idx}.total_qty`}
|
|
||||||
value={item.total_qty}
|
|
||||||
onChange={(e) =>
|
|
||||||
handlePurchaseItemChange(
|
|
||||||
idx,
|
|
||||||
'total_qty',
|
|
||||||
e.target.value
|
|
||||||
)
|
|
||||||
}
|
|
||||||
onBlur={formik.handleBlur}
|
|
||||||
type='number'
|
|
||||||
placeholder='Total Qty'
|
|
||||||
readOnly={type === 'detail'}
|
readOnly={type === 'detail'}
|
||||||
className={{
|
className={{
|
||||||
wrapper: 'min-w-24',
|
wrapper: 'min-w-24',
|
||||||
@@ -514,7 +494,6 @@ const PurchaseRequestForm = ({
|
|||||||
<TextInput
|
<TextInput
|
||||||
required
|
required
|
||||||
name={`purchase_items.${idx}.price`}
|
name={`purchase_items.${idx}.price`}
|
||||||
value={item.price}
|
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handlePurchaseItemChange(
|
handlePurchaseItemChange(
|
||||||
idx,
|
idx,
|
||||||
@@ -524,8 +503,22 @@ const PurchaseRequestForm = ({
|
|||||||
}
|
}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
type='number'
|
type='number'
|
||||||
placeholder='Price'
|
className={{
|
||||||
readOnly={type === 'detail'}
|
wrapper: 'min-w-24',
|
||||||
|
}}
|
||||||
|
disabled={true}
|
||||||
|
readOnly={true}
|
||||||
|
inputPrefix={'Rp'}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<TextInput
|
||||||
|
required
|
||||||
|
name={`purchase_items.${idx}.uom`}
|
||||||
|
onBlur={formik.handleBlur}
|
||||||
|
type='number'
|
||||||
|
readOnly={true}
|
||||||
|
disabled={true}
|
||||||
className={{
|
className={{
|
||||||
wrapper: 'min-w-24',
|
wrapper: 'min-w-24',
|
||||||
}}
|
}}
|
||||||
|
|||||||
Vendored
+1
-2
@@ -24,9 +24,8 @@ export type CreatePurchaseRequestPayload = {
|
|||||||
purchase_items: {
|
purchase_items: {
|
||||||
warehouse_id: number;
|
warehouse_id: number;
|
||||||
product_id: number;
|
product_id: number;
|
||||||
product_warehouse_id?: number | null;
|
product_warehouse_id: number;
|
||||||
sub_qty: number;
|
sub_qty: number;
|
||||||
price: number;
|
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user