diff --git a/src/routes.js b/src/routes.js index 0abaa22..6a2ef09 100644 --- a/src/routes.js +++ b/src/routes.js @@ -167,6 +167,7 @@ import SingleSales from "./views/Sales/SingleSale"; import MobileApp from "./views/configuration/MobileApp"; import PDOpeningInventory from "./views/OpeningInventory/PDOpeningInventory"; import DistributorOpeningInventory from "./views/PrincipalDistributors/OpeningInventory"; +import UploadOpeningInventory from "./views/PrincipalDistributors/UploadOpeningInventory"; const routes = [ //dashboard @@ -425,6 +426,12 @@ const routes = [ element: DistributorOpeningInventory, navName: "Distributor", }, + { + path: "/:distributortype/opening-inventory/upload/:id", + name: " Distributor Opening Inventory Upload", + element: UploadOpeningInventory, + navName: "Distributor", + }, //----------------------- End Product Management Routes------------------------------------------------ //Departure diff --git a/src/views/PrincipalDistributors/OpeningInventory.js b/src/views/PrincipalDistributors/OpeningInventory.js index f85f2f2..755f070 100644 --- a/src/views/PrincipalDistributors/OpeningInventory.js +++ b/src/views/PrincipalDistributors/OpeningInventory.js @@ -15,6 +15,7 @@ const DistributorOpeningInventory = () => { const [loading, setLoading] = useState(false); const [productsData, setProductsData] = useState([]); + const [allProductsData, setAllProductsData] = useState([]); const [categories, setCategories] = useState([]); const [brands, setBrands] = useState([]); const [user, setUser] = useState(null); @@ -77,8 +78,22 @@ const DistributorOpeningInventory = () => { }, } ); + // console.log(response.data.products); setProductsData(response.data?.products || []); setTotalData(response.data?.totalProducts || 0); + // Merge new products with existing ones in allProductsData + setAllProductsData((prev) => { + const updatedList = [...prev]; + response.data?.products?.forEach((product) => { + const index = updatedList.findIndex((p) => p._id === product._id); + if (index > -1) { + updatedList[index] = product; // Update existing product + } else { + updatedList.push(product); // Add new product + } + }); + return updatedList; + }); } catch (err) { swal({ title: "Error", @@ -157,19 +172,30 @@ const DistributorOpeningInventory = () => { ...prevStocks, [sku]: newStock, // Update stock for specific product (identified by SKU) })); + + // Update the stock directly in allProductsData + setAllProductsData((prev) => + prev.map((product) => + product.SKU === sku ? { ...product, stock: newStock } : product + ) + ); }; const handleSubmitStocks = async () => { try { - const updatedProducts = productsData.map((product) => ({ - ...product, - stock: updatedStocks[product.SKU] || product.stock, + const updatedProducts = allProductsData.map((product) => ({ + _id: product._id, + SKU: product.SKU, + name: product.name, + openingInventory: updatedStocks[product.SKU] || product.stock, })); - await axios.post( + // console.log(updatedProducts); + // console.log(id); + await axios.put( distributortype === "principaldistributor" - ? `/api/pd/updateStocks/${id}` - : `/api/rd/updateStocks/${id}`, - { updatedProducts }, + ? `/api/pd/stock-update` + : `/api/rd/stock-update`, + { products: updatedProducts, userId: id }, { headers: { Authorization: `Bearer ${token}` } } ); swal("Success", "Stocks updated successfully!", "success"); @@ -215,7 +241,23 @@ const DistributorOpeningInventory = () => { Email: {user?.email} - +
+ +
{/* Back Button on the right */}
+
+ +
-
+
{ + const [file, setFile] = useState(null); + const [loading, setLoading] = useState(false); + const [errors, setErrors] = useState([]); + const [newlyCreated, setNewlyCreated] = useState([]); + const [updatedInventories, setupdatedInventories] = useState([]); + const navigate = useNavigate(); + const token = isAutheticated(); + const { id, distributortype } = useParams(); + const handleFileChange = (e) => { + const selectedFile = e.target.files[0]; + if ( + selectedFile && + selectedFile.type === + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ) { + setFile(selectedFile); + } else { + swal("Error", "Please upload a valid Excel file", "error"); + setFile(null); + } + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + if (!file) { + toast.error("Please select a file to upload"); + return; + } + // console.log(file); + // console.log(token); + setLoading(true); + setErrors([]); + setNewlyCreated([]); + setupdatedInventories([]); + try { + const formData = new FormData(); + formData.append("file", file); + + const { data } = await axios.post( + `/api/openinginventories/upload/${id}`, + formData, + { + headers: { + "Content-Type": "multipart/form-data", + Authorization: `Bearer ${token}`, + }, + } + ); + // console.log(data); + if (data?.errors && data?.errors?.length > 0) { + setErrors(data.errors); + } + if (data?.newlyCreated && data?.newlyCreated?.length > 0) { + setNewlyCreated(data?.newlyCreated); + } + if (data?.updatedOpeningInventories && data?.updatedOpeningInventories?.length > 0) { + setupdatedInventories(data?.updatedOpeningInventories); + // console.log(data.updatedOpeningInventories); + } + + // Redirect or display success message + if (data?.errors && data?.errors.length > 0) { + setErrors(data?.errors); + swal({ + title: "SpreadSheet Upload Successful", + text: "A few Products have errors. Please fix them and upload again.", + icon: "warning", + button: "OK", + }); + } else if ( + data?.newlyCreated.length > 0 || + data?.updatedInventories.length > 0 + ) { + swal({ + title: "SpreadSheet Upload Successful", + text: "Product Opening Inventory uploaded successfully.", + icon: "success", + buttons: "OK", + }); + } else { + toast.success("File processed successfully with no new entries."); + handleCancel(); + } + setFile(null); // Clear the file input + document.querySelector('input[type="file"]').value = ""; + } catch (error) { + console.error("Upload error:", error); + swal( + "Error", + `Failed to upload Opening Inventory Spreedsheet: ${ + error.response?.data?.message || "An unexpected error occurred" + }`, + "error" + ); + } finally { + setLoading(false); + } + }; + const handleCancel = () => { + navigate( + distributortype === "principaldistributor" + ? `/principaldistributor/opening-inventory/${id}` + : `/retaildistributor/opening-inventory/${id}` + ); + }; + return ( +
+
+ +
+
Add Multiple Products Opening inventory
+
+
+
+ +
+
+ +
+
+

Upload only .xlsx files*

+
+ + {errors.length > 0 && ( +
+
Finding errors while adding the Opening Inventory.
+
+ + + + + + + + + + {errors.map((error, index) => ( + + + + + + + ))} + +
SKUProduct NameOpening InventoryMessage
{error.SKU || "N/A"}{error.productName || "N/A"}{error.openingInventory || "N/A"}{error.message}
+
+ )} + {updatedInventories.length > 0 && ( +
+
Updated Products in the Opening Inventory List
+ + + + + + + + + + + {updatedInventories.map((distributor, index) => ( + + + + + + + ))} + +
SKUProduct NameOpening InventoryMessage
{distributor.SKU || "N/A"}{distributor.productName || "N/A"}{distributor.openingInventory || "N/A"}{distributor.updatedFields}
+
+ )} + {newlyCreated.length > 0 && ( +
+
Newly Added Products in Opening Inventory:
+ + + + + + + + + + {newlyCreated.map((distributor, index) => ( + + + + + + ))} + +
SKUProduct NameOpening Inventory
{distributor.SKU || "N/A"}{distributor.productName || "N/A"}{distributor.openingInventory }
+
+ )} +
+ ); +}; + +export default UploadOpeningInventory; diff --git a/src/views/PrincipalDistributors/principalDistributor.js b/src/views/PrincipalDistributors/principalDistributor.js index 0795109..3286c3b 100644 --- a/src/views/PrincipalDistributors/principalDistributor.js +++ b/src/views/PrincipalDistributors/principalDistributor.js @@ -205,13 +205,17 @@ const principalDistributor = () => { -
+