Spaces:
Running
Running
Khôi phục từ commit e37f787
Browse files- qr-payment.js +15 -58
qr-payment.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
| 1 |
-
/* V.AI STUDIO — QR Payment / Quote Data
|
| 2 |
* FIX: parsePrompt — 'Malloca ck 35%' now correctly detected as global discount;
|
| 3 |
* 'ghi chú: giao thứ 7' treated as note, not a 7đ fee;
|
| 4 |
-
* small numbers with ordinal/date context (thứ, ngày, giờ) = note, not fee
|
| 5 |
-
* FIX EXPORT ARGS v2: window.VAI_QR now points to wrapper functions that accept arguments
|
| 6 |
-
* ROOT CAUSE FIXED: VAI_QR.exportExcel now correctly uses passed data with fees
|
| 7 |
*/
|
| 8 |
(function(){
|
| 9 |
'use strict';
|
|
@@ -59,6 +57,7 @@ function parsePrompt(text){
|
|
| 59 |
if(!text)return{fees:fees,notes:notes,discount:discount,deposit:deposit,discountPercent:discountPercent,itemDiscounts:itemDiscounts};
|
| 60 |
text.split(/[,;\n]+/).forEach(function(line){
|
| 61 |
line=line.trim();if(!line)return;
|
|
|
|
| 62 |
if(line.match(/^(ghi chú|ghichu|note|notes)\s*[:\-]?\s*/i)){
|
| 63 |
var nt=line.replace(/^(ghi chú|ghichu|note|notes)\s*[:\-]?\s*/i,'');
|
| 64 |
if(nt) notes.push(nt);
|
|
@@ -66,6 +65,7 @@ function parsePrompt(text){
|
|
| 66 |
}
|
| 67 |
parseItemDiscountLine(line,itemDiscounts);
|
| 68 |
if(Object.keys(itemDiscounts).length&&line.match(/\b[A-Za-z]{1,8}[A-Za-z0-9._\-\/]{1,30}\d[A-Za-z0-9._\-\/]*\b/i)&&line.match(/\b(ck|chiết khấu|chiet khau|giảm|giam|discount)\b/i))return;
|
|
|
|
| 69 |
if(line.match(/^(ck|chiết khấu|chiet khau|giảm|giam|discount)/i) || line.match(/\bck\s*[\d.,]+\s*%/i)){
|
| 70 |
discount=line;
|
| 71 |
var ckm=line.match(/([\d.,]+)\s*(%)?/);
|
|
@@ -77,9 +77,11 @@ function parsePrompt(text){
|
|
| 77 |
if(dm){var da=parseFloat(dm[1].replace(/\./g,'').replace(',','.'));var du=(dm[2]||'').toLowerCase();if(du==='k'||du==='nghìn'||du==='nghin')da*=1000;if(du==='triệu'||du==='tr')da*=1000000;deposit=da;}
|
| 78 |
return;
|
| 79 |
}
|
|
|
|
| 80 |
var m=line.match(/([\d.,]+)\s*(k|K|nghìn|nghin|triệu|tr|đ|d|vnd)?/);
|
| 81 |
if(m){
|
| 82 |
var amt=parseFloat(m[1].replace(/\./g,'').replace(',','.'));var u=(m[2]||'').toLowerCase();if(u==='k'||u==='nghìn'||u==='nghin')amt*=1000;if(u==='triệu'||u==='tr')amt*=1000000;if(amt<=0)return;
|
|
|
|
| 83 |
var lb=line.replace(m[0],'').trim();
|
| 84 |
if(amt<1000&&!u&&lb.match(/thứ|ngày|giờ|tuần|tháng|năm|lúc/i)){notes.push(line);return;}
|
| 85 |
if(lb.match(/giao|ship|vận chuyển|delivery/i))lb='Phí giao hàng';else if(lb.match(/lắp|lap|install/i))lb='Phí lắp đặt';else if(lb.match(/bốc|boc|xếp|xep|vác/i))lb='Phí bốc xếp';else if(!lb||lb.length<2)lb='Phụ phí';fees.push({label:lb,amount:amt});
|
|
@@ -191,59 +193,13 @@ async function _fetchImageAsBuffer(url){
|
|
| 191 |
function doOverride(){
|
| 192 |
if(typeof getQuoteData!=='function'||typeof html2canvas!=='function')return false;
|
| 193 |
window._origGetQuoteData=getQuoteData;
|
| 194 |
-
|
| 195 |
window.shareQuoteImage=async function(){var d=getData(),code=getEffectiveOrderCode(),qr=getQRUrl(d.deposit>0?d.remaining:d.grandTotal,code);try{var cv=await toCanvas(buildQuoteHTML(d,code,qr),1000);var blob=await new Promise(function(r){cv.toBlob(r,'image/png');});var f=new File([blob],code+'.png',{type:'image/png'});if(navigator.share&&navigator.canShare&&navigator.canShare({files:[f]})){await navigator.share({title:code,files:[f]});}else{var url=URL.createObjectURL(blob);var p=document.createElement('div');p.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.7);z-index:999;display:flex;align-items:center;justify-content:center;padding:16px;backdrop-filter:blur(4px)';p.innerHTML='<div style="background:#fff;border-radius:16px;max-width:90vw;max-height:85vh;overflow:auto;padding:16px"><img src="'+url+'" style="max-width:100%;border-radius:8px"><div style="display:flex;gap:8px;margin-top:12px;justify-content:center"><a href="'+url+'" download="'+code+'.png" style="padding:10px 20px;background:#003f62;color:#fff;border-radius:8px;font-weight:700;text-decoration:none">⬇ Tải ảnh</a><button onclick="this.closest(\'div[style*=fixed]\').remove()" style="padding:10px 20px;background:#e2e8f0;border:none;border-radius:8px;font-weight:700;cursor:pointer">Đóng</button></div></div>';document.body.appendChild(p);}}catch(e){console.error(e);}};
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
window.
|
| 199 |
-
|
| 200 |
-
console.log('[exportPDF] Using passed data with fees:', d.fees);
|
| 201 |
-
return _doExportPDF(d, code || getEffectiveOrderCode());
|
| 202 |
-
} else {
|
| 203 |
-
var d2=getData();
|
| 204 |
-
console.log('[exportPDF] Using getData() with fees:', d2.fees);
|
| 205 |
-
return _doExportPDF(d2, getEffectiveOrderCode());
|
| 206 |
-
}
|
| 207 |
-
};
|
| 208 |
-
|
| 209 |
-
window.exportExcel=function(d,qd,code,qr){
|
| 210 |
-
if(d && typeof d==='object' && d.qd){
|
| 211 |
-
console.log('[exportExcel] Using passed data with fees:', d.fees);
|
| 212 |
-
qd=qd||d.qd;
|
| 213 |
-
code=code||getEffectiveOrderCode();
|
| 214 |
-
if(!qr && d.grandTotal!==undefined){
|
| 215 |
-
qr=getQRUrl(d.deposit>0?d.remaining:d.grandTotal,code);
|
| 216 |
-
}
|
| 217 |
-
return _doExportExcel(d,qd,code,qr);
|
| 218 |
-
} else {
|
| 219 |
-
var d2=getData();
|
| 220 |
-
console.log('[exportExcel] Using getData() with fees:', d2.fees);
|
| 221 |
-
return _doExportExcel(d2,d2.qd,getEffectiveOrderCode(),getQRUrl(d2.deposit>0?d2.remaining:d2.grandTotal,getEffectiveOrderCode()));
|
| 222 |
-
}
|
| 223 |
-
};
|
| 224 |
-
|
| 225 |
-
window.exportDeliveryExcel=function(qd,code){
|
| 226 |
-
if(qd && typeof qd==='object' && qd.items){
|
| 227 |
-
console.log('[exportDeliveryExcel] Using passed qd');
|
| 228 |
-
return _doExportDeliveryExcel(qd, code || getEffectiveOrderCode());
|
| 229 |
-
} else {
|
| 230 |
-
var qd2=window._origGetQuoteData();
|
| 231 |
-
return _doExportDeliveryExcel(qd2, getEffectiveOrderCode());
|
| 232 |
-
}
|
| 233 |
-
};
|
| 234 |
-
|
| 235 |
-
window.exportDeliveryPDF=function(qd,code){
|
| 236 |
-
if(qd && typeof qd==='object' && qd.items){
|
| 237 |
-
console.log('[exportDeliveryPDF] Using passed qd');
|
| 238 |
-
return _doExportDeliveryPDF(qd, code || getEffectiveOrderCode());
|
| 239 |
-
} else {
|
| 240 |
-
var qd2=window._origGetQuoteData();
|
| 241 |
-
return _doExportDeliveryPDF(qd2, getEffectiveOrderCode());
|
| 242 |
-
}
|
| 243 |
-
};
|
| 244 |
-
|
| 245 |
window.getQuoteData=function(){var qd=window._origGetQuoteData.apply(this,arguments);if(qd.customer)qd.customer.orderCode=getEffectiveOrderCode();return qd;};
|
| 246 |
-
console.log('✅ QR Payment
|
| 247 |
}
|
| 248 |
|
| 249 |
async function _doExportPDF(d,code){
|
|
@@ -292,6 +248,7 @@ async function _doExportExcel(d,qd,code,qr){
|
|
| 292 |
var ckPct=Number(d.discountPercent||0);
|
| 293 |
|
| 294 |
// Pre-fetch ALL item images eagerly (with cache-bust) BEFORE building cells
|
|
|
|
| 295 |
var imgBuffers=[];
|
| 296 |
try{
|
| 297 |
for(var pi=0;pi<qd.items.length;pi++){
|
|
@@ -307,6 +264,7 @@ async function _doExportExcel(d,qd,code,qr){
|
|
| 307 |
var RB={top:{style:'thin',color:{argb:bgColor}},bottom:{style:'thin',color:{argb:bgColor}},left:{style:'thin',color:{argb:bgColor}},right:{style:'thin',color:{argb:bgColor}}};
|
| 308 |
row.getCell(1).value=it.stt||i+1;row.getCell(1).alignment={horizontal:'center',vertical:'middle'};
|
| 309 |
|
|
|
|
| 310 |
try{
|
| 311 |
if(imgBuffers[i]&&imgBuffers[i].byteLength>100){
|
| 312 |
ws.addImage(wb.addImage({buffer:imgBuffers[i],extension:'jpeg'}),{tl:{col:1,row:cr-1},ext:{width:46,height:46}});
|
|
@@ -402,6 +360,5 @@ document.addEventListener('click',function(e){
|
|
| 402 |
if(txt.includes('chia sẻ')&&txt.includes('ảnh')){e.preventDefault();e.stopPropagation();window.shareQuoteImage();return false;}
|
| 403 |
},true);
|
| 404 |
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
})();
|
|
|
|
| 1 |
+
/* V.AI STUDIO — QR Payment / Quote Data v1039
|
| 2 |
* FIX: parsePrompt — 'Malloca ck 35%' now correctly detected as global discount;
|
| 3 |
* 'ghi chú: giao thứ 7' treated as note, not a 7đ fee;
|
| 4 |
+
* small numbers with ordinal/date context (thứ, ngày, giờ) = note, not fee
|
|
|
|
|
|
|
| 5 |
*/
|
| 6 |
(function(){
|
| 7 |
'use strict';
|
|
|
|
| 57 |
if(!text)return{fees:fees,notes:notes,discount:discount,deposit:deposit,discountPercent:discountPercent,itemDiscounts:itemDiscounts};
|
| 58 |
text.split(/[,;\n]+/).forEach(function(line){
|
| 59 |
line=line.trim();if(!line)return;
|
| 60 |
+
// FIX: detect 'ghi chú:' / 'note:' prefix → rest is a note (skip all number matching)
|
| 61 |
if(line.match(/^(ghi chú|ghichu|note|notes)\s*[:\-]?\s*/i)){
|
| 62 |
var nt=line.replace(/^(ghi chú|ghichu|note|notes)\s*[:\-]?\s*/i,'');
|
| 63 |
if(nt) notes.push(nt);
|
|
|
|
| 65 |
}
|
| 66 |
parseItemDiscountLine(line,itemDiscounts);
|
| 67 |
if(Object.keys(itemDiscounts).length&&line.match(/\b[A-Za-z]{1,8}[A-Za-z0-9._\-\/]{1,30}\d[A-Za-z0-9._\-\/]*\b/i)&&line.match(/\b(ck|chiết khấu|chiet khau|giảm|giam|discount)\b/i))return;
|
| 68 |
+
// FIX: also match 'WORD ck X%' (e.g. 'Malloca ck 35%') — global discount
|
| 69 |
if(line.match(/^(ck|chiết khấu|chiet khau|giảm|giam|discount)/i) || line.match(/\bck\s*[\d.,]+\s*%/i)){
|
| 70 |
discount=line;
|
| 71 |
var ckm=line.match(/([\d.,]+)\s*(%)?/);
|
|
|
|
| 77 |
if(dm){var da=parseFloat(dm[1].replace(/\./g,'').replace(',','.'));var du=(dm[2]||'').toLowerCase();if(du==='k'||du==='nghìn'||du==='nghin')da*=1000;if(du==='triệu'||du==='tr')da*=1000000;deposit=da;}
|
| 78 |
return;
|
| 79 |
}
|
| 80 |
+
// FIX: number match — skip lines that look like dates/ordinals (e.g. 'thứ 7')
|
| 81 |
var m=line.match(/([\d.,]+)\s*(k|K|nghìn|nghin|triệu|tr|đ|d|vnd)?/);
|
| 82 |
if(m){
|
| 83 |
var amt=parseFloat(m[1].replace(/\./g,'').replace(',','.'));var u=(m[2]||'').toLowerCase();if(u==='k'||u==='nghìn'||u==='nghin')amt*=1000;if(u==='triệu'||u==='tr')amt*=1000000;if(amt<=0)return;
|
| 84 |
+
// FIX: small numbers (<1000, no unit) with context words → note, not fee
|
| 85 |
var lb=line.replace(m[0],'').trim();
|
| 86 |
if(amt<1000&&!u&&lb.match(/thứ|ngày|giờ|tuần|tháng|năm|lúc/i)){notes.push(line);return;}
|
| 87 |
if(lb.match(/giao|ship|vận chuyển|delivery/i))lb='Phí giao hàng';else if(lb.match(/lắp|lap|install/i))lb='Phí lắp đặt';else if(lb.match(/bốc|boc|xếp|xep|vác/i))lb='Phí bốc xếp';else if(!lb||lb.length<2)lb='Phụ phí';fees.push({label:lb,amount:amt});
|
|
|
|
| 193 |
function doOverride(){
|
| 194 |
if(typeof getQuoteData!=='function'||typeof html2canvas!=='function')return false;
|
| 195 |
window._origGetQuoteData=getQuoteData;
|
|
|
|
| 196 |
window.shareQuoteImage=async function(){var d=getData(),code=getEffectiveOrderCode(),qr=getQRUrl(d.deposit>0?d.remaining:d.grandTotal,code);try{var cv=await toCanvas(buildQuoteHTML(d,code,qr),1000);var blob=await new Promise(function(r){cv.toBlob(r,'image/png');});var f=new File([blob],code+'.png',{type:'image/png'});if(navigator.share&&navigator.canShare&&navigator.canShare({files:[f]})){await navigator.share({title:code,files:[f]});}else{var url=URL.createObjectURL(blob);var p=document.createElement('div');p.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.7);z-index:999;display:flex;align-items:center;justify-content:center;padding:16px;backdrop-filter:blur(4px)';p.innerHTML='<div style="background:#fff;border-radius:16px;max-width:90vw;max-height:85vh;overflow:auto;padding:16px"><img src="'+url+'" style="max-width:100%;border-radius:8px"><div style="display:flex;gap:8px;margin-top:12px;justify-content:center"><a href="'+url+'" download="'+code+'.png" style="padding:10px 20px;background:#003f62;color:#fff;border-radius:8px;font-weight:700;text-decoration:none">⬇ Tải ảnh</a><button onclick="this.closest(\'div[style*=fixed]\').remove()" style="padding:10px 20px;background:#e2e8f0;border:none;border-radius:8px;font-weight:700;cursor:pointer">Đóng</button></div></div>';document.body.appendChild(p);}}catch(e){console.error(e);}};
|
| 197 |
+
window.exportPDF=async function(){var d=getData(),code=getEffectiveOrderCode(),qr=getQRUrl(d.deposit>0?d.remaining:d.grandTotal,code);try{await _doExportPDF(d,code);}catch(e){console.error(e);alert('Không xuất được PDF: '+(e&&e.message?e.message:e));}};
|
| 198 |
+
window.exportExcel=async function(){if(typeof ExcelJS==='undefined')return;var d=getData(),qd=d.qd,code=getEffectiveOrderCode(),qr=getQRUrl(d.deposit>0?d.remaining:d.grandTotal,code);await _doExportExcel(d,qd,code,qr);};
|
| 199 |
+
window.exportDeliveryExcel=async function(){if(typeof ExcelJS==='undefined')return;var qd=window._origGetQuoteData(),code=getEffectiveOrderCode();await _doExportDeliveryExcel(qd,code);};
|
| 200 |
+
window.exportDeliveryPDF=async function(){var qd=window._origGetQuoteData(),code=getEffectiveOrderCode();await _doExportDeliveryPDF(qd,code);};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
window.getQuoteData=function(){var qd=window._origGetQuoteData.apply(this,arguments);if(qd.customer)qd.customer.orderCode=getEffectiveOrderCode();return qd;};
|
| 202 |
+
console.log('✅ QR Payment v1039 — parsePrompt fixed: ghi chú, Malloca ck 35%, thứ 7');return true;
|
| 203 |
}
|
| 204 |
|
| 205 |
async function _doExportPDF(d,code){
|
|
|
|
| 248 |
var ckPct=Number(d.discountPercent||0);
|
| 249 |
|
| 250 |
// Pre-fetch ALL item images eagerly (with cache-bust) BEFORE building cells
|
| 251 |
+
// This avoids DOM canvas taint — fetches directly from CDN with CORS
|
| 252 |
var imgBuffers=[];
|
| 253 |
try{
|
| 254 |
for(var pi=0;pi<qd.items.length;pi++){
|
|
|
|
| 264 |
var RB={top:{style:'thin',color:{argb:bgColor}},bottom:{style:'thin',color:{argb:bgColor}},left:{style:'thin',color:{argb:bgColor}},right:{style:'thin',color:{argb:bgColor}}};
|
| 265 |
row.getCell(1).value=it.stt||i+1;row.getCell(1).alignment={horizontal:'center',vertical:'middle'};
|
| 266 |
|
| 267 |
+
// Use pre-fetched image buffer (direct CORS fetch, no DOM canvas)
|
| 268 |
try{
|
| 269 |
if(imgBuffers[i]&&imgBuffers[i].byteLength>100){
|
| 270 |
ws.addImage(wb.addImage({buffer:imgBuffers[i],extension:'jpeg'}),{tl:{col:1,row:cr-1},ext:{width:46,height:46}});
|
|
|
|
| 360 |
if(txt.includes('chia sẻ')&&txt.includes('ảnh')){e.preventDefault();e.stopPropagation();window.shareQuoteImage();return false;}
|
| 361 |
},true);
|
| 362 |
|
| 363 |
+
window.VAI_QR={getEffectiveOrderCode:getEffectiveOrderCode,getQRUrl:getQRUrl,generateOrderCode:generateOrderCode,parsePrompt:parsePrompt,getPromptText:getPromptText,injectToModal:injectToModal,getData:getData,buildQuoteHTML:buildQuoteHTML,buildDeliveryHTML:buildDeliveryHTML,toCanvas:toCanvas,exportPDF:_doExportPDF,exportExcel:_doExportExcel,exportDeliveryPDF:_doExportDeliveryPDF,exportDeliveryExcel:_doExportDeliveryExcel,fmt:fmt,compactKey:compactKey,matchItemDiscount:matchItemDiscount,parseItemDiscountLine:parseItemDiscountLine,applyPromptDiscounts:applyPromptDiscounts};
|
| 364 |
+
})();
|
|
|