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? 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 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 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 LiquidacionesAgentesAtsFACTURAS() { List lf = new List(); 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(); 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 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) /// /// No asignada causa exención. /// ///NA, /// /// Exenta por el artículo 20 (Exenciones en operaciones interiores). /// ///E1, /// /// Exenta por el artículo 21 (Exportaciones). /// ///E2, /// /// Exenta por el artículo 22 (Operaciones asimiladas a las /// exportaciones: Navegación marítima internacional, aeronaves...). /// ///E3, /// /// Exenta por los artículos 23 y 24 (Exenciones relativas a /// regímenes aduaneros y fiscales: Depositos aduaneros...). /// ///E4, /// /// Exenta por el artículo 25 (Operaciones UE). /// ///E5, /// /// Exenta por otros. /// ///E6, /// /// Reservado 1 Impuesto = “03” (IGIC) /// ///E7, /// /// Reservado Impuesto = “03” (IGIC) /// ///E8 { List listaImpuestos = new List(); 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 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); } } }