Merge pull request 'feat: Add XLSX/PDF Download & Bulk Upload for Product, Stock, Purchase Order & Common Master' (#320) from beforeaddandroidfileforcapcitor into main
Reviewed-on: Pozomind/pozo-retail-app#320
This commit is contained in:
commit
e20494d2fb
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"appId": "com.example.app",
|
||||||
|
"appName": "PozoApp",
|
||||||
|
"webDir": "dist",
|
||||||
|
"plugins": {
|
||||||
|
"StatusBar": {
|
||||||
|
"overlay": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,10 +12,14 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/plots": "^2.6.8",
|
"@ant-design/plots": "^2.6.8",
|
||||||
|
"@capacitor-community/file-opener": "^8.0.0",
|
||||||
"@capacitor-community/speech-recognition": "^7.0.1",
|
"@capacitor-community/speech-recognition": "^7.0.1",
|
||||||
"@capacitor-mlkit/barcode-scanning": "^8.0.1",
|
"@capacitor-mlkit/barcode-scanning": "^8.0.1",
|
||||||
|
"@capacitor/android": "^8.3.0",
|
||||||
"@capacitor/app": "^8.0.1",
|
"@capacitor/app": "^8.0.1",
|
||||||
"@capacitor/core": "^8.1.0",
|
"@capacitor/cli": "^8.3.0",
|
||||||
|
"@capacitor/core": "^8.3.0",
|
||||||
|
"@capacitor/filesystem": "^8.1.2",
|
||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
"@dnd-kit/sortable": "^10.0.0",
|
"@dnd-kit/sortable": "^10.0.0",
|
||||||
"@emotion/react": "^11.11.4",
|
"@emotion/react": "^11.11.4",
|
||||||
|
|
@ -27,6 +31,7 @@
|
||||||
"@tanstack/react-query-devtools": "^5.91.1",
|
"@tanstack/react-query-devtools": "^5.91.1",
|
||||||
"@tanstack/react-virtual": "^3.13.18",
|
"@tanstack/react-virtual": "^3.13.18",
|
||||||
"@types/node": "^25.5.0",
|
"@types/node": "^25.5.0",
|
||||||
|
"@vitejs/plugin-legacy": "^8.0.1",
|
||||||
"@zxing/library": "^0.21.3",
|
"@zxing/library": "^0.21.3",
|
||||||
"antd": "^5.17.4",
|
"antd": "^5.17.4",
|
||||||
"antd-img-crop": "^4.22.0",
|
"antd-img-crop": "^4.22.0",
|
||||||
|
|
@ -92,7 +97,7 @@
|
||||||
"eslint-plugin-react-refresh": "^0.4.7",
|
"eslint-plugin-react-refresh": "^0.4.7",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"rollup-plugin-obfuscator": "^1.1.0",
|
"rollup-plugin-obfuscator": "^1.1.0",
|
||||||
"sass": "^1.77.2",
|
"sass": "^1.98.0",
|
||||||
"terser": "^5.31.3",
|
"terser": "^5.31.3",
|
||||||
"vite": "^8.0.0",
|
"vite": "^8.0.0",
|
||||||
"vite-plugin-obfuscator": "^1.0.5",
|
"vite-plugin-obfuscator": "^1.0.5",
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import { RadioGrpButton } from '../../Components/Forms/RadioGroup.jsx';
|
||||||
import { AiFillDelete } from 'react-icons/ai';
|
import { AiFillDelete } from 'react-icons/ai';
|
||||||
import upldimg from '../../Images/upldimg.png';
|
import upldimg from '../../Images/upldimg.png';
|
||||||
import { FiDelete, FiDownload } from 'react-icons/fi';
|
import { FiDelete, FiDownload } from 'react-icons/fi';
|
||||||
|
import { downloadFile } from '../../utils/downloadFile.js';
|
||||||
const allowedExcelTypes = [
|
const allowedExcelTypes = [
|
||||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
|
||||||
'application/vnd.ms-excel', // .xls
|
'application/vnd.ms-excel', // .xls
|
||||||
|
|
@ -328,10 +329,17 @@ const ConfigExcel = ({ handleSubmit, CategoryNames, SubCatData }) => {
|
||||||
window.navigator.msSaveOrOpenBlob(blob, filename);
|
window.navigator.msSaveOrOpenBlob(blob, filename);
|
||||||
} else {
|
} else {
|
||||||
// For other browsers
|
// For other browsers
|
||||||
const downloadLink = document.createElement('a');
|
downloadFile(
|
||||||
downloadLink.href = window.URL.createObjectURL(blob);
|
buffer,
|
||||||
downloadLink.download = filename;
|
"CategoryDatas.xlsx",
|
||||||
downloadLink.click();
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
(success) => {
|
||||||
|
if (!success) {
|
||||||
|
console.error("error occured while downloading")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -415,10 +423,17 @@ const ConfigExcel = ({ handleSubmit, CategoryNames, SubCatData }) => {
|
||||||
window.navigator.msSaveOrOpenBlob(blob, filename);
|
window.navigator.msSaveOrOpenBlob(blob, filename);
|
||||||
} else {
|
} else {
|
||||||
// For other browsers
|
// For other browsers
|
||||||
const downloadLink = document.createElement('a');
|
|
||||||
downloadLink.href = window.URL.createObjectURL(blob);
|
downloadFile(
|
||||||
downloadLink.download = filename;
|
buffer,
|
||||||
downloadLink.click();
|
"SubcatagoryDatas.xlsx",
|
||||||
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
(success) => {
|
||||||
|
if (!success) {
|
||||||
|
console.error("Failed to download the file. Please try again.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -529,10 +544,17 @@ const ConfigExcel = ({ handleSubmit, CategoryNames, SubCatData }) => {
|
||||||
window.navigator.msSaveOrOpenBlob(blob, filename);
|
window.navigator.msSaveOrOpenBlob(blob, filename);
|
||||||
} else {
|
} else {
|
||||||
// For other browsers
|
// For other browsers
|
||||||
const downloadLink = document.createElement('a');
|
downloadFile(
|
||||||
downloadLink.href = window.URL.createObjectURL(blob);
|
buffer,
|
||||||
downloadLink.download = filename;
|
"BrandDatas.xlsx",
|
||||||
downloadLink.click();
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
(success) => {
|
||||||
|
if (!success) {
|
||||||
|
console.error("Failed to download the file. Please try again.")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -673,7 +695,7 @@ const ConfigExcel = ({ handleSubmit, CategoryNames, SubCatData }) => {
|
||||||
...record,
|
...record,
|
||||||
...values,
|
...values,
|
||||||
});
|
});
|
||||||
} catch (errInfo) {}
|
} catch (errInfo) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
let childNode = children;
|
let childNode = children;
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ import Buttons from '../../Components/Forms/Buttons.jsx';
|
||||||
import { IoClose } from 'react-icons/io5';
|
import { IoClose } from 'react-icons/io5';
|
||||||
import { Messages } from '../../Components/Notifications/Messages.jsx';
|
import { Messages } from '../../Components/Notifications/Messages.jsx';
|
||||||
import useWhyDidYouUpdate from '../../Services/findrerender.js';
|
import useWhyDidYouUpdate from '../../Services/findrerender.js';
|
||||||
|
import { downloadFile } from '../../utils/downloadFile.js';
|
||||||
|
|
||||||
const getApplicationSampleData = (appName) => {
|
const getApplicationSampleData = (appName) => {
|
||||||
const sampleDataMap = {
|
const sampleDataMap = {
|
||||||
|
|
@ -1227,8 +1228,8 @@ const ProductExcel = ({
|
||||||
allowBlank: true,
|
allowBlank: true,
|
||||||
formulae: [
|
formulae: [
|
||||||
'"' +
|
'"' +
|
||||||
(typeof Unit !== 'undefined' ? Unit.join(',') : 'KGS,PCS,LITER') +
|
(typeof Unit !== 'undefined' ? Unit.join(',') : 'KGS,PCS,LITER') +
|
||||||
'"',
|
'"',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
sampleValue: sampleData?.uom || 'KGS',
|
sampleValue: sampleData?.uom || 'KGS',
|
||||||
|
|
@ -2357,23 +2358,21 @@ const ProductExcel = ({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Generate and download the file
|
|
||||||
const buffer = await workbook.xlsx.writeBuffer();
|
const buffer = await workbook.xlsx.writeBuffer();
|
||||||
const blob = new Blob([buffer], {
|
|
||||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
||||||
});
|
|
||||||
const filename = 'Product Data.xlsx';
|
|
||||||
|
|
||||||
if (typeof window !== 'undefined') {
|
downloadFile(
|
||||||
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
|
buffer,
|
||||||
window.navigator.msSaveOrOpenBlob(blob, filename);
|
"Product Data.xlsx",
|
||||||
} else {
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
const downloadLink = document.createElement('a');
|
(success) => {
|
||||||
downloadLink.href = window.URL.createObjectURL(blob);
|
if (success) {
|
||||||
downloadLink.download = filename;
|
console.log("File downloaded and opened successfully!");
|
||||||
downloadLink.click();
|
} else {
|
||||||
|
console.log("Failed to download/open file.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFileSubmit = (e) => {
|
const handleFileSubmit = (e) => {
|
||||||
|
|
@ -2908,15 +2907,21 @@ const ProductExcel = ({
|
||||||
selectUnlockedCells: true,
|
selectUnlockedCells: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// const buffer = await workbook.xlsx.writeBuffer();
|
||||||
|
// const blob = new Blob([buffer], {
|
||||||
|
// type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
// });
|
||||||
|
// const downloadLink = document.createElement('a');
|
||||||
|
// downloadLink.href = window.URL.createObjectURL(blob);
|
||||||
|
// downloadLink.download = 'Product_Data.xlsx';
|
||||||
|
// downloadLink.click();
|
||||||
const buffer = await workbook.xlsx.writeBuffer();
|
const buffer = await workbook.xlsx.writeBuffer();
|
||||||
const blob = new Blob([buffer], {
|
|
||||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
||||||
});
|
|
||||||
const downloadLink = document.createElement('a');
|
|
||||||
downloadLink.href = window.URL.createObjectURL(blob);
|
|
||||||
downloadLink.download = 'Product_Data.xlsx';
|
|
||||||
downloadLink.click();
|
|
||||||
|
|
||||||
|
downloadFile(
|
||||||
|
buffer,
|
||||||
|
"Product_Data.xlsx",
|
||||||
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||||
|
);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
} else {
|
} else {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
@ -3228,98 +3233,98 @@ const ProductExcel = ({
|
||||||
<div className="download-linkMain">
|
<div className="download-linkMain">
|
||||||
<div className="HeadingUploadExl">
|
<div className="HeadingUploadExl">
|
||||||
<p
|
<p
|
||||||
style={{
|
style={{
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Upload Your Excel
|
Upload Your Excel
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
gap: '0.5rem',
|
gap: '0.5rem',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Tooltip title="Field Setup">
|
<Tooltip title="Field Setup">
|
||||||
<div
|
|
||||||
className="btn btn--info"
|
|
||||||
style={{
|
|
||||||
background: '#00694aff',
|
|
||||||
color: '#fff',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
padding: '5px 12px',
|
|
||||||
borderRadius: '4px',
|
|
||||||
}}
|
|
||||||
onClick={handleFieldSetup}
|
|
||||||
>
|
|
||||||
<MdOutlineAppRegistration size={19} />
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
<div
|
<div
|
||||||
className="export-excel-div"
|
className="btn btn--info"
|
||||||
onClick={() => handleExportData()}
|
style={{
|
||||||
|
background: '#00694aff',
|
||||||
|
color: '#fff',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
padding: '5px 12px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
}}
|
||||||
|
onClick={handleFieldSetup}
|
||||||
>
|
>
|
||||||
<div>
|
<MdOutlineAppRegistration size={19} />
|
||||||
<CiExport size={20} strokeWidth={1} />
|
|
||||||
</div>
|
|
||||||
<div style={{ fontSize: '14px', letterSpacing: '0.2px' }}>
|
|
||||||
Export Excel
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
<div
|
||||||
|
className="export-excel-div"
|
||||||
|
onClick={() => handleExportData()}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<CiExport size={20} strokeWidth={1} />
|
||||||
|
</div>
|
||||||
|
<div style={{ fontSize: '14px', letterSpacing: '0.2px' }}>
|
||||||
|
Export Excel
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{message && (
|
{message && (
|
||||||
<div style={{ color: '#ff4d4f' }}>No Data Found</div>
|
<div style={{ color: '#ff4d4f' }}>No Data Found</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
|
|
||||||
{excelData?.length > 0 && excelData && (
|
|
||||||
<div>
|
|
||||||
<Tooltip title="Delete">
|
|
||||||
<AiFillDelete
|
|
||||||
onClick={handlechange22}
|
|
||||||
style={{
|
|
||||||
fontSize: '23px',
|
|
||||||
color: editdelete ? '#52c41a' : '#1292ee',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
className="download-link"
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent:
|
|
||||||
excelData?.length > 0 ? 'space-between' : 'flex-end',
|
|
||||||
gap: '1rem',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{excelData?.length > 0 && (
|
|
||||||
<div className="SheetIndiacte">
|
|
||||||
<div>
|
|
||||||
<p className="mdsheet"></p>
|
|
||||||
<span>Modified</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="mdsheet2"></p>
|
|
||||||
<span>Not Modified</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Tooltip title={'Format Sheet'} placement="top">
|
{excelData?.length > 0 && excelData && (
|
||||||
<button onClick={handleDownload}>
|
<div>
|
||||||
<FiDownload style={{ fontSize: '20px' }} />
|
<Tooltip title="Delete">
|
||||||
<span>Download Sample Sheet</span>
|
<AiFillDelete
|
||||||
</button>
|
onClick={handlechange22}
|
||||||
</Tooltip>
|
style={{
|
||||||
|
fontSize: '23px',
|
||||||
|
color: editdelete ? '#52c41a' : '#1292ee',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="download-link"
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent:
|
||||||
|
excelData?.length > 0 ? 'space-between' : 'flex-end',
|
||||||
|
gap: '1rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{excelData?.length > 0 && (
|
||||||
|
<div className="SheetIndiacte">
|
||||||
|
<div>
|
||||||
|
<p className="mdsheet"></p>
|
||||||
|
<span>Modified</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="mdsheet2"></p>
|
||||||
|
<span>Not Modified</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Tooltip title={'Format Sheet'} placement="top">
|
||||||
|
<button onClick={handleDownload}>
|
||||||
|
<FiDownload style={{ fontSize: '20px' }} />
|
||||||
|
<span>Download Sample Sheet</span>
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -3502,7 +3507,7 @@ const ProductExcel = ({
|
||||||
<div
|
<div
|
||||||
className={`singleimg ${
|
className={`singleimg ${
|
||||||
selectedImage === item ? 'selected' : ''
|
selectedImage === item ? 'selected' : ''
|
||||||
}`}
|
}`}
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => setSelectedImage(item)}
|
onClick={() => setSelectedImage(item)}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import { DefaultModal } from '../../Components/Modal/DefaultModal.jsx';
|
||||||
import Buttons from '../../Components/Forms/Buttons.jsx';
|
import Buttons from '../../Components/Forms/Buttons.jsx';
|
||||||
import { getPurchaseSupplierAndWareHouseData } from '../../Features/PurchaseOrder/PurchaseOrder.js';
|
import { getPurchaseSupplierAndWareHouseData } from '../../Features/PurchaseOrder/PurchaseOrder.js';
|
||||||
import { Messages } from '../../Components/Notifications/Messages.jsx';
|
import { Messages } from '../../Components/Notifications/Messages.jsx';
|
||||||
|
import { downloadFile } from '../../utils/downloadFile.js';
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
const ALLOWED_EXCEL_TYPES = [
|
const ALLOWED_EXCEL_TYPES = [
|
||||||
|
|
@ -522,15 +523,19 @@ const PurchaseExcel = ({ handleSubmit }) => {
|
||||||
|
|
||||||
// Step 7: Export file
|
// Step 7: Export file
|
||||||
const buffer = await workbook.xlsx.writeBuffer();
|
const buffer = await workbook.xlsx.writeBuffer();
|
||||||
const blob = new Blob([buffer], {
|
|
||||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
||||||
});
|
|
||||||
|
|
||||||
const filename = `PurchaseOrder_${supplierDisplayName}.xlsx`;
|
const filename = `PurchaseOrder_${supplierDisplayName}.xlsx`;
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = URL.createObjectURL(blob);
|
downloadFile(
|
||||||
link.download = filename;
|
buffer,
|
||||||
link.click();
|
filename,
|
||||||
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
(success) => {
|
||||||
|
if (!success) {
|
||||||
|
setMessageType('error');
|
||||||
|
setMessageData('Failed to download the file. Please try again.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
setSupplierProducts([]);
|
setSupplierProducts([]);
|
||||||
setSelectedSupplierData(null);
|
setSelectedSupplierData(null);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import {
|
||||||
import QRCodeLib from 'qrcode';
|
import QRCodeLib from 'qrcode';
|
||||||
import { LuDownload } from 'react-icons/lu';
|
import { LuDownload } from 'react-icons/lu';
|
||||||
import { BsFileEarmarkPdf } from 'react-icons/bs';
|
import { BsFileEarmarkPdf } from 'react-icons/bs';
|
||||||
|
import { downloadFile } from '../../../utils/downloadFile';
|
||||||
|
|
||||||
const subDirectory = import.meta.env.ENV_MAIN_BASE_URL || '/';
|
const subDirectory = import.meta.env.ENV_MAIN_BASE_URL || '/';
|
||||||
|
|
||||||
|
|
@ -312,7 +313,19 @@ const MenuQRCode = () => {
|
||||||
if (openPreview) {
|
if (openPreview) {
|
||||||
setIsPreviewModalOpen(true);
|
setIsPreviewModalOpen(true);
|
||||||
} else {
|
} else {
|
||||||
pdf.save('menu-qr.pdf');
|
// pdf.save('menu-qr.pdf');
|
||||||
|
const pdfBuffer = pdf.output('arraybuffer'); // ✅ arraybuffer for downloadFile
|
||||||
|
downloadFile(
|
||||||
|
pdfBuffer,
|
||||||
|
"menu-qr.pdf",
|
||||||
|
"application/pdf",
|
||||||
|
(success) => {
|
||||||
|
if (!success) {
|
||||||
|
setMessageType('error');
|
||||||
|
setMessageData('Failed to download the PDF. Please try again.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('PDF generation failed', err);
|
console.error('PDF generation failed', err);
|
||||||
|
|
@ -323,17 +336,21 @@ const MenuQRCode = () => {
|
||||||
|
|
||||||
const downloadPreviewPdf = () => {
|
const downloadPreviewPdf = () => {
|
||||||
if (!pdfPreviewUrl) return;
|
if (!pdfPreviewUrl) return;
|
||||||
|
|
||||||
fetch(pdfPreviewUrl)
|
fetch(pdfPreviewUrl)
|
||||||
.then((r) => r.blob())
|
.then((r) => r.arrayBuffer()) // ✅ arrayBuffer instead of blob
|
||||||
.then((blob) => {
|
.then((buffer) => {
|
||||||
const url = URL.createObjectURL(blob);
|
downloadFile(
|
||||||
const a = document.createElement('a');
|
buffer,
|
||||||
a.href = url;
|
"menu-qr.pdf",
|
||||||
a.download = 'menu-qr.pdf';
|
"application/pdf",
|
||||||
document.body.appendChild(a);
|
(success) => {
|
||||||
a.click();
|
if (!success) {
|
||||||
a.remove();
|
setMessageType('error');
|
||||||
URL.revokeObjectURL(url);
|
setMessageData('Failed to download the file. Please try again.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import {
|
||||||
import { Messages } from '../../Components/Notifications/Messages.jsx';
|
import { Messages } from '../../Components/Notifications/Messages.jsx';
|
||||||
import { getPurchaseSupplierAndWareHouseData } from '../../Features/PurchaseOrder/PurchaseOrder.js';
|
import { getPurchaseSupplierAndWareHouseData } from '../../Features/PurchaseOrder/PurchaseOrder.js';
|
||||||
import { getSupplaierIdwithTypeBasedProducts } from '../../Features/SupplierProductMapping/SupplierProductMapping.js';
|
import { getSupplaierIdwithTypeBasedProducts } from '../../Features/SupplierProductMapping/SupplierProductMapping.js';
|
||||||
|
import { downloadFile } from '../../utils/downloadFile.js';
|
||||||
|
|
||||||
const allowedExcelTypes = [
|
const allowedExcelTypes = [
|
||||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
|
||||||
|
|
@ -478,8 +479,8 @@ const StockExcel = ({
|
||||||
: c.key === 'Quantity'
|
: c.key === 'Quantity'
|
||||||
? 10
|
? 10
|
||||||
: c.key === 'Supplier' ||
|
: c.key === 'Supplier' ||
|
||||||
c.key === 'InvoiceDeliveryChallan' ||
|
c.key === 'InvoiceDeliveryChallan' ||
|
||||||
c.key === 'SupplierInvoiceNumber'
|
c.key === 'SupplierInvoiceNumber'
|
||||||
? 30
|
? 30
|
||||||
: 20,
|
: 20,
|
||||||
}));
|
}));
|
||||||
|
|
@ -1007,14 +1008,19 @@ const StockExcel = ({
|
||||||
});
|
});
|
||||||
|
|
||||||
const buffer = await workbook.xlsx.writeBuffer();
|
const buffer = await workbook.xlsx.writeBuffer();
|
||||||
const blob = new Blob([buffer], {
|
|
||||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
||||||
});
|
|
||||||
const filename = `PurchaseEntry_${supplierDisplayName}_${Date.now()}.xlsx`;
|
const filename = `PurchaseEntry_${supplierDisplayName}_${Date.now()}.xlsx`;
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = URL.createObjectURL(blob);
|
downloadFile(
|
||||||
link.download = filename;
|
buffer,
|
||||||
link.click();
|
filename,
|
||||||
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
(success) => {
|
||||||
|
if (!success) {
|
||||||
|
setMessageType('error');
|
||||||
|
setMessageData('Failed to download the file. Please try again.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
setSupplierProducts([]);
|
setSupplierProducts([]);
|
||||||
setSelectedSupplierData(null);
|
setSelectedSupplierData(null);
|
||||||
|
|
@ -1332,7 +1338,7 @@ const StockExcel = ({
|
||||||
...record,
|
...record,
|
||||||
...values,
|
...values,
|
||||||
});
|
});
|
||||||
} catch (errInfo) {}
|
} catch (errInfo) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
let childNode = children;
|
let childNode = children;
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ import {
|
||||||
getCommonAppPreference,
|
getCommonAppPreference,
|
||||||
} from '../../Features/BrachLogin/BranchLogin.js';
|
} from '../../Features/BrachLogin/BranchLogin.js';
|
||||||
import { IoClose } from 'react-icons/io5';
|
import { IoClose } from 'react-icons/io5';
|
||||||
|
import { downloadFile } from '../../utils/downloadFile.js';
|
||||||
|
|
||||||
const StockPriceUpdate = () => {
|
const StockPriceUpdate = () => {
|
||||||
const { SadminuserAccess } = useAuth();
|
const { SadminuserAccess } = useAuth();
|
||||||
|
|
@ -179,53 +180,53 @@ const StockPriceUpdate = () => {
|
||||||
},
|
},
|
||||||
...(hasFieldExists('Stock')
|
...(hasFieldExists('Stock')
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: 'Stock',
|
title: 'Stock',
|
||||||
dataIndex: 'Stock',
|
dataIndex: 'Stock',
|
||||||
key: 'Stock',
|
key: 'Stock',
|
||||||
width: 80,
|
width: 80,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...(hasFieldExists('Stock Date')
|
...(hasFieldExists('Stock Date')
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: 'Stock Date',
|
title: 'Stock Date',
|
||||||
dataIndex: 'StockDate',
|
dataIndex: 'StockDate',
|
||||||
key: 'StockDate',
|
key: 'StockDate',
|
||||||
width: 80,
|
width: 80,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...(hasFieldExists('Old MRP')
|
...(hasFieldExists('Old MRP')
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: 'Old MRP',
|
title: 'Old MRP',
|
||||||
dataIndex: 'OldMRP',
|
dataIndex: 'OldMRP',
|
||||||
key: 'OldMRP',
|
key: 'OldMRP',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...(hasFieldExists('Old SP')
|
...(hasFieldExists('Old SP')
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: 'Old SP',
|
title: 'Old SP',
|
||||||
dataIndex: 'OldSP',
|
dataIndex: 'OldSP',
|
||||||
key: 'OldSP',
|
key: 'OldSP',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...(hasFieldExists('Old Wholesale Price')
|
...(hasFieldExists('Old Wholesale Price')
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: 'Old Wholesale Price',
|
title: 'Old Wholesale Price',
|
||||||
dataIndex: 'OldWholeSalePrice',
|
dataIndex: 'OldWholeSalePrice',
|
||||||
key: 'OldWholeSalePrice',
|
key: 'OldWholeSalePrice',
|
||||||
width: 140,
|
width: 140,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
|
|
||||||
// ✅ EDITABLE
|
// ✅ EDITABLE
|
||||||
|
|
@ -322,7 +323,7 @@ const StockPriceUpdate = () => {
|
||||||
);
|
);
|
||||||
excelDataRef.current
|
excelDataRef.current
|
||||||
?.validateFields([`NewSellPrice${record.localId}`])
|
?.validateFields([`NewSellPrice${record.localId}`])
|
||||||
.catch(() => {});
|
.catch(() => { });
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -331,40 +332,40 @@ const StockPriceUpdate = () => {
|
||||||
},
|
},
|
||||||
...(hasFieldExists('New Wholesale Price')
|
...(hasFieldExists('New Wholesale Price')
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: 'New Wholesale Price',
|
title: 'New Wholesale Price',
|
||||||
dataIndex: 'NewWholeSalePrice',
|
dataIndex: 'NewWholeSalePrice',
|
||||||
key: 'NewWholeSalePrice',
|
key: 'NewWholeSalePrice',
|
||||||
width: 160,
|
width: 160,
|
||||||
render: (value, record, index) => (
|
render: (value, record, index) => (
|
||||||
<Form.Item name={`NewWholeSalePrice${record?.localId}`}>
|
<Form.Item name={`NewWholeSalePrice${record?.localId}`}>
|
||||||
<Input
|
<Input
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handlePriceChange(
|
handlePriceChange(
|
||||||
index,
|
index,
|
||||||
'NewWholeSalePrice',
|
'NewWholeSalePrice',
|
||||||
e.target.value,
|
e.target.value,
|
||||||
record.localId
|
record.localId
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
placeholder="New Wholesale"
|
||||||
|
inputMode="decimal"
|
||||||
|
onInput={(e) => {
|
||||||
|
let cleanedValue = e.target.value.replace(/[^0-9.]/g, '');
|
||||||
|
const parts = cleanedValue.split('.');
|
||||||
|
if (cleanedValue.startsWith('.')) {
|
||||||
|
cleanedValue = '0' + cleanedValue;
|
||||||
}
|
}
|
||||||
placeholder="New Wholesale"
|
e.target.value =
|
||||||
inputMode="decimal"
|
parts.length > 2
|
||||||
onInput={(e) => {
|
? `${parts[0]}.${parts.slice(1).join('')}`
|
||||||
let cleanedValue = e.target.value.replace(/[^0-9.]/g, '');
|
: cleanedValue;
|
||||||
const parts = cleanedValue.split('.');
|
}}
|
||||||
if (cleanedValue.startsWith('.')) {
|
/>
|
||||||
cleanedValue = '0' + cleanedValue;
|
</Form.Item>
|
||||||
}
|
),
|
||||||
e.target.value =
|
},
|
||||||
parts.length > 2
|
]
|
||||||
? `${parts[0]}.${parts.slice(1).join('')}`
|
|
||||||
: cleanedValue;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
: []),
|
||||||
{
|
{
|
||||||
title: 'Action',
|
title: 'Action',
|
||||||
|
|
@ -1092,79 +1093,79 @@ const StockPriceUpdate = () => {
|
||||||
},
|
},
|
||||||
...(hasField('Stock Date')
|
...(hasField('Stock Date')
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: 'stock Date',
|
title: 'stock Date',
|
||||||
dataIndex: 'InwardDate',
|
dataIndex: 'InwardDate',
|
||||||
key: 'InwardDate',
|
key: 'InwardDate',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 120,
|
width: 120,
|
||||||
render: (InwardDate) =>
|
render: (InwardDate) =>
|
||||||
InwardDate !== null ? ExtractDateFormate(InwardDate) : '-',
|
InwardDate !== null ? ExtractDateFormate(InwardDate) : '-',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...(hasField('Expiry Date')
|
...(hasField('Expiry Date')
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: 'Exp date',
|
title: 'Exp date',
|
||||||
dataIndex: 'ExpDate',
|
dataIndex: 'ExpDate',
|
||||||
key: 'ExpDate',
|
key: 'ExpDate',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 100,
|
width: 100,
|
||||||
render: (ExpDate) =>
|
render: (ExpDate) =>
|
||||||
ExpDate !== null ? ExtractDateFormate(ExpDate) : '-',
|
ExpDate !== null ? ExtractDateFormate(ExpDate) : '-',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...(hasField('Stock')
|
...(hasField('Stock')
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: 'stock',
|
title: 'stock',
|
||||||
dataIndex: 'BalanceQty',
|
dataIndex: 'BalanceQty',
|
||||||
key: 'BalanceQty',
|
key: 'BalanceQty',
|
||||||
align: 'right',
|
align: 'right',
|
||||||
width: '60px',
|
width: '60px',
|
||||||
render: (BalanceQty) => (BalanceQty !== null ? BalanceQty : '-'),
|
render: (BalanceQty) => (BalanceQty !== null ? BalanceQty : '-'),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...(hasField('Old MRP')
|
...(hasField('Old MRP')
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: 'Old MRP',
|
title: 'Old MRP',
|
||||||
dataIndex: 'MRP',
|
dataIndex: 'MRP',
|
||||||
key: 'MRP',
|
key: 'MRP',
|
||||||
align: 'right',
|
align: 'right',
|
||||||
width: '70px',
|
width: '70px',
|
||||||
render: (MRP) => (safeRound(MRP) !== null ? safeRound(MRP) : '-'),
|
render: (MRP) => (safeRound(MRP) !== null ? safeRound(MRP) : '-'),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...(hasField('Old SP')
|
...(hasField('Old SP')
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: 'Old SP',
|
title: 'Old SP',
|
||||||
dataIndex: 'SellPrice',
|
dataIndex: 'SellPrice',
|
||||||
key: 'SellPrice',
|
key: 'SellPrice',
|
||||||
align: 'right',
|
align: 'right',
|
||||||
width: '70px',
|
width: '70px',
|
||||||
render: (SellPrice) =>
|
render: (SellPrice) =>
|
||||||
safeRound(SellPrice) !== null ? safeRound(SellPrice) : '-',
|
safeRound(SellPrice) !== null ? safeRound(SellPrice) : '-',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...(hasField('Old Wholesale Price')
|
...(hasField('Old Wholesale Price')
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: 'Old Wholesale Price',
|
title: 'Old Wholesale Price',
|
||||||
dataIndex: 'WhSalePrice',
|
dataIndex: 'WhSalePrice',
|
||||||
key: 'WhSalePrice',
|
key: 'WhSalePrice',
|
||||||
align: 'right',
|
align: 'right',
|
||||||
width: '120px',
|
width: '120px',
|
||||||
render: (WhSalePrice) =>
|
render: (WhSalePrice) =>
|
||||||
safeRound(WhSalePrice) !== null ? safeRound(WhSalePrice) : '-',
|
safeRound(WhSalePrice) !== null ? safeRound(WhSalePrice) : '-',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
{
|
{
|
||||||
title: 'New MRP',
|
title: 'New MRP',
|
||||||
|
|
@ -1188,19 +1189,19 @@ const StockPriceUpdate = () => {
|
||||||
},
|
},
|
||||||
...(hasField('New Wholesale Price')
|
...(hasField('New Wholesale Price')
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: 'New Wholesale Price',
|
title: 'New Wholesale Price',
|
||||||
dataIndex: 'CurrentWhAmt',
|
dataIndex: 'CurrentWhAmt',
|
||||||
key: 'CurrentWhAmt',
|
key: 'CurrentWhAmt',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
with: '4rem',
|
with: '4rem',
|
||||||
editable: true,
|
editable: true,
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<p>{text ? text : 'Enter Wholesale Price'}</p>
|
<p>{text ? text : 'Enter Wholesale Price'}</p>
|
||||||
),
|
),
|
||||||
width: 120,
|
width: 120,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -1481,9 +1482,9 @@ const StockPriceUpdate = () => {
|
||||||
isStockVariantBased === 'Yes'
|
isStockVariantBased === 'Yes'
|
||||||
? BulkProductData || []
|
? BulkProductData || []
|
||||||
: (BulkProductData || [])?.filter(
|
: (BulkProductData || [])?.filter(
|
||||||
(item, index, self) =>
|
(item, index, self) =>
|
||||||
index === self.findIndex((p) => p.ProdId === item.ProdId)
|
index === self.findIndex((p) => p.ProdId === item.ProdId)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!uniqueBulkProductData?.length) {
|
if (!uniqueBulkProductData?.length) {
|
||||||
setMessageType('error');
|
setMessageType('error');
|
||||||
|
|
@ -1596,9 +1597,9 @@ const StockPriceUpdate = () => {
|
||||||
cell.border = isHiddenCol
|
cell.border = isHiddenCol
|
||||||
? undefined
|
? undefined
|
||||||
: {
|
: {
|
||||||
right: { style: 'thin', color: { argb: 'FF000000' } },
|
right: { style: 'thin', color: { argb: 'FF000000' } },
|
||||||
bottom: { style: 'thin', color: { argb: 'FF000000' } },
|
bottom: { style: 'thin', color: { argb: 'FF000000' } },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
/* ---------------- ADD DATA ---------------- */
|
/* ---------------- ADD DATA ---------------- */
|
||||||
|
|
@ -1713,14 +1714,19 @@ const StockPriceUpdate = () => {
|
||||||
|
|
||||||
/* ---------------- DOWNLOAD ---------------- */
|
/* ---------------- DOWNLOAD ---------------- */
|
||||||
const buffer = await workbook.xlsx.writeBuffer();
|
const buffer = await workbook.xlsx.writeBuffer();
|
||||||
const blob = new Blob([buffer], {
|
downloadFile(
|
||||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
buffer,
|
||||||
});
|
"PriceChange_Data.xlsx",
|
||||||
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
const link = document.createElement('a');
|
(success) => {
|
||||||
link.href = URL.createObjectURL(blob);
|
if (success) {
|
||||||
link.download = 'PriceChange_Data.xlsx';
|
console.log("Template downloaded successfully!");
|
||||||
link.click();
|
} else {
|
||||||
|
setMessageType('error');
|
||||||
|
setMessageData('Failed to download the template. Please try again.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
setExportLoading(false);
|
setExportLoading(false);
|
||||||
};
|
};
|
||||||
|
|
@ -1780,7 +1786,7 @@ const StockPriceUpdate = () => {
|
||||||
Number(current.MRP) !== Number(uploaded.NewMRP) ||
|
Number(current.MRP) !== Number(uploaded.NewMRP) ||
|
||||||
Number(current.SellPrice) !== Number(uploaded.NewSellPrice) ||
|
Number(current.SellPrice) !== Number(uploaded.NewSellPrice) ||
|
||||||
Number(current.WhSalePrice || 0) !==
|
Number(current.WhSalePrice || 0) !==
|
||||||
Number(uploaded.NewWholeSalePrice || 0);
|
Number(uploaded.NewWholeSalePrice || 0);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...uploaded,
|
...uploaded,
|
||||||
|
|
@ -2297,17 +2303,17 @@ const StockPriceUpdate = () => {
|
||||||
<div>
|
<div>
|
||||||
{(RadioSelection == 'Bulk' ||
|
{(RadioSelection == 'Bulk' ||
|
||||||
(RadioSelection == 'Single' && StockDetails.length > 0)) && (
|
(RadioSelection == 'Single' && StockDetails.length > 0)) && (
|
||||||
<div className="samplereportTableButton">
|
<div className="samplereportTableButton">
|
||||||
<Buttons
|
<Buttons
|
||||||
buttonText="Submit"
|
buttonText="Submit"
|
||||||
color="901D77"
|
color="901D77"
|
||||||
palcement={'right'}
|
palcement={'right'}
|
||||||
handleSubmit={HandlePutData}
|
handleSubmit={HandlePutData}
|
||||||
icon={<ArrowRightOutlined />}
|
icon={<ArrowRightOutlined />}
|
||||||
disabled={addnewAccess}
|
disabled={addnewAccess}
|
||||||
></Buttons>
|
></Buttons>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{RadioSelection == 'Single' && (
|
{RadioSelection == 'Single' && (
|
||||||
|
|
@ -2325,10 +2331,10 @@ const StockPriceUpdate = () => {
|
||||||
StockDetails?.length < 11
|
StockDetails?.length < 11
|
||||||
? false
|
? false
|
||||||
: {
|
: {
|
||||||
current: page,
|
current: page,
|
||||||
pageSize: pageSize,
|
pageSize: pageSize,
|
||||||
onChange: handlePageChange,
|
onChange: handlePageChange,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
></Table>
|
></Table>
|
||||||
|
|
@ -2395,7 +2401,7 @@ const StockPriceUpdate = () => {
|
||||||
<div
|
<div
|
||||||
className={`export-excel-div ${exportLoading ? 'is-loading' : ''}`}
|
className={`export-excel-div ${exportLoading ? 'is-loading' : ''}`}
|
||||||
onClick={
|
onClick={
|
||||||
exportLoading ? () => {} : () => showPriceChangeModal()
|
exportLoading ? () => { } : () => showPriceChangeModal()
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { RiFileExcel2Fill } from 'react-icons/ri';
|
||||||
import { Messages } from '../../Components/Notifications/Messages.jsx';
|
import { Messages } from '../../Components/Notifications/Messages.jsx';
|
||||||
import { getSession } from '../../Services/Others.js';
|
import { getSession } from '../../Services/Others.js';
|
||||||
import './OpeningStockExcel.scss';
|
import './OpeningStockExcel.scss';
|
||||||
|
import { downloadFile } from '../../utils/downloadFile.js';
|
||||||
|
|
||||||
const TEMPLATE_HEADERS = [
|
const TEMPLATE_HEADERS = [
|
||||||
{ key: 'ProdName', header: 'Product Name' },
|
{ key: 'ProdName', header: 'Product Name' },
|
||||||
|
|
@ -203,15 +204,20 @@ const OpeningStockExcel = ({ products = [], onApply, onCancel }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const buffer = await workbook.xlsx.writeBuffer();
|
const buffer = await workbook.xlsx.writeBuffer();
|
||||||
const blob = new Blob([buffer], {
|
|
||||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
||||||
});
|
|
||||||
|
|
||||||
const link = document.createElement('a');
|
downloadFile(
|
||||||
link.href = URL.createObjectURL(blob);
|
buffer,
|
||||||
link.download = 'opening_stock_template.xlsx';
|
"opening_stock_template.xlsx",
|
||||||
link.click();
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
URL.revokeObjectURL(link.href);
|
(success) => {
|
||||||
|
if (success) {
|
||||||
|
console.log("Template downloaded successfully!");
|
||||||
|
} else {
|
||||||
|
setMessageType('error');
|
||||||
|
setMessageData('Failed to download the template. Please try again.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Template download failed:', error);
|
console.error('Template download failed:', error);
|
||||||
setMessageType('error');
|
setMessageType('error');
|
||||||
|
|
@ -562,8 +568,8 @@ const OpeningStockExcel = ({ products = [], onApply, onCancel }) => {
|
||||||
: '',
|
: '',
|
||||||
TotalPcs:
|
TotalPcs:
|
||||||
row.OnePcsAvailable === 'Y' &&
|
row.OnePcsAvailable === 'Y' &&
|
||||||
row.TotalPiece !== undefined &&
|
row.TotalPiece !== undefined &&
|
||||||
row.TotalPiece !== null
|
row.TotalPiece !== null
|
||||||
? row.TotalPiece.toString()
|
? row.TotalPiece.toString()
|
||||||
: 0,
|
: 0,
|
||||||
InwardDetails: [],
|
InwardDetails: [],
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
import { Capacitor } from "@capacitor/core";
|
||||||
|
import { Filesystem, Directory } from "@capacitor/filesystem";
|
||||||
|
import { FileOpener } from "@capacitor-community/file-opener";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download and open a file (Excel, PDF, etc.)
|
||||||
|
* @param {ArrayBuffer | Blob} buffer - File data
|
||||||
|
* @param {string} filename - File name with extension
|
||||||
|
* @param {string} mimeType - File MIME type (example: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)
|
||||||
|
* @param {Function} onSuccess - Optional callback, called with true/false
|
||||||
|
*/
|
||||||
|
export const downloadFile = async (buffer, filename, mimeType, onSuccess) => {
|
||||||
|
try {
|
||||||
|
const isWeb = Capacitor.getPlatform() === "web";
|
||||||
|
|
||||||
|
// 🌐 Web download
|
||||||
|
if (isWeb) {
|
||||||
|
const blob = buffer instanceof Blob ? buffer : new Blob([buffer], { type: mimeType });
|
||||||
|
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = URL.createObjectURL(blob);
|
||||||
|
link.download = filename;
|
||||||
|
link.click();
|
||||||
|
|
||||||
|
URL.revokeObjectURL(link.href);
|
||||||
|
onSuccess?.(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 📱 Mobile (Android / iOS)
|
||||||
|
|
||||||
|
// Convert ArrayBuffer → Base64
|
||||||
|
let binary = "";
|
||||||
|
const bytes = new Uint8Array(buffer);
|
||||||
|
for (let i = 0; i < bytes.length; i++) {
|
||||||
|
binary += String.fromCharCode(bytes[i]);
|
||||||
|
}
|
||||||
|
const base64Data = btoa(binary);
|
||||||
|
|
||||||
|
// Save file inside app's Documents folder
|
||||||
|
|
||||||
|
const savedFile = await Filesystem.writeFile({
|
||||||
|
path: filename,
|
||||||
|
data: base64Data,
|
||||||
|
directory: Directory.Data, // ← was Directory.Documents
|
||||||
|
recursive: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// FileOpener requires removing "file://"
|
||||||
|
|
||||||
|
await FileOpener.open({
|
||||||
|
filePath: savedFile.uri, // ← was savedFile.uri.replace("file://", "")
|
||||||
|
contentType: mimeType,
|
||||||
|
});
|
||||||
|
|
||||||
|
onSuccess?.(true);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error("File download/open error:", err);
|
||||||
|
onSuccess?.(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -7,7 +7,7 @@ export default defineConfig(({ mode }) => {
|
||||||
return {
|
return {
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
|
|
||||||
base: isProd ? "/apps/retail/" : "/",
|
base: isProd ? "/apps/retail/" : "/", //for capcitor base: isProd ? "/" : "/",
|
||||||
|
|
||||||
envDir: "src",
|
envDir: "src",
|
||||||
envPrefix: "ENV_",
|
envPrefix: "ENV_",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue