Realestateunits Documentation

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:

Primary Functions

Related Controllers

---

๐Ÿ—„๏ธ Database Tables

Primary Tables (Direct Operations)

Table NamePurposeKey Columns
**realestates**Main property recordsid, realestatename, del, addtoday, adduserid, updatetoday, updateuserid, deltoday, deluserid, savaible, cavaible, incometypeid, expenstypeid
**realestatesunits**Individual property unitsid, realestateid, unitname, unitarea, del, addtoday, adduserid, updatetoday, updateuserid, deltoday, deluserid, cavaible
### Integration Tables (Automatic Creation)

Table NamePurposeKey Columns
**incometype**Income categoriesincomeTypeId, incomeTypeName, incomeTypeDetails
**expensestype**Expense categoriesexpensestypeid, expensestypename, expensestypedetails
### Reference Tables

Table NamePurposeKey Columns
**supplier**Supplier informationsupplierid, suppliername, supplierphone, conditions
**client**Client informationclientid, clientname, clientphone, conditions
**user**System usersuserid, 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:

// 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:

// 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)

$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:

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:

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:

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:

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:

function incomeexpenstype($realestateid, $realestatename) {

Process Flow:

1. Income Type Creation via CURL:

$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:

$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:

function showajax() {
    $columns = array('realestates.id', 'realestatename', '', 'realestates.addtoday', 'employeename', 'realestates.id', 'realestates.id');
}

Process Flow:

1. Filter Processing:

$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:

$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:

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:

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:

function removecontroller() {
    $id = filter_input(INPUT_POST, 'id');
}

Process Flow:

$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)

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)

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)

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)

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:

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:

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
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
1Display Property Creation Form
- Load realestateunitsview/add.html
- Initialize dynamic unit addition system
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
2User Adds Multiple Units (Dynamic)
- AJAX calls to addappend for each new unit
- Generate form fields: unitname_{i}, unitarea_{i}
- Track iteration count via realestatesunitsitr
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
3Form Submission (savedata)
- Validate property name
- Create/update realestates record
- Set audit trail fields (addtoday, adduserid)
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
4Process 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 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
5Create Income/Expense Types (New Property Only)
- CURL call to incomeTypeController.php
- CURL call to expensesTypeController.php
- Update property with type IDs
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
6Return Success Response
- Return property ID to frontend
- Frontend redirects or shows success message
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

---

Workflow 2: Property Editing with Units

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
START: Edit Existing Property
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
1Load Property and Units Data
- Load realestates record by ID
- Load all related realestatesunits (del < 2)
- Assign to template variables
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
2Display Edit Form
- Populate property name field
- Display existing units in form
- Enable dynamic unit addition/removal
- Include hidden unitid fields for existing units
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
3Form Submission with Changes
- Update property name (if changed)
- Mark property as updated (del = 1)
- Update related income/expense type names
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
4Process 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 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
5Return Update Success
- Property and units updated
- Income/expense types updated
- Audit trail maintained
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

---

๐ŸŒ URL Routes & Actions

URL ParameterFunction CalledDescription
`do=` (empty)Default actionProperty creation form
`do=addappend`addappend()Dynamic form component addition
`do=show`show actionProperties listing interface
`do=edit`edit actionProperty 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):

Property Edit (do=savedata, update):

Dynamic Addition (do=addappend):

AJAX Table (do=showajax):

---

๐Ÿงฎ Calculation Methods

Dynamic Unit Management

// 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

// 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

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

---

๐Ÿ”’ Security & Permissions

Input Validation

// 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

Transaction Safety

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

Soft Delete Protection

// 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

// 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:

// 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:

// 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:

// 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:

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

---

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