# تحليل دور الوسيط العقاري والجداول المستخدمة

## نظرة عامة
الوسيط العقاري (Office/Broker) هو المكتب العقاري المسؤول عن إدارة العقارات والملاك والمستأجرين في منصة B العقارية.

---

## 1. دور الوسيط العقاري

### 1.1 المهام الرئيسية

#### إدارة العقارات:
- ✅ عرض جميع العقارات المخصصة للمكتب
- ✅ إضافة عقارات جديدة
- ✅ تعديل بيانات العقارات
- ✅ حذف العقارات (مع التحقق من عدم وجود عقود أو تبعيات)
- ✅ تفعيل/تعطيل عرض العقار (`toggle`)
- ✅ تحديد حالة الإكمال (`status`: مكتمل/غير مكتمل)

#### إدارة الملاك:
- ✅ إضافة ملاك جدد
- ✅ عرض جميع الملاك المرتبطين بالمكتب
- ✅ تعديل بيانات الملاك
- ✅ حذف الملاك
- ✅ ربط الملاك بالعقارات

#### إدارة المستأجرين:
- ✅ إضافة مستأجرين جدد
- ✅ عرض جميع المستأجرين
- ✅ تعديل بيانات المستأجرين
- ✅ إدارة تقييمات المستأجرين

#### إدارة العقود:
- ✅ إنشاء عقود إيجار جديدة
- ✅ إدارة الأقساط والمدفوعات
- ✅ متابعة العقود السارية والمنتهية

#### إدارة طلبات العقارات:
- ✅ عرض طلبات العقارات المتاحة
- ✅ إنشاء عروض على طلبات العقارات
- ✅ إدارة المفاوضات مع العملاء
- ✅ متابعة حالة العروض (pending, accepted, rejected, negotiating)

---

## 2. الجداول الأساسية المستخدمة

### 2.1 جدول `office` (المكتب العقاري)

```sql
CREATE TABLE `office` (
  `id` int(11) NOT NULL COMMENT 'المعرّف الأساسي للمكتب',
  `user_id` int(11) DEFAULT NULL COMMENT 'يرتبط بـ users.usercode',
  `officeName` text NOT NULL COMMENT 'اسم المكتب',
  `officeStatus` text NOT NULL COMMENT 'حالة المكتب (نشط، موقوف، إلخ)',
  `subscriptionStatus` text NOT NULL COMMENT 'حالة الاشتراك (فعّال، منتهي، موقوف)',
  `region` varchar(100) DEFAULT NULL COMMENT 'المنطقة',
  `city` varchar(100) DEFAULT NULL COMMENT 'المدينة',
  ...
  PRIMARY KEY (`id`),
  KEY `fk_office_user` (`user_id`),
  CONSTRAINT `fk_office_user` FOREIGN KEY (`user_id`) 
    REFERENCES `users` (`usercode`)
)
```

**العلاقات:**
- `office.user_id` → `users.usercode` (الحساب المرتبط بالمكتب)

**الحالات:**
- `officeStatus`: `active`, `suspended`, `pending`, `rejected`, `inactive`, `under_review`
- `subscriptionStatus`: `active`, `expired`, `suspended`

---

### 2.2 جدول `properties` (العقارات)

```sql
CREATE TABLE `properties` (
  `id` int(11) NOT NULL COMMENT 'معرف العقار',
  `office_id` int(11) DEFAULT NULL COMMENT 'معرف المكتب العقاري',
  `woner_id` int(11) DEFAULT NULL COMMENT 'رقم المالك - مرتبط بجدول الملاك (users.usercode)',
  `main_title` varchar(250) NOT NULL COMMENT 'العنوان الرئيسي',
  `title_deed_number` text DEFAULT NULL COMMENT 'رقم صك الملكية',
  `status` text DEFAULT NULL COMMENT 'الحالة (مكتمل/غير مكتمل)',
  `toggle` tinyint(1) DEFAULT NULL COMMENT 'تفعيل/تعطيل العرض (1=مفعل, 0=معطل)',
  `rental_price` double NOT NULL COMMENT 'سعر الإيجار',
  `Sale` double DEFAULT NULL COMMENT 'سعر البيع',
  ...
  PRIMARY KEY (`id`),
  KEY `fk_properties_office` (`office_id`),
  CONSTRAINT `fk_properties_office` FOREIGN KEY (`office_id`) 
    REFERENCES `office` (`id`)
)
```

**العلاقات:**
- `properties.office_id` → `office.id` (المكتب المسؤول عن العقار)
- `properties.woner_id` → `users.usercode` (المالك)

**الحالات:**
- `status`: `'مكتمل'` (مكتمل) أو غير مكتمل (`NULL` أو أي قيمة أخرى)
- `toggle`: `1` (مفعل - يظهر للزوار) أو `0` (معطل - لا يظهر)

**الاستعلام الرئيسي لجلب عقارات المكتب:**

```sql
SELECT p.*, 
       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
FROM properties p
LEFT JOIN users u ON p.woner_id = u.usercode
WHERE p.office_id = ?
ORDER BY p.dateofInsert DESC
```

---

### 2.3 جدول `woner` (الملاك)

```sql
CREATE TABLE `woner` (
  `id` int(11) NOT NULL,
  `office_id` int(11) DEFAULT NULL COMMENT 'معرف المكتب',
  `owner_id` int(11) DEFAULT NULL COMMENT 'معرف المالك (users.usercode)',
  ...
  PRIMARY KEY (`id`),
  KEY `fk_woner_office` (`office_id`),
  CONSTRAINT `fk_woner_office` FOREIGN KEY (`office_id`) 
    REFERENCES `office` (`id`)
)
```

**العلاقات:**
- `woner.office_id` → `office.id` (المكتب)
- `woner.owner_id` → `users.usercode` (المالك)

**الاستعلام الرئيسي لجلب ملاك المكتب:**

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

---

### 2.4 جدول `tenant` (المستأجرين)

```sql
CREATE TABLE `tenant` (
  `id` int(11) NOT NULL,
  `id_office` int(11) DEFAULT NULL COMMENT 'معرف المكتب',
  `tenant_id` int(11) DEFAULT NULL COMMENT 'معرف المستأجر (users.usercode)',
  ...
  PRIMARY KEY (`id`),
  KEY `fk_tenant_office` (`id_office`),
  CONSTRAINT `fk_tenant_office` FOREIGN KEY (`id_office`) 
    REFERENCES `office` (`id`)
)
```

**العلاقات:**
- `tenant.id_office` → `office.id` (المكتب)
- `tenant.tenant_id` → `users.usercode` (المستأجر)

---

### 2.5 جدول `contracts` (العقود)

```sql
CREATE TABLE `contracts` (
  `id` int(11) NOT NULL,
  `office_id` int(11) DEFAULT NULL COMMENT 'معرف المكتب',
  `property_id` int(11) DEFAULT NULL COMMENT 'معرف العقار',
  `tenant_id` int(11) DEFAULT NULL COMMENT 'معرف المستأجر',
  `owner_id` int(11) DEFAULT NULL COMMENT 'معرف المالك',
  `status` text DEFAULT NULL COMMENT 'الحالة (ساري، منتهي، ملغى)',
  `total_amount` decimal(12,2) DEFAULT NULL COMMENT 'إجمالي قيمة العقد',
  `payment` decimal(12,2) DEFAULT NULL COMMENT 'المبلغ المدفوع',
  `remaining_amount` decimal(12,2) DEFAULT NULL COMMENT 'المبلغ المتبقي',
  `start_date` date DEFAULT NULL COMMENT 'تاريخ بداية العقد',
  `end_date` date DEFAULT NULL COMMENT 'تاريخ نهاية العقد',
  ...
  PRIMARY KEY (`id`),
  KEY `fk_contracts_office` (`office_id`),
  KEY `fk_contracts_property` (`property_id`),
  CONSTRAINT `fk_contracts_office` FOREIGN KEY (`office_id`) 
    REFERENCES `office` (`id`),
  CONSTRAINT `fk_contracts_property` FOREIGN KEY (`property_id`) 
    REFERENCES `properties` (`id`)
)
```

**العلاقات:**
- `contracts.office_id` → `office.id`
- `contracts.property_id` → `properties.id`
- `contracts.tenant_id` → `users.usercode`
- `contracts.owner_id` → `users.usercode`

**الحالات:**
- `status`: `'ساري'` (ساري), `'منتهي'` (منتهي), `'ملغى'` (ملغى)

---

### 2.6 جدول `property_request` (طلبات العقارات)

```sql
CREATE TABLE `property_request` (
  `id` int(11) NOT NULL,
  `user_code` varchar(50) NOT NULL COMMENT 'رمز المستخدم الذي أنشأ الطلب',
  `office_id` int(11) DEFAULT NULL COMMENT 'معرف المكتب (إن وجد)',
  `region` varchar(255) NOT NULL COMMENT 'المنطقة',
  `city` varchar(255) NOT NULL COMMENT 'المدينة',
  `request_type` enum('sale', 'rent', 'both') NOT NULL DEFAULT 'rent',
  `budget_monthly` decimal(12,2) DEFAULT NULL COMMENT 'المبلغ المتوقع شهرياً (إيجار)',
  `budget_annual` decimal(12,2) DEFAULT NULL COMMENT 'المبلغ المتوقع سنوياً (إيجار)',
  `sale_price_min` decimal(15,2) DEFAULT NULL COMMENT 'السعر الأدنى المتوقع (بيع)',
  `sale_price_max` decimal(15,2) DEFAULT NULL COMMENT 'السعر الأعلى المتوقع (بيع)',
  `status` enum('pending', 'active', 'closed', 'cancelled') DEFAULT 'pending',
  `urgency_level` enum('low', 'medium', 'high') DEFAULT 'low',
  ...
  PRIMARY KEY (`id`),
  KEY `fk_property_request_user` (`user_code`),
  KEY `fk_property_request_office` (`office_id`)
)
```

**العلاقات:**
- `property_request.user_code` → `users.usercode` (صاحب الطلب)
- `property_request.office_id` → `office.id` (مكتب مرتبط - اختياري)

**الحالات:**
- `status`: `pending`, `active`, `closed`, `cancelled`
- `request_type`: `sale`, `rent`, `both`
- `urgency_level`: `low`, `medium`, `high`

---

### 2.7 جدول `property_request_offers` (عروض المكاتب على الطلبات)

```sql
CREATE TABLE `property_request_offers` (
  `id` int(11) NOT NULL,
  `request_id` int(11) NOT NULL COMMENT 'معرف الطلب (FK إلى property_request)',
  `office_id` int(11) NOT NULL COMMENT 'معرف المكتب (FK إلى office)',
  `offer_type` enum('rent', 'sale') NOT NULL COMMENT 'نوع العرض',
  `offer_status` enum('pending', 'accepted', 'rejected', 'negotiating', 'expired') DEFAULT 'pending',
  `rent_monthly` decimal(12,2) DEFAULT NULL COMMENT 'الإيجار الشهري',
  `rent_annual` decimal(12,2) DEFAULT NULL COMMENT 'الإيجار السنوي',
  `sale_price` decimal(15,2) DEFAULT NULL COMMENT 'سعر البيع',
  `property_id` int(11) DEFAULT NULL COMMENT 'معرف العقار المرتبط (FK إلى properties)',
  `notes` text DEFAULT NULL COMMENT 'ملاحظات',
  `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
  ...
  PRIMARY KEY (`id`),
  KEY `fk_offers_request` (`request_id`),
  KEY `fk_offers_office` (`office_id`),
  KEY `fk_offers_property` (`property_id`)
)
```

**العلاقات:**
- `property_request_offers.request_id` → `property_request.id`
- `property_request_offers.office_id` → `office.id`
- `property_request_offers.property_id` → `properties.id` (اختياري)

**الحالات:**
- `offer_status`: `pending`, `accepted`, `rejected`, `negotiating`, `expired`
- `offer_type`: `rent`, `sale`

**الاستعلام الرئيسي لجلب عروض المكتب:**

```sql
SELECT 
    COUNT(*) as total_offers,
    SUM(CASE WHEN offer_status = 'pending' THEN 1 ELSE 0 END) as pending_offers,
    SUM(CASE WHEN offer_status = 'accepted' THEN 1 ELSE 0 END) as accepted_offers,
    SUM(CASE WHEN offer_status = 'rejected' THEN 1 ELSE 0 END) as rejected_offers,
    SUM(CASE WHEN offer_status = 'negotiating' THEN 1 ELSE 0 END) as negotiating_offers
FROM property_request_offers 
WHERE office_id = ?
```

---

### 2.8 جدول `property_request_negotiations` (المفاوضات)

```sql
CREATE TABLE `property_request_negotiations` (
  `id` int(11) NOT NULL,
  `request_id` int(11) NOT NULL COMMENT 'معرف الطلب',
  `offer_id` int(11) DEFAULT NULL COMMENT 'معرف العرض المرتبط',
  `office_id` int(11) DEFAULT NULL COMMENT 'معرف المكتب (عندما sender_type = office)',
  `sender_type` enum('user', 'office') NOT NULL COMMENT 'نوع المرسل',
  `message` text NOT NULL COMMENT 'نص الرسالة',
  `is_read` tinyint(1) DEFAULT 0 COMMENT 'تم القراءة؟',
  `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
  ...
  PRIMARY KEY (`id`),
  KEY `fk_negotiations_request` (`request_id`),
  KEY `fk_negotiations_offer` (`offer_id`),
  KEY `fk_negotiations_office` (`office_id`)
)
```

**العلاقات:**
- `property_request_negotiations.request_id` → `property_request.id`
- `property_request_negotiations.offer_id` → `property_request_offers.id`
- `property_request_negotiations.office_id` → `office.id` (عندما `sender_type = 'office'`)

**الاستعلام الرئيسي لجلب مفاوضات المكتب:**

```sql
SELECT 
    COUNT(*) as total_messages,
    SUM(CASE WHEN is_read = 0 AND sender_type = 'user' THEN 1 ELSE 0 END) as unread_messages
FROM property_request_negotiations 
WHERE office_id = ?
```

---

## 3. كيف يطلع الوسيط على العقارات المخصصة له

### 3.1 آلية جلب العقارات

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

**الدالة:** `getUserPropertiesFixed($connect, $office_id, $user_code)`

**الاستعلام الأساسي:**

```sql
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. **القيمة المالية:** إجمالي قيمة العقود والمدفوع والمتبقي

---

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

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

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

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

---

### 3.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 = ?
```

---

## 4. الجلسة (Session) والتحقق

### 4.1 المتغيرات الأساسية في الجلسة

```php
$_SESSION[SESSION_USER_CODE]    // رمز المستخدم (usercode)
$_SESSION['office_id']          // معرف المكتب (office.id)
$_SESSION['office_name']        // اسم المكتب
$_SESSION['user_name']          // اسم المستخدم
$_SESSION[SESSION_USER_TYPE]    // نوع المستخدم ('مكتب عقاري')
```

### 4.2 التحقق من الصلاحيات

**في `dashboard.php`:**

```php
// 1. التحقق من تسجيل الدخول
if (!isset($_SESSION[SESSION_USER_ID])) {
    header("Location: ../../register/login.php");
    exit();
}

// 2. التحقق من نوع المستخدم
if ($_SESSION[SESSION_USER_TYPE] !== 'مكتب عقاري') {
    header("Location: ../../register/login.php");
    exit();
}

// 3. التحقق من حالة المستخدم
if ($user['is_activated'] == 0) {
    header("Location: ../../includes/check/office_suspended.php");
    exit();
}

// 4. التحقق من حالة المكتب
if ($office['officeStatus'] == 'suspended' || $office['officeStatus'] == 'rejected') {
    header("Location: ../../includes/check/office_suspended.php");
    exit();
}

// 5. التحقق من حالة الاشتراك
if ($office['subscriptionStatus'] == 'expired' || $office['subscriptionStatus'] == 'suspended') {
    header("Location: ../../includes/check/subscription_expired.php");
    exit();
}

// 6. حفظ معرف المكتب في الجلسة
$_SESSION['office_id'] = $office['id'];
```

---

## 5. الصفحات الرئيسية

### 5.1 عرض العقارات
- **الملف:** `property/view_properties.php`
- **الاستخدام:** عرض جميع عقارات المكتب مع إمكانية التصفية والبحث

### 5.2 لوحة التحكم
- **الملف:** `dashboard.php`
- **الاستخدام:** عرض الإحصائيات الشاملة (عقارات، ملاك، مستأجرين، عقود، إلخ)

### 5.3 إدارة طلبات العقارات
- **الملف:** `property/property_requests/dashboard.php`
- **الاستخدام:** عرض طلبات العقارات المتاحة وإنشاء عروض عليها

---

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

```
office (id)
  ├── properties (office_id) → properties.id
  │     ├── contracts (property_id) → contracts.id
  │     └── property_media (property_id) → property_media.id
  ├── woner (office_id) → woner.id
  │     └── users (usercode = woner.owner_id)
  ├── tenant (id_office) → tenant.id
  │     └── users (usercode = tenant.tenant_id)
  ├── contracts (office_id) → contracts.id
  ├── property_request_offers (office_id) → property_request_offers.id
  └── property_request_negotiations (office_id) → property_request_negotiations.id
```

---

## 7. ملخص الجداول المهمة

| الجدول | المفتاح الأساسي | العلاقة مع office | الاستخدام |
|--------|-----------------|-------------------|-----------|
| `office` | `id` | - | معلومات المكتب العقاري |
| `properties` | `id` | `office_id` → `office.id` | العقارات المخصصة للمكتب |
| `woner` | `id` | `office_id` → `office.id` | الملاك المرتبطين بالمكتب |
| `tenant` | `id` | `id_office` → `office.id` | المستأجرين المرتبطين بالمكتب |
| `contracts` | `id` | `office_id` → `office.id` | العقود المبرمة من المكتب |
| `property_request` | `id` | `office_id` → `office.id` (اختياري) | طلبات العقارات |
| `property_request_offers` | `id` | `office_id` → `office.id` | عروض المكتب على الطلبات |
| `property_request_negotiations` | `id` | `office_id` → `office.id` | مفاوضات المكتب مع العملاء |

---

## 8. نصائح مهمة

1. **التحقق من الصلاحيات:** دائماً تحقق من `office_id` في الجلسة قبل أي عملية
2. **الفلترة:** استخدم دائماً `WHERE office_id = ?` في استعلامات العقارات والملاك والمستأجرين
3. **الحالات:** تأكد من فهم الفرق بين `status` (مكتمل/غير مكتمل) و `toggle` (مفعل/معطل)
4. **العلاقات:** تذكر أن `properties.woner_id` يرتبط مباشرة بـ `users.usercode` وليس بـ `woner.id`
5. **الأمان:** استخدم Prepared Statements دائماً للوقاية من SQL Injection

