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 quote (Cotizacion) is a price proposal that implicitly reserves stock for a defined validity window. While a quote is in PENDIENTE state and its validaHasta date has not passed, the quantities in that quote are counted as reserved across the whole system — the products API, the sales API, and new quote creation all factor in those reservations when checking available stock. This prevents a scenario where the same units are promised in multiple concurrent quotes or sold while a quote is still active. Quotes follow a strict state machine: PENDIENTECONVERTIDA (via the /convertir action) or PENDIENTECANCELADA (via /cancelar). A converted or cancelled quote cannot be modified again.

Endpoints

MethodPathDescriptionAuth required
GET/api/cotizacionesList quotes for the companyREALIZAR_VENTAS or ADMIN
POST/api/cotizacionesCreate a new quoteREALIZAR_VENTAS or ADMIN
POST/api/cotizaciones/[id]/convertirConvert a pending quote to a saleREALIZAR_VENTAS or ADMIN
POST/api/cotizaciones/[id]/cancelarCancel a pending quoteREALIZAR_VENTAS or ADMIN

GET /api/cotizaciones

Returns quotes belonging to the authenticated user’s company. Administrators see all quotes; non-admin users see only the quotes they created. Results are ordered by most recent first.
estado
string
Filter by quote state. Accepted values: PENDIENTE, CONVERTIDA, CANCELADA. Omit to return all states.
# All pending quotes
curl -X GET "https://your-domain.com/api/cotizaciones?estado=PENDIENTE" \
  -H "Cookie: <session-cookie>"
Response Returns a JSON array of quote objects. Each object contains the full Cotizacion fields plus an embedded vendedor object and an _count.items field:
id
number
Unique quote identifier.
estado
string
"PENDIENTE", "CONVERTIDA", or "CANCELADA".
total
number
Sum of all line item subtotals at time of creation.
validaHasta
string
ISO 8601 expiry timestamp. Once this date passes, the quote can no longer be converted.
creadoEn
string
ISO 8601 creation timestamp.
convertidaEn
string | null
Timestamp when the quote was converted to a sale, or null.
canceladaEn
string | null
Timestamp when the quote was cancelled, or null.
ventaId
number | null
ID of the Venta generated by conversion, or null while still pending.
vendedorId
string | null
ID of the user who created the quote.
vendedor
object | null
Embedded user object with id, nombre, and email.
clienteId
number | null
ID of the associated customer, or null.
notas
string | null
Optional notes on the quote.
motivoCancelacion
string | null
Cancellation reason, or null.
_count.items
number
Number of line items in this quote.
Error cases
StatusCause
401No active session.
403User lacks REALIZAR_VENTAS permission and is not an ADMIN.
500Unexpected server error.

POST /api/cotizaciones

Creates a new quote. Unlike a sale, creating a quote does not decrement physical stock — it only records a reservation. The reservation is computed as the sum of cantidad across all PENDIENTE quotes that have not yet expired. New quote creation checks that the requested quantities do not exceed producto.cantidad − already_reserved, using row-level locks to prevent concurrent over-commitment. The quote’s validity window defaults to 7 days from creation. Pass diasValidez to override this (maximum 365 days).
items
object[]
required
Array of line items. Must contain at least one entry.
items[].productoId
number
required
ID of the product to include. Must belong to the authenticated user’s company.
items[].cantidad
number
required
Quantity to quote. Must be a positive integer. Must not exceed the currently available (unreserved) stock.
diasValidez
number
default:"7"
Number of days the quote remains valid. Capped at 365.
cliente
string
Optional customer name string. If a matching Cliente record exists by name, it is linked; otherwise a new Cliente record is created automatically.
notas
string
Optional free-text notes for the quote.
curl -X POST "https://your-domain.com/api/cotizaciones" \
  -H "Content-Type: application/json" \
  -H "Cookie: <session-cookie>" \
  -d '{
    "items": [
      { "productoId": 42, "cantidad": 10 },
      { "productoId": 17, "cantidad": 2 }
    ],
    "diasValidez": 14,
    "cliente": "Distribuidora Andina",
    "notas": "Cotización para pedido mensual"
  }'
Returns the created Cotizacion object with HTTP 201 Created, including embedded items with product names and codes. Stock reservation behaviour When this quote is PENDIENTE and validaHasta > now():
  • Its quantities are counted as reserved when any subsequent quote or sale checks available stock for these products.
  • The product’s cantidad field is not changed — it still reflects physical stock on hand.
  • To see effective available stock, subtract the reserved amount: disponible = producto.cantidad − reservado_en_cotizaciones_pendientes.
Error cases
StatusCause
400Empty items, invalid product ID, cantidad ≤ 0, or insufficient available stock after accounting for other active reservations.
401No active session.
403Insufficient permissions or user has no company assigned.
404One or more products not found in the company.
500Unexpected server error.

POST /api/cotizaciones/[id]/convertir

Converts a PENDIENTE quote into a confirmed Venta. This action:
  1. Verifies physical stock is sufficient for each item (producto.cantidad >= item.cantidad).
  2. Creates a Venta with the same items, prices, and totals as the quote.
  3. Creates a salida movement per line item, linked to the new sale.
  4. Decrements each product’s cantidad.
  5. Sets cotizacion.estado = "CONVERTIDA", records convertidaEn, and links ventaId to the new sale.
Because the quote transitions out of PENDIENTE, the stock reservation is automatically released — it is replaced immediately by the actual stock decrement from the sale. Only the original vendor of the quote or an ADMIN can convert it. The quote must not be expired (validaHasta > now()).
id
number
required
The numeric ID of the quote to convert.
curl -X POST "https://your-domain.com/api/cotizaciones/55/convertir" \
  -H "Cookie: <session-cookie>"
Response Returns a JSON object with two top-level keys:
venta
object
The newly created Venta record.
cotizacion
object
The updated Cotizacion record with estado: "CONVERTIDA", convertidaEn timestamp, and ventaId pointing to the new sale.
Error cases
StatusCause
400Quote has expired (validaHasta is in the past), or physical stock is insufficient for one or more items.
401No active session.
403User is not the original vendor and not an ADMIN.
404Quote not found or belongs to a different company.
409Quote is already converted or already cancelled.
500Unexpected server error.

POST /api/cotizaciones/[id]/cancelar

Cancels a PENDIENTE quote, releasing all stock reservations held by it. Cancelling a quote does not touch physical stock (no movement is created) because quotes never decremented it. The quote is marked CANCELADA with the provided reason and a canceladaEn timestamp. Only the original vendor or an ADMIN can cancel a quote. A motivo (reason) is mandatory. A quote that is already CANCELADA cannot be cancelled again, and a CONVERTIDA quote cannot be cancelled — cancel the resulting sale instead.
id
number
required
The numeric ID of the quote to cancel.
motivo
string
required
Reason for cancellation. Cannot be empty.
curl -X POST "https://your-domain.com/api/cotizaciones/55/cancelar" \
  -H "Content-Type: application/json" \
  -H "Cookie: <session-cookie>" \
  -d '{ "motivo": "Cliente optó por otro proveedor" }'
Returns the updated Cotizacion object with estado: "CANCELADA", canceladaEn, canceladaPorId, and motivoCancelacion set. Error cases
StatusCause
400Missing or empty motivo.
401No active session.
403User is not the original vendor and not an ADMIN.
404Quote not found or belongs to a different company.
409Quote is already cancelled, or has already been converted (cancel the sale instead).
500Unexpected server error.

Build docs developers (and LLMs) love