The Quotes module handles the creation and lifecycle management of commercial proposals in B2B Import ERP. Quotes are always linked to a client and optionally to an open Requirement. They support multi-line item composition with per-line discounts and taxes, automatic header total recalculation, PDF export with tenant branding, and a full versioning system when a quote is rejected and needs to be revised. Once approved, a quote unlocks the transition of its linked Requirement toDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/ency07/B2B-import/llms.txt
Use this file to discover all available pages before exploring further.
OT_GENERADA (Work Order Generated).
Quote Lifecycle
Quote states are enforced by thevalidate_quote_state_transitions trigger. States marked as final cannot be changed once reached.
| State | Description |
|---|---|
BORRADOR | Draft; items can be freely added or modified |
EN_REVISION | Submitted for internal review; triggers the approval workflow |
ENVIADA | Sent to the client; awaiting client decision |
APROBADA | Approved — final state; unlocks work order creation |
RECHAZADA | Rejected — final state; a new version can be created |
VENCIDA | Expired; typically set when a new version supersedes this one |
CANCELADA | Cancelled — final state; only allowed from BORRADOR |
QuoteRow Interface
The following interface is exported fromsrc/app/actions/quotes.ts:
quote_code is auto-generated as COT-XXXXXX by the handle_quote_versioning trigger using tenant_sequences. The code is immutable after creation.Quote Items
Line items are stored in thequote_items table and linked to a quote via quote_id. The trg_calculate_quote_item_totals trigger computes line amounts automatically on every insert or update:
quote_items, trg_update_quote_totals recalculates the quote header:
| Field | Type | Description |
|---|---|---|
quote_id | uuid | FK to quotes.id |
item_order | integer | Display order of the line |
item_type | enum | MATERIAL · SERVICIO · EQUIPO · MANO_OBRA · OTRO |
description | text | Line item description (required) |
quantity | numeric(18,4) | Quantity > 0 |
unit | varchar(50) | Unit of measure (e.g. UNIDAD, ML, HR) |
unit_price | numeric(18,2) | Unit price ≥ 0 |
discount_amount | numeric(18,2) | Per-line monetary discount |
tax_percent | numeric(5,2) | Tax rate as a percentage (e.g. 19.00 for 19% IVA) |
line_total | numeric(18,2) | Auto-calculated net line total |
Server Actions
getQuotes
getQuotes(tenantCode?)Returns all non-deleted quotes for the resolved tenant with joined client.legal_name, ordered newest first.createQuote
createQuote(tenantCode, quoteData)Creates a new quote in BORRADOR status. quote_code and version are set by the database trigger. Provide requirementId to link the quote to an existing requirement.getQuoteItems
getQuoteItems(quoteId)Returns all line items for a specific quote ordered by item_order ascending.addQuoteItem
addQuoteItem(tenantCode, itemData)Inserts a line item. The trigger immediately calculates tax_amount and line_total, then recalculates the quote header totals.PDF Export
Quotes can be exported to PDF using jsPDF with full tenant branding applied in the document header (logo, tenant name, contact information) and footer (terms, validity date, signature area). The export is triggered from the quote detail page and generates a downloadable PDF client-side.A quote submitted for approval (
EN_REVISION) must have at least one line item. The state transition trigger raises an exception if quote_items is empty when attempting to move from BORRADOR to EN_REVISION.Versioning
When a quote is rejected (RECHAZADA), a new version can be created with the same quote_code but an incremented version number. The handle_quote_versioning trigger:
- Detects that a
quote_codealready exists in the tenant. - Sets
NEW.version = max_version + 1. - Marks the previous
ENVIADAorEN_REVISIONversion asVENCIDAautomatically.
Approval Flow
When a quote transitions toEN_REVISION, the route_quote_approvals trigger fires automatically and:
- Looks up an active
approval_rulesrule matching the quote’stotal_amountrange andentity_type = 'QUOTE'. - If a matching rule exists with a
flow_id, it creates anapproval_requestsrecord and instantiatesapproval_request_stepsfor each step in the flow. - If no rule is found, the quote is automatically escalated to the
GERENTE_GENERALrole. - If the rule has
flow_id = NULL, the quote is auto-approved immediately.
RBAC — Role-Based Access
| Permission | Roles |
|---|---|
quotes.create | ADMIN_EMPRESA, GERENTE_GENERAL, DIRECTOR_COMERCIAL, EJECUTIVO_COMERCIAL |
quotes.submit (→ EN_REVISION, ENVIADA) | EJECUTIVO_COMERCIAL, DIRECTOR_COMERCIAL |
quotes.approve (→ APROBADA, RECHAZADA) | GERENTE_GENERAL, DIRECTOR_COMERCIAL |
quotes.view | ADMIN_EMPRESA, GERENTE_GENERAL, DIRECTOR_COMERCIAL, EJECUTIVO_COMERCIAL, DIRECTOR_OPERACIONES, AUDITOR, CLIENTE |
quotes.cancel | EJECUTIVO_COMERCIAL, DIRECTOR_COMERCIAL, GERENTE_GENERAL |