diff --git a/Asegasa.sln b/Asegasa.sln index bed68ab..8afa0c5 100644 --- a/Asegasa.sln +++ b/Asegasa.sln @@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Servicio Gestion Asegasa", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "itsm", "itsm\itsm.csproj", "{09D06C54-3B7C-4A1D-8A1A-A1AEFAED2094}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WSAsegasaVerifactu", "WSAsegasaVerifactu\WSAsegasaVerifactu.csproj", "{E92893A7-620D-563C-05D1-C2BFCEE5497C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,6 +41,10 @@ Global {09D06C54-3B7C-4A1D-8A1A-A1AEFAED2094}.Debug|Any CPU.Build.0 = Debug|Any CPU {09D06C54-3B7C-4A1D-8A1A-A1AEFAED2094}.Release|Any CPU.ActiveCfg = Release|Any CPU {09D06C54-3B7C-4A1D-8A1A-A1AEFAED2094}.Release|Any CPU.Build.0 = Release|Any CPU + {E92893A7-620D-563C-05D1-C2BFCEE5497C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E92893A7-620D-563C-05D1-C2BFCEE5497C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E92893A7-620D-563C-05D1-C2BFCEE5497C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E92893A7-620D-563C-05D1-C2BFCEE5497C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Servicio Gestion Asegasa/Servicio Gestion Asegasa.csproj b/Servicio Gestion Asegasa/Servicio Gestion Asegasa.csproj index 9008ed3..9b025a9 100644 --- a/Servicio Gestion Asegasa/Servicio Gestion Asegasa.csproj +++ b/Servicio Gestion Asegasa/Servicio Gestion Asegasa.csproj @@ -2,6 +2,7 @@ net8.0 + © 2026 Tecnosis S.A. 1.2.0.0 - 2026-05-12 1.2.0.0 Correccion tsUtilidades diff --git a/WSAsegasaVerifactu/Configuracion.cs b/WSAsegasaVerifactu/Configuracion.cs new file mode 100644 index 0000000..2ed5d3e --- /dev/null +++ b/WSAsegasaVerifactu/Configuracion.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WSAsegasa +{ + public class Configuracion + { + public int SegundosMinimosEntreProcesos { get; set; } + public string? HoraProcesosDiarios { get; set; } + public string? NombreConexionBD { get; set; } + } +} diff --git a/WSAsegasaVerifactu/Logs.cs b/WSAsegasaVerifactu/Logs.cs new file mode 100644 index 0000000..89d2f39 --- /dev/null +++ b/WSAsegasaVerifactu/Logs.cs @@ -0,0 +1,102 @@ +using bdAsegasa; +using bdAsegasa.db; +using Microsoft.VisualBasic; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Serilog; +//mmm +namespace WSAsegasa +{ + internal class Logs + { + private static object oBloqueoLog; + //private static EventLog el; + public static void AñadeLog(tsUtilidades.Enumeraciones.TipoLog Tipo, string Mensaje, Exception e = null) + { + // ---------------------------------------------------------------------------------------------------- + // Descripción Sub: Gestión de logs de la aplicación + // Fecha. Creacion: ??? + // Creada por: manmog + // Ultima Modificacion: 24/11/2010 + // + // Modificaciones: + // =============== + if (oBloqueoLog == null) oBloqueoLog = new object(); + lock (oBloqueoLog) + { + try + { + if (e != null) + { + + string sStackTrace = "Tipo excepción: " + e.ToString() + Constants.vbCrLf; + Exception exError = e; + do + { + sStackTrace += exError.StackTrace + Constants.vbCrLf; + exError = exError.InnerException; + } + while (!Information.IsNothing(exError)); + if (sStackTrace != "") + Mensaje += Constants.vbCrLf + "|StackTrace: " + sStackTrace; + } + + bdAsegasa.db.cuentascorreo? cta = null; + + try + { + var bd = tscgestionasegasa.NuevoContexto(Procesos.Conf.NombreConexionBD, true, false, true, "WSAsegasa"); + cta = bd.cuentascorreo.First(x => x.Codigo == "DEFECTO"); + } + catch + { + } + + switch (Tipo) + { + case tsUtilidades.Enumeraciones.TipoLog.Fallo: + Mensaje = "Error WSAsegasa. " + " Enviado desde " + Environment.MachineName + ". Version:" + Assembly.GetEntryAssembly()?.GetName().Version + ". Mensaje: " + Mensaje; + Log.Fatal(Mensaje); + if (cta != null) tsCorreos.Funciones.EnviaCorreo(cta.ServidorSMTP, cta.Remitente, "sevilla@tecnosis.net", "Error en WSAsegasa", Mensaje, null, null, "", "", cta.CuentaCorreo, cta.Password, cta.Puerto.Value, true); + break; + case tsUtilidades.Enumeraciones.TipoLog.Advertencia: + Mensaje = "Advertencia WSAsegasa. " + " Enviado desde " + Environment.MachineName + ". Version:" + Assembly.GetEntryAssembly()?.GetName().Version + ". " + Mensaje; + Log.Warning(Mensaje); + if (cta != null) tsCorreos.Funciones.EnviaCorreo(cta.ServidorSMTP, cta.Remitente, "sevilla@tecnosis.net", "Advertencia en WSAsegasa", Mensaje, null, null, "", "", cta.CuentaCorreo, cta.Password, cta.Puerto.Value, true); + break; + case tsUtilidades.Enumeraciones.TipoLog.InicioServicio: + Mensaje = "Inicio WSAsegasa. " + " Enviado desde " + Environment.MachineName + ". Version:" + Assembly.GetEntryAssembly()?.GetName().Version + ". Mensaje: " + Mensaje; + Log.Information(Mensaje); + if (cta != null) tsCorreos.Funciones.EnviaCorreo(cta.ServidorSMTP, cta.Remitente, "sevilla@tecnosis.net", "Inicio WSAsegasa", Mensaje, null, null, "", "", cta.CuentaCorreo, cta.Password, cta.Puerto.Value, true); + break; + case tsUtilidades.Enumeraciones.TipoLog.FinServicio: + Mensaje = "Finalización WSAsegasa. " + " Enviado desde " + Environment.MachineName + ". Version:" + Assembly.GetEntryAssembly()?.GetName().Version + ". Mensaje: " + Mensaje; + Log.Information(Mensaje); + if (cta != null) tsCorreos.Funciones.EnviaCorreo(cta.ServidorSMTP, cta.Remitente, "sevilla@tecnosis.net", "Finalización WSAsegasa", Mensaje, null, null, "", "", cta.CuentaCorreo, cta.Password, cta.Puerto.Value, true); + break; + + default: + Mensaje = Tipo.ToString() + " WSAsegasa. " + " Enviado desde " + Environment.MachineName + ". Version:" + Assembly.GetEntryAssembly()?.GetName().Version + ". " + Mensaje; + Log.Information(Mensaje); + break; + } + + + } + catch (Exception ex) + { + if (e != null) + Mensaje += " --- " + e.StackTrace; + + Log.Fatal(Mensaje + " ---" + ex.Message + " --- " + ex.StackTrace); + } + } + } + } +} + diff --git a/WSAsegasaVerifactu/Procesos.cs b/WSAsegasaVerifactu/Procesos.cs new file mode 100644 index 0000000..8b51b12 --- /dev/null +++ b/WSAsegasaVerifactu/Procesos.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WSAsegasa; + + +namespace WSAsegasa +{ + public class Procesos + { + public static Configuracion Conf; + + public static DateTime? HoraUtcUltimaEjecucionProcesos = null; + private static bool Procesando; + + public static void Procesar() + { + if (!Procesando && (HoraUtcUltimaEjecucionProcesos.HasValue == false || DateTime.UtcNow.Subtract(HoraUtcUltimaEjecucionProcesos.Value).TotalSeconds > Conf.SegundosMinimosEntreProcesos)) ; + { + Procesando = true; + HoraUtcUltimaEjecucionProcesos = DateTime.UtcNow; + try + { + // ProcesosCorreos.EnviaCorreos(); + // Comprobaciones.CompruebaReplica(); + // Comprobaciones.ChequeaColaCorreo(); + + } + catch (Exception ex) + { + + Debug.WriteLine(@"Procesar: EXCEPCIÓN: " + ex.Message + " " + ex.StackTrace); + } + finally + { + Procesando = false; + } + + } + + } + } +} diff --git a/WSAsegasaVerifactu/ProcesosVeriFactuAsegasa.cs b/WSAsegasaVerifactu/ProcesosVeriFactuAsegasa.cs new file mode 100644 index 0000000..5e9a456 --- /dev/null +++ b/WSAsegasaVerifactu/ProcesosVeriFactuAsegasa.cs @@ -0,0 +1,517 @@ +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; + + +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; + } + + 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 (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); + } + + tsEncadenamiento? ItsVeriFactu.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; + } + } + + 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); + } + } + } +} diff --git a/WSAsegasaVerifactu/Program.cs b/WSAsegasaVerifactu/Program.cs new file mode 100644 index 0000000..c746507 --- /dev/null +++ b/WSAsegasaVerifactu/Program.cs @@ -0,0 +1,55 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging.Configuration; +using Microsoft.Extensions.Logging.EventLog; +using Serilog; +using System.IO; +using System.Reflection; +using WSAsegasa; + + +public class Program +{ + public static void Main(string[] args) + { + Serilog.Debugging.SelfLog.Enable(msg => Console.Error.WriteLine(msg)); + bdAsegasa.db.Utilidades.VersionPrograma = tsUtilidades.Utilidades.ExtraeValorCadena(Assembly.GetExecutingAssembly().FullName, "Version"); + // Configura Serilog antes de construir el host + string path = ""; + if (OperatingSystem.IsWindows()) + { + path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"\WSAsegasa\WSAsegasa.log"; + } + else + { + + path = @"/var/log/WSAsegasa/WSAsegasa.log"; + } + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Information() + .WriteTo.File(path, rollingInterval: RollingInterval.Day) + .CreateLogger(); + var host = CreateHostBuilder(args).Build(); + host.Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureServices((hostContext, services) => + { + IConfiguration configuration = hostContext.Configuration; + Configuracion options = configuration.GetSection("Configuracion").Get(); + + services.AddSingleton(options); + + // Solo registrar WindowsService si estamos en Windows + if (OperatingSystem.IsWindows()) + { + services.AddWindowsService(config => + { + config.ServiceName = "WSAsegasa"; + }); + } + + services.AddHostedService(); + }); +} diff --git a/WSAsegasaVerifactu/Properties/launchSettings.json b/WSAsegasaVerifactu/Properties/launchSettings.json new file mode 100644 index 0000000..db21562 --- /dev/null +++ b/WSAsegasaVerifactu/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "WSAsegasa": { + "commandName": "Project", + "dotnetRunMessages": true, + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Development" + } + } + } +} diff --git a/WSAsegasaVerifactu/WSAsegasaVerifactu.csproj b/WSAsegasaVerifactu/WSAsegasaVerifactu.csproj new file mode 100644 index 0000000..cd8aee0 --- /dev/null +++ b/WSAsegasaVerifactu/WSAsegasaVerifactu.csproj @@ -0,0 +1,37 @@ + + + + net8.0 + enable + enable + dotnet-WSAsegasa-3170e77c-9190-48a1-9c66-26323b65ac5d + win-x64;linux-x64 + 1.0.0.0 + 1.0.0.0 + Manuel + Tecnosis S.A + Servicio de envío de facturas de asegasa al sistema Verifactu + + - 2026-05-19 V1.0.0.0 Versión renombrada de wsasegasa a wsasegasaverifactu + + + + + + + + + + + + + + + + + + + + + + diff --git a/WSAsegasaVerifactu/Worker.cs b/WSAsegasaVerifactu/Worker.cs new file mode 100644 index 0000000..94f717d --- /dev/null +++ b/WSAsegasaVerifactu/Worker.cs @@ -0,0 +1,185 @@ +using bdAsegasa; +using bdAsegasa.db; +using Microsoft.Extensions.Logging; +using Microsoft.VisualBasic; +using Quartz; +using Quartz.Impl; +using System.ComponentModel.DataAnnotations.Schema; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Drawing.Text; +using System.Reflection; +using System.Threading.Tasks; +using System.Web.Services.Description; +using tsUtilidades.SEPA_3414; +using WSAsegasa; + +namespace WSAsegasa +{ + + public class Worker : BackgroundService + { + private readonly ILogger _logger; + + public Worker(ILogger logger, Configuracion Conf) + { + _logger = logger; + Procesos.Conf = Conf; + } + + + + + + protected override async System.Threading.Tasks.Task ExecuteAsync(CancellationToken stoppingToken) + { + string Mensaje = "WSAsegasa. Versin: " + tsUtilidades.Utilidades.ExtraeValorCadena(Assembly.GetExecutingAssembly().FullName, "Version"); + try + { + + if (Procesos.Conf.HoraProcesosDiarios != null) + { + Mensaje += " Hora Procesos Programados: " + Procesos.Conf.HoraProcesosDiarios; + CreaTareaProcesosDiarios(); + } + CreaTareaEnvioFacturas(); + + Logs.AadeLog(tsUtilidades.Enumeraciones.TipoLog.InicioServicio, "Inicio " + Mensaje); + + while (!stoppingToken.IsCancellationRequested) + { + if (_logger.IsEnabled(LogLevel.Information)) + { + _logger.LogInformation("Servicio en ejecucin: {time}", DateTimeOffset.Now); + //Creo q aqui se deberia llamar a los servicios + } + Procesos.Procesar(); + await System.Threading.Tasks.Task.Delay(1000*60*5, stoppingToken); + } + } + catch (OperationCanceledException) + { + // Logs.AadeLog(tsUtilidades.Enumeraciones.TipoLog.FinServicio, "Detencin " + Mensaje); + // When the stopping token is canceled, for example, a call made from services.msc, + // we shouldn't exit with a non-zero exit code. In other words, this is expected... + } + catch (Exception ex) + { + _logger.LogError(ex, "{Message}", ex.Message); + Environment.Exit(1); + } + + } + public override async Task StopAsync(CancellationToken cancellationToken) + { + string Mensaje = "WSAsegasa. Versin: " + tsUtilidades.Utilidades.ExtraeValorCadena(Assembly.GetExecutingAssembly().FullName, "Version"); + Logs.AadeLog(tsUtilidades.Enumeraciones.TipoLog.FinServicio, "Finalizando " + Mensaje); + + await base.StopAsync(cancellationToken); + Logs.AadeLog(tsUtilidades.Enumeraciones.TipoLog.FinServicio, "Servicio Finalizado " + Mensaje); + } + + + + private void CreaTareaProcesosDiarios() + { + ISchedulerFactory schedulerFactory = new StdSchedulerFactory(); + IScheduler scheduler = schedulerFactory.GetScheduler().Result; + scheduler.Start().Wait(); + // Crear un trabajo + IJobDetail job = JobBuilder.Create() + .WithIdentity("TareasProgramadas", "Grupo1") + .Build(); + // Crear un trigger que se ejecute diariamente a una hora especfica + + + int Hora = int.Parse(Procesos.Conf.HoraProcesosDiarios.Split(":")[0]); + int Minutos = int.Parse(Procesos.Conf.HoraProcesosDiarios.Split(":")[1]); + ITrigger trigger = TriggerBuilder.Create() + .WithIdentity("TareasProgramadas", "Grupo1") + .StartAt(DateBuilder.TodayAt(Hora, Minutos, 0)) + .WithSimpleSchedule(x => x + .WithIntervalInHours(24) + .RepeatForever()) + .Build(); + + // Programar el trabajo con el trigger + scheduler.ScheduleJob(job, trigger).Wait(); + } + + private void CreaTareaEnvioFacturas() + { + ISchedulerFactory schedulerFactory = new StdSchedulerFactory(); + IScheduler scheduler = schedulerFactory.GetScheduler().Result; + scheduler.Start().Wait(); + // Crear un trabajo + IJobDetail job = JobBuilder.Create() + .WithIdentity("EnvioFacturas", "Grupo1") + .Build(); + // Crear un trigger que se ejecute diariamente a una hora especfica + + ITrigger trigger = TriggerBuilder.Create() + .WithIdentity("EnvioFacturas", "Grupo1") + .StartAt(DateBuilder.TodayAt(DateTime.Now.Hour, DateTime.Now.Minute, 0)) + .WithSimpleSchedule(x => x + .WithIntervalInMinutes(15) + .RepeatForever()) + .Build(); + + // Programar el trabajo con el trigger + scheduler.ScheduleJob(job, trigger).Wait(); + } + + + } + + + public class TareasProgramadas : IJob + { + public Task Execute(IJobExecutionContext context) + { + //var ch = bdTecnosis.db.chequeos; + // var bd = bdTecnosis.tscTecnosis.NuevoContexto(); + //var c = bd.chequeos.FirstOrDefault(x => x.idChequeo == ch.idChequeo); + //Comprobaciones.ChequeaColaCorreo(bd,c); + //Comprobaciones.CompruebaReplica(); + //Aqui van los procesos y comprobaciones + return Task.CompletedTask; + } + } + + + public class EnvioFacturas : IJob + { + private static readonly SemaphoreSlim _semaforo = new SemaphoreSlim(1, 1); + + public async Task Execute(IJobExecutionContext context) + { + var cancellationToken = context.CancellationToken; + + if (await _semaforo.WaitAsync(0, cancellationToken)) // no espera si est ocupado + { + try + { + var ft = new ProcesosVeriFactuAsegasa(); + await ft.Iniciar(cancellationToken); + } + catch (Exception ex) + { + Logs.AadeLog(tsUtilidades.Enumeraciones.TipoLog.Fallo, ex.Message, ex); + } + finally + { + _semaforo.Release(); + } + } + else + { + var bd = tscgestionasegasa.NuevoContexto(Procesos.Conf.NombreConexionBD, true, false, true, "ProcesosVeriFactuTecnosis"); + var cvf = bd.enumeraciones.First(x => x.Codigo == "VF.CONF"); + if (DateTime.Now.Hour < cvf.ValorNumerico2.Value) Logs.AadeLog(tsUtilidades.Enumeraciones.TipoLog.Advertencia, "Bloqueo en EnvioFacturas"); + + } + } + } +} diff --git a/WSAsegasaVerifactu/appsettings.Development.json b/WSAsegasaVerifactu/appsettings.Development.json new file mode 100644 index 0000000..b2dcdb6 --- /dev/null +++ b/WSAsegasaVerifactu/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/WSAsegasaVerifactu/appsettings.json b/WSAsegasaVerifactu/appsettings.json new file mode 100644 index 0000000..67c764c --- /dev/null +++ b/WSAsegasaVerifactu/appsettings.json @@ -0,0 +1,8 @@ +{ + + "Configuracion": { + "SegundosMinimosEntreProcesos": "60", + "HoraProcesosDiarios": "06:30", + "NombreConexionBD": "Producción Remoto" + } +} diff --git a/bdAsegasa/bdAsegasa.csproj b/bdAsegasa/bdAsegasa.csproj index 762199d..00224d9 100644 --- a/bdAsegasa/bdAsegasa.csproj +++ b/bdAsegasa/bdAsegasa.csproj @@ -16,7 +16,7 @@ - + diff --git a/bdAsegasa/dbcontext/conexion.cs b/bdAsegasa/dbcontext/conexion.cs index 8bd8ac8..d70dba8 100644 --- a/bdAsegasa/dbcontext/conexion.cs +++ b/bdAsegasa/dbcontext/conexion.cs @@ -24,7 +24,8 @@ namespace bdAsegasa.dbcontext public static List ListaConexiones() { List lc = new List(); - lc.Add(new Conexion() { Nombre = "Producción", Servidor = "192.168.61.201", Puerto = 30002, Usuario = "asegasa", Contraseña = "tk-8Vb/#%+2ÄM", Database = "gestionasegasa" }); + // lc.Add(new Conexion() { Nombre = "Producción", Servidor = "192.168.61.201", Puerto = 30002, Usuario = "asegasa", Contraseña = "tk-8Vb/#%+2ÄM", Database = "gestionasegasa" }); + lc.Add(new Conexion() { Nombre = "Producción", Servidor = "192.168.61.203", Puerto = 36200, Usuario = "asegasa", Contraseña = "tk-8Vb/#%+2ÄM", Database = "gestionasegasa" }); lc.Add(new Conexion() { Nombre = "Desarrollo", Servidor = "192.168.41.26", Puerto = 3307, Usuario = "asegasa", Contraseña = "tk-8Vb/#%+2ÄM", Database = "gestionasegasa" }); lc.Add(new Conexion() { Nombre = "Producción Remoto", Servidor = "sevilla.asegasa.com", Puerto = 30002, Usuario = "asegasa", Contraseña = "tk-8Vb/#%+2ÄM", Database = "gestionasegasa" }); return lc; diff --git a/itsm/itsm.csproj b/itsm/itsm.csproj index b98af41..78fdf2e 100644 --- a/itsm/itsm.csproj +++ b/itsm/itsm.csproj @@ -9,6 +9,6 @@ - + \ No newline at end of file