feat: price home delivery with Jadlog
All checks were successful
Build and deploy / Validate source (push) Successful in 1m18s
Build and deploy / Integration suite on a real stack (push) Successful in 2m33s
Build and deploy / Secret scan and release gate (push) Successful in 9s
Build and deploy / Publish images (push) Successful in 1m42s

FREIGHT_ADAPTER=jadlog prices "Receber em casa" through Jadlog's Simulador
de Frete from the order's billed metres and value, adding production days
to Jadlog's delivery time. The package weight is a base plus a weight per
metre from the client, with no default: the adapter refuses to start
without it and without the credentials. The cart re-quotes when the package
changes, and approval quotes again from the server-priced items. The
production stack takes the Jadlog settings, so the read-only probe runs
from the worker's console.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Cauê Faleiros
2026-09-29 09:34:01 -03:00
parent 641aafc87d
commit 4de2151e9a
13 changed files with 199 additions and 26 deletions

View File

@@ -81,7 +81,8 @@
const rows = approved.items.map(item => linha(
(MODOS[item.mode]?.tit || item.mode)+' · '+fmtM(Number(item.billed_metres))+' m', rs(item.total_cents/100)));
const pickup = approved.freight.service === 'pickup';
rows.push(linha(pickup ? 'Retirada em Franca' : 'Frete',
const prazo = approved.freight.days ? ' · até '+approved.freight.days+' dias úteis' : '';
rows.push(linha(pickup ? 'Retirada em Franca' : 'Frete'+prazo,
approved.freight.total_cents ? rs(approved.freight.total_cents/100) : 'Grátis'));
rows.push(linha('Total', rs(approved.total_cents/100), 'tot'));
resumo.replaceChildren(node('h4','Resumo do pedido'), ...rows);
@@ -96,17 +97,40 @@
const session=await ready;
return window.dtfUpload(file,{api,progress:message,scope:session.cart_scope});
}
// The cart's package: billed metres and value. The charged freight is
// quoted again by the server from the approved items.
const pacote = () => {
const items=[...pedido,...(itemAtual?[itemAtual]:[])];
return {metres:items.reduce((t,it)=>t+(it.cob||0),0), cents:Math.round(items.reduce((t,it)=>t+(it.total||0),0)*100)};
};
let freightQuoted = null;
window.dtfFreight = async () => {
const cep = entrega.cep;
const service = (await ready).freight_service;
if (!service) {
$('cepMsg').textContent = 'A entrega ainda não está disponível. Escolha a retirada em Franca.';
return;
}
const {metres, cents} = pacote();
if (!metres) { $('cepMsg').textContent = 'Adicione um item ao pedido para cotar o frete.'; return; }
$('cepMsg').textContent = 'Cotando o frete…';
try {
const result = await api('/freight',{service:'mock-standard',postal_code:cep});
const result = await api('/freight',{service,postal_code:cep,metres:metres.toFixed(2),declared_cents:cents});
if (entrega.cep !== cep || entrega.tipo !== 'frete') return;
entrega.valor = result.total_cents/100;
entrega.cotado = true;
$('cepMsg').textContent = 'Frete estimado: '+rs(entrega.valor)+'.';
freightQuoted = JSON.stringify(pacote());
$('cepMsg').textContent = 'Frete: '+rs(entrega.valor)+
(result.days ? ' · entrega em até '+result.days+' dias úteis.' : '.');
pintaEntrega();
} catch(error) { $('cepMsg').textContent = error.message; }
};
// A different package is a different freight: quote it again.
window.addEventListener('dtf-cart-changed',()=>{
if (entrega.tipo==='frete' && entrega.cotado && freightQuoted && freightQuoted!==JSON.stringify(pacote())) {
entrega.cotado=false; freightQuoted=null; window.dtfFreight();
}
});
window.dtfCheckout = async () => {
if (busy) return;
// The cart that was sent goes straight to its payment; a changed cart is sent again.
@@ -135,7 +159,9 @@
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}};
const service = entrega.tipo==='retira' ? 'pickup' : (await ready).freight_service;
if (!service) throw new Error('A entrega ainda não está disponível. Escolha a retirada em Franca.');
const content = {customer:{...cliente},items,freight:{service,postal_code:entrega.tipo==='retira'?'':entrega.cep}};
const destination = destinoApi();
if (destination) content.destination = destination;
if (cartSnapshot()!==initialCart) throw new Error('O carrinho mudou durante o envio. Confira os itens e envie de novo.');