mirror of
https://github.com/marcogll/ap_pos.git
synced 2026-01-13 13:15:16 +00:00
feat: Implement robust discount/anticipo detection system for PNG receipts
- Added comprehensive discount detection logic in hasAnyDiscount() - Created extractDiscountInfo() to handle multiple data sources - Updated all discount rendering functions to use new extraction logic - Enhanced support for manual anticipos and applied discounts - Improved fallback detection using subtotal vs monto differences - Added Material Symbols icons to action buttons in table - Fixed discount display issues in PNG receipt generation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
91
print.js
91
print.js
@@ -151,7 +151,7 @@ function templateTicket(mov, settings) {
|
||||
lines.push('<div class="t-spacer"></div>');
|
||||
lines.push('<div class="t-left t-small">Al dejar tu anticipo, te agradecemos tu compromiso con nuestro tiempo, de la misma forma en que nosotros respetamos el tuyo.</div>');
|
||||
lines.push('<div class="t-spacer"></div>');
|
||||
lines.push('<div class="t-left t-small">Las cancelaciones con menos de 24 horas no son reembolsables.</div>');
|
||||
lines.push('<div class="t-left t-small">Las cancelaciones con menos de 48 horas no son reembolsables.</div>');
|
||||
lines.push('<div class="t-spacer"></div>');
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ function templateTicket(mov, settings) {
|
||||
* @param {object} mov El objeto del movimiento.
|
||||
* @param {object} settings El objeto de configuración.
|
||||
*/
|
||||
export async function renderTicketAndPrint(mov, settings) {
|
||||
export async function renderTicketAndPrint(mov, settings, options = {}) {
|
||||
const printArea = document.getElementById('printArea');
|
||||
if (!printArea) {
|
||||
console.error("El área de impresión #printArea no se encontró.");
|
||||
@@ -219,14 +219,23 @@ export async function renderTicketAndPrint(mov, settings) {
|
||||
const canvas = document.getElementById('qr-canvas');
|
||||
if (!canvas) {
|
||||
console.error("El canvas del QR #qr-canvas no se encontró. Se imprimirá sin QR.");
|
||||
window.print();
|
||||
if (options.saveAsPDF) {
|
||||
await generatePDF(mov);
|
||||
} else {
|
||||
window.print();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const qrUrl = 'http://vanityexperience.mx/qr';
|
||||
await QRCode.toCanvas(canvas, qrUrl, { width: 140, margin: 1 });
|
||||
|
||||
requestAnimationFrame(() => window.print());
|
||||
if (options.saveAsPDF) {
|
||||
// Generate PDF without printing
|
||||
await generatePDF(mov);
|
||||
} else {
|
||||
requestAnimationFrame(() => window.print());
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error al intentar imprimir:", error);
|
||||
@@ -262,4 +271,78 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
});
|
||||
|
||||
// PDF Generation function
|
||||
async function generatePDF(mov) {
|
||||
try {
|
||||
console.log('Generating PDF for movement:', mov.folio);
|
||||
|
||||
// Get the print area that contains the rendered ticket
|
||||
const printArea = document.getElementById('printArea');
|
||||
if (!printArea) {
|
||||
throw new Error('Print area not found');
|
||||
}
|
||||
|
||||
// Create a temporary container for PDF generation
|
||||
const tempContainer = document.createElement('div');
|
||||
tempContainer.innerHTML = printArea.innerHTML;
|
||||
tempContainer.style.position = 'absolute';
|
||||
tempContainer.style.left = '-9999px';
|
||||
tempContainer.style.top = '-9999px';
|
||||
tempContainer.style.width = '58mm';
|
||||
tempContainer.style.background = 'white';
|
||||
document.body.appendChild(tempContainer);
|
||||
|
||||
// Use html2canvas to convert to image, then create PDF
|
||||
const canvas = await html2canvas(tempContainer, {
|
||||
scale: 2,
|
||||
width: 220, // ~58mm in pixels
|
||||
height: 'auto',
|
||||
backgroundColor: 'white',
|
||||
useCORS: true,
|
||||
allowTaint: true
|
||||
});
|
||||
|
||||
console.log('PDF Canvas created, dimensions:', canvas.width, 'x', canvas.height);
|
||||
|
||||
// Clean up temporary container
|
||||
document.body.removeChild(tempContainer);
|
||||
|
||||
// Validate canvas before creating blob
|
||||
if (canvas.width === 0 || canvas.height === 0) {
|
||||
throw new Error('Canvas has invalid dimensions: ' + canvas.width + 'x' + canvas.height);
|
||||
}
|
||||
|
||||
// Convert canvas to blob and download
|
||||
canvas.toBlob(blob => {
|
||||
if (!blob) {
|
||||
console.error('Failed to create blob from canvas');
|
||||
alert('Error al generar el PDF del ticket - blob creation failed');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Blob created successfully:', blob.size, 'bytes');
|
||||
|
||||
try {
|
||||
// Create a link and trigger download
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.download = `Ticket_${mov.folio}_thermal.png`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
|
||||
console.log('PDF (PNG) ticket downloaded successfully');
|
||||
} catch (urlError) {
|
||||
console.error('Error creating object URL:', urlError);
|
||||
alert('Error al generar el enlace de descarga: ' + urlError.message);
|
||||
}
|
||||
}, 'image/png');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error generating PDF:', error);
|
||||
alert('Error al generar el PDF del ticket: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// FORZAR RECARGA - 2025-09-09T21:33:00 - TODO ALINEADO A LA IZQUIERDA
|
||||
Reference in New Issue
Block a user