# تحليل نظام الوسيط العقاري (Office System Analysis)

## نظرة عامة
نظام الوسيط العقاري هو جزء من منصة B العقارية الذي يسمح للمكاتب العقارية بإدارة عقاراتها وملاكها ومستأجريها.

---

## 1. دور الوسيط العقاري وصلاحياته

### 1.1 التحقق من الهوية والصلاحيات

#### ملفات التحقق الرئيسية:
- **`includes/auth_guard.php`**: حارس المصادقة الأساسي
  - يتحقق من تسجيل الدخول (`SESSION_USER_CODE`)
  - يجلب اسم المستخدم وصورته من جدول `users`
  
- **`includes/check_user_role.php`**: التحقق من دور المستخدم
  - يتحقق من وجود المستخدم في قاعدة البيانات
  - يتحقق من `usercode` في جدول `users`

- **`dashboard.php`**: لوحة التحكم الرئيسية
  - يتحقق من نوع المستخدم: `$_SESSION[SESSION_USER_TYPE] !== 'مكتب عقاري'`
  - يتحقق من حالة المستخدم: `is_activated == 1`
  - يتحقق من حالة المكتب: `officeStatus` و `subscriptionStatus`
  - يحفظ `office_id` في الجلسة: `$_SESSION['office_id']`

#### شروط الوصول:
1. **نوع المستخدم**: يجب أن يكون `'مكتب عقاري'`
2. **حالة المستخدم**: `is_activated = 1` (مفعل)
3. **حالة المكتب**: 
   - `officeStatus` يجب ألا يكون `'suspended'` أو `'rejected'`
   - `subscriptionStatus` يجب ألا يكون `'expired'` أو `'suspended'`
4. **وجود مكتب**: يجب أن يكون هناك سجل في جدول `office` مرتبط بـ `user_id`

### 1.2 الصلاحيات الرئيسية

#### إدارة العقارات:
- ✅ إضافة عقارات جديدة (`property/add_property.php`)
- ✅ عرض جميع عقارات المكتب (`property/view_properties.php`)
- ✅ تعديل العقارات (`property/edit_property.php`)
- ✅ حذف العقارات (`property/delete_property.php`)
- ✅ إدارة حالة العقار (`toggle` - تفعيل/تعطيل)
- ✅ إدارة حالة الإكمال (`status` - مكتمل/غير مكتمل)

#### إدارة الملاك:
- ✅ إضافة ملاك جدد (`worners/add_owner.php`)
- ✅ عرض جميع الملاك (`worners/owners.php`)
- ✅ تعديل بيانات الملاك (`worners/edit_owner.php`)
- ✅ حذف الملاك (`worners/delete_owner.php`)
- ✅ ربط الملاك بالعقارات

#### إدارة المستأجرين:
- ✅ إضافة مستأجرين جدد (`tenant/add_tenant.php`)
- ✅ عرض جميع المستأجرين (`tenant/tenants.php`)
- ✅ تعديل بيانات المستأجرين (`tenant/edit_tenant.php`)
- ✅ حذف المستأجرين (`tenant/delete_tenant.php`)
- ✅ إدارة تقييمات المستأجرين

#### إدارة العقود:
- ✅ إنشاء عقود إيجار (`contracts/create_contract.php`)
- ✅ عرض العقود النشطة (`contracts/active_contracts.php`)
- ✅ إدارة الأقساط (`contracts/installments.php`)
- ✅ إدارة الرسائل والطلبات

#### إدارة المالية:
- ✅ إدارة الإيصالات (`receipts/`)
- ✅ إدارة الفواتير (`invoices/`)
- ✅ إدارة المدفوعات (`payments.php`)
- ✅ إدارة المصروفات (`expenses/`)

#### إدارة الصيانة:
- ✅ عرض طلبات الصيانة (`maintenance/`)
- ✅ تحديث حالة الصيانة

---

## 2. استدعاء العقارات (Properties Retrieval)

### 2.1 الملف الرئيسي: `property/property_controller_fixed.php`

#### الدالة الرئيسية: `getUserPropertiesFixed($connect, $office_id, $user_code)`

```php
// الاستعلام الرئيسي
SELECT p.*, 
       (SELECT media FROM property_media pm WHERE pm.property_id = p.id AND pm.background = 1 LIMIT 1) AS background_image,
       (SELECT default_image FROM property_media pmd WHERE pmd.property_id = p.id AND pmd.default_image IS NOT NULL LIMIT 1) AS default_image,
       (SELECT COUNT(*) FROM property_media pmc WHERE pmc.property_id = p.id AND pmc.document_name != 'img_default') AS media_count,
       CASE 
           WHEN p.woner_id = ? THEN 'عقاراتك'
           WHEN u.name IS NOT NULL THEN u.name
           ELSE 'مؤجر غير محدد'
       END as owner_name,
       (SELECT COUNT(*) FROM contracts c WHERE c.property_id = p.id AND c.status = 'ساري') as active_contracts,
       (SELECT COUNT(*) FROM contracts c WHERE c.property_id = p.id AND c.status = 'منتهي') as inactive_contracts,
       (SELECT MAX(c.end_date) FROM contracts c WHERE c.property_id = p.id AND c.status = 'ساري') as last_contract_date,
       (SELECT SUM(c.total_amount) FROM contracts c WHERE c.property_id = p.id AND c.status = 'ساری') as total_contract_value,
       (SELECT SUM(c.payment) FROM contracts c WHERE c.property_id = p.id AND c.status = 'ساري') as total_paid,
       (SELECT SUM(c.remaining_amount) FROM contracts c WHERE c.property_id = p.id AND c.status = 'ساري') as total_remaining
FROM properties p
LEFT JOIN users u ON p.woner_id = u.usercode
WHERE p.office_id = ?
ORDER BY p.dateofInsert DESC
```

#### الشروط:
- **`p.office_id = ?`**: فقط عقارات المكتب الحالي
- **الترتيب**: حسب تاريخ الإضافة (`dateofInsert DESC`)

#### البيانات المرتبطة:
1. **صور العقار**: من جدول `property_media`
2. **اسم المالك**: من جدول `users` عبر `woner_id`
3. **العقود النشطة**: عدد العقود السارية
4. **القيمة المالية**: إجمالي قيمة العقود والمدفوع والمتبقي

### 2.2 تصنيف العقارات

#### الدالة: `classifyProperties($properties)`

```php
// العقارات المكتملة
if ($property['status'] === 'مكتمل') {
    $complete_properties[] = $property;
}
// العقارات غير المكتملة
else {
    $incomplete_properties[] = $property;
}
```

#### الحالات:
- **مكتمل**: `status = 'مكتمل'` - عقار كامل البيانات
- **غير مكتمل**: `status != 'مكتمل'` أو `NULL` - عقار غير مكتمل

### 2.3 إحصائيات العقارات

```sql
SELECT 
    COUNT(*) AS 'إجمالي العقارات',
    COUNT(DISTINCT woner_id) AS 'عدد الملاك',
    SUM(CASE WHEN status = 'مكتمل' AND toggle = 1 THEN 1 ELSE 0 END) AS 'عقارات مفعلة',
    SUM(CASE WHEN status = 'مكتمل' AND (toggle = 0 OR toggle IS NULL) THEN 1 ELSE 0 END) AS 'عقارات معطلة',
    SUM(CASE WHEN status = 'مكتمل' THEN 1 ELSE 0 END) AS 'عقارات مكتملة',
    SUM(CASE WHEN status != 'مكتمل' OR status IS NULL THEN 1 ELSE 0 END) AS 'عقارات غير مكتملة',
    SUM(CAST(distiance AS DECIMAL(10,2))) AS 'إجمالي المساحة',
    COUNT(DISTINCT title_deed_number) AS 'عدد الصكوك المختلفة'
FROM properties
WHERE office_id = ?
```

---

## 3. استدعاء الملاك (Owners Retrieval)

### 3.1 الملف الرئيسي: `worners/owners.php`

#### الاستعلام الرئيسي:

```php
SELECT 
    u.usercode as id, 
    u.name, 
    u.mobile, 
    u.email, 
    u.identity as national_id, 
    u.nationaladdress as commercial_registration,
    u.city, 
    u.region,
    u.created_at
FROM users u
JOIN woner w ON u.usercode = w.owner_id
WHERE w.office_id = ?
ORDER BY u.created_at DESC
```

#### العلاقات:
- **`users`**: جدول المستخدمين (يحتوي بيانات الملاك)
- **`woner`**: جدول ربط الملاك بالمكاتب
  - `woner.owner_id` = `users.usercode`
  - `woner.office_id` = `office.id`

#### الفلترة:
- **البحث**: بالاسم، الجوال، أو البريد الإلكتروني
- **المنطقة**: فلترة حسب `region`

#### الإحصائيات:

```sql
SELECT 
    COUNT(*) as total_owners,
    COUNT(CASE WHEN u.nationaladdress IS NOT NULL AND u.nationaladdress != '' THEN 1 END) as company_owners,
    COUNT(CASE WHEN u.nationaladdress IS NULL OR u.nationaladdress = '' THEN 1 END) as individual_owners
FROM users u
JOIN woner w ON u.usercode = w.owner_id
WHERE w.office_id = ?
```

#### عدد العقارات لكل مالك:

```sql
SELECT COUNT(*) as property_count 
FROM properties 
WHERE woner_id = ? AND office_id = ?
```

---

## 4. استدعاء المستأجرين (Tenants Retrieval)

### 4.1 الملف الرئيسي: `tenant/tenants.php`

#### الملف المساعد: `tenant/fetch_tenants.php`

#### الاستعلام الرئيسي:

```php
SELECT 
    t.id,
    u.usercode,
    u.name,
    u.identity,
    u.mobile,
    u.email,
    u.region,
    u.city,
    u.created_at,
    (SELECT COUNT(*) FROM contracts c WHERE c.tenant_id = t.id AND c.office_id = ?) as contract_count
FROM tenant t
JOIN users u ON t.usercode = u.usercode
WHERE t.id_office = ?
ORDER BY u.created_at DESC
LIMIT ? OFFSET ?
```

#### العلاقات:
- **`tenant`**: جدول المستأجرين
  - `tenant.usercode` = `users.usercode`
  - `tenant.id_office` = `office.id`
- **`users`**: جدول المستخدمين (يحتوي بيانات المستأجرين)
- **`contracts`**: جدول العقود (لحساب عدد العقود)

#### الفلترة:
- **البحث**: بالاسم، رقم الهوية، أو الجوال
- **المنطقة**: فلترة حسب `region`

#### الإحصائيات:

```sql
SELECT 
    COUNT(DISTINCT t.id) as total_tenants,
    COUNT(DISTINCT c.id) as total_contracts,
    COUNT(DISTINCT CASE WHEN c.status = 'ساري' THEN c.id END) as active_contracts,
    COUNT(DISTINCT CASE WHEN c.status IN ('منتهي', 'ملغي') THEN c.id END) as expired_contracts,
    COUNT(DISTINCT CASE WHEN t.blacklist = 1 THEN t.id END) as blacklisted_tenants,
    COUNT(DISTINCT CASE WHEN t.created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) THEN t.id END) as new_tenants_30days
FROM tenant t
LEFT JOIN contracts c ON c.tenant_id = t.id AND c.office_id = ?
WHERE t.id_office = ?
```

---

## 5. بنية جدول العقار (Properties Table Structure)

### 5.1 الجدول: `properties`

#### المعرفات والروابط:
```sql
id                      INT(11)         -- معرف العقار (Primary Key)
woner_id                INT(11)         -- رقم المالك (يربط بـ users.usercode)
office_id               INT(11)         -- رقم المكتب (يربط بـ office.id)
```

#### المعلومات الأساسية:
```sql
main_title              VARCHAR(250)    -- العنوان الرئيسي
number_of_real_estates  TEXT            -- رقم العقارات
title_deed_number       TEXT            -- رقم صك الملكية
title_deed_date         DATE            -- تاريخ صك الملكية
TypeofStrcture          TEXT            -- نوع العقار (فيلا، شقة، محل تجاري...)
property_type           TEXT            -- نوع الوحدة
```

#### الموقع:
```sql
AddressOfnationlatity   TEXT            -- عنوان الوطني
Region                  TEXT            -- المنطقة
governorate             TEXT            -- المحافظة
district                TEXT            -- الحي
```

#### المساحة:
```sql
distiance               TEXT            -- المساحة
length                  TEXT            -- الطول
width                   TEXT            -- العرض
unit                    TEXT            -- الوحدة (متر مربع، قدم مربع...)
```

#### الأسعار:
```sql
rental_price            DOUBLE          -- سعر الإيجار
bidding_price           DOUBLE          -- سعر السوم
Sale                    DOUBLE          -- سعر البيع
```

#### خيارات العرض:
```sql
rent_checked            TINYINT(1)      -- مفعل للإيجار؟
sale_checked            TINYINT(1)      -- مفعل للبيع؟
sale_and_rent_checked   TINYINT(1)      -- مفعل للإيجار والبيع معًا؟
```

#### المواصفات:
```sql
rooms                   INT(11)         -- عدد الغرف
bath                    INT(11)          -- عدد الحمامات
aircondition            TINYINT(11)     -- عدد المكيفات
parking                 TINYINT(1)      -- موقف سيارة؟
furnished               TINYINT(1)      -- مفروش؟
elevator                TINYINT(1)      -- مصعد؟
swimming_pool           TINYINT(4)      -- مسبح؟
internet                TINYINT(1)      -- إنترنت؟
kitchen                 TINYINT(1)      -- مطبخ؟
```

#### الخدمات:
```sql
electrcity              VARCHAR(50)     -- عداد الكهرباء
electricity_inty        TINYINT(1)      -- توفر كهرباء؟
water                   VARCHAR(50)     -- عداد الماء
water_inty              TINYINT(1)      -- توفر ماء؟
gas                     VARCHAR(50)     -- عداد الغاز
gas_inty                TINYINT(1)      -- توفر غاز؟
```

#### القيود:
```sql
singles_only            TINYINT(1)      -- للعزاب فقط؟
families_only           TINYINT(1)      -- للعوائل فقط؟
```

#### الحدود:
```sql
south                   TEXT            -- الحد الجنوبي
east                    TEXT            -- الحد الشرقي
west                    TEXT            -- الحد الغربي
north                   TEXT            -- الحد الشمالي
```

#### الحالة والإدارة:
```sql
status                  TEXT            -- الحالة (مكتمل، غير مكتمل، مؤجر، شاغر...)
toggle                  TINYINT(1)      -- حالة التفعيل (1 = مفعل، 0 = معطل)
advertisingLicenseNumber TEXT           -- رقم رخصة الإعلان
```

#### معلومات إضافية:
```sql
add_details             TEXT            -- تفاصيل إضافية
add_title               VARCHAR(70)     -- عنوان إضافي
resthouse_number        TEXT            -- رقم الاستراحة
placeholder             TEXT            -- Placeholder نصي
title                   VARCHAR(50)     -- عنوان مختصر للعقار
```

#### الكيانات القانونية:
```sql
judicial_guardian_id        INT(11)     -- الوصي القضائي
office_owner_id          INT(11)       -- مالك المكتب
establishment_owner_id     INT(11)      -- مالك المؤسسة
company_liquidator_id       INT(11)      -- مصفي الشركة
company_representative_id   INT(11)      -- ممثل الشركة
waqf_supervisor_id          INT(11)      -- مشرف الوقف
agency_agent_id             INT(11)      -- وكيل وكالة
minor_guardian_id           INT(11)      -- ولي قاصر
```

#### معلومات إضافية متقدمة:
```sql
property_usage              VARCHAR(120) -- استخدام العقار
title_deed_issuer           VARCHAR(120) -- جهة إصدار الصك
title_deed_place_of_issue   VARCHAR(120) -- مكان إصدار الصك
units_count                 INT(11)      -- عدد الوحدات
floors_count                INT(11)      -- عدد الأدوار
parking_lots                INT(11)      -- عدد المواقف
elevators_count             INT(11)      -- عدد المصاعد
```

#### التقييمات:
```sql
average_rating              DECIMAL(2,1) -- متوسط التقييم
total_ratings                INT(11)      -- إجمالي التقييمات
```

#### الطوابع الزمنية:
```sql
dateofInsert                DATETIME     -- تاريخ الإضافة
dateofUpdate                DATETIME     -- تاريخ التحديث الأخير
```

### 5.2 العلاقات الرئيسية

#### مع جدول `users` (الملاك):
```sql
properties.woner_id = users.usercode
```

#### مع جدول `office` (المكاتب):
```sql
properties.office_id = office.id
```

#### مع جدول `contracts` (العقود):
```sql
contracts.property_id = properties.id
```

#### مع جدول `property_media` (الصور والوسائط):
```sql
property_media.property_id = properties.id
```

---

## 6. ملخص العلاقات بين الجداول

### 6.1 العلاقة: المكتب → العقارات
```
office.id = properties.office_id
```
- كل مكتب يمكنه إدارة عدة عقارات
- كل عقار مرتبط بمكتب واحد

### 6.2 العلاقة: المكتب → الملاك
```
office.id = woner.office_id
woner.owner_id = users.usercode
```
- كل مكتب يمكنه إدارة عدة ملاك
- كل مالك يمكن أن يكون مرتبط بعدة مكاتب (من خلال جدول `woner`)

### 6.3 العلاقة: المكتب → المستأجرين
```
office.id = tenant.id_office
tenant.usercode = users.usercode
```
- كل مكتب يمكنه إدارة عدة مستأجرين
- كل مستأجر مرتبط بمكتب واحد

### 6.4 العلاقة: المالك → العقارات
```
users.usercode = properties.woner_id
```
- كل مالك يمكن أن يملك عدة عقارات
- كل عقار مرتبط بمالك واحد

### 6.5 العلاقة: العقار → العقود
```
properties.id = contracts.property_id
```
- كل عقار يمكن أن يكون له عدة عقود (تاريخية)
- كل عقد مرتبط بعقار واحد

### 6.6 العلاقة: المستأجر → العقود
```
tenant.id = contracts.tenant_id
```
- كل مستأجر يمكن أن يكون له عدة عقود
- كل عقد مرتبط بمستأجر واحد

---

## 7. نقاط مهمة للفهم

### 7.1 الفرق بين `woner_id` و `office_owner_id`
- **`woner_id`**: المالك الفعلي للعقار (من جدول `users`)
- **`office_owner_id`**: مالك المكتب (إذا كان المكتب مملوكًا لشخص)

### 7.2 حالة العقار (`status` و `toggle`)
- **`status`**: حالة الإكمال (`'مكتمل'` أو `'غير مكتمل'`)
- **`toggle`**: حالة التفعيل (`1` = مفعل، `0` = معطل)
- **العقار يظهر للزوار فقط إذا**: `status = 'مكتمل'` AND `toggle = 1`

### 7.3 جدول `woner` (الملاك)
- هذا الجدول يربط الملاك بالمكاتب
- يسمح لمالك واحد بالعمل مع عدة مكاتب
- العلاقة: `woner.owner_id = users.usercode` و `woner.office_id = office.id`

### 7.4 جدول `tenant` (المستأجرين)
- هذا الجدول يربط المستأجرين بالمكاتب
- كل مستأجر مرتبط بمكتب واحد فقط (`id_office`)
- العلاقة: `tenant.usercode = users.usercode`

---

## 8. أمثلة على الاستعلامات الشائعة

### 8.1 جلب جميع عقارات المكتب مع معلومات المالك:
```sql
SELECT p.*, u.name as owner_name, u.mobile as owner_mobile
FROM properties p
LEFT JOIN users u ON p.woner_id = u.usercode
WHERE p.office_id = ?
ORDER BY p.dateofInsert DESC
```

### 8.2 جلب جميع الملاك مع عدد عقاراتهم:
```sql
SELECT u.*, COUNT(p.id) as property_count
FROM users u
JOIN woner w ON u.usercode = w.owner_id
LEFT JOIN properties p ON p.woner_id = u.usercode AND p.office_id = w.office_id
WHERE w.office_id = ?
GROUP BY u.usercode
```

### 8.3 جلب جميع المستأجرين مع عدد عقودهم النشطة:
```sql
SELECT u.*, COUNT(c.id) as active_contracts_count
FROM users u
JOIN tenant t ON u.usercode = t.usercode
LEFT JOIN contracts c ON c.tenant_id = t.id AND c.status = 'ساري' AND c.office_id = ?
WHERE t.id_office = ?
GROUP BY u.usercode
```

### 8.4 جلب العقارات المؤجرة حالياً:
```sql
SELECT DISTINCT p.*
FROM properties p
JOIN contracts c ON c.property_id = p.id
WHERE p.office_id = ? 
  AND c.status = 'ساري'
  AND c.end_date >= CURDATE()
```

---

## 9. الخلاصة

نظام الوسيط العقاري يوفر:
1. ✅ إدارة كاملة للعقارات (إضافة، تعديل، حذف، تفعيل/تعطيل)
2. ✅ إدارة الملاك (ربط الملاك بالعقارات)
3. ✅ إدارة المستأجرين (ربط المستأجرين بالعقود)
4. ✅ إدارة العقود (إنشاء، متابعة، إدارة الأقساط)
5. ✅ إدارة مالية (إيصالات، فواتير، مدفوعات)
6. ✅ إدارة الصيانة (طلبات الصيانة من المستأجرين)

جميع العمليات مرتبطة بـ `office_id` لضمان عزل البيانات بين المكاتب المختلفة.

