167 lines
8.4 KiB
JavaScript
167 lines
8.4 KiB
JavaScript
/* Checkout bridge only: approved commercial functions in web/index.html stay intact. */
|
|
(() => {
|
|
const status = document.getElementById('checkoutStatus');
|
|
const actions = document.getElementById('checkoutActions');
|
|
let busy = false;
|
|
let draftId = localStorage.getItem('dtf-quote');
|
|
let requestKey = localStorage.getItem('dtf-request-key');
|
|
let requestBody = localStorage.getItem('dtf-request-body');
|
|
let quotedCart = localStorage.getItem('dtf-quote-cart');
|
|
let refreshVersion = 0;
|
|
function cartSnapshot() {
|
|
const items=[...pedido,...(itemAtual?[itemAtual]:[])];
|
|
return JSON.stringify({customer:cliente,delivery:entrega,items:items.map(item=>({
|
|
mode:item.modo,metres:item.metros,grade:item.nota,production:item.production,
|
|
quality:item.qualityStatus,
|
|
acknowledged:item.qualityAcknowledged,
|
|
files:(item.localFiles||[]).map(file=>({name:file.name,size:file.size,lastModified:file.lastModified}))
|
|
}))});
|
|
}
|
|
function clearDraft() {
|
|
draftId=null;quotedCart=null;requestKey=null;requestBody=null;
|
|
for(const key of ['dtf-quote','dtf-quote-cart','dtf-request-key','dtf-request-body'])
|
|
localStorage.removeItem(key);
|
|
actions.replaceChildren();
|
|
}
|
|
const api = async (path, body) => {
|
|
const response = await fetch('/api'+path, {
|
|
credentials: 'same-origin', headers: {'Content-Type':'application/json'},
|
|
...(body === undefined ? {} : {method:'POST', body:JSON.stringify(body)})
|
|
});
|
|
const text = await response.text();
|
|
let data;
|
|
try { data = text ? JSON.parse(text) : {}; }
|
|
catch (_) { throw new Error(response.ok ? 'Resposta inválida do serviço.' : 'O serviço está indisponível. Tente novamente em instantes.'); }
|
|
if (!response.ok) { const error=new Error(typeof data.detail === 'string' ? data.detail : 'Confira os dados do pedido ('+response.status+').');error.status=response.status;throw error; }
|
|
return data;
|
|
};
|
|
const ready = api('/session');
|
|
ready.then(session=>{
|
|
window.dtfUploadMaxBytes=session.max_upload_bytes;
|
|
const limit=document.getElementById('zLimite');
|
|
if(limit)limit.textContent='Até '+(session.max_upload_bytes/1048576).toFixed(0)+
|
|
' MB por arquivo enquanto a verificação de segurança para arquivos grandes é preparada.';
|
|
}).catch(()=>{});
|
|
window.dtfSessionReady=ready;
|
|
window.dtfApi=api;
|
|
ready.catch(error => { status.textContent = error.message; });
|
|
function message(text) { status.textContent = text; }
|
|
function button(label, handler) {
|
|
const el = document.createElement('button');
|
|
el.textContent = label;
|
|
el.style.cssText = 'margin:8px 8px 0 0;padding:8px 14px;cursor:pointer';
|
|
el.onclick = handler;
|
|
actions.append(el);
|
|
return el;
|
|
}
|
|
async function upload(file) {
|
|
const session=await ready;
|
|
return window.dtfUpload(file,{api,progress:message,scope:session.cart_scope});
|
|
}
|
|
window.dtfFreight = async () => {
|
|
const cep = entrega.cep;
|
|
try {
|
|
const result = await api('/freight',{service:'mock-standard',postal_code:cep});
|
|
if (entrega.cep !== cep || entrega.tipo !== 'frete') return;
|
|
entrega.valor = result.total_cents/100;
|
|
entrega.cotado = true;
|
|
$('cepMsg').textContent = 'Frete estimado: '+rs(entrega.valor)+'.';
|
|
pintaEntrega();
|
|
} catch(error) { $('cepMsg').textContent = error.message; }
|
|
};
|
|
window.dtfCheckout = async () => {
|
|
if (busy) return;
|
|
if (draftId) { await refresh(); status.scrollIntoView({behavior:'smooth',block:'nearest'}); return; }
|
|
if (!clienteOk() || !entrega.cotado) return;
|
|
if (!cartPodeEnviar()) return message('Revise a qualidade e confirme a ressalva de cada item antes de enviar o pedido.');
|
|
const cart = [...pedido,...(itemAtual?[itemAtual]:[])];
|
|
if (!cart.length) return message('Adicione um item ao pedido.');
|
|
const initialCart=cartSnapshot();
|
|
busy = true;
|
|
$('bPagar').disabled = true;
|
|
try {
|
|
await ready;
|
|
if((await api('/session')).cart_scope !== (await ready).cart_scope) throw new Error('Sua conta ou sessão mudou. Recarregue a página antes de enviar o carrinho.');
|
|
const items=[];
|
|
for (const item of cart) {
|
|
if (!item.localFiles?.length) throw new Error('Selecione novamente os arquivos deste item.');
|
|
const uploads=[];
|
|
for (const file of item.localFiles) uploads.push(await upload(file));
|
|
if (item.production?.version!==2 || item.production.sources?.length!==uploads.length)
|
|
throw new Error('A montagem deste item precisa ser refeita antes da cotação.');
|
|
items.push({mode:item.modo, metres:String(item.metros), grade:item.nota, uploads,
|
|
production:{...item.production,sources:item.production.sources.map((source,index)=>({
|
|
upload_id:uploads[index],...source}))},
|
|
quality_status:item.qualityStatus,quality_acknowledged:item.qualityAcknowledged});
|
|
}
|
|
const content = {customer:{...cliente},items,freight:{service:entrega.tipo==='retira'?'pickup':'mock-standard',postal_code:entrega.tipo==='retira'?'':entrega.cep}};
|
|
if (cartSnapshot()!==initialCart) throw new Error('O carrinho mudou durante o envio. Confira os itens e envie de novo.');
|
|
const serialized = JSON.stringify(content);
|
|
if (!requestKey || serialized !== requestBody) {
|
|
requestKey = crypto.randomUUID(); requestBody = serialized;
|
|
localStorage.setItem('dtf-request-key',requestKey);
|
|
localStorage.setItem('dtf-request-body',requestBody);
|
|
}
|
|
const quote = await api('/quotes',{request_key:requestKey,...content});
|
|
quotedCart=initialCart;localStorage.setItem('dtf-quote-cart',quotedCart);
|
|
draftId=quote.id; localStorage.setItem('dtf-quote',draftId);
|
|
await refresh();
|
|
status.scrollIntoView({behavior:'smooth',block:'nearest'});
|
|
} catch(error) { message(error.message); }
|
|
finally { busy=false; pintaEntrega(); }
|
|
};
|
|
async function refresh() {
|
|
if (!draftId) return;
|
|
const version=++refreshVersion, shownId=draftId;
|
|
try {
|
|
await ready;
|
|
const quote=await api('/quotes/'+shownId);
|
|
if(version!==refreshVersion || draftId!==shownId) return;
|
|
actions.replaceChildren();
|
|
if (quote.status!=='paid' && (!quotedCart || quotedCart!==cartSnapshot())) {
|
|
message('O carrinho mudou ou não está disponível neste navegador. A cotação anterior continua separada; envie o carrinho atual para uma nova revisão.');
|
|
button('Enviar carrinho atual',()=>{clearDraft();window.dtfCheckout();});
|
|
return;
|
|
}
|
|
if (quote.status==='pending_review') {
|
|
message('Arquivos enviados. No Kanban, confira metragem e nota e aprove a cotação '+draftId.slice(0,8)+'.');
|
|
} else if (quote.status==='approved') {
|
|
message('Total validado no servidor: '+rs(quote.approved.total_cents/100)+' · inclui frete. Cotação válida por 24 horas.');
|
|
if ((await ready).environment !== 'local') {
|
|
message('Cotação revisada. O pagamento online ainda não está disponível.');
|
|
return;
|
|
}
|
|
button('Criar pedido de teste',async event=>{
|
|
if (!quotedCart || quotedCart!==cartSnapshot()) { await refresh(); return; }
|
|
event.target.disabled=true;
|
|
try {
|
|
const order=await api('/orders/dev-paid',{quote_id:draftId});
|
|
pedido=[]; itemAtual=null; limpaPaineis();
|
|
await window.dtfClearCart?.();
|
|
message('Pedido #'+order.number+' criado e disponível no Kanban.');
|
|
await refresh();
|
|
} catch(error) { message(error.message); event.target.disabled=false; }
|
|
});
|
|
} else if (quote.status==='paid') {
|
|
message('Pedido #'+quote.order.number+' · etapa: '+quote.order.state+'.');
|
|
button('Novo pedido',()=>{clearDraft();location.reload();});
|
|
} else {
|
|
message('Cotação expirada. Envie o carrinho para uma nova revisão.');
|
|
button('Nova cotação',clearDraft);
|
|
}
|
|
} catch(error) {
|
|
if(version!==refreshVersion || draftId!==shownId) return;
|
|
message(error.message);
|
|
actions.replaceChildren();
|
|
button('Limpar referência e tentar de novo',clearDraft);
|
|
}
|
|
}
|
|
const quoteFromPortal=new URLSearchParams(location.search).get('quote');
|
|
if(quoteFromPortal && /^[0-9a-f-]{36}$/.test(quoteFromPortal)){
|
|
if(draftId!==quoteFromPortal){quotedCart=null;localStorage.removeItem('dtf-quote-cart');}
|
|
draftId=quoteFromPortal;localStorage.setItem('dtf-quote',draftId);
|
|
}
|
|
window.addEventListener('dtf-cart-changed',()=>{if(draftId) refresh();});
|
|
refresh();
|
|
})();
|