Skip to main content

Documentation 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.

Products in Acrylitec represent the distinct item types your shop offers — keychains, signs, trophies, custom-cut panels, and anything else that gets quoted or sold. Each Productos record drives two core workflows: the quoting form uses the product’s margin and optional fixed price to pre-fill the cost estimate, and the POS screen (/pedidos/nuevo/) lists all products so staff can add line items to a cart. Keeping your product catalogue complete and accurate is the first step to generating reliable quotes.

Product Fields

The following fields are defined on the Productos model:
FieldTypeDescription
nombreCharField (max 100)Product name shown in the catalogue and POS screen
detalleCharField (max 100)Short description or technical specification
precio_fijoDecimalField (optional)Fixed retail price in currency units; bypasses the dynamic formula when set
porcentaje_utilidadIntegerField (default 40)Profit margin percentage applied over material cost in the dynamic formula
fotoCharField (max 255, optional)Relative path to the product image stored under MEDIA_ROOT/

Pricing Logic

Acrylitec supports two mutually exclusive pricing modes for each product:

Fixed Price

When precio_fijo is set to any non-null value, that amount is always returned as the quote total. The area, thickness, and laser-time formula is bypassed entirely. Useful for standard catalogue items sold at a set retail price.

Dynamic Formula

When precio_fijo is blank, the system calculates cost from sheet area (cm²), a thickness factor from the TabuladorCostos table, the product’s porcentaje_utilidad, and laser minutes. See Pricing Configuration for the full formula.
The check happens at calculation time in _calcular_monto in views.py:
prod = Productos.objects.filter(pk=producto_id).first()
if prod and prod.precio_fijo:
    return { ..., 'monto_total': prod.precio_fijo }
Use precio_fijo for standard catalogue items with a set retail price. Leave it blank for custom-cut orders where the price depends on dimensions, thickness, and cutting time.

Creating a Product

1

Open the creation form

Navigate to /productos/nuevo/. The form is rendered by the crear_producto view.
2

Fill in product details

Enter the product name, an optional description, and choose a pricing mode:
  • Set a value in Precio fijo to use a fixed price, or
  • Leave it blank and enter a % de Utilidad (defaults to 40) to use the dynamic formula.
Both fields are visible simultaneously; if both are filled, precio_fijo takes priority.
3

Upload an optional photo

Choose an image file (JPG, PNG, or WEBP). On save, the view generates a UUID-based filename and stores the file via default_storage:
ext = os.path.splitext(foto.name)[1]
foto_path = default_storage.save(f"productos/{uuid.uuid4().hex}{ext}", foto)
The relative path (e.g., productos/a3f9...jpg) is saved to the foto field and served from MEDIA_ROOT/.
4

Submit

Click Crear producto. The view calls Productos.objects.create(...) and redirects to /productos/.

Editing a Product

Send a POST request to /productos/<pk>/editar/. The editar_producto view loads the existing record, applies the submitted field values, and saves. If a new photo file is included in the request, the old file is deleted from storage before the new one is saved:
if 'foto' in request.FILES:
    if producto.foto:
        default_storage.delete(producto.foto)   # remove old file
    producto.foto = default_storage.save(
        f"productos/{uuid.uuid4().hex}{ext}", foto)
Navigate to the edit form via the ✏️ Editar button on any product card in /productos/.

Deleting a Product

Send a POST request to /productos/<pk>/eliminar/. The eliminar_producto view:
  1. Retrieves the product record.
  2. If a photo exists, deletes the file from storage with default_storage.delete(producto.foto).
  3. Calls producto.delete() to remove the database row.
  4. Redirects to /productos/.
Use the 🗑️ Eliminar button on the product card, which leads to a confirmation page (producto_confirm_delete.html) before the POST is sent.

Searching Products

The product list at GET /productos/ accepts an optional q parameter. The view filters by nombre or detalle using case-insensitive icontains lookups via Django Q objects:
productos = productos.filter(
    Q(nombre__icontains=query) |
    Q(detalle__icontains=query)
)
If no results match and a q value was supplied, the template shows a “No se encontraron resultados” message with a shortcut to add a new product.

Build docs developers (and LLMs) love