# Real Estate Units Controller

**File**: `/controllers/realestateunits.php`
**Purpose**: Comprehensive management system for real estate properties and their individual units
**Last Updated**: December 20, 2024
**Total Functions**: 14
**Lines of Code**: ~372

---

## 📋 Overview

The Real Estate Units Controller serves as the central management system for real estate properties and their individual units. It provides complete CRUD operations, dynamic form handling, and comprehensive search functionality. This controller handles:

- Real estate property creation and management
- Individual unit management within properties
- Dynamic form addition/removal of units
- Advanced search and filtering capabilities
- Integration with income and expense type creation
- AJAX-powered data tables
- Select2 dropdown integration
- Comprehensive reporting and display

### Primary Functions
- [x] Create and edit real estate properties
- [x] Manage individual property units
- [x] Dynamic unit addition/removal
- [x] Advanced search and filtering
- [x] AJAX data table management
- [x] Select2 dropdown integration
- [x] Automatic income/expense type creation
- [x] Comprehensive property reporting
- [x] Soft delete functionality
- [x] Audit trail maintenance

### Related Controllers
- [realestateaveragerevenue.php](realestateaveragerevenue.md) - Revenue analysis
- [realestatepayments.php](realestatepayments.md) - Payment tracking
- [incomeTypeController.php](#) - Income type management
- [expensesTypeController.php](#) - Expense type management

---

## 🗄️ Database Tables

### Primary Tables (Direct Operations)
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **realestates** | Main property records | id, realestatename, del, addtoday, adduserid, updatetoday, updateuserid, deltoday, deluserid, savaible, cavaible, incometypeid, expenstypeid |
| **realestatesunits** | Individual property units | id, realestateid, unitname, unitarea, del, addtoday, adduserid, updatetoday, updateuserid, deltoday, deluserid, cavaible |

### Integration Tables (Automatic Creation)
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **incometype** | Income categories | incomeTypeId, incomeTypeName, incomeTypeDetails |
| **expensestype** | Expense categories | expensestypeid, expensestypename, expensestypedetails |

### Reference Tables
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **supplier** | Supplier information | supplierid, suppliername, supplierphone, conditions |
| **client** | Client information | clientid, clientname, clientphone, conditions |
| **user** | System users | userid, employeename |

---

## 🔑 Key Functions

### 1. **Default Action** - Property Creation Form
**Location**: Lines 6-10
**Purpose**: Display the main property creation interface

**Process Flow**:
1. Display header template
2. Load property creation form (`realestateunitsview/add.html`)
3. Set realestateunits flag for template
4. Display footer template

---

### 2. **addappend** - Dynamic Form Component Addition
**Location**: Lines 11-18
**Purpose**: Dynamically add form components (units) to the property form

**Function Signature**:
```php
// Triggered when: do=addappend (POST)
$itr = filter_input(INPUT_POST, 'itr');
$dataitr = filter_input(INPUT_POST, 'dataitr');
$container = filter_input(INPUT_POST, 'container');
```

**Process Flow**:
1. Extract iteration parameters for dynamic form generation
2. Assign iterator values to template
3. Set realestateunits flag
4. Display specified container template (e.g., unit row)

---

### 3. **show** - Properties Listing Interface
**Location**: Lines 19-23
**Purpose**: Display the main properties listing and search interface

**Process Flow**:
1. Display header template
2. Load properties listing view (`realestateunitsview/show.html`)
3. Set realestateunits flag
4. Display footer template

---

### 4. **edit** - Property Edit Interface
**Location**: Lines 24-33
**Purpose**: Display property editing form with existing data

**Function Signature**:
```php
// Triggered when: do=edit (GET)
$id = filter_input(INPUT_GET, 'id');
```

**Process Flow**:
1. Load property data by ID
2. Load all related units for the property
3. Assign edit data and units to template
4. Display edit form (`realestateunitsview/edit.html`)

```php
$editdata = R::load('realestates', $id);
$realestatesunits = R::findAll('realestatesunits','realestateid = ? and del < 2',[$id]);
$smarty->assign('editdata', $editdata);
$smarty->assign('realestatesunits', $realestatesunits);
```

---

### 5. **savedata** - Property and Units Save Operation
**Location**: Lines 118-182
**Purpose**: Save or update property with multiple units in single transaction

**Function Signature**:
```php
function savedata() {
    $realestatename = filter_input(INPUT_POST, 'realestatename');
    $realestatesunitsitr = filter_input(INPUT_POST, 'realestatesunitsitr');
    $id = filter_input(INPUT_POST, 'id');
}
```

**Process Flow**:

1. **Property Creation/Update**:
```php
if (!$id) {
    // Create new property
    $realestates = R::dispense('realestates');
    $realestates->del = 0;
    $realestates->addtoday = $today;
    $realestates->adduserid = $userid;
    $realestates->savaible = 0;
    $realestates->cavaible = 0;
    $realestates->incometypeid = 0;
    $realestates->expenstypeid = 0;
} else {
    // Update existing property
    $realestates = R::load('realestates', $id);
    $realestates->del = 1; // Mark as updated
    $realestates->updatetoday = $today;
    $realestates->updateuserid = $userid;
    
    // Update related income and expense types
    R::exec("UPDATE `incometype` SET `incomeTypeName`='$realestatename', 
             `incomeTypeDetails`='$realestatename' WHERE incomeTypeId = $realestates->incometypeid");
    R::exec("UPDATE `expensestype` SET `expensestypename`='$realestatename', 
             `expensestypedetails`='$realestatename' WHERE expensestypeid = $realestates->expenstypeid");
}
```

2. **Units Processing Loop**:
```php
for ($i = 1; $i <= $realestatesunitsitr; $i++) {
    $unitname = filter_input(INPUT_POST, 'unitname_' . $i);
    $unitarea = filter_input(INPUT_POST, 'unitarea_' . $i);
    $unitid = filter_input(INPUT_POST, 'unitid_' . $i);
    
    if (!$unitname) {continue;} // Skip empty units
    
    if (!$unitid) {
        // Create new unit
        $realestatesunits = R::dispense('realestatesunits');
        $realestatesunits->del = 0;
        $realestatesunits->addtoday = $today;
        $realestatesunits->adduserid = $userid;
    } else {
        // Update existing unit
        $realestatesunits = R::load('realestatesunits', $unitid);
        $realestatesunits->del = 1; // Mark as updated
        $realestatesunits->updatetoday = $today;
        $realestatesunits->updateuserid = $userid;
    }
    
    $realestatesunits->realestateid = $realestateid;
    $realestatesunits->unitname = $unitname;
    $realestatesunits->unitarea = $unitarea;
    $realestatesunits->cavaible = 0;
    R::store($realestatesunits);
}
```

3. **Income/Expense Type Integration**:
```php
if (!$id) {
    incomeexpenstype($realestateid, $realestatename);
}
```

---

### 6. **incomeexpenstype** - Automatic Type Creation
**Location**: Lines 185-198
**Purpose**: Automatically create income and expense types for new properties

**Function Signature**:
```php
function incomeexpenstype($realestateid, $realestatename) {
```

**Process Flow**:

1. **Income Type Creation via CURL**:
```php
$send_data = array(
    'parent' => 0, 
    'name' => $realestatename, 
    'defaultValue' => 0,
    'descripe' => $realestatename, 
    'curlpost' => 1
);
$incometypeid = CURL_IT2($send_data, 'incomeTypeController.php?do=add');

if ($incometypeid > 0) {
    R::exec("UPDATE `realestates` SET `incometypeid`= $incometypeid WHERE id = '" . $realestateid . "'");
}
```

2. **Expense Type Creation via CURL**:
```php
$send_data = array(
    'parent' => 0, 
    'treeType' => 0, 
    'name' => $realestatename, 
    'type' => 0, 
    'saveid' => 0, 
    'defaultValue' => 0,
    'descripe' => $realestatename, 
    'curlpost' => 1
);
$expenstypeid = CURL_IT2($send_data, 'expensesTypeController.php?do=add');

if ($expenstypeid > 0) {
    R::exec("UPDATE `realestates` SET `expenstypeid`= $expenstypeid WHERE id = '" . $realestateid . "'");
}
```

---

### 7. **showajax** - AJAX Data Table Provider
**Location**: Lines 209-305
**Purpose**: Provide server-side data for advanced DataTables with search/filter

**Function Signature**:
```php
function showajax() {
    $columns = array('realestates.id', 'realestatename', '', 'realestates.addtoday', 'employeename', 'realestates.id', 'realestates.id');
}
```

**Process Flow**:

1. **Filter Processing**:
```php
$start_date = filter_input(INPUT_POST, 'start_date');
$end_date = filter_input(INPUT_POST, 'end_date');
$del = filter_input(INPUT_POST, 'del');
$realestateid = filter_input(INPUT_POST, 'realestateid');
$realestateunitid = filter_input(INPUT_POST, 'realestateunitid');
$savaible = filter_input(INPUT_POST, 'savaible');
$cavaible = filter_input(INPUT_POST, 'cavaible');
```

2. **Dynamic Query Building**:
```php
$searchQuery = " ";
$searchjoin = " ";

if($realestateid != ''){
    $searchQuery .= " and realestates.id = ".$realestateid. " ";
}

if($del == ''){
    $searchQuery .= " and realestates.del < 2 "; 
}

if ($savaible) {
    $searchQuery .= " and realestates.savaible = ".$savaible. " ";
}

if ($cavaible) {
    $searchQuery .= " and realestates.cavaible = ".$cavaible. " ";
}

if($realestateunitid != ''){
    $searchQuery .= " and realestatesunits.id = ".$realestateunitid. " ";
    $searchjoin .= " LEFT JOIN realestatesunits ON realestates.id = realestatesunits.realestateid ";
}
```

3. **Search Functionality**:
```php
if (isset($_POST['search']['value']) && $_POST['search']['value'] != "") {
    $searchQuery .= "and ( realestates.id LIKE '%".$_POST["search"]["value"]."%' 
                    OR realestates.realestatename LIKE '%".$_POST["search"]["value"]."%'
                    OR realestates.addtoday LIKE '%".$_POST["search"]["value"]."%'
                    OR employeename LIKE '%".$_POST["search"]["value"]."%'
        )";
}
```

4. **Units Aggregation**:
```php
foreach ($rResult as $row) {
    $realestatesunits = R::findAll('realestatesunits',"realestateid = ? and del < 2 ",[$row['id']]);
    $allunits = '';
    foreach($realestatesunits as $units){
        $allunits .= $units->unitname . ' / ';
    }
    // Add to sub_array[2]
}
```

---

### 8. **removecontroller** - Soft Delete Property
**Location**: Lines 309-325
**Purpose**: Soft delete property and cascade to all units

**Function Signature**:
```php
function removecontroller() {
    $id = filter_input(INPUT_POST, 'id');
}
```

**Process Flow**:
```php
$tables = R::load('realestates', $id);
$tables->del = 2; // Soft delete
$tables->deltoday = $today;
$tables->deluserid = $userid;

try {
    R::store($tables);
    // Cascade delete to all units
    R::exec("UPDATE `realestatesunits` SET `del`= 3 WHERE realestateid = '" . $id . "'");
    echo 1; // Success
} catch (Exception $e) {
    echo 0; // Failure
}
```

---

### 9. **Select2 Integration Functions** - Dynamic Dropdown Data

#### **select2supplier** (Lines 53-65)
```php
function select2supplier() {
    $name = $_POST['searchTerm'];
    $productsData = R::getAll("SELECT supplierid, CONCAT(suppliername,'/',supplierphone) as texts
        FROM supplier WHERE conditions = 0 and CONCAT(suppliername,'/',supplierphone) 
        LIKE '%" . $name . "%' limit 50");
    
    $return_arr = array();
    foreach ($productsData as $pro) {
        $row_array = array();
        $row_array['id'] = $pro['supplierid'];
        $row_array['text'] = $pro['texts'];
        array_push($return_arr, $row_array);
    }
    echo json_encode($return_arr);
}
```

#### **select2client** (Lines 68-80)
```php
function select2client() {
    $name = $_POST['searchTerm'];
    $productsData = R::getAll("SELECT clientid, CONCAT(clientname,'/',clientphone) as texts
        FROM client WHERE conditions = 0 and CONCAT(clientname,'/',clientphone) 
        LIKE '%" . $name . "%' limit 50");
    // Similar structure to select2supplier
}
```

#### **select2realestates** (Lines 84-98)
```php
function select2realestates() {   
    $name = $_POST['searchTerm'];
    $productsData = R::getAll("SELECT id, realestatename
        FROM realestates WHERE del < 2 and realestatename LIKE '%" . $name . "%' limit 50");
    // Returns property list for dropdown selection
}
```

#### **select2realestatesunits** (Lines 100-115)
```php
function select2realestatesunits() {
    $name = $_POST['searchTerm'];
    $realestateid = $_POST['realestateid'];
    $productsData = R::getAll("SELECT id, CONCAT(unitname,'/',unitarea) as texts
        FROM realestatesunits WHERE del < 2 and CONCAT(unitname,'/',unitarea) 
        LIKE '%" . $name . "%' and realestatesunits.realestateid = $realestateid limit 50");
    // Returns units filtered by parent property
}
```

---

### 10. **getexpenstype** - Expense Type Retrieval
**Location**: Lines 201-205
**Purpose**: Get expense type ID for a property

**Function Signature**:
```php
function getexpenstype() {
    $id = filter_input(INPUT_POST, 'id');
    $realestates = R::load('realestates', $id);
    echo $realestates->expenstypeid;
}
```

---

### 11. **CURL_IT2** - Internal API Communication
**Location**: Lines 347-371
**Purpose**: Internal CURL function for controller-to-controller communication

**Function Signature**:
```php
function CURL_IT2($data_arr = array(), $url) {
    $url = 'http://' . $_SERVER['HTTP_HOST'] . explode('controllers', $_SERVER['REQUEST_URI'])[0] . 'controllers/' . $url;
}
```

**Process Flow**:
1. Build internal URL from current request
2. Add session data to request
3. Execute CURL POST request
4. Return response for income/expense type creation

---

## 🔄 Workflows

### Workflow 1: Complete Property Creation
```
┌─────────────────────────────────────────────────────────────┐
│              START: Create New Property                    │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  1. Display Property Creation Form                          │
│     - Load realestateunitsview/add.html                    │
│     - Initialize dynamic unit addition system              │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  2. User Adds Multiple Units (Dynamic)                     │
│     - AJAX calls to addappend for each new unit            │
│     - Generate form fields: unitname_{i}, unitarea_{i}     │
│     - Track iteration count via realestatesunitsitr        │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  3. Form Submission (savedata)                             │
│     - Validate property name                               │
│     - Create/update realestates record                     │
│     - Set audit trail fields (addtoday, adduserid)        │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  4. Process All Units in Loop                              │
│     FOR i = 1 to realestatesunitsitr:                      │
│       │                                                     │
│       ├─→ Extract unitname_i and unitarea_i                │
│       │                                                     │
│       ├─→ Skip if unitname is empty                        │
│       │                                                     │
│       ├─→ Create realestatesunits record                   │
│       │   ├─ Link to parent realestateid                   │
│       │   ├─ Set unit details (name, area)                 │
│       │   └─ Set audit trail and defaults                  │
│       │                                                     │
│       └─→ Store unit record                                │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  5. Create Income/Expense Types (New Property Only)        │
│     - CURL call to incomeTypeController.php                │
│     - CURL call to expensesTypeController.php              │
│     - Update property with type IDs                        │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  6. Return Success Response                                │
│     - Return property ID to frontend                       │
│     - Frontend redirects or shows success message          │
└─────────────────────────────────────────────────────────────┘
```

---

### Workflow 2: Property Editing with Units
```
┌─────────────────────────────────────────────────────────────┐
│            START: Edit Existing Property                   │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  1. Load Property and Units Data                           │
│     - Load realestates record by ID                        │
│     - Load all related realestatesunits (del < 2)          │
│     - Assign to template variables                          │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  2. Display Edit Form                                      │
│     - Populate property name field                         │
│     - Display existing units in form                       │
│     - Enable dynamic unit addition/removal                 │
│     - Include hidden unitid fields for existing units      │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  3. Form Submission with Changes                           │
│     - Update property name (if changed)                    │
│     - Mark property as updated (del = 1)                   │
│     - Update related income/expense type names             │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  4. Process Units with Create/Update Logic                 │
│     FOR each unit in form:                                 │
│       │                                                     │
│       ├─→ If unitid exists: Update existing unit          │
│       │   ├─ Load existing record                          │
│       │   ├─ Update fields (name, area)                    │
│       │   └─ Set update audit trail                        │
│       │                                                     │
│       └─→ If no unitid: Create new unit                   │
│           ├─ Create new record                             │
│           ├─ Set all fields and defaults                   │
│           └─ Set creation audit trail                      │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  5. Return Update Success                                  │
│     - Property and units updated                           │
│     - Income/expense types updated                         │
│     - Audit trail maintained                               │
└─────────────────────────────────────────────────────────────┘
```

---

## 🌐 URL Routes & Actions

| URL Parameter | Function Called | Description |
|---------------|----------------|-------------|
| `do=` (empty) | Default action | Property creation form |
| `do=addappend` | addappend() | Dynamic form component addition |
| `do=show` | show action | Properties listing interface |
| `do=edit` | edit action | Property editing form |
| `do=savedata` | savedata() | Save/update property and units |
| `do=showajax` | showajax() | AJAX data table provider |
| `do=removecontroller` | removecontroller() | Soft delete property |
| `do=select2client` | select2client() | Client dropdown data |
| `do=select2supplier` | select2supplier() | Supplier dropdown data |
| `do=select2realestates` | select2realestates() | Properties dropdown data |
| `do=select2realestatesunits` | select2realestatesunits() | Units dropdown data |
| `do=getexpenstype` | getexpenstype() | Get expense type ID |

### Required Parameters by Action

**Property Creation** (`do=savedata`, new):
- `realestatename` - Property name
- `realestatesunitsitr` - Number of units
- `unitname_{i}` - Unit names (1 to N)
- `unitarea_{i}` - Unit areas (1 to N)

**Property Edit** (`do=savedata`, update):
- `id` - Property ID
- `realestatename` - Updated property name  
- `realestatesunitsitr` - Number of units
- `unitname_{i}` - Unit names
- `unitarea_{i}` - Unit areas
- `unitid_{i}` - Unit IDs (for existing units)

**Dynamic Addition** (`do=addappend`):
- `itr` - Current iteration number
- `dataitr` - Data iteration parameter
- `container` - Template container to load

**AJAX Table** (`do=showajax`):
- Standard DataTables parameters (draw, start, length, search, order)
- Optional filters: start_date, end_date, del, realestateid, etc.

---

## 🧮 Calculation Methods

### Dynamic Unit Management
```php
// Loop through all submitted units
for ($i = 1; $i <= $realestatesunitsitr; $i++) {
    $unitname = filter_input(INPUT_POST, 'unitname_' . $i);
    $unitarea = filter_input(INPUT_POST, 'unitarea_' . $i);
    $unitid = filter_input(INPUT_POST, 'unitid_' . $i);   
    
    if (!$unitname) {continue;} // Skip empty units
    
    // Create or update logic based on unitid presence
}
```

### Audit Trail Management
```php
// For new records
$record->del = 0;           // Active status
$record->addtoday = $today; // Creation timestamp
$record->adduserid = $userid; // Creator ID

// For updates
$record->del = 1;              // Updated status
$record->updatetoday = $today;  // Update timestamp
$record->updateuserid = $userid; // Updater ID

// For soft deletes
$record->del = 2;             // Deleted status (properties)
$record->del = 3;             // Deleted status (units, cascade)
$record->deltoday = $today;   // Deletion timestamp
$record->deluserid = $userid; // Deleter ID
```

### Search Query Building
```php
$searchQuery = " ";
if($realestateid != ''){
    $searchQuery .= " and realestates.id = ".$realestateid. " ";
}
if($del == ''){
    $searchQuery .= " and realestates.del < 2 "; // Active records only
}
```

---

## 🔒 Security & Permissions

### Input Validation
```php
// All inputs filtered through PHP filter_input
$realestatename = filter_input(INPUT_POST, 'realestatename');
$realestatesunitsitr = filter_input(INPUT_POST, 'realestatesunitsitr');
$id = filter_input(INPUT_POST, 'id');

// Dynamic unit inputs validated in loop
for ($i = 1; $i <= $realestatesunitsitr; $i++) {
    $unitname = filter_input(INPUT_POST, 'unitname_' . $i);
    $unitarea = filter_input(INPUT_POST, 'unitarea_' . $i);
}
```

### SQL Injection Prevention
- RedBeanPHP ORM with parameterized queries
- Proper integer casting for IDs
- Safe string concatenation for search terms

### Transaction Safety
```php
try {
    $realestateid = R::store($realestates);
    // Process all units...
    echo $realestateid; // Success
} catch (Exception $e) {
    echo 0; // Failure - transaction rolled back
}
```

### Soft Delete Protection
```php
// Only show active records
$searchQuery .= " and realestates.del < 2 ";

// Cascade soft delete to units
R::exec("UPDATE `realestatesunits` SET `del`= 3 WHERE realestateid = '" . $id . "'");
```

---

## 📊 Performance Considerations

### Database Optimization
1. **Critical Indexes**:
   - `realestates(del, id)`
   - `realestatesunits(realestateid, del)`
   - `realestates(addtoday)` for date filtering
   - `realestates(realestatename)` for searching

2. **Query Efficiency**:
   - Efficient JOIN usage in showajax
   - Proper LIMIT clauses for Select2 dropdowns
   - Conditional query building to avoid unnecessary WHERE clauses

3. **Memory Management**:
   - Iterative unit processing instead of bulk loading
   - Efficient template variable assignment
   - Clean JSON encoding for AJAX responses

### AJAX Performance
```php
// Limit Select2 results for performance
"SELECT ... LIMIT 50"

// Efficient DataTables pagination
if (isset($_POST['start']) && $_POST['length'] != '-1') {
    $searchQuery .= "LIMIT " . intval($_POST['start']) . ", " . intval($_POST['length']);
}
```

---

## 🐛 Common Issues & Troubleshooting

### 1. **Units Not Saving**
**Issue**: Units disappear after property save
**Cause**: Empty unitname causing continue in loop

**Debug**:
```php
// Add debugging to savedata function
for ($i = 1; $i <= $realestatesunitsitr; $i++) {
    $unitname = filter_input(INPUT_POST, 'unitname_' . $i);
    echo "Processing unit $i: $unitname<br>";
    if (!$unitname) {
        echo "Skipping empty unit $i<br>";
        continue;
    }
}
```

### 2. **Income/Expense Types Not Created**
**Issue**: New properties don't get associated income/expense types
**Cause**: CURL_IT2 function failing or endpoint issues

**Debug**:
```php
// Check CURL responses
$incometypeid = CURL_IT2($send_data, 'incomeTypeController.php?do=add');
echo "Income type ID: " . $incometypeid;
if ($incometypeid <= 0) {
    echo "Income type creation failed";
}
```

### 3. **AJAX Table Not Loading**
**Issue**: DataTable shows "No data available"
**Cause**: showajax query issues or wrong column count

**Debug**:
```php
// Add debugging to showajax
$totals = R::count('realestates','LEFT JOIN user ON realestates.adduserid = user.userid 
    '.$searchjoin.' WHERE 1 '.$searchQuery.' ');
echo "Total records: " . $totals;

// Check column count matches JavaScript
$columns = array('realestates.id', 'realestatename', '', 'realestates.addtoday', 'employeename', 'realestates.id', 'realestates.id');
echo "Column count: " . count($columns);
```

### 4. **Select2 Dropdowns Not Populating**
**Issue**: Dropdowns show "No results found"
**Cause**: Search term handling or conditions filtering

**Debug**:
```sql
-- Test supplier search directly
SELECT supplierid, CONCAT(suppliername,'/',supplierphone) as texts
FROM supplier 
WHERE conditions = 0 
AND CONCAT(suppliername,'/',supplierphone) LIKE '%test%' 
LIMIT 50;
```

---

## 🧪 Testing Scenarios

### Test Case 1: Complete Property Creation
```
1. Navigate to property creation form
2. Enter property name
3. Add 3 units dynamically using addappend
4. Fill unit names and areas
5. Submit form
6. Verify property and units saved correctly
7. Check income/expense types created
8. Verify audit trail fields populated
```

### Test Case 2: Property Edit with Unit Changes
```
1. Load existing property with 2 units
2. Edit property name
3. Modify existing unit details
4. Add 1 new unit
5. Submit changes
6. Verify property name updated
7. Verify existing units modified
8. Verify new unit created
9. Check income/expense types updated
```

### Test Case 3: AJAX Table Functionality
```
1. Create multiple properties with different names/dates
2. Load properties listing page
3. Test search functionality
4. Test date range filtering
5. Test sorting by different columns
6. Test pagination
7. Verify edit/delete buttons work
```

### Test Case 4: Select2 Integration
```
1. Test supplier dropdown search
2. Test client dropdown search  
3. Test properties dropdown search
4. Test units dropdown (with parent property filter)
5. Verify JSON responses are properly formatted
6. Test with special characters in search terms
```

### Test Case 5: Soft Delete Functionality
```
1. Create property with multiple units
2. Soft delete the property
3. Verify property marked as del = 2
4. Verify all units marked as del = 3
5. Verify property doesn't appear in listings
6. Verify audit trail maintained
```

---

## 📚 Related Documentation

- [CLAUDE.md](/Applications/AMPPS/www/erp19/CLAUDE.md) - PHP 8.2 migration guide
- [realestateaveragerevenue.md](realestateaveragerevenue.md) - Revenue analysis
- [realestatepayments.md](realestatepayments.md) - Payment tracking
- [Database Schema Documentation](#) - Table relationships
- [Select2 Documentation](https://select2.org/) - Dropdown component
- [DataTables Documentation](https://datatables.net/) - Table component

---

**Key Features Summary**:
1. **Complete CRUD Operations** - Create, read, update, soft delete
2. **Dynamic Unit Management** - Add/remove units on the fly
3. **AJAX Integration** - Server-side DataTables and Select2
4. **Automatic Type Creation** - Income/expense types via CURL
5. **Comprehensive Audit Trail** - Full change tracking
6. **Advanced Search/Filter** - Multiple criteria support
7. **Soft Delete Protection** - Data preservation with del flags
8. **Transaction Safety** - Exception handling and rollback

---

**Documented By**: AI Assistant  
**Review Status**: ✅ Complete  
**Next Review**: When major changes occur