diff --git a/src/components/purchase/ManagePurchase.jsx b/src/components/purchase/ManagePurchase.jsx
index 89c1b1b3..fb757b54 100644
--- a/src/components/purchase/ManagePurchase.jsx
+++ b/src/components/purchase/ManagePurchase.jsx
@@ -28,21 +28,21 @@ const ManagePurchase = ({ onClose, purchaseId }) => {
const stepsConfig = useMemo(
() => [
{
- name: "Party Details",
+ name: "Vendor & Project Details",
icon: "bx bx-user bx-md",
- subtitle: "Supplier & project information",
+ subtitle: "Vendor information and project association",
component: ,
},
{
- name: "Invoice & Transport",
+ name: "Invoice & Logistics",
icon: "bx bx-receipt bx-md",
- subtitle: "Invoice, eWay bill & transport info",
+ subtitle: "Invoice, e-Way bill, and logistics information",
component: ,
},
{
- name: "Payment Details",
+ name: "Invoice & Tax Amount",
icon: "bx bx-credit-card bx-md",
- subtitle: "Amount, tax & due date",
+ subtitle: "Payment terms, tax breakdown, and due dates",
component: ,
},
],
diff --git a/src/components/purchase/PurchasePayment.jsx b/src/components/purchase/PurchasePayment.jsx
new file mode 100644
index 00000000..a1e440a4
--- /dev/null
+++ b/src/components/purchase/PurchasePayment.jsx
@@ -0,0 +1,298 @@
+import React from "react";
+import {
+ AppFormController,
+ AppFormProvider,
+ useAppForm,
+} from "../../hooks/appHooks/useAppForm";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { AddPurchasePayment, defaultPurchasePayment } from "./PurchaseSchema";
+import { usePaymentAjustmentHead } from "../../hooks/masterHook/useMaster";
+import { formatFigure, localToUtc } from "../../utils/appUtils";
+import Label from "../common/Label";
+import DatePicker from "../common/DatePicker";
+import {
+ useAddPurchasePayment,
+ usePurchase,
+ usePurchasePaymentHistory,
+} from "../../hooks/usePurchase";
+import SelectField from "../common/Forms/SelectField";
+import { SpinnerLoader } from "../common/Loader";
+import { formatUTCToLocalTime } from "../../utils/dateUtils";
+import Avatar from "../common/Avatar";
+
+const PurchasePayment = ({ purchaseId }) => {
+ const {
+ data: Purchase,
+ isLoading: isPurchaseLoading,
+ error: purchaseError,
+ } = usePurchase(purchaseId);
+ const methods = useAppForm({
+ resolver: zodResolver(AddPurchasePayment),
+ defaultValues: defaultPurchasePayment,
+ });
+ const {
+ control,
+ register,
+ handleSubmit,
+ reset,
+ formState: { errors },
+ } = methods;
+
+ const {
+ data: paymentTypes,
+ isLoading: isPaymentTypeLoading,
+ isError: isPaymentTypeError,
+ error: paymentError,
+ } = usePaymentAjustmentHead(true);
+
+ const { mutate: AddPayment, isPending } = useAddPurchasePayment(() => {
+ handleClose();
+ });
+ const { data, isLoading, isError, error } =
+ usePurchasePaymentHistory(purchaseId);
+ const onSubmit = (formData) => {
+ const payload = {
+ ...formData,
+ paymentReceivedDate: localToUtc(formData.paymentReceivedDate),
+ invoiceId: purchaseId,
+ };
+ AddPayment(payload);
+ };
+
+ const handleClose = (formData) => {
+ reset(defaultPurchasePayment);
+ };
+ return (
+
+
+
Supplier / Vendor Transaction
+
+
+
+
+
+
+
+ {isLoading ? (
+
+ ) : (
+ data?.length > 0 && (
+
+ {data
+ .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
+ .map((payment, index) => (
+
+
+
+
+
+
+ Transaction Date:
+ {" "}
+ {formatUTCToLocalTime(
+ payment.paymentReceivedDate
+ )}
+
+
+ {formatFigure(payment.amount, {
+ type: "currency",
+ currency: "INR",
+ })}
+
+
+
+
+
+ Updated By:
+ {" "}
+
{" "}
+ {payment?.createdBy?.firstName}{" "}
+ {payment.createdBy?.lastName}
+
+
+
+
+
+
+
+ Transaction ID:
+ {" "}
+ {payment.transactionId}
+
+
+
+
+
+ {payment?.paymentAdjustmentHead?.name}
+
+
+ {formatFigure(payment.amount, {
+ type: "currency",
+ currency: "INR",
+ })}
+
+
+
+ {payment?.comment}
+
+
+
+
+
+ ))}
+
+ )
+ )}
+ {data?.length === 0 && (
+
+
+
+
+
You don't have any payment yet.
+
+
+ )}
+
+
+
+ );
+};
+
+export default PurchasePayment;
diff --git a/src/components/purchase/PurchaseSchema.jsx b/src/components/purchase/PurchaseSchema.jsx
index c10a375b..824b2a28 100644
--- a/src/components/purchase/PurchaseSchema.jsx
+++ b/src/components/purchase/PurchaseSchema.jsx
@@ -13,20 +13,17 @@ export const AttachmentSchema = z.object({
invoiceAttachmentTypeId: z.string().nullable(),
fileName: z.string().min(1, { message: "Filename is required" }),
base64Data: z.string().nullable(),
- contentType: z
- .string()
- .refine((val) => ALLOWED_TYPES.includes(val), {
- message: "Only PDF, PNG, JPG, or JPEG files are allowed",
- }),
+ contentType: z.string().refine((val) => ALLOWED_TYPES.includes(val), {
+ message: "Only PDF, PNG, JPG, or JPEG files are allowed",
+ }),
fileSize: z.number().max(MAX_FILE_SIZE, {
message: "File size must be less than or equal to 5MB",
}),
description: z.string().optional().default(""),
isActive: z.boolean().default(true),
- documentId:z.string().nullable().default(null)
+ documentId: z.string().nullable().default(null),
});
-
export const PurchaseSchema = z.object({
title: z.string().min(1, { message: "Title is required" }),
projectId: z.string().min(1, { message: "Project is required" }),
@@ -57,14 +54,10 @@ export const PurchaseSchema = z.object({
paymentDueDate: z.coerce.date().nullable(),
transportCharges: z.number().nullable(),
description: z.string().min(1, { message: "Description is required" }),
- invoiceAttachmentTypeId:z.string().nullable(),
- attachments: z
- .array(AttachmentSchema)
-
-
+ invoiceAttachmentTypeId: z.string().nullable(),
+ attachments: z.array(AttachmentSchema),
});
-
export const defaultPurchaseValue = {
title: "",
projectId: "",
@@ -94,7 +87,7 @@ export const defaultPurchaseValue = {
paymentDueDate: null,
transportCharges: null,
description: "",
- invoiceAttachmentTypeId:null,
+ invoiceAttachmentTypeId: null,
attachments: [],
};
@@ -130,7 +123,7 @@ export const getStepFields = (stepIndex) => {
"paymentDueDate",
"invoiceAttachmentTypeId",
"description",
- "attachments"
+ "attachments",
],
};
@@ -172,12 +165,11 @@ export const DeliveryChallanSchema = z.object({
invoiceAttachmentTypeId: z.string().nullable(),
deliveryChallanDate: z.string().min(1, { message: "Deliver date required" }),
description: z.string().min(1, { message: "Description required" }),
- attachment: z.any().refine(
- (val) => val && typeof val === "object" && !!val.base64Data,
- {
+ attachment: z
+ .any()
+ .refine((val) => val && typeof val === "object" && !!val.base64Data, {
message: "Please upload document",
- }
- ),
+ }),
});
export const DeliveryChallanDefaultValue = {
@@ -187,3 +179,20 @@ export const DeliveryChallanDefaultValue = {
attachment: null,
invoiceAttachmentTypeId: null,
};
+
+export const AddPurchasePayment = z.object({
+ paymentReceivedDate: z.string().min(1, { message: "Date is required" }),
+ transactionId: z.string().min(1, "Transaction ID is required"),
+ amount: z.number().min(1, "Amount must be greater than zero"),
+ comment: z.string().min(1, { message: "Comment required" }),
+ paymentAdjustmentHeadId: z
+ .string()
+ .min(1, { message: "Payment Type required" }),
+});
+export const defaultPurchasePayment = {
+ paymentReceivedDate: null,
+ transactionId: "",
+ amount: 0,
+ comment: "",
+ paymentAdjustmentHeadId: "",
+};
diff --git a/src/hooks/usePurchase.jsx b/src/hooks/usePurchase.jsx
index 405700d1..b328f9f3 100644
--- a/src/hooks/usePurchase.jsx
+++ b/src/hooks/usePurchase.jsx
@@ -55,6 +55,17 @@ export const usePurchase = (id) => {
});
};
+export const usePurchasePaymentHistory = (id) => {
+ return useQuery({
+ queryKey: ["purchase_payment_history", id],
+ queryFn: async () => {
+ const resp = await PurchaseRepository.GetPaymentHistory(id);
+ return resp.data;
+ },
+ enabled: !!id,
+ });
+};
+
export const useCreatePurchaseInvoice = (onSuccessCallback) => {
const queryClient = useQueryClient();
diff --git a/src/pages/purchase/PurchasePage.jsx b/src/pages/purchase/PurchasePage.jsx
index 785f434e..d3991ed3 100644
--- a/src/pages/purchase/PurchasePage.jsx
+++ b/src/pages/purchase/PurchasePage.jsx
@@ -6,6 +6,9 @@ import ManagePurchase from "../../components/purchase/ManagePurchase";
import PurchaseList from "../../components/purchase/PurchaseList";
import ViewPurchase from "../../components/purchase/ViewPurchase";
import DeliveryChallane from "../../components/purchase/DeliveryChallane";
+import PurchasePayment from "../../components/purchase/PurchasePayment";
+import { useHasUserPermission } from "../../hooks/useHasUserPermission";
+import { MANAGEPURCHASE_INVOICE } from "../../utils/constants";
export const PurchaseContext = createContext();
export const usePurchaseContext = () => {
@@ -29,15 +32,22 @@ const PurchasePage = () => {
isOpen: false,
purchaseId: null,
});
+ const [addPayment, setAddPayment] = useState({
+ isOpen: false,
+ purchaseId: null,
+ });
const [viewPurchaseState, setViewPurchase] = useState({
isOpen: false,
purchaseId: null,
});
+ const canCreatePurchase = useHasUserPermission(MANAGEPURCHASE_INVOICE);
+
const contextValue = {
setViewPurchase,
setManagePurchase,
setChallan,
+ setAddPayment,
};
return (
@@ -80,17 +90,19 @@ const PurchasePage = () => {
-
+ {canCreatePurchase && (
+
+ )}
@@ -132,7 +144,8 @@ const PurchasePage = () => {
)}
{addChallan.isOpen && (
- setChallan({ isOpen: false, purchaseId: null })}
>
@@ -142,6 +155,18 @@ const PurchasePage = () => {
/>
)}
+
+ {addPayment.isOpen && (
+
+ setAddPayment({ isOpen: false, purchaseId: null })
+ }
+ >
+
+
+ )}
);
diff --git a/src/utils/constants.jsx b/src/utils/constants.jsx
index 1ca271ec..b3231405 100644
--- a/src/utils/constants.jsx
+++ b/src/utils/constants.jsx
@@ -2,7 +2,6 @@ export const BASE_URL = process.env.VITE_BASE_URL;
// export const BASE_URL = "https://api.marcoaiot.com";
-
export const THRESH_HOLD = 48; // hours
export const DURATION_TIME = 10; // minutes
export const ITEMS_PER_PAGE = 20;
@@ -66,8 +65,6 @@ export const PROCESS_EXPENSE = "ea5a1529-4ee8-4828-80ea-0e23c9d4dd11";
export const EXPENSE_MANAGE = "bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3";
-
-
// --------------------------------Collection----------------------------
export const ADMIN_COLLECTION = "dbf17591-09fe-4c93-9e1a-12db8f5cc5de";
@@ -76,6 +73,13 @@ export const CREATE_COLLECTION = "b93141fd-dbd3-4051-8f57-bf25d18e3555";
export const EDIT_COLLECTION = "455187b4-fef1-41f9-b3d0-025d0b6302c3";
export const ADDPAYMENT_COLLECTION = "061d9ccd-85b4-4cb0-be06-2f9f32cebb72";
+// --------------------Purchase Invoice--------------------------------
+export const VIEWSELF_PURCHASEINVOICE = "91e09825-512a-465e-82ad-fa355b305585";
+export const VIEWALL_PURCHASEINVOICE = "d6ae78d3-a941-4cc4-8d0a-d40479be4211";
+export const MANAGEPURCHASE_INVOICE = "68ff925d-8ebf-4034-a137-8d3317c56ca1";
+export const DELETEPURCHASE_INVOICE = "a4b77638-bf31-42bb-afd4-d5bbd15ccadc";
+export const ADD_DELIVERY_CHALLAN = "a4b77638-bf31-42bb-afd4-d5bbd15ccadc";
+
// ----------------------------Tenant-------------------------
export const SUPPER_TENANT = "d032cb1a-3f30-462c-bef0-7ace73a71c0b";
export const MANAGE_TENANTS = "00e20637-ce8d-4417-bec4-9b31b5e65092";
@@ -98,7 +102,7 @@ export const EXPENSE_REJECTEDBY = [
];
export const EXPENSE_DRAFT = "297e0d8f-f668-41b5-bfea-e03b354251c8";
export const EXPENSE_MANAGEMENT = "a4e25142-449b-4334-a6e5-22f70e4732d7";
-export const EXPENSE_CREATE = "b8586f67-dc19-49c3-b4af-224149efe1d3"
+export const EXPENSE_CREATE = "b8586f67-dc19-49c3-b4af-224149efe1d3";
export const INR_CURRENCY_CODE = "78e96e4a-7ce0-4164-ae3a-c833ad45ec2c";
export const EXPENSE_PROCESSED = "61578360-3a49-4c34-8604-7b35a3787b95";
export const TENANT_STATUS = [
@@ -165,7 +169,7 @@ export const EXPENSE_STATUS = {
approve_pending: "4068007f-c92f-4f37-a907-bc15fe57d4d8",
payment_processed: "61578360-3a49-4c34-8604-7b35a3787b95",
payment_done: "b8586f67-dc19-49c3-b4af-224149efe1d3",
-}
+};
export const UUID_REGEX =
/^\/employee\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
@@ -184,7 +188,7 @@ export const FREQUENCY_FOR_RECURRING = {
2: "Half-Yearly",
3: "Yearly",
4: "Daily",
- 5: "Weekly"
+ 5: "Weekly",
};
export const PAYEE_RECURRING_EXPENSE = [
@@ -206,9 +210,8 @@ export const PAYEE_RECURRING_EXPENSE = [
},
];
-
//#region Service Project and Jobs
-export const STATUS_JOB_CLOSED = "3ddeefb5-ae3c-4e10-a922-35e0a452bb69"
+export const STATUS_JOB_CLOSED = "3ddeefb5-ae3c-4e10-a922-35e0a452bb69";
//#endregion
@@ -241,4 +244,4 @@ export const JOBS_STATUS_IDS = [
id: "75a0c8b8-9c6a-41af-80bf-b35bab722eb2",
label: "On Hold",
},
-];
\ No newline at end of file
+];