Giuliano Paschoalino 606b841435 feat: Add ComplianceNFs.Infrastructure.Tests project and implement unit tests for various services
- Added ComplianceNFs.Infrastructure.Tests project to the solution.
- Implemented unit tests for AccessDbRepository, ArchivingService, AttachmentRepository, InvoiceIngestionService, MailListener, MonitorViewModel, and Worker.
- Enhanced existing tests with additional assertions and mock setups.
- Updated TODOs and roadmap documentation to reflect changes in service implementations and testing coverage.
- Modified ComplianceNFs.sln to include new test project and adjust solution properties.
2025-06-18 16:34:44 -03:00

134 lines
5.4 KiB
C#

using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using ComplianceNFs.Core.Entities;
using ComplianceNFs.Core.Ports;
using Unimake.Business.DFe.Xml.NFe;
namespace ComplianceNFs.Infrastructure.Parsers
{
public class XmlParser : IXmlParser
{
public ParsedInvoice Parse(Stream xmlStream)
{
string xml = ReadXmlFromStream(xmlStream);
var nfeProc = Unimake.Business.DFe.Utility.XMLUtility.Deserializar<NfeProc>(xml);
var infNFe = nfeProc.NFe.InfNFe.First();
var comprador = infNFe.Dest;
var vendedor = infNFe.Emit;
var produtos = infNFe.Det;
var detalhes = produtos.First();
var impostos = detalhes.Imposto;
decimal somaProdutos = CalcularSomaProdutos(produtos);
decimal montanteOperacao = CalcularMontanteOperacao(produtos);
decimal valorFinalComImpostos = CalcularValorFinalComImpostos(infNFe);
decimal icmsNF = CalcularICMS(impostos.ICMS, somaProdutos, valorFinalComImpostos);
decimal valorUnitario = CalcularValorUnitario(comprador, vendedor, somaProdutos, montanteOperacao, icmsNF);
return new ParsedInvoice
{
CnpjComp = FormatCnpjOrCpf(comprador.CNPJ ?? comprador.CPF),
CnpjVend = FormatCnpjOrCpf(vendedor.CNPJ),
MontNF = montanteOperacao,
PrecNF = valorUnitario,
ValorFinalComImpostos = valorFinalComImpostos,
RsComp = DecodeHtml(comprador?.XNome),
RsVend = DecodeHtml(vendedor?.XNome),
NumeroNF = infNFe.Ide.NNF.ToString(),
IcmsNF = icmsNF,
UfComp = comprador?.EnderDest?.UF.ToString(),
UfVend = vendedor?.EnderEmit?.UF.ToString()
};
}
private static string ReadXmlFromStream(Stream xmlStream)
{
using var reader = new StreamReader(xmlStream, Encoding.UTF8, true, 1024, leaveOpen: true);
string xml = reader.ReadToEnd();
xmlStream.Position = 0;
return xml;
}
private static decimal CalcularSomaProdutos(System.Collections.Generic.List<Det> produtos)
{
return produtos.Sum(prod =>
(prod.Prod.UCom == "KWH" ? prod.Prod.QCom / 1000M : prod.Prod.QCom) *
(prod.Prod.UCom == "KWH" ? prod.Prod.VUnCom * 1000M : prod.Prod.VUnCom)
);
}
private static decimal CalcularMontanteOperacao(System.Collections.Generic.List<Det> produtos)
{
return produtos.Sum(prod => prod.Prod.UCom == "KWH" ? prod.Prod.QCom / 1000M : prod.Prod.QCom);
}
private static decimal CalcularValorFinalComImpostos(InfNFe infNFe)
{
if (infNFe.Pag?.DetPag?.Sum(pag => pag.VPag) > 0)
return (decimal)infNFe.Pag.DetPag.Sum(pag => pag.VPag);
if (infNFe.Cobr?.Fat?.VLiq > 0)
return (decimal)infNFe.Cobr.Fat.VLiq;
return 0;
}
private static decimal CalcularICMS(ICMS icms, decimal somaProdutos, decimal valorFinalComImpostos)
{
decimal icmsValue = GetICMS(icms);
if (icmsValue == 0 && valorFinalComImpostos != 0)
return 1 - (somaProdutos / valorFinalComImpostos);
return icmsValue;
}
private static decimal CalcularValorUnitario(Dest comprador, Emit vendedor, decimal somaProdutos, decimal montanteOperacao, decimal icmsNF)
{
if (comprador.EnderDest.UF.ToString() == "SP" && vendedor.EnderEmit.UF.ToString() == "SP")
{
return montanteOperacao == 0 ? 0 : somaProdutos / montanteOperacao * (1 - icmsNF);
}
else
{
return montanteOperacao == 0 ? 0 : somaProdutos / montanteOperacao;
}
}
private static string? FormatCnpjOrCpf(string? value)
{
if (string.IsNullOrWhiteSpace(value)) return null;
if (long.TryParse(value, out var num))
return num.ToString("00000000000000");
return value;
}
private static string? DecodeHtml(string? value)
{
return value != null ? WebUtility.HtmlDecode(value) : null;
}
public static decimal GetICMS(ICMS icms)
{
var propICMS = icms.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.Name.StartsWith("ICMS"))
.ToList();
var primeiraProp = propICMS
.Select(p => new { Prop = p, Valor = p.GetValue(icms) })
.FirstOrDefault(x => x.Valor != null);
if (primeiraProp == null || primeiraProp.Valor == null) return 0;
var tipo = primeiraProp.Valor.GetType();
var valor = Convert.ChangeType(primeiraProp.Valor, tipo);
var listICMSReal = valor.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.Name.StartsWith("PICMS"))
.Select(p => p.GetValue(valor))
.FirstOrDefault();
decimal icmsReal = 0;
if (listICMSReal != null && decimal.TryParse(listICMSReal.ToString(), out icmsReal))
icmsReal /= 100m;
return icmsReal;
}
}
}