mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
feat(FE-208,212): update purchase request form to use 'qty' instead of 'quantity' and add credit term field
This commit is contained in:
@@ -7,6 +7,7 @@ type PurchaseRequestFormSchemaType = {
|
||||
label: string;
|
||||
} | null;
|
||||
supplier_id: number;
|
||||
credit_term: number;
|
||||
area?: {
|
||||
value: number;
|
||||
label: string;
|
||||
@@ -34,7 +35,7 @@ type PurchaseRequestFormSchemaType = {
|
||||
label: string;
|
||||
} | null;
|
||||
product_id: number;
|
||||
quantity: number | string;
|
||||
qty: number | string;
|
||||
}[];
|
||||
};
|
||||
|
||||
@@ -49,7 +50,7 @@ export type PurchaseItemSchema = {
|
||||
label: string;
|
||||
} | null;
|
||||
product_id: number;
|
||||
quantity: number | string;
|
||||
qty: number | string;
|
||||
};
|
||||
|
||||
const PurchaseItemObjectSchema: Yup.ObjectSchema<PurchaseItemSchema> =
|
||||
@@ -70,7 +71,7 @@ const PurchaseItemObjectSchema: Yup.ObjectSchema<PurchaseItemSchema> =
|
||||
.required('Produk wajib dipilih!')
|
||||
.min(1, 'Produk wajib dipilih!')
|
||||
.typeError('Produk wajib dipilih!'),
|
||||
quantity: Yup.mixed<string | number>()
|
||||
qty: Yup.mixed<string | number>()
|
||||
.required('Kuantitas wajib diisi!')
|
||||
.test(
|
||||
'is-valid-qty',
|
||||
@@ -91,6 +92,10 @@ export const PurchaseRequestFormSchema: Yup.ObjectSchema<PurchaseRequestFormSche
|
||||
value: Yup.number().min(1).required(),
|
||||
label: Yup.string().required(),
|
||||
}).nullable(),
|
||||
credit_term: Yup.number()
|
||||
.required('Jangka waktu kredit wajib diisi!')
|
||||
.min(0, 'Jangka waktu kredit tidak boleh kurang dari 0!')
|
||||
.typeError('Jangka waktu kredit wajib diisi!'),
|
||||
supplier_id: Yup.number()
|
||||
.required('Supplier wajib dipilih!')
|
||||
.min(1, 'Supplier wajib dipilih!')
|
||||
@@ -143,6 +148,7 @@ export const getPurchaseRequestFormInitialValues = (
|
||||
}
|
||||
: null,
|
||||
supplier_id: initialValues?.supplier?.id ?? 0,
|
||||
credit_term: initialValues?.credit_term ?? 0,
|
||||
area: initialValues?.area
|
||||
? {
|
||||
value: initialValues.area.id,
|
||||
@@ -157,7 +163,6 @@ export const getPurchaseRequestFormInitialValues = (
|
||||
}
|
||||
: null,
|
||||
location_id: initialValues?.location?.id ?? 0,
|
||||
notes: initialValues?.notes ?? null,
|
||||
warehouse: initialValues?.warehouse
|
||||
? {
|
||||
value: initialValues.warehouse.id,
|
||||
@@ -165,5 +170,6 @@ export const getPurchaseRequestFormInitialValues = (
|
||||
}
|
||||
: undefined,
|
||||
warehouse_id: initialValues?.warehouse?.id ?? 0,
|
||||
notes: initialValues?.notes ?? null,
|
||||
items: [],
|
||||
});
|
||||
|
||||
@@ -68,13 +68,13 @@ const PurchaseRequestForm = ({
|
||||
product_warehouse_id: number;
|
||||
warehouse_id: number;
|
||||
warehouse_name: string;
|
||||
quantity: number;
|
||||
qty: number;
|
||||
}
|
||||
|
||||
// ===== UTILITY FUNCTIONS =====
|
||||
const getPurchaseItemError = (
|
||||
idx: number,
|
||||
field: 'warehouse_id' | 'product_warehouse_id' | 'product_id' | 'quantity'
|
||||
field: 'warehouse_id' | 'product_warehouse_id' | 'product_id' | 'qty'
|
||||
): { isError: boolean; errorMessage: string } => {
|
||||
const touchedItem = formik.touched.items?.[idx];
|
||||
const errorItem = formik.errors.items?.[idx] as
|
||||
@@ -191,32 +191,21 @@ const PurchaseRequestForm = ({
|
||||
typeof values.supplier_id === 'string'
|
||||
? parseInt(values.supplier_id) || 0
|
||||
: values.supplier_id || 0,
|
||||
credit_term: values.credit_term || 0,
|
||||
notes: values.notes || '',
|
||||
area_id:
|
||||
typeof values.area_id === 'string'
|
||||
? parseInt(values.area_id) || 0
|
||||
: values.area_id || 0,
|
||||
location_id:
|
||||
typeof values.location_id === 'string'
|
||||
? parseInt(values.location_id) || 0
|
||||
: values.location_id || 0,
|
||||
items: (values.items || []).map((item) => ({
|
||||
warehouse_id:
|
||||
typeof values.warehouse_id === 'string'
|
||||
? parseInt(values.warehouse_id) || 0
|
||||
: values.warehouse_id || 0,
|
||||
items: (values.items || []).map((item) => ({
|
||||
product_warehouse_id:
|
||||
typeof item.product_warehouse_id === 'string'
|
||||
? parseInt(item.product_warehouse_id) || 0
|
||||
: item.product_warehouse_id || 0,
|
||||
product_id:
|
||||
typeof item.product_id === 'string'
|
||||
? parseInt(item.product_id) || 0
|
||||
: item.product_id || 0,
|
||||
quantity:
|
||||
typeof item.quantity === 'string'
|
||||
? parseFloat(item.quantity) || 0
|
||||
: item.quantity || 0,
|
||||
qty:
|
||||
typeof item.qty === 'string'
|
||||
? parseFloat(item.qty) || 0
|
||||
: item.qty || 0,
|
||||
})),
|
||||
};
|
||||
|
||||
@@ -261,7 +250,7 @@ const PurchaseRequestForm = ({
|
||||
product_warehouse_id: pw.id,
|
||||
warehouse_id: pw.warehouse.id,
|
||||
warehouse_name: pw.warehouse.name,
|
||||
quantity: pw.quantity,
|
||||
qty: pw.quantity,
|
||||
})) || []
|
||||
);
|
||||
}, [productWarehouses]);
|
||||
@@ -295,6 +284,7 @@ const PurchaseRequestForm = ({
|
||||
});
|
||||
return data;
|
||||
}, [productsResponse]);
|
||||
|
||||
const locationsUrl = useMemo(() => {
|
||||
const params = new URLSearchParams({
|
||||
search: locationSelectInputValue,
|
||||
@@ -436,7 +426,7 @@ const PurchaseRequestForm = ({
|
||||
product_warehouse_id: null,
|
||||
product: null,
|
||||
product_id: '',
|
||||
quantity: '',
|
||||
qty: '',
|
||||
},
|
||||
];
|
||||
formik.setFieldValue('items', newPurchaseItems);
|
||||
@@ -460,13 +450,13 @@ const PurchaseRequestForm = ({
|
||||
// ===== PURCHASE ITEM OPERATIONS =====
|
||||
const handlePurchaseItemChange = (
|
||||
idx: number,
|
||||
field: 'quantity',
|
||||
field: 'qty',
|
||||
value: string | number
|
||||
) => {
|
||||
if (field === 'quantity') {
|
||||
if (field === 'qty') {
|
||||
const numValue =
|
||||
typeof value === 'string' ? parseFloat(value) || 0 : value;
|
||||
formik.setFieldValue(`items.${idx}.quantity`, numValue);
|
||||
formik.setFieldValue(`items.${idx}.qty`, numValue);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -519,28 +509,28 @@ const PurchaseRequestForm = ({
|
||||
isClearable
|
||||
/>
|
||||
|
||||
{/*<NumberInput*/}
|
||||
{/* required={!!formik.values.supplier_id}*/}
|
||||
{/* label='Jatuh tempo (hari)'*/}
|
||||
{/* name='credit_term'*/}
|
||||
{/* value={formik.values.credit_term || ''}*/}
|
||||
{/* onChange={formik.handleChange}*/}
|
||||
{/* onBlur={formik.handleBlur}*/}
|
||||
{/* isError={*/}
|
||||
{/* formik.touched.credit_term &&*/}
|
||||
{/* Boolean(formik.errors.credit_term)*/}
|
||||
{/* }*/}
|
||||
{/* errorMessage={formik.errors.credit_term as string}*/}
|
||||
{/* readOnly={type === 'detail' || !formik.values.supplier_id}*/}
|
||||
{/* disabled={type === 'detail' || !formik.values.supplier_id}*/}
|
||||
{/* allowNegative={false}*/}
|
||||
{/* decimalScale={0}*/}
|
||||
{/* placeholder={*/}
|
||||
{/* !formik.values.supplier_id*/}
|
||||
{/* ? 'Pilih Vendor terlebih dahulu'*/}
|
||||
{/* : 'Masukkan jumlah hari jatuh tempo'*/}
|
||||
{/* }*/}
|
||||
{/*/>*/}
|
||||
<NumberInput
|
||||
required={!!formik.values.supplier_id}
|
||||
label='Jatuh tempo (hari)'
|
||||
name='credit_term'
|
||||
value={formik.values.credit_term || ''}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
isError={
|
||||
formik.touched.credit_term &&
|
||||
Boolean(formik.errors.credit_term)
|
||||
}
|
||||
errorMessage={formik.errors.credit_term as string}
|
||||
readOnly={type === 'detail' || !formik.values.supplier_id}
|
||||
disabled={type === 'detail' || !formik.values.supplier_id}
|
||||
allowNegative={false}
|
||||
decimalScale={0}
|
||||
placeholder={
|
||||
!formik.values.supplier_id
|
||||
? 'Pilih Vendor terlebih dahulu'
|
||||
: 'Masukkan jumlah hari jatuh tempo'
|
||||
}
|
||||
/>
|
||||
|
||||
<SelectInput
|
||||
required
|
||||
@@ -579,62 +569,6 @@ const PurchaseRequestForm = ({
|
||||
key={`location-${formik.values.area_id}`}
|
||||
/>
|
||||
|
||||
<SelectInput
|
||||
required
|
||||
label='Gudang'
|
||||
placeholder={
|
||||
!formik.values.area_id
|
||||
? 'Pilih Area terlebih dahulu'
|
||||
: formik.values.location_id
|
||||
? 'Pilih Gudang...'
|
||||
: 'Pilih Area dan Lokasi terlebih dahulu'
|
||||
}
|
||||
value={formik.values.warehouse}
|
||||
onChange={(val) => {
|
||||
const warehouse = val as OptionType | null;
|
||||
formik.setFieldTouched('warehouse', true);
|
||||
formik.setFieldValue('warehouse', warehouse);
|
||||
formik.setFieldTouched('warehouse_id', true);
|
||||
formik.setFieldValue(
|
||||
'warehouse_id',
|
||||
(warehouse as OptionType)?.value || 0
|
||||
);
|
||||
if (formik.values.items) {
|
||||
formik.values.items.forEach((_, idx) => {
|
||||
formik.setFieldValue(
|
||||
`items.${idx}.product_warehouse`,
|
||||
null
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`items.${idx}.product_warehouse_id`,
|
||||
null
|
||||
);
|
||||
formik.setFieldValue(`items.${idx}.product`, null);
|
||||
formik.setFieldValue(`items.${idx}.product_id`, '');
|
||||
});
|
||||
}
|
||||
}}
|
||||
options={warehouseOptions}
|
||||
onInputChange={setWarehouseSelectInputValue}
|
||||
isLoading={isLoadingWarehouses}
|
||||
isError={
|
||||
formik.touched.warehouse &&
|
||||
Boolean(formik.errors.warehouse_id)
|
||||
}
|
||||
errorMessage={formik.errors.warehouse_id as string}
|
||||
isDisabled={
|
||||
type === 'detail' ||
|
||||
!formik.values.area_id ||
|
||||
!formik.values.location_id
|
||||
}
|
||||
isClearable={
|
||||
type !== 'detail' &&
|
||||
!!formik.values.area_id &&
|
||||
!!formik.values.location_id
|
||||
}
|
||||
key={`warehouse-${formik.values.area_id}-${formik.values.location_id}`}
|
||||
/>
|
||||
|
||||
<div className={'col-span-2'}>
|
||||
<TextInput
|
||||
label='Notes'
|
||||
@@ -691,6 +625,10 @@ const PurchaseRequestForm = ({
|
||||
/>
|
||||
</th>
|
||||
)}
|
||||
<th>
|
||||
Gudang
|
||||
<span className='text-error'>*</span>
|
||||
</th>
|
||||
<th>
|
||||
Item
|
||||
<span className='text-error'>*</span>
|
||||
@@ -733,113 +671,68 @@ const PurchaseRequestForm = ({
|
||||
/>
|
||||
</td>
|
||||
)}
|
||||
{/*<td>*/}
|
||||
{/* <SelectInput*/}
|
||||
{/* required*/}
|
||||
{/* value={item.warehouse}*/}
|
||||
{/* key={`warehouse-${idx}`}*/}
|
||||
{/* onChange={(val) => {*/}
|
||||
{/* const warehouse = val as OptionType | null;*/}
|
||||
{/* formik.setFieldValue(*/}
|
||||
{/* `purchase_items.${idx}.warehouse`,*/}
|
||||
{/* warehouse*/}
|
||||
{/* );*/}
|
||||
{/* formik.setFieldValue(*/}
|
||||
{/* `purchase_items.${idx}.warehouse_id`,*/}
|
||||
{/* (warehouse as OptionType)?.value || 0*/}
|
||||
{/* );*/}
|
||||
{/* formik.setFieldTouched(*/}
|
||||
{/* `purchase_items.${idx}.product_warehouse`,*/}
|
||||
{/* false*/}
|
||||
{/* );*/}
|
||||
{/* formik.setFieldValue(*/}
|
||||
{/* `purchase_items.${idx}.product_warehouse`,*/}
|
||||
{/* null*/}
|
||||
{/* );*/}
|
||||
{/* formik.setFieldTouched(*/}
|
||||
{/* `purchase_items.${idx}.product_warehouse_id`,*/}
|
||||
{/* false*/}
|
||||
{/* );*/}
|
||||
{/* formik.setFieldValue(*/}
|
||||
{/* `purchase_items.${idx}.product_warehouse_id`,*/}
|
||||
{/* 0*/}
|
||||
{/* );*/}
|
||||
{/* formik.setFieldTouched(*/}
|
||||
{/* `purchase_items.${idx}.product_id`,*/}
|
||||
{/* false*/}
|
||||
{/* );*/}
|
||||
{/* formik.setFieldValue(*/}
|
||||
{/* `purchase_items.${idx}.product_id`,*/}
|
||||
{/* 0*/}
|
||||
{/* );*/}
|
||||
{/* }}*/}
|
||||
{/* options={warehouseOptions}*/}
|
||||
{/* onInputChange={setWarehouseSelectInputValue}*/}
|
||||
{/* isLoading={isLoadingWarehouses}*/}
|
||||
{/* isError={*/}
|
||||
{/* getPurchaseItemError(idx, 'warehouse_id').isError*/}
|
||||
{/* }*/}
|
||||
{/* errorMessage={*/}
|
||||
{/* getPurchaseItemError(idx, 'warehouse_id')*/}
|
||||
{/* .errorMessage*/}
|
||||
{/* }*/}
|
||||
{/* isDisabled={type === 'detail'}*/}
|
||||
{/* isClearable*/}
|
||||
{/* placeholder='Pilih Gudang'*/}
|
||||
{/* className={{*/}
|
||||
{/* wrapper: 'min-w-32',*/}
|
||||
{/* }}*/}
|
||||
{/* />*/}
|
||||
{/*</td>*/}
|
||||
{/*<td>*/}
|
||||
{/* <SelectInput*/}
|
||||
{/* required*/}
|
||||
{/* value={item.product_warehouse}*/}
|
||||
{/* key={`product-warehouse-${idx}-${item.warehouse_id}`}*/}
|
||||
{/* onChange={(val) => {*/}
|
||||
{/* const productWarehouse =*/}
|
||||
{/* val as ProductWarehouseOptionType | null;*/}
|
||||
{/* formik.setFieldValue(*/}
|
||||
{/* `purchase_items.${idx}.product_warehouse`,*/}
|
||||
{/* productWarehouse*/}
|
||||
{/* );*/}
|
||||
{/* formik.setFieldValue(*/}
|
||||
{/* `purchase_items.${idx}.product_warehouse_id`,*/}
|
||||
{/* (productWarehouse as ProductWarehouseOptionType)*/}
|
||||
{/* ?.value || 0*/}
|
||||
{/* );*/}
|
||||
{/* const productId =*/}
|
||||
{/* (productWarehouse as ProductWarehouseOptionType)*/}
|
||||
{/* ?.product_id || 0;*/}
|
||||
{/* formik.setFieldValue(*/}
|
||||
{/* `purchase_items.${idx}.product_id`,*/}
|
||||
{/* productId*/}
|
||||
{/* );*/}
|
||||
{/* }}*/}
|
||||
{/* options={getProductWarehouseOptionsForItem(*/}
|
||||
{/* item.warehouse_id*/}
|
||||
{/* )}*/}
|
||||
{/* isLoading={isLoadingProductWarehouses}*/}
|
||||
{/* isError={*/}
|
||||
{/* getPurchaseItemError(idx, 'product_warehouse_id')*/}
|
||||
{/* .isError*/}
|
||||
{/* }*/}
|
||||
{/* errorMessage={*/}
|
||||
{/* getPurchaseItemError(idx, 'product_warehouse_id')*/}
|
||||
{/* .errorMessage*/}
|
||||
{/* }*/}
|
||||
{/* isDisabled={type === 'detail' || !item.warehouse_id}*/}
|
||||
{/* isClearable={type !== 'detail' && !!item.warehouse_id}*/}
|
||||
{/* placeholder={*/}
|
||||
{/* !item.warehouse_id*/}
|
||||
{/* ? 'Pilih Gudang terlebih dahulu'*/}
|
||||
{/* : 'Pilih Produk'*/}
|
||||
{/* }*/}
|
||||
{/* className={{*/}
|
||||
{/* wrapper: 'min-w-32',*/}
|
||||
{/* }}*/}
|
||||
{/* />*/}
|
||||
{/*</td>*/}
|
||||
<td>
|
||||
<SelectInput
|
||||
required
|
||||
placeholder={
|
||||
!formik.values.area_id
|
||||
? 'Pilih Area terlebih dahulu'
|
||||
: formik.values.location_id
|
||||
? 'Pilih Gudang...'
|
||||
: 'Pilih Area dan Lokasi terlebih dahulu'
|
||||
}
|
||||
value={formik.values.warehouse}
|
||||
onChange={(val) => {
|
||||
const warehouse = val as OptionType | null;
|
||||
formik.setFieldTouched('warehouse', true);
|
||||
formik.setFieldValue('warehouse', warehouse);
|
||||
formik.setFieldTouched('warehouse_id', true);
|
||||
formik.setFieldValue(
|
||||
'warehouse_id',
|
||||
(warehouse as OptionType)?.value || 0
|
||||
);
|
||||
if (formik.values.items) {
|
||||
formik.values.items.forEach((_, idx) => {
|
||||
formik.setFieldValue(
|
||||
`items.${idx}.product_warehouse`,
|
||||
null
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`items.${idx}.product_warehouse_id`,
|
||||
null
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`items.${idx}.product`,
|
||||
null
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`items.${idx}.product_id`,
|
||||
''
|
||||
);
|
||||
});
|
||||
}
|
||||
}}
|
||||
options={warehouseOptions}
|
||||
onInputChange={setWarehouseSelectInputValue}
|
||||
isLoading={isLoadingWarehouses}
|
||||
isError={
|
||||
formik.touched.warehouse &&
|
||||
Boolean(formik.errors.warehouse_id)
|
||||
}
|
||||
errorMessage={formik.errors.warehouse_id as string}
|
||||
isDisabled={
|
||||
type === 'detail' ||
|
||||
!formik.values.area_id ||
|
||||
!formik.values.location_id
|
||||
}
|
||||
isClearable={
|
||||
type !== 'detail' &&
|
||||
!!formik.values.area_id &&
|
||||
!!formik.values.location_id
|
||||
}
|
||||
key={`warehouse-${formik.values.area_id}-${formik.values.location_id}`}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<SelectInput
|
||||
required
|
||||
@@ -895,25 +788,19 @@ const PurchaseRequestForm = ({
|
||||
<td>
|
||||
<NumberInput
|
||||
required
|
||||
name={`items.${idx}.quantity`}
|
||||
value={item.quantity || ''}
|
||||
name={`items.${idx}.qty`}
|
||||
value={item.qty || ''}
|
||||
onChange={(e) =>
|
||||
handlePurchaseItemChange(
|
||||
idx,
|
||||
'quantity',
|
||||
e.target.value
|
||||
)
|
||||
handlePurchaseItemChange(idx, 'qty', e.target.value)
|
||||
}
|
||||
onBlur={formik.handleBlur}
|
||||
placeholder='Masukkan kuantitas'
|
||||
readOnly={type === 'detail'}
|
||||
allowNegative={false}
|
||||
decimalScale={0}
|
||||
isError={
|
||||
getPurchaseItemError(idx, 'quantity').isError
|
||||
}
|
||||
isError={getPurchaseItemError(idx, 'qty').isError}
|
||||
errorMessage={
|
||||
getPurchaseItemError(idx, 'quantity').errorMessage
|
||||
getPurchaseItemError(idx, 'qty').errorMessage
|
||||
}
|
||||
className={{
|
||||
wrapper: 'min-w-24',
|
||||
@@ -928,9 +815,7 @@ const PurchaseRequestForm = ({
|
||||
item.product_id && productData[item.product_id]
|
||||
? (
|
||||
productData[item.product_id].product_price *
|
||||
(parseFloat(
|
||||
item.quantity?.toString() || '0'
|
||||
) || 0)
|
||||
(parseFloat(item.qty?.toString() || '0') || 0)
|
||||
).toLocaleString('en-US')
|
||||
: ''
|
||||
}
|
||||
|
||||
Vendored
+4
-5
@@ -13,6 +13,7 @@ export type PurchaseItem = {
|
||||
product: Product;
|
||||
product_warehouse: ProductWarehouse;
|
||||
quantity: number;
|
||||
qty: number;
|
||||
sub_qty: number;
|
||||
total_qty: number;
|
||||
total_used: number;
|
||||
@@ -47,14 +48,12 @@ export type Purchase = BaseMetadata & BasePurchase;
|
||||
|
||||
export type CreatePurchaseRequestPayload = {
|
||||
supplier_id: number;
|
||||
area_id: number;
|
||||
location_id: number;
|
||||
warehouse_id: number;
|
||||
credit_term: number;
|
||||
notes?: string | null;
|
||||
items: {
|
||||
product_warehouse_id: number;
|
||||
warehouse_id: number;
|
||||
product_id: number;
|
||||
quantity: number;
|
||||
qty: number;
|
||||
}[];
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user