2026-01-27 18:27:29 +05:30
|
|
|
import React, { useMemo } from "react";
|
|
|
|
|
import { useSelector } from "react-redux";
|
2026-03-05 12:12:46 +05:30
|
|
|
import { GloabalDCtoInvoiceFieldDetails, GloabalFieldDetails } from "../../../Features/ThemeChange/ThemeChange";
|
2026-01-27 18:27:29 +05:30
|
|
|
import { dateFormatChange1 } from "../../../Services/Others";
|
|
|
|
|
|
|
|
|
|
const PrintStyleDCToInvoiceA4Standard = ({ invoiceData, preference, printDatas }) => {
|
|
|
|
|
const {
|
|
|
|
|
InvoiceNo,
|
|
|
|
|
DCNo,
|
|
|
|
|
InvoiceDate,
|
|
|
|
|
CustMobile,
|
|
|
|
|
GrandTotal,
|
|
|
|
|
TaxAmount,
|
|
|
|
|
TotalAmount,
|
|
|
|
|
ProductDetails,
|
|
|
|
|
AddressDetails,
|
|
|
|
|
CustName,
|
|
|
|
|
VehicleNo
|
|
|
|
|
} = invoiceData;
|
|
|
|
|
console.log(invoiceData, "invoiceData")
|
|
|
|
|
|
2026-03-05 12:12:46 +05:30
|
|
|
const fieldDetails = useSelector(GloabalDCtoInvoiceFieldDetails);
|
2026-01-27 18:27:29 +05:30
|
|
|
const signature = fieldDetails?.["signature"];
|
|
|
|
|
const termsAndConditions = fieldDetails?.["terms&conditions"];
|
|
|
|
|
const termsAndConditionsData = printDatas?.TermsandConditions;
|
|
|
|
|
const signatureImg = printDatas?.Signature;
|
|
|
|
|
const notesText = printDatas?.Notes;
|
|
|
|
|
const formatTheme = printDatas?.PrintType === "S";
|
|
|
|
|
const pageSize = printDatas?.PageSize;
|
|
|
|
|
const branch = AddressDetails[0];
|
|
|
|
|
const bankDetails = branch?.BankDetails;
|
|
|
|
|
console.log(branch, "branchbranch")
|
|
|
|
|
const logo = branch?.CompLogo;
|
|
|
|
|
|
|
|
|
|
const printGreeting = preference?.[0]?.SettingDtlDetails?.find(
|
|
|
|
|
(i) => i.SettingIdName === 'PrintGreetings'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const chunkSize = pageSize === "A5" ? 8 : 11;
|
|
|
|
|
|
|
|
|
|
const paginatedChunks = useMemo(() => {
|
|
|
|
|
const chunks = [];
|
|
|
|
|
for (let i = 0; i < ProductDetails.length; i += chunkSize) {
|
|
|
|
|
chunks.push(ProductDetails.slice(i, i + chunkSize));
|
|
|
|
|
}
|
|
|
|
|
return chunks;
|
|
|
|
|
}, [ProductDetails, chunkSize]);
|
|
|
|
|
|
|
|
|
|
const lastChunkRows = paginatedChunks.at(-1)?.length || 0;
|
|
|
|
|
const shouldFooterBeOnNewPage = lastChunkRows > (pageSize === "A5" ? 5 : 10);
|
2026-03-05 12:12:46 +05:30
|
|
|
let printColors = printDatas?.PrintColors;
|
|
|
|
|
const headerColor = printColors?.find(obj => obj.headerColor)?.headerColor;
|
|
|
|
|
const tableHeaderColor = printColors?.find(obj => obj.tableHeaderColor)?.tableHeaderColor;
|
|
|
|
|
const tableBodyColor = printColors?.find(obj => obj.tableBodyColor)?.tableBodyColor;
|
|
|
|
|
const footerColor = printColors?.find(obj => obj.footerColor)?.footerColor;
|
|
|
|
|
const netAmtColor = printColors?.find(obj => obj.netAmtColor)?.netAmtColor;
|
|
|
|
|
const headerStyle = {
|
|
|
|
|
backgroundColor: headerColor?.background,
|
|
|
|
|
color: headerColor?.font,
|
|
|
|
|
}
|
|
|
|
|
const tableHeaderStyle = {
|
|
|
|
|
backgroundColor: tableHeaderColor?.background,
|
|
|
|
|
color: tableHeaderColor?.font,
|
|
|
|
|
}
|
|
|
|
|
const tableBodyStyle = {
|
|
|
|
|
backgroundColor: tableBodyColor?.background,
|
|
|
|
|
color: tableBodyColor?.font,
|
|
|
|
|
}
|
|
|
|
|
const rowtypeStyle = tableBodyColor?.rowType;
|
|
|
|
|
const footerColorStyle = {
|
|
|
|
|
backgroundColor: footerColor?.background,
|
|
|
|
|
color: footerColor?.font,
|
|
|
|
|
}
|
|
|
|
|
const netAmountStyle = {
|
|
|
|
|
backgroundColor: netAmtColor?.background,
|
|
|
|
|
color: netAmtColor?.font,
|
|
|
|
|
}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
const getPageStyle = (isFinalFooterPage) => ({
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexDirection: "column",
|
|
|
|
|
justifyContent: isFinalFooterPage ? "space-between" : "",
|
|
|
|
|
height: pageSize === "A5" ? "170mm" : "95vh",
|
|
|
|
|
maxHeight: "97vh"
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const HeaderSection = () => (
|
|
|
|
|
<>
|
|
|
|
|
<Header logo={logo} branch={branch} />
|
|
|
|
|
<InvoiceMeta
|
|
|
|
|
InvoiceNo={InvoiceNo}
|
|
|
|
|
DCNo={DCNo}
|
|
|
|
|
InvoiceDate={InvoiceDate}
|
|
|
|
|
CustMobile={CustMobile}
|
|
|
|
|
CustName={CustName}
|
|
|
|
|
VehicleNo={VehicleNo}
|
2026-03-05 12:12:46 +05:30
|
|
|
headerStyle={headerStyle}
|
2026-01-27 18:27:29 +05:30
|
|
|
/>
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const renderFooter = () => (
|
|
|
|
|
<>
|
|
|
|
|
{(termsAndConditions || signature || bankDetails?.length > 0) && (<div className="termsAndSignatureAndBankDetails">
|
|
|
|
|
<div className="bankDetailsAndTerms">
|
|
|
|
|
{(bankDetails?.length > 0) && <div className="bank-details-container">
|
|
|
|
|
<h4 className="bank-details-title">Bank Details:</h4>
|
|
|
|
|
<div className="bank-details">
|
|
|
|
|
<div className="bank-detail-item"><strong>Bank Name:</strong> {bankDetails?.[0]?.BankName}</div>
|
|
|
|
|
<div className="bank-detail-item"><strong>Account No.:</strong> {bankDetails?.[0]?.AccountNo}</div>
|
|
|
|
|
<div className="bank-detail-item"><strong>IFSC Code:</strong> {bankDetails?.[0]?.IFSCCode}</div>
|
|
|
|
|
<div className="bank-detail-item"><strong>Branch Name:</strong> {bankDetails?.[0]?.BankBranch}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<hr />
|
|
|
|
|
</div>}
|
|
|
|
|
{termsAndConditions && termsAndConditionsData?.length > 0 && (
|
2026-03-05 12:12:46 +05:30
|
|
|
<div className="termsAndConditions" style={{...footerColorStyle}}>
|
2026-01-27 18:27:29 +05:30
|
|
|
<p className="termsAndConditionsHead">Terms & Conditions</p>
|
|
|
|
|
<ol className="termsAndConditionsList">
|
|
|
|
|
{termsAndConditionsData.map((item, idx) => (
|
|
|
|
|
<li key={idx}>{item?.TermsandConditions}</li>
|
|
|
|
|
))}
|
|
|
|
|
</ol>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
{signature && (<div className="signature-container">
|
|
|
|
|
<div>Certified that the particulars given above are true and correct.</div>
|
|
|
|
|
<div className="signature">
|
|
|
|
|
<p>Authorised Signatory</p>
|
|
|
|
|
<img src={signatureImg} alt="Authorized Signature" />
|
|
|
|
|
<p>(Common Seal)</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>)}
|
|
|
|
|
</div>)}
|
|
|
|
|
{(notesText || printGreeting?.SettingValue === "Y") && (
|
|
|
|
|
<>
|
|
|
|
|
{notesText && <p className="notesText text-center">{notesText}</p>}
|
|
|
|
|
{printGreeting?.SettingValue === "Y" && (
|
|
|
|
|
<div className="printGreeting">Thank You Visit Again</div>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
{formatTheme ? (
|
|
|
|
|
paginatedChunks.map((dataChunk, chunkIndex) => {
|
|
|
|
|
const isLastPage = chunkIndex === paginatedChunks.length - 1;
|
|
|
|
|
const isFinalFooterPage = isLastPage && !shouldFooterBeOnNewPage;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
key={chunkIndex}
|
|
|
|
|
className={`container print-chunk${chunkIndex > 0 ? ' print-page-break' : ''}`}
|
|
|
|
|
style={getPageStyle(isFinalFooterPage)}
|
|
|
|
|
>
|
|
|
|
|
<div>
|
|
|
|
|
{(chunkIndex === 0 || formatTheme) && <HeaderSection />}
|
2026-03-05 12:12:46 +05:30
|
|
|
<ProductTable data={dataChunk} tableHeaderStyle={tableHeaderStyle} tableBodyStyle={tableBodyStyle}rowtypeStyle={rowtypeStyle}/>
|
|
|
|
|
{isLastPage && <Summary bankDetails={bankDetails} TotalAmount={TotalAmount} TaxAmount={TaxAmount} GrandTotal={GrandTotal} netAmountStyle={netAmountStyle}/>}
|
2026-01-27 18:27:29 +05:30
|
|
|
{!formatTheme && isFinalFooterPage && renderFooter()}
|
|
|
|
|
</div>
|
|
|
|
|
{formatTheme && isFinalFooterPage && <div>{renderFooter()}</div>}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
) : (
|
|
|
|
|
<div className="container">
|
|
|
|
|
<HeaderSection />
|
2026-03-05 12:12:46 +05:30
|
|
|
<ProductTable data={ProductDetails} tableHeaderStyle={tableHeaderStyle} tableBodyStyle={tableBodyStyle}rowtypeStyle={rowtypeStyle}/>
|
|
|
|
|
<Summary bankDetails={bankDetails} TotalAmount={TotalAmount} TaxAmount={TaxAmount} GrandTotal={GrandTotal} netAmountStyle={netAmountStyle}/>
|
2026-01-27 18:27:29 +05:30
|
|
|
{renderFooter()}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default PrintStyleDCToInvoiceA4Standard;
|
|
|
|
|
|
|
|
|
|
// -------------------- COMPONENTS --------------------
|
|
|
|
|
|
2026-03-05 12:12:46 +05:30
|
|
|
const Header = ({ logo, branch,headerStyle }) => (
|
2026-01-27 18:27:29 +05:30
|
|
|
<>
|
2026-03-05 12:12:46 +05:30
|
|
|
<div className="header" style={{...headerStyle}}>
|
2026-01-27 18:27:29 +05:30
|
|
|
{/* {logo && <img src={logo} alt={`${branch?.CompName} Logo`} className="logo" />} */}
|
|
|
|
|
<div className="headerText">
|
|
|
|
|
<div className="companyName">{branch.CompName}</div>
|
|
|
|
|
<div>{branch.Address1}-{branch.City}-{branch?.Zip}</div>
|
|
|
|
|
<div><strong>Phone:</strong> {branch.BrMobile}</div>
|
|
|
|
|
{branch?.BrEmail && <div><strong>Email:</strong> {branch.BrEmail}</div>}
|
|
|
|
|
{branch?.BrGSTIN && <div><strong>GSTIN:</strong> {branch.BrGSTIN}</div>}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<hr />
|
|
|
|
|
<div className="text-center"><strong>SALES INVOICE</strong></div>
|
|
|
|
|
<hr />
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const InvoiceMeta = ({ InvoiceNo, DCNo, InvoiceDate, CustMobile, VehicleNo, CustName }) => (
|
|
|
|
|
|
|
|
|
|
<div className="invoiceMeta">
|
|
|
|
|
<div className="invoice-head">Details of Receiver | Billed to</div>
|
|
|
|
|
<div className="invoiceInfo">
|
|
|
|
|
<div>
|
|
|
|
|
<div className="text-left"><strong>Invoice No:</strong> {InvoiceNo}</div>
|
|
|
|
|
<div className="text-left"><strong>Delivery No:</strong> {DCNo}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<div className="text-right"><strong>Date:</strong> {dateFormatChange1(InvoiceDate)}</div>
|
|
|
|
|
{VehicleNo && <div className="text-right"><strong>Vehicle No:</strong> {VehicleNo}</div>}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="customer-section">
|
|
|
|
|
{CustName && <div className="text-left"><strong>Customer Name:</strong> {CustName}</div>}
|
|
|
|
|
<div className="text-left"><strong>Customer Mobile No:</strong> {CustMobile || '-'}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const InvoiceAmountWords = ({ amount }) => {
|
|
|
|
|
const numberToWords = (num) => {
|
|
|
|
|
const a = [
|
|
|
|
|
"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten",
|
|
|
|
|
"Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen",
|
|
|
|
|
"Eighteen", "Nineteen"
|
|
|
|
|
];
|
|
|
|
|
const b = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"];
|
|
|
|
|
|
|
|
|
|
if (num === 0) return "Zero";
|
|
|
|
|
|
|
|
|
|
if (num < 20) return a[num];
|
|
|
|
|
if (num < 100) return b[Math.floor(num / 10)] + (num % 10 ? " " + a[num % 10] : "");
|
|
|
|
|
if (num < 1000)
|
|
|
|
|
return a[Math.floor(num / 100)] + " Hundred" + (num % 100 ? " and " + numberToWords(num % 100) : "");
|
|
|
|
|
if (num < 100000)
|
|
|
|
|
return numberToWords(Math.floor(num / 1000)) + " Thousand" + (num % 1000 ? " " + numberToWords(num % 1000) : "");
|
|
|
|
|
|
|
|
|
|
return "Number too large";
|
|
|
|
|
};
|
|
|
|
|
return (
|
|
|
|
|
<div className="amount-in-words">
|
|
|
|
|
<p>
|
|
|
|
|
Total Invoice Amount in Words:
|
|
|
|
|
</p>
|
|
|
|
|
<p>
|
|
|
|
|
{numberToWords(amount)}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-05 12:12:46 +05:30
|
|
|
const ProductTable = ({ data ,tableHeaderStyle,tableBodyStyle,rowtypeStyle}) => {
|
2026-01-27 18:27:29 +05:30
|
|
|
const columns = [
|
|
|
|
|
{ label: "S.No", key: "sno", width: "5%" },
|
|
|
|
|
{ label: "Product", key: "ProdName", width: "20%" },
|
|
|
|
|
{ label: "Variant", key: "ProdVariantName", width: "20%" },
|
|
|
|
|
{ label: "Qty", key: "Qty", width: "10%" },
|
|
|
|
|
{ label: "Rate", key: "ProductRate", width: "10%" },
|
|
|
|
|
{ label: "Tax", key: "TaxAmount", width: "10%" },
|
|
|
|
|
{ label: "Total", key: "TotalAmount", width: "15%" }
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<table className="productTable">
|
|
|
|
|
<thead>
|
2026-03-05 12:12:46 +05:30
|
|
|
<tr style={{...tableHeaderStyle}}>
|
2026-01-27 18:27:29 +05:30
|
|
|
{columns.map(col => (
|
|
|
|
|
<th key={col.key} style={{ width: col.width }} scope="col">{col.label}</th>
|
|
|
|
|
))}
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
{data.map((prod, index) => (
|
2026-03-05 12:12:46 +05:30
|
|
|
<tr key={prod.UniqueId}
|
|
|
|
|
style={
|
|
|
|
|
index % 2 !== 1 && rowtypeStyle === "even"
|
|
|
|
|
? {
|
|
|
|
|
...tableBodyStyle
|
|
|
|
|
}
|
|
|
|
|
: index % 2 === 1 && rowtypeStyle === "odd"
|
|
|
|
|
? {
|
|
|
|
|
...tableBodyStyle
|
|
|
|
|
}
|
|
|
|
|
: {}
|
|
|
|
|
}>
|
2026-01-27 18:27:29 +05:30
|
|
|
<td>{index + 1}</td>
|
|
|
|
|
<td>{prod.ProdName}</td>
|
|
|
|
|
<td>{prod.ProdVariantName}</td>
|
|
|
|
|
<td>{prod.Qty}</td>
|
|
|
|
|
<td>{prod.ProductRate}</td>
|
|
|
|
|
<td>{prod.TaxAmount}</td>
|
|
|
|
|
<td>{prod.TotalAmount}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
))}
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-05 12:12:46 +05:30
|
|
|
const Summary = ({ bankDetails, TotalAmount, TaxAmount, GrandTotal ,netAmountStyle}) => (
|
2026-01-27 18:27:29 +05:30
|
|
|
<>
|
2026-03-05 12:12:46 +05:30
|
|
|
<div className="summary" style={{...netAmountStyle}}>
|
2026-01-27 18:27:29 +05:30
|
|
|
<div><strong>Subtotal:</strong> ₹ {TotalAmount.toFixed(2)}</div>
|
|
|
|
|
<div><strong>Tax Amount:</strong> ₹ {TaxAmount.toFixed(2)}</div>
|
|
|
|
|
<div className="bold"><strong>Grand Total:</strong> ₹ {GrandTotal.toFixed(2)}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="summary-grid">
|
|
|
|
|
<div class="summary-left">
|
|
|
|
|
<InvoiceAmountWords amount={TotalAmount} />
|
|
|
|
|
</div>
|
|
|
|
|
<div class="summary-right">
|
|
|
|
|
<div class="amount-item">
|
|
|
|
|
<div class="amount-label">Total Amount Before Tax</div>
|
|
|
|
|
<div class="amount-value"> ₹ {TotalAmount.toFixed(2)}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="additional-info">
|
|
|
|
|
</div>
|
|
|
|
|
<hr />
|
|
|
|
|
<div class="summary-item-bold">
|
|
|
|
|
<span>Total Amount After Tax</span>
|
|
|
|
|
<span> ₹ {(TotalAmount + TaxAmount).toFixed(2)}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="total-amount"> ₹ {(TotalAmount + TaxAmount).toFixed(2)}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
);
|