// Vendas — detalhe (drawer) + novo (modal full-form) function VendaDetail({ venda, onClose, onAddEntrada, onAddFaturamento, onChangeStatus }) { const [tab, setTab] = React.useState("resumo"); const [novaEntrada, setNovaEntrada] = React.useState(null); const [novoFat, setNovoFat] = React.useState(null); if (!venda) return null; const cliente = window.MP_DATA.clientes.find(c => c.id === venda.clienteId); const tipo = window.MP_DATA.tipos.find(t => t.id === venda.tipoId); const vendedor = window.MP_DATA.vendedores.find(v => v.id === venda.vendedorId); const fat = calcFaturado(venda); const ent = calcEntradas(venda); const cnpjMap = vendaPorCnpj(venda); const saldo = venda.valor - fat; const aReceber = fat - ent; return ( OP {venda.op} {cliente?.nome} } subtitle={venda.descricao} footer={ <>
} > {/* Status + meta */}
{tipo?.nome}
{vendedor?.nome}
{/* Resumo financeiro */}
Valor da venda
{fmtBRL(venda.valor)}
Peso total
{fmtNumber(venda.peso)} kg
Faturado
{fmtBRL(fat)}
Saldo a faturar: {fmtBRL(saldo)}
Recebido
{fmtBRL(ent)}
A receber: {fmtBRL(aReceber)}
{/* Cliente / Obra */}

Cliente · Obra

{cliente?.nome} {cliente?.cnpj} · {cliente?.contato} · {cliente?.telefone}
Endereço da obra {venda.enderecoObra}
Início {fmtDate(venda.dataInicio)}
{/* Faturamento por CNPJ */}

Faturamento por CNPJ

{venda.faturamentos.length === 0 ? (
Nenhuma parcela faturada. Adicione a primeira parcela quando emitir a NF.
) : (
{venda.faturamentos.map((f, i) => (
{fmtDateShort(f.data)}
NF {f.nf} Parcela {i + 1} de {venda.faturamentos.length}
{fmtBRL(f.valor)}
))}
)} {/* Entradas */}

Entradas financeiras

{venda.entradas.length === 0 ? (
Nenhuma entrada registrada ainda.
) : (
{venda.entradas.map((e) => (
{fmtDateShort(e.data)}
{e.forma} {e.obs || "Sem observação"}
+ {fmtBRL(e.valor)}
))}
)} {/* Modais inline */} setNovaEntrada(null)} onSave={(payload) => { onAddEntrada(venda.op, payload); setNovaEntrada(null); }} /> setNovoFat(null)} onSave={(payload) => { onAddFaturamento(venda.op, payload); setNovoFat(null); }} /> ); } function NovaEntradaModal({ open, valor, saldo, onClose, onSave }) { const [data, setData] = React.useState(""); const [v, setV] = React.useState(0); const [forma, setForma] = React.useState("Transferência"); const [obs, setObs] = React.useState(""); React.useEffect(() => { if (open && valor) { setData(valor.data); setV(valor.valor); setForma(valor.forma); setObs(valor.obs); } }, [open]); if (!open) return null; return ( } >
Saldo a receber (faturado − pago) {fmtBRL(saldo)}
setData(e.target.value)} /> setObs(e.target.value)} placeholder="Ex: 1ª medição, sinal 30%..." />
); } function NovoFaturamentoModal({ open, valor, saldo, onClose, onSave }) { const [cnpjId, setCnpjId] = React.useState("padrao"); const [v, setV] = React.useState(0); const [data, setData] = React.useState(""); const [nf, setNf] = React.useState(""); React.useEffect(() => { if (open && valor) { setCnpjId(valor.cnpjId); setV(valor.valor); setData(valor.data); setNf(valor.nf); } }, [open]); if (!open) return null; return ( } >
Saldo a faturar {fmtBRL(saldo)}
setData(e.target.value)} /> setNf(e.target.value)} placeholder="ex: 12.450" />
); } // ───────────────────────────────────────────────────────────────────────────── // NOVA VENDA — Modal grande (formulário completo) // ───────────────────────────────────────────────────────────────────────────── function NovaVendaModal({ open, onClose, onSave, proxOp }) { const [f, setF] = React.useState(() => ({ op: proxOp, vendedorId: "cris", clienteId: "", tipoId: "estrutura", descricao: "", peso: 0, valor: 0, status: "previsao", enderecoObra: "", dataInicio: new Date().toISOString().slice(0, 10), })); const [opAuto, setOpAuto] = React.useState(true); React.useEffect(() => { if (open) setF(s => ({ ...s, op: proxOp })); }, [open, proxOp]); const set = (k, v) => setF(s => ({ ...s, [k]: v })); const valid = f.clienteId && f.descricao && f.valor > 0; if (!open) return null; return ( } >
Identificação
set("op", e.target.value)} disabled={opAuto} />
set("tipoId", v)} options={window.MP_DATA.tipos.map(t => ({ value: t.id, label: t.nome }))} />
Cliente · Projeto
set("dataInicio", e.target.value)} /> set("descricao", e.target.value)} placeholder="Ex: Estrutura sobre laje residência" /> set("enderecoObra", e.target.value)} placeholder="Rua, número — cidade/UF" />
Valores
set("peso", parseFloat(e.target.value) || 0)} suffix="kg" /> set("valor", v)} /> 0 ? fmtBRL(f.valor / f.peso) : "—"} disabled />
O faturamento por CNPJ (Padrão, FFC, Quantico) é registrado depois, parcela por parcela, conforme as NFs forem emitidas.
); } window.VendaDetail = VendaDetail; window.NovaVendaModal = NovaVendaModal;