Skip to main content

Overview

The Sales API manages sale transactions with automatic stock updates, IVA (tax) calculations, and support for both quick sales and registered client sales.

Venta Model (Sale)

id
integer
Unique sale identifier (auto-generated)
usuario
integer
Foreign key to admin user (owner)
cliente
string
Quick sale customer name (optional, max 100 characters)
cliente_fk
integer
Foreign key to registered Cliente (optional, takes precedence over cliente)
forma_pago
string
Payment method: Efectivo or Transferencia (default: Efectivo)
banco
string
Bank name (required if forma_pago='Transferencia', max 50 characters)
referencia
string
Transaction reference number (optional, max 100 characters)
fecha_venta
datetime
Sale timestamp (default: current time)
vendedor
integer
Foreign key to User who created the sale
total_venta
decimal
Total amount including IVA (12 digits, 2 decimals, auto-calculated)

DetalleVenta Model (Sale Detail)

id
integer
Detail line identifier
venta
integer
Foreign key to parent Venta
producto
integer
Foreign key to Producto (PROTECT constraint - cannot delete products in sales)
cantidad
integer
Quantity sold (positive integer, default: 1)
precio_unitario
decimal
Base price before IVA (10 digits, 2 decimals)
monto_iva
decimal
IVA amount per unit (auto-calculated: 19% of precio_unitario)
precio_unitario_final
decimal
Final unit price with IVA (auto-calculated: precio_unitario + monto_iva)
subtotal
decimal
Line total (auto-calculated: cantidad × precio_unitario_final)
costo_compra
decimal
Product cost at time of sale (copied from producto.precio_compra)

IngresoExtra Model (Extra Income)

id
integer
Extra income identifier
usuario
integer
Foreign key to User
tipo
string
Income type: domicilio, servicio, mano_obra, or otro
descripcion
string
Description (max 200 characters, optional)
monto
decimal
Amount (10 digits, 2 decimals)
fecha
datetime
Income timestamp (default: current time)

List Sales

curl -X GET http://localhost:8000/ventas/ \
  -H "Cookie: sessionid=<your-session>"

Response

Returns rendered HTML with list of sales for the authenticated user.

Create Sale

Requires authentication. Both admin and vendedor can create sales.
curl -X POST http://localhost:8000/ventas/nueva/ \
  -H "Cookie: sessionid=<session>; csrftoken=<token>" \
  -H "X-CSRFToken: <token>" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "cliente=Juan Perez" \
  -d "forma_pago=Efectivo"

Request Parameters

cliente
string
Customer name for quick sale (optional if cliente_fk provided)
cliente_fk
integer
Registered client ID (optional, takes precedence)
forma_pago
string
required
Payment method: Efectivo or Transferencia
banco
string
Bank name (required if forma_pago=‘Transferencia’)
referencia
string
Transaction reference

Adding Products to Sale

Products are typically added via the frontend interface or separate AJAX calls. The sale detail creation:
  1. Decrements product stock automatically
  2. Calculates IVA (19%)
  3. Calculates subtotals
  4. Updates total_venta on parent Venta

Response

Success: Redirects to sales list with flash message

Update Sale

curl -X POST http://localhost:8000/ventas/editar/<venta_id>/ \
  -H "Cookie: sessionid=<session>; csrftoken=<token>" \
  -H "X-CSRFToken: <token>" \
  -d "cliente=Juan Perez (Updated)" \
  -d "forma_pago=Transferencia" \
  -d "banco=Banco de Bogota" \
  -d "referencia=REF123456"

URL Parameters

venta_id
integer
required
Sale ID to update

Delete Sale

Deleting a sale restores product stock for all detail lines.
curl -X POST http://localhost:8000/ventas/eliminar/<venta_id>/ \
  -H "Cookie: sessionid=<session>; csrftoken=<token>" \
  -H "X-CSRFToken: <token>"

URL Parameters

venta_id
integer
required
Sale ID to delete

Response

Success: Stock restored, sale deleted, redirects to sales list

AJAX/API Endpoints

Search Client

curl -X POST http://localhost:8000/ventas/api/buscar-cliente/ \
  -H "Cookie: sessionid=<session>; csrftoken=<token>" \
  -H "Content-Type: application/json" \
  -H "X-CSRFToken: <token>" \
  -d '{"nombre": "Juan"}'
nombre
string
required
Client name to search (partial match)

Response

{
  "success": true,
  "clientes": [
    {
      "id": 1,
      "nombre": "Juan Perez",
      "telefono": "3001234567",
      "documento": "123456789"
    }
  ]
}

Search Product by Barcode

curl -X POST http://localhost:8000/ventas/api/buscar-producto/ \
  -H "Cookie: sessionid=<session>; csrftoken=<token>" \
  -H "Content-Type: application/json" \
  -H "X-CSRFToken: <token>" \
  -d '{"codigo_barras": "1234567890"}'
codigo_barras
string
required
Product barcode to search

Response

{
  "success": true,
  "producto": {
    "id": 5,
    "nombre": "Laptop Dell XPS 15",
    "precio": "1500.00",
    "stock": 10,
    "codigo_barras": "1234567890"
  }
}
Product Not Found:
{
  "success": false,
  "error": "Producto no encontrado"
}

Get Sale Detail (JSON)

curl -X GET http://localhost:8000/ventas/api/datos-json/<venta_id>/ \
  -H "Cookie: sessionid=<session>"
venta_id
integer
required
Sale ID

Response

{
  "id": 15,
  "cliente": "Juan Perez",
  "forma_pago": "Efectivo",
  "total_venta": "3570.00",
  "fecha_venta": "2024-03-15T10:30:00-05:00",
  "detalles": [
    {
      "producto": {
        "id": 5,
        "nombre": "Laptop Dell XPS 15"
      },
      "cantidad": 2,
      "precio_unitario": "1500.00",
      "monto_iva": "285.00",
      "precio_unitario_final": "1785.00",
      "subtotal": "3570.00"
    }
  ]
}

Search Sales

curl -X GET "http://localhost:8000/ventas/api/buscar-ventas/?q=Juan" \
  -H "Cookie: sessionid=<session>"
q
string
required
Search query (searches cliente name)

Get Products by Sale

curl -X GET http://localhost:8000/ventas/<venta_id>/productos/ \
  -H "Cookie: sessionid=<session>"
venta_id
integer
required
Sale ID

Response

Returns JSON array of products in the sale.

Extra Income

Register Extra Income

curl -X POST http://localhost:8000/ventas/api/ingreso-extra/ \
  -H "Cookie: sessionid=<session>; csrftoken=<token>" \
  -H "Content-Type: application/json" \
  -H "X-CSRFToken: <token>" \
  -d '{
    "tipo": "domicilio",
    "descripcion": "Delivery fee",
    "monto": "5000.00"
  }'
tipo
string
required
Income type: domicilio, servicio, mano_obra, or otro
descripcion
string
Description (max 200 characters)
monto
decimal
required
Amount (e.g., “5000.00”)

Response

{
  "success": true,
  "ingreso": {
    "id": 10,
    "tipo": "domicilio",
    "descripcion": "Delivery fee",
    "monto": "5000.00",
    "fecha": "2024-03-15T14:20:00-05:00"
  }
}

Get Extra Income Detail

curl -X GET http://localhost:8000/ventas/api/ingreso-extra/<ingreso_id>/ \
  -H "Cookie: sessionid=<session>"

Delete Extra Income

curl -X POST http://localhost:8000/ventas/ingreso-extra/eliminar/<ingreso_id>/ \
  -H "Cookie: sessionid=<session>; csrftoken=<token>" \
  -H "X-CSRFToken: <token>"

Generate Sale Invoice (PDF)

curl -X GET http://localhost:8000/ventas/factura/<venta_id>/ \
  -H "Cookie: sessionid=<session>" \
  --output factura.pdf
venta_id
integer
required
Sale ID

Response

Content-Type: application/pdf Downloads PDF invoice with sale details.

Business Logic

Automatic Stock Management

When DetalleVenta is saved:
# Stock decremented
producto.stock -= cantidad
producto.save()
When DetalleVenta is deleted:
# Stock restored
producto.stock += cantidad
producto.save()
When DetalleVenta quantity updated:
# Adjust stock by difference
diferencia = new_cantidad - old_cantidad
producto.stock -= diferencia
producto.save()

IVA Calculation (19%)

Constant defined: IVA_RATE = Decimal('0.19') On save:
base = Decimal(self.precio_unitario)
self.monto_iva = (base * IVA_RATE).quantize(Decimal('0.01'))
self.precio_unitario_final = (base + self.monto_iva).quantize(Decimal('0.01'))
self.subtotal = self.cantidad * self.precio_unitario_final

Total Venta Update

After each detail save/delete:
venta.actualizar_total()  # Recalculates sum of all detail subtotals

Cost Tracking

On first save, costo_compra copied from product:
if not self.pk or self.costo_compra == 0:
    self.costo_compra = self.producto.precio_compra
This preserves historical cost for profit analysis.

Example Workflow

# 1. Search for product by barcode
curl -X POST http://localhost:8000/ventas/api/buscar-producto/ \
  -H "Content-Type: application/json" \
  -H "X-CSRFToken: <token>" \
  -d '{"codigo_barras": "APP-IPH14-001"}'

# Response: {"success": true, "producto": {"id": 5, "precio": "999.00", "stock": 8}}

# 2. Create sale (typically done via web form)
curl -X POST http://localhost:8000/ventas/nueva/ \
  -d "cliente=Maria Lopez" \
  -d "forma_pago=Transferencia" \
  -d "banco=Bancolombia" \
  -d "referencia=TRX789"

# 3. Add product to sale (via detail creation)
# This happens in the UI - detail is created with:
# - producto_id=5
# - cantidad=2
# - precio_unitario=999.00
# Auto-calculates: monto_iva=189.81, precio_unitario_final=1188.81, subtotal=2377.62
# Stock updated: 8 - 2 = 6

# 4. Get sale detail as JSON
curl http://localhost:8000/ventas/api/datos-json/15/

# 5. Download invoice
curl http://localhost:8000/ventas/factura/15/ --output invoice.pdf
  • Products API - Stock management
  • Clients API - Registered customer sales
  • See source: applications/ventas/views.py and applications/ventas/models.py

Build docs developers (and LLMs) love