A quote (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.
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: PENDIENTE → CONVERTIDA (via the /convertir action) or PENDIENTE → CANCELADA (via /cancelar). A converted or cancelled quote cannot be modified again.
Endpoints
| Method | Path | Description | Auth required |
|---|---|---|---|
| GET | /api/cotizaciones | List quotes for the company | REALIZAR_VENTAS or ADMIN |
| POST | /api/cotizaciones | Create a new quote | REALIZAR_VENTAS or ADMIN |
| POST | /api/cotizaciones/[id]/convertir | Convert a pending quote to a sale | REALIZAR_VENTAS or ADMIN |
| POST | /api/cotizaciones/[id]/cancelar | Cancel a pending quote | REALIZAR_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.Filter by quote state. Accepted values:
PENDIENTE, CONVERTIDA, CANCELADA. Omit to return all states.Cotizacion fields plus an embedded vendedor object and an _count.items field:
Unique quote identifier.
"PENDIENTE", "CONVERTIDA", or "CANCELADA".Sum of all line item subtotals at time of creation.
ISO 8601 expiry timestamp. Once this date passes, the quote can no longer be converted.
ISO 8601 creation timestamp.
Timestamp when the quote was converted to a sale, or
null.Timestamp when the quote was cancelled, or
null.ID of the
Venta generated by conversion, or null while still pending.ID of the user who created the quote.
Embedded user object with
id, nombre, and email.ID of the associated customer, or
null.Optional notes on the quote.
Cancellation reason, or
null.Number of line items in this quote.
| Status | Cause |
|---|---|
401 | No active session. |
403 | User lacks REALIZAR_VENTAS permission and is not an ADMIN. |
500 | Unexpected 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 ofcantidad 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).
Array of line items. Must contain at least one entry.
ID of the product to include. Must belong to the authenticated user’s company.
Quantity to quote. Must be a positive integer. Must not exceed the currently available (unreserved) stock.
Number of days the quote remains valid. Capped at 365.
Optional customer name string. If a matching
Cliente record exists by name, it is linked; otherwise a new Cliente record is created automatically.Optional free-text notes for the quote.
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
cantidadfield 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.
| Status | Cause |
|---|---|
400 | Empty items, invalid product ID, cantidad ≤ 0, or insufficient available stock after accounting for other active reservations. |
401 | No active session. |
403 | Insufficient permissions or user has no company assigned. |
404 | One or more products not found in the company. |
500 | Unexpected server error. |
POST /api/cotizaciones/[id]/convertir
Converts aPENDIENTE quote into a confirmed Venta. This action:
- Verifies physical stock is sufficient for each item (
producto.cantidad >= item.cantidad). - Creates a
Ventawith the same items, prices, and totals as the quote. - Creates a
salidamovement per line item, linked to the new sale. - Decrements each product’s
cantidad. - Sets
cotizacion.estado = "CONVERTIDA", recordsconvertidaEn, and linksventaIdto the new sale.
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()).
The numeric ID of the quote to convert.
The newly created
Venta record.The updated
Cotizacion record with estado: "CONVERTIDA", convertidaEn timestamp, and ventaId pointing to the new sale.| Status | Cause |
|---|---|
400 | Quote has expired (validaHasta is in the past), or physical stock is insufficient for one or more items. |
401 | No active session. |
403 | User is not the original vendor and not an ADMIN. |
404 | Quote not found or belongs to a different company. |
409 | Quote is already converted or already cancelled. |
500 | Unexpected server error. |
POST /api/cotizaciones/[id]/cancelar
Cancels aPENDIENTE 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.
The numeric ID of the quote to cancel.
Reason for cancellation. Cannot be empty.
Cotizacion object with estado: "CANCELADA", canceladaEn, canceladaPorId, and motivoCancelacion set.
Error cases
| Status | Cause |
|---|---|
400 | Missing or empty motivo. |
401 | No active session. |
403 | User is not the original vendor and not an ADMIN. |
404 | Quote not found or belongs to a different company. |
409 | Quote is already cancelled, or has already been converted (cancel the sale instead). |
500 | Unexpected server error. |