Invoices are the central document of Eme2App’s billing system. Every invoice moves through a well-defined lifecycle — from an editable borrador draft, through confirmada (emitted with due dates generated), to anulada (voided via a mirror negative invoice). Payment status is derived from the state of the invoice’sDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/eme2dev/Eme2App/llms.txt
Use this file to discover all available pages before exploring further.
facturas_vencimientos rows — pending, partial, or cobrado — rather than being stored directly on the invoice. The backend enforces strict transition rules at each step, preventing data loss and ensuring fiscal integrity throughout.
Invoice Lifecycle
| Estado | Meaning |
|---|---|
borrador | Draft — fully editable, no due dates generated yet |
confirmada | Emitted — due dates generated from forma_pago; can be reverted to borrador if no cobros exist |
anulada | Voided — a mirror negative invoice (rectificativa) was automatically created |
cobrada, parcialmente cobrada, and vencida are display states derived from vencimientos — they are not stored in the facturas.estado column. An invoice is considered fully collected when all its facturas_vencimientos rows reach cobrado state.Series and Numbering
When the company hasusa_series = true in the empresa table, every invoice must belong to a series_facturas entry. A series carries a short codigo (e.g. "A", "B") and a flag es_rectificativa — only non-rectificative series may be used for regular invoices.
To retrieve the next available number for a given series:
The unique constraint on the
facturas table is (empresa_id, numero, serie). Two invoices may share the same numero as long as they belong to different series.Creating an Invoice
POST /api/facturas
All routes under /api/facturas require a valid JWT (verificarAutenticacion middleware). The authenticated user’s empresa_id is injected automatically.
Required fields:
| Field | Type | Notes |
|---|---|---|
cliente_id | string (UUID) | Must exist and belong to the company |
numero | integer | Unique within (empresa_id, serie) |
detalles | array | At least one line item |
forma_pago_id | string (UUID) | Falls back to cliente.forma_pago_defecto_id if omitted |
fecha (defaults to today), serie / serie_id, notas.
Detail line fields:
| Field | Type | Notes |
|---|---|---|
articulo_id | string | Required for non-comment lines |
descripcion | string | Free-text override of the article description |
cantidad | number | Quantity |
precio_unitario | number | Unit price before tax |
es_comentario | boolean | If true, the line is a text-only comment; articulo_id, cantidad, precio_unitario are ignored |
articulo.iva_id, applies recargo de equivalencia for clients in the REC or SIM tax regime, and withholds IRPF according to the client’s regimen_irpf. Totals (subtotal, iva_monto, recargo_total, irpf_monto, total) are computed server-side and stored in the facturas table.
Emitting an Invoice (estado-emision)
Theestado_emision field tracks the physical emission of the invoice document, independently of the billing state. Valid values and their one-way progression:
POST /api/facturas/:id/enviar-email automatically advances estado_emision to "email" upon a successful send.
Confirming and Reverting State
UsePUT /api/facturas/:id/estado to advance or revert the billing state:
borrador → confirmada: generatesfacturas_vencimientosrows from theforma_pagotemplate.confirmada → borrador: allowed only if no vencimientos have been collected or partially paid; all vencimientos are deleted.anulada → *: blocked — an anulada invoice is immutable.borrador → anulada: blocked — confirm the invoice first.
Voiding an Invoice
POST /api/facturas/:id/anular
Only confirmada invoices can be voided. The system:
- Locates the active rectificative series (or prompts the user to choose if multiple exist).
- Creates a mirror negative invoice (
factura espejo) in that series with all amounts negated. - Copies the original line items with negative
cantidad. - Creates negative
cobrosentries in the original invoice to reflect any payments already registered. - Marks the original invoice as
anulada.
To delete the rectificative invoice and restore the original to
confirmada, call DELETE /api/facturas/:id on the rectificative. The backend detects the factura_origen_anulacion_id link and restores the original automatically. Note that invoices with grouped vencimientos (agrupador_id) cannot be voided until they are ungrouped from the Treasury module.Due Dates (Vencimientos)
When an invoice transitions toconfirmada, due dates are auto-generated from the formas_pago_vencimientos configuration of the invoice’s forma_pago. Each row in facturas_vencimientos represents one instalment:
| Field | Description |
|---|---|
numero_cuota | Sequential instalment number |
importe | Amount due for this instalment |
fecha_vencimiento | Due date |
estado | pending / partial / cobrado / overdue |
instrumento_id | Expected payment instrument |
agrupador_id | Set when this vencimiento belongs to a treasury group |
Registering Collections (Cobros)
Cobros are registered against a specificvencimiento_id. The instrumento_id (payment instrument) is mandatory.
POST /api/facturas/:id/cobros
importe is less than the vencimiento’s full amount, provide fecha_vencimiento_resto — the backend marks the current vencimiento as partial, reduces its amount, and creates a new vencimiento for the remainder.
pending.
Sending by Email
POST /api/facturas/:id/enviar-email
The invoice must be in confirmada state. The frontend generates the PDF client-side and sends it as a Base64 string:
smtp_host, smtp_port, smtp_user, smtp_pass, email_from). On success, estado_emision is automatically advanced to "email".
Typical Workflow
Create a draft invoice
Call
POST /api/facturas with cliente_id, numero, serie, forma_pago_id, and at least one detail line. The invoice is saved with estado = "borrador".Review and confirm
Call
PUT /api/facturas/:id/estado with { "estado": "confirmada" }. The backend generates facturas_vencimientos rows from the forma de pago template.Send the PDF by email
Call
POST /api/facturas/:id/enviar-email with the Base64 PDF. The estado_emision advances to "email" automatically.Register a cobro
When the client pays, call
POST /api/facturas/:id/cobros with the vencimiento_id, importe, fecha_pago, and instrumento_id.API Quick Reference
| Method | Endpoint | Description |
|---|---|---|
GET | /api/facturas/proximo-numero | Next available invoice number |
GET | /api/facturas | Paginated invoice list |
GET | /api/facturas/informe-cobros | Collections report |
GET | /api/facturas/:id | Invoice detail |
POST | /api/facturas | Create invoice |
PUT | /api/facturas/:id | Update invoice (borrador or confirmada) |
PUT | /api/facturas/:id/estado | Change billing state |
PATCH | /api/facturas/:id/estado-emision | Advance emission state |
POST | /api/facturas/:id/anular | Void invoice (creates mirror negative) |
DELETE | /api/facturas/:id | Delete invoice (blocked if cobros exist or vencimientos are grouped) |
POST | /api/facturas/:id/enviar-email | Send PDF by email |
GET | /api/facturas/:id/vencimientos | List due dates |
GET | /api/facturas/:id/vencimientos-disponibles | List pending/partial due dates |
POST | /api/facturas/:id/vencimientos | Create a due date manually |
PATCH | /api/facturas/:id/vencimientos/:vencimiento_id | Update a due date |
DELETE | /api/facturas/:id/vencimientos/:vencimiento_id | Delete a due date |
POST | /api/facturas/:id/vencimientos/restaurar | Regenerate due dates from forma_pago |
POST | /api/facturas/:id/cobros | Register a collection |
GET | /api/facturas/:id/cobros | List collections with summary |
DELETE | /api/facturas/:id/cobros/:cobro_id | Delete cobro and revert vencimiento |
PUT | /api/facturas/cobros/:id | Update a cobro (date, instrument, notes) |
DELETE | /api/facturas/cobros/:id | Delete a cobro |
POST | /api/facturas/:id/vencimientos/:vencimiento_id/revertir-cobro | Revert all cobros on a vencimiento |