added updation invoice

This commit is contained in:
pramod.mahajan 2025-11-27 16:52:33 +05:30
parent 528255c2bd
commit 1b3e090211
9 changed files with 183 additions and 49 deletions

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { AppFormProvider, useAppForm } from "../../hooks/appHooks/useAppForm";
import { zodResolver } from "@hookform/resolvers/zod";
import {
@ -9,9 +9,13 @@ import {
import PurchasePartyDetails from "./PurchasePartyDetails";
import PurchaseTransportDetails from "./PurchaseTransportDetails";
import PurchasePaymentDetails from "./PurchasePaymentDetails";
import { useCreatePurchaseInvoice } from "../../hooks/usePurchase";
const ManagePurchase = ({ onClose }) => {
import {
useCreatePurchaseInvoice,
usePurchase,
useUpdatePurchaseInvoice,
} from "../../hooks/usePurchase";
const ManagePurchase = ({ onClose, purchaseId }) => {
const { data } = usePurchase(purchaseId);
const [activeTab, setActiveTab] = useState(0);
const [completedTabs, setCompletedTabs] = useState([]);
@ -20,7 +24,7 @@ const ManagePurchase = ({ onClose }) => {
name: "Party Details",
icon: "bx bx-user bx-md",
subtitle: "Supplier & project information",
component: <PurchasePartyDetails />,
component: <PurchasePartyDetails purchase={data} />,
},
{
name: "Invoice & Transport",
@ -40,10 +44,25 @@ const ManagePurchase = ({ onClose }) => {
resolver: zodResolver(PurchaseSchema),
defaultValues: defaultPurchaseValue,
mode: "onChange",
shouldUnregister: false,
});
const {reset} = purchaseOrder;
const handleNext = async () => {
const {
reset,
formState: { errors },
} = purchaseOrder;
useEffect(() => {
if (purchaseId && data) {
reset(data);
setCompletedTabs([0, 1, 2]);
}
}, [purchaseId, data, reset]);
const handleNext = async (e) => {
e.preventDefault();
e.stopPropagation();
const currentStepFields = getStepFields(activeTab);
const valid = await purchaseOrder.trigger(currentStepFields);
@ -53,18 +72,53 @@ const ManagePurchase = ({ onClose }) => {
}
};
const handlePrev = () => {
const handlePrev = (e) => {
e.preventDefault();
e.stopPropagation();
setActiveTab((prev) => Math.max(prev - 1, 0));
};
const { mutate: CreateInvoice, isPending } = useCreatePurchaseInvoice(() => {
reset()
const { mutate: CreateInvoice, isPending } =
useCreatePurchaseInvoice(() => {
reset();
onClose();
});
const { mutate: updatePurchase, isPending: isUpdating } =
useUpdatePurchaseInvoice(() => {
reset();
onClose();
});
const onSubmit = (formData) => {
let payload = formData;
CreateInvoice(payload);
if (activeTab !== 2) {
console.warn("Submit blocked - not on last step");
return;
}
const dirtyFields = purchaseOrder.formState.dirtyFields;
if (purchaseId) {
const changedData = Object.keys(dirtyFields).reduce((acc, key) => {
if (dirtyFields[key]) {
acc.push({
operationType: 0,
path: `/${key}`,
op: "replace",
from: null,
value: formData[key],
});
}
return acc;
}, []);
updatePurchase({
purchaseId,
payload: changedData,
});
} else {
CreateInvoice(formData);
}
};
return (
@ -96,7 +150,9 @@ const ManagePurchase = ({ onClose }) => {
<span className="bs-stepper-label">
<span className="bs-stepper-title">{step.name}</span>
<span className="bs-stepper-subtitle">{step.subtitle}</span>
<span className="bs-stepper-subtitle">
{step.subtitle}
</span>
</span>
</button>
</div>
@ -112,7 +168,23 @@ const ManagePurchase = ({ onClose }) => {
{/* Content */}
<div className="bs-stepper-content py-2">
<AppFormProvider {...purchaseOrder}>
<form onSubmit={purchaseOrder.handleSubmit(onSubmit)}>
<form
onKeyDown={(e) => {
if (e.key === "Enter" && activeTab !== 2) {
e.preventDefault();
}
}}
onSubmit={(e) => {
e.preventDefault();
if (activeTab !== 2) {
console.warn("BLOCKED SUBMIT on step:", activeTab);
return;
}
purchaseOrder.handleSubmit(onSubmit)(e);
}}
>
{stepsConfig[activeTab].component}
<div className="d-flex justify-content-between mt-4">
@ -124,21 +196,27 @@ const ManagePurchase = ({ onClose }) => {
>
Previous
</button>
<di>
<div>
{activeTab < stepsConfig.length - 1 ? (
<button
type="button"
className="btn btn-sm btn-primary"
onClick={handleNext}
disabled={isPending || isUpdating}
>
Next <i className="bx bx-sm bx-right-arrow"></i>
</button>
) : (
<button type="submit" className="btn btn-sm btn-primary">
{isPending ? "Please Wait" : "SUbmit"}
<button
type="submit"
className="btn btn-sm btn-primary"
disabled={isPending || isUpdating}
>
{isPending || isUpdating ? "Please Wait" : "Submit"}
</button>
)}
</di>
</div>
</div>
</form>
</AppFormProvider>
@ -148,3 +226,4 @@ const ManagePurchase = ({ onClose }) => {
};
export default ManagePurchase;

View File

@ -8,7 +8,7 @@ import { useDebounce } from "../../utils/appUtils";
import { usePurchaseContext } from "../../pages/purchase/PurchasePage";
const PurchaseList = ({ searchString }) => {
const { setViewPurchase } = usePurchaseContext();
const { setViewPurchase, setManagePurchase } = usePurchaseContext();
const [currentPage, setCurrentPage] = useState(1);
const debounceSearch = useDebounce(searchString, 300);
const { data, isLoading } = usePurchasesList(
@ -101,14 +101,22 @@ const PurchaseList = ({ searchString }) => {
})
}
>
<i className="bx bx-eye me-2"></i>
<i className="bx bx-show me-2"></i>
<span className="align-left">view</span>
</a>
</li>
<li>
<a className="dropdown-item cursor-pointer">
<i className="bx bx-trash me-2"></i>
<span className="align-left">Add</span>
<a
className="dropdown-item cursor-pointer"
onClick={() =>
setManagePurchase({
isOpen: true,
purchaseId: item.id,
})
}
>
<i className="bx bx-edit me-2"></i>
<span className="align-left">Edit</span>
</a>
</li>
<li>

View File

@ -37,7 +37,7 @@ const PurchasePaymentDetails = () => {
id="baseAmount"
type="number"
className="form-control form-control-md"
{...register("baseAmount")}
{...register("baseAmount", { valueAsNumber: true })}
/>
{errors?.baseAmount && (
@ -56,7 +56,7 @@ const PurchasePaymentDetails = () => {
id="taxAmount"
type="number"
className="form-control form-control-md"
{...register("taxAmount")}
{...register("taxAmount",{ valueAsNumber: true })}
/>
{errors?.taxAmount && (
@ -75,7 +75,7 @@ const PurchasePaymentDetails = () => {
id="totalAmount"
type="number"
className="form-control form-control-md"
{...register("totalAmount")}
{...register("totalAmount",{ valueAsNumber: true })}
readOnly
/>

View File

@ -49,7 +49,7 @@ export const PurchaseSchema = z.object({
proformaInvoiceNumber: z.string().nullable(),
proformaInvoiceDate: z.coerce.date().nullable(),
proformaInvoiceAmount: z.string().nullable(),
proformaInvoiceAmount: z.number().optional(),
invoiceNumber: z.string().nullable(),
invoiceDate: z.coerce.date().nullable(),
@ -59,11 +59,11 @@ export const PurchaseSchema = z.object({
acknowledgmentDate: z.coerce.date().nullable(),
acknowledgmentNumber: z.string().nullable(),
baseAmount: z.string().min(1, { message: "Base amount is required" }),
taxAmount: z.string().min(1, { message: "Tax amount is required" }),
totalAmount: z.string().min(1, { message: "Total amount is required" }),
baseAmount: z.number().min(1, { message: "Base amount is required" }),
taxAmount: z.number().min(1, { message: "Tax amount is required" }),
totalAmount: z.number().min(1, { message: "Total amount is required" }),
paymentDueDate: z.coerce.date().nullable(),
transportCharges: z.string().nullable(),
transportCharges: z.number().nullable(),
description: z.string().min(1, { message: "Description is required" }),
attachments: z.array(AttachmentSchema([], 25)).optional(),
@ -98,9 +98,9 @@ export const defaultPurchaseValue = {
acknowledgmentNumber: null,
acknowledgmentDate: null,
baseAmount: "",
taxAmount: "",
totalAmount: "",
baseAmount: 0,
taxAmount: 0,
totalAmount: 0,
paymentDueDate: null,
transportCharges: null,
description: "",

View File

@ -39,13 +39,13 @@ export const useOrganizationModal = () => {
// ================================Query=============================================================
export const useGlobaleOrganizations = (pageSize, pageNumber, searchString) => {
export const useGlobaleOrganizations = (pageSize, pageNumber,id, searchString) => {
return useQuery({
queryKey: ["global_organization",pageSize, pageNumber, searchString],
queryKey: ["global_organization",pageSize, pageNumber,id, searchString],
queryFn: async () => {
const resp = await OrganizationRepository.getGlobalOrganization(
pageSize,
pageNumber,
pageNumber,id,
searchString
);
return resp.data;

View File

@ -62,3 +62,23 @@ export const useCreatePurchaseInvoice = (onSuccessCallback) => {
},
});
};
export const useUpdatePurchaseInvoice = (onSuccessCallback) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({purchaseId,payload}) => PurchaseRepository.UpdatePurchase(purchaseId, payload),
onSuccess: (data, variables) => {
showToast("Purchase Invoice Updated successfully", "success");
if (onSuccessCallback) onSuccessCallback();
},
onError: (error) => {
showToast(
error?.response?.data?.message ||
error.message ||
"Failed to create invoice",
"error"
);
},
});
};

View File

@ -18,7 +18,10 @@ export const usePurchaseContext = () => {
};
const PurchasePage = () => {
const [searchText, setSearchText] = useState("");
const [addePurchase, setAddedPurchase] = useState(false);
const [managePurchase, setManagePurchase] = useState({
isOpen: false,
purchaseId: null,
});
const [viewPurchaseState, setViewPurchase] = useState({
isOpen: false,
purchaseId: null,
@ -26,8 +29,8 @@ const PurchasePage = () => {
const contextValue = {
setViewPurchase,
setManagePurchase,
};
console.log(ViewPurchase);
return (
<PurchaseContext.Provider value={contextValue}>
<div className="container-fluid">
@ -56,7 +59,12 @@ const PurchasePage = () => {
<di className="col-6 text-end">
<button
className="btn btn-sm btn-primary"
onClick={() => setAddedPurchase(true)}
onClick={() =>
setManagePurchase({
isOpen: true,
purchaseId: null,
})
}
>
<i className="bx bx-plus-circle me-2"></i>Add
</button>
@ -65,20 +73,33 @@ const PurchasePage = () => {
</div>
<PurchaseList searchString={searchText} />
{addePurchase && (
{managePurchase.isOpen && (
<GlobalModel
isOpen={addePurchase}
isOpen={managePurchase.isOpen}
size="lg"
closeModal={() => setAddedPurchase(false)}
closeModal={() =>
setManagePurchase({
isOpen: false,
purchaseId: null,
})
}
>
<ManagePurchase onClose={() => setAddedPurchase(false)} />
<ManagePurchase
onClose={() =>
setManagePurchase({
isOpen: false,
purchaseId: null,
})
}
purchaseId={managePurchase.purchaseId}
/>
</GlobalModel>
)}
{viewPurchaseState.isOpen && (
<GlobalModel
isOpen={viewPurchaseState.isOpen}
size="lg"
size="xl"
closeModal={() =>
setViewPurchase({ isOpen: false, purchaseId: null })
}

View File

@ -41,9 +41,11 @@ const OrganizationRepository = {
return api.get(url);
},
getGlobalOrganization: (pageSize, pageNumber, searchString) =>
getGlobalOrganization: (pageSize, pageNumber, searchString, id) =>
api.get(
`/api/Organization/list/basic?pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}`
`/api/Organization/list/basic?pageSize=${pageSize}&pageNumber=${pageNumber}${
id ? `&id=${id}` : ""
}&searchString=${searchString}`
),
};

View File

@ -10,6 +10,10 @@ export const PurchaseRepository = {
GetPurchase: (id) => api.get(`/api/PurchaseInvoice/details/${id}`),
UpdatePurchase: (id, data) =>
api.patch(`/api/PurchaseInvoice/edit/${id}`, data),
GetDeliveryChallan: (purchaseInvoiceId) =>
api.get(`/api/PurchaseInvoice/delivery-challan/list/${purchaseInvoiceId}`),
addDelievryChallan: (data) =>
api.post(`/api/PurchaseInvoice/delivery-challan/create`, data),
};
// const filterPayload = JSON.stringify({