/* O Tal Picolé — Sistema de comprovantes (impressão / PDF)
Suporta 3 formatos: A4, 80mm térmica, 58mm térmica.
Abre uma nova janela com o conteúdo formatado e chama print(). */
function _money(v){ return "R$ " + (v||0).toLocaleString("pt-BR",{minimumFractionDigits:2,maximumFractionDigits:2}); }
function _date(d){ const dt = d instanceof Date ? d : new Date(d); return dt.toLocaleDateString("pt-BR"); }
function _now(){ const d = new Date(); return d.toLocaleDateString("pt-BR") + " " + d.toLocaleTimeString("pt-BR",{hour:"2-digit",minute:"2-digit"}); }
function _docNum(prefix, id){
const n = (id||"").replace(/[^a-z0-9]/gi,"").slice(-6).toUpperCase().padStart(6,"0");
return (prefix||"DOC") + "-" + n;
}
/* Carrega logo customizada (data URL) salva pela fábrica, se houver. */
function _getLogoDataUrl(){
try { return localStorage.getItem("otp.logo") || ""; } catch(e){ return ""; }
}
/* Cores da marca alinhadas ao design system */
const BRAND_COLORS = {
red: "#D4310B",
redDark: "#B3270A",
redSoft: "#FFF1EA",
redSofter:"#FDE6DC",
ink: "#1A1A1A",
inkSoft: "#666666",
cream: "#FAFAFB",
};
/* Renderiza HTML do cabeçalho da empresa — minimalista e profissional. */
function _headerHtml(company, fmt){
const logoUrl = _getLogoDataUrl();
if (fmt === "a4") {
const logoSize = 64;
const logoBlock = logoUrl
? ``
: `
Data da operação${_date(sale.date||new Date())}${sale.time ? " · "+sale.time : ""}
Discriminação dos itens
Produto
Quantidade
Un.
Vl. unitário
Subtotal
${rows}
Subtotal${_money(sale.subtotal||sale.total)}
${sale.discount>0 ? `
Desconto− ${_money(sale.discount)}
` : ""}
Total${_money(sale.total)}
${paid > 0 && paid < sale.total ? `
Valor pago${_money(paid)}
Saldo pendente${_money(pending)}
` : ""}
${pending > 0 ? `
Venda a prazo: O cliente compromete-se a quitar o saldo pendente de ${_money(pending)} conforme condições negociadas. Pagamentos parciais serão registrados sequencialmente até a quitação integral.
Comissão acordada${picolezeiro?.commission||0}% sobre valor vendido
Produtos retirados (${totalUnits} un)
Produto
Quantidade
Vl. unitário
Valor máx.
${rows}
Total de unidades${totalUnits} un
Valor máximo previsto${_money(expectedValue)}
Termos da consignação: O picolezeiro recebe os produtos relacionados em consignação. No retorno deverá prestar contas dos valores efetivamente vendidos. Sobras retornam ao estoque da fábrica. A comissão é calculada sobre o faturamento líquido confirmado no retorno.
);
}
/* ============================================================
COMPROVANTE DE COMISSÃO (Picolezeiro · LUCRO)
Recibo formal de pagamento da comissão devida ao picolezeiro.
Pode ser por 1 retorno OU por período (várias trips).
props:
- company
- picolezeiro
- trips: array de trips fechados (1 ou mais)
- period: { label, start, end } opcional
- paymentMethod: forma de pagamento da comissão
- paymentDate: data do pagamento (default hoje)
- fmt: "a4" | "mm80" | "mm58"
============================================================ */
function printCommissionReceipt({ company, picolezeiro, trips, beaches, period, paymentMethod, paymentDate, fmt, autoPrint }){
const tripsArr = Array.isArray(trips) ? trips : [trips];
const beachesArr = beaches || [];
const docNum = _docNum("COM", (tripsArr[0]?.id || "") + (tripsArr.length > 1 ? "-" + tripsArr.length : "") + Date.now().toString(36));
const css = _baseCss(fmt);
const faturadoTotal = tripsArr.reduce((s, t) => s + (t.faturado || 0), 0);
const comissaoTotal = tripsArr.reduce((s, t) => s + (t.comissao || 0), 0);
const liquidoEmpresa = faturadoTotal - comissaoTotal;
const totalSold = tripsArr.reduce((s, t) => s + ((t.sold||[]).reduce((a, x) => a + x.qty, 0)), 0);
/* Valor da comissão por extenso (simples). */
const valorPorExtenso = (v) => {
const reais = Math.floor(v);
const cent = Math.round((v - reais) * 100);
return `${reais} reais${cent > 0 ? " e " + cent + " centavos" : ""}`;
};
const dataPgto = paymentDate || new Date().toISOString().slice(0,10);
const periodLabel = period?.label || (tripsArr.length === 1
? "Retorno de " + _date(tripsArr[0].date)
: tripsArr.length + " retornos");
let body = "";
if (fmt === "a4") {
const tripRows = tripsArr.map(t => {
const tripFat = t.faturado || 0;
const tripCom = t.comissao || 0;
const tripSold = (t.sold||[]).reduce((s,x)=>s+x.qty,0);
const tripBeaches = (t.beachesActual || t.beachesPlanned || [])
.map(bid => beachesArr.find(b => b.id === bid)?.name)
.filter(Boolean)
.join(", ") || "—";
return `
${_date(t.date)}
${tripBeaches}
${tripSold}
${_money(tripFat)}
${_money(tripCom)}
`;
}).join("");
body = `
${_headerHtml(company, "a4")}
Recibo de Pagamento
Recibo de Comissão · Picolezeiro
Pago
Nº ${docNum}Emitido em ${_now()}
Valor recebido
${_money(comissaoTotal)}
(${valorPorExtenso(comissaoTotal)})
Eu, ${picolezeiro?.name||"—"}${picolezeiro?.cpf ? ", portador(a) do CPF nº " + picolezeiro.cpf : ""}, declaro ter recebido da empresa ${company.name||"—"}${company.cnpj ? ", inscrita no CNPJ sob nº " + company.cnpj : ""}, a importância de ${_money(comissaoTotal)} (${valorPorExtenso(comissaoTotal)}), referente à comissão de ${picolezeiro?.commission||0}% sobre o faturamento de ${_money(faturadoTotal)} apurado em ${periodLabel}, conforme detalhamento abaixo. Para clareza, firmo o presente recibo, dando plena e geral quitação da obrigação acima referida.
Comissão acordada${picolezeiro?.commission||0}% sobre valor vendido
Detalhamento por retorno
Data
Praias
Un. vendidas
Faturado
Comissão (${picolezeiro?.commission||0}%)
${tripRows}
Totais
${totalSold} un
${_money(faturadoTotal)}
${_money(comissaoTotal)}
Faturamento total${_money(faturadoTotal)}
Alíquota de comissão${picolezeiro?.commission||0}%
Líquido retido pela empresa${_money(liquidoEmpresa)}
LUCRO DO PICOLEZEIRO${_money(comissaoTotal)}
Dou plena, geral e irrevogável quitação à empresa pagadora quanto ao valor acima descrito, referente exclusivamente ao período/retornos discriminados. Nada mais tendo a reclamar a qualquer título.