/* global React */
const { useState, useRef } = React;
const { brl, pct, intFmt } = window;
function ProdutoView({ produto, params, setProduto, viewingMode, onExitView, onSave, savingHint, onShowToast }) {
if (!produto) return null;
const c = window.calcProduto(produto, params);
// Estado do XML
const [xmlText, setXmlText] = useState('');
const [xmlModalOpen, setXmlModalOpen] = useState(false);
const [xmlParsed, setXmlParsed] = useState(null);
const setNF = (patch) => setProduto({ ...produto, nf: { ...produto.nf, ...patch } });
const setProd = (patch) => setProduto({ ...produto, prod: { ...produto.prod, ...patch } });
const setInsumo = (idx, patch) => {
const novo = [...produto.insumos];
novo[idx] = { ...novo[idx], ...patch };
setProduto({ ...produto, insumos: novo });
};
const addInsumo = () => {
setProduto({
...produto,
insumos: [...produto.insumos, { nome: 'Novo insumo', valor: 0, credPC: false, credICMS: false, aliqICMS: 18, nota: '', custom: true }]
});
};
const removeInsumo = (idx) => {
const novo = [...produto.insumos];
novo.splice(idx, 1);
setProduto({ ...produto, insumos: novo });
};
const processarXml = () => {
const texto = (xmlText || '').trim();
if (!texto) {
onShowToast('Cole o XML da NF-e no campo acima', 'err');
return;
}
const parsed = window.parseXmlNFe(texto);
if (!parsed.ok) {
onShowToast(parsed.erro || 'Falha ao processar XML', 'err');
return;
}
// Agrupa para decidir se precisa de seleção
const grupos = window.agruparItensXml(parsed.itens);
if (grupos.length === 1) {
// Item único: aplica direto sem abrir modal
const selecao = window.calcularSelecaoXml(grupos, parsed);
aplicarXml(selecao, parsed);
} else {
// Múltiplos itens: abre modal de seleção
setXmlParsed(parsed);
setXmlModalOpen(true);
}
};
const aplicarXml = (selecao, parsed) => {
const { produtoAtualizado, kgPreenchido } = window.aplicarXmlAoProduto(produto, selecao, parsed);
setProduto(produtoAtualizado);
setXmlText(''); // limpa textarea
let msg = `XML importado: ${parsed.fornecedor || 'fornecedor'} — ${selecao.qtdItens} item(s)`;
if (selecao.hasST) msg += ' · ⚠ contém ICMS-ST (sem crédito)';
if (!kgPreenchido) msg += ` · ⚠ unidade "${selecao.unidade}" — preencha kg manualmente`;
onShowToast(msg, selecao.hasST || !kgPreenchido ? 'warn' : 'ok');
};
const onXmlModalConfirm = ({ selecao, parsed }) => {
setXmlModalOpen(false);
aplicarXml(selecao, parsed);
setXmlParsed(null);
};
const onXmlModalCancel = () => {
setXmlModalOpen(false);
setXmlParsed(null);
};
const kgWarn = produto.nf.xmlInfo && produto.nf.xmlInfo.isKg === false;
return (
<>
{viewingMode && (
Modo visualização — versão v#{String(viewingMode.seq).padStart(4, '0')}
salvo em {new Date(viewingMode.createdAt).toLocaleString('pt-BR')}
)}
setProduto({ ...produto, nome: e.target.value })}
placeholder="Nome do produto"
/>
CMV {brl(c.cmv.cmvUn, 4)} / un
{intFmt(produto.prod.qtd)} un / dia
{produto.nf.kg} kg / nota
XML
Importar NF-e
Cole o XML para preencher os campos da NF
{produto.nf.xmlInfo && (
XML importado: {produto.nf.xmlInfo.fornecedor || '—'} ·{' '}
{produto.nf.xmlInfo.qtdItens} item(s) · Unidade {produto.nf.xmlInfo.unidade}
)}
01
Nota fiscal da matéria-prima
setNF({ valor: n })} />
setNF({ kg: n })}
className={`mono ${kgWarn ? 'input-warn' : ''}`}
/>
{kgWarn && (
⚠ XML veio em "{produto.nf.xmlInfo.unidade}" — converta manualmente.
)}
setNF({ icms: n })} />
setNF({ ipi: n })} />
setNF({ simples: val })}
options={[{ value: 'SIM', label: 'Sim' }, { value: 'NAO', label: 'Não' }]}
/>
Despesas acessórias
setNF({ frete: n })} />
setNF({ seguro: n })} />
setNF({ outras: n })} />
setNF({ desconto: n })} />
Decomposição automática
{brl(c.nf.valorProd)}
{brl(c.nf.icmsDestac)}
{brl(c.nf.basePC)}
{brl(c.nf.credPIS)}
{brl(c.nf.credCOFINS)}
{brl(c.nf.credTotal)}
{brl(c.nf.custoLiq)}
{brl(c.nf.custoKg, 4)}
02
Custos diários de produção
Subtotal: {brl(c.insumos.subtotal)} / dia
Insumo
Valor / dia
Alíq. ICMS
Créd. PIS/COF.
Créd. ICMS
Observação
{produto.insumos.map((item, idx) => (
{item.custom ? (
setInsumo(idx, { nome: e.target.value })}
/>
) : (
{item.nome}
)}
setInsumo(idx, { valor: n })} />
setInsumo(idx, { aliqICMS: n })} />
setInsumo(idx, { credPC: val === 'SIM' })}
options={[{ value: 'SIM', label: 'Sim' }, { value: 'NAO', label: 'Não' }]}
/>
setInsumo(idx, { credICMS: val === 'SIM' })}
options={[{ value: 'SIM', label: 'Sim' }, { value: 'NAO', label: 'Não' }]}
/>
{item.custom ? (
setInsumo(idx, { nota: e.target.value })}
placeholder="Observação"
/>
) : (
{item.nota}
)}
{item.custom && (
)}
))}
Subtotal custos diretos
{brl(c.insumos.subtotal)}
setProd({ mpKg: n })} />
setProd({ qtd: n })} />
04
CMV — Custo da mercadoria vendida
Custo MP líquida (consumo × R$/kg)
{brl(c.cmv.mpDia)}
Custos diretos / dia
{brl(c.insumos.subtotal)}
(−) Créditos apurados
{brl(-c.insumos.credTotalDiretos)}
Custo total de produção / dia
{brl(c.cmv.custoTotalDia)}
Quantidade produzida / dia
{intFmt(produto.prod.qtd)} un
CMV unitário
{brl(c.cmv.cmvUn, 4)}
/ un
Salvar registra uma versão imutável deste produto no histórico.
>
);
}
window.ProdutoView = ProdutoView;