# نظام التوزيع التلقائي للمدفوعات على الأقساط

## 📋 نظرة عامة

تم تحديث نظام الدفعات ليعمل بطريقة أكثر مرونة وواقعية. بدلاً من ربط كل دفعة بقسط محدد، يقوم النظام الآن **بتوزيع المدفوعات تلقائياً** على الأقساط بالترتيب الزمني.

---

## 🎯 الفكرة الأساسية

### قبل التحديث:
- كل دفعة يجب أن تكون مرتبطة بقسط محدد
- الدفعة تُسجل للقسط المختار فقط
- صعوبة في التعامل مع الدفعات الجزئية أو المدفوعات التي تغطي عدة أقساط

### بعد التحديث:
- العميل يدفع مبلغ معين (مثلاً 2000 جنيه)
- النظام يوزع المبلغ **تلقائياً** على الأقساط المستحقة بالترتيب
- كل قسط يأخذ حقه من المبلغ حسب قيمته
- الأقساط تُحدث حالتها تلقائياً (مدفوع كلياً/جزئياً)

---

## 💡 مثال عملي

### المعطيات:
```
عقد به 6 أقساط:
- القسط 1: 700 جنيه (تاريخ الاستحقاق: 2026-01-15)
- القسط 2: 700 جنيه (تاريخ الاستحقاق: 2026-02-15)
- القسط 3: 700 جنيه (تاريخ الاستحقاق: 2026-03-15)
- القسط 4: 700 جنيه (تاريخ الاستحقاق: 2026-04-15)
- القسط 5: 700 جنيه (تاريخ الاستحقاق: 2026-05-15)
- القسط 6: 700 جنيه (تاريخ الاستحقاق: 2026-06-15)

إجمالي المبلغ المستحق: 4,200 جنيه
```

### السيناريو:
العميل دفع **2,000 جنيه**

### النتيجة التلقائية:

```
القسط 1:
  - القيمة: 700 جنيه
  - المدفوع: 700 جنيه
  - الحالة: ✅ مدفوع كلياً
  - المتبقي من المبلغ: 1,300 جنيه

القسط 2:
  - القيمة: 700 جنيه
  - المدفوع: 700 جنيه
  - الحالة: ✅ مدفوع كلياً
  - المتبقي من المبلغ: 600 جنيه

القسط 3:
  - القيمة: 700 جنيه
  - المدفوع: 600 جنيه
  - الحالة: ⚠️ مدفوع جزئياً (85.7%)
  - المتبقي من المبلغ: 0 جنيه

القسط 4:
  - القيمة: 700 جنيه
  - المدفوع: 0 جنيه
  - الحالة: ❌ غير مدفوع

القسط 5:
  - القيمة: 700 جنيه
  - المدفوع: 0 جنيه
  - الحالة: ❌ غير مدفوع

القسط 6:
  - القيمة: 700 جنيه
  - المدفوع: 0 جنيه
  - الحالة: ❌ غير مدفوع
```

---

## 🔧 التغييرات التقنية

### 1. تعديل جدول المدفوعات (Payments Table)

```php
// database/migrations/2026_03_06_000001_make_installment_id_nullable_in_payments.php

Schema::table('payments', function (Blueprint $table) {
    // جعل installment_id اختياري
    $table->foreignId('installment_id')->nullable()->change();
});
```

**السبب:** المدفوعات الآن لا تكون مرتبطة بقسط واحد، بل يتم توزيعها على عدة أقساط.

---

### 2. إضافة PaymentObserver

```php
// app/Observers/PaymentObserver.php

class PaymentObserver
{
    public function created(Payment $payment): void
    {
        if ($payment->status === 'completed' && $payment->contract_id) {
            $this->distributePaymentToInstallments($payment);
        }
    }
    
    private function distributePaymentToInstallments(Payment $payment): void
    {
        // الحصول على الأقساط غير المدفوعة بالترتيب
        $installments = Installment::where('contract_id', $payment->contract_id)
            ->where('is_paid', false)
            ->orderBy('due_date', 'asc')
            ->get();

        $remainingAmount = (float) $payment->amount;

        foreach ($installments as $installment) {
            if ($remainingAmount <= 0) break;

            // المبلغ المتبقي من القسط
            $installmentRemaining = $installment->value - $installment->paid_amount;

            // المبلغ الذي سيُدفع لهذا القسط
            $amountToPay = min($remainingAmount, $installmentRemaining);

            // تحديث القسط
            $installment->paid_amount += $amountToPay;
            
            if ($installment->paid_amount >= $installment->value) {
                $installment->is_paid = true;
                $installment->payment_date = $payment->payment_date;
            }
            
            $installment->save();
            $remainingAmount -= $amountToPay;
        }
    }
}
```

---

### 3. تحديث نموذج Payment (PaymentResource)

```php
// app/Filament/Resources/Payments/PaymentResource.php

Select::make('installment_id')
    ->label(__('payments.installment_due_date'))
    ->helperText('اختياري: يمكن ترك هذا الحقل فارغاً وسيتم توزيع المبلغ تلقائياً على الأقساط')
    // ... اختياري الآن، لا يوجد required()

TextInput::make('amount')
    ->label(__('payments.amount'))
    ->helperText('المبلغ المدفوع - سيتم توزيعه تلقائياً على الأقساط بالترتيب')
    ->required()
    ->numeric()
    // ... لم يعد readonly
```

---

### 4. تحديث الحسابات في موديل Contract

```php
// app/Models/Contract.php

// حساب الإجمالي المحصل (من الأقساط المدفوعة)
public function getTotalCollectedAttribute()
{
    return $this->installments()->sum('paid_amount');
}

// عدد الأقساط المدفوعة كلياً
public function getPaidInstallmentsCountAttribute()
{
    return $this->installments()->where('is_paid', true)->count();
}

// عدد الأقساط المدفوعة جزئياً
public function getPartiallyPaidInstallmentsCountAttribute()
{
    return $this->installments()
        ->where('is_paid', false)
        ->where('paid_amount', '>', 0)
        ->count();
}

// عدد الأقساط غير المدفوعة
public function getUnpaidInstallmentsCountAttribute()
{
    return $this->installments()
        ->where('is_paid', false)
        ->where('paid_amount', 0)
        ->count();
}
```

---

## 📊 حالات الأقساط

### 1. مدفوع كلياً (Fully Paid)
```php
is_paid = true
paid_amount >= value
```

### 2. مدفوع جزئياً (Partially Paid)
```php
is_paid = false
paid_amount > 0
paid_amount < value
```

### 3. غير مدفوع (Unpaid)
```php
is_paid = false
paid_amount = 0
```

---

## 🔄 آلية التوزيع التفصيلية

### الخطوة 1: استلام الدفعة
```php
Payment::create([
    'customer_id' => 1,
    'contract_id' => 5,
    'amount' => 2000,
    'payment_date' => now(),
    'status' => 'completed',
]);
```

### الخطوة 2: تفعيل Observer تلقائياً
```php
PaymentObserver::created() → distributePaymentToInstallments()
```

### الخطوة 3: جلب الأقساط غير المدفوعة بالترتيب
```php
$installments = Installment::where('contract_id', 5)
    ->where('is_paid', false)
    ->orderBy('due_date', 'asc')
    ->get();
```

### الخطوة 4: توزيع المبلغ
```
المبلغ المتبقي: 2000 جنيه

القسط 1 (700 جنيه):
  - يأخذ 700 جنيه
  - is_paid = true
  - المتبقي: 1300 جنيه

القسط 2 (700 جنيه):
  - يأخذ 700 جنيه
  - is_paid = true
  - المتبقي: 600 جنيه

القسط 3 (700 جنيه):
  - يأخذ 600 جنيه (كل المتبقي)
  - is_paid = false (لم يكتمل)
  - paid_amount = 600
  - المتبقي: 0 جنيه

انتهى التوزيع ✅
```

---

## 🔙 عكس التوزيع (عند حذف دفعة)

عند حذف دفعة، يتم **عكس التوزيع** تلقائياً:

```php
public function deleting(Payment $payment): void
{
    $this->reversePaymentDistribution($payment);
}
```

**مثال:**
- إذا تم حذف دفعة بقيمة 2000 جنيه
- يتم خصم المبلغ من الأقساط بنفس الترتيب
- الأقساط ترجع لحالتها السابقة

---

## ✅ المزايا

1. **مرونة أكبر**: لا حاجة لتحديد قسط معين
2. **واقعية أكثر**: يطابق الواقع العملي للمحاسبة
3. **توفير الوقت**: التوزيع تلقائي بدون تدخل يدوي
4. **دقة أعلى**: لا يوجد خطأ في توزيع المبالغ
5. **تتبع أفضل**: حالة كل قسط واضحة (كلي/جزئي/غير مدفوع)

---

## 📝 ملاحظات مهمة

### 1. ترتيب الأقساط
- التوزيع يتم **بالترتيب الزمني** (حسب `due_date`)
- الأقساط الأقدم تُدفع أولاً

### 2. الأقساط المدفوعة مسبقاً
- يتم تجاهل الأقساط التي `is_paid = true`
- التوزيع يشمل فقط الأقساط غير المدفوعة كلياً

### 3. الدفعات الجزئية
- لا مشكلة في دفع مبلغ أقل من قيمة القسط
- `paid_amount` يتراكم مع كل دفعة جديدة

### 4. حذف الدفعات
- عند الحذف، يتم عكس التوزيع تلقائياً
- الأقساط ترجع لحالتها السابقة

---

## 🚀 طريقة الاستخدام

### 1. إضافة دفعة جديدة

1. اذهب إلى **المدفوعات** → **إضافة دفعة**
2. اختر **العميل**
3. اختر **العقد**
4. ❌ **لا تختر قسط محدد** (اتركه فارغاً)
5. أدخل **المبلغ المدفوع**
6. حدد **التاريخ** و**طريقة الدفع**
7. احفظ ✅

**النظام سيوزع المبلغ تلقائياً على الأقساط!**

### 2. عرض حالة الأقساط

اذهب إلى **العقد** → **علامة التبويب: الأقساط**

ستجد:
- ✅ الأقساط المدفوعة (أخضر)
- ⚠️ الأقساط الجزئية (برتقالي)
- ❌ الأقساط غير المدفوعة (رمادي)

---

## 🧪 مثال اختبار

```php
// إنشاء عقد بـ 4 أقساط
$contract = Contract::create([
    'customer_id' => 1,
    'installment_price' => 4000,
    'installment_count' => 4,
    'installment_value' => 1000,
    // ...
]);

// توليد الأقساط تلقائياً (1000 × 4)

// الدفعة الأولى: 1500 جنيه
Payment::create([
    'contract_id' => $contract->id,
    'amount' => 1500,
    'status' => 'completed',
]);

// النتيجة:
// - القسط 1: 1000 (مدفوع كلياً) ✅
// - القسط 2: 500 (مدفوع جزئياً) ⚠️
// - القسط 3: 0 (غير مدفوع) ❌
// - القسط 4: 0 (غير مدفوع) ❌

// الدفعة الثانية: 2000 جنيه
Payment::create([
    'contract_id' => $contract->id,
    'amount' => 2000,
    'status' => 'completed',
]);

// النتيجة:
// - القسط 1: 1000 (مدفوع كلياً) ✅
// - القسط 2: 1000 (مدفوع كلياً) ✅ (تم إكماله)
// - القسط 3: 1000 (مدفوع كلياً) ✅
// - القسط 4: 500 (مدفوع جزئياً) ⚠️

// إجمالي المدفوع: 3500 من أصل 4000
// المتبقي: 500 جنيه
```

---

## 📞 الدعم

إذا واجهت أي مشكلة أو كان لديك استفسار، يمكنك:
1. مراجعة ملف `PaymentObserver.php`
2. التحقق من logs في `storage/logs/laravel.log`
3. استخدام `dd()` للتتبع

---

تم التحديث في: **6 مارس 2026**
