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.

VentaController and DetalleVentaController together manage the complete sales lifecycle in Tienda Mi Cholo. VentaController handles sale headers — browsing the sales list, creating new sales with full client resolution and voucher auto-numbering, viewing a sale’s detail page, deleting a sale with stock restoration, and a live product-search endpoint used by the sale form. DetalleVentaController manages individual line items on an existing sale: adding a new line (with stock validation and total recalculation) and removing a line (with stock restoration and total recalculation). Both controllers carry [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)] and require an authenticated user via [Authorize] at the class level; individual actions narrow access further with role-based [Authorize(Roles = "...")] attributes.

VentaController

GET /Venta/Lista

Returns all sales ordered by FechaVenta descending, each with its related Cliente record eagerly loaded, and passes the list to the Lista view. Authorization: Any authenticated user (all roles).
List<Venta> lista = await _context.Ventas
    .Include(v => v.Cliente)
    .OrderByDescending(v => v.FechaVenta)
    .ToListAsync();

GET /Venta/Nueva

Loads the new-sale form. Populates ViewBag.Clientes with every client whose ID_Cliente is not 1 (i.e., all non-default clients) so the cashier can optionally select an existing customer. Authorization: Administrador, Gerente, Cajero.
Client ID 1 is the reserved Público General default client. It is excluded from the dropdown because it is selected automatically when no client name is provided on the POST.

POST /Venta/Nueva

Creates a new sale inside a database transaction. Resolves or creates the appropriate client record depending on tipoComprobante, auto-generates a correlative voucher number, decrements product stock for each line item, and persists the Venta together with its DetalleVenta collection in a single SaveChangesAsync call. Authorization: Administrador, Gerente, Cajero. Decorated with [ValidateAntiForgeryToken] — the form must include a valid anti-forgery token or the request is rejected with a 400 Bad Request.
productoIds
int[]
required
Array of product IDs to include in the sale. Must not be empty and must have the same length as cantidades and precios.
cantidades
int[]
required
Quantity for each product, parallel to productoIds. Each value must be greater than zero and must not exceed the product’s current Stock.
precios
decimal[]
required
Unit price for each product, parallel to productoIds. Used directly to compute Subtotal = cantidad × precio.
tipoComprobante
string
required
Either "Boleta" or "Factura". Determines both the voucher prefix (B001- / F001-) and the client-resolution logic.
clienteNombres
string
Full name (Boleta) or Razón Social (Factura) of the customer. Optional for Boleta; required for Factura.
numeroDocumento
string
DNI (Boleta) or RUC (Factura). For Factura, must be exactly 11 digits and start with 10 or 20. Ignored for Boleta unless a name was supplied.
telefono
string
Mobile number. For Factura, must be 9 digits, start with 9, and must not be all-identical digits. Ignored for Boleta.
On success: Sets TempData["Success"] with the voucher number and redirects to GET /Venta/Lista. On validation failure: Rolls back the transaction, sets TempData["Error"], restores form state via ViewBag (including a JSON-serialized cart for JavaScript re-hydration), and returns the Nueva view.

GET /Venta/BuscarProductos?q=

Live search endpoint consumed by the new-sale form’s product typeahead. Returns a JSON array of matching active products that have stock available. Authorization: Any authenticated user (all roles).
q
string
required
Search term matched against NombreProducto using a SQL LIKE/Contains. Returns an empty array when blank or whitespace.
Results are filtered to Estado = true and Stock > 0, limited to 20 records. Response shape:
[
  {
    "id": 14,
    "nombre": "Leche Gloria 1L",
    "precio": 4.50,
    "stock": 120
  }
]
Call this endpoint from client-side JavaScript as the user types in the product search field. The 20-record cap keeps response sizes small even on large catalogs.

GET /Venta/Detalle/

Returns the full sale record for display: the Venta header with its Cliente, and all DetalleVenta line items each with their associated Producto. Authorization: Any authenticated user (all roles).
id
int
required
Primary key (ID_Venta) of the sale to display.
Venta venta = await _context.Ventas
    .Include(v => v.Cliente)
    .Include(v => v.Detalles)
        .ThenInclude(d => d.Producto)
    .FirstAsync(v => v.ID_Venta == id);

GET /Venta/Eliminar/

Permanently deletes a sale after restoring the stock for every product that appeared in it. Removes all associated DetalleVenta rows first, then removes the Venta header, and redirects to the sales list. Authorization: Administrador, Gerente.
id
int
required
Primary key (ID_Venta) of the sale to delete.
This action is irreversible. All DetalleVenta records are hard-deleted along with the parent Venta. Product stock is restored by adding each line item’s Cantidad back to Producto.Stock before deletion.

DetalleVentaController

POST /DetalleVenta/Nuevo

Adds a single line item to an existing sale. Fetches the product to validate stock and resolve the current unit price, computes the subtotal, decrements stock, persists the new DetalleVenta, then recalculates and saves Venta.MontoTotal. Authorization: Administrador, Gerente, Cajero.
detalle
DetalleVenta
required
Model-bound DetalleVenta object. The required fields are:
  • Venta_ID — the parent sale.
  • Producto_ID — the product to add.
  • Cantidad — units to add; must be greater than zero and not exceed current stock.
PrecioUnitario and Subtotal are overwritten by the server from the product record regardless of what is submitted.
If Cantidad ≤ 0, the action silently redirects back to GET /Venta/Detalle/{id} without adding a line. If Cantidad > producto.Stock, it redirects with TempData["Error"] set.
After saving, Venta.MontoTotal is recalculated as the sum of all remaining DetalleVenta.Subtotal values for that sale:
venta.MontoTotal = venta.Detalles.Sum(d => d.Subtotal);
On success: Redirects to GET /Venta/Detalle/{Venta_ID}.

GET /DetalleVenta/Eliminar/

Removes a single line item from a sale. Restores the product’s stock by adding the line’s Cantidad back, deletes the DetalleVenta record, then recalculates and saves Venta.MontoTotal. Authorization: Administrador, Gerente, Cajero.
id
int
required
Primary key (ID_DetalleVenta) of the line item to remove.
After removal, Venta.MontoTotal is recalculated the same way as in the Nuevo action:
venta.MontoTotal = venta.Detalles.Sum(d => d.Subtotal);
On success: Redirects to GET /Venta/Detalle/{Venta_ID}.

Build docs developers (and LLMs) love