Acrylitec’s data layer is defined inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/YonAnn99/Acrylitec/llms.txt
Use this file to discover all available pages before exploring further.
gestion/models.py using the Django ORM. There are 8 models across the gestion app, covering customers, quotes, materials, products, cost configuration, and sales — both through the legacy quotation flow and the newer point-of-sale (POS) cart flow.
Clientes
Stores customer contact information. Used by bothCotizaciones (legacy quotes) and Ventas (POS sales).
Database table: clientes
Primary key. Auto-incremented integer assigned by the database.
Full name of the customer. Maximum 100 characters.
Phone number. Stored as a string to support formatting variations. Maximum 100 characters.
Email address. Maximum 100 characters.
Street or delivery address. Unrestricted length text field.
Cotizaciones
Represents a single-product quotation. Stores all inputs needed for pricing and automatically computesmonto_total on every save via calcular_monto().
Database table: cotizaciones
Primary key. Auto-incremented integer.
The customer this quote is for. Uses
DO_NOTHING on delete — deleting a client does not cascade to their quotes. Database column: id_cliente.The product being quoted. Uses
DO_NOTHING on delete. Database column: id_producto.The acrylic sheet material to be used. Uses
DO_NOTHING on delete. Database column: id_material.Length of the piece in centimetres. Verbose name:
"Largo (cm)".Width of the piece in centimetres. Verbose name:
"Ancho (cm)".Thickness of the acrylic sheet in millimetres. Used to look up the matching
TabuladorCostos entry. Verbose name: "Espesor (mm)".Profit margin percentage applied on top of material cost. Defaults to
40. Verbose name: "Utilidad (%)".Estimated laser-cutting time in minutes. Multiplied by
ConfiguracionPrecios.tarifa_laser_minuto to compute laser cost.Final quoted price. This field is auto-calculated — do not set it manually. It is written by
save() via calcular_monto().Date the quote was created or issued.
Methods
calcular_monto()
Returns the computed quote total as a Decimal. Implements the full pricing formula (see Pricing Engine):
- If
id_producto.precio_fijois set, returns that value immediately (no further calculation). - Otherwise, computes area → looks up
TabuladorCostos→ applies profit margin → adds laser cost, then rounds to two decimal places via.quantize(Decimal('0.01')).
save(*args, **kwargs)
Overrides the default Django save() to call calcular_monto() and write the result into monto_total before persisting the record.
Materiales
Represents a sheet of acrylic stock. Tracks physical dimensions and inventory levels. Referenced by both quotes and sale line items. Database table:materiales
Primary key. Auto-incremented integer.
Human-readable description of the material (e.g.,
"Acrílico transparente 3mm"). Maximum 100 characters.Sheet length in centimetres.
Sheet width in centimetres.
Current quantity of sheets in stock. Decremented automatically when a POS sale is confirmed.
Minimum stock threshold. When
stock_actual <= stock_minimo, the system raises a low-stock alert in the POS flow.The
eliminar_material view guards against deleting a material that is still referenced by active Cotizaciones or DetalleVenta records. A deletion attempt will display an error message instead of removing the row.Productos
Represents a product template (e.g., a keychain, a sign, a frame). Products carry a default profit margin and an optional fixed price that short-circuits the pricing formula entirely. Database table:productos
Primary key. Auto-incremented integer.
Product name displayed in the UI (e.g.,
"Llavero"). Maximum 100 characters.Short description or variant detail (e.g.,
"Rectangular 5x10"). Maximum 100 characters.When populated, this value is returned directly by the pricing engine, bypassing all area/material/laser calculations. Verbose name:
"Precio Fijo (Opcional)".Per-product default profit margin percentage. Defaults to
40. Can be overridden per-quote via Cotizaciones.porcentaje_utilidad.Relative file path under
MEDIA_ROOT where the product photo is stored (e.g., productos/abc123.jpg). Saved and deleted via Django’s default_storage backend.TabuladorCostos
A lookup table that maps acrylic thickness values to a cost factor used in the area-based pricing formula. Each row represents one thickness configuration. Database table:tabulador_costos
Primary key. Auto-incremented integer.
Thickness in millimetres (e.g.,
3, 5, 8). The pricing engine queries this field with an exact match against Cotizaciones.espesor_mm.Cost factor in pesos per square metre (m²). Multiplied by the piece area to produce
costo_material. Four decimal places for precision.Ventas
Represents a confirmed sale. Supports two flows:- Legacy flow — linked 1-to-1 with a
Cotizacionesrecord viaid_cotizacion. - POS flow — linked directly to a
Clientesrecord viaid_cliente, with one or moreDetalleVentaline items.
ventas
Primary key. Auto-incremented integer.
Links to the originating quote in the legacy single-product flow. Uses
DO_NOTHING on delete. Database column: id_cotizacion.Direct client link used in the POS cart flow (not via a quote). Uses
SET_NULL on delete so that deleting a client does not erase the sale record. Database column: id_cliente_directo.Amount already paid or deposited by the customer. Defaults to
0.00. Verbose name: "Anticipo/Abono".Current status of the sale. Defaults to
"pendiente". Valid choices:| Value | Display |
|---|---|
pendiente | Pendiente |
en_produccion | En producción |
pagada | Pagada |
entregada | Entregada |
Promised delivery date. Set manually by staff via the status-update form.
Date the sale was created. Set automatically via
auto_now_add=True.Properties
saldo_restante
A computed property (not stored in the database) that returns the outstanding balance owed by the customer:
ConfiguracionPrecios
A singleton model — only one row ever exists (primary key1). Stores system-wide pricing parameters configurable by administrators.
Database table: configuracion_precios
Laser cutting rate charged per minute, in pesos. Defaults to
15.00. Verbose name: "Tarifa láser por minuto ($)".Timestamp of the last update. Managed automatically via
auto_now=True — updated on every save().Class Methods
get_config()
Returns the singleton configuration object, creating it with default values if it does not yet exist:
DetalleVenta
Represents a single line item in a POS-flow sale. MultipleDetalleVenta records belong to one Ventas record via the detalles reverse relation.
Database table: detalle_venta
Primary key. Auto-incremented integer.
The parent sale record. Uses
CASCADE on delete — removing a sale also removes all its line items. related_name='detalles' enables venta.detalles.all().The product on this line. Uses
CASCADE on delete.The material used for this line item. Uses
CASCADE on delete.Number of units ordered for this line item. Defaults to
1. Each unit decrements Materiales.stock_actual by 1 when the sale is confirmed.Length of the piece in centimetres, captured at the time of sale.
Width of the piece in centimetres, captured at the time of sale.
Thickness in millimetres, stored as a decimal on the line item (contrast with
Cotizaciones.espesor_mm which is an IntegerField).Laser-cutting minutes for this line item. Defaults to
0.Pre-calculated price for this line item. Computed in the browser via the pricing engine and submitted with the cart payload. Summed by
Ventas.saldo_restante in the POS flow.Relationships Diagram
The two sale flows connect the models differently, so it helps to think of them separately. Legacy quotation flow: AClientes record is linked to a Cotizaciones record, which in turn references one Productos entry and one Materiales entry. When the quote is confirmed as a sale, a Ventas record is created with id_cotizacion populated. The total comes directly from Cotizaciones.monto_total.
POS cart flow: A Clientes record is linked directly to a Ventas record via id_cliente (stored as id_cliente_directo). One or more DetalleVenta rows are attached to that sale via the detalles reverse relation, each carrying its own Productos and Materiales foreign keys. The sale total is the sum of all DetalleVenta.subtotal values.
Shared lookup tables: Both flows rely on TabuladorCostos (consulted at pricing time by espesor_mm) and ConfiguracionPrecios (the singleton that provides the laser rate). Neither of these tables holds foreign keys back into the sale chain — they are pure reference data consumed by the pricing engine.