Skip to main content

Overview

Property management in Core Projects involves a hierarchical structure: ProjectsTorresFloorsUnits (Apartments/Locals). This guide covers the complete workflow for building your property inventory.

Property Hierarchy

Proyecto (Project)
└── Torre (Tower/Building)
    └── Piso (Floor)
        ├── Apartamentos (Apartments)
        ├── Locales (Commercial Units)
        └── Parqueaderos (Parking)

Managing Torres (Towers)

Towers are the primary building structures within a project.

Creating Towers

1

Access Tower Creation

Navigate to /admin/torres/create or from a project detail page via the wizard flow with ?flow_proyecto_id={id} parameter.
2

Select Project Context

Choose the project for this tower:
id_proyecto: required|exists:proyectos,id_proyecto
3

Configure Tower Details

Enter tower specifications:Required Fields:
nombre_torre:    string(max:100)  // e.g., "Torre A", "Edificio Norte"
id_proyecto:     integer
id_estado:       integer           // Tower state (Activo, En construcción)
Optional Fields:
numero_pisos:    integer           // Number of floors
descripcion:     text
4

Save Tower

Submit the form to create the tower. The system redirects to /admin/torres/{id} showing the tower detail view.

Batch Tower Creation

The wizard flow supports creating multiple towers simultaneously:
// Frontend: Create.vue allows adding multiple tower forms
torres: [
  { nombre_torre: 'Torre A', numero_pisos: 15, id_estado: 1 },
  { nombre_torre: 'Torre B', numero_pisos: 15, id_estado: 1 },
  { nombre_torre: 'Torre C', numero_pisos: 12, id_estado: 1 }
]
All towers are created in a single transaction and associated with the project.

Tower Routes

GET    /admin/torres              # List all towers
GET    /admin/torres/create       # Create new tower
POST   /admin/torres              # Store tower
GET    /admin/torres/{id}         # View tower details
GET    /admin/torres/{id}/edit    # Edit tower
PUT    /admin/torres/{id}         # Update tower
DELETE /admin/torres/{id}         # Delete tower

Managing Floors (Pisos)

Floors define the vertical structure within each tower.

Creating Floors

1

Navigate to Floor Creation

Go to /pisos-torre/create from the project wizard or directly.
2

Select Project and Tower

Use cascading selects:
  1. Choose Proyecto
  2. Select Torre (filtered by project via /torres-por-proyecto/{id})
3

Define Floor Properties

Enter floor details:
numero_piso:     string(max:10)   // e.g., "1", "PB", "Mezanine"
id_torre:        integer
cantidad_apto:   integer           // Units on this floor
descripcion:     text
4

Save Floor

Submit to create the floor record. Repeat for each floor in the tower.

Floor Routes

GET  /pisos-torre              # List floors
POST /pisos-torre              # Create floor
GET  /pisos-torre/{id}/edit    # Edit floor
Helper endpoint for cascading selects:
GET /torres-por-proyecto/{id_proyecto}  # Returns towers for project

Managing Apartment Types

Apartment types serve as blueprints defining characteristics and base pricing for units.

Creating Apartment Types

1

Access Type Creation

Navigate to /tipos-apartamento/create from the project wizard (Step 4).
2

Select Project

Associate the type with a project:
id_proyecto: required|exists:proyectos,id_proyecto
3

Define Type Characteristics

Enter unit specifications:Physical Attributes:
nombre:                    string(max:100)  // e.g., "Tipo A - 3 Hab"
area_construida:           numeric          // Total area (m²)
area_privada:              numeric          // Private area (m²)
cantidad_habitaciones:     integer          // Bedrooms
cantidad_banos:            integer          // Bathrooms
Pricing:
valor_m2:                  numeric          // Price per m²
The system auto-calculates:
valor_estimado = ceil(area_construida * valor_m2)
4

Upload Type Image (Optional)

Attach a floor plan or unit image:
imagen: 'nullable|image|mimes:jpg,jpeg,png,webp|max:2048'
Stored at: storage/tipos-apartamento/{filename}
5

Save Type

Submit the form. The type is now available for assigning to apartments.

Batch Type Creation

Create multiple types at once:
// Controller: TipoApartamentoWebController::store
if ($request->has('tipos') && is_array($request->input('tipos'))) {
    // Loop through array and create all types in transaction
}
Example payload:
{
  "id_proyecto": 5,
  "tipos": [
    {
      "nombre": "Tipo A - 2 Habitaciones",
      "area_construida": 65.5,
      "cantidad_habitaciones": 2,
      "cantidad_banos": 2,
      "valor_m2": 4500000
    },
    {
      "nombre": "Tipo B - 3 Habitaciones",
      "area_construida": 85.0,
      "cantidad_habitaciones": 3,
      "cantidad_banos": 2,
      "valor_m2": 4800000
    }
  ]
}

Type Routes

GET    /tipos-apartamento              # List types
GET    /tipos-apartamento/create       # Create type
POST   /tipos-apartamento              # Store type(s)
GET    /tipos-apartamento/{id}         # View type details
GET    /tipos-apartamento/{id}/edit    # Edit type
PUT    /tipos-apartamento/{id}         # Update type
DELETE /tipos-apartamento/{id}         # Delete type (if no apartments)

Managing Apartments

Apartments are individual residential units linked to types, towers, and floors.

Creating Apartments

1

Navigate to Apartment Creation

Go to /admin/apartamentos/create (Step 6 in project wizard).
2

Select Project Context

Choose project, which enables cascading selects:
  1. Proyecto → loads torres
  2. Torre → loads pisos via /api/pisos-por-torre/{id_torre}
  3. Piso → floor for this unit
3

Select Apartment Type

Choose the apartment type (blueprint) created earlier. This determines:
  • Base pricing
  • Area specifications
  • Room configuration
4

Enter Unit Details

Define unit-specific information:
numero:                 string(max:10)    // Unit number (e.g., "101", "1501")
id_torre:               integer
id_piso_torre:          integer
id_tipo_apartamento:    integer
id_estado_inmueble:     integer           // Default: "Disponible"
Pricing Fields:
valor_total:            numeric           // Copied from tipo.valor_estimado
valor_final:            numeric           // Adjusted by PriceEngine
5

Save Apartment

Submit to create the unit. The apartment is now inventory ready for sales.

Apartment Routes

GET  /apartamentos              # List apartments
GET  /admin/apartamentos/create # Create apartment
POST /apartamentos              # Store apartment
GET  /apartamentos/{id}         # View apartment
GET  /apartamentos/{id}/edit    # Edit apartment
Helper endpoints:
GET /api/pisos-por-torre/{id_torre}              # Floors for tower
GET /torres-por-proyecto/{id_proyecto}           # Towers for project

Managing Commercial Locals

Commercial units follow a similar structure to apartments but without types.

Creating Locals

1

Access Local Creation

Navigate to /locales/create.
2

Select Location

Use cascading selects to choose:
  • Proyecto
  • Torre
  • Piso (via /api/pisos-por-torre/{id_torre})
3

Enter Local Details

Define commercial unit properties:
numero:              string(max:10)
area_total:          numeric            // Total area
valor_total:         numeric            // Base price
id_estado_inmueble:  integer
descripcion:         text
4

Save Local

Submit to add the commercial unit to inventory.

Local Routes

GET  /locales              # List locals
GET  /locales/create       # Create local
POST /locales              # Store local

Managing Parking (Parqueaderos)

Parking spaces can be:
  1. Linked to apartments (id_apartamento set) – Included with unit
  2. Additional/standalone (id_apartamento NULL) – Sold separately

Creating Parking Spaces

1

Navigate to Parking Creation

Go to /parqueaderos/create.
2

Select Project and Tower

Choose the project and optionally the tower for this parking area.
3

Define Parking Details

Enter parking specifications:
numero:          string(max:10)      // Space number (e.g., "S1-05")
tipo:            enum                // 'Vehículo' or 'Moto'
id_proyecto:     integer
id_torre:        integer (optional)
id_apartamento:  integer (optional)  // NULL = additional parking
precio:          numeric             // Price if sold separately
4

Associate with Apartment (Optional)

If this parking is included with a unit:
  • Select apartment via /api/apartamentos-por-torre/{id_torre}
  • Set id_apartamento
  • Parking price is added to unit total
If standalone:
  • Leave id_apartamento as NULL
  • Available for separate purchase during sales
5

Save Parking

Submit to add parking space to inventory.

Parking Routes

GET  /parqueaderos              # List parking
GET  /parqueaderos/create       # Create parking
POST /parqueaderos              # Store parking

Managing Social Areas

Common amenity areas for projects.

Creating Social Areas

1

Access Social Area Creation

Navigate to /zonas-sociales/create.
2

Enter Area Details

Define the social area:
nombre:          string(max:100)    // e.g., "Piscina", "Gimnasio"
descripcion:     text
id_proyecto:     integer
area:            numeric             // Area size (optional)
3

Save Social Area

Submit to add the amenity to the project.

Social Area Routes

GET  /zonas-sociales              # List social areas
GET  /zonas-sociales/create       # Create area
POST /zonas-sociales              # Store area

Property States (Estados Inmueble)

All properties (apartments, locals, parking) have a state:
StateDescriptionUsed For
DisponibleAvailable for saleInitial state
SeparadoReserved with separation paymentTemporary hold
VendidoSold with payment plan activeCompleted sale
BloqueadoAdministratively blockedHold for issues
CongeladoTemporarily frozenFuture release
States are managed at /estados-inmueble and transition automatically during sales:
// VentaWebController logic
if ($tipo_operacion === 'venta') {
    $inmueble->id_estado_inmueble = EstadoInmueble::where('nombre', 'Vendido')->first()->id;
} elseif ($tipo_operacion === 'separacion') {
    $inmueble->id_estado_inmueble = EstadoInmueble::where('nombre', 'Separado')->first()->id;
}

Dynamic Pricing Integration

When apartments are created or sold, the PriceEngine service adjusts pricing:
app\Services\PriceEngine::recalcularProyecto($proyecto);
This applies configured pricing policies to update valor_final for all available units based on:
  • Number of units sold
  • Escalation thresholds
  • Time-based factors

Validation & Business Rules

Required Relationships

Properties cannot be deleted if they have associated sales:
if ($apartamento->ventas()->exists()) {
    return back()->withErrors(['delete' => 'Cannot delete apartment with sales']);
}

Cascading Deletes

Deleting a tower requires:
  1. No apartments in tower
  2. No locals in tower
  3. No floors in tower

Unique Constraints

Unit numbers must be unique within their scope:
Rule::unique('apartamentos')->where('id_torre', $id_torre)

Bulk Operations

For large projects, use batch creation:
  1. Tipos – Create all apartment types first
  2. Torres – Batch create all towers
  3. Pisos – Script to generate floors (e.g., 1-15 for each tower)
  4. Apartamentos – Generate units based on types and floors

Next Steps

Sales Module Overview

Learn how configured properties are used in the sales workflow.

Technical Reference

  • Controllers:
    • app/Http/Controllers/Admin/AdminTorreController.php
    • app/Http/Controllers/Admin/ApartamentoWebController.php
    • app/Http/Controllers/Admin/TipoApartamentoWebController.php
    • app/Http/Controllers/Admin/LocalWebController.php
    • app/Http/Controllers/Admin/ParqueaderoWebController.php
  • Views: resources/js/Pages/Admin/Torres/, Apartamento/, etc.
  • Routes: routes/web.php:98-217

Build docs developers (and LLMs) love