Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/juadariasmar/inventory_project/llms.txt

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

A sale (Venta) represents a confirmed transaction where one or more products leave the inventory. When a sale is created, the API executes a pessimistic-locked database transaction that validates available stock (physical quantity minus any quantities currently reserved by active quotes), decrements each product’s cantidad, and creates a salida movement per line item — all atomically. Sales are immutable after creation; the only post-creation operation is cancellation, which is restricted to the same calendar day and requires ADMIN privileges.

Endpoints

MethodPathDescriptionAuth required
POST/api/ventasCreate a new saleREALIZAR_VENTAS permission or ADMIN
POST/api/ventas/[id]/cancelarCancel a sale (same-day only)ADMIN
A GET /api/ventas listing endpoint is not yet exposed as a standalone route. Sales data is available through the analytics endpoint (GET /api/analisis) and the individual sale records stored in the database.

POST /api/ventas

Creates a sale with one or more line items. The entire operation runs inside a single database transaction with row-level locks on the affected products to prevent overselling under concurrent load. Stock availability is calculated as producto.cantidad − reservado_en_cotizaciones and validated inside the transaction (TOCTOU-safe). If the same productoId appears more than once in the items array, quantities are consolidated before processing.
items
object[]
required
Array of line items. Must contain at least one item.
items[].productoId
number
required
ID of the product being sold. Must belong to the authenticated user’s company.
items[].cantidad
number
required
Quantity being sold. Must be a positive integer.
notas
string
Optional free-text notes attached to the sale record.
curl -X POST "https://your-domain.com/api/ventas" \
  -H "Content-Type: application/json" \
  -H "Cookie: <session-cookie>" \
  -d '{
    "items": [
      { "productoId": 42, "cantidad": 3 },
      { "productoId": 17, "cantidad": 1 }
    ],
    "notas": "Venta mostrador — cliente frecuente"
  }'
Returns the created Venta object with HTTP 201 Created, including embedded items with product details. Response fields
id
number
Unique sale identifier.
total
number
Sum of all line item subtotals (precioUnitario × cantidad).
vendedorId
string | null
ID of the user who recorded the sale.
notas
string | null
Notes attached to the sale.
creadoEn
string
ISO 8601 creation timestamp.
canceladaEn
string | null
null for active sales; set to an ISO 8601 timestamp when cancelled.
canceladaPorId
string | null
ID of the admin who cancelled the sale, or null.
motivoCancelacion
string | null
Reason provided at cancellation time, or null.
empresaId
string
Company tenant identifier.
items
ItemVenta[]
Array of line items (see below).
Each ItemVenta in items:
id
number
Line item identifier.
ventaId
number
Parent sale ID.
productoId
number
Product ID.
cantidad
number
Quantity sold.
precioUnitario
number
Unit price at time of sale (snapshot from Producto.precio).
subtotal
number
Computed as precioUnitario × cantidad.
Error cases
StatusCause
400Empty items array, invalid productoId, cantidad ≤ 0, or insufficient available stock for one or more products.
401No active session.
403User lacks REALIZAR_VENTAS permission and is not an ADMIN.
404One or more products not found in the company.
500Unexpected server error.

POST /api/ventas/[id]/cancelar

Cancels a previously recorded sale. On success, the API marks the sale with canceladaEn, canceladaPorId, and motivoCancelacion, then creates a entrada movement per line item to restore stock to each product. Restrictions:
  • Only ADMIN users can cancel sales.
  • The sale must have been created on the same calendar day (based on the server’s local timezone). Sales from prior days cannot be cancelled through the API.
  • A sale cannot be cancelled more than once.
Cancellation does reverse the inventory movements — an entrada is created per line item with the note "Devolución por cancelación de venta #N" and the product’s cantidad is incremented accordingly. The sale record is preserved in history and excluded from sales totals.
id
number
required
The numeric ID of the sale to cancel.
motivo
string
Optional reason for the cancellation. Stored in Venta.motivoCancelacion. Passed in the request body as motivo (note: the field is named motivo in the cancel body, stored as motivoCancelacion in the database).
curl -X POST "https://your-domain.com/api/ventas/88/cancelar" \
  -H "Content-Type: application/json" \
  -H "Cookie: <session-cookie>" \
  -d '{ "motivo": "Error de cobro — cliente solicitó devolución" }'
Returns the updated Venta object including the canceladaEn timestamp and the embedded items with product names and codes. Error cases
StatusCause
400Sale was created on a previous calendar day and cannot be cancelled.
401No active session.
403Not an ADMIN, or user has no company assigned.
404Sale not found or belongs to a different company.
409Sale has already been cancelled.
500Unexpected server error.

Build docs developers (and LLMs) love