Hide completed import catalog entries without losing order history
This commit is contained in:
parent
11e7b4bd56
commit
be0fd9aee7
11
docs/import-cleanup-20260918.md
Normal file
11
docs/import-cleanup-20260918.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Completed Telegram import cleanup
|
||||||
|
|
||||||
|
The working menu, new-order selection, search, category counts and catalog PDFs exclude items with `hidden: true`. Historical order lookup still resolves these items, preserving original names, quantities, prices, payments and proposal snapshots. Adding a retired item through a stale catalog button is ignored.
|
||||||
|
|
||||||
|
The one-time Telegram archive viewer is removed. Its script remains a small compatibility cleanup for cached markup; it does not expose a stored archive again after synchronization or account changes.
|
||||||
|
|
||||||
|
The separate, owner-authorized production cleanup is limited to the Sun workspace and to catalog entries matching all four markers: category 0, section `Импорт из Telegram`, source `telegram-20260917`, and the `tg-item-` ID prefix. These temporary catalog references are retired rather than physically deleted because existing orders use their IDs. The global archive payload is removed; individual orders and their source details are preserved.
|
||||||
|
|
||||||
|
The operation makes a server backup, uses optimistic revision locking and verifies unchanged orders, client records, unrelated storage and regular catalog entries. Private payload backups and customer information are kept outside this repository.
|
||||||
|
|
||||||
|
Validation: desktop and mobile tests cover retired catalog visibility, search, printed and generated catalogs, historical order totals, paid state, contact details, proposal contents, reload persistence, archive retirement, company branding and banquet behavior (26 tests). Syntax, security, release checks and database smoke checks pass.
|
||||||
@ -11,7 +11,7 @@
|
|||||||
"serverReady": true,
|
"serverReady": true,
|
||||||
"workspaceAutoDiscovery": true,
|
"workspaceAutoDiscovery": true,
|
||||||
"invitesTemporarilyDisabled": false,
|
"invitesTemporarilyDisabled": false,
|
||||||
"pwaCache": "v106-20260918-proposals-six",
|
"pwaCache": "v107-20260918-import-cleanup",
|
||||||
"fullOfferDescriptions": true,
|
"fullOfferDescriptions": true,
|
||||||
"dynamicOfferRows": true,
|
"dynamicOfferRows": true,
|
||||||
"pdfOfferDescriptionFix": true,
|
"pdfOfferDescriptionFix": true,
|
||||||
@ -431,5 +431,7 @@
|
|||||||
],
|
],
|
||||||
"proposalTransparentLogoTrim": true,
|
"proposalTransparentLogoTrim": true,
|
||||||
"proposalLogoAspectRatio": true,
|
"proposalLogoAspectRatio": true,
|
||||||
"proposalLogoContrastMasthead": true
|
"proposalLogoContrastMasthead": true,
|
||||||
|
"retiredCatalogItemsPreserveOrderHistory": true,
|
||||||
|
"oneTimeTelegramArchiveUiRemoved": true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -152,7 +152,7 @@ window.SUN_LEGACY_CATALOG_V175=[];
|
|||||||
const buildPdf=pages=>window.SunPdfEngine.fromJpegs(pages);
|
const buildPdf=pages=>window.SunPdfEngine.fromJpegs(pages);
|
||||||
|
|
||||||
async function createCatalogPdfBlob(cat,progress){
|
async function createCatalogPdfBlob(cat,progress){
|
||||||
const items=allBoxes().filter(item=>Number(item.category||0)===Number(cat));
|
const items=allBoxes().filter(item=>item.hidden!==true&&Number(item.category||0)===Number(cat));
|
||||||
if(!items.length)throw new Error('В этом разделе нет позиций.');
|
if(!items.length)throw new Error('В этом разделе нет позиций.');
|
||||||
const pages=[],dateText=new Date().toLocaleDateString('ru-RU'),brand=window.CateriumBranding.identity();
|
const pages=[],dateText=new Date().toLocaleDateString('ru-RU'),brand=window.CateriumBranding.identity();
|
||||||
for(let i=0;i<items.length;i++){
|
for(let i=0;i<items.length;i++){
|
||||||
@ -203,7 +203,7 @@ window.SUN_LEGACY_CATALOG_V175=[];
|
|||||||
|
|
||||||
window.sunOpenCatalogPdfViewer=openCatalogPdfViewer;
|
window.sunOpenCatalogPdfViewer=openCatalogPdfViewer;
|
||||||
window.sunBuildCatalogPdfBlob=()=>createCatalogPdfBlob(currentCategory());
|
window.sunBuildCatalogPdfBlob=()=>createCatalogPdfBlob(currentCategory());
|
||||||
window.sunCatalogDebugPdfPages=async(cat=currentCategory(),limit=3)=>{const items=allBoxes().filter(item=>Number(item.category||0)===Number(cat)).slice(0,Math.max(1,Number(limit||3)));const dateText=new Date().toLocaleDateString('ru-RU'),pages=[];for(let i=0;i<items.length;i++)pages.push(await renderPageJpeg(items[i],cat,i,items.length,dateText));return pages};
|
window.sunCatalogDebugPdfPages=async(cat=currentCategory(),limit=3)=>{const items=allBoxes().filter(item=>item.hidden!==true&&Number(item.category||0)===Number(cat)).slice(0,Math.max(1,Number(limit||3)));const dateText=new Date().toLocaleDateString('ru-RU'),pages=[];for(let i=0;i<items.length;i++)pages.push(await renderPageJpeg(items[i],cat,i,items.length,dateText));return pages};
|
||||||
installButton();setTimeout(installButton,150);setTimeout(installButton,800);
|
installButton();setTimeout(installButton,150);setTimeout(installButton,800);
|
||||||
document.addEventListener('click',e=>{if(e.target.closest('#new .cats button,#new .sun-catalog-top-toolbar .cats button'))setTimeout(installButton,30)},true);
|
document.addEventListener('click',e=>{if(e.target.closest('#new .cats button,#new .sun-catalog-top-toolbar .cats button'))setTimeout(installButton,30)},true);
|
||||||
const catalog=document.querySelector('#new .catalog');if(catalog&&'MutationObserver'in window)new MutationObserver(()=>{const b=$('sunLiveCatalogPdfButton');if(!b||b.textContent!=='PDF'||b.onclick!==openCatalogPdfViewer)queueMicrotask(installButton)}).observe(catalog,{childList:true,subtree:true});
|
const catalog=document.querySelector('#new .catalog');if(catalog&&'MutationObserver'in window)new MutationObserver(()=>{const b=$('sunLiveCatalogPdfButton');if(!b||b.textContent!=='PDF'||b.onclick!==openCatalogPdfViewer)queueMicrotask(installButton)}).observe(catalog,{childList:true,subtree:true});
|
||||||
@ -356,7 +356,7 @@ window.SUN_LEGACY_CATALOG_V175=[];
|
|||||||
function renderCategoryManager(){
|
function renderCategoryManager(){
|
||||||
ensureCategoryModal();const root=$('sunCategoryRows');if(!root)return;
|
ensureCategoryModal();const root=$('sunCategoryRows');if(!root)return;
|
||||||
root.innerHTML=catalogCats.slice().sort((a,b)=>a.order-b.order).map(c=>{
|
root.innerHTML=catalogCats.slice().sort((a,b)=>a.order-b.order).map(c=>{
|
||||||
const count=(typeof boxes!=='undefined'?boxes:[]).filter(b=>Number(b.category||0)===Number(c.id)).length;
|
const count=(typeof boxes!=='undefined'?boxes:[]).filter(b=>b.hidden!==true&&Number(b.category||0)===Number(c.id)).length;
|
||||||
return `<div class="sun-category-row ${c.hidden?'is-hidden':''}" data-cat-row="${c.id}"><input value="${esc(c.name)}" data-cat-name="${c.id}" aria-label="Название вкладки"><label class="sun-category-color" title="Цвет вкладки"><input type="color" value="${esc(c.accent||'#708090')}" data-cat-color="${c.id}" aria-label="Цвет вкладки"></label><small>${count} поз.</small><div class="sun-category-row-actions"><button class="outline" type="button" data-cat-up="${c.id}" title="Выше">↑</button><button class="outline" type="button" data-cat-down="${c.id}" title="Ниже">↓</button><button class="outline" type="button" data-cat-toggle="${c.id}">${c.hidden?'Восстановить':'Скрыть'}</button></div></div>`;
|
return `<div class="sun-category-row ${c.hidden?'is-hidden':''}" data-cat-row="${c.id}"><input value="${esc(c.name)}" data-cat-name="${c.id}" aria-label="Название вкладки"><label class="sun-category-color" title="Цвет вкладки"><input type="color" value="${esc(c.accent||'#708090')}" data-cat-color="${c.id}" aria-label="Цвет вкладки"></label><small>${count} поз.</small><div class="sun-category-row-actions"><button class="outline" type="button" data-cat-up="${c.id}" title="Выше">↑</button><button class="outline" type="button" data-cat-down="${c.id}" title="Ниже">↓</button><button class="outline" type="button" data-cat-toggle="${c.id}">${c.hidden?'Восстановить':'Скрыть'}</button></div></div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
qa('[data-cat-name]',root).forEach(input=>input.onchange=()=>{const c=catById(input.dataset.catName);if(!c)return;c.name=input.value.trim()||c.name;saveCats();renderCategoryTabs();syncEditorCategoryOptions();renderCatalogV5();renderCategoryManager();});
|
qa('[data-cat-name]',root).forEach(input=>input.onchange=()=>{const c=catById(input.dataset.catName);if(!c)return;c.name=input.value.trim()||c.name;saveCats();renderCategoryTabs();syncEditorCategoryOptions();renderCatalogV5();renderCategoryManager();});
|
||||||
@ -421,7 +421,7 @@ window.SUN_LEGACY_CATALOG_V175=[];
|
|||||||
const fields=ensureBanquetEditor();if(!fields)return;const isBanquet=Number(category)===BANQUET_CATEGORY;
|
const fields=ensureBanquetEditor();if(!fields)return;const isBanquet=Number(category)===BANQUET_CATEGORY;
|
||||||
fields.section.style.display=isBanquet?'flex':'none';fields.weight.style.display=isBanquet?'flex':'none';
|
fields.section.style.display=isBanquet?'flex':'none';fields.weight.style.display=isBanquet?'flex':'none';
|
||||||
const caption=$('boxPriceCaption');if(caption)caption.textContent=isBanquet?'Цена на 1 гостя, ₽':'Цена, ₽';
|
const caption=$('boxPriceCaption');if(caption)caption.textContent=isBanquet?'Цена на 1 гостя, ₽':'Цена, ₽';
|
||||||
window.CateriumBanquet?.editor(category,item,boxes.filter(i=>Number(i.category)===6));
|
window.CateriumBanquet?.editor(category,item,boxes.filter(i=>i.hidden!==true&&Number(i.category)===6));
|
||||||
if(isBanquet){if($('banquetSection'))$('banquetSection').value=item?.catalogSection||'';if($('banquetWeightGrams'))$('banquetWeightGrams').value=parseWeightGrams(item?.weight)||''}
|
if(isBanquet){if($('banquetSection'))$('banquetSection').value=item?.catalogSection||'';if($('banquetWeightGrams'))$('banquetWeightGrams').value=parseWeightGrams(item?.weight)||''}
|
||||||
}
|
}
|
||||||
function installIngredientEditorV175(){window.renderIngredients=()=>{if(!edited)return;normalizeBoxItem(edited);const root=$('ingredients');if(!root)return;const head='<div class="sun-ingredient-head"><span>Вид / название</span><span>Кол-во</span><span>Ед.</span><span>Вес 1 шт., г</span><span></span></div>';root.innerHTML=head+edited.ingredients.map((row,i)=>{const w=ingredientUnitWeight(row);return `<div class="ingredient sun-ingredient-v175"><input value="${esc(cleanIngredientName(row[0]))}" onchange="edited.ingredients[${i}][0]=this.value"><input type="number" min="0" step="0.01" value="${Number(row[1]||0)}" onchange="edited.ingredients[${i}][1]=+this.value"><input value="${esc(row[2]||'шт.')}" onchange="edited.ingredients[${i}][2]=this.value"><input type="number" min="0" step="0.1" inputmode="decimal" placeholder="г" value="${w||''}" onchange="edited.ingredients[${i}][3]=Math.max(0,+this.value||0)"><button type="button" onclick="edited.ingredients.splice(${i},1);renderIngredients()">×</button></div>`}).join('')};window.addIngredient=()=>{if(!edited)return;if(!Array.isArray(edited.ingredients))edited.ingredients=[];edited.ingredients.push(['Новая позиция',1,'шт.',0]);window.renderIngredients();};}
|
function installIngredientEditorV175(){window.renderIngredients=()=>{if(!edited)return;normalizeBoxItem(edited);const root=$('ingredients');if(!root)return;const head='<div class="sun-ingredient-head"><span>Вид / название</span><span>Кол-во</span><span>Ед.</span><span>Вес 1 шт., г</span><span></span></div>';root.innerHTML=head+edited.ingredients.map((row,i)=>{const w=ingredientUnitWeight(row);return `<div class="ingredient sun-ingredient-v175"><input value="${esc(cleanIngredientName(row[0]))}" onchange="edited.ingredients[${i}][0]=this.value"><input type="number" min="0" step="0.01" value="${Number(row[1]||0)}" onchange="edited.ingredients[${i}][1]=+this.value"><input value="${esc(row[2]||'шт.')}" onchange="edited.ingredients[${i}][2]=this.value"><input type="number" min="0" step="0.1" inputmode="decimal" placeholder="г" value="${w||''}" onchange="edited.ingredients[${i}][3]=Math.max(0,+this.value||0)"><button type="button" onclick="edited.ingredients.splice(${i},1);renderIngredients()">×</button></div>`}).join('')};window.addIngredient=()=>{if(!edited)return;if(!Array.isArray(edited.ingredients))edited.ingredients=[];edited.ingredients.push(['Новая позиция',1,'шт.',0]);window.renderIngredients();};}
|
||||||
@ -437,13 +437,13 @@ window.SUN_LEGACY_CATALOG_V175=[];
|
|||||||
function wantedBoxNumber(query){const raw=String(query||'').trim();if(!raw)return null;const match=raw.match(/^(?:бокс\s*)?(?:№\s*)?0*(\d+)\s*$/i);return match?Number(match[1]):null}
|
function wantedBoxNumber(query){const raw=String(query||'').trim();if(!raw)return null;const match=raw.match(/^(?:бокс\s*)?(?:№\s*)?0*(\d+)\s*$/i);return match?Number(match[1]):null}
|
||||||
function itemMatches(item,query){if(!query)return true;if(Number(activeCat)===0){const wanted=wantedBoxNumber(query);return wanted!==null&&boxNumber(item)===wanted}const q=query.trim().toLowerCase();const parts=[item.name,item.catalogSection,item.weight,...(Array.isArray(item.composition)?item.composition:[]),...(Array.isArray(item.ingredients)?item.ingredients.map(x=>x?.[0]):[])];return parts.join(' ').toLowerCase().includes(q)}
|
function itemMatches(item,query){if(!query)return true;if(Number(activeCat)===0){const wanted=wantedBoxNumber(query);return wanted!==null&&boxNumber(item)===wanted}const q=query.trim().toLowerCase();const parts=[item.name,item.catalogSection,item.weight,...(Array.isArray(item.composition)?item.composition:[]),...(Array.isArray(item.ingredients)?item.ingredients.map(x=>x?.[0]):[])];return parts.join(' ').toLowerCase().includes(q)}
|
||||||
const BANQUET_CATEGORY=6;
|
const BANQUET_CATEGORY=6;
|
||||||
function banquetCatalog(){return boxes.filter(item=>Number(item.category)===BANQUET_CATEGORY)}
|
function banquetCatalog(){return boxes.filter(item=>item.hidden!==true&&Number(item.category)===BANQUET_CATEGORY)}
|
||||||
window.toggleBanquetItem=id=>{window.CateriumBanquet.toggle(draft,banquetCatalog(),String(id));renderCatalogV5();};
|
window.toggleBanquetItem=id=>{window.CateriumBanquet.toggle(draft,banquetCatalog(),String(id));renderCatalogV5();};
|
||||||
function renderBanquetView(items){return window.CateriumBanquet.render({items,catalog:banquetCatalog(),draft})}
|
function renderBanquetView(items){return window.CateriumBanquet.render({items,catalog:banquetCatalog(),draft})}
|
||||||
function renderCatalogV5(){
|
function renderCatalogV5(){
|
||||||
$('new')?.classList.toggle('sun-banquet-active',Number(activeCat)===BANQUET_CATEGORY);
|
$('new')?.classList.toggle('sun-banquet-active',Number(activeCat)===BANQUET_CATEGORY);
|
||||||
renderCategoryTabs();ensureCatalogTools();const catalogSearch=$('sunCatalogSearch');if(catalogSearch){const boxMode=[0,5].includes(Number(activeCat));catalogSearch.placeholder=boxMode?'Поиск по № бокса':'Поиск по позиции';catalogSearch.inputMode=boxMode?'numeric':'search';}const title=document.querySelector('#new .catalog h1');if(title)title.textContent=catName(activeCat);
|
renderCategoryTabs();ensureCatalogTools();const catalogSearch=$('sunCatalogSearch');if(catalogSearch){const boxMode=[0,5].includes(Number(activeCat));catalogSearch.placeholder=boxMode?'Поиск по № бокса':'Поиск по позиции';catalogSearch.inputMode=boxMode?'numeric':'search';}const title=document.querySelector('#new .catalog h1');if(title)title.textContent=catName(activeCat);
|
||||||
const all=boxes.filter(item=>Number(item.category||0)===Number(activeCat)),items=all.filter(item=>itemMatches(item,catalogQuery));const cat=catById(activeCat)||{name:'Каталог',prep:true};
|
const all=boxes.filter(item=>item.hidden!==true&&Number(item.category||0)===Number(activeCat)),items=all.filter(item=>itemMatches(item,catalogQuery));const cat=catById(activeCat)||{name:'Каталог',prep:true};
|
||||||
if(Number(activeCat)===BANQUET_CATEGORY){$('tiles').innerHTML=renderBanquetView(items);window.CateriumBanquet.bind($('tiles'),{catalog:banquetCatalog(),draft,rerender:renderCatalogV5});renderOrderLines();updateOrderSummary();return;}
|
if(Number(activeCat)===BANQUET_CATEGORY){$('tiles').innerHTML=renderBanquetView(items);window.CateriumBanquet.bind($('tiles'),{catalog:banquetCatalog(),draft,rerender:renderCatalogV5});renderOrderLines();updateOrderSummary();return;}
|
||||||
const cards=items.map(item=>`<button class="tile" type="button" onclick="add('${esc(item.id)}')" title="Добавить в заказ">${item.photo?`<img src="${esc(window.SunSafe.imageAssetSrc(item.photo))}" alt="" loading="lazy" decoding="async" onerror="this.onerror=null;this.src='${window.CateriumBranding.logoHTML()}'">`:("<div class=\"ph\"><img src=\""+window.CateriumBranding.logoHTML()+"\" class=\"sun-ph-logo\" alt=\"Логотип "+window.CateriumBranding.nameHTML()+"\"></div>")}<span>${esc(item.name)}</span>${item.catalogSection?`<small class="tile-section">${esc(item.catalogSection)}</small>`:''}${(item.weight||inferBoxPieces(item))?`<small class="tile-meta">${item.weight?`Вес: ${esc(item.weight)}`:''}${item.weight&&inferBoxPieces(item)?' · ':''}${inferBoxPieces(item)?`${inferBoxPieces(item)} шт.`:''}</small>`:''}<span class="tile-price-wrap"><small class="tile-price">${money(item.price||0)}</small>${Number(item.oldPrice||0)>Number(item.price||0)?`<small class="old-price">${money(item.oldPrice)}</small>`:''}</span>${Number(item.oldPrice||0)>Number(item.price||0)?`<span class="sale-badge">АКЦИЯ</span>`:''}</button>`).join('');
|
const cards=items.map(item=>`<button class="tile" type="button" onclick="add('${esc(item.id)}')" title="Добавить в заказ">${item.photo?`<img src="${esc(window.SunSafe.imageAssetSrc(item.photo))}" alt="" loading="lazy" decoding="async" onerror="this.onerror=null;this.src='${window.CateriumBranding.logoHTML()}'">`:("<div class=\"ph\"><img src=\""+window.CateriumBranding.logoHTML()+"\" class=\"sun-ph-logo\" alt=\"Логотип "+window.CateriumBranding.nameHTML()+"\"></div>")}<span>${esc(item.name)}</span>${item.catalogSection?`<small class="tile-section">${esc(item.catalogSection)}</small>`:''}${(item.weight||inferBoxPieces(item))?`<small class="tile-meta">${item.weight?`Вес: ${esc(item.weight)}`:''}${item.weight&&inferBoxPieces(item)?' · ':''}${inferBoxPieces(item)?`${inferBoxPieces(item)} шт.`:''}</small>`:''}<span class="tile-price-wrap"><small class="tile-price">${money(item.price||0)}</small>${Number(item.oldPrice||0)>Number(item.price||0)?`<small class="old-price">${money(item.oldPrice)}</small>`:''}</span>${Number(item.oldPrice||0)>Number(item.price||0)?`<span class="sale-badge">АКЦИЯ</span>`:''}</button>`).join('');
|
||||||
const addText=Number(activeCat)===0?'Добавить бокс':(Number(activeCat)===5?'Добавить премиум':'Добавить позицию');
|
const addText=Number(activeCat)===0?'Добавить бокс':(Number(activeCat)===5?'Добавить премиум':'Добавить позицию');
|
||||||
@ -452,7 +452,7 @@ window.SUN_LEGACY_CATALOG_V175=[];
|
|||||||
renderOrderLines();updateOrderSummary();
|
renderOrderLines();updateOrderSummary();
|
||||||
}
|
}
|
||||||
window.render=renderCatalogV5;
|
window.render=renderCatalogV5;
|
||||||
window.add=id=>{const item=boxes.find(x=>String(x.id)===String(id));if(!item)return;let line=(draft.lines||[]).find(x=>String(x.id)===String(id));if(line)line.qty=Math.max(0,Number(line.qty||0))+1;else{if(!Array.isArray(draft.lines))draft.lines=[];draft.lines.push({id:item.id,qty:1,price:Math.max(0,Number(item.price||0))})}renderCatalogV5();};
|
window.add=id=>{const item=boxes.find(x=>String(x.id)===String(id));if(!item||item.hidden===true)return;let line=(draft.lines||[]).find(x=>String(x.id)===String(id));if(line)line.qty=Math.max(0,Number(line.qty||0))+1;else{if(!Array.isArray(draft.lines))draft.lines=[];draft.lines.push({id:item.id,qty:1,price:Math.max(0,Number(item.price||0))})}renderCatalogV5();};
|
||||||
window.qty=(id,n)=>{if(!Array.isArray(draft.lines))draft.lines=[];const next=Math.max(0,Number(n||0));if(next<1)draft.lines=draft.lines.filter(x=>String(x.id)!==String(id));else{const line=draft.lines.find(x=>String(x.id)===String(id));if(line)line.qty=next}renderCatalogV5();};
|
window.qty=(id,n)=>{if(!Array.isArray(draft.lines))draft.lines=[];const next=Math.max(0,Number(n||0));if(next<1)draft.lines=draft.lines.filter(x=>String(x.id)!==String(id));else{const line=draft.lines.find(x=>String(x.id)===String(id));if(line)line.qty=next}renderCatalogV5();};
|
||||||
|
|
||||||
function ensureManagerToolbar(){
|
function ensureManagerToolbar(){
|
||||||
@ -461,7 +461,7 @@ window.SUN_LEGACY_CATALOG_V175=[];
|
|||||||
}
|
}
|
||||||
function renderManagerV5(){
|
function renderManagerV5(){
|
||||||
ensureManagerToolbar();const managerSearch=$('sunManagerSearch');if(managerSearch){const boxMode=[0,5].includes(Number(activeCat));managerSearch.placeholder=boxMode?'Поиск по № бокса':'Поиск по позиции';managerSearch.inputMode=boxMode?'numeric':'search';}const title=document.querySelector('#manager .dialog-head h2'),add=document.querySelector('#manager .sun-manager-toolbar .primary')||document.querySelector('#manager .primary');if(title)title.textContent=catName(activeCat);if(add){add.textContent=Number(activeCat)===0?'Добавить бокс':(Number(activeCat)===5?'Добавить премиум':'Добавить позицию');add.onclick=()=>window.editBox(null)}
|
ensureManagerToolbar();const managerSearch=$('sunManagerSearch');if(managerSearch){const boxMode=[0,5].includes(Number(activeCat));managerSearch.placeholder=boxMode?'Поиск по № бокса':'Поиск по позиции';managerSearch.inputMode=boxMode?'numeric':'search';}const title=document.querySelector('#manager .dialog-head h2'),add=document.querySelector('#manager .sun-manager-toolbar .primary')||document.querySelector('#manager .primary');if(title)title.textContent=catName(activeCat);if(add){add.textContent=Number(activeCat)===0?'Добавить бокс':(Number(activeCat)===5?'Добавить премиум':'Добавить позицию');add.onclick=()=>window.editBox(null)}
|
||||||
const items=boxes.filter(i=>Number(i.category||0)===Number(activeCat)&&itemMatches(i,managerQuery)),cat=catById(activeCat)||{prep:true};
|
const items=boxes.filter(i=>i.hidden!==true&&Number(i.category||0)===Number(activeCat)&&itemMatches(i,managerQuery)),cat=catById(activeCat)||{prep:true};
|
||||||
$('managerList').innerHTML=items.length?items.map(item=>`<button type="button" onclick="editBox('${esc(item.id)}')">${item.photo?`<img src="${esc(window.SunSafe.imageAssetSrc(item.photo))}" alt="" loading="lazy" decoding="async" onerror="this.onerror=null;this.src='${window.CateriumBranding.logoHTML()}'">`:("<div class=\"ph\"><img src=\""+window.CateriumBranding.logoHTML()+"\" class=\"sun-ph-logo\" alt=\"Логотип "+window.CateriumBranding.nameHTML()+"\"></div>")}<b>${esc(item.name)}</b><span class="manager-price-wrap"><small class="manager-card-price">${money(item.price||0)}</small>${Number(item.oldPrice||0)>Number(item.price||0)?`<small class="old-price">${money(item.oldPrice)}</small>`:''}</span>${(item.weight||inferBoxPieces(item))?`<small class="manager-card-meta">${item.weight?`Вес: ${esc(item.weight)}`:''}${item.weight&&inferBoxPieces(item)?' · ':''}${inferBoxPieces(item)?`${inferBoxPieces(item)} шт.`:''}</small>`:''}${cat.prep?`<small>${(item.ingredients||[]).length} позиций в составе</small>`:''}</button>`).join(''):'<p class="empty">Ничего не найдено.</p>';
|
$('managerList').innerHTML=items.length?items.map(item=>`<button type="button" onclick="editBox('${esc(item.id)}')">${item.photo?`<img src="${esc(window.SunSafe.imageAssetSrc(item.photo))}" alt="" loading="lazy" decoding="async" onerror="this.onerror=null;this.src='${window.CateriumBranding.logoHTML()}'">`:("<div class=\"ph\"><img src=\""+window.CateriumBranding.logoHTML()+"\" class=\"sun-ph-logo\" alt=\"Логотип "+window.CateriumBranding.nameHTML()+"\"></div>")}<b>${esc(item.name)}</b><span class="manager-price-wrap"><small class="manager-card-price">${money(item.price||0)}</small>${Number(item.oldPrice||0)>Number(item.price||0)?`<small class="old-price">${money(item.oldPrice)}</small>`:''}</span>${(item.weight||inferBoxPieces(item))?`<small class="manager-card-meta">${item.weight?`Вес: ${esc(item.weight)}`:''}${item.weight&&inferBoxPieces(item)?' · ':''}${inferBoxPieces(item)?`${inferBoxPieces(item)} шт.`:''}</small>`:''}${cat.prep?`<small>${(item.ingredients||[]).length} позиций в составе</small>`:''}</button>`).join(''):'<p class="empty">Ничего не найдено.</p>';
|
||||||
}
|
}
|
||||||
window.openManager=()=>{managerQuery='';ensureManagerToolbar();if($('sunManagerSearch'))$('sunManagerSearch').value='';renderManagerV5();window.modal?.('manager');};
|
window.openManager=()=>{managerQuery='';ensureManagerToolbar();if($('sunManagerSearch'))$('sunManagerSearch').value='';renderManagerV5();window.modal?.('manager');};
|
||||||
@ -471,7 +471,7 @@ window.SUN_LEGACY_CATALOG_V175=[];
|
|||||||
const cat=catById(edited.category)||{name:'Каталог',prep:true};$('editTitle').textContent=edited.id?`Изменить: ${cat.name}`:(Number(edited.category)===0?'Новый бокс':(Number(edited.category)===5?'Новая премиум позиция':'Новая позиция'));const zone=document.querySelector('#editor .ingredient-zone');if(zone)zone.style.display=cat.prep?'block':'none';window.renderIngredients?.();window.modal?.('editor');
|
const cat=catById(edited.category)||{name:'Каталог',prep:true};$('editTitle').textContent=edited.id?`Изменить: ${cat.name}`:(Number(edited.category)===0?'Новый бокс':(Number(edited.category)===5?'Новая премиум позиция':'Новая позиция'));const zone=document.querySelector('#editor .ingredient-zone');if(zone)zone.style.display=cat.prep?'block':'none';window.renderIngredients?.();window.modal?.('editor');
|
||||||
};
|
};
|
||||||
if($('itemCategory'))$('itemCategory').onchange=function(){if(!edited)return;edited.category=Number(this.value);const c=catById(edited.category)||{name:'Каталог',prep:true};const zone=document.querySelector('#editor .ingredient-zone');if(zone)zone.style.display=c.prep?'block':'none';syncBoxWeightEditor(edited.category,edited);syncBanquetEditor(edited.category,edited);$('editTitle').textContent=edited.id?`Изменить: ${c.name}`:(Number(edited.category)===0?'Новый бокс':(Number(edited.category)===5?'Новая премиум позиция':'Новая позиция'));};
|
if($('itemCategory'))$('itemCategory').onchange=function(){if(!edited)return;edited.category=Number(this.value);const c=catById(edited.category)||{name:'Каталог',prep:true};const zone=document.querySelector('#editor .ingredient-zone');if(zone)zone.style.display=c.prep?'block':'none';syncBoxWeightEditor(edited.category,edited);syncBanquetEditor(edited.category,edited);$('editTitle').textContent=edited.id?`Изменить: ${c.name}`:(Number(edited.category)===0?'Новый бокс':(Number(edited.category)===5?'Новая премиум позиция':'Новая позиция'));};
|
||||||
window.saveBox=()=>{if(!edited)return;edited.name=$('boxName').value.trim();edited.price=Math.max(0,Number($('boxPrice').value||0));edited.oldPrice=Math.max(0,Number($('boxOldPrice')?.value||0));if(!(edited.oldPrice>edited.price))delete edited.oldPrice;edited.sale=Boolean(edited.oldPrice&&edited.oldPrice>edited.price);edited.category=Number($('itemCategory').value);if([0,5].includes(edited.category)){const grams=Math.max(0,Math.round(Number($('boxWeightGrams')?.value||0)));edited.weight=grams?`${grams} г`:'';edited.pieces=Math.max(0,Math.round(Number($('boxPiecesCount')?.value||0)));}if(edited.category===BANQUET_CATEGORY){edited.catalogSection=($('banquetSection')?.value||'').trim();const grams=Math.max(0,Math.round(Number($('banquetWeightGrams')?.value||0)));edited.weight=grams?`${grams} г`:'';}window.CateriumBanquet?.saveEditor(edited,boxes.filter(i=>Number(i.category)===6));edited.ingredients=Array.isArray(edited.ingredients)?edited.ingredients:[];if([0,5].includes(edited.category)&&$('boxCompositionText')){const next=$('boxCompositionText').value.split(/\r?\n/).map(x=>x.trim()).filter(Boolean);const before=JSON.stringify(Array.isArray(edited.composition)?edited.composition:[]);edited.composition=next;if(JSON.stringify(next)!==before)edited.compositionSource='manual';}normalizeBoxItem(edited,{cleanup:true});if(!edited.name)return alert('Введите название.');if(!edited.id){edited.id=(typeof sunUUID==='function'?sunUUID():`item-${Date.now()}`);boxes.push(edited)}else{const i=boxes.findIndex(x=>String(x.id)===String(edited.id));if(i>=0)boxes[i]=edited}if(!catById(edited.category)?.hidden)activeCat=edited.category;persist();closeModal('editor');closeModal('manager');renderCatalogV5();renderOrders?.();window.sunClientOfferCatalogChanged?.(edited.id);};
|
window.saveBox=()=>{if(!edited)return;edited.name=$('boxName').value.trim();edited.price=Math.max(0,Number($('boxPrice').value||0));edited.oldPrice=Math.max(0,Number($('boxOldPrice')?.value||0));if(!(edited.oldPrice>edited.price))delete edited.oldPrice;edited.sale=Boolean(edited.oldPrice&&edited.oldPrice>edited.price);edited.category=Number($('itemCategory').value);if([0,5].includes(edited.category)){const grams=Math.max(0,Math.round(Number($('boxWeightGrams')?.value||0)));edited.weight=grams?`${grams} г`:'';edited.pieces=Math.max(0,Math.round(Number($('boxPiecesCount')?.value||0)));}if(edited.category===BANQUET_CATEGORY){edited.catalogSection=($('banquetSection')?.value||'').trim();const grams=Math.max(0,Math.round(Number($('banquetWeightGrams')?.value||0)));edited.weight=grams?`${grams} г`:'';}window.CateriumBanquet?.saveEditor(edited,boxes.filter(i=>i.hidden!==true&&Number(i.category)===6));edited.ingredients=Array.isArray(edited.ingredients)?edited.ingredients:[];if([0,5].includes(edited.category)&&$('boxCompositionText')){const next=$('boxCompositionText').value.split(/\r?\n/).map(x=>x.trim()).filter(Boolean);const before=JSON.stringify(Array.isArray(edited.composition)?edited.composition:[]);edited.composition=next;if(JSON.stringify(next)!==before)edited.compositionSource='manual';}normalizeBoxItem(edited,{cleanup:true});if(!edited.name)return alert('Введите название.');if(!edited.id){edited.id=(typeof sunUUID==='function'?sunUUID():`item-${Date.now()}`);boxes.push(edited)}else{const i=boxes.findIndex(x=>String(x.id)===String(edited.id));if(i>=0)boxes[i]=edited}if(!catById(edited.category)?.hidden)activeCat=edited.category;persist();closeModal('editor');closeModal('manager');renderCatalogV5();renderOrders?.();window.sunClientOfferCatalogChanged?.(edited.id);};
|
||||||
window.removeBox=()=>{if(!edited?.id||!confirm(`Удалить «${edited.name}» из каталога?`))return;boxes=boxes.filter(x=>String(x.id)!==String(edited.id));draft.lines=(draft.lines||[]).filter(x=>String(x.id)!==String(edited.id));persist();closeModal('editor');closeModal('manager');renderCatalogV5();renderOrders?.();};
|
window.removeBox=()=>{if(!edited?.id||!confirm(`Удалить «${edited.name}» из каталога?`))return;boxes=boxes.filter(x=>String(x.id)!==String(edited.id));draft.lines=(draft.lines||[]).filter(x=>String(x.id)!==String(edited.id));persist();closeModal('editor');closeModal('manager');renderCatalogV5();renderOrders?.();};
|
||||||
|
|
||||||
function fileAsDataUrl(file){return new Promise((resolve,reject)=>{const reader=new FileReader();reader.onerror=()=>reject(reader.error||new Error('FileReader error'));reader.onload=()=>resolve(String(reader.result||''));reader.readAsDataURL(file)})}
|
function fileAsDataUrl(file){return new Promise((resolve,reject)=>{const reader=new FileReader();reader.onerror=()=>reject(reader.error||new Error('FileReader error'));reader.onload=()=>resolve(String(reader.result||''));reader.readAsDataURL(file)})}
|
||||||
|
|||||||
@ -1,29 +1,12 @@
|
|||||||
(()=>{
|
(()=>{
|
||||||
'use strict';
|
'use strict';
|
||||||
if(window.CateriumImportArchive)return;
|
// The one-time import is complete. Keep this cleanup entry point for old caches.
|
||||||
const KEY='sunTelegramImportArchiveV1';
|
// Source details attached to individual orders remain available in order history.
|
||||||
let dialog=null;
|
function removeArchiveUI(){
|
||||||
const read=()=>{try{return JSON.parse(localStorage.getItem(KEY)||'null')}catch(_){return null}};
|
document.querySelectorAll('#cateriumTelegramArchive,dialog[aria-label="Архив заказов из Telegram"]').forEach(el=>el.remove());
|
||||||
const node=(tag,text)=>{const e=document.createElement(tag);if(text!==undefined)e.textContent=String(text);return e};
|
|
||||||
function close(){dialog?.remove();dialog=null}
|
|
||||||
function show(){
|
|
||||||
const archive=read();if(!archive)return;close();
|
|
||||||
dialog=node('dialog');dialog.setAttribute('aria-label','Архив заказов из Telegram');dialog.style.cssText='width:min(900px,94vw);max-height:88vh;overflow:auto;border:1px solid #ccd2d6;border-radius:16px;padding:24px';
|
|
||||||
const top=node('div');top.style.cssText='display:flex;justify-content:space-between;gap:20px';top.append(node('h2','Исходный архив Telegram'));const exit=node('button','Закрыть');exit.onclick=close;top.append(exit);dialog.append(top);
|
|
||||||
dialog.append(node('p',`${archive.orderCount} заказов · ${archive.clientCount} клиентов. Цены и платежи сохранены по исходным сообщениям. Неуказанная оплата не подтверждает долг. Автоматическое закрытие импортированных заказов отключено.`));
|
|
||||||
const search=node('input');search.type='search';search.placeholder='Номер заказа, имя, телефон или адрес';search.setAttribute('aria-label','Поиск в архиве');search.style.cssText='width:100%;padding:12px;margin:8px 0';dialog.append(search);
|
|
||||||
const list=node('div');dialog.append(list);
|
|
||||||
const render=()=>{list.replaceChildren();const q=search.value.toLocaleLowerCase('ru');for(const message of archive.messages||[]){if(q&&!`${message.id} ${message.text} ${message.transcription||''}`.toLocaleLowerCase('ru').includes(q))continue;const d=node('details');d.style.cssText='padding:10px 0;border-bottom:1px solid #ddd';d.append(node('summary',`${message.sentAt} · ${message.id} · ${(message.text||'Фотография').split('\n')[0]}`));const pre=node('pre',message.text);pre.style.cssText='white-space:pre-wrap;overflow-wrap:anywhere;font:inherit';d.append(pre);if(message.transcription)d.append(node('p',message.transcription));for(const a of archive.attachments||[]){if(a.messageId!==message.id||!/^data:image\/(?:jpeg|png|webp);base64,[A-Za-z0-9+/=]+$/.test(a.data||''))continue;const img=node('img');img.src=a.data;img.alt=a.href;img.loading='lazy';img.style.cssText='display:block;max-width:100%;max-height:80vh;object-fit:contain';d.append(img);}list.append(d);}};
|
|
||||||
search.oninput=render;render();document.body.append(dialog);dialog.showModal();dialog.addEventListener('close',close);
|
|
||||||
}
|
}
|
||||||
function install(){
|
window.CateriumImportArchive={show:removeArchiveUI,refresh:removeArchiveUI};
|
||||||
const archive=read(),ordersView=document.getElementById('orders');let b=document.getElementById('cateriumTelegramArchive');
|
window.addEventListener('sun:cloud-state-applied',removeArchiveUI);
|
||||||
if(!archive){b?.remove();return}if(!ordersView||b)return;
|
window.addEventListener('sun:cloud-permissions-changed',removeArchiveUI);
|
||||||
b=node('button','Исходный архив Telegram');b.id='cateriumTelegramArchive';b.type='button';b.className='outline';b.onclick=show;
|
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',removeArchiveUI,{once:true});else removeArchiveUI();
|
||||||
const anchor=ordersView.querySelector('h1');if(anchor)anchor.insertAdjacentElement('afterend',b);else ordersView.prepend(b);
|
|
||||||
}
|
|
||||||
window.CateriumImportArchive={show,refresh:install};
|
|
||||||
window.addEventListener('sun:cloud-state-applied',()=>{close();install()});
|
|
||||||
window.addEventListener('sun:cloud-permissions-changed',()=>{close();install()});
|
|
||||||
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',install,{once:true});else install();
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@ -119,7 +119,7 @@
|
|||||||
let originalModal=null,originalCloseModal=null,originalSaveBox=null,originalRemoveBox=null;
|
let originalModal=null,originalCloseModal=null,originalSaveBox=null,originalRemoveBox=null;
|
||||||
function menuCanEdit(){if(support())return false;const c=cloud();if(!c?.getSession?.()?.user)return true;return can('catalog.edit')}
|
function menuCanEdit(){if(support())return false;const c=cloud();if(!c?.getSession?.()?.user)return true;return can('catalog.edit')}
|
||||||
function currentCategory(){return CATEGORIES.find(x=>x.id===menuCategory)||CATEGORIES[0]}
|
function currentCategory(){return CATEGORIES.find(x=>x.id===menuCategory)||CATEGORIES[0]}
|
||||||
function menuItems(){const q=menuQuery.trim().toLowerCase();return boxes().filter(x=>Number(x.category||0)===menuCategory&&(!q||[x.name,x.weight,x.catalogSection,...(x.composition||[])].join(' ').toLowerCase().includes(q)))}
|
function menuItems(){const q=menuQuery.trim().toLowerCase();return boxes().filter(x=>x.hidden!==true&&Number(x.category||0)===menuCategory&&(!q||[x.name,x.weight,x.catalogSection,...(x.composition||[])].join(' ').toLowerCase().includes(q)))}
|
||||||
function restoreEditorDialog(){if(editorHome&&editorDialog&&editorDialog.parentNode!==editorHome){editorHome.appendChild(editorDialog);editorDialog.classList.remove('sun-menu-editor-docked');}editorHome?.classList.remove('on');}
|
function restoreEditorDialog(){if(editorHome&&editorDialog&&editorDialog.parentNode!==editorHome){editorHome.appendChild(editorDialog);editorDialog.classList.remove('sun-menu-editor-docked');}editorHome?.classList.remove('on');}
|
||||||
function emptyMenuDetail(text='Выберите позицию слева, чтобы открыть карточку.'){
|
function emptyMenuDetail(text='Выберите позицию слева, чтобы открыть карточку.'){
|
||||||
const pane=$('sunMenuDetailV1762');if(!pane)return;restoreEditorDialog();pane.innerHTML=`<div class="sun-menu-detail-placeholder"><div><b>${esc(text)}</b>${!menuCanEdit()?'<div class="sun-menu-readonly-badge" style="margin-top:9px">только просмотр</div>':''}</div></div>`;
|
const pane=$('sunMenuDetailV1762');if(!pane)return;restoreEditorDialog();pane.innerHTML=`<div class="sun-menu-detail-placeholder"><div><b>${esc(text)}</b>${!menuCanEdit()?'<div class="sun-menu-readonly-badge" style="margin-top:9px">только просмотр</div>':''}</div></div>`;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
(()=>{
|
(()=>{
|
||||||
'use strict';
|
'use strict';
|
||||||
const VERSION='17.7.3';
|
const VERSION='17.7.3';
|
||||||
const RELEASE='20260918-proposals-six';
|
const RELEASE='20260918-import-cleanup';
|
||||||
|
|
||||||
const hasStoredSession=()=>{try{return Object.keys(localStorage).some(k=>/^sb-.*-auth-token$/i.test(k)&&String(localStorage.getItem(k)||'').length>20)}catch(_){return false}};
|
const hasStoredSession=()=>{try{return Object.keys(localStorage).some(k=>/^sb-.*-auth-token$/i.test(k)&&String(localStorage.getItem(k)||'').length>20)}catch(_){return false}};
|
||||||
function installAuthBoot(){
|
function installAuthBoot(){
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1,5 +1,5 @@
|
|||||||
const CACHE='sun-catering-pwa-v106-20260918-proposals-six';
|
const CACHE='sun-catering-pwa-v107-20260918-import-cleanup';
|
||||||
const VERSION='20260918-proposals-six';
|
const VERSION='20260918-import-cleanup';
|
||||||
const CORE=[
|
const CORE=[
|
||||||
'./vendor/supabase-2.112.4.min.js',
|
'./vendor/supabase-2.112.4.min.js',
|
||||||
`./core/help-center.js?v=${VERSION}`,`./core/help-center.css?v=${VERSION}`,`./help/knowledge-v1.json?v=${VERSION}`,
|
`./core/help-center.js?v=${VERSION}`,`./core/help-center.css?v=${VERSION}`,`./help/knowledge-v1.json?v=${VERSION}`,
|
||||||
|
|||||||
@ -39,17 +39,56 @@ test('imported history keeps partial payments and delivery is charged once after
|
|||||||
expect(result).toEqual({shown:7500,total:7500,prepayment:2000,status:'Новый',flag:true,rows:1});
|
expect(result).toEqual({shown:7500,total:7500,prepayment:2000,status:'Новый',flag:true,rows:1});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('private import archive safely shows messages and clears on workspace change',async({page})=>{
|
test('completed import archive stays removed even with an old cached payload',async({page})=>{
|
||||||
await page.route('**/index.html',r=>r.fulfill({contentType:'text/html',body:'<html><body><section id="orders"><h1>Заказы</h1></section></body></html>'}));
|
await page.route('**/index.html',r=>r.fulfill({contentType:'text/html; charset=utf-8',body:'<html><body><section id="orders"><h1>Заказы</h1><button id="cateriumTelegramArchive">Исходный архив Telegram</button></section><dialog aria-label="Архив заказов из Telegram"></dialog></body></html>'}));
|
||||||
await page.goto('/index.html');
|
await page.goto('/index.html');
|
||||||
await page.evaluate(()=>localStorage.setItem('sunTelegramImportArchiveV1',JSON.stringify({orderCount:1,clientCount:1,messages:[{id:'message1',sentAt:'01.01.2026',text:'Заказ <img src=x onerror=alert(1)>\nАдрес: тест'}],attachments:[]})));
|
await page.evaluate(()=>localStorage.setItem('sunTelegramImportArchiveV1',JSON.stringify({orderCount:1,clientCount:1,messages:[{id:'message1',sentAt:'01.01.2026',text:'Заказ <img src=x onerror=alert(1)>\nАдрес: тест'}],attachments:[]})));
|
||||||
await page.addScriptTag({url:'/core/import-archive.js'});
|
await page.addScriptTag({url:'/core/import-archive.js'});
|
||||||
await page.getByRole('button',{name:'Исходный архив Telegram'}).click();
|
await page.evaluate(()=>{
|
||||||
await page.getByRole('searchbox').fill('Адрес');
|
window.CateriumImportArchive.show();window.CateriumImportArchive.refresh();
|
||||||
await page.locator('summary').click();
|
window.dispatchEvent(new Event('sun:cloud-state-applied'));
|
||||||
await expect(page.locator('dialog pre')).toContainText('<img src=x');
|
window.dispatchEvent(new Event('sun:cloud-permissions-changed'));
|
||||||
expect(await page.locator('dialog img').count()).toBe(0);
|
});
|
||||||
await page.evaluate(()=>{localStorage.removeItem('sunTelegramImportArchiveV1');window.dispatchEvent(new Event('sun:cloud-state-applied'))});
|
|
||||||
expect(await page.locator('dialog').count()).toBe(0);
|
expect(await page.locator('dialog').count()).toBe(0);
|
||||||
expect(await page.locator('#cateriumTelegramArchive').count()).toBe(0);
|
expect(await page.locator('#cateriumTelegramArchive').count()).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('retired import positions leave the working catalogs but preserve historical orders and proposals',async({page})=>{
|
||||||
|
test.setTimeout(45000);
|
||||||
|
await page.route('https://**',r=>r.abort());
|
||||||
|
await page.goto('/index.html',{waitUntil:'domcontentloaded'});
|
||||||
|
await page.waitForFunction(()=>window.SunOpsUXV1762&&window.sunClientOfferDebugCreateSnapshot&&window.__cateriumOrderEnhancementsV1775);
|
||||||
|
await page.evaluate(()=>{
|
||||||
|
boxes=[{id:'5',name:'Фуршетный бокс №5',price:4900,category:0,photo:'',ingredients:[]},
|
||||||
|
{id:'tg-item-fixture',name:'Фуршетный набор 8 — Салаты в шотах',price:3900,category:0,hidden:true,catalogSection:'Импорт из Telegram',photo:'',ingredients:[]}];
|
||||||
|
orders=[{id:900002,event:'История импорта',date:'2026-09-10',time:'12:00',contact:'Тестовый клиент',phone:'+79990000000',address:'Тестовая улица, 1',note:'Исходные сведения',status:'Новый',lines:[{id:'tg-item-fixture',qty:2,price:3500}],total:7000,prepayment:7000,paymentStatus:'paid',autoCompletionDisabled:true}];
|
||||||
|
draft.lines=[];persist();window.render();
|
||||||
|
});
|
||||||
|
await expect(page.locator('#tiles')).toContainText('Фуршетный бокс №5');
|
||||||
|
await expect(page.locator('#tiles')).not.toContainText('Салаты в шотах');
|
||||||
|
await page.evaluate(()=>{window.add('tg-item-fixture');window.openManager()});
|
||||||
|
expect(await page.evaluate(()=>draft.lines.length)).toBe(0);
|
||||||
|
await expect(page.locator('#managerList')).not.toContainText('Салаты в шотах');
|
||||||
|
await page.evaluate(()=>{window.closeModal('manager');window.SunOpsUXV1762.openMenu()});
|
||||||
|
await expect(page.locator('#sunMenuCountV1762')).toHaveText('1 поз.');
|
||||||
|
await expect(page.locator('#sunMenuListV1762')).not.toContainText('Импорт из Telegram');
|
||||||
|
await page.evaluate(()=>{const input=document.getElementById('sunGlobalSearchInput');input.value='Салаты в шотах';input.dispatchEvent(new Event('input'))});
|
||||||
|
expect(await page.locator('#sunGlobalSearchResults [data-action="box"]').count()).toBe(0);
|
||||||
|
const catalog=await page.evaluate(async()=>{
|
||||||
|
window.print=()=>{};await window.sunPrintLiveCatalog();
|
||||||
|
const text=document.getElementById('sunLiveCatalogPrintRoot').textContent;
|
||||||
|
const pages=await window.sunCatalogDebugPdfPages(0,10);
|
||||||
|
return {text,pages:pages.length};
|
||||||
|
});
|
||||||
|
expect(catalog.text).toContain('Фуршетный бокс №5');expect(catalog.text).not.toContain('Салаты в шотах');expect(catalog.pages).toBe(1);
|
||||||
|
await page.evaluate(()=>window.openOrder(900002));
|
||||||
|
await expect(page.locator('#lines')).toContainText('Салаты в шотах');
|
||||||
|
await expect(page.locator('#orderTotal')).toHaveValue('7000');
|
||||||
|
await expect(page.locator('#phone')).toHaveValue('+79990000000');
|
||||||
|
const snapshot=await page.evaluate(()=>window.sunClientOfferDebugCreateSnapshot(orders[0]));
|
||||||
|
expect(snapshot.items).toHaveLength(1);expect(snapshot.items[0]).toMatchObject({name:'Фуршетный набор 8 — Салаты в шотах',qty:2,unitPrice:3500,sum:7000});
|
||||||
|
expect(await page.evaluate(()=>window.sunOrderPaymentState(orders[0]))).toBe('paid');
|
||||||
|
await page.reload();await page.waitForFunction(()=>window.SunOpsUXV1762);
|
||||||
|
await expect(page.locator('#tiles')).not.toContainText('Салаты в шотах');
|
||||||
|
expect(await page.evaluate(()=>({hidden:boxes.find(b=>b.id==='tg-item-fixture').hidden,lines:orders[0].lines.length,address:orders[0].address}))).toEqual({hidden:true,lines:1,address:'Тестовая улица, 1'});
|
||||||
|
});
|
||||||
|
|||||||
@ -14,8 +14,8 @@ check(!index.includes('offer-gallery-data.js'),'blocking Base64 gallery absent')
|
|||||||
check((runtime.match(/\/Type \/Catalog/g)||[]).length===0,'runtime contains no PDF binary writer');
|
check((runtime.match(/\/Type \/Catalog/g)||[]).length===0,'runtime contains no PDF binary writer');
|
||||||
check(read('core/pdf-engine.js').includes('595.28')&&read('core/pdf-engine.js').includes('841.89'),'PDF engine uses A4 MediaBox');
|
check(read('core/pdf-engine.js').includes('595.28')&&read('core/pdf-engine.js').includes('841.89'),'PDF engine uses A4 MediaBox');
|
||||||
check([...index.matchAll(/@page\{([^}]*)\}/g)].every(m=>/size:A4/i.test(m[1])),'compact @page rules use A4');
|
check([...index.matchAll(/@page\{([^}]*)\}/g)].every(m=>/size:A4/i.test(m[1])),'compact @page rules use A4');
|
||||||
check(sw.includes('v106-20260918-proposals-six')&&sw.includes('data-layer-v1773.js')&&sw.includes('server-automation-v1770.js')&&sw.includes('offer-workspace-v1769.js'),'service worker cache is v17.7.3');
|
check(sw.includes('v107-20260918-import-cleanup')&&sw.includes('data-layer-v1773.js')&&sw.includes('server-automation-v1770.js')&&sw.includes('offer-workspace-v1769.js'),'service worker cache is v17.7.3');
|
||||||
check(index.includes('20260918-proposals-six')&&index.includes('classic-offer-pdf-v1767.js')&&!index.includes('20260907-v17-6-0-stability-security'),'index cache-busting points to v17.7.3');
|
check(index.includes('20260918-import-cleanup')&&index.includes('classic-offer-pdf-v1767.js')&&!index.includes('20260907-v17-6-0-stability-security'),'index cache-busting points to v17.7.3');
|
||||||
check(performance.includes('SunAttachmentGuard')&&performance.includes('TARGET=2*1024*1024'),'chat photo auto-compression is versioned');
|
check(performance.includes('SunAttachmentGuard')&&performance.includes('TARGET=2*1024*1024'),'chat photo auto-compression is versioned');
|
||||||
check(performance.includes("rpc('sun_dev_dashboard')")&&performance.includes('server_size')&&performance.includes('storage_size'),'Developer Console server/storage counters are versioned');
|
check(performance.includes("rpc('sun_dev_dashboard')")&&performance.includes('server_size')&&performance.includes('storage_size'),'Developer Console server/storage counters are versioned');
|
||||||
check(performance.includes('MEMORY_REFRESH_MS=30000')&&performance.includes('MEMORY_TIMEOUT_MS=8000')&&performance.includes('memoryPromise'),'Developer Console memory refresh is bounded');
|
check(performance.includes('MEMORY_REFRESH_MS=30000')&&performance.includes('MEMORY_TIMEOUT_MS=8000')&&performance.includes('memoryPromise'),'Developer Console memory refresh is bounded');
|
||||||
@ -39,7 +39,7 @@ check(!/sb_secret_[A-Za-z0-9_-]{20,}|service_role\s*[:=]\s*["'][A-Za-z0-9._-]{30
|
|||||||
check(lock.version===pkg.version&&lock.packages?.['']?.version===pkg.version,'package.json and package-lock.json versions match');
|
check(lock.version===pkg.version&&lock.packages?.['']?.version===pkg.version,'package.json and package-lock.json versions match');
|
||||||
check(releaseManifest.version===`v${pkg.version}`,'release manifest version matches package.json');
|
check(releaseManifest.version===`v${pkg.version}`,'release manifest version matches package.json');
|
||||||
check(releaseManifest.channel==='production','release manifest channel is production');
|
check(releaseManifest.channel==='production','release manifest channel is production');
|
||||||
check(String(releaseManifest.pwaCache||'').includes('v106-20260918-proposals-six'),'release manifest points to current PWA cache');
|
check(String(releaseManifest.pwaCache||'').includes('v107-20260918-import-cleanup'),'release manifest points to current PWA cache');
|
||||||
check(['17.6.2','17.6.3','17.6.4','17.6.5','17.6.6','17.6.7','17.6.8','17.6.9','17.7.0','17.7.1','17.7.2','17.7.3'].every(v=>fs.existsSync(path.join(root,`docs/releases/V${v}-CHANGES.txt`))),'release notes exist through v17.7.3');
|
check(['17.6.2','17.6.3','17.6.4','17.6.5','17.6.6','17.6.7','17.6.8','17.6.9','17.7.0','17.7.1','17.7.2','17.7.3'].every(v=>fs.existsSync(path.join(root,`docs/releases/V${v}-CHANGES.txt`))),'release notes exist through v17.7.3');
|
||||||
check(runtime.includes('CLOUD_RPC_TIMEOUT_MS=45000')&&runtime.includes('CLOUD_CONFLICT_MAX_RETRIES=4')&&runtime.includes('retryCount'),'cloud sync has timeout and capped exponential conflict retries');
|
check(runtime.includes('CLOUD_RPC_TIMEOUT_MS=45000')&&runtime.includes('CLOUD_CONFLICT_MAX_RETRIES=4')&&runtime.includes('retryCount'),'cloud sync has timeout and capped exponential conflict retries');
|
||||||
check(runtime.includes("const VERSION = '17.7.3'")&&runtime.includes('ERROR_DEDUPE_MS=5*60*1000')&&runtime.includes('mirrorBusy=false')&&runtime.includes('backupBusy=false'),'stability logger uses current version, dedupe and single-flight guards');
|
check(runtime.includes("const VERSION = '17.7.3'")&&runtime.includes('ERROR_DEDUPE_MS=5*60*1000')&&runtime.includes('mirrorBusy=false')&&runtime.includes('backupBusy=false'),'stability logger uses current version, dedupe and single-flight guards');
|
||||||
@ -65,8 +65,8 @@ check(offerWorkspace.includes('PDF и предпросмотр')&&offerWorkspace
|
|||||||
check(offerWorkspace.includes('SunClassicOfferPDFV1767')&&offerWorkspace.includes('finalGallery=galleryFor'),'custom gallery is injected into PDF renderer');
|
check(offerWorkspace.includes('SunClassicOfferPDFV1767')&&offerWorkspace.includes('finalGallery=galleryFor'),'custom gallery is injected into PDF renderer');
|
||||||
check(releaseManifest.offerWorkspaceTabs===true&&releaseManifest.offerTemplatesSeparateTab===true&&releaseManifest.offerTwoCustomGalleryPhotos===true,'release manifest records offer workspace changes');
|
check(releaseManifest.offerWorkspaceTabs===true&&releaseManifest.offerTemplatesSeparateTab===true&&releaseManifest.offerTwoCustomGalleryPhotos===true,'release manifest records offer workspace changes');
|
||||||
check(pkg.version==='17.7.3','package version is v17.7.3');
|
check(pkg.version==='17.7.3','package version is v17.7.3');
|
||||||
check(index.includes('20260918-proposals-six'),'index cache bust is v17.7.3');
|
check(index.includes('20260918-import-cleanup'),'index cache bust is v17.7.3');
|
||||||
check(sw.includes('v106-20260918-proposals-six')&&sw.includes('data-layer-v1773.js')&&sw.includes('server-automation-v1770.js'),'PWA caches v17.7.3 client foundation modules');
|
check(sw.includes('v107-20260918-import-cleanup')&&sw.includes('data-layer-v1773.js')&&sw.includes('server-automation-v1770.js'),'PWA caches v17.7.3 client foundation modules');
|
||||||
check(fs.existsSync(path.join(root,'public/core/data-layer-v1773.js'))&&fs.existsSync(path.join(root,'public/core/server-automation-v1770.js')),'data layer and server automation modules exist');
|
check(fs.existsSync(path.join(root,'public/core/data-layer-v1773.js'))&&fs.existsSync(path.join(root,'public/core/server-automation-v1770.js')),'data layer and server automation modules exist');
|
||||||
check(ux.includes('CateriumServerAutomationV1770?.enabled'),'cloud browser auto completion is disabled when server automation is active');
|
check(ux.includes('CateriumServerAutomationV1770?.enabled'),'cloud browser auto completion is disabled when server automation is active');
|
||||||
check(runtime.includes("const VERSION = '17.7.3'")&&runtime.includes("v17.7.3 Clients Server Read"),'stability logger reports v17.7.3');
|
check(runtime.includes("const VERSION = '17.7.3'")&&runtime.includes("v17.7.3 Clients Server Read"),'stability logger reports v17.7.3');
|
||||||
|
|||||||
@ -28,8 +28,8 @@ if(current!==113)fail(`current catalog photo count ${current}, expected 113`);el
|
|||||||
if(legacyCount!==60)fail(`legacy catalog photo count ${legacyCount}, expected 60`);else ok('60 legacy catalog photos');
|
if(legacyCount!==60)fail(`legacy catalog photo count ${legacyCount}, expected 60`);else ok('60 legacy catalog photos');
|
||||||
const gallery=fs.readdirSync(path.join(pub,'offer-gallery')).filter(x=>/\.jpg$/i.test(x));
|
const gallery=fs.readdirSync(path.join(pub,'offer-gallery')).filter(x=>/\.jpg$/i.test(x));
|
||||||
if(gallery.length!==2)fail(`offer gallery contains ${gallery.length} jpg files, expected 2`);else ok('offer gallery trimmed');
|
if(gallery.length!==2)fail(`offer gallery contains ${gallery.length} jpg files, expected 2`);else ok('offer gallery trimmed');
|
||||||
if(!sw.includes('20260918-proposals-six')||!sw.includes('login-signature-v1776.js')||!sw.includes('data-layer-v1773.js')||!sw.includes('server-automation-v1770.js')||!sw.includes('offer-workspace-v1769.js')||sw.includes('offer-gallery-data.js'))fail('service worker cache is stale');else ok('PWA cache updated for login refresh');
|
if(!sw.includes('20260918-import-cleanup')||!sw.includes('login-signature-v1776.js')||!sw.includes('data-layer-v1773.js')||!sw.includes('server-automation-v1770.js')||!sw.includes('offer-workspace-v1769.js')||sw.includes('offer-gallery-data.js'))fail('service worker cache is stale');else ok('PWA cache updated for login refresh');
|
||||||
if(html.includes('20260907-v17-6-0-stability-security')||html.includes('20260909-v17-7-3-clients-server-read')||!html.includes('20260918-proposals-six')||!html.includes('classic-offer-pdf-v1767.js'))fail('index still serves stale core asset version');else ok('index cache-busting is current');
|
if(html.includes('20260907-v17-6-0-stability-security')||html.includes('20260909-v17-7-3-clients-server-read')||!html.includes('20260918-import-cleanup')||!html.includes('classic-offer-pdf-v1767.js'))fail('index still serves stale core asset version');else ok('index cache-busting is current');
|
||||||
if(!performance.includes('SunAttachmentGuard')||!performance.includes('MAX_SIDE=2048'))fail('chat photo compression guard missing');else ok('chat photo compression guard present');
|
if(!performance.includes('SunAttachmentGuard')||!performance.includes('MAX_SIDE=2048'))fail('chat photo compression guard missing');else ok('chat photo compression guard present');
|
||||||
if(!performance.includes("rpc('sun_dev_dashboard')")||!performance.includes('storage_size')||!performance.includes('server_size'))fail('Developer Console memory counters missing');else ok('Developer Console memory counters present');
|
if(!performance.includes("rpc('sun_dev_dashboard')")||!performance.includes('storage_size')||!performance.includes('server_size'))fail('Developer Console memory counters missing');else ok('Developer Console memory counters present');
|
||||||
if(performance.includes('records.forEach(r=>r.addedNodes.forEach(n=>{if(n.nodeType===1)scan(n)}));enhanceDeveloperMemory()'))fail('Developer Console memory refresh is still coupled to MutationObserver');else ok('Developer Console memory refresh loop removed');
|
if(performance.includes('records.forEach(r=>r.addedNodes.forEach(n=>{if(n.nodeType===1)scan(n)}));enhanceDeveloperMemory()'))fail('Developer Console memory refresh is still coupled to MutationObserver');else ok('Developer Console memory refresh loop removed');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user