Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/interezante456-pixel/proyecto-dise-o/llms.txt

Use this file to discover all available pages before exploring further.

ReporteController proporciona analítica de ventas para Tienda MiCholo. A diferencia del resto de controllers, no tiene ningún atributo [Authorize] declarado a nivel de clase, por lo que el acceso queda gobernado únicamente por el middleware de autenticación global de la aplicación. El controller recibe AppDbContext vía inyección de dependencias y utiliza LINQ para agregar los datos de DetallesVentas directamente, sin pasar por el modelo Venta.

GET /Reporte/MasVendidos

Consulta la tabla DetallesVentas, agrupa por producto y devuelve el top 5 de productos más vendidos según la cantidad total despachada. Autorización: Sin [Authorize] explícito en el controller ni en la acción. Comportamiento: La consulta parte de _context.DetallesVentas.Include(d => d.Producto), agrupa por Producto_ID y proyecta el siguiente objeto anónimo para cada grupo:
var topProductos = await _context.DetallesVentas
    .Include(d => d.Producto)
    .GroupBy(d => d.Producto_ID)
    .Select(grupo => new {
        ProductoId      = grupo.Key,
        NombreProducto  = grupo.First().Producto.Nombre,
        CantidadTotal   = grupo.Sum(d => d.Cantidad),
        TotalRecaudado  = grupo.Sum(d => d.Cantidad * d.PrecioUnitario)
    })
    .OrderByDescending(x => x.CantidadTotal)
    .Take(5)
    .ToListAsync();
Forma del resultado proyectado:
ProductoId
int
Identificador del producto (Producto_ID, clave de agrupación).
NombreProducto
string
Nombre del producto obtenido del primer elemento del grupo mediante la navegación grupo.First().Producto.Nombre.
CantidadTotal
int
Suma total de unidades vendidas (SUM(Cantidad)) a lo largo de todos los DetallesVentas del grupo.
TotalRecaudado
decimal
Monto total recaudado calculado como SUM(Cantidad * PrecioUnitario) para todos los DetallesVentas del grupo.
Ordenamiento: descendente por CantidadTotal. En caso de empate, el orden lo determina el motor de base de datos. Límite: .Take(5) — solo se devuelven los 5 primeros resultados. Comportamiento en error:
  • Si ocurre una excepción durante la consulta, establece TempData["Error"] con el mensaje de la excepción y redirige a Home/Index.
Retorno: View(List<{ProductoId, NombreProducto, CantidadTotal, TotalRecaudado}>).
[HttpGet]
public async Task<IActionResult> MasVendidos()

El reporte incluye todos los DetallesVentas históricos, incluyendo aquellos pertenecientes a ventas con Estado == EstadoVenta.Anulada. Esto se debe a que la consulta se realiza directamente sobre DetallesVentas sin hacer join con la tabla Ventas ni filtrar por estado.
Para excluir las ventas anuladas del cómputo, agrega un filtro sobre la navegación a Venta antes del GroupBy:
_context.DetallesVentas
    .Include(d => d.Producto)
    .Include(d => d.Venta)                                     // incluir navegación
    .Where(d => d.Venta.Estado == EstadoVenta.Activa)          // solo ventas activas
    .GroupBy(d => d.Producto_ID)
    .Select(grupo => new {
        ProductoId     = grupo.Key,
        NombreProducto = grupo.First().Producto.Nombre,
        CantidadTotal  = grupo.Sum(d => d.Cantidad),
        TotalRecaudado = grupo.Sum(d => d.Cantidad * d.PrecioUnitario)
    })
    .OrderByDescending(x => x.CantidadTotal)
    .Take(5)
Esto requiere que la entidad DetalleVenta tenga una propiedad de navegación Venta configurada en el modelo EF Core.

Build docs developers (and LLMs) love