---
description: توثيق ربط البنوك بالحسابات في شجرة الحسابات
alwaysApply: true
---

# ربط البنوك بالحسابات في شجرة الحسابات

## المشكلة

يجب أن يكون كل بنك في النظام مرتبطاً بحساب فرعي في شجرة الحسابات بنفس اسم البنك. هذا الربط ضروري لضمان التكامل بين نظام البنوك ونظام المحاسبة، حيث يتم تسجيل جميع معاملات البنك تلقائياً في الحساب المرتبط به.

## الحل المطلوب

1. **التحقق من وجود حساب لكل بنك**: يجب التأكد من أن كل بنك له حساب فرعي مقابل في شجرة الحسابات بنفس اسم البنك.
2. **إنشاء حسابات للبنوك الجديدة**: عند إنشاء بنك جديد، يجب إنشاء حساب فرعي له تلقائياً في شجرة الحسابات.
3. **تحديث الحسابات عند تحديث البنوك**: عند تحديث اسم البنك، يجب تحديث اسم الحساب المقابل له في شجرة الحسابات.
4. **حذف الحسابات عند حذف البنوك**: عند حذف بنك، يجب حذف الحساب المقابل له في شجرة الحسابات.

## هيكل البيانات

### جدول البنوك (banks)

يحتوي على معلومات البنوك في النظام:

```php
protected $fillable = [
    'company_id',
    'name',
    'code',
    'swift_code',
    'address',
    'contact_person',
    'contact_phone',
    'contact_email',
    'notes',
    'is_active',
];
```

### جدول شجرة الحسابات (chart_of_accounts)

يحتوي على معلومات الحسابات في النظام:

```php
protected $fillable = [
    'company_id',
    'account_code',
    'name',
    'name_en',
    'account_type',
    'sub_type',
    'parent_id',
    'description',
    'is_active',
    'is_system',
    'opening_balance',
    'current_balance',
    'currency',
    'balance_type',
    'is_cash_account',
    'is_bank_account',
    'level',
    'is_parent'
];
```

## آلية الربط

### 1. إنشاء حساب للبنك

عند إنشاء بنك جديد، يتم إنشاء حساب فرعي له في شجرة الحسابات تحت حساب النقدية والبنوك:

```php
// البحث عن حساب النقدية والبنوك أو إنشائه
$cashAndBanksAccount = $this->findOrCreateCashAndBanksAccount($bank->company_id);

// توليد رمز حساب فريد
$lastAccountCode = ChartOfAccount::where('parent_id', $cashAndBanksAccount->id)
    ->where('is_bank_account', true)
    ->orderBy('account_code', 'desc')
    ->value('account_code');

$newAccountCode = $lastAccountCode ? (intval($lastAccountCode) + 1) : ($cashAndBanksAccount->account_code . '01');

// إنشاء حساب للبنك
$account = ChartOfAccount::create([
    'company_id' => $bank->company_id,
    'account_code' => $newAccountCode,
    'name' => $bank->name,
    'name_en' => $bank->name,
    'account_type' => 'asset',
    'sub_type' => 'bank',
    'parent_id' => $cashAndBanksAccount->id,
    'description' => 'حساب البنك: ' . $bank->name,
    'is_active' => $bank->is_active,
    'is_system' => false,
    'opening_balance' => 0,
    'current_balance' => 0,
    'currency' => 'SAR',
    'balance_type' => 'debit',
    'is_cash_account' => false,
    'is_bank_account' => true,
    'level' => $cashAndBanksAccount->level + 1,
    'is_parent' => false
]);
```

### التسلسل الهرمي للحسابات

يتم إنشاء حساب البنك ضمن التسلسل الهرمي التالي:

1. **الأصول (1000)** - الحساب الرئيسي للأصول
2. **الأصول المتداولة (1100)** - حساب فرعي تحت الأصول
3. **النقدية والبنوك (1110)** - حساب فرعي تحت الأصول المتداولة
4. **حساب البنك** - حساب فرعي تحت النقدية والبنوك

يتم التحقق من وجود كل حساب في التسلسل الهرمي، وإنشائه إذا لم يكن موجوداً، قبل إنشاء حساب البنك.

### 2. البحث عن حساب البنك

للبحث عن حساب البنك في شجرة الحسابات:

```php
// البحث عن حساب النقدية والبنوك
$cashAndBanksAccount = $this->findOrCreateCashAndBanksAccount($bank->company_id);

// البحث عن حساب البنك تحت حساب النقدية والبنوك
return ChartOfAccount::where('company_id', $bank->company_id)
    ->where('parent_id', $cashAndBanksAccount->id)
    ->where('name', $bank->name)
    ->where('is_bank_account', true)
    ->first();
```

### 3. تحديث حساب البنك

عند تحديث اسم البنك أو معلوماته، يتم تحديث الحساب المرتبط به:

```php
// تحديث حساب البنك
$account->update([
    'name' => $bank->name,
    'name_en' => $bank->name,
    'description' => 'حساب البنك: ' . $bank->name,
    'is_active' => $bank->is_active
]);
```

### 4. حذف حساب البنك

عند حذف البنك، يتم حذف الحساب المرتبط به:

```php
// البحث عن حساب البنك في شجرة الحسابات
$account = $this->bankAccountService->findBankAccount($bank);

// حذف حساب البنك من شجرة الحسابات إذا كان موجوداً
if ($account) {
    $account->delete();
}
```

## التنفيذ المقترح

### 1. إنشاء خدمة BankAccountService

تم إنشاء خدمة `BankAccountService` لإدارة حسابات البنوك في شجرة الحسابات:

```php
<?php

namespace App\Services;

use App\Models\Bank;
use App\Models\ChartOfAccount;
use Illuminate\Support\Facades\Log;

class BankAccountService
{
    /**
     * إنشاء حساب للبنك في شجرة الحسابات
     *
     * @param Bank $bank
     * @return ChartOfAccount|null
     */
    public function createBankAccount(Bank $bank)
    {
        // البحث عن حساب البنوك الرئيسي أو إنشائه
        $parentAccount = $this->findOrCreateParentBankAccount($bank->company_id);

        // إنشاء حساب للبنك
        $account = ChartOfAccount::create([
            'company_id' => $bank->company_id,
            'account_code' => 'BANK-' . $bank->id,
            'name' => $bank->name,
            'name_en' => $bank->name,
            'account_type' => 'asset',
            'sub_type' => 'bank',
            'parent_id' => $parentAccount->id,
            'description' => 'حساب البنك: ' . $bank->name,
            'is_active' => $bank->is_active,
            'is_system' => false,
            'opening_balance' => 0,
            'current_balance' => 0,
            'currency' => 'SAR',
            'balance_type' => 'debit',
            'is_cash_account' => false,
            'is_bank_account' => true,
            'level' => $parentAccount->level + 1,
            'is_parent' => false
        ]);

        return $account;
    }

    /**
     * البحث عن حساب البنوك الرئيسي أو إنشائه
     *
     * @param int $companyId
     * @return ChartOfAccount
     */
    private function findOrCreateParentBankAccount($companyId)
    {
        // البحث عن حساب البنوك الرئيسي
        $parentAccount = ChartOfAccount::where('company_id', $companyId)
            ->where('account_type', 'asset')
            ->where('is_bank_account', true)
            ->where('parent_id', null)
            ->first();

        if (!$parentAccount) {
            // إنشاء حساب البنوك الرئيسي
            $parentAccount = ChartOfAccount::create([
                'company_id' => $companyId,
                'account_code' => 'BANK',
                'name' => 'البنوك',
                'name_en' => 'Banks',
                'account_type' => 'asset',
                'sub_type' => 'bank',
                'parent_id' => null,
                'description' => 'حساب البنوك الرئيسي',
                'is_active' => true,
                'is_system' => true,
                'opening_balance' => 0,
                'current_balance' => 0,
                'currency' => 'SAR',
                'balance_type' => 'debit',
                'is_cash_account' => false,
                'is_bank_account' => true,
                'level' => 1,
                'is_parent' => true
            ]);
        }

        return $parentAccount;
    }

    /**
     * تحديث حساب البنك في شجرة الحسابات
     *
     * @param Bank $bank
     * @param ChartOfAccount $account
     * @return bool
     */
    public function updateBankAccount(Bank $bank, ChartOfAccount $account)
    {
        $account->update([
            'name' => $bank->name,
            'name_en' => $bank->name,
            'description' => 'حساب البنك: ' . $bank->name,
            'is_active' => $bank->is_active
        ]);

        return true;
    }

    /**
     * البحث عن حساب البنك في شجرة الحسابات
     *
     * @param Bank $bank
     * @return ChartOfAccount|null
     */
    public function findBankAccount(Bank $bank)
    {
        // البحث عن حساب البنوك الرئيسي
        $parentAccount = $this->findOrCreateParentBankAccount($bank->company_id);

        return ChartOfAccount::where('company_id', $bank->company_id)
            ->where('parent_id', $parentAccount->id)
            ->where('name', $bank->name)
            ->where('is_bank_account', true)
            ->first();
    }
}
```

### 2. تعديل BankController

تم تعديل وحدة التحكم `BankController` لاستخدام خدمة `BankAccountService`:

```php
/**
 * Store a newly created bank in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function store(Request $request)
{
    // التحقق من البيانات وإنشاء البنك
    // ...

    try {
        DB::beginTransaction();

        $bank = Bank::create($validated);

        // إنشاء حساب للبنك في شجرة الحسابات
        $account = $this->bankAccountService->createBankAccount($bank);
        
        if (!$account) {
            throw new \Exception('فشل في إنشاء حساب البنك في شجرة الحسابات');
        }

        DB::commit();

        return redirect()->route('banks.index')
            ->with('success', 'تم إنشاء البنك وحسابه في شجرة الحسابات بنجاح.');
    } catch (\Exception $e) {
        DB::rollBack();
        // ...
    }
}

/**
 * Update the specified bank in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \App\Models\Bank  $bank
 * @return \Illuminate\Http\Response
 */
public function update(Request $request, Bank $bank)
{
    // التحقق من البيانات وتحديث البنك
    // ...

    try {
        DB::beginTransaction();

        $bank->update($validated);

        // البحث عن حساب البنك في شجرة الحسابات أو إنشائه
        $account = $this->bankAccountService->findBankAccount($bank);
        
        if ($account) {
            // تحديث الحساب إذا كان موجوداً
            $this->bankAccountService->updateBankAccount($bank, $account);
        } else {
            // إنشاء حساب جديد إذا لم يكن موجوداً
            $account = $this->bankAccountService->createBankAccount($bank);
        }

        DB::commit();

        return redirect()->route('banks.index')
            ->with('success', 'تم تحديث البنك وحسابه في شجرة الحسابات بنجاح.');
    } catch (\Exception $e) {
        DB::rollBack();
        // ...
    }
}

/**
 * Remove the specified bank from storage.
 *
 * @param  \App\Models\Bank  $bank
 * @return \Illuminate\Http\Response
 */
public function destroy(Bank $bank)
{
    // التحقق من البيانات وحذف البنك
    // ...

    try {
        DB::beginTransaction();

        // التحقق من وجود حسابات بنكية مرتبطة بالبنك
        if ($bank->bankAccounts()->count() > 0) {
            return redirect()->back()
                ->with('error', 'لا يمكن حذف البنك لوجود حسابات بنكية مرتبطة به.');
        }

        // البحث عن حساب البنك في شجرة الحسابات وحذفه
        $account = $this->bankAccountService->findBankAccount($bank);
        
        if ($account) {
            $account->delete();
        }

        $bank->delete();

        DB::commit();

        return redirect()->route('banks.index')
            ->with('success', 'تم حذف البنك وحسابه في شجرة الحسابات بنجاح.');
    } catch (\Exception $e) {
        DB::rollBack();
        // ...
    }
}
```

### 3. أمر لإصلاح البنوك الحالية

تم إنشاء أمر `FixBankAccounts` لإصلاح البنوك الحالية التي ليس لها حسابات في شجرة الحسابات:

```php
<?php

namespace App\Console\Commands;

use App\Models\Bank;
use App\Services\BankAccountService;
use Illuminate\Console\Command;

class FixBankAccounts extends Command
{
    protected $signature = 'banks:fix-accounts';
    protected $description = 'إنشاء حسابات في شجرة الحسابات للبنوك التي ليس لها حسابات';

    protected $bankAccountService;

    public function __construct(BankAccountService $bankAccountService)
    {
        parent::__construct();
        $this->bankAccountService = $bankAccountService;
    }

    public function handle()
    {
        $this->info('بدء إصلاح حسابات البنوك في شجرة الحسابات...');

        // الحصول على جميع البنوك
        $banks = Bank::all();
        $count = 0;

        foreach ($banks as $bank) {
            // البحث عن حساب البنك في شجرة الحسابات
            $account = $this->bankAccountService->findBankAccount($bank);

            if (!$account) {
                // إنشاء حساب للبنك إذا لم يكن موجوداً
                $account = $this->bankAccountService->createBankAccount($bank);

                if ($account) {
                    $count++;
                    $this->info("تم إنشاء حساب للبنك: {$bank->name}");
                } else {
                    $this->error("فشل في إنشاء حساب للبنك: {$bank->name}");
                }
            } else {
                $this->line("البنك {$bank->name} لديه حساب بالفعل في شجرة الحسابات");
            }
        }

        $this->info("تم الانتهاء من إصلاح حسابات البنوك. تم إنشاء {$count} حساب جديد.");

        return 0;
    }
}
```

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

1. يجب التأكد من أن كل بنك له حساب واحد فقط في شجرة الحسابات.
2. يجب أن يكون اسم الحساب مطابقاً لاسم البنك.
3. عند تغيير اسم البنك، يجب تحديث اسم الحساب المرتبط به.
4. عند حذف البنك، يجب حذف الحساب المرتبط به.
5. يجب أن تكون جميع حسابات البنوك من نوع `asset` وتحت نوع `bank` وتحت حساب النقدية والبنوك.
6. يتم إنشاء حسابات البنوك ضمن التسلسل الهرمي التالي: الأصول (1000) -> الأصول المتداولة (1100) -> النقدية والبنوك (1110) -> حساب البنك.
7. يتم توليد رمز حساب فريد لكل بنك بناءً على آخر رمز حساب موجود تحت حساب النقدية والبنوك.
8. يمكن تشغيل الأمر `php artisan banks:fix-accounts` لإصلاح البنوك الحالية التي ليس لها حسابات في شجرة الحسابات.