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 Producto entity represents a physical item stocked and sold through the Tienda Mi Cholo point-of-sale system. Each product belongs to exactly one Categoria, carries both a purchase (cost) price and a selling price, tracks its current inventory level via Stock, and can be soft-deleted by toggling the Estado flag. Products are exposed through the AppDbContext.Productos DbSet and are referenced by DetalleVenta line items whenever a sale is recorded.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Final_proyecto.Models
{
    public class Producto
    {
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int ID_Producto { get; set; }
        [Required, StringLength(100)]
        public string NombreProducto { get; set; }
        [StringLength(200)]
        public string? Descripcion { get; set; }
        [Required]
        [Column(TypeName = "decimal(10,2)")]
        public decimal PrecioCompra { get; set; }
        [Required]
        [Column(TypeName = "decimal(10,2)")]
        public decimal PrecioVenta { get; set; }
        [Required]
        public int Stock { get; set; }
        public bool Estado { get; set; } = true;
        public int Categoria_ID { get; set; }
        public Categoria? Categoria { get; set; }
        public ICollection<DetalleVenta>? Detalles { get; set; }
    }
}

Properties

ID_Producto
int
required
Primary key. Auto-generated by the database using DatabaseGeneratedOption.Identity. Annotated with [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]. Never set manually.
NombreProducto
string
required
Human-readable product name displayed in the POS search results and inventory lists. Annotated with [Required, StringLength(100)] — must be non-null and no longer than 100 characters.
Descripcion
string?
Optional free-text description of the product. Annotated with [StringLength(200)] — maximum 200 characters. May be null.
PrecioCompra
decimal(10,2)
required
The cost price paid to acquire one unit of this product. Stored as decimal(10,2) via [Column(TypeName = "decimal(10,2)")]. Used to calculate margins but not shown to cashier-role users on the POS screen. Must be a positive value.
PrecioVenta
decimal(10,2)
required
The selling price charged to customers per unit. Stored as decimal(10,2). This value is snapshotted into DetalleVenta.PrecioUnitario at the moment a sale line item is created, so historical sales are never affected by future price changes. Must be greater than or equal to PrecioCompra (enforced at the controller level).
Stock
int
required
Current number of units available for sale. Decremented automatically when a DetalleVenta is committed. Only products where Stock > 0 and Estado = true are returned by the BuscarProductos POS endpoint.
Estado
bool
Soft-delete / active flag. Defaults to true (active) on creation. Setting Estado = false hides the product from all POS searches and prevents it from being added to new sales, without physically deleting the database row or invalidating historical DetalleVenta records.
Categoria_ID
int
required
Foreign key to Categoria.ID_Categoria. Configured via Fluent API in AppDbContext.OnModelCreating:
modelBuilder.Entity<Producto>()
    .HasOne(p => p.Categoria)
    .WithMany(c => c.Productos)
    .HasForeignKey(p => p.Categoria_ID);
Categoria
Categoria?
Navigation property to the parent Categoria. Nullable — may be null if the related entity is not loaded (i.e., query did not use .Include(p => p.Categoria)).
Detalles
ICollection<DetalleVenta>?
Inverse navigation collection of all DetalleVenta line items that reference this product. Nullable collection — will be null unless explicitly loaded with .Include(p => p.Detalles). Useful for sales history reporting per product.

Validation Rules

The following business rules are applied by ProductoController in addition to the data-annotation constraints declared on the model:
PrecioVenta ≥ PrecioCompra — The controller rejects any create or edit request where the selling price is lower than the purchase/cost price. This prevents accidental negative-margin listings and is enforced before ModelState is committed to the database.
Estado defaults to true — On the create action, Estado is explicitly set to true if it has not been provided in the form payload, ensuring every new product starts in an active, saleable state.
BuscarProductos filter — The product search endpoint used by the POS view applies a compound filter: Estado == true && Stock > 0. A product with Estado = true but zero stock is not returned, preventing cashiers from adding out-of-stock items to a sale cart.
When deactivating a product that still has stock, set Estado = false rather than deleting the row. This preserves referential integrity with existing DetalleVenta records and allows the product to be reactivated later.

Build docs developers (and LLMs) love