Commit fa934c04 authored by DevPilot's avatar DevPilot

fix(accounting): إيداع الشيك بالبنك ما كانش بيرحّل قيد + أداة تصفية رصيد شيكات تحت التحصيل

العميل قال إن رصيد «شيكات تحت التحصيل» طلع ناقص بعد ما عمل قيد التحصيل،
وإن فيه «رسم تحصيل» اتخصم. السبب الحقيقي مش رسوم — ده باج في الترحيل:

InstrumentPostingService::STATUS_MAP كانت بتسمع لحالة 'under_collection'
بس، لكن شاشة «إيداع بالبنك» بتحط الحالة 'deposited'. يعني إيداع الشيك
في البنك ما كانش بيولّد أي قيد خالص (اتأكدت من الداتا: حركة الإيداع
للشيك TSTD-B1-NR بـ journal_entry_id = NULL).

فالحساب كان بيتقفل بالدائن وقت التحصيل (52,000) من غير ما يكون اتدين
وقت الإيداع — فيطلع رصيده بالسالب. والرقم اللي العميل شافه «104» هو
في الحقيقة 104,000 = مجموع الدائن (52,000 مرتين، لأن القيد المجمّع
اليومي كرّر نفس الحركة وبعدين اتعكس).

الإصلاح:
- 'deposited' اتضافت لـ STATUS_MAP، فالإيداع بقى يرحّل رجله:
  من ح/ شيكات تحت التحصيل إلى ح/ أوراق قبض.
- حارس منع تكرار: لو الورقة عدّت على 'deposited' وبعدين 'under_collection'
  (والاتنين نفس الحدث المحاسبي) القيد بيتعمل مرة واحدة بس.

وأداة جديدة في شاشة سد الفجوات — تصفية رصيد شيكات تحت التحصيل:
السيناريو ده طبيعي جداً: نادي داخل على النظام وعنده رصيد مرحّل من السنة
اللي فاتت، رقم مجمّع من غير أرقام شيكات ولا أسماء، ولازم يتقفل وإلا
هيفضل ظاهر للأبد كأن فيه شيكات معلّقة. الشاشة بتوريه:
- رصيده الحالي، وكام منه شيكات متسجّلة فعلاً وكام رصيد مرحّل من غير شيكات
- وبيختار الرصيد راح فين: اتحصّل ودخل البنك / ارتد ورجع دين / تسوية رصيد قديم
- وبيدوّر على الحساب الطرف التاني بالاسم، والنظام بيعمل القيد في الاتجاه
  الصح (سواء الرصيد مدين أو دائن) ومش بيسمح بتصفية أكتر من الرصيد الموجود.
parent 42786176
...@@ -9,6 +9,7 @@ use App\Core\Response; ...@@ -9,6 +9,7 @@ use App\Core\Response;
use App\Modules\Accounting\Services\Revenue\AcademyContractImportService; use App\Modules\Accounting\Services\Revenue\AcademyContractImportService;
use App\Modules\Accounting\Services\Revenue\AccrualRunner; use App\Modules\Accounting\Services\Revenue\AccrualRunner;
use App\Modules\Accounting\Services\Revenue\GapToolService; use App\Modules\Accounting\Services\Revenue\GapToolService;
use App\Modules\Accounting\Services\UnderCollectionSettlementService;
/** /**
* سد الفجوات — the screen where an accountant closes what the scanner will not * سد الفجوات — the screen where an accountant closes what the scanner will not
...@@ -34,9 +35,39 @@ class GapController extends Controller ...@@ -34,9 +35,39 @@ class GapController extends Controller
'academyPending' => AcademyContractImportService::pending(), 'academyPending' => AcademyContractImportService::pending(),
'academyImported' => AcademyContractImportService::alreadyImported(), 'academyImported' => AcademyContractImportService::alreadyImported(),
'brokenLinks' => $ready ? GapToolService::brokenMemberLinks() : [], 'brokenLinks' => $ready ? GapToolService::brokenMemberLinks() : [],
'underCollection' => UnderCollectionSettlementService::currentBalance(),
'settleReasons' => UnderCollectionSettlementService::REASONS,
]); ]);
} }
/**
* تصفية رصيد «شيكات تحت التحصيل» المرحّل من سنة سابقة.
*
* رصيد بيدخل النظام كرقم مجمّع من غير أرقام شيكات، فمحتاج قفل يدوي
* بقرار من المحاسب — مش حاجة النظام يقدر يستنتجها لوحده.
*/
public function settleUnderCollection(Request $request): Response
{
$this->authorize('accounting.gaps.manage');
$result = UnderCollectionSettlementService::settle(
trim((string) $request->post('amount', '0')),
(string) $request->post('reason', ''),
(int) $request->post('counter_account_id', 0),
[
'note' => (string) $request->post('note', ''),
'date' => $request->post('date') ?: date('Y-m-d'),
]
);
if (!($result['success'] ?? false)) {
return $this->redirect('/accounting/gaps')->withError($result['error']);
}
return $this->redirect('/accounting/gaps')
->withSuccess('تم تصفية ' . money($result['amount']) . ' من رصيد شيكات تحت التحصيل — قيد رقم ' . $result['journal_entry_id']);
}
/** /**
* الحالات اللي جوّه فجوة معيّنة — بيتفتحوا من زر «عرض التفاصيل» في الشاشة. * الحالات اللي جوّه فجوة معيّنة — بيتفتحوا من زر «عرض التفاصيل» في الشاشة.
*/ */
......
...@@ -211,6 +211,7 @@ return [ ...@@ -211,6 +211,7 @@ return [
['GET', '/accounting/gaps/details', 'Accounting\\Controllers\\GapController@details', ['auth'], 'accounting.gaps.view'], ['GET', '/accounting/gaps/details', 'Accounting\\Controllers\\GapController@details', ['auth'], 'accounting.gaps.view'],
['POST', '/accounting/gaps', 'Accounting\Controllers\GapController@save', ['auth', 'csrf'], 'accounting.gaps.manage'], ['POST', '/accounting/gaps', 'Accounting\Controllers\GapController@save', ['auth', 'csrf'], 'accounting.gaps.manage'],
['POST', '/accounting/gaps/academy-contracts', 'Accounting\Controllers\GapController@importAcademyContracts', ['auth', 'csrf'], 'accounting.gaps.manage'], ['POST', '/accounting/gaps/academy-contracts', 'Accounting\Controllers\GapController@importAcademyContracts', ['auth', 'csrf'], 'accounting.gaps.manage'],
['POST', '/accounting/gaps/under-collection', 'Accounting\Controllers\GapController@settleUnderCollection', ['auth', 'csrf'], 'accounting.gaps.manage'],
// ── Branch fee settings (per-branch policy, government withholding) ── // ── Branch fee settings (per-branch policy, government withholding) ──
['GET', '/accounting/branch-fees', 'Accounting\Controllers\BranchFeeController@index', ['auth'], 'accounting.branch_fees.view'], ['GET', '/accounting/branch-fees', 'Accounting\Controllers\BranchFeeController@index', ['auth'], 'accounting.branch_fees.view'],
......
...@@ -76,6 +76,12 @@ final class InstrumentPostingService ...@@ -76,6 +76,12 @@ final class InstrumentPostingService
/** Which ledger leg a status change corresponds to, by instrument direction. */ /** Which ledger leg a status change corresponds to, by instrument direction. */
private const STATUS_MAP = [ private const STATUS_MAP = [
'received' => [ 'received' => [
// «تسليم للبنك» و«تحت التحصيل» نفس الحدث المحاسبي: الورقة خرجت من
// أوراق القبض ودخلت تحت التحصيل. شاشة الإيداع بتحط الحالة
// 'deposited'، وكانت مش موجودة هنا — فالإيداع ما كانش بيرحّل أي
// قيد، والنتيجة إن حساب «تحت التحصيل» بيتقفل بالدائن وقت التحصيل
// من غير ما يكون اتدين أصلاً، فيطلع رصيده بالسالب.
'deposited' => 'instrument:deposited',
'under_collection' => 'instrument:deposited', 'under_collection' => 'instrument:deposited',
'collected' => 'instrument:collected', 'collected' => 'instrument:collected',
'bounced' => 'instrument:bounced', 'bounced' => 'instrument:bounced',
...@@ -87,6 +93,42 @@ final class InstrumentPostingService ...@@ -87,6 +93,42 @@ final class InstrumentPostingService
], ],
]; ];
/**
* هل رجل القيد دي اترحّلت قبل كده للورقة دي؟
*
* بنقارن بكل الحالات اللي بتودّي لنفس الـ stream، عشان لو الورقة عدّت
* على «تسليم للبنك» وبعدين «تحت التحصيل» ما يتعملش قيدين لنفس الحركة.
*
* @return int|null رقم القيد الموجود، أو null لو لسه ما اترحّلش
*/
private static function alreadyPosted(string $direction, string $stream, int $instrumentId): ?int
{
if ($instrumentId <= 0) {
return null;
}
$statuses = array_keys(array_filter(
self::STATUS_MAP[$direction] ?? [],
static fn ($s) => $s === $stream
));
if (!$statuses) {
return null;
}
$refTypes = array_map(static fn ($s) => 'instrument_' . $s, $statuses);
$in = implode(',', array_fill(0, count($refTypes), '?'));
$row = App::getInstance()->db()->selectOne(
"SELECT id FROM journal_entries
WHERE reference_id = ? AND reference_type IN ({$in})
AND status <> 'reversed' AND is_archived = 0
LIMIT 1",
array_merge([$instrumentId], $refTypes)
);
return $row ? (int) $row['id'] : null;
}
/** /**
* Post the ledger movement for a status change. * Post the ledger movement for a status change.
* *
...@@ -114,6 +156,13 @@ final class InstrumentPostingService ...@@ -114,6 +156,13 @@ final class InstrumentPostingService
$leg = self::LEGS[$stream]; $leg = self::LEGS[$stream];
// نفس الحدث ممكن يتسجّل بأكتر من حالة (تسليم للبنك ثم تحت التحصيل)،
// فلازم نتأكد إن رجل القيد دي ما اترحّلتش قبل كده للورقة دي.
$already = self::alreadyPosted($direction, $stream, (int) ($instrument['id'] ?? 0));
if ($already !== null) {
return ['posted' => false, 'journal_entry_id' => $already, 'error' => null];
}
// The bank leg follows the instrument's own bank account when it has one, // The bank leg follows the instrument's own bank account when it has one,
// so a club with several banks does not need a rule per bank. // so a club with several banks does not need a rule per bank.
$counterId = self::resolveLegAccount($leg['counter'], $instrument); $counterId = self::resolveLegAccount($leg['counter'], $instrument);
......
<?php
declare(strict_types=1);
namespace App\Modules\Accounting\Services;
use App\Core\App;
use App\Core\Logger;
use App\Modules\Accounting\Services\Revenue\PostingRouter;
/**
* تصفية رصيد «شيكات تحت التحصيل» المرحّل من سنة سابقة.
*
* السيناريو الطبيعي: النادي داخل على النظام وعنده رصيد في حساب «شيكات تحت
* التحصيل» جاي من السنة اللي فاتت — رقم مجمّع من غير أرقام شيكات ولا أسماء.
* الرصيد ده لازم يتقفل، وإلا هيفضل ظاهر للأبد كأن فيه شيكات لسه معلّقة.
*
* الشاشة بتقول له رصيده كام دلوقتي، وبيختار الرصيد راح فين:
* - اتحصّل فعلاً ودخل البنك → من ح/ البنك إلى ح/ تحت التحصيل
* - ارتد ورجع دين على العميل → من ح/ المدينين إلى ح/ تحت التحصيل
* - رصيد وهمي من ترحيل قديم غلط → من ح/ تسوية فروق إلى ح/ تحت التحصيل
*
* ولو الرصيد دائن (الحساب اتقفل من غير ما يتفتح — بيحصل لما الإيداع ما
* رحّلش قيده)، بيتعمل العكس: يتدين تحت التحصيل ويتدائن الطرف التاني.
*/
final class UnderCollectionSettlementService
{
private const SCALE = 2;
/** الطرق المتاحة لتصفية الرصيد. */
public const REASONS = [
'collected' => [
'label' => 'اتحصّل فعلاً ودخل البنك',
'hint' => 'البنك حصّل الشيكات وحوّل قيمتها — اختار الحساب البنكي اللي دخل فيه.',
'pointer' => 'bank',
],
'bounced' => [
'label' => 'ارتد ورجع دين على العميل',
'hint' => 'الشيكات ارتدّت والمبلغ رجع مديونية على العميل.',
'pointer' => 'receivable',
],
'adjustment' => [
'label' => 'رصيد قديم غير صحيح — تسوية',
'hint' => 'الرصيد ده جاي من ترحيل قديم غلط ومالوش شيكات فعلية وراه.',
'pointer' => 'adjustment',
],
];
/** رصيد حساب «شيكات تحت التحصيل» الحالي. */
public static function currentBalance(): array
{
$db = App::getInstance()->db();
$accountId = self::underCollectionAccountId();
if ($accountId === null) {
return [
'ok' => false,
'error' => 'حساب «شيكات تحت التحصيل» مش مربوط — اربطه من شاشة توزيع الإيرادات',
'balance' => '0.00',
];
}
$row = $db->selectOne(
"SELECT COALESCE(SUM(jel.debit),0) AS d, COALESCE(SUM(jel.credit),0) AS c
FROM journal_entry_lines jel
JOIN journal_entries je ON je.id = jel.journal_entry_id
WHERE jel.account_id = ? AND je.status = 'posted' AND je.is_archived = 0",
[$accountId]
);
$debit = (string) ($row['d'] ?? '0');
$credit = (string) ($row['c'] ?? '0');
$balance = bcsub($debit, $credit, self::SCALE);
$account = $db->selectOne(
"SELECT account_code, name_ar FROM chart_of_accounts WHERE id = ?",
[$accountId]
);
// الأوراق اللي لسه فعلاً تحت التحصيل — الفرق بينها وبين الرصيد هو
// الجزء المرحّل اللي ملوش شيكات وراه.
$open = $db->selectOne(
"SELECT COALESCE(SUM(amount),0) AS n, COUNT(*) AS c
FROM negotiable_instruments
WHERE direction = 'receivable'
AND status IN ('deposited','under_collection')
AND is_archived = 0"
);
$tracked = (string) ($open['n'] ?? '0');
return [
'ok' => true,
'account_id' => $accountId,
'account_code' => $account['account_code'] ?? '',
'account_name' => $account['name_ar'] ?? 'شيكات تحت التحصيل',
'total_debit' => $debit,
'total_credit' => $credit,
'balance' => $balance,
'tracked' => $tracked,
'tracked_count' => (int) ($open['c'] ?? 0),
'untracked' => bcsub($balance, $tracked, self::SCALE),
];
}
/**
* تصفية الرصيد بقيد واحد.
*
* @param string $amount المبلغ المراد تصفيته (موجب دايماً)
* @param string $reason مفتاح من REASONS
* @param int $counterAccountId الحساب الطرف التاني
*/
public static function settle(string $amount, string $reason, int $counterAccountId, array $options = []): array
{
if (!isset(self::REASONS[$reason])) {
return ['success' => false, 'error' => 'سبب التصفية غير معروف'];
}
if (bccomp($amount, '0.01', self::SCALE) < 0) {
return ['success' => false, 'error' => 'المبلغ لازم يكون أكبر من صفر'];
}
$state = self::currentBalance();
if (!$state['ok']) {
return ['success' => false, 'error' => $state['error']];
}
$accountId = (int) $state['account_id'];
if ($counterAccountId <= 0 || $counterAccountId === $accountId) {
return ['success' => false, 'error' => 'اختار حساب طرف تاني مختلف عن حساب تحت التحصيل'];
}
$db = App::getInstance()->db();
$counter = $db->selectOne(
"SELECT id, name_ar FROM chart_of_accounts
WHERE id = ? AND is_header = 0 AND is_active = 1 AND is_archived = 0",
[$counterAccountId]
);
if (!$counter) {
return ['success' => false, 'error' => 'الحساب الطرف التاني غير صالح للترحيل عليه'];
}
$balance = $state['balance'];
$isDebitBalance = bccomp($balance, '0', self::SCALE) > 0;
// ما ينفعش نصفّي أكتر من الرصيد الموجود
$abs = $isDebitBalance ? $balance : bcmul($balance, '-1', self::SCALE);
if (bccomp($amount, $abs, self::SCALE) > 0) {
return [
'success' => false,
'error' => 'المبلغ أكبر من الرصيد الحالي (' . $abs . ') — مينفعش تصفّي أكتر منه',
];
}
$label = self::REASONS[$reason]['label'];
$desc = 'تصفية رصيد شيكات تحت التحصيل — ' . $label;
if (!empty($options['note'])) {
$desc .= ' — ' . trim((string) $options['note']);
}
// رصيد مدين => نقفله بالدائن والطرف التاني مدين
// رصيد دائن => العكس
$lines = $isDebitBalance
? [
['account_id' => $counterAccountId, 'debit' => $amount, 'credit' => '0.00', 'description_ar' => $desc],
['account_id' => $accountId, 'debit' => '0.00', 'credit' => $amount, 'description_ar' => $desc],
]
: [
['account_id' => $accountId, 'debit' => $amount, 'credit' => '0.00', 'description_ar' => $desc],
['account_id' => $counterAccountId, 'debit' => '0.00', 'credit' => $amount, 'description_ar' => $desc],
];
$result = JournalService::createEntry([
'entry_date' => $options['date'] ?? date('Y-m-d'),
'description_ar' => $desc,
'reference_type' => 'under_collection_settlement',
'reference_number' => $reason,
'source_module' => 'accounting',
'is_auto_generated' => 0,
], $lines, true);
if (!($result['success'] ?? false)) {
return ['success' => false, 'error' => $result['error'] ?? 'فشل إنشاء القيد'];
}
Logger::info('UnderCollectionSettlementService: settled ' . $amount . ' as ' . $reason,
['journal_entry_id' => $result['journal_entry_id']]);
return [
'success' => true,
'journal_entry_id' => (int) $result['journal_entry_id'],
'amount' => $amount,
'direction' => $isDebitBalance ? 'credit_out' : 'debit_out',
];
}
/** حساب «تحت التحصيل» من نفس المؤشّر اللي الأوراق التجارية بتستخدمه. */
private static function underCollectionAccountId(): ?int
{
// نفس الـ router اللي InstrumentPostingService بيرحّل بيه، عشان الشاشة
// دي تقفل نفس الحساب اللي الأوراق التجارية بتفتحه — مش حساب تاني.
$id = PostingRouter::accountFor('instrument:under_collection_account', '1207', 'collection');
if ($id) {
return (int) $id;
}
$row = App::getInstance()->db()->selectOne(
"SELECT id FROM chart_of_accounts
WHERE account_code = '1207' AND is_header = 0 AND is_archived = 0 LIMIT 1"
);
return $row ? (int) $row['id'] : null;
}
}
...@@ -163,6 +163,130 @@ ...@@ -163,6 +163,130 @@
</div> </div>
<?php endforeach; ?> <?php endforeach; ?>
<!-- ══ رصيد شيكات تحت التحصيل المرحّل ══ -->
<?php if (!empty($underCollection['ok'])): ?>
<?php
$ucBal = (string) $underCollection['balance'];
$ucIsZero = bccomp($ucBal, '0', 2) === 0;
$ucAbs = bccomp($ucBal, '0', 2) > 0 ? $ucBal : bcmul($ucBal, '-1', 2);
$ucIsCredit = bccomp($ucBal, '0', 2) < 0;
?>
<div class="card" style="margin-bottom:14px;border-right:3px solid <?= $ucIsZero ? '#059669' : '#D97706' ?>;">
<div style="padding:15px 20px;">
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:10px;">
<h3 style="margin:0;font-size:15px;">
رصيد «<?= e($underCollection['account_name']) ?>»
<code style="font-size:12px;color:#6B7280;"><?= e($underCollection['account_code']) ?></code>
</h3>
<span style="font-weight:700;font-size:16px;direction:ltr;color:<?= $ucIsZero ? '#059669' : ($ucIsCredit ? '#DC2626' : '#D97706') ?>;">
<?= money($ucAbs) ?> <?= $ucIsZero ? '' : ($ucIsCredit ? 'دائن' : 'مدين') ?>
</span>
</div>
<?php if ($ucIsZero): ?>
<p style="margin:10px 0 0;color:#059669;font-size:12.5px;">
الحساب مقفول — مفيش رصيد معلّق.
</p>
<?php else: ?>
<p style="margin:10px 0 0;color:#6B7280;font-size:12.5px;line-height:1.9;">
منهم <strong><?= money($underCollection['tracked']) ?></strong> شيكات متسجّلة فعلاً في النظام
(<?= (int) $underCollection['tracked_count'] ?> ورقة)، والباقي
<strong><?= money($underCollection['untracked']) ?></strong> رصيد مرحّل من غير شيكات وراه.
</p>
<?php if ($ucIsCredit): ?>
<div style="margin-top:10px;padding:10px 12px;background:#FEF2F2;border:1px solid #FECACA;border-radius:7px;color:#991B1B;font-size:12.5px;line-height:1.9;">
الرصيد <strong>دائن</strong>، ودي حالة غير طبيعية لحساب أصول: معناها إن
الشيك اتحصّل (اتقفل الحساب بالدائن) من غير ما يكون اتسلّم للبنك الأول
(اللي بيدين الحساب). التصفية تحت هتظبّط الفرق.
</div>
<?php endif; ?>
<?php if (can('accounting.gaps.manage')): ?>
<form method="POST" action="/accounting/gaps/under-collection" style="margin-top:14px;"
onsubmit="return confirm('هيتعمل قيد بالمبلغ ده. متأكد؟');">
<?= csrf_field() ?>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px;align-items:end;">
<div>
<label class="form-label" style="font-size:12px;">المبلغ</label>
<input type="number" step="0.01" min="0.01" max="<?= e($ucAbs) ?>" name="amount"
value="<?= e($ucAbs) ?>" class="form-input" required
style="direction:ltr;text-align:left;">
</div>
<div>
<label class="form-label" style="font-size:12px;">الرصيد ده راح فين؟</label>
<select name="reason" id="ucReason" class="form-select" required>
<?php foreach (($settleReasons ?? []) as $key => $r): ?>
<option value="<?= e($key) ?>" data-hint="<?= e($r['hint']) ?>"><?= e($r['label']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div style="position:relative;">
<label class="form-label" style="font-size:12px;">الحساب الطرف التاني</label>
<input type="text" id="ucAccSearch" class="form-input" autocomplete="off"
placeholder="ابحث باسم الحساب أو كوده...">
<input type="hidden" name="counter_account_id" id="ucAccId" required>
<div id="ucAccResults" style="display:none;position:absolute;z-index:40;inset-inline:0;top:100%;margin-top:4px;background:#fff;border:1px solid #E5E7EB;border-radius:8px;box-shadow:0 6px 18px rgba(0,0,0,.1);max-height:230px;overflow:auto;"></div>
</div>
<div>
<label class="form-label" style="font-size:12px;">التاريخ</label>
<input type="date" name="date" value="<?= e(date('Y-m-d')) ?>" class="form-input">
</div>
</div>
<div style="display:flex;gap:12px;align-items:end;margin-top:10px;flex-wrap:wrap;">
<div style="flex:1;min-width:220px;">
<label class="form-label" style="font-size:12px;">ملاحظة (بتتكتب في بيان القيد)</label>
<input type="text" name="note" class="form-input" placeholder="مثال: رصيد مرحّل من 2025">
</div>
<button type="submit" class="btn btn-primary">تصفية الرصيد</button>
</div>
<p id="ucHint" style="margin:8px 0 0;color:#6B7280;font-size:12px;"></p>
</form>
<script>
(function(){
var reason=document.getElementById('ucReason'), hint=document.getElementById('ucHint');
function sync(){ if(reason&&hint) hint.textContent = reason.selectedOptions[0].dataset.hint || ''; }
if(reason){ reason.addEventListener('change',sync); sync(); }
var box=document.getElementById('ucAccSearch'), hid=document.getElementById('ucAccId'),
res=document.getElementById('ucAccResults'), timer=null;
if(!box) return;
box.addEventListener('input',function(){
var q=this.value.trim(); hid.value='';
clearTimeout(timer);
if(q.length<2){res.style.display='none';return;}
timer=setTimeout(function(){
fetch('/accounting/journal-entries/search-accounts?q='+encodeURIComponent(q),
{headers:{'X-Requested-With':'XMLHttpRequest'}})
.then(function(r){return r.json();})
.then(function(rows){
res.innerHTML='';
var list=rows.results||rows||[];
if(!list.length){res.innerHTML='<div style="padding:9px 12px;color:#6B7280;font-size:12.5px;">مفيش نتائج</div>';res.style.display='';return;}
list.forEach(function(a){
var d=document.createElement('div');
d.style.cssText='padding:8px 12px;cursor:pointer;border-bottom:1px solid #F3F4F6;font-size:12.5px;';
d.textContent=(a.account_code||a.code||'')+' — '+(a.name_ar||a.text||'');
d.addEventListener('mouseenter',function(){d.style.background='#F9FAFB';});
d.addEventListener('mouseleave',function(){d.style.background='';});
d.addEventListener('click',function(){
hid.value=a.id; box.value=d.textContent; res.style.display='none';
});
res.appendChild(d);
});
res.style.display='';
}).catch(function(){res.style.display='none';});
},300);
});
document.addEventListener('click',function(e){ if(!box.parentNode.contains(e.target)) res.style.display='none'; });
})();
</script>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<!-- ══ Players linked to a member that does not exist ══ --> <!-- ══ Players linked to a member that does not exist ══ -->
<?php if (!empty($brokenLinks)): ?> <?php if (!empty($brokenLinks)): ?>
<?php <?php
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment