Files
romfast-website/efactura-generator/js/print.js
2025-08-13 22:47:45 +03:00

251 lines
11 KiB
JavaScript

import { InvoiceFormatter } from './formatter.js';
export class InvoicePrintHandler {
constructor() {
this.printWindow = null;
this.formatter = new InvoiceFormatter();
this.templates = {
standard: './templates/print.html',
compact: './templates/print-compact.html'
};
this.currentTemplate = 'standard';
}
setTemplate(templateName) {
if (this.templates[templateName]) {
this.currentTemplate = templateName;
}
}
collectInvoiceData() {
return {
// Basic details
invoiceNumber: document.querySelector('[name="invoiceNumber"]').value,
issueDate: document.querySelector('[name="issueDate"]').value,
dueDate: document.querySelector('[name="dueDate"]').value,
documentCurrencyCode: document.querySelector('[name="documentCurrencyCode"]').value.toUpperCase() || 'RON',
taxCurrencyCode: document.querySelector('[name="taxCurrencyCode"]').value.toUpperCase(),
exchangeRate: parseFloat(document.querySelector('[name="exchangeRate"]')?.value || 1),
// Supplier details
supplier: {
name: document.querySelector('[name="supplierName"]').value,
vat: document.querySelector('[name="supplierVAT"]').value,
companyId: document.querySelector('[name="supplierCompanyId"]').value,
address: document.querySelector('[name="supplierAddress"]').value,
city: document.querySelector('[name="supplierCity"]').value,
county: document.querySelector('[name="supplierCountrySubentity"]').value,
country: document.querySelector('[name="supplierCountry"]').value,
phone: document.querySelector('[name="supplierPhone"]').value,
contactName: document.querySelector('[name="supplierContactName"]').value,
email: document.querySelector('[name="supplierEmail"]').value
},
// Customer details
customer: {
name: document.querySelector('[name="customerName"]').value,
vat: document.querySelector('[name="customerVAT"]').value,
companyId: document.querySelector('[name="customerCompanyId"]').value,
address: document.querySelector('[name="customerAddress"]').value,
city: document.querySelector('[name="customerCity"]').value,
county: document.querySelector('[name="customerCountrySubentity"]').value,
country: document.querySelector('[name="customerCountry"]').value,
phone: document.querySelector('[name="customerPhone"]').value,
contactName: document.querySelector('[name="customerContactName"]').value,
email: document.querySelector('[name="customerEmail"]').value
},
// Line items with formatted values
items: Array.from(document.querySelectorAll('.line-item')).map((item, index) => ({
number: index + 1,
description: item.querySelector('[name^="description"]').value,
quantity: this.formatter.formatQuantity(item.querySelector('[name^="quantity"]').value),
unit: item.querySelector('[name^="unit"]').value,
price: this.formatter.formatCurrency(item.querySelector('[name^="price"]').value),
vatRate: this.formatter.formatCurrency(item.querySelector('[name^="vatRate"]').value),
totalAmount: this.formatter.formatCurrency(
this.formatter.parseQuantity(item.querySelector('[name^="quantity"]').value) *
this.formatter.parseCurrency(item.querySelector('[name^="price"]').value)
)
})),
// Note
note: document.querySelector('[name="invoiceNote"]')?.value,
// Get totals directly from the display elements
totals: {
subtotal: document.getElementById('subtotal').textContent,
allowances: document.getElementById('totalAllowances').textContent,
charges: document.getElementById('totalCharges').textContent,
netAmount: document.getElementById('netAmount').textContent,
vat: document.getElementById('vat').textContent,
total: document.getElementById('total').textContent
},
// VAT Breakdown
vatBreakdown: Array.from(document.querySelectorAll('.vat-row')).map(row => ({
type: row.querySelector('.vat-type').value,
rate: row.querySelector('.vat-rate').value,
base: row.querySelector('.vat-base').value,
amount: row.querySelector('.vat-amount').value
}))
};
}
createPartyHTML(party) {
return `
<p><strong>${party.name}</strong></p>
<p>CUI: ${party.vat}</p>
<p>Nr. Reg. Com.: ${party.companyId}</p>
<p>${party.address}</p>
<p>${party.city}${party.county ? ', ' + party.county : ''}</p>
<p>${party.country}</p>
${party.phone ? `<p>Tel: ${party.phone}</p>` : ''}
${party.contactName ? `<p>Contact: ${party.contactName}</p>` : ''}
${party.email ? `<p>Email: ${party.email}</p>` : ''}
`;
}
getVATTypeLabel(type) {
const labels = {
'S': 'Standard',
'AE': 'Taxare Inversă',
'O': 'Neplătitor TVA',
'Z': 'Cotă 0%',
'E': 'Scutit'
};
return labels[type] || type;
}
async print() {
try {
// Collect all the data
const invoiceData = this.collectInvoiceData();
// Open new window and load the selected print template
this.printWindow = window.open(
this.templates[this.currentTemplate],
'_blank',
'width=800,height=600'
);
// Wait for the window to load
await new Promise(resolve => {
this.printWindow.onload = resolve;
});
// Generate QR code
const qrData = {
invoiceNumber: invoiceData.invoiceNumber,
issueDate: invoiceData.issueDate,
supplier: invoiceData.supplier.name,
customer: invoiceData.customer.name,
total: this.formatter.parseCurrency(invoiceData.totals.total)
};
const qrElement = this.printWindow.document.getElementById('qrcode');
if (qrElement) {
new this.printWindow.QRCode(qrElement, {
text: JSON.stringify(qrData),
width: 100,
height: 100,
colorDark: "#2563eb",
colorLight: "#ffffff",
correctLevel: this.printWindow.QRCode.CorrectLevel.L
});
}
// Populate the template with data
this.populatePrintWindow(invoiceData);
// Print the window
this.printWindow.print();
// Clean up
this.printWindow.onafterprint = () => {
this.printWindow.close();
this.printWindow = null;
};
} catch (error) {
console.error('Print failed:', error);
if (this.printWindow) {
this.printWindow.close();
this.printWindow = null;
}
alert('A apărut o eroare la printare. Vă rugăm să încercați din nou.');
}
}
populatePrintWindow(data) {
if (!this.printWindow) return;
const doc = this.printWindow.document;
// Basic details
doc.getElementById('print-invoice-number').textContent = data.invoiceNumber;
doc.getElementById('print-issue-date').textContent = data.issueDate;
doc.getElementById('print-due-date').textContent = data.dueDate;
doc.getElementById('print-document-currency').textContent = data.documentCurrencyCode;
// Currency information
const taxCurrencyContainer = doc.getElementById('print-tax-currency-container');
if (data.taxCurrencyCode && data.taxCurrencyCode !== data.documentCurrencyCode) {
taxCurrencyContainer.style.display = 'block';
doc.getElementById('print-tax-currency').textContent = data.taxCurrencyCode;
doc.getElementById('print-exchange-rate').textContent = this.formatter.formatNumber(data.exchangeRate);
}
// Party details
doc.getElementById('print-supplier-details').innerHTML = this.createPartyHTML(data.supplier);
doc.getElementById('print-customer-details').innerHTML = this.createPartyHTML(data.customer);
// Note
if (data.note) {
const noteSection = doc.getElementById('print-note');
noteSection.style.display = 'block';
noteSection.querySelector('div').textContent = data.note;
}
// Line items - use formatted values from data
doc.getElementById('print-items').innerHTML = data.items.map(item => `
<tr>
<td>${item.number}</td>
<td>${item.description}</td>
<td>${item.unit}</td>
<td class="number-cell">${item.quantity}</td>
<td class="number-cell">${item.price}</td>
<td class="number-cell">${item.vatRate}%</td>
<td class="number-cell">${item.totalAmount}</td>
</tr>
`).join('');
// Totals - use values directly from display
doc.getElementById('print-subtotal').textContent = data.totals.subtotal;
doc.getElementById('print-allowances').textContent = data.totals.allowances;
doc.getElementById('print-charges').textContent = data.totals.charges;
doc.getElementById('print-net-amount').textContent = data.totals.netAmount;
doc.getElementById('print-total').textContent = data.totals.total;
// VAT Breakdown - use values directly from display
doc.getElementById('print-vat-breakdown').innerHTML = data.vatBreakdown.map(vat => `
<div>${this.getVATTypeLabel(vat.type)}</div>
<div>${vat.rate}%</div>
<div>${vat.base}</div>
<div>${vat.amount}</div>
`).join('');
// VAT totals
doc.getElementById('print-vat-currency-main').textContent = data.documentCurrencyCode;
doc.getElementById('print-vat-main').textContent = data.totals.vat;
const secondaryVatRow = doc.getElementById('print-vat-secondary');
if (data.taxCurrencyCode && data.taxCurrencyCode !== data.documentCurrencyCode) {
secondaryVatRow.style.display = 'flex';
doc.getElementById('print-vat-currency-secondary').textContent = data.taxCurrencyCode;
const vatInTaxCurrency = this.formatter.parseCurrency(data.totals.vat) * data.exchangeRate;
doc.getElementById('print-vat-secondary-amount').textContent =
this.formatter.formatCurrency(vatInTaxCurrency);
}
}
}