`);w.document.close(); } function exportCSV(){ const cols=["code","created_at","status","store_name","customer_name","phone","zone","address","subtotal","delivery_fee","discount","total","payment","payment_status","courier_name","courier_fee","service_fee","commission","coupon","rating"]; const csv=[cols.join(";")].concat(D.orders.map(o=>cols.map(c=>`"${String(o[c]??"").replace(/"/g,'""')}"`).join(";"))).join("\n"); const a=document.createElement("a");a.href=URL.createObjectURL(new Blob(["\ufeff"+csv],{type:"text/csv;charset=utf-8"}));a.download="pedidos-entregas-pvh.csv";a.click(); } /* ---------- diálogo genérico ---------- */ function dlg(title,body,foot){ const d=$("#dlg");d.innerHTML=`

${title}

${body}
${foot?`
${foot}
`:""}
`; d.querySelectorAll("[data-x]").forEach(b=>b.onclick=()=>d.close());if(!d.open)d.showModal(); } $("#dlg").addEventListener("click",e=>{if(e.target.id==="dlg")e.target.close()}); function field(f,v){ const n=`name="${f.k}"`; if(f.t==="bool")return ``; if(f.t==="select")return ``; if(f.t==="area")return ``; if(f.t==="image")return `
${v?``:"Sem foto"}

${f.l}

`; return ``; } function form(title,fields,vals,onSave){ const body=`
${fields.map(f=>Array.isArray(f)?`
${f.map(x=>field(x,vals[x.k])).join("")}
`:field(f,vals[f.k])).join("")}
`; dlg(title,body,``); $("#dlg").querySelectorAll("[data-x]").forEach(b=>b.onclick=()=>$("#dlg").close()); const fm=$("#gf"),flat=fields.flat(); fm.querySelectorAll("[data-up]").forEach(inp=>inp.onchange=async()=>{const file=inp.files[0];if(!file)return;const wrap=inp.closest(".imgf"),st=wrap.querySelector("[data-ust]");st.textContent="Enviando…";$("#gfSave").disabled=true; try{const fd=new FormData();fd.append("file",file);const r=await fetch("https://wish4.com/api/projects/"+PID+"/uploads",{method:"POST",body:fd});const d=await r.json();if(!r.ok)throw new Error(d.error||"Falha no envio"); fm[inp.dataset.up].value=d.url;wrap.querySelector("[data-pv]").innerHTML=``;st.textContent="✓ Foto enviada"}catch(e){st.textContent=e.message}$("#gfSave").disabled=false}); fm.querySelectorAll("[data-clr]").forEach(b=>b.onclick=()=>{fm[b.dataset.clr].value="";b.closest(".imgf").querySelector("[data-pv]").textContent="Sem foto"}); const save=async e=>{e?.preventDefault();const out={}; for(const f of flat){const el=fm[f.k];if(f.t==="bool")out[f.k]=el.checked;else if(f.t==="number")out[f.k]=parseFloat(String(el.value).replace(",","."))||0;else if(f.num)out[f.k]=+el.value;else out[f.k]=el.value.trim(); if(f.req&&!out[f.k]&&out[f.k]!==0)return toast(`Preencha: ${f.l}`,1)} const b=$("#gfSave");b.disabled=true;try{await onSave(out);$("#dlg").close();toast("Salvo ✓")}catch(err){toast(err.message,1);b.disabled=false}}; fm.onsubmit=save;$("#gfSave").onclick=save; } async function upsert(table,arr,rec,data){if(rec&&rec.id){await update(table,rec.id,data);Object.assign(rec,data)}else{const r=await create(table,data);arr.push(r)}S.sig="";render()} async function remove(table,arr,id,what){if(!confirm(`Excluir ${what}? Esta ação não pode ser desfeita.`))return;try{await del(table,id);const i=arr.findIndex(x=>x.id==id);if(i>=0)arr.splice(i,1);toast("Excluído");S.sig="";render()}catch(e){toast(e.message,1)}} /* ---------- lojas ---------- */ const storeFields=[[{k:"name",l:"Nome da loja",req:1},{k:"category",l:"Categoria",t:"select",o:CATS}],{k:"description",l:"Descrição",t:"area"},{k:"address",l:"Endereço (para o entregador coletar)",ph:"Rua, número - Bairro"},[{k:"emoji",l:"Emoji (se não houver foto)",ph:"🍔"},{k:"color",l:"Cor da capa",t:"color"}],[{k:"eta",l:"Tempo de entrega",ph:"30-45 min"},{k:"min_order",l:"Pedido mínimo (R$)",t:"number"}],[{k:"commission_pct",l:"💎 Comissão sobre as vendas (%)",t:"number",hint:"Quanto você fica de cada venda da loja"},{k:"monthly_fee",l:"💎 Mensalidade (R$)",t:"number",hint:"0 = sem mensalidade"}],[{k:"phone",l:"WhatsApp do responsável"},{k:"pix_key",l:"Chave Pix da loja (repasses)"}],{k:"rating",l:"Nota exibida (0 a 5)",t:"number"},{k:"image",l:"Foto / logo da loja",t:"image"},{k:"open",l:"Aberta agora",t:"bool"},{k:"active",l:"Visível no app",t:"bool"}]; function vLojas(){ return pageTop("Lojas",`${D.stores.length} lojas cadastradas`,``)+ `
${D.stores.map(s=>{const n=D.products.filter(p=>p.store_id==s.id).length;return `
${s.image?``:esc(s.emoji||"🏪")}

${esc(s.name)}

${s.active===false?`Oculta`:""}

${esc(s.category)} · ${n} produtos · mín. ${brl(s.min_order)}

💎 ${storePct(s.id)}% de comissão${num(s.monthly_fee)?" · "+brl(s.monthly_fee)+"/mês":""}

`}).join("")||`

Nenhuma loja.

`}
`; } after.lojas=()=>document.querySelectorAll("[data-sopen]").forEach(b=>b.onclick=async()=>{const s=D.stores.find(x=>x.id==b.dataset.sopen);try{await update("Store",s.id,{open:!s.open});s.open=!s.open;S.sig="";render()}catch(e){toast(e.message,1)}}); function editStore(id){const s=D.stores.find(x=>x.id==id);const dc=num(D.settings.default_commission??12);form(s?"Editar loja":"Nova loja",storeFields,s?{...s,commission_pct:s.commission_pct??dc,monthly_fee:s.monthly_fee??0}:{color:"#FF5A1F",emoji:"🏪",eta:"30-45 min",rating:5,category:"Lanches",commission_pct:dc,monthly_fee:0},d=>{d.phone=digits(d.phone);return upsert("Store",D.stores,s,d)})} /* ---------- produtos ---------- */ function vProdutos(){ const ps=D.products.filter(p=>!S.pstore||p.store_id==S.pstore); return pageTop("Produtos",`${ps.length} produtos`,``)+ `
${ps.map(p=>``).join("")||``}
ProdutoLojaSeçãoPreçoDisponível
${p.image?``:esc(p.emoji||"🍽️")}
${esc(p.name)}
${esc((p.description||"").slice(0,60))}
${esc(D.stores.find(s=>s.id==p.store_id)?.name||"—")}${esc(p.section||"")}${brl(p.price)}
Nenhum produto.
`; } after.produtos=()=>{$("#pst").onchange=e=>{S.pstore=e.target.value;render()};document.querySelectorAll("[data-pav]").forEach(b=>b.onclick=async()=>{const p=D.products.find(x=>x.id==b.dataset.pav);const v=p.available===false;try{await update("Product",p.id,{available:v});p.available=v;render()}catch(e){toast(e.message,1)}})}; function editProduct(id){const p=D.products.find(x=>x.id==id); form(p?"Editar produto":"Novo produto",[{k:"store_id",l:"Loja",t:"select",num:1,o:D.stores.map(s=>[s.id,s.name])},{k:"name",l:"Nome",req:1},{k:"description",l:"Descrição",t:"area"},[{k:"price",l:"Preço (R$)",t:"number",req:1},{k:"section",l:"Seção do cardápio",ph:"Ex: Lanches"}],{k:"emoji",l:"Emoji (se não houver foto)",ph:"🍔"},{k:"image",l:"Foto do produto",t:"image"},{k:"available",l:"Disponível para venda",t:"bool"}],p||{store_id:S.pstore||D.stores[0]?.id,emoji:"🍽️"},d=>upsert("Product",D.products,p,d))} /* ---------- entregadores ---------- */ function vEntregadores(){ const cs=D.couriers.filter(c=>c.status===S.ctab);const cnt=k=>D.couriers.filter(c=>c.status===k).length; const stats=id=>{const d=D.orders.filter(o=>o.courier_id==id&&o.status==="entregue");return [d.length,d.reduce((a,o)=>a+(+o.courier_fee||0),0)]}; return pageTop("Entregadores",`${D.couriers.filter(c=>c.online&&c.status==="aprovado").length} online agora · link de cadastro: /entregador`)+ `
${[["pendente","⏳ Pendentes"],["aprovado","✅ Aprovados"],["bloqueado","⛔ Bloqueados"]].map(([k,l])=>``).join("")}
${cs.map(c=>{const [n,g]=stats(c.id);return ``}).join("")||``}
EntregadorVeículoStatusEntregasGanhosPix
${esc(c.name)}
${esc(c.phone)}
${esc(c.vehicle||"")} ${esc(c.plate||"")}${c.status==="aprovado"?`${c.online?"● online":"offline"}`:`${c.status}`}${n}${brl(g)}${esc(c.pix_key||"—")}
${c.status!=="aprovado"?``:""}${c.status!=="bloqueado"?``:""}
Nenhum entregador nesta lista.
`; } after.entregadores=()=>{document.querySelectorAll("[data-ct]").forEach(b=>b.onclick=()=>{S.ctab=b.dataset.ct;render()}); document.querySelectorAll("[data-cs]").forEach(b=>b.onclick=async()=>{const c=D.couriers.find(x=>x.id==b.dataset.cid);const st=b.dataset.cs;try{await update("Courier",c.id,{status:st,...(st==="bloqueado"?{online:false}:{})});c.status=st;if(st==="bloqueado")c.online=false;toast(st==="aprovado"?`${c.name} aprovado ✓`:`${c.name} bloqueado`);render();renderNav()}catch(e){toast(e.message,1)}})}; function editCourier(id){const c=D.couriers.find(x=>x.id==id);form("Editar entregador",[[{k:"name",l:"Nome",req:1},{k:"phone",l:"WhatsApp",req:1}],[{k:"vehicle",l:"Veículo",t:"select",o:["Moto","Bicicleta","Carro"]},{k:"plate",l:"Placa"}],{k:"pix_key",l:"Chave Pix"},{k:"status",l:"Status",t:"select",o:["pendente","aprovado","bloqueado"]}],c,d=>{d.phone=digits(d.phone);return upsert("Courier",D.couriers,c,d)})} /* ---------- bairros ---------- */ function vBairros(){ return pageTop("Bairros e taxas de entrega",`${D.zones.filter(z=>z.active!==false).length} bairros atendidos · o entregador recebe ${esc(D.settings.courier_pct||80)}% da taxa`,``)+ `
${D.zones.map(z=>``).join("")}
BairroTaxaRepasse ao entregadorSua margemAtendido
${esc(z.name)}${brl(z.fee)}${brl(z.fee*num(D.settings.courier_pct??80)/100)}${brl(z.fee-z.fee*num(D.settings.courier_pct??80)/100)}${z.active!==false?"Sim":"Não"}
`; } function editZone(id){const z=D.zones.find(x=>x.id==id);form(z?"Editar bairro":"Novo bairro",[{k:"name",l:"Nome do bairro",req:1},{k:"fee",l:"Taxa de entrega (R$)",t:"number"},{k:"active",l:"Atendemos este bairro",t:"bool"}],z||{fee:8},async d=>{await upsert("Zone",D.zones,z,d);D.zones.sort((a,b)=>a.name.localeCompare(b.name,"pt-BR"));render()})} /* ---------- cupons ---------- */ const CT={percentual:"% de desconto",fixo:"R$ de desconto",frete:"Frete grátis"}; function vCupons(){ return pageTop("Cupons de desconto",`${D.coupons.filter(c=>c.active!==false).length} cupons ativos`,``)+ `
${D.coupons.map(c=>``).join("")||``}
CódigoBenefícioPedido mínimoUsosStatus
${esc(c.code)}${c.type==="percentual"?esc(c.value)+"% off":c.type==="fixo"?brl(c.value)+" off":"Frete grátis"}${brl(c.min_order)}${+c.uses||0}${c.active!==false?"Ativo":"Inativo"}
Nenhum cupom.
`; } function editCoupon(id){const c=D.coupons.find(x=>x.id==id);form(c?"Editar cupom":"Novo cupom",[{k:"code",l:"Código",req:1,ph:"EX: PVH20"},{k:"type",l:"Tipo",t:"select",o:Object.entries(CT)},[{k:"value",l:"Valor (% ou R$; ignorado no frete grátis)",t:"number"},{k:"min_order",l:"Pedido mínimo (R$)",t:"number"}],{k:"active",l:"Cupom ativo",t:"bool"}],c||{type:"percentual"},d=>{d.code=d.code.toUpperCase().replace(/\s/g,"");if(!c&&D.coupons.some(x=>x.code===d.code))throw new Error("Já existe um cupom com esse código");return upsert("Coupon",D.coupons,c,{...d,uses:c?.uses||0})})} /* ---------- financeiro ---------- */ function vFinanceiro(){ const days=+S.period;const os=D.orders.filter(o=>o.status==="entregue"&&(days===0||Date.now()-new Date(o.delivered_at||o.created_at)os.reduce((a,o)=>a+(+o[k]||0),0);const by=m=>os.filter(o=>o.payment===m).reduce((a,o)=>a+(+o.total||0),0); const fees=sum("delivery_fee"),cf=sum("courier_fee"); const bal=D.couriers.filter(c=>c.status!=="pendente").map(c=>{const e=D.orders.filter(o=>o.courier_id==c.id&&o.status==="entregue").reduce((a,o)=>a+(+o.courier_fee||0),0);const p=D.payouts.filter(x=>x.courier_id==c.id).reduce((a,x)=>a+(+x.amount||0),0);return {c,e,p,b:r2(e-p)}}).filter(x=>x.e>0||x.p>0); return pageTop("Financeiro","Valores de pedidos entregues",``)+ `
Vendas totais${brl(sum("total"))}
Produtos (lojas)${brl(sum("subtotal"))}
Taxas de entrega${brl(fees)}
Repasse a entregadores${brl(cf)}
Descontos (cupons)${brl(sum("discount"))}
Taxas de serviço${brl(sum("service_fee"))}
💎 Seu lucro líquido${brl(os.reduce((a,o)=>a+earn(o).net,0))}

Saldo dos entregadores

${bal.length?`${bal.map(x=>``).join("")}
EntregadorGanho totalPagoA pagar
${esc(x.c.name)}
Pix: ${esc(x.c.pix_key||"—")}
${brl(x.e)}${brl(x.p)}${brl(x.b)}${x.b>0?``:"✓"}
`:`

Os saldos aparecem conforme as entregas são concluídas.

`}

Por forma de pagamento

${Object.entries(PAY).map(([k,l])=>`
${l}${brl(by(k))}
`).join("")}

Últimos repasses

${D.payouts.slice(0,8).map(p=>`
${esc(p.courier_name)}
${new Date(p.created_at).toLocaleDateString("pt-BR")}
${brl(p.amount)}
`).join("")||`

Nenhum repasse registrado.

`}
`; } after.financeiro=()=>{$("#per").onchange=e=>{S.period=e.target.value;render()}; document.querySelectorAll("[data-pay]").forEach(b=>b.onclick=async()=>{const c=D.couriers.find(x=>x.id==b.dataset.pay);const v=prompt(`Valor pago via Pix para ${c.name} (chave: ${c.pix_key||"—"}):`,String(b.dataset.amt).replace(".",","));if(v===null)return;const amt=parseFloat(v.replace(",","."));if(!(amt>0))return toast("Valor inválido",1); try{const r=await create("Payout",{courier_id:c.id,courier_name:c.name,amount:r2(amt),note:"Repasse via Pix"});D.payouts.unshift(r);toast("Repasse registrado ✓");render()}catch(e){toast(e.message,1)}})}; /* ---------- meus ganhos ---------- */ const num=v=>+v||0; const MES=d=>d.getFullYear()+"-"+String(d.getMonth()+1).padStart(2,"0"); const mesLabel=k=>{const [y,m]=k.split("-");return new Date(+y,+m-1,1).toLocaleDateString("pt-BR",{month:"long",year:"numeric"})}; const inPer=(d,days)=>days===0||Date.now()-new Date(d)x.id==id);return num(s&&s.commission_pct!=null?s.commission_pct:(D.settings.default_commission??12))} function earn(o){ const sub=num(o.subtotal),fee=num(o.delivery_fee),cf=num(o.courier_fee),disc=num(o.discount),svc=num(o.service_fee); const has=o.commission!=null;const com=has?num(o.commission):r2(sub*storePct(o.store_id)/100); const pct=has?(sub?Math.round(com/sub*1000)/10:0):storePct(o.store_id);const df=r2(fee-cf); return {pct,com,svc,df,disc,cf,net:r2(com+svc+df-disc),store:r2(sub-com)}; } function splitBox(o){const e=earn(o);return `

💎 Divisão do pedido

🏪 Loja recebe (vendas − ${e.pct}% de comissão)${brl(e.store)}
🏍️ Entregador recebe${brl(e.cf)}
💎 Você ganha
comissão ${brl(e.com)} + entrega ${brl(e.df)}${e.svc?" + serviço "+brl(e.svc):""}${e.disc?" − cupom "+brl(e.disc):""}
${brl(e.net)}
`} function storeBal(id){ const net=D.orders.filter(o=>o.store_id==id&&o.status==="entregue").reduce((a,o)=>a+earn(o).store,0); const tx=D.txns.filter(t=>t.store_id==id);const sumT=k=>tx.filter(t=>t.type===k).reduce((a,t)=>a+num(t.amount),0); const rep=sumT("repasse"),men=sumT("mensalidade"); return {net:r2(net),rep:r2(rep),men:r2(men),bal:r2(net-rep-men),charged:tx.some(t=>t.type==="mensalidade"&&t.ref_month===MES(new Date()))}; } function vGanhos(){ const days=+S.gperiod,s=D.settings,mk=MES(new Date()); const E=D.orders.filter(o=>o.status==="entregue"&&inPer(o.delivered_at||o.created_at,days)).map(o=>({o,e:earn(o)})); const tot=k=>r2(E.reduce((a,x)=>a+x.e[k],0)); const menP=D.txns.filter(t=>t.type==="mensalidade"&&inPer(t.created_at,days)); const men=r2(menP.reduce((a,t)=>a+num(t.amount),0));const lucro=r2(tot("net")+men); const rows=D.stores.map(st=>{const a=E.filter(x=>x.o.store_id==st.id);const g=k=>r2(a.reduce((q,x)=>q+x.e[k],0));const m=r2(menP.filter(t=>t.store_id==st.id).reduce((q,t)=>q+num(t.amount),0)); return {st,n:a.length,sales:r2(a.reduce((q,x)=>q+num(x.o.subtotal),0)),com:g("com"),df:g("df"),svc:g("svc"),men:m,tot:r2(g("net")+m)}}).filter(r=>r.n||r.men||r.st.active!==false).sort((a,b)=>b.tot-a.tot); const pend=D.stores.filter(st=>num(st.monthly_fee)>0&&st.active!==false&&!storeBal(st.id).charged); return pageTop("Meus ganhos 💎","Quanto o Entregas PVH lucra por loja e por entrega",``)+ `
💎 Seu lucro líquido${brl(lucro)}
🏪 Comissões das lojas${brl(tot("com"))}
🛵 Margem nas entregas${brl(tot("df"))}
🧾 Taxas de serviço${brl(tot("svc"))}
📅 Mensalidades${brl(men)}
🎟️ Custo dos cupons− ${brl(tot("disc"))}
📦 Lucro médio por entrega${brl(E.length?tot("net")/E.length:0)}

Ganhos por loja

${rows.map(r=>``).join("")||``}
LojaPedidosVendasComissãoEntregasServiçoMensal.Seu ganho
${esc(r.st.name)}
${storePct(r.st.id)}%${num(r.st.monthly_fee)?" · "+brl(r.st.monthly_fee)+"/mês":""}
${r.n}${brl(r.sales)}${brl(r.com)}${brl(r.df)}${brl(r.svc)}${brl(r.men)}${brl(r.tot)}
Sem dados.

Para mudar a comissão ou a mensalidade de uma loja: aba → Editar. "Seu ganho" já desconta os cupons, que são bancados pela plataforma.

⚙️ Seu modelo de ganhos

Mudanças valem para os próximos pedidos. Os pedidos já feitos mantêm os valores da época.

🤝 Acerto com as lojas

Vendas líquidas (já sem a sua comissão) − repasses feitos − mensalidades cobradas

${pend.length?``:""}
${D.stores.map(st=>{const b=storeBal(st.id);return ``}).join("")}
LojaVendas líquidasRepassadoMensalidadesSaldo
${esc(st.name)}
Pix: ${esc(st.pix_key||"—")}
${brl(b.net)}${brl(b.rep)}${brl(b.men)}${brl(Math.abs(b.bal))}
${b.bal>0?"você deve à loja":b.bal<0?"a loja deve a você":"em dia"}
${b.bal>0?``:""}${num(st.monthly_fee)>0&&!b.charged?``:""}${st.phone?`WhatsApp`:""}

Últimas movimentações com lojas

${D.txns.slice(0,12).map(t=>`
${t.type==="repasse"?"💸 Repasse para":"📅 Mensalidade de"} ${esc(t.store_name)}
${new Date(t.created_at).toLocaleDateString("pt-BR")} · ${esc(t.note||"")}
${brl(t.amount)}
`).join("")||`

Nenhuma movimentação ainda.

`}
`; } after.ganhos=()=>{ $("#gper").onchange=e=>{S.gperiod=e.target.value;render()}; const f=$("#model");const val=n=>Math.max(0,parseFloat(String(f[n].value).replace(",","."))||0); const sim=()=>{const sub=50,fee=8,pct=Math.min(100,val("default_commission")),cp=Math.min(100,val("courier_pct")),sv=val("service_fee"),fa=val("service_free_above");const svc=fa>0&&sub>=fa?0:sv;const com=r2(sub*pct/100),cf=r2(fee*cp/100),you=r2(com+svc+fee-cf); $("#simul").innerHTML=`
Simulação: pedido de ${brl(sub)} + frete de ${brl(fee)}
👤 Cliente paga${brl(sub+fee+svc)}
🏪 Loja recebe${brl(sub-com)}
🏍️ Entregador recebe${brl(cf)}
💎 Você ganha${brl(you)}
Comissão ${brl(com)} + frete ${brl(r2(fee-cf))} + serviço ${brl(svc)}
`}; sim();f.oninput=sim; f.onsubmit=async e=>{e.preventDefault();const d={default_commission:Math.min(100,val("default_commission")),courier_pct:Math.min(100,val("courier_pct")),service_fee:r2(val("service_fee")),service_free_above:r2(val("service_free_above"))}; try{await update("Setting",D.settings.id,d);Object.assign(D.settings,d);toast("Modelo de ganhos salvo ✓");render()}catch(err){toast(err.message,1)}}; document.querySelectorAll("[data-srep]").forEach(b=>b.onclick=async()=>{const st=D.stores.find(x=>x.id==b.dataset.srep);const bal=storeBal(st.id).bal;const v=prompt(`Valor repassado para ${st.name} (Pix: ${st.pix_key||"—"}):`,String(bal).replace(".",","));if(v===null)return;const amt=parseFloat(v.replace(",","."));if(!(amt>0))return toast("Valor inválido",1);await addTxn(st,"repasse",r2(amt),"Repasse via Pix")}); document.querySelectorAll("[data-smen]").forEach(b=>b.onclick=async()=>{const st=D.stores.find(x=>x.id==b.dataset.smen);if(!confirm(`Cobrar a mensalidade de ${brl(st.monthly_fee)} de ${st.name}? O valor será descontado do próximo repasse.`))return;await addTxn(st,"mensalidade",num(st.monthly_fee),"Mensalidade de "+mesLabel(MES(new Date())))}); $("#menAll")?.addEventListener("click",async e=>{const mk=MES(new Date());const arr=D.stores.filter(st=>num(st.monthly_fee)>0&&st.active!==false&&!storeBal(st.id).charged);if(!confirm(`Cobrar a mensalidade de ${arr.length} loja(s) referente a ${mesLabel(mk)}?`))return;e.target.disabled=true;for(const st of arr)await addTxn(st,"mensalidade",num(st.monthly_fee),"Mensalidade de "+mesLabel(mk),true);toast("Mensalidades cobradas ✓");render()}); document.querySelectorAll("[data-sext]").forEach(b=>b.onclick=()=>printStatement(+b.dataset.sext)); document.querySelectorAll("[data-tdel]").forEach(b=>b.onclick=()=>remove("StoreTxn",D.txns,+b.dataset.tdel,"esta movimentação")); }; async function addTxn(st,type,amount,note,silent){try{const r=await create("StoreTxn",{store_id:st.id,store_name:st.name,type,amount,note,ref_month:MES(new Date())});D.txns.unshift(r);if(!silent){toast(type==="repasse"?"Repasse registrado ✓":"Mensalidade cobrada ✓");render()}}catch(e){toast(e.message,1)}} function printStatement(id){ const st=D.stores.find(x=>x.id==id);const os=D.orders.filter(o=>o.store_id==id&&o.status==="entregue");const tx=D.txns.filter(t=>t.store_id==id);const b=storeBal(id); const w=window.open("","_blank","width=760,height=820");if(!w)return toast("Permita pop-ups para imprimir",1); w.document.write(`Extrato ${esc(st.name)}

Entregas PVH — Extrato da loja

${esc(st.name)} · Comissão ${storePct(id)}%${num(st.monthly_fee)?" · Mensalidade "+brl(st.monthly_fee):""} · Emitido em ${new Date().toLocaleString("pt-BR")}

Pedidos entregues (${os.length})

${os.map(o=>{const e=earn(o);return ``}).join("")||``}
DataPedidoVendasComissãoLíquido
${new Date(o.delivered_at||o.created_at).toLocaleDateString("pt-BR")}#${esc(o.code)}${brl(o.subtotal)}− ${brl(e.com)}${brl(e.store)}
Nenhum pedido.

Repasses e mensalidades

${tx.map(t=>``).join("")||``}
DataDescriçãoValor
${new Date(t.created_at).toLocaleDateString("pt-BR")}${t.type==="repasse"?"Repasse":"Mensalidade"} — ${esc(t.note||"")}− ${brl(t.amount)}
Nenhuma movimentação.

Vendas líquidas ${brl(b.net)} − repasses ${brl(b.rep)} − mensalidades ${brl(b.men)} = ${b.bal>=0?"saldo a receber":"saldo devedor"}: ${brl(Math.abs(b.bal))}