Files
Asegasa.NET/WSAsegasa/ProcesosVeriFactuAsegasa.cs

516 lines
23 KiB
C#

using bdAsegasa;
using bdAsegasa.db;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Update.Internal;
using System;
using System.Collections.Generic;
using System.Diagnostics.Eventing.Reader;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using System.Web.Services.Description;
using System.Xml;
using tsUtilidades;
using tsUtilidades.Enumeraciones;
using tsUtilidades.Extensiones;
using tsVeriFactu;
using tsVeriFactu.tsClases;
using wsVerifactu;
using static bdAsegasa.db.registrosverifactu;
using static Org.BouncyCastle.Math.EC.ECCurve;
using static Quartz.Logging.OperationName;
using static tsVeriFactu.Enums;
using static tsVeriFactu.tsDetalle;
namespace WSAsegasa
{
public class ProcesosVeriFactuAsegasa : ItsVeriFactu
{
private tscgestionasegasa? bd;
private List<registrosverifactu>? lrp;
private DatosConfig? Configuracion;
private enumeraciones? confVerifactu = null;
private enumeraciones? confSI = null;
public async Task Iniciar(CancellationToken cancellationToken)
{
try
{
bd = tscgestionasegasa.NuevoContexto(Procesos.Conf.NombreConexionBD, true, false, true, "ProcesosVeriFactu");
confVerifactu = bd.enumeraciones.First(x => x.Codigo == "VF.CONF");
var Hoy = DateTime.Today;
confSI = bd.enumeraciones.Where(x => x.Codigo.StartsWith("VF.SI-") && x.Fecha1.HasValue && x.Fecha1 <= Hoy).OrderByDescending(x => x.Fecha1).FirstOrDefault();
if (confSI != null)
{
if (confVerifactu.Fecha2.HasValue == false)
{
if (confVerifactu.Fecha3.HasValue)
{
TimeSpan espera = confVerifactu.Fecha3.Value - DateTime.Now;
if (espera.TotalMilliseconds > 0) await System.Threading.Tasks.Task.Delay(espera, cancellationToken);
}
confVerifactu.ValorAlfabeticoLargo = "";
var pc = await tsVeriFactu.Procesos.EnviaFacturasAEAT(this, cancellationToken);
}
}
}
catch (Exception ex)
{
Logs.AñadeLog(tsUtilidades.Enumeraciones.TipoLog.Fallo, ex.Message, ex);
}
}
public DatosConfig ObtieneConfiguracion()
{
var bd = tscgestionasegasa.NuevoContexto(Procesos.Conf.NombreConexionBD, true, false, true, "ProcesosVeriFactu");
var bdts = bdFactu.tscFactu.NuevoContexto("Producción", true, false, true, "ProcesosVeriFactu");
//var emp = bd.enumeraciones.First(x => x.Codigo == "CONF.EMP");
var rso = bd.enumeraciones.First(x => x.Codigo == "DATEMP.RAZONSOCIAL").ValorAlfabeticoLargo;
var cif = bd.enumeraciones.First(x => x.Codigo == "DATEMP.CIF").ValorAlfabeticoLargo;
var c = bdts.certificados.First(x => x.Codigo == "PFX-A29221801" && x.FechaValidez <= DateTime.Now && x.FechaCaducidad >= DateTime.Now);
var p = tsUtilidades.crypt.SHA256(System.Text.Encoding.UTF8.GetBytes(c.FechaCaducidad.Value.ToString("yyyyMMddhhmmss") + c.CERT_ID + "-M3Soft."));
Assembly ensamblado = Assembly.GetAssembly(typeof(ProcesosVeriFactuAsegasa));
var Version = ensamblado?.GetName().Version?.Major.ToString().PadLeft(3, '0') + "." + ensamblado?.GetName().Version?.Minor.ToString().PadLeft(3, '0') + "." + ensamblado?.GetName().Version?.Build.ToString().PadLeft(3, '0');
Configuracion = new DatosConfig(
NIFEmpresa: cif,
RazonSocialEmpresa: rso,
EsProduccion: confSI.ValorNumerico4.Value > 0,
Certificado: new X509Certificate2(c.ContenedorClaves, p),
TipoCertificadoSello: false,
datosSistemInfor: new tsDatosSistemaInformatico
{
NombreRazon = confSI.ValorAlfabetico1,
NIFEmpresa = confSI.ValorAlfabetico2,
NombreSistemaInformatico = confSI.ValorAlfabetico3,
IdSistemaInformatico = confSI.ValorNumerico1.ToString(),
Version = Version,
NumeroInstalacion = confSI.ValorNumerico2.ToString().PadLeft(12, '0'),
}
);
return Configuracion;
}
public List<tsRegistroFacturacion> ObtenerOperacionesPendientes()
{
DateTime Ahora = DateTime.Now;
int OperAlta = (int)bdAsegasa.db.registrosverifactu.OperacionEnum.ALTA;
//DateTime fl = DateTime.Now.AddMinutes(-120);
DateOnly fl = DateOnly.FromDateTime(DateTime.Now);
DateOnly fc = DateOnly.FromDateTime(confSI.Fecha1.Value);
int tl = (int)AplicacionEnum.LIQUIDACION_AGENTE;
var lfp = bd.liquidacionesagentes
.Where(l =>
l.idSerieFactura.HasValue &&
l.FechaFactura.HasValue &&
l.FechaFactura.Value >= fc &&
l.FechaFactura.Value <= fl &&
l.idSerieFacturaNavigation.TipoVerifactu.HasValue &&
!bd.registrosverifactu.Any(r => r.idAplicacion == l.idLiquidacionAgente && r.TipoFactura==tl)
).OrderBy(x => x.FechaFactura).ThenBy(x => x.NumeroFactura).ToList();
//List<bdAsegasa.db.liquidacionesagentes> lfp = bd.liquidacionesagentes.Where(x => x.idSerieFactura.HasValue && x.FechaFactura.HasValue && x.FechaFactura.Value >= fc && x.FechaEmision < fl && x.idSerieFacturaNavigation.TipoVerifactu.HasValue && !x.registrosverifactu.Any(y => y.Operacion == OperAlta)).OrderBy(x => x.FechaFactura).ThenBy(x => x.NumeroFactura).ToList();
foreach (var f in lfp)
{
registrosverifactu rvf = new registrosverifactu();
bd.registrosverifactu.Add(rvf);
rvf.idAplicacion = f.idLiquidacionAgente;
rvf.Aplicacion = (int)registrosverifactu.AplicacionEnum.LIQUIDACION_AGENTE;
rvf.TipoFactura = f.idSerieFacturaNavigation.TipoVerifactu.Value;
rvf.Estado = (int)bdAsegasa.db.registrosverifactu.EstadoEnum.PENDIENTE_RESPUESTA;
rvf.FechaGeneracion = DateTime.Now;
rvf.Operacion = OperAlta;
}
bd.SaveChanges();
int EstPendiente = (int)bdAsegasa.db.registrosverifactu.EstadoEnum.PENDIENTE_RESPUESTA;
lrp = bd.registrosverifactu.Where(x => x.Estado == EstPendiente).OrderBy(x => x.idRegistro).ToList();
return LiquidacionesAgentesAtsFACTURAS();
}
private List<tsRegistroFacturacion> LiquidacionesAgentesAtsFACTURAS()
{
List<tsRegistroFacturacion> lf = new List<tsRegistroFacturacion>();
try
{
var rso = bd.enumeraciones.First(x => x.Codigo == "DATEMP.RAZONSOCIAL").ValorAlfabeticoLargo;
var cif = bd.enumeraciones.First(x => x.Codigo == "DATEMP.CIF").ValorAlfabeticoLargo;
foreach (registrosverifactu r in lrp)
{
try
{
if (r.Operacion == (int)registrosverifactu.OperacionEnum.ANULACIÓN)
{
// Anulación de factura
liquidacionesagentes fCancelar = bd.liquidacionesagentes.First(x=> x.idLiquidacionAgente==r.idAplicacion);
tsRegistroFacturacionAnulacion nf = new tsRegistroFacturacionAnulacion(
"01",
fCancelar.idAgenteNavigation.CIF,
fCancelar.NumeroFacturaVF(confSI.ValorAlfabetico4),
fCancelar.FechaFactura.Value,
r.idRegistro.ToString()
);
lf.Add(nf);
}
else
{
liquidacionesagentes fr = bd.liquidacionesagentes.First(x => x.idLiquidacionAgente == r.idAplicacion);
tsRegistroFacturacionAlta nf = new tsRegistroFacturacionAlta(
"01",
fr.idAgenteNavigation.CIF,//emp.ValorAlfabetico1,
fr.FechaFactura.Value.Year==2025? "2025": fr.idSerieFacturaNavigation.Serie,
fr.NumeroFacturaVF(confSI.ValorAlfabetico4),
fr.FechaFactura.Value,
fr.idAgenteNavigation.Nombre, // emp.ValorAlfabeticoLargo,
TercerosODestinatarioType.D,
(ClaveTipoFacturaType)fr.idSerieFacturaNavigation.TipoVerifactu,
"COMISIONES SEGUROS",
rso, //fr.idAgenteNavigation.Nombre ,
cif, //fr.idAgenteNavigation.CIF,
fr.IVA,
fr.TotalFacturaSinIRPF,
ObtieneImpuestos(fr).ToArray(),
r.idRegistro.ToString(),
(TipoRegistroAltaEnum)r.Operacion
);
if (nf.TipoFactura >= ClaveTipoFacturaType.R1 )
{
nf.TipoRectificativa = TipoRectificativaEnum.POR_DIFERENCIAS;
nf.FacturasRectificadas = new List<tsFacturaRectificada>();
foreach (var frect in fr.InverseidLiquidacionRectificativaNavigation)
{
nf.FacturasRectificadas.Add(new tsFacturaRectificada
{
NumeroFacturaRectificada = frect.NumeroFacturaVF(confSI.ValorAlfabetico4),
FechaFacturaRectificada = frect.FechaFactura.Value,
BaseImponibleRectificada = frect.BaseImponible,
CuotaRectificada = frect.IVA,
CuotaRecargoRectificada = null
});
}
}
lf.Add(nf);
}
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
return lf;
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
public static List<tsDetalle> ObtieneImpuestos(liquidacionesagentes factura)
// IdOperacionesTrascendenciaTributariaType:
// Representa el tipo de operación con trascendencia tributaria según el reglamento VERI*FACTU.
// Estos valores permiten clasificar las facturas según su naturaleza fiscal.
// 01 - Operación sujeta y no exenta de IVA
// 02 - Operación sujeta y exenta de IVA
// 03 - Operación no sujeta a IVA
// 04 - Operación intracomunitaria
// 05 - Exportación
// 06 - Régimen especial (agencias de viajes, bienes usados, etc.)
// 07 - Operación con inversión del sujeto pasivo
// 08 - Operación en régimen simplificado
// 09 - Operación en régimen de recargo de equivalencia
// 10 - Otras operaciones con relevancia tributaria
// S1,
// Operación sujeta a IVA (tipo general, reducido o superreducido).
// Ejemplo: Ventas estándar de bienes y servicios (21%, 10%, 4%).
// S2,
// Operación sujeta a IVA con régimen especial (Recargo de Equivalencia, Agricultura, etc.).
//Ejemplo: Ventas en Recargo de Equivalencia para comerciantes minoristas.
// N1,
// Operación exenta de IVA (pero declarable).
// Ejemplo: Servicios médicos, educación, servicios financieros exentos.
// N2
// Operación no sujeta a IVA (fuera del ámbito del impuesto).
// Ejemplo: Donaciones, ventas entre particulares no profesionales.
// CAUSA DE EXENCIÓN (E1 a E8 y NA)
/// <summary>
/// No asignada causa exención.
/// </summary>
///NA,
/// <summary>
/// Exenta por el artículo 20 (Exenciones en operaciones interiores).
/// </summary>
///E1,
/// <summary>
/// Exenta por el artículo 21 (Exportaciones).
/// </summary>
///E2,
/// <summary>
/// Exenta por el artículo 22 (Operaciones asimiladas a las
/// exportaciones: Navegación marítima internacional, aeronaves...).
/// </summary>
///E3,
/// <summary>
/// Exenta por los artículos 23 y 24 (Exenciones relativas a
/// regímenes aduaneros y fiscales: Depositos aduaneros...).
/// </summary>
///E4,
/// <summary>
/// Exenta por el artículo 25 (Operaciones UE).
/// </summary>
///E5,
/// <summary>
/// Exenta por otros.
/// </summary>
///E6,
/// <summary>
/// Reservado 1 Impuesto = “03” (IGIC)
/// </summary>
///E7,
/// <summary>
/// Reservado Impuesto = “03” (IGIC)
/// </summary>
///E8
{
List<tsDetalle> listaImpuestos = new List<tsDetalle>();
tsDetalle nd = new tsDetalle();
nd.ClaveRegimen = (IdOperacionesTrascendenciaTributariaType)factura.idSerieFacturaNavigation.TranscendenciaTributaria.Value;
nd.CalificacionOperacionOExencion = (CalificacionOperacionOExencionEnum)factura.idSerieFacturaNavigation.CalificacionOperacionesOExencion.Value;
nd.BaseImponibleOimporteNoSujeto = factura.BaseImponible;
// nd.ClaveRegimenSpecified = true;
if (factura.PorcentajeIVA.HasValue && factura.IVA > 0)
{
nd.TipoImpositivo = (double)factura.PorcentajeIVA;
nd.CuotaRepercutida = factura.IVA;
}
listaImpuestos.Add(nd);
return listaImpuestos;
}
public tsEncadenamiento? ObtenerUltimoEncadenamiento(string idEmisorFactura)
{
int pr = (int)bdAsegasa.db.registrosverifactu.EstadoEnum.PENDIENTE_RESPUESTA;
// int ae = (int)bdAsegasa.db.registrosverifactu.EstadoEnum.ACEPTADO_CON_ERRORES;
// int OperAlta = (int)bdAsegasa.db.registrosverifactu.OperacionEnum.ALTA;
var ultimoEncadenamiento = (
from rv in bd.registrosverifactu
join la in bd.liquidacionesagentes
on rv.idAplicacion equals la.idLiquidacionAgente
where rv.Estado > pr && !string.IsNullOrEmpty(rv.Huella) && la.idAgenteNavigation.CIF==idEmisorFactura
orderby rv.idRegistro descending
select new { Registro = rv, Liquidacion = la }
).FirstOrDefault();
//var ultimoEncadenamiento = bd.registrosverifactu
// .Where(x => x.Estado > pr && x.Huella != null && x.Huella != "")
// .OrderByDescending(x => x.idRegistro)
// .FirstOrDefault();
if (ultimoEncadenamiento != null)
{
liquidacionesagentes liq = bd.liquidacionesagentes.First(x => x.idLiquidacionAgente == ultimoEncadenamiento.Registro.idAplicacion);
return new tsEncadenamiento
{
ReferenciaExterna = ultimoEncadenamiento.Registro.idRegistro.ToString(),
FechaExpedicionFactura = liq.FechaFactura.Value,
NumSerieFactura = liq.NumeroFacturaVF(confSI.ValorAlfabetico4),
Huella = ultimoEncadenamiento.Registro.Huella,
IDEmisorFactura = idEmisorFactura
};
}
else
{
return null;
}
}
private peticionesverifactu? pvf;
public void GuardarPeticionAEAT(string Peticion)
{
pvf = new peticionesverifactu();
pvf.Peticion = System.Text.UTF8Encoding.UTF8.GetBytes(Peticion);
pvf.FechaHoraPeticion = DateTime.Now;
bd.Add(pvf);
bd.SaveChanges();
}
public void GuardarRespuestaAEAT(RespuestaRegFactuSistemaFacturacionType Respuesta, List<tsRegistroFacturacion> listadoRegistros)
{
try
{
pvf.Respuesta = System.Text.UTF8Encoding.UTF8.GetBytes(tsUtilidades.Utilidades.serializar(Respuesta));
pvf.FechaHoraRespuesta = DateTime.Now;
pvf.CSV = Respuesta.CSV;
var ProximoEnvio = DateTime.Now.AddSeconds(int.Parse(Respuesta.TiempoEsperaEnvio));
confVerifactu.Fecha3 = ProximoEnvio;
bd.SaveChanges();
foreach (var linea in Respuesta.RespuestaLinea)
{
// string nf = linea.IDFactura.NumSerieFactura;
int refex = int.Parse(linea.RefExterna);
var rvf = lrp.First(x => x.idRegistro == refex);
var tsRf = listadoRegistros.First(x => x.ReferenciaExterna == rvf.idRegistro.ToString());
rvf.Huella = tsRf.Huella;
rvf.FechaEncadenado = tsRf.FechaHoraHusoGenRegistro;
int? idRa = tsRf.EncadenamientoAnterior == null ? null : int.Parse(tsRf.EncadenamientoAnterior.ReferenciaExterna);
rvf.idRegistroAnterior = idRa;
rvf.idRespuestaVerifactuNavigation = pvf;
switch (linea.EstadoRegistro)
{
case EstadoRegistroType.Correcto:
rvf.Estado = (int)registrosverifactu.EstadoEnum.CORRECTO;
break;
case EstadoRegistroType.AceptadoConErrores:
rvf.Estado = (int)registrosverifactu.EstadoEnum.ACEPTADO_CON_ERRORES;
rvf.ErrorVerifactu = linea.DescripcionErrorRegistro.Acortar(500);
break;
case EstadoRegistroType.Incorrecto:
rvf.Estado = (int)registrosverifactu.EstadoEnum.INCORRECTO;
rvf.ErrorVerifactu = linea.DescripcionErrorRegistro.Acortar(500);
break;
}
}
bd.SaveChanges();
}
catch (Exception ex)
{
Logs.AñadeLog(tsUtilidades.Enumeraciones.TipoLog.Fallo, ex.Message, ex);
}
}
public (bool,string, DateOnly?)? ObtenerUltimaFacturaEnviada(string Serie, DateOnly Fecha)
{
//int iAlta = (int)registrosverifactu.OperacionEnum.ALTA;
//int iPendiente = (int)registrosverifactu.EstadoEnum.PENDIENTE_RESPUESTA;
//liquidacionesagentes? ultimaFactura;
//if (Fecha.Year != 2025)
//{
// ultimaFactura = (
// from l in bd.liquidacionesagentes
// join r in bd.registrosverifactu
// on l.idLiquidacionAgente equals r.idAplicacion
// where l.idSerieFacturaNavigation.Serie == Serie
// && l.FechaFactura.HasValue
// && l.FechaFactura.Value.Year == Fecha.Year
// && r.Operacion == iAlta
// && r.Estado > iPendiente
// orderby l.NumeroFactura descending
// select l).FirstOrDefault();
// if (ultimaFactura != null)
// {
// return (true,ultimaFactura.NumeroFactura, ultimaFactura.FechaFactura.Value);
// }
// else
// {
// return null;
// }
//}
//else
//{
return (false,"", null); // Se devuelve vacío para que no se compruebe la numeración
//}
}
public void Excepcion(Exception ex, string RespuestaAEAT)
{
try
{
// Si la excepción es de tipo FACTURA_ERRONEA, se detiene el proceso de envío
if (pvf != null && RespuestaAEAT != null)
{
pvf.Respuesta = System.Text.UTF8Encoding.UTF8.GetBytes(RespuestaAEAT);
pvf.FechaHoraRespuesta = DateTime.Now;
pvf.Estado = (int)peticionesverifactu.EstadoEnum.ENVIO_RECHAZADO_O_CON_ERRORES;
}
if (!tsExcepcion.Es(ex, "RECHAZO_VERIFACTU.ERROR_503") && (!tsExcepcion.Es(ex, "RECHAZO_VERIFACTU.ERROR_EN_SERVICIO_AEAT")) || (confVerifactu.ValorNumerico4.HasValue && confVerifactu.ValorNumerico4.Value > 4))
{
string sMensaje = @"Error en envío de facturas por VERIFACTU. Los procesos de envío se detendrán. Una vez corregido los problemas se deberá reanudar manualmente los envíos.";
if (RespuestaAEAT != null) sMensaje += " Respuesta AEAT: " + RespuestaAEAT;
Logs.AñadeLog(tsUtilidades.Enumeraciones.TipoLog.Fallo, sMensaje, ex);
confVerifactu.Fecha2 = DateTime.Now;
confVerifactu.ValorAlfabeticoLargo = ex.Message.Acortar(255);
}
else
{
string sMensaje = @"Servicio Verifactu no disponible, se reintentará en 1 Hora.";
if (RespuestaAEAT != null) sMensaje += " Respuesta AEAT: " + RespuestaAEAT;
Logs.AñadeLog(tsUtilidades.Enumeraciones.TipoLog.Advertencia, sMensaje, ex);
confVerifactu.Fecha3 = DateTime.Now.AddHours(1);
confVerifactu.ValorAlfabeticoLargo = ex.Message.Acortar(255);
confVerifactu.ValorNumerico4 = confVerifactu.ValorNumerico4.HasValue ? confVerifactu.ValorNumerico4.Value + 1 : 1;
}
bd.SaveChanges();
}
catch (Exception ex2)
{
Logs.AñadeLog(tsUtilidades.Enumeraciones.TipoLog.Fallo, ex2.Message + Environment.NewLine + ex.Message, ex2);
}
}
public void OperacionIncorrecta(tsRegistroFacturacion op, Exception ex)
{
int idAplicacion = int.Parse(op.ReferenciaExterna);
var rvf = lrp.First(x => x.idAplicacion == idAplicacion);
rvf.Estado = (int)registrosverifactu.EstadoEnum.INCORRECTO;
rvf.ErrorVerifactu = ex.Message.Acortar(500);
bd.SaveChanges();
}
public void Log(string Mensaje, TipoLog Tipo)
{
Logs.AñadeLog(Tipo, Mensaje);
}
}
}