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.

A completed sale in Tienda Mi Cholo is modelled as a two-level structure: a single Venta header record that captures the receipt type, document number, timestamp, client, and cashier, plus one or more DetalleVenta line items — one per distinct product in the cart. The MontoTotal on the header is the authoritative sum of every DetalleVenta.Subtotal and is recalculated automatically whenever items are added to or removed from the cart. Both entities are persisted through AppDbContext (Ventas and DetalleVentas DbSets respectively) and their relationship is configured via Fluent API in OnModelCreating.

Venta Properties

ID_Venta
int
required
Primary key. Auto-generated by the database using DatabaseGeneratedOption.Identity. Annotated with [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]. Never assigned manually.
TipoComprobante
string
required
The receipt document type for this sale. Annotated with [Required, StringLength(20)]. Accepted values are:
  • "Boleta" — consumer receipt; typically linked to the Público General client for anonymous walk-in customers.
  • "Factura" — tax invoice; requires a client with a valid RUC (NumeroDocumento starting with 10 or 20).
NumeroComprobante
string
required
Unique receipt/invoice number assigned at the time of sale. Annotated with [Required, StringLength(20)]. Auto-generated by the controller using the following formats:
  • Boleta: B001-XXXXXXXX (e.g., B001-00000042)
  • Factura: F001-XXXXXXXX (e.g., F001-00000007)
The numeric suffix is zero-padded to eight digits and is derived by finding the most-recent existing comprobante of the same type (ordered descending by NumeroComprobante), parsing its numeric suffix, and incrementing by one.
FechaVenta
DateTime
required
The date and time the sale was finalised and persisted. Annotated with [Required]. Set to DateTime.Now by the controller at the moment the sale is committed; never editable after creation.
MontoTotal
decimal(10,2)
required
The grand total amount charged for the sale, in Peruvian soles (S/). Stored as decimal(10,2) via [Column(TypeName = "decimal(10,2)")]. Equals the sum of all associated DetalleVenta.Subtotal values. Recalculated automatically — see Auto-Calculated Fields.
Cliente_ID
int
required
Foreign key to Cliente.ID_Cliente. Configured via Fluent API:
modelBuilder.Entity<Venta>()
    .HasOne(v => v.Cliente)
    .WithMany(c => c.Ventas)
    .HasForeignKey(v => v.Cliente_ID);
For anonymous Boleta sales, this defaults to 1 (the seeded Público General client).
Cliente
Cliente
required
Navigation property to the associated Cliente. Non-nullable — every Venta must have a client (at minimum the Público General placeholder). Requires .Include(v => v.Cliente) to load.
Usuario_ID
int
required
The ID_Usuario of the logged-in cashier or administrator who processed the sale. Populated from HttpContext.Session.GetInt32("IdUsuario") at the time of sale creation; falls back to 1 if the session value is absent. Not a formal EF Core navigation property — stored as a plain integer foreign key with no corresponding navigation object on the Venta class.
Detalles
ICollection<DetalleVenta>
required
Collection of all DetalleVenta line items that belong to this sale. Non-nullable — a valid Venta must contain at least one line item. Requires .Include(v => v.Detalles) to load eagerly.

Venta — C# Source

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Final_proyecto.Models
{
    public class Venta
    {
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int ID_Venta { get; set; }

        [Required, StringLength(20)]
        public string TipoComprobante { get; set; } // Boleta o Factura

        [Required, StringLength(20)]
        public string NumeroComprobante { get; set; }

        [Required]
        public DateTime FechaVenta { get; set; }

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

        public int Cliente_ID { get; set; }
        public Cliente Cliente { get; set; }

        public int Usuario_ID { get; set; }

        public ICollection<DetalleVenta> Detalles { get; set; }
    }
}

DetalleVenta Properties

ID_DetalleVenta
int
required
Primary key. Auto-generated by the database using DatabaseGeneratedOption.Identity. Annotated with [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]. Never assigned manually.
Cantidad
int
required
The number of units of the product sold in this line item. Annotated with [Required]. Must be a positive integer; the controller validates that the requested quantity does not exceed the product’s current Stock.
PrecioUnitario
decimal(10,2)
required
A snapshot of Producto.PrecioVenta captured at the exact moment the line item is added to the sale. Stored as decimal(10,2). Because this is a point-in-time copy, changing a product’s price after a sale has been recorded does not retroactively alter PrecioUnitario on historical line items.
Subtotal
decimal(10,2)
required
The monetary value of this line item, computed as Cantidad × PrecioUnitario. Stored as decimal(10,2). Recalculated by the controller whenever the line item is created or modified — see Auto-Calculated Fields.
Producto_ID
int
required
Foreign key to Producto.ID_Producto. Configured via Fluent API:
modelBuilder.Entity<DetalleVenta>()
    .HasOne(d => d.Producto)
    .WithMany(p => p.Detalles)
    .HasForeignKey(d => d.Producto_ID);
Producto
Producto
required
Navigation property to the associated Producto. Non-nullable. Requires .Include(d => d.Producto) to load eagerly.
Venta_ID
int
required
Foreign key to Venta.ID_Venta. Configured via Fluent API:
modelBuilder.Entity<DetalleVenta>()
    .HasOne(d => d.Venta)
    .WithMany(v => v.Detalles)
    .HasForeignKey(d => d.Venta_ID);
Venta
Venta
required
Navigation property back to the parent Venta header. Non-nullable. Requires .Include(d => d.Venta) to load eagerly.

DetalleVenta — C# Source

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Final_proyecto.Models
{
    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; }

        public int Venta_ID { get; set; }
        public Venta Venta { get; set; }
    }
}

Auto-Calculated Fields

DetalleVenta.Subtotal is always derived, never entered directly. Each time a line item is added to or removed from the POS cart, the controller recalculates Subtotal = Cantidad × PrecioUnitario and writes the result back to the DetalleVenta row. Do not set this field manually when constructing a DetalleVenta object outside the controller — the value will be overwritten before the transaction is committed.
Venta.MontoTotal reflects the live cart total. After every add-to-cart or remove-from-cart operation the controller re-aggregates all DetalleVenta.Subtotal values for the current sale and updates MontoTotal on the parent Venta header. This means MontoTotal is always consistent with the line items and is never manually entered through the UI.

Build docs developers (and LLMs) love