All checks were successful
Optimized Build and Deploy / remote-build-and-deploy (push) Successful in 3m58s
Se modifica la lógica de cálculo para la fila "General" en la tabla de promedios del reporte de Listado de Distribución para distribuidores.
**Motivación:**
Por requerimiento explícito del usuario final, el cálculo de los promedios generales (Llevados, Devueltos, Ventas y % Devolución) debe ser un promedio aritmético simple de los valores de los días de la semana mostrados en la tabla (ej. Viernes, Sábado, Domingo), en lugar del promedio ponderado que se calculaba anteriormente basado en los totales generales.
**Cambios Realizados:**
1. **Backend (`ListadoDistribucionDistribuidoresViewModel.cs`):**
* Se actualizó la propiedad `PromedioGeneral` para que calcule sus valores (Promedio\_Llevados, Promedio\_Devueltos, etc.) promediando directamente los valores de la colección `PromediosPorDia`.
2. **PDF (`ListadoDistribucionDistribuidoresDocument.cs`):**
* Se ajustó la lógica de renderizado de la fila "General" para que el porcentaje de devolución también se calcule como el promedio de los porcentajes de los días individuales, asegurando consistencia con el ViewModel.
3. **Frontend (`ReporteListadoDistribucionPage.tsx`):**
* Se modificó el cálculo del estado `totalesPromedios` dentro de la función `handleGenerarReporte`. Ahora, en lugar de usar los totales de la tabla de detalle, suma los valores de la tabla de promedios y los divide por la cantidad de días para obtener un promedio simple.
**Resultado:**
Tanto la interfaz web como el PDF generado ahora muestran en la fila "General" un promedio simple de las filas de promedios diarios, alineándose con la lógica solicitada por el usuario.
283 lines
14 KiB
C#
283 lines
14 KiB
C#
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using System.Text;
|
|
using GestionIntegral.Api.Data;
|
|
using GestionIntegral.Api.Services.Contables;
|
|
using GestionIntegral.Api.Services.Distribucion;
|
|
using GestionIntegral.Api.Services.Radios;
|
|
using GestionIntegral.Api.Data.Repositories.Contables;
|
|
using GestionIntegral.Api.Data.Repositories.Distribucion;
|
|
using GestionIntegral.Api.Data.Repositories.Impresion;
|
|
using GestionIntegral.Api.Data.Repositories.Radios;
|
|
using GestionIntegral.Api.Services.Impresion;
|
|
using GestionIntegral.Api.Services.Usuarios;
|
|
using GestionIntegral.Api.Data.Repositories.Usuarios;
|
|
using Microsoft.OpenApi.Models;
|
|
using GestionIntegral.Api.Data.Repositories.Reportes;
|
|
using GestionIntegral.Api.Services.Reportes;
|
|
using GestionIntegral.Api.Services.Pdf;
|
|
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
|
using GestionIntegral.Api.Services.Anomalia;
|
|
using GestionIntegral.Api.Data.Repositories.Suscripciones;
|
|
using GestionIntegral.Api.Services.Suscripciones;
|
|
using GestionIntegral.Api.Models.Comunicaciones;
|
|
using GestionIntegral.Api.Services.Comunicaciones;
|
|
using GestionIntegral.Api.Data.Repositories.Comunicaciones;
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
// --- Registros de Servicios ---
|
|
builder.Services.AddSingleton<DbConnectionFactory>();
|
|
builder.Services.AddScoped<PasswordHasherService>();
|
|
builder.Services.AddScoped<IAuthRepository, AuthRepository>();
|
|
builder.Services.AddScoped<IAuthService, AuthService>();
|
|
builder.Services.AddScoped<ITipoPagoRepository, TipoPagoRepository>();
|
|
builder.Services.AddScoped<ITipoPagoService, TipoPagoService>();
|
|
builder.Services.AddScoped<IZonaRepository, ZonaRepository>();
|
|
builder.Services.AddScoped<IZonaService, ZonaService>();
|
|
builder.Services.AddScoped<IEmpresaRepository, EmpresaRepository>();
|
|
builder.Services.AddScoped<IEmpresaService, EmpresaService>();
|
|
builder.Services.AddScoped<ISaldoRepository, SaldoRepository>();
|
|
builder.Services.AddScoped<IPlantaRepository, PlantaRepository>();
|
|
builder.Services.AddScoped<IPlantaService, PlantaService>();
|
|
builder.Services.AddScoped<ITipoBobinaRepository, TipoBobinaRepository>();
|
|
builder.Services.AddScoped<ITipoBobinaService, TipoBobinaService>();
|
|
builder.Services.AddScoped<IEstadoBobinaRepository, EstadoBobinaRepository>();
|
|
builder.Services.AddScoped<IEstadoBobinaService, EstadoBobinaService>();
|
|
builder.Services.AddScoped<IOtroDestinoRepository, OtroDestinoRepository>();
|
|
builder.Services.AddScoped<IOtroDestinoService, OtroDestinoService>();
|
|
builder.Services.AddScoped<IPerfilRepository, PerfilRepository>();
|
|
builder.Services.AddScoped<IPerfilService, PerfilService>();
|
|
builder.Services.AddScoped<IPermisoRepository, PermisoRepository>();
|
|
builder.Services.AddScoped<IPermisoService, PermisoService>();
|
|
builder.Services.AddScoped<IUsuarioRepository, UsuarioRepository>();
|
|
builder.Services.AddScoped<IUsuarioService, UsuarioService>();
|
|
builder.Services.AddScoped<ICanillaRepository, CanillaRepository>();
|
|
builder.Services.AddScoped<ICanillaService, CanillaService>();
|
|
builder.Services.AddScoped<IDistribuidorRepository, DistribuidorRepository>();
|
|
builder.Services.AddScoped<IDistribuidorService, DistribuidorService>();
|
|
builder.Services.AddScoped<IPublicacionRepository, PublicacionRepository>();
|
|
builder.Services.AddScoped<IPublicacionService, PublicacionService>();
|
|
builder.Services.AddScoped<IRecargoZonaRepository, RecargoZonaRepository>();
|
|
builder.Services.AddScoped<IRecargoZonaService, RecargoZonaService>();
|
|
builder.Services.AddScoped<IPorcPagoRepository, PorcPagoRepository>();
|
|
builder.Services.AddScoped<IPorcPagoService, PorcPagoService>();
|
|
builder.Services.AddScoped<IPorcMonCanillaRepository, PorcMonCanillaRepository>();
|
|
builder.Services.AddScoped<IPorcMonCanillaService, PorcMonCanillaService>();
|
|
builder.Services.AddScoped<IPubliSeccionRepository, PubliSeccionRepository>();
|
|
builder.Services.AddScoped<IPubliSeccionService, PubliSeccionService>();
|
|
builder.Services.AddScoped<IPrecioRepository, PrecioRepository>();
|
|
builder.Services.AddScoped<IPrecioService, PrecioService>();
|
|
builder.Services.AddScoped<IStockBobinaRepository, StockBobinaRepository>();
|
|
builder.Services.AddScoped<IStockBobinaService, StockBobinaService>();
|
|
builder.Services.AddScoped<IRegTiradaRepository, RegTiradaRepository>();
|
|
builder.Services.AddScoped<IRegPublicacionSeccionRepository, RegPublicacionSeccionRepository>();
|
|
builder.Services.AddScoped<ITiradaService, TiradaService>();
|
|
builder.Services.AddScoped<ISalidaOtroDestinoRepository, SalidaOtroDestinoRepository>();
|
|
builder.Services.AddScoped<ISalidaOtroDestinoService, SalidaOtroDestinoService>();
|
|
builder.Services.AddScoped<IEntradaSalidaDistRepository, EntradaSalidaDistRepository>();
|
|
builder.Services.AddScoped<IEntradaSalidaDistService, EntradaSalidaDistService>();
|
|
builder.Services.AddScoped<IEntradaSalidaCanillaRepository, EntradaSalidaCanillaRepository>();
|
|
builder.Services.AddScoped<IEntradaSalidaCanillaService, EntradaSalidaCanillaService>();
|
|
builder.Services.AddScoped<IControlDevolucionesRepository, ControlDevolucionesRepository>();
|
|
builder.Services.AddScoped<IControlDevolucionesService, ControlDevolucionesService>();
|
|
builder.Services.AddScoped<IPagoDistribuidorRepository, PagoDistribuidorRepository>();
|
|
builder.Services.AddScoped<IPagoDistribuidorService, PagoDistribuidorService>();
|
|
builder.Services.AddScoped<INotaCreditoDebitoRepository, NotaCreditoDebitoRepository>();
|
|
builder.Services.AddScoped<INotaCreditoDebitoService, NotaCreditoDebitoService>();
|
|
builder.Services.AddScoped<IRitmoRepository, RitmoRepository>();
|
|
builder.Services.AddScoped<IRitmoService, RitmoService>();
|
|
builder.Services.AddScoped<ICancionRepository, CancionRepository>();
|
|
builder.Services.AddScoped<ICancionService, CancionService>();
|
|
builder.Services.AddScoped<IRadioListaService, RadioListaService>();
|
|
builder.Services.AddScoped<INovedadCanillaRepository, NovedadCanillaRepository>();
|
|
builder.Services.AddScoped<INovedadCanillaService, NovedadCanillaService>();
|
|
builder.Services.AddScoped<ICambioParadaRepository, CambioParadaRepository>();
|
|
builder.Services.AddScoped<ICambioParadaService, CambioParadaService>();
|
|
// Servicio de Saldos
|
|
builder.Services.AddScoped<ISaldoService, SaldoService>();
|
|
// Repositorios de Reportes
|
|
builder.Services.AddScoped<IReportesRepository, ReportesRepository>();
|
|
// Servicios de Reportes
|
|
builder.Services.AddScoped<IReportesService, ReportesService>();
|
|
// QuestPDF
|
|
builder.Services.AddScoped<IQuestPdfGenerator, QuestPdfGenerator>();
|
|
// Servicio de Alertas
|
|
builder.Services.AddScoped<IAlertaService, AlertaService>();
|
|
|
|
// --- Suscripciones ---
|
|
builder.Services.AddScoped<IFormaPagoRepository, FormaPagoRepository>();
|
|
builder.Services.AddScoped<ISuscriptorRepository, SuscriptorRepository>();
|
|
builder.Services.AddScoped<ISuscripcionRepository, SuscripcionRepository>();
|
|
builder.Services.AddScoped<IFacturaRepository, FacturaRepository>();
|
|
builder.Services.AddScoped<ILoteDebitoRepository, LoteDebitoRepository>();
|
|
builder.Services.AddScoped<IPagoRepository, PagoRepository>();
|
|
builder.Services.AddScoped<IPromocionRepository, PromocionRepository>();
|
|
builder.Services.AddScoped<IAjusteRepository, AjusteRepository>();
|
|
builder.Services.AddScoped<IFacturaDetalleRepository, FacturaDetalleRepository>();
|
|
|
|
builder.Services.AddScoped<IFormaPagoService, FormaPagoService>();
|
|
builder.Services.AddScoped<ISuscriptorService, SuscriptorService>();
|
|
builder.Services.AddScoped<ISuscripcionService, SuscripcionService>();
|
|
builder.Services.AddScoped<IFacturacionService, FacturacionService>();
|
|
builder.Services.AddScoped<IDebitoAutomaticoService, DebitoAutomaticoService>();
|
|
builder.Services.AddScoped<IPagoService, PagoService>();
|
|
builder.Services.AddScoped<IPromocionService, PromocionService>();
|
|
builder.Services.AddScoped<IAjusteService, AjusteService>();
|
|
|
|
// --- Comunicaciones ---
|
|
builder.Services.Configure<MailSettings>(builder.Configuration.GetSection("MailSettings"));
|
|
builder.Services.AddTransient<IEmailService, EmailService>();
|
|
builder.Services.AddScoped<IEmailLogRepository, EmailLogRepository>();
|
|
builder.Services.AddScoped<IEmailLogService, EmailLogService>();
|
|
builder.Services.AddScoped<ILoteDeEnvioRepository, LoteDeEnvioRepository>();
|
|
|
|
// --- SERVICIO DE HEALTH CHECKS ---
|
|
// Añadimos una comprobación específica para SQL Server.
|
|
// El sistema usará la cadena de conexión configurada en appsettings.json o variables de entorno.
|
|
builder.Services.AddHealthChecks()
|
|
.AddSqlServer(
|
|
connectionString: builder.Configuration.GetConnectionString("DefaultConnection") ?? "",
|
|
healthQuery: "SELECT 1;",
|
|
name: "sql-server",
|
|
failureStatus: HealthStatus.Unhealthy,
|
|
tags: new string[] { "database" }
|
|
);
|
|
|
|
// --- Configuración de Autenticación JWT ---
|
|
var jwtSettings = builder.Configuration.GetSection("Jwt");
|
|
|
|
// Le decimos que busque la clave JWT en la raíz de la configuración (donde están las variables de entorno).
|
|
// Si no la encuentra, como respaldo, busca en la sección "Jwt" del appsettings.
|
|
var jwtKey = builder.Configuration["JWT_KEY"] ?? jwtSettings["Key"] ?? throw new ArgumentNullException("JWT_KEY or Jwt:Key not configured");
|
|
|
|
var keyBytes = Encoding.ASCII.GetBytes(jwtKey);
|
|
|
|
builder.Services.AddAuthentication(options =>
|
|
{
|
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
})
|
|
.AddJwtBearer(options =>
|
|
{
|
|
options.RequireHttpsMetadata = builder.Environment.IsProduction();
|
|
options.SaveToken = true;
|
|
options.TokenValidationParameters = new TokenValidationParameters
|
|
{
|
|
ValidateIssuerSigningKey = true,
|
|
IssuerSigningKey = new SymmetricSecurityKey(keyBytes),
|
|
ValidateIssuer = true,
|
|
ValidIssuer = jwtSettings["Issuer"],
|
|
ValidateAudience = true,
|
|
ValidAudience = jwtSettings["Audience"],
|
|
ValidateLifetime = true,
|
|
ClockSkew = TimeSpan.Zero
|
|
};
|
|
});
|
|
|
|
// --- Configuración de Autorización ---
|
|
builder.Services.AddAuthorization();
|
|
|
|
// --- Configuración de CORS --- //
|
|
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
|
|
builder.Services.AddCors(options =>
|
|
{
|
|
options.AddPolicy(name: MyAllowSpecificOrigins,
|
|
policy =>
|
|
{
|
|
policy.WithOrigins(
|
|
"http://localhost:5175", // Para desarrollo local
|
|
"https://gestion.eldiaservicios.com" // Para producción
|
|
)
|
|
.AllowAnyHeader()
|
|
.AllowAnyMethod();
|
|
});
|
|
});
|
|
// --- Fin CORS ---
|
|
|
|
// --- Servicios del Contenedor ---
|
|
builder.Services.AddControllers();
|
|
builder.Services.AddEndpointsApiExplorer();
|
|
|
|
// --- Configuración Avanzada de Swagger/OpenAPI ---
|
|
builder.Services.AddSwaggerGen(options =>
|
|
{
|
|
// Definición general del documento Swagger
|
|
options.SwaggerDoc("v1", new OpenApiInfo
|
|
{
|
|
Version = "v1",
|
|
Title = "GestionIntegral API",
|
|
Description = "API para el sistema de Gestión Integral (Migración VB.NET)",
|
|
// Puedes añadir TermsOfService, Contact, License si lo deseas
|
|
});
|
|
|
|
// (Opcional) Incluir comentarios XML si los usas en tus controladores/DTOs
|
|
// var xmlFilename = $"{System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
|
// options.IncludeXmlComments(System.IO.Path.Combine(AppContext.BaseDirectory, xmlFilename));
|
|
|
|
// Definición de Seguridad para JWT en Swagger UI
|
|
// Esto añade el botón "Authorize" en la UI de Swagger para poder pegar el token Bearer
|
|
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
|
{
|
|
In = ParameterLocation.Header,
|
|
Description = "Por favor, introduce 'Bearer' seguido de un espacio y luego tu token JWT.",
|
|
Name = "Authorization",
|
|
Type = SecuritySchemeType.ApiKey, // Usar ApiKey para el formato Bearer simple
|
|
Scheme = "Bearer" // Esquema a usar
|
|
});
|
|
|
|
options.AddSecurityRequirement(new OpenApiSecurityRequirement
|
|
{
|
|
{
|
|
new OpenApiSecurityScheme
|
|
{
|
|
Reference = new OpenApiReference
|
|
{
|
|
Type = ReferenceType.SecurityScheme,
|
|
Id = "Bearer" // Debe coincidir con el Id definido en AddSecurityDefinition
|
|
},
|
|
Scheme = "oauth2", // Aunque el scheme sea ApiKey, a veces se usa oauth2 aquí para la UI
|
|
Name = "Bearer",
|
|
In = ParameterLocation.Header,
|
|
},
|
|
new List<string>() // Lista de scopes (vacía si no usas scopes OAuth2 complejos)
|
|
}
|
|
});
|
|
});
|
|
// --- Fin Configuración Swagger ---
|
|
|
|
var app = builder.Build();
|
|
|
|
// Habilitamos Swagger SIEMPRE, sin importar el entorno.
|
|
app.UseSwagger(); // Habilita el middleware para servir el JSON de Swagger
|
|
app.UseSwaggerUI(options => // Habilita el middleware para servir la UI de Swagger
|
|
{
|
|
options.SwaggerEndpoint("/swagger/v1/swagger.json", "GestionIntegral API v1");
|
|
// Opcional: Para que Swagger aparezca en la raíz de la API (ej: http://192.168.4.128:8081/)
|
|
options.RoutePrefix = string.Empty;
|
|
});
|
|
|
|
|
|
// Mantenemos esta lógica solo para la página de error de desarrollo, si quieres.
|
|
if (app.Environment.IsDevelopment())
|
|
{
|
|
// Aquí puedes dejar otras herramientas solo para desarrollo si las tuvieras.
|
|
}
|
|
|
|
// ¡¡¡NO USAR UseHttpsRedirection si la API corre en HTTP!!!
|
|
// Comenta o elimina la siguiente línea si SÓLO usas http://localhost:5183
|
|
//app.UseHttpsRedirection();
|
|
|
|
app.UseCors(MyAllowSpecificOrigins);
|
|
|
|
app.UseAuthentication(); // Debe ir ANTES de UseAuthorization
|
|
app.UseAuthorization();
|
|
|
|
// Mapeamos la ruta "/health". Cuando se acceda a ella, se ejecutarán todas las comprobaciones registradas.
|
|
// Esto va ANTES de app.MapControllers().
|
|
app.MapHealthChecks("/health");
|
|
|
|
app.MapControllers();
|
|
|
|
app.Run(); |