Skip to main content

Overview

The Sales API manages both sales (ventas) and separations (separaciones/reservations). A separation is a temporary reservation that can be converted to a full sale. Both operations share the same ventas table but have different business logic.

Model Structure

Venta Model

Table: ventas
Primary Key: id_venta (auto-increment)

Core Attributes

id_venta
integer
Primary key, auto-increment
tipo_operacion
enum
required
Operation type: 'venta' or 'separacion'
estado_operacion
string
Operation status: 'vigente', 'vencida', 'convertida', 'cancelada'
id_empleado
integer
required
Sales agent/employee ID. Foreign key to empleados table.
documento_cliente
string
required
Client document number. Foreign key to clientes table.
fecha_venta
date
required
Sale or separation date
id_proyecto
integer
required
Project ID. Foreign key to proyectos table.

Property Information

id_apartamento
integer
Apartment ID if selling apartment. Foreign key to apartamentos table.
id_local
integer
Commercial space ID if selling local. Foreign key to locales table.
id_parqueadero
integer
Optional additional parking space ID. Foreign key to parqueaderos table.
id_estado_inmueble
integer
Property status ID. Foreign key to estados_inmueble table.

Financial Attributes

valor_base
decimal(15,2)
Base value of the property (excluding parking)
iva
decimal(15,2)
VAT/Tax amount (if applicable)
valor_total
decimal(15,2)
required
Total sale value (base + parking + taxes)
id_forma_pago
integer
required
Payment method ID. Foreign key to formas_pago table.

Sale-Specific Fields (tipo_operacion = ‘venta’)

cuota_inicial
decimal(15,2)
Down payment amount. Must meet project minimum percentage.
valor_restante
decimal(15,2)
Remaining balance after down payment
plazo_cuota_inicial_meses
integer
Down payment term in months
frecuencia_cuota_inicial_meses
integer
Payment frequency in months (e.g., 1 = monthly, 2 = bimonthly)
fecha_vencimiento
date
Final payment due date

Separation-Specific Fields (tipo_operacion = ‘separacion’)

valor_separacion
decimal(15,2)
Separation/reservation fee. Must meet project minimum.
fecha_limite_separacion
date
Separation expiration date. Must be within project maximum days.
plazo_separacion_dias
integer
Separation period in days
descripcion
text
Additional notes or description

Relationships

empleado
BelongsTo
Sales agent who created the operation
cliente
BelongsTo
Client/buyer information
proyecto
BelongsTo
Project details
apartamento
BelongsTo
Apartment details (if applicable)
local
BelongsTo
Commercial space details (if applicable)
parqueadero
BelongsTo
Additional parking space (if purchased separately)
formaPago
BelongsTo
Payment method details
estadoInmueble
BelongsTo
Property status (Disponible, Separado, Vendido)
planAmortizacion
HasOne
Payment schedule for down payment
pagos
HasMany
Collection of payment records

List Sales & Separations

curl -X GET "https://api.coreprojects.com/ventas" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Query Parameters

tipo_operacion
string
Filter by type: venta or separacion
id_proyecto
integer
Filter by project ID
documento_cliente
string
Filter by client document
estado_operacion
string
Filter by status: vigente, vencida, convertida, cancelada

Response

[
  {
    "id_venta": 1,
    "tipo_operacion": "venta",
    "estado_operacion": "vigente",
    "id_empleado": 5,
    "documento_cliente": "1234567890",
    "fecha_venta": "2024-01-15",
    "id_proyecto": 1,
    "id_apartamento": 101,
    "id_local": null,
    "id_parqueadero": 15,
    "valor_base": 250000000,
    "valor_total": 270000000,
    "cuota_inicial": 67500000,
    "valor_restante": 202500000,
    "plazo_cuota_inicial_meses": 18,
    "frecuencia_cuota_inicial_meses": 1,
    "id_forma_pago": 1,
    "descripcion": "Venta apto 301 Torre A",
    "cliente": {
      "documento": "1234567890",
      "nombre": "Juan Pérez García"
    },
    "apartamento": {
      "id_apartamento": 101,
      "numero": "301",
      "torre": {
        "nombre_torre": "Torre A"
      }
    },
    "parqueadero": {
      "id_parqueadero": 15,
      "numero": "P-15",
      "tipo": "Cubierto",
      "precio": 20000000
    }
  }
]

Get Sale by ID

curl -X GET "https://api.coreprojects.com/ventas/{id}" \
  -H "Authorization: Bearer {token}"

Path Parameters

id
integer
required
Sale ID (id_venta)

Create Sale

curl -X POST "https://api.coreprojects.com/ventas" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "tipo_operacion": "venta",
    "id_empleado": 5,
    "documento_cliente": "1234567890",
    "fecha_venta": "2024-01-15",
    "id_proyecto": 1,
    "inmueble_tipo": "apartamento",
    "inmueble_id": 101,
    "id_forma_pago": 1,
    "cuota_inicial": 67500000,
    "plazo_cuota_inicial_meses": 18,
    "frecuencia_cuota_inicial_meses": 1,
    "id_parqueadero": 15,
    "descripcion": "Venta apartamento 301"
  }'

Request Body

tipo_operacion
enum
required
Operation type: 'venta' or 'separacion'
id_empleado
integer
required
Sales agent ID
documento_cliente
string
required
Client document number
fecha_venta
date
required
Sale/separation date (format: YYYY-MM-DD)
id_proyecto
integer
required
Project ID
inmueble_tipo
enum
required
Property type: 'apartamento' or 'local'
inmueble_id
integer
required
Property ID (apartamento or local ID based on tipo)
id_forma_pago
integer
required
Payment method ID
id_parqueadero
integer
Optional additional parking space ID (apartments only)
cuota_inicial
decimal
Down payment amount (required for sales)
plazo_cuota_inicial_meses
integer
Down payment term in months (required for sales)
frecuencia_cuota_inicial_meses
integer
Payment frequency in months (default: 1)
valor_separacion
decimal
Separation fee (required for separations)
fecha_limite_separacion
date
Separation expiration date (required for separations)
descripcion
string
Additional notes (max 300 characters)

Business Logic

Sale Validation (tipo_operacion = ‘venta’)

  1. Down Payment Minimum: cuota_inicial must be ≥ project’s porcentaje_cuota_inicial_min of valor_total
  2. Term Limits: plazo_cuota_inicial_meses must be ≤ project’s plazo_max_cuota_inicial_meses
  3. Frequency Validation: frecuencia_cuota_inicial_meses must be ≤ plazo_cuota_inicial_meses
  4. Property Status: Property must have status 'Disponible'
  5. Parking Validation:
    • Only apartments can have additional parking
    • Parking must be “additional” (not assigned to an apartment)
    • Parking must belong to same project
    • Parking must not be reserved by another sale

Separation Validation (tipo_operacion = ‘separacion’)

  1. Minimum Fee: valor_separacion must be ≥ project’s valor_min_separacion
  2. Maximum Period: fecha_limite_separacion must be ≤ project’s plazo_max_separacion_dias from today
  3. Property Status: Property must have status 'Disponible'

Automatic Operations

  1. Value Calculation: Backend calculates valor_total = property value + parking price
  2. Remaining Balance: For sales, valor_restante = valor_total - cuota_inicial
  3. Property Status Update: Changes to 'Vendido' (sale) or 'Separado' (separation)
  4. Parking Assignment: If parking included, assigns to apartment in parqueaderos table
  5. Amortization Plan: For sales, auto-generates payment schedule
  6. Price Recalculation: Triggers project pricing engine (dynamic pricing based on sales count)

Response

{
  "id_venta": 1,
  "tipo_operacion": "venta",
  "estado_operacion": "vigente",
  "valor_total": 270000000,
  "cuota_inicial": 67500000,
  "valor_restante": 202500000,
  "mensaje": "Operación registrada exitosamente"
}

Error Responses

422
validation_error
Validation errors:
  • Down payment below minimum
  • Term exceeds maximum
  • Property not available
  • Parking already reserved
  • Separation fee below minimum
409
conflict
Business logic conflicts:
  • Property already has active operation
  • Parking assigned to another apartment

Update Sale

curl -X PUT "https://api.coreprojects.com/ventas/{id}" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "cuota_inicial": 75000000,
    "plazo_cuota_inicial_meses": 24,
    "descripcion": "Plazo extendido"
  }'

Path Parameters

id
integer
required
Sale ID to update
Updating a sale regenerates the amortization plan. Previous payment plan is deleted.

Delete Sale

curl -X DELETE "https://api.coreprojects.com/ventas/{id}" \
  -H "Authorization: Bearer {token}"
Deleting a sale:
  • Restores property status to “Disponible”
  • Releases any associated parking
  • Deletes payment plan and all related cuotas
  • Does NOT delete payment records (for audit trail)
  • Triggers project price recalculation

Convert Separation to Sale

curl -X POST "https://api.coreprojects.com/ventas/separaciones/{id}/convertir-venta" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "id_forma_pago": 1,
    "cuota_inicial": 75000000,
    "plazo_cuota_inicial_meses": 18,
    "frecuencia_cuota_inicial_meses": 1,
    "descripcion": "Conversión de separación"
  }'

Path Parameters

id
integer
required
Separation ID to convert

Request Body

id_forma_pago
integer
required
Payment method for the sale
cuota_inicial
decimal
required
Down payment amount (must meet project minimum)
plazo_cuota_inicial_meses
integer
required
Payment term in months
frecuencia_cuota_inicial_meses
integer
required
Payment frequency (1 = monthly, 2 = bimonthly, etc.)
id_parqueadero
integer
Optional: Add or change parking space
descripcion
string
Updated description

Business Logic

  1. Validation:
    • Only separations with estado_operacion = 'vigente' can be converted
    • Down payment must meet project minimum percentage
    • Term must be within project maximum
  2. State Changes:
    • tipo_operacion: 'separacion''venta'
    • estado_operacion: 'vigente''convertida'
    • Property status: 'Separado''Vendido'
  3. Financial Changes:
    • valor_separacionnull
    • fecha_limite_separacionnull
    • Sets cuota_inicial, valor_restante, payment terms
  4. Auto-Generated:
    • Payment schedule (amortization plan)
    • Updates project pricing

Response

{
  "id_venta": 1,
  "tipo_operacion": "venta",
  "estado_operacion": "convertida",
  "cuota_inicial": 75000000,
  "valor_restante": 195000000,
  "mensaje": "La separación fue convertida a venta correctamente"
}

Cancel Separation

curl -X POST "https://api.coreprojects.com/ventas/separaciones/{id}/cancelar" \
  -H "Authorization: Bearer {token}"

Path Parameters

id
integer
required
Separation ID to cancel
Canceling a separation:
  • Deletes the separation record
  • Restores property status to “Disponible”
  • Releases any parking assignment
  • Triggers project price recalculation

Auto-Expire Separations (CRON)

curl -X GET "https://api.coreprojects.com/ventas/cron/vencer-separaciones" \
  -H "X-Cron-Secret: {secret}"
This endpoint should be called by a scheduled task (CRON job) to automatically expire separations past their fecha_limite_separacion.

Helper Methods

Check if Sale

$venta->esVenta(); // Returns true if tipo_operacion === 'venta'

Check if Separation

$venta->esSeparacion(); // Returns true if tipo_operacion === 'separacion'

Check if Expired

$venta->estaVencida(); // Returns true if fecha_vencimiento is past

Get Property (Polymorphic)

$inmueble = $venta->inmueble(); // Returns apartamento or local relation

State Transitions

Separation Lifecycle

  • vigente: Active separation within expiration date
  • convertida: Successfully converted to sale
  • vencida: Expired (past fecha_limite_separacion)
  • cancelada: Manually canceled

Sale Lifecycle

  • vigente: Active sale with pending payments
  • completed: All payments received (tracked externally)
  • cancelada: Sale canceled (rare)

Build docs developers (and LLMs) love