mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 21:41:57 +00:00
refactor(FE-208): rename PurchaseRequestForm to PurchaseRequisitionsForm and update related components
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import PurchaseRequestForm from '@/components/pages/purchase/form/request/PurchaseRequestForm';
|
||||
import PurchaseRequisitionsForm from '@/components/pages/purchase/form/request/PurchaseRequisitionsForm';
|
||||
|
||||
const AddPurchaseRequest = () => {
|
||||
const AddPurchaseRequisitions = () => {
|
||||
return (
|
||||
<div className='w-full p-4 flex flex-row justify-center'>
|
||||
<PurchaseRequestForm />
|
||||
<PurchaseRequisitionsForm />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddPurchaseRequest;
|
||||
export default AddPurchaseRequisitions;
|
||||
|
||||
@@ -2,243 +2,9 @@
|
||||
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import PurchaseRequestForm from '@/components/pages/purchase/form/request/PurchaseRequestForm';
|
||||
|
||||
import PurchaseRequisitionsForm from '@/components/pages/purchase/form/request/PurchaseRequisitionsForm';
|
||||
import { PurchaseApi } from '@/services/api/purchase';
|
||||
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||
|
||||
import { Purchase } from '@/types/api/purchase/purchase';
|
||||
|
||||
// TODO: delete dummy data
|
||||
const DUMMY_PURCHASE_EDIT: Purchase = {
|
||||
id: 1,
|
||||
pr_number: 'PR-001',
|
||||
po_number: 'PO-001',
|
||||
po_date: '2024-01-15',
|
||||
supplier: {
|
||||
id: 1,
|
||||
name: 'Supplier A',
|
||||
address: '123 Main St, Cityville',
|
||||
account_number: 'ACC-12345',
|
||||
alias: 'SupA',
|
||||
category: 'Electronics',
|
||||
type: 'Local',
|
||||
phone: '555-1234',
|
||||
email: 'email@.com',
|
||||
npwp: '12.345.678.9-012.345',
|
||||
pic: 'John Doe',
|
||||
balance: 1000000,
|
||||
hatchery: 'N/A',
|
||||
due_date: 30,
|
||||
created_at: '2024-01-10T10:00:00Z',
|
||||
updated_at: '2024-01-12T12:00:00Z',
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
},
|
||||
credit_term: 30,
|
||||
due_date: '2024-02-14',
|
||||
grand_total: 1500000,
|
||||
notes: 'Urgent delivery required',
|
||||
deleted_at: null,
|
||||
created_at: '2024-01-10T10:00:00Z',
|
||||
updated_at: '2024-01-12T12:00:00Z',
|
||||
created_by: 2,
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
purchase_items: [
|
||||
{
|
||||
id: 1,
|
||||
product_warehouse: {
|
||||
id: 1,
|
||||
product_id: 1,
|
||||
warehouse_id: 1,
|
||||
quantity: 100,
|
||||
product: {
|
||||
id: 1,
|
||||
name: 'Product A',
|
||||
brand: 'Brand A',
|
||||
sku: 'PROD-A-001',
|
||||
product_price: 500000,
|
||||
expiry_period: 0,
|
||||
uom: {
|
||||
id: 1,
|
||||
name: 'pcs',
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
},
|
||||
product_category: {
|
||||
id: 1,
|
||||
code: 'CAT-1',
|
||||
name: 'Electronics',
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
},
|
||||
suppliers: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Supplier A',
|
||||
alias: 'SupA',
|
||||
pic: 'John Doe',
|
||||
type: 'Local',
|
||||
category: 'Electronics',
|
||||
hatchery: 'N/A',
|
||||
phone: '555-1234',
|
||||
email: 'email@.com',
|
||||
address: '123 Main St, Cityville',
|
||||
npwp: '12.345.678.9-012.345',
|
||||
account_number: 'ACC-12345',
|
||||
due_date: 30,
|
||||
balance: 1000000,
|
||||
created_at: '2024-01-10T10:00:00Z',
|
||||
updated_at: '2024-01-12T12:00:00Z',
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
},
|
||||
],
|
||||
flags: [],
|
||||
created_at: '2024-01-05T09:00:00Z',
|
||||
updated_at: '2024-01-07T11:00:00Z',
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
},
|
||||
warehouse: {
|
||||
id: 1,
|
||||
name: 'Main Warehouse',
|
||||
type: 'AREA',
|
||||
area: { id: 1, name: 'Area 1' },
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
},
|
||||
created_at: '2024-01-05T09:00:00Z',
|
||||
updated_at: '2024-01-07T11:00:00Z',
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
},
|
||||
product: {
|
||||
id: 1,
|
||||
name: 'Product A',
|
||||
brand: 'Brand A',
|
||||
sku: 'PROD-A-001',
|
||||
product_price: 500000,
|
||||
expiry_period: 0,
|
||||
uom: {
|
||||
id: 1,
|
||||
name: 'pcs',
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
},
|
||||
product_category: {
|
||||
id: 1,
|
||||
code: 'CAT-1',
|
||||
name: 'Electronics',
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
},
|
||||
suppliers: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Supplier A',
|
||||
alias: 'SupA',
|
||||
pic: 'John Doe',
|
||||
type: 'Local',
|
||||
category: 'Electronics',
|
||||
hatchery: 'N/A',
|
||||
phone: '555-1234',
|
||||
email: 'email@.com',
|
||||
address: '123 Main St, Cityville',
|
||||
npwp: '12.345.678.9-012.345',
|
||||
account_number: 'ACC-12345',
|
||||
due_date: 30,
|
||||
balance: 1000000,
|
||||
created_at: '2024-01-10T10:00:00Z',
|
||||
updated_at: '2024-01-12T12:00:00Z',
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
},
|
||||
],
|
||||
flags: [],
|
||||
created_at: '2024-01-05T09:00:00Z',
|
||||
updated_at: '2024-01-07T11:00:00Z',
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
},
|
||||
warehouse: {
|
||||
id: 1,
|
||||
name: 'Main Warehouse',
|
||||
type: 'AREA',
|
||||
area: { id: 1, name: 'Area 1' },
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
},
|
||||
sub_qty: 3,
|
||||
},
|
||||
],
|
||||
};
|
||||
import { isResponseSuccess, isResponseError } from '@/lib/api-helper';
|
||||
|
||||
const PurchaseEdit = () => {
|
||||
const router = useRouter();
|
||||
@@ -261,11 +27,7 @@ const PurchaseEdit = () => {
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: remove dummy data and integrate with real API
|
||||
if (
|
||||
!isLoadingPurchase &&
|
||||
(!purchase || (isResponseError(purchase) && !DUMMY_PURCHASE_EDIT))
|
||||
) {
|
||||
if (!isLoadingPurchase && (!purchase || isResponseError(purchase))) {
|
||||
router.replace('/404');
|
||||
return;
|
||||
}
|
||||
@@ -275,9 +37,9 @@ const PurchaseEdit = () => {
|
||||
{isLoadingPurchase && (
|
||||
<span className='loading loading-spinner loading-xl' />
|
||||
)}
|
||||
|
||||
{/* DEBUG TEMP: force dummy to verify form mapping/rendering */}
|
||||
<PurchaseRequestForm type='edit' initialValues={DUMMY_PURCHASE_EDIT} />
|
||||
{!isLoadingPurchase && isResponseSuccess(purchase) && (
|
||||
<PurchaseRequisitionsForm type='edit' initialValues={purchase.data} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,59 +2,9 @@
|
||||
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import PurchaseRequestForm from '@/components/pages/purchase/form/request/PurchaseRequestForm';
|
||||
|
||||
import PurchaseRequisitionsForm from '@/components/pages/purchase/form/request/PurchaseRequisitionsForm';
|
||||
import { PurchaseApi } from '@/services/api/purchase';
|
||||
import { isResponseError } from '@/lib/api-helper';
|
||||
|
||||
import { Purchase } from '@/types/api/purchase/purchase';
|
||||
|
||||
// TODO: delete dummy data
|
||||
const DUMMY_PURCHASE_DETAIL: Purchase = {
|
||||
id: 1,
|
||||
pr_number: 'PR-001',
|
||||
po_number: 'PO-001',
|
||||
po_date: '2024-01-15',
|
||||
supplier: {
|
||||
id: 1,
|
||||
name: 'Supplier A',
|
||||
address: '123 Main St, Cityville',
|
||||
account_number: 'ACC-12345',
|
||||
alias: 'SupA',
|
||||
category: 'Electronics',
|
||||
type: 'Local',
|
||||
phone: '555-1234',
|
||||
email: 'email@.com',
|
||||
npwp: '12.345.678.9-012.345',
|
||||
pic: 'John Doe',
|
||||
balance: 1000000,
|
||||
hatchery: 'N/A',
|
||||
due_date: 30,
|
||||
created_at: '2024-01-10T10:00:00Z',
|
||||
updated_at: '2024-01-12T12:00:00Z',
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
},
|
||||
credit_term: 30,
|
||||
due_date: '2024-02-14',
|
||||
grand_total: 1500000,
|
||||
notes: 'Urgent delivery required',
|
||||
deleted_at: null,
|
||||
created_at: '2024-01-10T10:00:00Z',
|
||||
updated_at: '2024-01-12T12:00:00Z',
|
||||
created_by: 2,
|
||||
created_user: {
|
||||
id: 2,
|
||||
id_user: 2,
|
||||
email: 'a@email.com',
|
||||
name: 'Admin User',
|
||||
},
|
||||
};
|
||||
import { isResponseSuccess, isResponseError } from '@/lib/api-helper';
|
||||
|
||||
const PurchaseDetail = () => {
|
||||
const router = useRouter();
|
||||
@@ -77,11 +27,7 @@ const PurchaseDetail = () => {
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: remove dummy data and integrate with real API
|
||||
if (
|
||||
!isLoadingPurchase &&
|
||||
(!purchase || (isResponseError(purchase) && !DUMMY_PURCHASE_DETAIL))
|
||||
) {
|
||||
if (!isLoadingPurchase && (!purchase || isResponseError(purchase))) {
|
||||
router.replace('/404');
|
||||
return;
|
||||
}
|
||||
@@ -91,15 +37,9 @@ const PurchaseDetail = () => {
|
||||
{isLoadingPurchase && (
|
||||
<span className='loading loading-spinner loading-xl' />
|
||||
)}
|
||||
{/* {!isLoadingPurchase && isResponseSuccess(purchase) && (
|
||||
<PurchaseRequestForm type='detail' initialValues={purchase.data} />
|
||||
)} */}
|
||||
|
||||
{/* TODO: remove this dummy data and integrate to real API */}
|
||||
<PurchaseRequestForm
|
||||
type='detail'
|
||||
initialValues={DUMMY_PURCHASE_DETAIL}
|
||||
/>
|
||||
{!isLoadingPurchase && isResponseSuccess(purchase) && (
|
||||
<PurchaseRequisitionsForm type='detail' initialValues={purchase.data} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -149,9 +149,12 @@ const PurchaseTable = () => {
|
||||
cell: (props) => props.row.original.supplier.name,
|
||||
},
|
||||
{
|
||||
accessorKey: 'created_user',
|
||||
accessorKey: 'created_by',
|
||||
header: 'Nama Pengaju',
|
||||
cell: (props) => props.row.original.created_user.name,
|
||||
cell: (props) => {
|
||||
const purchase = props.row.original;
|
||||
return purchase.created_user?.name || `User ID: ${purchase.created_by}`;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'po_date',
|
||||
@@ -172,8 +175,9 @@ const PurchaseTable = () => {
|
||||
{
|
||||
header: 'Aging',
|
||||
cell: (props) => {
|
||||
if (!props.row.original.po_date) return '-';
|
||||
const poDate = new Date(props.row.original.po_date);
|
||||
const purchase = props.row.original;
|
||||
if (!purchase.po_date) return '-';
|
||||
const poDate = new Date(purchase.po_date);
|
||||
const today = new Date();
|
||||
const diffTime = Math.abs(today.getTime() - poDate.getTime());
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
|
||||
+276
-188
@@ -17,11 +17,11 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
||||
import { useModal } from '@/components/Modal';
|
||||
|
||||
import {
|
||||
PurchaseRequestFormSchema,
|
||||
PurchaseRequestFormValues,
|
||||
getPurchaseRequestFormInitialValues,
|
||||
UpdatePurchaseRequestFormSchema,
|
||||
} from './PurchaseRequestForm.schema';
|
||||
PurchaseRequisitionsFormSchema,
|
||||
PurchaseRequisitionsFormValues,
|
||||
getPurchaseRequisitionsFormInitialValues,
|
||||
UpdatePurchaseRequisitionsFormSchema,
|
||||
} from './PurchaseRequisitionsForm.schema';
|
||||
import {
|
||||
SupplierApi,
|
||||
AreaApi,
|
||||
@@ -37,7 +37,7 @@ import { PurchaseApi } from '@/services/api/purchase';
|
||||
|
||||
import Card from '@/components/Card';
|
||||
import {
|
||||
CreatePurchaseRequestPayload,
|
||||
CreatePurchaseRequisitionsPayload,
|
||||
Purchase,
|
||||
} from '@/types/api/purchase/purchase';
|
||||
|
||||
@@ -46,7 +46,7 @@ interface PurchaseRequestFormProps {
|
||||
initialValues?: Purchase;
|
||||
}
|
||||
|
||||
const PurchaseRequestForm = ({
|
||||
const PurchaseRequisitionsForm = ({
|
||||
type = 'add',
|
||||
initialValues,
|
||||
}: PurchaseRequestFormProps) => {
|
||||
@@ -72,10 +72,10 @@ const PurchaseRequestForm = ({
|
||||
// ===== UTILITY FUNCTIONS =====
|
||||
const getPurchaseItemError = (
|
||||
idx: number,
|
||||
field: 'warehouse_id' | 'product_warehouse_id' | 'product_id' | 'sub_qty'
|
||||
field: 'warehouse_id' | 'product_warehouse_id' | 'product_id' | 'quantity'
|
||||
): { isError: boolean; errorMessage: string } => {
|
||||
const touchedItem = formik.touched.purchase_items?.[idx];
|
||||
const errorItem = formik.errors.purchase_items?.[idx] as
|
||||
const touchedItem = formik.touched.items?.[idx];
|
||||
const errorItem = formik.errors.items?.[idx] as
|
||||
| Record<string, string>
|
||||
| undefined;
|
||||
|
||||
@@ -103,7 +103,7 @@ const PurchaseRequestForm = ({
|
||||
|
||||
// ===== SUBMISSION HANDLERS =====
|
||||
const createPurchaseRequestHandler = useCallback(
|
||||
async (payload: CreatePurchaseRequestPayload) => {
|
||||
async (payload: CreatePurchaseRequisitionsPayload) => {
|
||||
const res = await PurchaseApi.create(payload);
|
||||
if (isResponseError(res)) {
|
||||
setPurchaseRequestFormErrorMessage(res.message);
|
||||
@@ -118,7 +118,7 @@ const PurchaseRequestForm = ({
|
||||
const updatePurchaseRequestHandler = useCallback(
|
||||
async (
|
||||
purchaseRequestId: number,
|
||||
payload: CreatePurchaseRequestPayload
|
||||
payload: CreatePurchaseRequisitionsPayload
|
||||
) => {
|
||||
const res = await PurchaseApi.update(purchaseRequestId, payload);
|
||||
if (isResponseError(res)) {
|
||||
@@ -170,47 +170,51 @@ const PurchaseRequestForm = ({
|
||||
} = useSelect(WarehouseApi.basePath, 'id', 'name', 'search');
|
||||
|
||||
// ===== FORM CONFIGURATION =====
|
||||
const formikInitialValues = useMemo<PurchaseRequestFormValues>(
|
||||
() => getPurchaseRequestFormInitialValues(initialValues),
|
||||
const formikInitialValues = useMemo<PurchaseRequisitionsFormValues>(
|
||||
() => getPurchaseRequisitionsFormInitialValues(initialValues),
|
||||
[initialValues]
|
||||
);
|
||||
|
||||
const formik = useFormik<PurchaseRequestFormValues>({
|
||||
const formik = useFormik<PurchaseRequisitionsFormValues>({
|
||||
initialValues: formikInitialValues,
|
||||
validationSchema:
|
||||
type === 'edit'
|
||||
? UpdatePurchaseRequestFormSchema
|
||||
: PurchaseRequestFormSchema,
|
||||
? UpdatePurchaseRequisitionsFormSchema
|
||||
: PurchaseRequisitionsFormSchema,
|
||||
validateOnChange: true,
|
||||
validateOnBlur: true,
|
||||
onSubmit: async (values) => {
|
||||
const payload: CreatePurchaseRequestPayload = {
|
||||
const payload: CreatePurchaseRequisitionsPayload = {
|
||||
supplier_id:
|
||||
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 || '',
|
||||
purchase_items: (values.purchase_items || []).map((item) => ({
|
||||
warehouse_id:
|
||||
typeof item.warehouse_id === 'string'
|
||||
? parseInt(item.warehouse_id) || 0
|
||||
: item.warehouse_id || 0,
|
||||
product_id:
|
||||
typeof item.product_id === 'string'
|
||||
? parseInt(item.product_id) || 0
|
||||
: item.product_id || 0,
|
||||
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,
|
||||
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,
|
||||
sub_qty:
|
||||
typeof item.sub_qty === 'string'
|
||||
? parseFloat(item.sub_qty) || 0
|
||||
: item.sub_qty || 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,
|
||||
})),
|
||||
};
|
||||
|
||||
@@ -261,7 +265,7 @@ const PurchaseRequestForm = ({
|
||||
|
||||
const productUrl = useMemo(() => {
|
||||
const productIds =
|
||||
formik.values.purchase_items
|
||||
formik.values.items
|
||||
?.filter(
|
||||
(item) => item.product_id && typeof item.product_id === 'number'
|
||||
)
|
||||
@@ -272,7 +276,7 @@ const PurchaseRequestForm = ({
|
||||
id: productIds.join(','),
|
||||
}).toString()}`
|
||||
: null;
|
||||
}, [formik.values.purchase_items]);
|
||||
}, [formik.values.items]);
|
||||
|
||||
const { data: productsResponse } = useSWR(
|
||||
productUrl,
|
||||
@@ -392,16 +396,12 @@ const PurchaseRequestForm = ({
|
||||
setLocationSelectInputValue('');
|
||||
|
||||
// Reset area dependent fields in all purchase items
|
||||
if (formik.values.purchase_items) {
|
||||
formik.values.purchase_items.forEach((_, idx) => {
|
||||
formik.setFieldValue(`purchase_items.${idx}.warehouse`, null);
|
||||
formik.setFieldValue(`purchase_items.${idx}.warehouse_id`, '');
|
||||
formik.setFieldValue(`purchase_items.${idx}.product_warehouse`, null);
|
||||
formik.setFieldValue(
|
||||
`purchase_items.${idx}.product_warehouse_id`,
|
||||
null
|
||||
);
|
||||
formik.setFieldValue(`purchase_items.${idx}.product_id`, '');
|
||||
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`, '');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -414,16 +414,12 @@ const PurchaseRequestForm = ({
|
||||
formik.setFieldValue('location_id', (location as OptionType)?.value || 0);
|
||||
|
||||
// Reset location dependent fields in all purchase items
|
||||
if (formik.values.purchase_items) {
|
||||
formik.values.purchase_items.forEach((_, idx) => {
|
||||
formik.setFieldValue(`purchase_items.${idx}.warehouse`, null);
|
||||
formik.setFieldValue(`purchase_items.${idx}.warehouse_id`, '');
|
||||
formik.setFieldValue(`purchase_items.${idx}.product_warehouse`, null);
|
||||
formik.setFieldValue(
|
||||
`purchase_items.${idx}.product_warehouse_id`,
|
||||
null
|
||||
);
|
||||
formik.setFieldValue(`purchase_items.${idx}.product_id`, '');
|
||||
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`, '');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -431,48 +427,43 @@ const PurchaseRequestForm = ({
|
||||
// Purchase Items Handlers
|
||||
const addPurchaseItem = () => {
|
||||
const newPurchaseItems = [
|
||||
...(formik.values.purchase_items || []),
|
||||
...(formik.values.items || []),
|
||||
{
|
||||
warehouse: null,
|
||||
warehouse_id: '',
|
||||
product: null,
|
||||
product_id: '',
|
||||
product_warehouse: null,
|
||||
product_warehouse_id: null,
|
||||
sub_qty: '',
|
||||
product: null,
|
||||
product_id: '',
|
||||
quantity: '',
|
||||
},
|
||||
];
|
||||
formik.setFieldValue('purchase_items', newPurchaseItems);
|
||||
formik.setFieldValue('items', newPurchaseItems);
|
||||
};
|
||||
|
||||
const removePurchaseItem = (idx: number) => {
|
||||
const updatedPurchaseItems = formik.values.purchase_items?.filter(
|
||||
const updatedPurchaseItems = formik.values.items?.filter(
|
||||
(_, i) => i !== idx
|
||||
);
|
||||
formik.setFieldValue('purchase_items', updatedPurchaseItems);
|
||||
formik.setFieldValue('items', updatedPurchaseItems);
|
||||
};
|
||||
|
||||
const removeSelectedPurchaseItems = () => {
|
||||
const updatedPurchaseItems = formik.values.purchase_items?.filter(
|
||||
const updatedPurchaseItems = formik.values.items?.filter(
|
||||
(_, idx) => !selectedPurchaseItems.includes(idx)
|
||||
);
|
||||
formik.setFieldValue('purchase_items', updatedPurchaseItems);
|
||||
formik.setFieldValue('items', updatedPurchaseItems);
|
||||
setSelectedPurchaseItems([]);
|
||||
};
|
||||
|
||||
// ===== PURCHASE ITEM OPERATIONS =====
|
||||
const handlePurchaseItemChange = (
|
||||
idx: number,
|
||||
field: 'sub_qty' | 'price',
|
||||
field: 'quantity',
|
||||
value: string | number
|
||||
) => {
|
||||
if (field === 'sub_qty') {
|
||||
const numValue = typeof value === 'string' ? parseInt(value) || 0 : value;
|
||||
formik.setFieldValue(`purchase_items.${idx}.sub_qty`, numValue);
|
||||
} else if (field === 'price') {
|
||||
if (field === 'quantity') {
|
||||
const numValue =
|
||||
typeof value === 'string' ? parseFloat(value) || 0 : value;
|
||||
formik.setFieldValue(`purchase_items.${idx}.price`, numValue);
|
||||
formik.setFieldValue(`items.${idx}.quantity`, numValue);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -525,28 +516,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
|
||||
label='Area'
|
||||
@@ -583,6 +574,59 @@ const PurchaseRequestForm = ({
|
||||
key={`location-${formik.values.area_id}`}
|
||||
/>
|
||||
|
||||
<SelectInput
|
||||
label='Gudang'
|
||||
placeholder={
|
||||
!formik.values.area_id || !formik.values.location_id
|
||||
? 'Pilih Area dan Lokasi terlebih dahulu'
|
||||
: 'Pilih Gudang...'
|
||||
}
|
||||
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'
|
||||
@@ -618,16 +662,14 @@ const PurchaseRequestForm = ({
|
||||
type='checkbox'
|
||||
className='checkbox checkbox-sm'
|
||||
checked={
|
||||
formik.values.purchase_items?.length ===
|
||||
formik.values.items?.length ===
|
||||
selectedPurchaseItems.length &&
|
||||
formik.values.purchase_items?.length > 0
|
||||
formik.values.items?.length > 0
|
||||
}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setSelectedPurchaseItems(
|
||||
formik.values.purchase_items?.map(
|
||||
(_, idx) => idx
|
||||
) ?? []
|
||||
formik.values.items?.map((_, idx) => idx) ?? []
|
||||
);
|
||||
} else {
|
||||
setSelectedPurchaseItems([]);
|
||||
@@ -636,10 +678,6 @@ const PurchaseRequestForm = ({
|
||||
/>
|
||||
</th>
|
||||
)}
|
||||
<th>
|
||||
Gudang
|
||||
<span className='text-error'>*</span>
|
||||
</th>
|
||||
<th>
|
||||
Item
|
||||
<span className='text-error'>*</span>
|
||||
@@ -654,7 +692,7 @@ const PurchaseRequestForm = ({
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{formik.values.purchase_items?.map((item, idx) => (
|
||||
{formik.values.items?.map((item, idx) => (
|
||||
<tr key={`purchase-item-${idx}`}>
|
||||
{type !== 'detail' && (
|
||||
<td className='!align-middle'>
|
||||
@@ -677,91 +715,141 @@ 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.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
|
||||
value={item.product_warehouse}
|
||||
key={`product-warehouse-${idx}-${item.warehouse_id}`}
|
||||
key={`product-warehouse-${idx}-${formik.values.warehouse_id}`}
|
||||
onChange={(val) => {
|
||||
const productWarehouse =
|
||||
val as ProductWarehouseOptionType | null;
|
||||
formik.setFieldValue(
|
||||
`purchase_items.${idx}.product_warehouse`,
|
||||
`items.${idx}.product_warehouse`,
|
||||
productWarehouse
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`purchase_items.${idx}.product_warehouse_id`,
|
||||
`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`,
|
||||
`items.${idx}.product_id`,
|
||||
productId
|
||||
);
|
||||
}}
|
||||
options={getProductWarehouseOptionsForItem(
|
||||
item.warehouse_id
|
||||
formik.values.warehouse_id
|
||||
)}
|
||||
isLoading={isLoadingProductWarehouses}
|
||||
isError={
|
||||
@@ -772,10 +860,14 @@ const PurchaseRequestForm = ({
|
||||
getPurchaseItemError(idx, 'product_warehouse_id')
|
||||
.errorMessage
|
||||
}
|
||||
isDisabled={type === 'detail' || !item.warehouse_id}
|
||||
isClearable={type !== 'detail' && !!item.warehouse_id}
|
||||
isDisabled={
|
||||
type === 'detail' || !formik.values.warehouse_id
|
||||
}
|
||||
isClearable={
|
||||
type !== 'detail' && !!formik.values.warehouse_id
|
||||
}
|
||||
placeholder={
|
||||
!item.warehouse_id
|
||||
!formik.values.warehouse_id
|
||||
? 'Pilih Gudang terlebih dahulu'
|
||||
: 'Pilih Produk'
|
||||
}
|
||||
@@ -787,12 +879,12 @@ const PurchaseRequestForm = ({
|
||||
<td>
|
||||
<NumberInput
|
||||
required
|
||||
name={`purchase_items.${idx}.sub_qty`}
|
||||
value={item.sub_qty || ''}
|
||||
name={`items.${idx}.quantity`}
|
||||
value={item.quantity || ''}
|
||||
onChange={(e) =>
|
||||
handlePurchaseItemChange(
|
||||
idx,
|
||||
'sub_qty',
|
||||
'quantity',
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
@@ -801,9 +893,11 @@ const PurchaseRequestForm = ({
|
||||
readOnly={type === 'detail'}
|
||||
allowNegative={false}
|
||||
decimalScale={0}
|
||||
isError={getPurchaseItemError(idx, 'sub_qty').isError}
|
||||
isError={
|
||||
getPurchaseItemError(idx, 'quantity').isError
|
||||
}
|
||||
errorMessage={
|
||||
getPurchaseItemError(idx, 'sub_qty').errorMessage
|
||||
getPurchaseItemError(idx, 'quantity').errorMessage
|
||||
}
|
||||
className={{
|
||||
wrapper: 'min-w-24',
|
||||
@@ -813,24 +907,18 @@ const PurchaseRequestForm = ({
|
||||
<td>
|
||||
<TextInput
|
||||
required
|
||||
name={`purchase_items.${idx}.price`}
|
||||
name={`items.${idx}.price`}
|
||||
value={
|
||||
item.product_id && productData[item.product_id]
|
||||
? (
|
||||
productData[item.product_id].product_price *
|
||||
(parseFloat(
|
||||
item.sub_qty?.toString() || '0'
|
||||
item.quantity?.toString() || '0'
|
||||
) || 0)
|
||||
).toLocaleString('en-US')
|
||||
: ''
|
||||
}
|
||||
onChange={(e) =>
|
||||
handlePurchaseItemChange(
|
||||
idx,
|
||||
'price',
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
onChange={(e) => {}}
|
||||
onBlur={formik.handleBlur}
|
||||
type='text'
|
||||
className={{
|
||||
@@ -856,7 +944,7 @@ const PurchaseRequestForm = ({
|
||||
<td>
|
||||
<TextInput
|
||||
required
|
||||
name={`purchase_items.${idx}.uom`}
|
||||
name={`items.${idx}.uom`}
|
||||
value={
|
||||
item.product_id && productData[item.product_id]
|
||||
? productData[item.product_id].uom.name
|
||||
@@ -1011,4 +1099,4 @@ const PurchaseRequestForm = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default PurchaseRequestForm;
|
||||
export default PurchaseRequisitionsForm;
|
||||
Reference in New Issue
Block a user