Skip to main content

Documentation Index

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

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

The sale detail page is a read-only summary of a single completed transaction. It presents the full receipt header — voucher number, receipt type, emission date and time, and client information — alongside an itemized table of every product sold, the quantity purchased, the unit price captured at the moment of sale, and the calculated subtotal for each line. Every authenticated user regardless of role can access this page, making it useful for cashiers who need to verify a receipt as well as managers reviewing transaction history.

What’s Displayed

The detail view is divided into two visual areas. The upper area contains the receipt header information and the grand total, while the lower area holds the product line-item table. Receipt header fields:
FieldSourceExample
Tipo de ComprobanteVenta.TipoComprobanteBoleta / Factura (color-coded badge)
Nro. ComprobanteVenta.NumeroComprobanteB001-00000003 / F001-00000001
ClienteVenta.Cliente.Nombres + .ApellidosJuan Pérez / Inversiones Mi Cholo S.A.C.
Tipo/Nro. DocumentoCliente.TipoDocumento + .NumeroDocumentoDNI: 45821693 / RUC: 20147852369
TeléfonoCliente.Telefono987654321 (shown only when non-empty)
Fecha y Hora de EmisiónVenta.FechaVenta15/06/2025 14:32:07
Monto TotalVenta.MontoTotalS/ 127.50
The Monto Total is displayed prominently as a stat card with large typography, along with a count of how many distinct product lines (Detalles?.Count) the sale contains. Line-item table columns:
ColumnSource fieldNotes
#Row counterSequential starting at 1
ProductoDetalleVenta.Producto.NombreProductoLoaded via ThenInclude(d => d.Producto)
CantidadDetalleVenta.CantidadUnits sold
Precio Unit.DetalleVenta.PrecioUnitarioPrice at time of sale — see note below
SubtotalDetalleVenta.SubtotalCantidad × PrecioUnitario

Line Item Details

Each row in the line-item table corresponds to one DetalleVenta record. The DetalleVenta model exposes the following persisted fields:
public class DetalleVenta
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID_DetalleVenta { get; set; }

    [Required]
    public int Cantidad { get; set; }

    [Required]
    [Column(TypeName = "decimal(10,2)")]
    public decimal PrecioUnitario { get; set; }

    [Required]
    [Column(TypeName = "decimal(10,2)")]
    public decimal Subtotal { get; set; }

    public int Producto_ID { get; set; }
    public Producto Producto { get; set; }   // Navigation property

    public int Venta_ID { get; set; }
    public Venta Venta { get; set; }         // Navigation property
}
The Producto navigation property is eagerly loaded by the controller (see URL and Access below), so det.Producto.NombreProducto is always available without a lazy-load round-trip. Subtotal is a stored, computed column. It is set equal to Cantidad × PrecioUnitario at the moment the detail record is created and is never updated afterward. This means the displayed subtotals reflect exactly what was charged at the time of the transaction.

Price Snapshot

PrecioUnitario in DetalleVenta stores the product’s PrecioVenta at the exact moment the sale was processed — not the product’s current price. If a product’s price is updated in the catalog after a sale has been recorded, the historical PrecioUnitario on every past DetalleVenta remains unchanged. This ensures that sale totals, receipts, and audit records always reflect what the customer was actually charged.
During new-sale creation, PrecioUnitario is set directly from the submitted precios[] array (which the POS screen populates from the product search API response):
detalles.Add(new DetalleVenta
{
    Producto_ID = producto.ID_Producto,
    Cantidad    = cant,
    PrecioUnitario = precios[i],   // captured at time of sale
    Subtotal    = cant * precios[i]
});

URL and Access

GET /Venta/Detalle/{id}
ParameterTypeDescription
idintThe ID_Venta of the sale to display
Access: All authenticated users. No role restriction is applied — only [Authorize] at the controller level is required. The controller loads the sale with all necessary related data in a single query using Include and ThenInclude:
Venta venta = await _context.Ventas
    .Include(v => v.Cliente)
    .Include(v => v.Detalles)
        .ThenInclude(d => d.Producto)
    .FirstAsync(v => v.ID_Venta == id);

return View(venta);
This query joins three tables in one round-trip:
  • Ventas — the root sale record
  • Clientes — the linked client record (for name, document type/number, and phone)
  • DetalleVentasProductos — every line item and its associated product name
The view is strongly typed to Final_proyecto.Models.Venta and uses the fully populated model directly without any additional ViewBag data.

Build docs developers (and LLMs) love