diff --git a/src/components/pages/purchase/form/PurchaseRequestForm.schema.ts b/src/components/pages/purchase/form/PurchaseRequestForm.schema.ts index c885af99..cc53de7a 100644 --- a/src/components/pages/purchase/form/PurchaseRequestForm.schema.ts +++ b/src/components/pages/purchase/form/PurchaseRequestForm.schema.ts @@ -26,9 +26,9 @@ export const PurchaseRequestFormSchema = Yup.object({ value: Yup.number().min(1).required(), label: Yup.string().required(), }).nullable(), - warehouse_ids: Yup.number() + warehouse_id: Yup.number() .required('Warehouse wajib diisi!') - .min(1, 'Produk wajib diisi!') + .min(1, 'Warehouse wajib diisi!') .typeError('Warehouse harus berupa angka!'), product: Yup.object({ value: Yup.number().min(1).required(), @@ -42,17 +42,14 @@ export const PurchaseRequestFormSchema = Yup.object({ value: Yup.number().min(1).required(), label: Yup.string().required(), }).nullable(), - product_warehouse_id: Yup.number() - .required('Product warehouse wajib diisi!') - .min(1, 'Product warehouse wajib diisi!') - .typeError('Product warehouse harus berupa angka!'), - total_qty: Yup.number() - .required('Jumlah total wajib diisi!') - .min(1, 'Jumlah total tidak boleh negatif!') - .typeError('Jumlah total harus berupa angka!'), + product_warehouse_id: Yup.number().optional().nullable(), + sub_qty: Yup.number() + .required('Sub Qty wajib diisi!') + .min(0.001, 'Sub Qty tidak boleh negatif!') + .typeError('Sub Qty harus berupa angka!'), price: Yup.number() .required('Harga wajib diisi!') - .min(1, 'Harga tidak boleh negatif!') + .min(0, 'Harga tidak boleh negatif!') .typeError('Harga harus berupa angka!'), }) ) @@ -99,7 +96,7 @@ export const getPurchaseRequestFormInitialValues = ( label: item.warehouse.name, } : null, - warehouse_ids: item.warehouse_ids, + warehouse_id: item.warehouse_id, product: item.product ? { value: item.product.id, @@ -113,19 +110,19 @@ export const getPurchaseRequestFormInitialValues = ( label: item.product_warehouse.product.name, } : null, - product_warehouse_id: item.product_warehouse_id, - total_qty: item.total_qty, + product_warehouse_id: item.product_warehouse_id || null, + sub_qty: item.sub_qty, price: item.price, }) ) ?? [ { warehouse: null, - warehouse_ids: 0, + warehouse_id: 0, product: null, product_id: 0, product_warehouse: null, - product_warehouse_id: 0, - total_qty: 0, + product_warehouse_id: null, + sub_qty: 0, price: 0, }, ], diff --git a/src/components/pages/purchase/form/PurchaseRequestForm.tsx b/src/components/pages/purchase/form/PurchaseRequestForm.tsx index 2c5c7b97..21b0ca03 100644 --- a/src/components/pages/purchase/form/PurchaseRequestForm.tsx +++ b/src/components/pages/purchase/form/PurchaseRequestForm.tsx @@ -1,12 +1,15 @@ 'use client'; -import { useMemo, useState } from 'react'; +import { useCallback, useMemo, useState } from 'react'; import { useFormik } from 'formik'; import useSWR from 'swr'; +import { useRouter } from 'next/navigation'; import { Icon } from '@iconify/react'; +import { toast } from 'react-hot-toast'; import Button from '@/components/Button'; import TextInput from '@/components/input/TextInput'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; +import { useModal } from '@/components/Modal'; import { FormHeader } from '@/components/helper/form/FormHeader'; import { FormActions } from '@/components/helper/form/FormActions'; @@ -18,8 +21,8 @@ import { } from './PurchaseRequestForm.schema'; import { SupplierApi } from '@/services/api/master-data'; import { WarehouseApi } from '@/services/api/master-data'; -import { isResponseSuccess } from '@/lib/api-helper'; -import { usePurchaseRequestFormHandlers } from './usePurchaseRequestFormHandlers'; +import { isResponseSuccess, isResponseError } from '@/lib/api-helper'; +import { PurchaseApi } from '@/services/api/purchasing'; import Card from '@/components/Card'; import { @@ -36,19 +39,61 @@ const PurchaseRequestForm = ({ type = 'add', initialValues, }: PurchaseRequestFormProps) => { + const router = useRouter(); + const deleteModal = useModal(); + const [selectedPurchaseItems, setSelectedPurchaseItems] = useState( [] ); + const [purchaseRequestFormErrorMessage, setPurchaseRequestFormErrorMessage] = + useState(''); + const [isDeleteLoading, setIsDeleteLoading] = useState(false); - const { - deleteModal, - purchaseRequestFormErrorMessage, - isDeleteLoading, - createPurchaseRequestHandler, - updatePurchaseRequestHandler, - deletePurchaseRequestClickHandler, - confirmationModalDeleteClickHandler, - } = usePurchaseRequestFormHandlers(initialValues?.id); + // ===== FORM HANDLERS ===== + const createPurchaseRequestHandler = useCallback( + async (payload: CreatePurchaseRequestPayload) => { + const res = await PurchaseApi.create(payload); + if (isResponseError(res)) { + setPurchaseRequestFormErrorMessage(res.message); + return; + } + toast.success(res?.message as string); + router.push('/purchase'); + }, + [router] + ); + + const updatePurchaseRequestHandler = useCallback( + async ( + purchaseRequestId: number, + payload: CreatePurchaseRequestPayload + ) => { + const res = await PurchaseApi.update(purchaseRequestId, payload); + if (isResponseError(res)) { + setPurchaseRequestFormErrorMessage(res.message); + return; + } + toast.success(res?.message as string); + router.refresh(); + router.push('/purchase'); + }, + [router] + ); + + const deletePurchaseRequestClickHandler = useCallback(() => { + deleteModal.openModal(); + }, [deleteModal]); + + const confirmationModalDeleteClickHandler = useCallback(async () => { + if (!initialValues?.id) return; + + setIsDeleteLoading(true); + await PurchaseApi.delete(initialValues.id); + deleteModal.closeModal(); + toast.success('Successfully delete Purchase Request!'); + setIsDeleteLoading(false); + router.push('/purchase'); + }, [deleteModal, initialValues?.id, router]); // ===== API DATA FETCHING ===== const { data: suppliers, isLoading: isLoadingSuppliers } = useSWR( @@ -101,9 +146,10 @@ const PurchaseRequestForm = ({ credit_term: values.credit_term || 0, notes: values.notes || '', purchase_items: (values.purchase_items || []).map((item) => ({ - warehouse_ids: item.warehouse_ids || 0, + warehouse_id: item.warehouse_id || 0, product_id: item.product_id || 0, - product_warehouse_id: item.product_warehouse_id || 0, + product_warehouse_id: item.product_warehouse_id || undefined, + sub_qty: item.sub_qty || 0, total_qty: item.total_qty || 0, price: typeof item.price === 'number' @@ -147,11 +193,12 @@ const PurchaseRequestForm = ({ ...(formik.values.purchase_items || []), { warehouse: null, - warehouse_ids: 0, + warehouse_id: 0, product: null, product_id: 0, product_warehouse: null, - product_warehouse_id: 0, + product_warehouse_id: null, + sub_qty: 0, total_qty: 0, price: 0, }, @@ -180,12 +227,12 @@ const PurchaseRequestForm = ({ value: string | number ) => { const integerFields = [ - 'warehouse_ids', + 'warehouse_id', 'product_id', 'product_warehouse_id', 'total_qty', ]; - const floatFields = ['price']; + const floatFields = ['price', 'sub_qty']; if (integerFields.includes(field)) { const numValue = typeof value === 'string' ? parseInt(value) || 0 : value; @@ -320,6 +367,10 @@ const PurchaseRequestForm = ({ Product Warehouse ID * + + Sub Qty + * + Total Qty * @@ -358,18 +409,18 @@ const PurchaseRequestForm = ({ handlePurchaseItemChange( idx, - 'warehouse_ids', + 'warehouse_id', e.target.value ) } onBlur={formik.handleBlur} type='number' - placeholder='Warehouse IDs' + placeholder='Warehouse ID' readOnly={type === 'detail'} className={{ wrapper: 'min-w-24', @@ -399,7 +450,6 @@ const PurchaseRequestForm = ({ @@ -418,6 +468,27 @@ const PurchaseRequestForm = ({ }} /> + + + handlePurchaseItemChange( + idx, + 'sub_qty', + e.target.value + ) + } + onBlur={formik.handleBlur} + type='number' + placeholder='Sub Qty' + readOnly={type === 'detail'} + className={{ + wrapper: 'min-w-24', + }} + /> + { - const router = useRouter(); - const deleteModal = useModal(); - const [purchaseRequestFormErrorMessage, setPurchaseRequestFormErrorMessage] = - useState(''); - const [isDeleteLoading, setIsDeleteLoading] = useState(false); - - const createPurchaseRequestHandler = useCallback( - async (payload: CreatePurchaseRequestPayload) => { - const res = await PurchaseApi.create(payload); - if (isResponseError(res)) { - setPurchaseRequestFormErrorMessage(res.message); - return; - } - toast.success(res?.message as string); - router.push('/purchase'); - }, - [router] - ); - - const updatePurchaseRequestHandler = useCallback( - async ( - purchaseRequestId: number, - payload: UpdatePurchaseRequestPayload - ) => { - const res = await PurchaseApi.update(purchaseRequestId, payload); - if (res?.status === 'error') { - setPurchaseRequestFormErrorMessage(res.message); - return; - } - toast.success(res?.message as string); - router.refresh(); - router.push('/purchase'); - }, - [router] - ); - - const deletePurchaseRequestClickHandler = useCallback(() => { - deleteModal.openModal(); - }, [deleteModal]); - - const confirmationModalDeleteClickHandler = useCallback(async () => { - if (!initialValuesId) return; - - setIsDeleteLoading(true); - await PurchaseApi.delete(initialValuesId); - deleteModal.closeModal(); - toast.success('Successfully delete Purchase Request!'); - setIsDeleteLoading(false); - router.push('/purchase'); - }, [deleteModal, initialValuesId, router]); - - return { - deleteModal, - purchaseRequestFormErrorMessage, - isDeleteLoading, - createPurchaseRequestHandler, - updatePurchaseRequestHandler, - deletePurchaseRequestClickHandler, - confirmationModalDeleteClickHandler, - }; -}; diff --git a/src/types/api/purchase/purchase.d.ts b/src/types/api/purchase/purchase.d.ts index 48a9df9e..b44553ba 100644 --- a/src/types/api/purchase/purchase.d.ts +++ b/src/types/api/purchase/purchase.d.ts @@ -1,6 +1,5 @@ import { BaseMetadata } from '@/types/api/api-general'; import { Supplier } from '@/types/api/master-data/supplier'; -import { Warehouse } from '@/types/api/master-data/warehouse'; export type BasePurchase = { id: number; @@ -8,7 +7,6 @@ export type BasePurchase = { po_number: string; po_date: string; supplier: Supplier; - warehouse: Warehouse[]; credit_term: number; due_date: string; grand_total: number; @@ -24,10 +22,10 @@ export type CreatePurchaseRequestPayload = { credit_term: number; notes?: string | null; purchase_items: { - warehouse_ids: number; + warehouse_id: number; product_id: number; - product_warehouse_id: number; - total_qty: number; + product_warehouse_id?: number | null; + sub_qty: number; price: number; }[]; };