Preenchimento Automático de Tributos - Item de Terceiro (Ordem de Compra)
📋 Visão Geral
Este documento explica como funciona o preenchimento automático da seção "Condição Fiscal e Tributária da Compra" na tela de adição de itens em Ordens de Compra.
URL da tela: http://localhost:8000/comercial/adicionar-item-estoque/{pedidoId}?tipoPedidoItem=OrdemCompra
🔄 Fluxo Completo de Preenchimento
┌─────────────────────────────────────────────────────────────┐
│ 1. Usuário seleciona mercadoria │
└───────────────────┬─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 2. JavaScript busca CFOPs disponíveis (AJAX) │
│ Endpoint: /comercial/pedidoitem/obter-cfop-configuracoes│
└───────────────────┬─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 3. CFOP é selecionado (automático ou manual) │
└───────────────────┬─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 4. JavaScript busca configurações ICMS/IPI/PIS-COFINS │
│ Endpoints: │
│ - /comercial/pedidoitem/obter-icms-configuracoes │
│ - /comercial/pedidoitem/obter-ipi-configuracoes │
│ - /comercial/pedidoitem/obter-piscofins-configuracoes │
└───────────────────┬─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 5. JavaScript chama endpoint calcular-tributos │
│ Endpoint: /comercial/pedidoitem/calcular-tributos │
└───────────────────┬─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 6. Backend calcula impostos usando _pedidoItemService │
└───────────────────┬─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 7. JavaScript preenche tabela com valores calculados │
│ Função: popularTabelaTributos(data) │
└─────────────────────────────────────────────────────────────┘
🎯 1. Carregamento Inicial da Página
Controller - PedidoItemController.cs
Arquivo: src/Nelmetais.SGE.WebApp/Areas/Comercial/Controllers/PedidoItemController.cs
// Linha 106-125
[Route("adicionar-item-estoque/{pedidoId:int}")]
[AuthorizeCustom(PermissaoTypeEnum.Pedido, PermissaoValueEnum.Adicionar)]
public async Task<IActionResult> Create(int pedidoId, TipoPedidoItemEnum tipoPedidoItem)
{
var pedidoItemViewModel = new PedidoItemViewModel
{
PedidoId = pedidoId,
Pedido = await ObterPedido(pedidoId),
TipoPedidoItem = (int)tipoPedidoItem
};
if (tipoPedidoItem == TipoPedidoItemEnum.OrdemCompra)
pedidoItemViewModel.OrdemCompraItem = new() {
OrdemCompra = new() {
NaturezaOperacaoId = (int)TipoNaturezaOperacaoEnum.Compra
}
};
// Popula as listas dropdown incluindo tributos
pedidoItemViewModel = await PopularListasDropDown(pedidoItemViewModel);
return View(pedidoItemViewModel);
}
Método PopularListasDropDown
// Linha 267-304
private async Task<PedidoItemViewModel> PopularListasDropDown(PedidoItemViewModel viewModel)
{
ViewBag.TiposOrigemMercadoria = await PopularTiposOrigemMercadoria();
ViewBag.Fornecedores = await PopularFornecedores();
ViewBag.Empresas = await PopularEmpresas();
ViewBag.TiposNormaCorte = await PopularTiposNormaCorte();
ViewBag.Cfops = await PopularCfops();
if (viewModel.TipoPedidoItem == (int)TipoPedidoItemEnum.OrdemCompra)
{
ViewBag.EmpresasOrdemCompra = await PopularEmpresas(retornarPessoaId: false);
ViewBag.FornecedoresOrdemCompra = await PopularFornecedorOrdemCompra(viewModel.OrdemCompraItem?.OrdemCompra?.FornecedorId);
ViewBag.TransportadoresOrdemCompra = await PopularTransportador(viewModel.OrdemCompraItem?.OrdemCompra?.TransportadorId);
ViewBag.FormasPagamento = await PopularFormasPagamento();
ViewBag.TiposOrigemMercadoria = await PopularTiposOrigemMercadoria();
ViewBag.UnidadesMedidas = await PopularUnidadesMedidas();
ViewBag.CstIcms = await PopularCstIcms();
ViewBag.CstIpi = await PopularCstIpi();
if (viewModel.OrdemCompraItem?.OrdemCompra!.NaturezaOperacao is null)
viewModel.OrdemCompraItem!.OrdemCompra!.NaturezaOperacao =
await _naturezaOperacaoRepository.ObterNaturezaOperacao(viewModel.OrdemCompraItem!.OrdemCompra!.NaturezaOperacaoId);
if (viewModel.OrdemCompraItem?.OrdemCompraItemImposto is not null)
{
if (viewModel.OrdemCompraItem.OrdemCompraItemImposto.NcmId.HasValue)
ViewBag.Ncm = await PopularNcm(viewModel.OrdemCompraItem.OrdemCompraItemImposto.NcmId.Value);
if (viewModel.OrdemCompraItem.OrdemCompraItemImposto.CfopId.HasValue)
ViewBag.Cfop = await PopularCfop(viewModel.OrdemCompraItem.OrdemCompraItemImposto.CfopId.Value);
}
}
// ← CHAMA PopularTributos
viewModel = await PopularTributos(viewModel);
return viewModel;
}
Método PopularTributos
// Linha 620-695
private async Task<PedidoItemViewModel> PopularTributos(PedidoItemViewModel viewModel)
{
if (viewModel.MercadoriaId != null)
{
// Busca configurações de CFOP
var selectCfopConfig = await PopularCfopConfiguracoes(viewModel.PedidoId, viewModel.MercadoriaId, viewModel.TipoOrigemMercadoriaId);
if (selectCfopConfig != null)
{
ViewBag.CfopConfig = selectCfopConfig;
if (viewModel.PedidoItemImposto is null)
viewModel.PedidoItemImposto = new();
var cfopConfigList = selectCfopConfig.Where(a => a.Value != "");
viewModel.PedidoItemImposto!.CfopConfigIds = cfopConfigList.Select(x => int.Parse(x.Value)).ToList();
if (selectCfopConfig != null && selectCfopConfig.Any())
{
int? cfopConfigId = null;
if (viewModel.PedidoItemImposto?.CfopConfigId != null)
cfopConfigId = viewModel.PedidoItemImposto?.CfopConfigId;
else if (selectCfopConfig.Count == 1)
{
bool sucesso = int.TryParse(selectCfopConfig.FirstOrDefault()!.Value, out int id);
if (sucesso) cfopConfigId = id;
}
if (cfopConfigId != null)
{
// Busca configurações de ICMS
var selectIcmsConfig = await PopularIcmsConfiguracoes(viewModel.PedidoId,
viewModel.TipoOrigemMercadoriaId,
viewModel.MercadoriaId,
cfopConfigId);
if (selectIcmsConfig != null)
{
ViewBag.IcmsConfig = selectIcmsConfig;
if (viewModel.PedidoItemImposto != null)
{
var icmsConfigList = selectIcmsConfig.Where(a => a.Value != "");
viewModel.PedidoItemImposto!.IcmsConfigIds = icmsConfigList.Select(x => int.Parse(x.Value)).ToList();
}
}
// Busca configurações de IPI
var selectIpiConfig = await PopularIpiConfiguracoes(viewModel.PedidoId,
viewModel.MercadoriaId,
cfopConfigId);
if (selectIpiConfig != null)
{
ViewBag.IpiConfig = selectIpiConfig;
if (viewModel.PedidoItemImposto != null)
{
var ipiConfigList = selectIpiConfig.Where(a => a.Value != "");
viewModel.PedidoItemImposto!.IpiConfigIds = ipiConfigList.Select(x => int.Parse(x.Value)).ToList();
}
}
// Busca configurações de PIS/COFINS
var selectPisCofinsConfig = await PopularPisCofinsConfiguracoes(viewModel.PedidoId,
viewModel.MercadoriaId,
cfopConfigId);
if (selectPisCofinsConfig != null)
{
ViewBag.PisCofinsConfig = selectPisCofinsConfig;
if (viewModel.PedidoItemImposto != null)
{
var piCofinsConfigList = selectPisCofinsConfig.Where(a => a.Value != "");
viewModel.PedidoItemImposto!.PisCofinsConfigIds = piCofinsConfigList.Select(x => int.Parse(x.Value)).ToList();
}
}
}
}
}
}
return viewModel;
}
🎯 2. Seleção de Mercadoria (Gatilho Principal)
JavaScript - _ValidationScriptsPedidoItemPartial.cshtml
Arquivo: src/Nelmetais.SGE.WebApp/Areas/Comercial/Views/PedidoItem/Shared/_ValidationScriptsPedidoItemPartial.cshtml
// Linha 44
selectMercadoriaSelecionada.addEventListener('change', selecionarMercadoria);
// Linha 170-184
function selecionarMercadoria() {
mercadoriaSelecionada = mercadorias.find(mercadoria => mercadoria.id == selectMercadoriaSelecionada.value);
popularSelectLiga();
popularSelectUnidadeComercial();
popularTabelaEstoqueMercadoria();
popularCaracteristicaMercadoria();
popularSelectPoliticaVenda();
popularSelectTipoServico();
popularSelectCfop(); // ← BUSCA CFOPs
calcularPesoTeorico();
mercadoriaSalvaId = selectMercadoriaSelecionada.value;
}
Função popularSelectCfop
// Linha 1068-1077
function popularSelectCfop() {
if (mercadoriaSalvaId != selectMercadoriaSelecionada.value) {
limparOptionsSelectNoChange(selectCfopConfiguracoes);
cfopConfigValues.value = '';
selecionarCfop(); // ← Busca CFOPs disponíveis via AJAX
selectCfopConfiguracoes.dispatchEvent(new Event('change'));
}
}
// Linha 1023-1027
function selecionarCfop() {
if (selectMercadoriaSelecionada.value) {
popularSelectCfopConfiguracoes(@Model.PedidoId, selectMercadoriaSelecionada.value);
}
}
🎯 3. Busca de Configurações de CFOP via AJAX
JavaScript
// Linha 870-898
function popularSelectCfopConfiguracoes(pedidoId, mercadoriaId) {
let selectTributo = selectCfopConfiguracoes;
let tibutoListaIds = cfopConfigValues;
let ids = '';
limparOptionsSelectNoChange(selectTributo);
tibutoListaIds.value = '';
if (pedidoId && mercadoriaId) {
$.ajax({
type: 'get',
url: '/comercial/pedidoitem/obter-cfop-configuracoes',
data: {
pedidoId: pedidoId,
mercadoriaId: mercadoriaId
},
dataType: 'json',
contentType: 'application/json; charset=utf-8',
async: false,
success(data) {
$.each(data, function (index, tributoConfiguracao) {
selectTributo.append(new Option(tributoConfiguracao.text, tributoConfiguracao.value))
ids = (ids != '' ? ids + "," : '') + tributoConfiguracao.value;
});
tibutoListaIds.value = ids;
},
});
}
}
Controller Endpoint
// PedidoItemController.cs:781-786
[HttpGet("[controller]/obter-cfop-configuracoes")]
[AuthorizeCustom(PermissaoTypeEnum.Pedido, PermissaoValueEnum.Listar)]
public async Task<JsonResult> ObterCfopConfiguracoes(int? pedidoId, int? mercadoriaId, int? tipoOrigemMercadoriaId)
{
return Json(await PopularCfopConfiguracoes(pedidoId, mercadoriaId, tipoOrigemMercadoriaId));
}
// Linha 521-543
private async Task<List<SelectListItem>?> PopularCfopConfiguracoes(int? pedidoId, int? mercadoriaId, int? tipoOrigemMercadoriaId)
{
var cfopConfiguracoes = await _pedidoItemService.ObterCfopConfiguracoes(pedidoId, mercadoriaId, tipoOrigemMercadoriaId);
if (cfopConfiguracoes != null && cfopConfiguracoes.Count > 0)
{
List<SelectListItem> listaCfopConfiguracoes = new();
listaCfopConfiguracoes = _mapper.Map<List<CfopConfig>>(cfopConfiguracoes)
.Select(x => new SelectListItem()
{
Value = x.Id.ToString(),
Text = $"{x.Id} - {x.Nome}"
}).ToList();
if (listaCfopConfiguracoes.Count > 1)
InserirSelectItemNaoEspecificado(listaCfopConfiguracoes);
return listaCfopConfiguracoes;
}
return null;
}
🎯 4. Seleção de CFOP Dispara Outros Tributos
// Linha 54
selectCfopConfiguracoes.addEventListener('change', selecionarTributos);
// Linha 1050-1066
function selecionarTributos() {
limparOptionsSelectNoChange(selectIcmsConfiguracoes);
limparOptionsSelectNoChange(selectIpiConfiguracoes);
limparOptionsSelectNoChange(selectPisCofinsConfiguracoes);
icmsConfigValues.value = '';
ipiConfigValues.value = '';
pisCofinsConfigValues.value = '';
selecionarIcms(); // ← Busca configurações ICMS
selecionarIpi(); // ← Busca configurações IPI
selecionarPisCofins(); // ← Busca configurações PIS/COFINS
calcularTributos(); // ← CALCULA OS VALORES DOS IMPOSTOS
configurarSelectTributos();
}
Busca de Configurações ICMS
// Linha 1029-1036
function selecionarIcms() {
if (selectMercadoriaSelecionada.value && selectTipoOrigemMercadoria.value && selectCfopConfiguracoes.value) {
popularSelectIcmsConfiguracoes(@Model.PedidoId,
selectTipoOrigemMercadoria.value,
selectMercadoriaSelecionada.value,
selectCfopConfiguracoes.value);
}
}
// Linha 900-930
function popularSelectIcmsConfiguracoes(pedidoId, tipoOrigemMercadoria, mercadoriaId, cfopConfigId) {
let selectTributo = selectIcmsConfiguracoes;
let tibutoListaIds = icmsConfigValues;
let ids = '';
limparOptionsSelectNoChange(selectTributo);
tibutoListaIds.value = '';
if (pedidoId && tipoOrigemMercadoria && mercadoriaId && cfopConfigId) {
$.ajax({
type: 'get',
url: '/comercial/pedidoitem/obter-icms-configuracoes',
data: {
pedidoId: pedidoId,
tipoOrigemMercadoria: tipoOrigemMercadoria,
mercadoriaId: mercadoriaId,
cfopConfigId: cfopConfigId
},
dataType: 'json',
contentType: 'application/json; charset=utf-8',
async: false,
success(data) {
$.each(data, function (index, tributoConfiguracao) {
selectTributo.append(new Option(tributoConfiguracao.text, tributoConfiguracao.value))
ids = (ids != '' ? ids + "," : '') + tributoConfiguracao.value;
});
tibutoListaIds.value = ids;
},
});
}
}
Controller Endpoint ICMS
// PedidoItemController.cs:788-793
[HttpGet("[controller]/obter-icms-configuracoes")]
[AuthorizeCustom(PermissaoTypeEnum.Pedido, PermissaoValueEnum.Listar)]
public async Task<JsonResult> ObterIcmsConfiguracoes(int? pedidoId, int? tipoOrigemMercadoria, int? mercadoriaId, int? cfopConfigId)
{
return Json(await PopularIcmsConfiguracoes(pedidoId, tipoOrigemMercadoria, mercadoriaId, cfopConfigId));
}
🎯 5. Cálculo dos Tributos (Parte Principal)
JavaScript - Chamada AJAX
// Linha 994-1021
function calcularTributos() {
if (@Model.PedidoId && selectMercadoriaSelecionada.value) {
$.ajax({
type: 'get',
url: '/comercial/pedidoitem/calcular-tributos',
data: {
pedidoId: @Model.PedidoId,
mercadoriaId: selectMercadoriaSelecionada.value,
cfopConfigId: selectCfopConfiguracoes.value,
icmsConfigId: selectIcmsConfiguracoes.value,
ipiConfigId: selectIpiConfiguracoes.value,
pisCofinsConfigId: selectPisCofinsConfiguracoes.value,
unidadeComercialId: selectUnidadeComercial.value,
unidadeSeparacaoId: selectUnidadeSeparacao.value,
quantidadeSeparacao: (inputQuantidadeSeparacao.value ? parseFloat(inputQuantidadeSeparacao.value.replace(",", ".")) : null),
comprimentoMM: inputComprimentoEmMM.value,
larguraMM: inputLarguraEmMM.value,
valorUnitario: (inputValorUnitario.value ? parseFloat(inputValorUnitario.value.replace(",", ".")) : null)
},
dataType: 'json',
contentType: 'application/json; charset=utf-8',
async: false,
success(data) {
popularTabelaTributos(data); // ← Preenche a tabela de impostos
},
});
}
}
Controller Endpoint - Cálculo de Tributos
// PedidoItemController.cs:809-842
[HttpGet("[controller]/calcular-tributos")]
[AuthorizeCustom(PermissaoTypeEnum.Pedido, PermissaoValueEnum.Listar)]
public async Task<JsonResult> CalcularTributos(int? pedidoId,
int? mercadoriaId,
int? cfopConfigId,
int? icmsConfigId,
int? ipiConfigId,
int? pisCofinsConfigId,
int? unidadeComercialId,
int? unidadeSeparacaoId,
decimal? quantidadeSeparacao,
int? comprimentoMM,
int? larguraMM,
decimal? valorUnitario)
{
var tributos = await _pedidoItemService
.CalcularTributos(new PedidoTributosDto()
{
PedidoId = pedidoId,
MercadoriaId = mercadoriaId,
CfopConfigId = cfopConfigId,
IcmsConfigId = icmsConfigId,
IpiConfigId = ipiConfigId,
PisCofinsConfigId = pisCofinsConfigId,
UnidadeComercialId = unidadeComercialId,
UnidadeSeparacaoId = unidadeSeparacaoId,
QuantidadeSeparacao = quantidadeSeparacao,
ComprimentoMM = comprimentoMM,
LarguraMM = larguraMM,
ValorUnitario = valorUnitario
});
return Json(tributos);
}
🎯 6. Preenchimento da Tabela de Tributos
JavaScript - Função popularTabelaTributos
// Linha 572-785
function popularTabelaTributos(tributos) {
let tabelaTributos = document.getElementById("table-tributos");
let body = tabelaTributos.querySelector("tbody");
if (tributos) {
let outerHTML = "";
let rows = $('#table-tributos').find('tbody > tr');
let cst = "", aliquota = "", aliquotaReducao = "", mva = "", baseCalculo = "", valor = "";
let cst_st = "", aliquota_st = "", aliquotaReducao_st = "", mva_st = "", baseCalculo_st = "", valor_st = "";
// Remove linhas existentes
for (let i = 0; i < rows.length; i++)
rows[i].remove();
// ICMS
if (tributos.cstIcms) {
cst = tributos.percentualIcms ? tributos.cstIcms.codigo : "";
aliquota = tributos.percentualIcms ? numberFormat(tributos.percentualIcms, 3) + " %" : "";
aliquotaReducao = tributos.percentualIcms ? numberFormat(tributos.percentualIcmsReducao, 3) + " %" : "";
baseCalculo = tributos.percentualIcms ? "R$ " + numberFormat(tributos.valorBaseCalculoIcms, 2) : "";
valor = tributos.percentualIcms ? "R$ " + numberFormat(tributos.valorIcms, 2) : "";
cst_st = tributos.percentualIcmsSt ? tributos.cstIcms.codigo : "";
aliquota_st = tributos.percentualIcmsSt ? numberFormat(tributos.percentualIcmsSt, 3) + " %" : "";
aliquotaReducao_st = tributos.percentualIcmsSt ? numberFormat(tributos.percentualIcmsStReducao, 3) + " %" : "";
mva_st = tributos.percentualIcmsSt ? numberFormat(tributos.percentualIcmsStMva, 3) + " %" : "";
baseCalculo_st = tributos.percentualIcmsSt ? "R$ " + numberFormat(tributos.valorBaseCalculoIcmsSt, 2) : "";
valor_st = tributos.percentualIcmsSt ? "R$ " + numberFormat(tributos.valorIcmsSt, 2) : "";
}
// Insere linha ICMS
outerHTML += `<td class="font-weight-bold align-middle text-left">ICMS</td>`
outerHTML += `<td id="cst_icms" class="align-middle">${cst}</td>`
outerHTML += `<td id="percentual_icms" class="align-middle">${aliquota}</td>`
outerHTML += `<td id="percentual_reducao_icms" class="align-middle">${aliquotaReducao}</td>`
outerHTML += `<td id="percentual_mva_icms" class="align-middle">${mva}</td>`
outerHTML += `<td id="valor_base_icms" class="align-middle">${baseCalculo}</td>`
outerHTML += `<td id="valor_icms" class="align-middle">${valor}</td>`
row = body.insertRow();
row.innerHTML = outerHTML;
// ... Continua para ICMS ST, IPI, PIS, COFINS, FCP, etc.
}
}
View - Tabela de Tributos
Arquivo: src/Nelmetais.SGE.WebApp/Areas/Comercial/Views/PedidoItem/Shared/_FiscalTributarioPartial.cshtml
<!-- Linha 38-213 -->
<table id="table-tributos" class="table table-bordered table-hover table-sm">
<thead>
<tr class="table-secondary text-center">
<th class="text-left" style="width: 100px;">Imposto</th>
<th>CST</th>
<th>Alíquota</th>
<th>Alíquota Redução</th>
<th>MVA</th>
<th>Valor Base Cálculo</th>
<th>Valor Imposto</th>
</tr>
</thead>
<tbody>
<!-- Linhas preenchidas dinamicamente via JavaScript -->
<tr>
<td class="font-weight-bold align-middle text-left">ICMS</td>
<td id="cst_icms" class="align-middle">...</td>
<td id="percentual_icms" class="align-middle">...</td>
<td id="percentual_reducao_icms" class="align-middle">...</td>
<td id="percentual_mva_icms" class="align-middle"></td>
<td id="valor_base_icms" class="align-middle">...</td>
<td id="valor_icms" class="align-middle">...</td>
</tr>
<!-- ICMS ST, IPI, PIS, COFINS, FCP -->
</tbody>
</table>
⚡ Gatilhos para Recálculo Automático
Os tributos são recalculados automaticamente quando você altera:
// Event Listeners
selectCfopConfiguracoes.addEventListener('change', selecionarTributos); // Linha 54
selectIcmsConfiguracoes.addEventListener('change', calcularTributos); // Linha 55
selectIpiConfiguracoes.addEventListener('change', calcularTributos); // Linha 56
selectPisCofinsConfiguracoes.addEventListener('change', calcularTributos); // Linha 57
selectUnidadeSeparacao.addEventListener('change', calcularTributos); // Linha 47
inputQuantidadeSeparacao.addEventListener('blur', calcularTributosQuantidadeSeparacao); // Linha 62
inputValorUnitario.addEventListener('blur', calcularTributosValorUnitario); // Linha 63
// NH-118: Verificar se campos existem antes de adicionar event listeners (campos ocultos para OrdemCompra)
if (inputComprimentoEmMM) {
inputComprimentoEmMM.addEventListener('blur', calcularTributosComprimentoEmMM); // Linha 70
}
if (inputLarguraEmMM) {
inputLarguraEmMM.addEventListener('blur', calcularTributosLarguraEmMM); // Linha 72
}
Campos que Disparam Recálculo
| Campo | Evento | Descrição |
|---|---|---|
| CFOP Config | change |
Muda todas as configurações tributárias |
| ICMS Config | change |
Recalcula todos os impostos |
| IPI Config | change |
Recalcula todos os impostos |
| PIS/COFINS Config | change |
Recalcula todos os impostos |
| Unidade de Separação | change |
Afeta base de cálculo |
| Quantidade Separação | blur |
Afeta valor total e base de cálculo |
| Valor Unitário | blur |
Afeta valor total e base de cálculo |
| Comprimento (MM) | blur |
Afeta quantidade e base de cálculo |
| Largura (MM) | blur |
Afeta quantidade e base de cálculo |
| Tipo Origem Mercadoria | change |
Afeta configurações de ICMS |
📊 Dados Retornados pelo Cálculo
O endpoint /comercial/pedidoitem/calcular-tributos retorna um objeto PedidoTributosDto com:
{
"cstIcms": { "codigo": "00", "nome": "Tributada integralmente" },
"percentualIcms": 18.00,
"percentualIcmsReducao": 0.00,
"valorBaseCalculoIcms": 1000.00,
"valorIcms": 180.00,
"percentualIcmsSt": 18.00,
"percentualIcmsStReducao": 0.00,
"percentualIcmsStMva": 30.00,
"valorBaseCalculoIcmsSt": 1300.00,
"valorIcmsSt": 234.00,
"cstIpi": { "codigo": "50", "nome": "Saída tributada" },
"percentualIpi": 5.00,
"valorBaseCalculoIpi": 1000.00,
"valorIpi": 50.00,
"cstPis": { "codigo": "01", "nome": "Operação Tributável" },
"percentualPis": 1.65,
"valorBaseCalculoPis": 1000.00,
"valorPis": 16.50,
"percentualPisSt": 0.00,
"valorBaseCalculoPisSt": 0.00,
"valorPisSt": 0.00,
"cstCofins": { "codigo": "01", "nome": "Operação Tributável" },
"percentualCofins": 7.60,
"valorBaseCalculoCofins": 1000.00,
"valorCofins": 76.00,
"percentualCOFINSST": 0.00,
"valorBaseCalculoCofinsSt": 0.00,
"valorCofinsSt": 0.00,
"percentualFcp": 2.00,
"valorBaseCalculoFcp": 1000.00,
"valorFcp": 20.00,
"percentualFcpSt": 0.00,
"valorBaseCalculoFcpSt": 0.00,
"valorFcpSt": 0.00
}
🔍 Arquivos Envolvidos
Backend (C#)
| Arquivo | Responsabilidade |
|---|---|
PedidoItemController.cs |
Controla requisições HTTP e coordena serviços |
IPedidoItemService |
Interface do serviço de cálculo de tributos |
PedidoItemService |
Implementa lógica de cálculo de impostos |
ICfopConfigRepository |
Busca configurações de CFOP |
IIcmsConfigRepository |
Busca configurações de ICMS |
IIpiConfigRepository |
Busca configurações de IPI |
IPisCofinsConfigRepository |
Busca configurações de PIS/COFINS |
Frontend (JavaScript/Razor)
| Arquivo | Responsabilidade |
|---|---|
_ValidationScriptsPedidoItemPartial.cshtml |
JavaScript principal com lógica de interação |
_FiscalTributarioPartial.cshtml |
View da seção de tributos |
Create.cshtml / Edit.cshtml |
Views principais do formulário |
📝 Observações Importantes
- Ordem de Execução: As configurações são buscadas em cascata (CFOP → ICMS → IPI → PIS/COFINS)
- Dependências: Cada configuração tributária depende da anterior
- Cálculo Automático: O cálculo é disparado automaticamente em qualquer alteração relevante
- Performance: Chamadas AJAX são síncronas (
async: false) para garantir ordem de execução - Validação: Todos os cálculos dependem de ter mercadoria selecionada e pedido válido
🚀 Fluxo Simplificado
Cada etapa busca as configurações disponíveis no backend e, ao final, o cálculo real dos valores é feito pelo serviço _pedidoItemService.CalcularTributos().
Última atualização: 2025-11-10
Relacionado: Ver também NATUREZA-OPERACAO-ORDEM-COMPRA.md