# تحليل شامل: الملاك والمستأجرين والعقود

## 📋 نظرة عامة

هذا التحليل يشرح العلاقات بين:
- **الملاك** (`woner`) والمكتب العقاري
- **العقار** (`properties`) كحلقة الوصل بين المالك والمكتب
- **المستأجرين** (`tenant`) والمكتب العقاري
- **العقود** (`contracts`) التي تربط المالك والمستأجر والعقار والمكتب

---

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

### الهيكل الكامل:

```sql
CREATE TABLE `woner` (
  `id` int(11) NOT NULL,
  `owner_id` int(11) DEFAULT NULL COMMENT 'يربط بالمالك (users.usercode)',
  `office_id` int(11) DEFAULT NULL COMMENT 'يربط بالمكتب العقاري (office.id)'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
```

### الحقول الأساسية:

1. **`id`** - معرف السجل (المفتاح الأساسي)
2. **`owner_id`** - معرف المالك (يربط بـ `users.usercode`)
3. **`office_id`** - معرف المكتب العقاري (يربط بـ `office.id`)

### العلاقات (Foreign Keys):

```sql
-- العلاقة مع المستخدم (المالك)
fk_woner_usercode: woner.owner_id → users.usercode (SET NULL)

-- العلاقة مع المكتب العقاري
fk_woner_office: woner.office_id → office.id (SET NULL)
```

---

## 🔗 علاقة المالك بالمكتب العقاري

### العلاقة الأساسية:

```
users (usercode)
  ↓
woner (owner_id, office_id)
  ├── owner_id → users.usercode (المالك)
  └── office_id → office.id (المكتب العقاري)
```

### المبدأ الأساسي:

**العلاقة بين المالك والمكتب هي علاقة "كثير إلى كثير" (Many-to-Many):**
- مالك واحد يمكن أن يكون مرتبطاً بعدة مكاتب
- مكتب واحد يمكن أن يكون مرتبطاً بعدة ملاك

**مثال:**
```
المالك (usercode = 6):
  - مرتبط بالمكتب 7 (woner: owner_id=6, office_id=7)
  - يمكن أن يكون مرتبطاً بالمكتب 8 (woner: owner_id=6, office_id=8)
```

---

## 🏠 العقار كحلقة الوصل

### جدول `properties` - العقارات:

```sql
CREATE TABLE `properties` (
  `id` int(11) NOT NULL,
  `woner_id` int(11) DEFAULT NULL COMMENT 'يربط بالمالك (woner.owner_id أو users.usercode)',
  `office_id` int(11) DEFAULT NULL COMMENT 'يربط بالمكتب العقاري (office.id)',
  `main_title` varchar(255) DEFAULT NULL,
  `property_type` varchar(50) DEFAULT NULL,
  -- ... باقي الحقول
)
```

### العلاقات:

```sql
-- العلاقة مع المالك
fk_properties_woner_ownerid: properties.woner_id → woner.owner_id (SET NULL)
fk_owner_usercode: properties.woner_id → users.usercode (SET NULL)

-- العلاقة مع المكتب
fk_properties_office_id: properties.office_id → office.id (SET NULL)
```

### السلسلة الكاملة:

```
office (id)
  ↓
woner (office_id, owner_id)
  ↓
properties (office_id, woner_id)
  ├── office_id → office.id (المكتب المسؤول)
  └── woner_id → woner.owner_id → users.usercode (المالك)
```

### المبدأ الأساسي:

**العقار يربط المالك بالمكتب:**
- كل عقار له مالك واحد (`woner_id`)
- كل عقار مرتبط بمكتب واحد (`office_id`)
- المكتب يدير العقارات التي `properties.office_id = office.id`
- المالك يملك العقارات التي `properties.woner_id = woner.owner_id`

---

## 🔄 دورة ربط المالك بالمكتب عبر العقار

### المرحلة 1: إضافة مالك جديد للمكتب

```
1. المكتب يضيف مالك جديد
   ↓
2. التحقق من وجود المستخدم في users
   ↓
3. إنشاء سجل في woner:
   - owner_id = users.usercode
   - office_id = office.id
   ↓
4. المالك أصبح مرتبطاً بالمكتب
```

**الكود:**
```php
// التحقق من وجود المستخدم
SELECT usercode FROM users WHERE usercode = :owner_usercode;

// إضافة المالك للمكتب
INSERT INTO woner (owner_id, office_id) 
VALUES (:owner_usercode, :office_id);
```

---

### المرحلة 2: إنشاء عقار للمالك

```
1. المكتب يختار مالك مرتبط به (woner.office_id = office.id)
   ↓
2. التحقق: المالك مرتبط بالمكتب
   SELECT 1 FROM woner 
   WHERE owner_id = :owner_id AND office_id = :office_id;
   ↓
3. إنشاء عقار:
   - woner_id = woner.owner_id (المالك)
   - office_id = office.id (المكتب)
   ↓
4. العقار يربط المالك بالمكتب
```

**الكود:**
```php
// التحقق من أن المالك مرتبط بالمكتب
$stmtCheckWoner = $pdo->prepare("
    SELECT owner_id FROM woner 
    WHERE owner_id = ? AND office_id = ?
");
$stmtCheckWoner->execute([$owner_usercode, $office_id]);

if (!$stmtCheckWoner->fetch()) {
    throw new Exception('المالك غير مرتبط بمكتبك');
}

// إنشاء العقار
INSERT INTO properties (woner_id, office_id, main_title, ...) 
VALUES (:woner_id, :office_id, :main_title, ...);
```

---

### المرحلة 3: عرض العقارات المرتبطة بالمكتب

```
1. المكتب يطلب عرض العقارات
   ↓
2. جلب العقارات المرتبطة به:
   SELECT * FROM properties 
   WHERE office_id = :office_id;
   ↓
3. جلب معلومات الملاك:
   SELECT p.*, u.name AS owner_name, w.office_id
   FROM properties p
   JOIN woner w ON p.woner_id = w.owner_id
   JOIN users u ON w.owner_id = u.usercode
   WHERE p.office_id = :office_id;
```

---

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

### الهيكل الكامل:

```sql
CREATE TABLE `tenant` (
  `id` int(11) NOT NULL,
  `usercode` int(11) DEFAULT NULL COMMENT 'يربط بالمستأجر (users.usercode)',
  `id_office` int(11) DEFAULT NULL COMMENT 'يربط بالمكتب العقاري (office.id)',
  `blacklist` tinyint(1) DEFAULT NULL COMMENT 'هل المستأجر في القائمة السوداء؟',
  `dateofInsert` date NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
```

### الحقول الأساسية:

1. **`id`** - معرف السجل (المفتاح الأساسي)
2. **`usercode`** - معرف المستأجر (يربط بـ `users.usercode`)
3. **`id_office`** - معرف المكتب العقاري (يربط بـ `office.id`)
4. **`blacklist`** - هل المستأجر في القائمة السوداء؟ (0=لا، 1=نعم)

### العلاقة الأساسية:

```
users (usercode)
  ↓
tenant (usercode, id_office)
  ├── usercode → users.usercode (المستأجر)
  └── id_office → office.id (المكتب العقاري)
```

---

## 🔗 علاقة المستأجر بالمكتب العقاري

### المبدأ الأساسي:

**العلاقة بين المستأجر والمكتب هي علاقة "كثير إلى كثير":**
- مستأجر واحد يمكن أن يكون مرتبطاً بعدة مكاتب
- مكتب واحد يمكن أن يكون مرتبطاً بعدة مستأجرين

**مثال:**
```
المستأجر (usercode = 101):
  - مرتبط بالمكتب 7 (tenant: usercode=101, id_office=7)
  - يمكن أن يكون مرتبطاً بالمكتب 8 (tenant: usercode=101, id_office=8)
```

---

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

### الهيكل الكامل:

```sql
CREATE TABLE `contracts` (
  `id` int(11) NOT NULL,
  `contract_number` varchar(50) NOT NULL COMMENT 'رقم العقد الفريد',
  `property_id` int(11) DEFAULT NULL COMMENT 'يربط بالعقار (properties.id)',
  `woner_id` int(11) DEFAULT NULL COMMENT 'يربط بالمالك (woner.owner_id)',
  `tenant_id` int(11) DEFAULT NULL COMMENT 'يربط بالمستأجر (tenant.usercode)',
  `office_id` int(11) DEFAULT NULL COMMENT 'يربط بالمكتب العقاري (office.id)',
  `start_date` date NOT NULL COMMENT 'تاريخ بداية العقد',
  `end_date` date NOT NULL COMMENT 'تاريخ نهاية العقد',
  `total_amount` float NOT NULL COMMENT 'القيمة الإجمالية',
  `payment` float NOT NULL COMMENT 'تم الدفع',
  `remaining_amount` float NOT NULL COMMENT 'المبلغ المتبقي',
  `security_deposit` float DEFAULT NULL COMMENT 'الضمان',
  `extra_charges` float DEFAULT NULL COMMENT 'رسوم إضافية',
  `payment_type` varchar(50) DEFAULT NULL COMMENT 'نوع الدفع',
  `contract_date` date NOT NULL COMMENT 'تاريخ العقد',
  `invoice_date` date NOT NULL COMMENT 'تاريخ الفاتورة',
  `note` text DEFAULT NULL COMMENT 'ملاحظات',
  `status` enum('ساري','منتهي','ملغى','مغادر') NOT NULL DEFAULT 'ساري',
  `date_inserted` timestamp NOT NULL DEFAULT current_timestamp()
)
```

### العلاقات (Foreign Keys):

```sql
-- العلاقة مع العقار
contracts_ibfk_1: contracts.property_id → properties.id

-- العلاقة مع المكتب
fk_contracts_office: contracts.office_id → office.id (SET NULL)

-- العلاقة مع المالك
fk_contracts_woner: contracts.woner_id → woner.owner_id (SET NULL)

-- العلاقة مع المستأجر
fk_contracts_tenant: contracts.tenant_id → tenant.usercode (SET NULL)
```

---

## 🔗 علاقة المستأجر بالعقود

### السلسلة الكاملة:

```
office (id)
  ↓
tenant (id_office, usercode)
  ↓
contracts (tenant_id, office_id, property_id, woner_id)
  ├── tenant_id → tenant.usercode (المستأجر)
  ├── office_id → office.id (المكتب)
  ├── property_id → properties.id (العقار)
  └── woner_id → woner.owner_id (المالك)
```

### المبدأ الأساسي:

**العقد يربط:**
- **المستأجر** (`tenant_id` → `tenant.usercode`)
- **المالك** (`woner_id` → `woner.owner_id`)
- **العقار** (`property_id` → `properties.id`)
- **المكتب** (`office_id` → `office.id`)

---

## 🔄 دورة إنشاء العقد

### المرحلة 1: التحقق من العلاقات

```
1. المكتب يريد إنشاء عقد إيجار
   ↓
2. التحقق من المالك:
   SELECT 1 FROM woner 
   WHERE owner_id = :owner_id AND office_id = :office_id;
   ↓
3. التحقق من العقار:
   SELECT woner_id FROM properties 
   WHERE id = :property_id AND office_id = :office_id;
   ↓
4. التحقق من تطابق المالك مع العقار:
   IF properties.woner_id != woner.owner_id THEN ERROR;
   ↓
5. التحقق من المستأجر:
   SELECT 1 FROM tenant 
   WHERE usercode = :tenant_id AND id_office = :office_id;
```

**الكود:**
```php
// التحقق من المالك
$owner_check = $pdo->prepare("
    SELECT 1 FROM woner 
    WHERE owner_id = :owner_id 
      AND office_id = :office_id
");
$owner_check->execute(['owner_id' => $owner_id, 'office_id' => $office_id]);
if (!$owner_check->fetch()) {
    throw new Exception('المالك غير مرتبط بمكتبك');
}

// التحقق من العقار
$property_check = $pdo->prepare("
    SELECT woner_id FROM properties 
    WHERE id = :property_id 
      AND office_id = :office_id
");
$property_check->execute(['property_id' => $property_id, 'office_id' => $office_id]);
$property = $property_check->fetch();
if (!$property) {
    throw new Exception('العقار غير مرتبط بمكتبك');
}

// التحقق من تطابق المالك مع العقار
if ($property['woner_id'] != $owner_id) {
    throw new Exception('المالك لا يطابق العقار');
}

// التحقق من المستأجر
$tenant_check = $pdo->prepare("
    SELECT 1 FROM tenant 
    WHERE usercode = :tenant_id 
      AND id_office = :office_id
");
$tenant_check->execute(['tenant_id' => $tenant_id, 'office_id' => $office_id]);
if (!$tenant_check->fetch()) {
    throw new Exception('المستأجر غير مرتبط بمكتبك');
}
```

---

### المرحلة 2: إنشاء العقد

```
1. إدخال بيانات العقد:
   - contract_number (رقم العقد)
   - property_id (العقار)
   - woner_id (المالك)
   - tenant_id (المستأجر)
   - office_id (المكتب)
   - start_date, end_date (التواريخ)
   - total_amount (القيمة الإجمالية)
   - payment (المدفوع)
   - remaining_amount (المتبقي)
   - security_deposit (الضمان)
   - status = 'ساري'
   ↓
2. حفظ العقد في contracts
```

**الكود:**
```php
$pdo->beginTransaction();

try {
    // إدراج العقد
    $insert = $pdo->prepare("
        INSERT INTO contracts (
            contract_number, property_id, woner_id, tenant_id, office_id,
            start_date, end_date, total_amount, payment, remaining_amount,
            security_deposit, contract_date, invoice_date, status
        ) VALUES (
            :contract_number, :property_id, :woner_id, :tenant_id, :office_id,
            :start_date, :end_date, :total_amount, :payment, :remaining_amount,
            :security_deposit, :contract_date, :invoice_date, 'ساري'
        )
    ");
    $insert->execute([
        'contract_number' => $contract_number,
        'property_id' => $property_id,
        'woner_id' => $owner_id,
        'tenant_id' => $tenant_id,
        'office_id' => $office_id,
        'start_date' => $start_date,
        'end_date' => $end_date,
        'total_amount' => $total_amount,
        'payment' => $payment,
        'remaining_amount' => $remaining_amount,
        'security_deposit' => $security_deposit,
        'contract_date' => $contract_date,
        'invoice_date' => $invoice_date
    ]);
    
    $pdo->commit();
} catch (Exception $e) {
    $pdo->rollBack();
    throw $e;
}
```

---

## 📊 العلاقات الكاملة في النظام

### السلسلة الكاملة من المكتب إلى العقد:

```
office (id = 7)
  ↓
woner (office_id = 7, owner_id = 6)
  ↓
properties (office_id = 7, woner_id = 6, id = 1)
  ↓
contracts (office_id = 7, property_id = 1, woner_id = 6, tenant_id = 101)
  ├── office_id → office.id (المكتب)
  ├── property_id → properties.id (العقار)
  ├── woner_id → woner.owner_id → users.usercode (المالك)
  └── tenant_id → tenant.usercode → users.usercode (المستأجر)
```

### السلسلة من المستأجر إلى العقد:

```
office (id = 7)
  ↓
tenant (id_office = 7, usercode = 101)
  ↓
contracts (office_id = 7, tenant_id = 101)
  ├── tenant_id → tenant.usercode (المستأجر)
  ├── property_id → properties.id (العقار)
  ├── woner_id → woner.owner_id (المالك)
  └── office_id → office.id (المكتب)
```

---

## 🔍 أمثلة على الاستعلامات

### 1. جلب الملاك المرتبطين بالمكتب:

```sql
SELECT 
    w.id AS woner_id,
    w.owner_id,
    u.name AS owner_name,
    u.mobile AS owner_mobile,
    u.email AS owner_email,
    COUNT(p.id) AS properties_count
FROM woner w
JOIN users u ON w.owner_id = u.usercode
LEFT JOIN properties p ON p.woner_id = w.owner_id AND p.office_id = w.office_id
WHERE w.office_id = :office_id
GROUP BY w.id, w.owner_id, u.name, u.mobile, u.email
ORDER BY u.name ASC;
```

### 2. جلب العقارات المرتبطة بمكتب مع معلومات الملاك:

```sql
SELECT 
    p.id AS property_id,
    p.main_title,
    p.property_type,
    p.office_id,
    w.owner_id,
    u.name AS owner_name,
    u.mobile AS owner_mobile,
    o.officeName
FROM properties p
JOIN woner w ON p.woner_id = w.owner_id AND p.office_id = w.office_id
JOIN users u ON w.owner_id = u.usercode
LEFT JOIN office o ON p.office_id = o.id
WHERE p.office_id = :office_id
ORDER BY p.dateofInsert DESC;
```

### 3. جلب المستأجرين المرتبطين بالمكتب:

```sql
SELECT 
    t.id AS tenant_id,
    t.usercode,
    u.name AS tenant_name,
    u.mobile AS tenant_mobile,
    u.email AS tenant_email,
    t.blacklist,
    COUNT(c.id) AS contracts_count
FROM tenant t
JOIN users u ON t.usercode = u.usercode
LEFT JOIN contracts c ON c.tenant_id = t.usercode AND c.office_id = t.id_office
WHERE t.id_office = :office_id
GROUP BY t.id, t.usercode, u.name, u.mobile, u.email, t.blacklist
ORDER BY u.name ASC;
```

### 4. جلب العقود المرتبطة بمكتب مع معلومات المالك والمستأجر والعقار:

```sql
SELECT 
    c.id AS contract_id,
    c.contract_number,
    c.start_date,
    c.end_date,
    c.total_amount,
    c.payment,
    c.remaining_amount,
    c.status,
    p.main_title AS property_title,
    u_owner.name AS owner_name,
    u_tenant.name AS tenant_name,
    o.officeName
FROM contracts c
JOIN properties p ON c.property_id = p.id
JOIN woner w ON c.woner_id = w.owner_id AND c.office_id = w.office_id
JOIN users u_owner ON w.owner_id = u_owner.usercode
JOIN tenant t ON c.tenant_id = t.usercode AND c.office_id = t.id_office
JOIN users u_tenant ON t.usercode = u_tenant.usercode
LEFT JOIN office o ON c.office_id = o.id
WHERE c.office_id = :office_id
ORDER BY c.date_inserted DESC;
```

### 5. جلب عقود مستأجر معين:

```sql
SELECT 
    c.id AS contract_id,
    c.contract_number,
    c.start_date,
    c.end_date,
    c.status,
    p.main_title AS property_title,
    u_owner.name AS owner_name,
    o.officeName
FROM contracts c
JOIN properties p ON c.property_id = p.id
JOIN woner w ON c.woner_id = w.owner_id
JOIN users u_owner ON w.owner_id = u_owner.usercode
LEFT JOIN office o ON c.office_id = o.id
WHERE c.tenant_id = :tenant_usercode
  AND c.office_id = :office_id
ORDER BY c.start_date DESC;
```

### 6. جلب عقود مالك معين:

```sql
SELECT 
    c.id AS contract_id,
    c.contract_number,
    c.start_date,
    c.end_date,
    c.status,
    p.main_title AS property_title,
    u_tenant.name AS tenant_name,
    o.officeName
FROM contracts c
JOIN properties p ON c.property_id = p.id
JOIN tenant t ON c.tenant_id = t.usercode
JOIN users u_tenant ON t.usercode = u_tenant.usercode
LEFT JOIN office o ON c.office_id = o.id
WHERE c.woner_id = :owner_id
  AND c.office_id = :office_id
ORDER BY c.start_date DESC;
```

---

## 🔐 قواعد الأمان والصلاحيات

### 1. التحقق من ملكية المكتب للمالك:

```php
// التحقق من أن المالك مرتبط بالمكتب
SELECT * FROM woner 
WHERE owner_id = :owner_id 
  AND office_id = :office_id;
```

### 2. التحقق من ملكية المكتب للعقار:

```php
// التحقق من أن العقار مرتبط بالمكتب
SELECT * FROM properties 
WHERE id = :property_id 
  AND office_id = :office_id;
```

### 3. التحقق من تطابق المالك مع العقار:

```php
// التحقق من أن المالك يطابق العقار
SELECT woner_id FROM properties 
WHERE id = :property_id 
  AND woner_id = :owner_id 
  AND office_id = :office_id;
```

### 4. التحقق من ملكية المكتب للمستأجر:

```php
// التحقق من أن المستأجر مرتبط بالمكتب
SELECT * FROM tenant 
WHERE usercode = :tenant_id 
  AND id_office = :office_id;
```

### 5. التحقق من ملكية المكتب للعقد:

```php
// التحقق من أن العقد مرتبط بالمكتب
SELECT * FROM contracts 
WHERE id = :contract_id 
  AND office_id = :office_id;
```

---

## 📈 الإحصائيات المتوقعة

### لمكتب واحد (متوسط):
- **الملاك:** 500 مالك
- **العقارات:** 5,000 عقار
- **المستأجرين:** 2,000 مستأجر
- **العقود:** 3,000 عقد
- **العقود السارية:** 2,500 عقد
- **العقود المنتهية:** 400 عقد
- **العقود الملغاة:** 100 عقد

### لـ 100 مكتب:
- **الملاك:** 50,000 مالك
- **العقارات:** 500,000 عقار
- **المستأجرين:** 200,000 مستأجر
- **العقود:** 300,000 عقد
- **العقود السارية:** 250,000 عقد
- **العقود المنتهية:** 40,000 عقد
- **العقود الملغاة:** 10,000 عقد

---

## 🎯 الخلاصة

### المبادئ الأساسية:

1. ✅ **العلاقة بين المالك والمكتب** (`woner.office_id`)
   - مالك واحد يمكن أن يكون مرتبطاً بعدة مكاتب
   - مكتب واحد يمكن أن يكون مرتبطاً بعدة ملاك

2. ✅ **العقار يربط المالك بالمكتب** (`properties.woner_id`, `properties.office_id`)
   - كل عقار له مالك واحد
   - كل عقار مرتبط بمكتب واحد
   - العقار هو حلقة الوصل بين المالك والمكتب

3. ✅ **العلاقة بين المستأجر والمكتب** (`tenant.id_office`)
   - مستأجر واحد يمكن أن يكون مرتبطاً بعدة مكاتب
   - مكتب واحد يمكن أن يكون مرتبطاً بعدة مستأجرين

4. ✅ **العقد يربط المالك والمستأجر والعقار والمكتب** (`contracts`)
   - كل عقد يربط: مالك + مستأجر + عقار + مكتب
   - العقد هو الوثيقة الرسمية للعلاقة

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

```
office → woner (office_id) → properties (woner_id, office_id)
office → tenant (id_office) → contracts (tenant_id, office_id)
contracts → properties (property_id) → woner (woner_id)
```

### السلسلة الكاملة:

```
office (id)
  ├── woner (office_id, owner_id)
  │   └── properties (office_id, woner_id)
  │       └── contracts (property_id, woner_id, office_id)
  │
  └── tenant (id_office, usercode)
      └── contracts (tenant_id, office_id)
```

---

**تاريخ الإنشاء:** 2025-01-25
**آخر تحديث:** 2025-01-25
