/**
* V.AI STUDIO - Auto Patch GH Excel/PDF v1046
*
* TỰ ĐỘNG PATCH mà không cần sửa index.html
* Chỉ cần thêm dòng: vào index.html
*
* FIX:
* - exportDeliveryExcel/PDF nhận order parameter đúng
* - Click protection (chống bấm nhiều lần)
* - Blob retention 5 phút (tải nhiều lần được)
*/
(function() {
'use strict';
// === WAIT FOR VAI_QR READY ===
function initPatch() {
if (typeof window.VAI_QR === 'undefined') {
setTimeout(initPatch, 500);
return;
}
// === STORE ORIGINAL FOR REFERENCE ===
var origExportDE = window.exportDeliveryExcel;
var origExportDP = window.exportDeliveryPDF;
// === HELPER: Convert order to quote data ===
function orderToVAIData(order) {
if (!order || !order.items) return null;
return {
qd: {
customer: {
name: order.customer || '',
phone: order.phone || '',
email: order.email || '',
addr: order.addr || '',
date: order.date || ''
},
items: (order.items || []).map(function(it, i) {
return {
stt: i + 1,
image: it.image || '',
name: it.name || '',
model: it.model || '',
specs: it.specs || it.info || '',
qty: it.qty || 1,
price: it.price || it.listPrice || it.discPrice || 0,
discPrice: it.discPrice || it.price || 0,
total: it.total || 0,
note: it.note || ''
};
}),
grandTotal: order.grandTotal || 0
}
};
}
// === CLICK STATE ===
var activeExportBtn = null;
function setBtnState(btn, exporting) {
if (!btn) return;
if (exporting) {
btn.disabled = true;
btn.dataset.vaiExporting = '1';
btn._origHtml = btn.innerHTML;
btn.innerHTML = '⏳';
} else {
btn.disabled = false;
btn.dataset.vaiExporting = '0';
if (btn._origHtml) btn.innerHTML = btn._origHtml;
}
}
// === PATCH EXPORT DELIVERY EXCEL ===
window.exportDeliveryExcel = async function(order, opt) {
var btn = document.activeElement;
if (btn && btn.dataset.vaiExporting === '1') {
console.log('[AutoPatch] Already exporting, ignoring...');
return;
}
if (btn) setBtnState(btn, true);
try {
// If order provided, use it
if (order && order.items && order.items.length) {
var vaData = orderToVAIData(order);
var code = order.code || 'GH-' + Date.now();
// Use qr-payment.js internal function if available
if (window.VAI_QR && window.VAI_QR._doExportDeliveryExcel) {
await window.VAI_QR._doExportDeliveryExcel(vaData.qd, code);
console.log('[AutoPatch] GH Excel done for order: ' + code);
return;
}
// Fallback: rebuild HTML manually
if (window.VAI_QR && window.VAI_QR.buildDeliveryHTML) {
let html = window.VAI_QR.buildDeliveryHTML(vaData.qd, code);
let div = document.createElement('div');
div.style.cssText = 'position:absolute;left:-9999px;top:0;width:700px;background:#fff;padding:28px';
div.innerHTML = html;
document.body.appendChild(div);
await new Promise(r => setTimeout(r, 300));
if (window.ExcelJS) {
let wb = new ExcelJS.Workbook();
let ws = wb.addWorksheet('Giao hàng');
ws.views = [{showGridLines: false}];
ws.columns = [{width: 5}, {width: 34}, {width: 14}, {width: 8}, {width: 20}];
ws.getCell('A1').value = 'PHIẾU GIAO HÀNG';
ws.getCell('A2').value = 'KH: ' + (vaData.qd.customer.name || '');
ws.getCell('D2').value = 'Mã: ' + code;
ws.getCell('A3').value = 'SĐT: ' + (vaData.qd.customer.phone || '');
ws.getCell('A4').value = 'Địa chỉ: ' + (vaData.qd.customer.addr || '');
let headerRow = ws.getRow(6);
['STT', 'Tên sản phẩm', 'Mã SP', 'SL', 'Ghi chú'].forEach(function(h, i) {
let c = headerRow.getCell(i + 1);
c.value = h;
c.fill = {type: 'pattern', pattern: 'solid', fgColor: {argb: 'FF003F62'}};
c.font = {bold: true, color: {argb: 'FFFFFFFF'}};
});
let cr = 7;
(vaData.qd.items || []).forEach(function(it) {
let row = ws.getRow(cr);
row.getCell(1).value = it.stt;
row.getCell(2).value = it.name;
row.getCell(3).value = it.model;
row.getCell(4).value = it.qty;
row.getCell(5).value = it.note;
cr++;
});
let buf = await wb.xlsx.writeBuffer();
let blob = new Blob([buf], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
let url = URL.createObjectURL(blob);
let a = document.createElement('a');
a.href = url;
a.download = 'GH-' + code + '.xlsx';
a.click();
// Keep blob for 5 minutes
setTimeout(() => URL.revokeObjectURL(url), 300000);
}
div.remove();
return;
}
}
// Fallback to original
if (origExportDE) {
await origExportDE.call(this, order, opt);
}
} catch (e) {
console.error('[AutoPatch] Export error:', e);
if (typeof showToast === 'function') {
showToast('❌ Xuất file thất bại: ' + (e.message || e));
}
} finally {
setTimeout(() => { if (btn) setBtnState(btn, false); }, 1000);
}
};
// === PATCH EXPORT DELIVERY PDF ===
window.exportDeliveryPDF = async function(order, opt) {
var btn = document.activeElement;
if (btn && btn.dataset.vaiExporting === '1') {
console.log('[AutoPatch] Already exporting, ignoring...');
return;
}
if (btn) setBtnState(btn, true);
try {
if (order && order.items && order.items.length) {
var vaData = orderToVAIData(order);
var code = order.code || 'GH-' + Date.now();
if (window.VAI_QR && window.VAI_QR._doExportDeliveryPDF) {
await window.VAI_QR._doExportDeliveryPDF(vaData.qd, code);
console.log('[AutoPatch] GH PDF done for order: ' + code);
return;
}
if (window.VAI_QR && window.VAI_QR.buildDeliveryHTML) {
let html = window.VAI_QR.buildDeliveryHTML(vaData.qd, code);
let div = document.createElement('div');
div.style.cssText = 'position:absolute;left:-9999px;top:0;width:700px;background:#fff;padding:28px';
div.innerHTML = html;
document.body.appendChild(div);
await new Promise(r => setTimeout(r, 300));
if (window.html2canvas && window.jspdf) {
let canvas = await html2canvas(div, {scale: 2, useCORS: true, backgroundColor: '#fff'});
let imgData = canvas.toDataURL('image/png');
let {jsPDF} = window.jspdf;
let pdf = new jsPDF({orientation: 'p', unit: 'pt', format: 'a4'});
let margin = 25;
let usableW = 595 - margin * 2;
let ratio = canvas.height / canvas.width;
let imgH = usableW * ratio;
pdf.addImage(imgData, 'PNG', margin, margin, usableW, imgH > 842 - margin * 2 ? 842 - margin * 2 : imgH);
pdf.save('GH-' + code + '.pdf');
}
div.remove();
return;
}
}
if (origExportDP) {
await origExportDP.call(this, order, opt);
}
} catch (e) {
console.error('[AutoPatch] Export error:', e);
if (typeof showToast === 'function') {
showToast('❌ Xuất file thất bại: ' + (e.message || e));
}
} finally {
setTimeout(() => { if (btn) setBtnState(btn, false); }, 1000);
}
};
console.log('[AutoPatch v1046] GH Excel/PDF patched - ready!');
}
// Start patching
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initPatch);
} else {
initPatch();
}
// Also run after delays (HF Spaces loads scripts dynamically)
setTimeout(initPatch, 2000);
setTimeout(initPatch, 5000);
})();