bep40 commited on
Commit
c4b565c
·
verified ·
1 Parent(s): 8f026f1

Khôi phục từ commit e37f787

Browse files
Files changed (1) hide show
  1. qr-payment.js +15 -58
qr-payment.js CHANGED
@@ -1,9 +1,7 @@
1
- /* V.AI STUDIO — QR Payment / Quote Data v1041
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
- // CRITICAL FIX: Export functions now ALWAYS use passed arguments, never fallback incorrectly
198
- window.exportPDF=function(d,code){
199
- if(d && typeof d==='object' && d.qd){
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 v1041 — EXPORT ARGS FIXED: Now correctly uses passed arguments with fees');return true;
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
- // CRITICAL FIX: VAI_QR now points to wrapper functions (window.exportExcel etc.) NOT internal functions
406
- window.VAI_QR={getEffectiveOrderCode:getEffectiveOrderCode,getQRUrl:getQRUrl,generateOrderCode:generateOrderCode,parsePrompt:parsePrompt,getPromptText:getPromptText,injectToModal:injectToModal,getData:getData,buildQuoteHTML:buildQuoteHTML,buildDeliveryHTML:buildDeliveryHTML,toCanvas:toCanvas,exportPDF:window.exportPDF,exportExcel:window.exportExcel,exportDeliveryPDF:window.exportDeliveryPDF,exportDeliveryExcel:window.exportDeliveryExcel,fmt:fmt,compactKey:compactKey,matchItemDiscount:matchItemDiscount,parseItemDiscountLine:parseItemDiscountLine,applyPromptDiscounts:applyPromptDiscounts};
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
+ })();