Merge pull request 'product-receipt' (#148) from product-receipt into main
Reviewed-on: Pozomind/pozo-retail-app#148
This commit is contained in:
commit
6f7e2f6cdd
|
|
@ -79,17 +79,23 @@ export const getRePrintReason = createAsyncThunk(
|
|||
export const ReprintDetails = createAsyncThunk(
|
||||
"addCustomer/ReprintDetails",
|
||||
async (data) => {
|
||||
const { AppId, CompId, BranchId, OrderFromDate, OrderToDate, OrderId } = data || {};
|
||||
const { AppId, CompId, BranchId, OrderFromDate, OrderToDate, OrderId,PageNumber } = data || {};
|
||||
if (OrderId && !OrderFromDate && !OrderToDate) {
|
||||
return await axiosRetailInstanceData.get(
|
||||
`/reprint?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&OrderId=${OrderId}&pageNumber=${data.PageNumber}&Type=${data.Type}`
|
||||
);
|
||||
}
|
||||
if (OrderFromDate && OrderToDate) {
|
||||
if (OrderFromDate && OrderToDate && PageNumber) {
|
||||
return await axiosRetailInstanceData.get(
|
||||
`/reprint?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&orderFromDate=${OrderFromDate}&orderToDate=${OrderToDate} &pageNumber=${data.PageNumber}&Type=${data.Type}`
|
||||
);
|
||||
} else {
|
||||
}
|
||||
else if(OrderFromDate && OrderToDate ) {
|
||||
return await axiosRetailInstanceData.get(
|
||||
`/reprint?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&orderFromDate=${OrderFromDate}&orderToDate=${OrderToDate}&Type=${data.Type}`
|
||||
);
|
||||
}
|
||||
else {
|
||||
return await axiosRetailInstanceData.get(
|
||||
`/reprint?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&pageNumber=${data.PageNumber}&Type=${data.Type}`
|
||||
);
|
||||
|
|
|
|||
|
|
@ -105,11 +105,12 @@ export const postBulkConfiguration = createAsyncThunk(
|
|||
export const SelfBookingEmailSendLink = createAsyncThunk(
|
||||
'email/sendEmailLink',
|
||||
async (EmailData) => {
|
||||
const { toEmail, type, fileUrl} = EmailData;
|
||||
const { toEmail, type, fileUrl,HeaderType} = EmailData;
|
||||
const data = {
|
||||
toEmail:toEmail,
|
||||
Type: type,
|
||||
fileUrl:fileUrl,
|
||||
HeaderType:HeaderType
|
||||
};
|
||||
return await axiosEmail_SMSData.post('/SendUrlEmail', data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { PublicQrCodepost } from '../../../../Features/ConfigMasterPage/ConfigMa
|
|||
import { renderToStaticMarkup } from 'react-dom/server';
|
||||
|
||||
const MainHomeUrl = import.meta.env.ENV_MAIN_BASE_URL;
|
||||
const uploadApiUrl = import.meta.env.ENV_IMAGE_UPLOAD_API_URL;
|
||||
|
||||
// Create a secure blob URL creator that works in all environments
|
||||
const createSecureBlobUrl = (blob) => {
|
||||
|
|
@ -60,10 +61,10 @@ export const MobileMultiPdfPrint = async ({
|
|||
dispatch,
|
||||
UserId = '',
|
||||
onProgress = () => {},
|
||||
returnBlob = false,
|
||||
}) => {
|
||||
try {
|
||||
const style = await PrintStyleFunction(printerTemplateStyle, 'Sales');
|
||||
|
||||
const stylesMap = {
|
||||
'Style 1': 'PrintStyle1',
|
||||
'Style 2': 'PrintStyle2',
|
||||
|
|
@ -170,6 +171,15 @@ export const MobileMultiPdfPrint = async ({
|
|||
revokeSecureBlobUrl(blobUrl);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// Return blob if requested (after download completes)
|
||||
if (returnBlob && PrintComing === 'download') {
|
||||
setPrintOrderDetails([]);
|
||||
if (container) {
|
||||
document.body.removeChild(container);
|
||||
}
|
||||
return { success: true, pdfBlob: combinedPdfBlob };
|
||||
}
|
||||
|
||||
// if (PrintComing === "whatsapp") {
|
||||
// const orderIds = PrintOrderDetails.map((row) => row?.OrderId).filter(Boolean);
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ import { changeOrderOfferDetail } from '../../../../../Features/Offer/Offer.js';
|
|||
import { ChangeFullFreeProductList, changeFullOfferAppliedProducts, changeLoyaltyConsumedQuantities } from '../../../../../Features/Offer/Offernew/BookingOffernew.js';
|
||||
import { ChangeTotalAmount } from '../../../../../Features/ExteraCharges/ExtraCharges.js';
|
||||
import { Radio } from 'antd';
|
||||
import ReprintPDFDataShare from './ReprintPDFDataShare.jsx';
|
||||
import { ImShare } from 'react-icons/im';
|
||||
|
||||
const RetailApiurl = import.meta.env.ENV_API_URL;
|
||||
|
||||
|
|
@ -116,7 +118,6 @@ function BSReprint({ setOpenModel = () => { } }) {
|
|||
const [bulkMode, setBulkMode] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [reprintData, setReprintData] = useState([]);
|
||||
console.log(reprintData, 'reprintData');
|
||||
const [reprintReasonList, setReprintReasonList] = useState([]);
|
||||
const [isDuplicate, setIsDuplicate] = useState('Original');
|
||||
const [BillSearch, setBillSearch] = useState('');
|
||||
|
|
@ -138,7 +139,7 @@ function BSReprint({ setOpenModel = () => { } }) {
|
|||
SettingDataSelector?.[0]?.['SettingDtlDetails']?.find(
|
||||
(item) => item.SettingIdName === 'Estimation'
|
||||
)?.SettingValue === 'Y';
|
||||
console.log(preferenceEstimate, 'preferenceEstimate');
|
||||
console.log(preferenceEstimate, 'preferenceEstimate');
|
||||
const editBill = SettingDataSelector?.[0]?.SettingDtlDetails?.find(
|
||||
(setting) =>
|
||||
setting?.SettingIdName?.toLowerCase() === 'editbill' &&
|
||||
|
|
@ -167,9 +168,10 @@ function BSReprint({ setOpenModel = () => { } }) {
|
|||
const SessionMobileNo = getSession('MobileNo');
|
||||
const [dateStrings, setDateStrings] = useState([]);
|
||||
const [type, setType] = useState("Sales");
|
||||
const [showShareModal, setShowShareModal] = useState(false);
|
||||
// ---- 1. Fetch Function ----
|
||||
const fetchData = async ({ queryKey }) => {
|
||||
const [_, dates, page,type] = queryKey;
|
||||
const [_, dates, page, type] = queryKey;
|
||||
const Response = await dispatch(
|
||||
ReprintDetails({
|
||||
CompId,
|
||||
|
|
@ -178,7 +180,7 @@ function BSReprint({ setOpenModel = () => { } }) {
|
|||
OrderFromDate: dates?.[0] ?? '',
|
||||
OrderToDate: dates?.[1] ?? '',
|
||||
PageNumber: page,
|
||||
Type:type
|
||||
Type: type
|
||||
})
|
||||
).unwrap();
|
||||
if (Response?.data?.statusCode === 1) {
|
||||
|
|
@ -189,7 +191,7 @@ function BSReprint({ setOpenModel = () => { } }) {
|
|||
};
|
||||
|
||||
const { data, isLoading, error } = useQuery({
|
||||
queryKey: ['reprint', dateStrings, page,type],
|
||||
queryKey: ['reprint', dateStrings, page, type],
|
||||
queryFn: fetchData,
|
||||
enabled: true,
|
||||
staleTime: 1000 * 60 * 5,
|
||||
|
|
@ -250,7 +252,7 @@ function BSReprint({ setOpenModel = () => { } }) {
|
|||
};
|
||||
commonMasterApiCall();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
useEffect(() => {
|
||||
DefaultReprintReason();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
|
|
@ -263,7 +265,7 @@ function BSReprint({ setOpenModel = () => { } }) {
|
|||
dispatch(getPrinterMappingDetails(data)).unwrap();
|
||||
const Data1 = { AppId, CompId, BranchId };
|
||||
dispatch(getPrintSelectionComponentData(Data1)).unwrap();
|
||||
|
||||
|
||||
}, []);
|
||||
|
||||
const handleDateChange = (dates, dateStrings) => {
|
||||
|
|
@ -1193,7 +1195,6 @@ function BSReprint({ setOpenModel = () => { } }) {
|
|||
const mutiplePrint = async (printType) => {
|
||||
setIsProcessing(true);
|
||||
setProcessingProgress(0);
|
||||
|
||||
const result = await MobileMultiPdfPrint({
|
||||
printerTemplateStyle,
|
||||
printDatas,
|
||||
|
|
@ -1280,7 +1281,7 @@ function BSReprint({ setOpenModel = () => { } }) {
|
|||
OverallDisc,
|
||||
OrderPaymentDtl,
|
||||
} = orderDtls;
|
||||
|
||||
|
||||
const updated = productDetails?.map((item) => ({
|
||||
...item,
|
||||
Offer: item?.OfferAmt,
|
||||
|
|
@ -1406,7 +1407,7 @@ function BSReprint({ setOpenModel = () => { } }) {
|
|||
}
|
||||
}
|
||||
|
||||
const typeOptions = [
|
||||
const typeOptions = [
|
||||
{ label: "Sales", value: "Sales" },
|
||||
{ label: "Estimate", value: "Est" },
|
||||
];
|
||||
|
|
@ -1490,7 +1491,9 @@ function BSReprint({ setOpenModel = () => { } }) {
|
|||
Reprintformdata();
|
||||
}}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<ImShare fontSize={22} onClick={() => setShowShareModal(true)} style={{ cursor: 'pointer' }} />
|
||||
</div>
|
||||
<div>
|
||||
{selectedRows.length > 0 && (
|
||||
<div className="action-icons-reprint">
|
||||
|
|
@ -1503,6 +1506,9 @@ function BSReprint({ setOpenModel = () => { } }) {
|
|||
onClick={() => mutiplePrint('whatsapp')}
|
||||
className="icon-whatsapp"
|
||||
/>
|
||||
{/* <ReprintPDFDataShare
|
||||
printData={selectedRows}
|
||||
/> */}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -1848,6 +1854,14 @@ function BSReprint({ setOpenModel = () => { } }) {
|
|||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{ showShareModal && <ReprintPDFDataShare
|
||||
printerTemplateStyle={printerTemplateStyle}
|
||||
printDatas={printDatas}
|
||||
SettingDataSelector={SettingDataSelector}
|
||||
open={showShareModal}
|
||||
onClose={() => setShowShareModal(false)}
|
||||
/>}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,281 @@
|
|||
import { FaDownload, FaWhatsapp } from "react-icons/fa";
|
||||
import { extractLastNumberOrderId, getSession } from "../../../../../Services/Others";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useCallback, useState } from "react";
|
||||
import { DatePicker, Modal } from "antd";
|
||||
import { ReprintDetails } from "../../../../../Features/BookingScreen/Customer/addCustomer";
|
||||
import Buttons from "../../../../../Components/Forms/Buttons";
|
||||
import { MobileMultiPdfPrint, PdfProcessingProgress } from "../../BookingFunctionality/MobileMultiPdfPrint";
|
||||
import PaymentPdfBooking from "../../../../paymentpdfPage/PaymentPdfBooking";
|
||||
import { MdEmail } from "react-icons/md";
|
||||
import { uploadImage } from "../../../../../Features/upload/upload";
|
||||
import { SelfBookingEmailSendLink } from "../../../../../Features/ConfigMasterPage/ConfigMasterPage";
|
||||
import { Messages } from "../../../../../Components/Notifications/Messages";
|
||||
const { RangePicker } = DatePicker;
|
||||
const uploadApiUrl = import.meta.env.ENV_IMAGE_UPLOAD_API_URL;
|
||||
|
||||
const ReprintPDFDataShare = ({ printDatas, printerTemplateStyle, SettingDataSelector, open = false, onClose = () => { } }) => {
|
||||
const dispatch = useDispatch();
|
||||
const CompId = getSession('CompId');
|
||||
const BranchId = getSession('BranchId');
|
||||
const AppId = getSession('AppId');
|
||||
const UserId = getSession('UserId');
|
||||
|
||||
const [dateStrings, setDateStrings] = useState([]);
|
||||
const [type, setType] = useState("Sales");
|
||||
const [reprintData, setReprintData] = useState();
|
||||
const [isProcessing, setIsProcessing] = useState(false);
|
||||
const [processingProgress, setProcessingProgress] = useState(0);
|
||||
const [isDuplicate, setIsDuplicate] = useState('Original');
|
||||
const [emailId, setEmailId] = useState('');
|
||||
const [isEmail, setIsEmail] = useState(false);
|
||||
const [pdfUrl, setPdfUrl] = useState(false);
|
||||
const [messageType, setMessageType] = useState(null);
|
||||
const [messageData, setMessageData] = useState(null);
|
||||
const [isFetching, setIsFetching] = useState(false);
|
||||
|
||||
const handleDateChange = (dateStrings) => {
|
||||
if (dateStrings[0] && dateStrings[1]) {
|
||||
setDateStrings(dateStrings);
|
||||
fetchData(dateStrings);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchData = async (dates = dateStrings) => {
|
||||
setIsFetching(true);
|
||||
try {
|
||||
const Response = await dispatch(ReprintDetails({
|
||||
CompId,
|
||||
BranchId,
|
||||
AppId,
|
||||
OrderFromDate: dates?.[0] ?? '',
|
||||
OrderToDate: dates?.[1] ?? '',
|
||||
Type: type
|
||||
})).unwrap();
|
||||
if (Response?.data?.statusCode === 1) {
|
||||
setReprintData(Response?.data?.data);
|
||||
} else {
|
||||
setReprintData(null);
|
||||
}
|
||||
} finally {
|
||||
setIsFetching(false);
|
||||
}
|
||||
};
|
||||
|
||||
const pdfPast = async () => {
|
||||
if (printerTemplateStyle !== "TaxInvoice") {
|
||||
setMessageType("error");
|
||||
setMessageData("Please select invoice print style");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reprintData || reprintData.length === 0) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
setIsProcessing(true);
|
||||
setProcessingProgress(0);
|
||||
const result = await MobileMultiPdfPrint({
|
||||
printerTemplateStyle,
|
||||
printDatas,
|
||||
PrintOrderDetails: reprintData,
|
||||
setPrintOrderDetails: setReprintData,
|
||||
PrintComing: 'download',
|
||||
UserId: UserId,
|
||||
dispatch,
|
||||
onProgress: (progress) => setProcessingProgress(progress),
|
||||
returnBlob: true
|
||||
});
|
||||
|
||||
if (result?.pdfBlob) {
|
||||
const file = new File([result.pdfBlob], 'invoices.pdf', { type: 'application/pdf' });
|
||||
const uploadImgData = await dispatch(uploadImage(file)).unwrap();
|
||||
if (uploadImgData?.data?.status) {
|
||||
const imageUrl = uploadImgData?.data?.image;
|
||||
const urlObj = new URL(imageUrl);
|
||||
const fileName = urlObj.searchParams.get("fileId");
|
||||
const downloadUrl = `${uploadApiUrl}/upload/DownloadFile?fileId=${fileName}`;
|
||||
setPdfUrl(downloadUrl);
|
||||
} else {
|
||||
setMessageType("error");
|
||||
setMessageData("Failed to upload PDF");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
setMessageType("error");
|
||||
setMessageData("Error processing PDF");
|
||||
} finally {
|
||||
setIsProcessing(false);
|
||||
}
|
||||
};
|
||||
const handleDownload = () => {
|
||||
if (pdfUrl) {
|
||||
window.open(pdfUrl, '_blank');
|
||||
}
|
||||
};
|
||||
const SendToEmailLink = async () => {
|
||||
if (!emailId) {
|
||||
setMessageType("error");
|
||||
setMessageData("Please enter a recipient email.");
|
||||
return;
|
||||
}
|
||||
const data = {
|
||||
toEmail: emailId,
|
||||
type: 'M',
|
||||
HeaderType:'invoice attached',
|
||||
fileUrl: pdfUrl,
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await dispatch(SelfBookingEmailSendLink(data)).unwrap();
|
||||
setMessageType("success");
|
||||
setMessageData(res.data?.response);
|
||||
clearAndClose();
|
||||
} catch (err) {
|
||||
console.error("Error sending Email:", err);
|
||||
setMessageType("error");
|
||||
setMessageData("Failed to send email. Please try again.");
|
||||
}
|
||||
};
|
||||
|
||||
const handleWhatsAppClick = () => {
|
||||
window.open(whatsappShareUrl, '_blank');
|
||||
clearAndClose();
|
||||
};
|
||||
|
||||
const clearAndClose = () => {
|
||||
setDateStrings([]);
|
||||
setReprintData(null);
|
||||
setPdfUrl(false);
|
||||
setEmailId('');
|
||||
setIsEmail(false);
|
||||
onClose();
|
||||
setDateStrings([]);
|
||||
};
|
||||
const message = `
|
||||
Please find your complete bill invoice attached in the link below:
|
||||
${pdfUrl}
|
||||
|
||||
Kindly review the details and keep this invoice for your records.
|
||||
|
||||
Thank you for choosing us!`;
|
||||
|
||||
const whatsappShareUrl = `https://wa.me/?text=${encodeURIComponent(message)}`;
|
||||
|
||||
const onComplete = useCallback(() => {
|
||||
setMessageData(null);
|
||||
setMessageType(null);
|
||||
}, []);
|
||||
return (
|
||||
<div>
|
||||
<Messages
|
||||
messageType={messageType}
|
||||
messageData={messageData}
|
||||
onComplete={onComplete}
|
||||
/>
|
||||
<Modal
|
||||
title="Invoice Send"
|
||||
open={open}
|
||||
onCancel={onClose}
|
||||
footer={null}
|
||||
>
|
||||
<>
|
||||
<div style={{ display: 'flex', gap: '1rem', alignItems: "center" }}>
|
||||
<div>
|
||||
<RangePicker
|
||||
placeholder={['Start Date', 'End Date']}
|
||||
format="YYYY-MM-DD"
|
||||
onChange={handleDateChange}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Buttons
|
||||
buttonText="Invoice Pdf"
|
||||
color="901D77"
|
||||
handleSubmit={pdfPast}
|
||||
disabled={!reprintData || reprintData.length === 0 || isFetching}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{isEmail && <div style={{ display: 'flex', gap: '1rem', alignItems: "center", marginTop: '1rem' }}>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Enter email address"
|
||||
value={emailId}
|
||||
onChange={(e) => setEmailId(e.target.value)}
|
||||
style={{ flex: 1, padding: '8px', borderRadius: '4px', border: '1px solid #d9d9d9' }}
|
||||
/>
|
||||
<Buttons
|
||||
buttonText="Send Email"
|
||||
color="901D77"
|
||||
handleSubmit={() => SendToEmailLink()}
|
||||
/>
|
||||
|
||||
</div>}
|
||||
{pdfUrl && (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: '10px',
|
||||
margin: '20px 0px'
|
||||
}}
|
||||
>
|
||||
<div className="action-icons-reprint">
|
||||
<FaDownload
|
||||
onClick={handleDownload}
|
||||
className="icon-download"
|
||||
style={{ cursor: 'pointer' }}
|
||||
/>
|
||||
<MdEmail onClick={() => setIsEmail(prev => !prev)} className="icon-email" style={{ cursor: 'pointer' }} />
|
||||
<FaWhatsapp
|
||||
onClick={handleWhatsAppClick}
|
||||
className="icon-whatsapp"
|
||||
style={{ cursor: 'pointer' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
<PdfProcessingProgress
|
||||
progress={processingProgress}
|
||||
isProcessing={isProcessing}
|
||||
/>
|
||||
</>
|
||||
</Modal>
|
||||
|
||||
<div style={{ display: 'none' }}>
|
||||
{reprintData?.map((orderDetail, index) => (
|
||||
<div key={index} id={`RePrint-${index}`}>
|
||||
<PaymentPdfBooking
|
||||
index={index}
|
||||
table2Data={orderDetail}
|
||||
singleData2={orderDetail?.productDetails}
|
||||
ReprintType={isDuplicate}
|
||||
orderId={
|
||||
orderDetail?.OrderId &&
|
||||
extractLastNumberOrderId(
|
||||
orderDetail?.OrderId,
|
||||
orderDetail?.FYStatus
|
||||
)
|
||||
}
|
||||
CreatedDate={orderDetail?.CreatedDate}
|
||||
PaymentStatus={orderDetail?.OrderPaymentDtl}
|
||||
Preference={SettingDataSelector}
|
||||
printDatas={printDatas}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
export default ReprintPDFDataShare;
|
||||
Loading…
Reference in New Issue