Commit 9245247e authored by DevPilot's avatar DevPilot

fix(accounting): المطابقة تقارن حساب الذمم مش إجمالي الدفتر

أول ما شغّلت الشاشة على عضو حقيقي طلّعت «فرق ٣٦٣ ألف» على عضو حسابه سليم.
السبب: القيد بيتعلّم برقم العضو على الطرفين (مدين الصندوق / دائن الإيراد)،
فجمع كل سطوره بيطلّع صفر دايمًا والفرق مالوش معنى.

المطابقة الصح بتقارن رصيد العضو في حسابات الذمم (١٢٠٣/١٢٠٤ للعملاء،
٢٣٠٦ للموردين) بالحساب المساعد. والعضو اللي بيدفع نقدي وقت العملية
مالوش حساب ذمم أصلًا، فبقت الشاشة بتقول كده صريح بدل تحذير غلط.
parent 7a6dba5d
...@@ -35,11 +35,12 @@ class PartyStatementController extends Controller ...@@ -35,11 +35,12 @@ class PartyStatementController extends Controller
$partyId = 0; $partyId = 0;
} }
$ledger = $subledger = $recon = null; $ledger = $subledger = $recon = $control = null;
if ($partyId > 0) { if ($partyId > 0) {
$ledger = PartyStatementService::ledger($type, $partyId, $from, $to); $ledger = PartyStatementService::ledger($type, $partyId, $from, $to);
$subledger = PartyStatementService::subledger($type, $partyId, $from, $to); $subledger = PartyStatementService::subledger($type, $partyId, $from, $to);
$recon = PartyStatementService::reconcile($ledger, $subledger); $control = PartyStatementService::controlBalance($type, $partyId, $to);
$recon = PartyStatementService::reconcile($control, $subledger);
} }
return $this->view('Accounting.Views.statements.party', [ return $this->view('Accounting.Views.statements.party', [
...@@ -54,6 +55,7 @@ class PartyStatementController extends Controller ...@@ -54,6 +55,7 @@ class PartyStatementController extends Controller
'ledger' => $ledger, 'ledger' => $ledger,
'subledger' => $subledger, 'subledger' => $subledger,
'recon' => $recon, 'recon' => $recon,
'control' => $control,
]); ]);
} }
......
...@@ -150,20 +150,73 @@ final class PartyStatementService ...@@ -150,20 +150,73 @@ final class PartyStatementService
return self::withRunningBalance($rows, $opening); return self::withRunningBalance($rows, $opening);
} }
/** بادئات حسابات الذمم — العملاء وأوراق القبض والمدينون / الموردون. */
private const CONTROL_PREFIXES = [
'member' => ['1203', '1204'], // العملاء وأوراق القبض، مدينون
'supplier' => ['2306'], // الموردون وأوراق الدفع
];
/** /**
* المطابقة بين الدفترين. * رصيد الطرف في حساب الذمم بالدفتر — ده الوحيد اللي ينفع يتقارن
* بالحساب المساعد.
* *
* @return array{matches:bool, difference:string, ledger_closing:string, subledger_closing:string} * ليه مش إجمالي الدفتر: القيد بيتعلّم برقم العضو على الطرفين
* (مدين الصندوق / دائن الإيراد)، فلو جمعنا كل سطوره الفرق بيطلع صفر
* دايمًا وما يعنيش حاجة. الرصيد الحقيقي للعضو هو اللي في حساب الذمم بس.
*
* @return array{balance:string, lines:int}
*/ */
public static function reconcile(array $ledger, array $subledger): array public static function controlBalance(string $type, int $id, string $to): array
{ {
$diff = bcsub($ledger['closing'], $subledger['closing'], 2); $db = App::getInstance()->db();
$key = $type === 'supplier' ? 'jel.supplier_id' : 'jel.member_id';
$prefixes = self::CONTROL_PREFIXES[$type] ?? self::CONTROL_PREFIXES['member'];
$conds = implode(' OR ', array_fill(0, count($prefixes), 'coa.account_code LIKE ?'));
$params = array_map(fn($p) => $p . '%', $prefixes);
$row = $db->selectOne(
"SELECT COALESCE(SUM(jel.debit) - SUM(jel.credit), 0) AS balance, COUNT(*) AS lines
FROM journal_entry_lines jel
JOIN journal_entries je ON je.id = jel.journal_entry_id
JOIN chart_of_accounts coa ON coa.id = jel.account_id
WHERE {$key} = ? AND je.status = 'posted' AND je.is_archived = 0
AND je.entry_date <= ?
AND ({$conds})",
array_merge([$id, $to], $params)
);
return [
'balance' => (string) ($row['balance'] ?? '0.00'),
'lines' => (int) ($row['lines'] ?? 0),
];
}
/**
* المطابقة: حساب الذمم في الدفتر مقابل الحساب المساعد.
*
* لو الطرف ما لهوش أي سطر في حساب الذمم، يبقى تعاملاته نقدية بالكامل
* ومفيش حاجة تتطابق — بنقولها صريح بدل ما نطلّع تحذير فرق مالوش معنى.
*
* @return array{status:string, difference:string, control_balance:string,
* subledger_closing:string, control_lines:int}
*/
public static function reconcile(array $control, array $subledger): array
{
$diff = bcsub($control['balance'], $subledger['closing'], 2);
if ($control['lines'] === 0) {
$status = bccomp($subledger['closing'], '0.00', 2) === 0 ? 'clean' : 'cash_only';
} else {
$status = bccomp($diff, '0.00', 2) === 0 ? 'matched' : 'mismatch';
}
return [ return [
'matches' => bccomp($diff, '0.00', 2) === 0, 'status' => $status,
'difference' => $diff, 'difference' => $diff,
'ledger_closing' => $ledger['closing'], 'control_balance' => $control['balance'],
'subledger_closing' => $subledger['closing'], 'subledger_closing' => $subledger['closing'],
'control_lines' => $control['lines'],
]; ];
} }
......
...@@ -67,24 +67,40 @@ ...@@ -67,24 +67,40 @@
</p> </p>
</div> </div>
<div style="text-align:left;"> <div style="text-align:left;">
<div style="color:#6B7280;font-size:11px;">رصيد آخر المدة (دفتر الأستاذ)</div> <div style="color:#6B7280;font-size:11px;">رصيد الذمم في الدفتر</div>
<div style="font-size:22px;font-weight:800;direction:ltr;"><?= money($ledger['closing']) ?></div> <div style="font-size:22px;font-weight:800;direction:ltr;"><?= money($recon['control_balance']) ?></div>
</div> </div>
</div> </div>
<?php <?php
$ok = $recon['matches']; // المطابقة بتقارن حساب الذمم بالحساب المساعد. مش بتقارن إجمالي الدفتر
$bg = $ok ? '#ECFDF5' : '#FEF2F2'; // لأن القيد بيتعلّم برقم الطرف على الطرفين، فالإجمالي بيطلع صفر دايمًا.
$bd = $ok ? '#A7F3D0' : '#FECACA'; $styles = [
$fg = $ok ? '#047857' : '#B91C1C'; 'matched' => ['#ECFDF5', '#A7F3D0', '#047857'],
'clean' => ['#F9FAFB', '#E5E7EB', '#374151'],
'cash_only' => ['#FFFBEB', '#FDE68A', '#92400E'],
'mismatch' => ['#FEF2F2', '#FECACA', '#B91C1C'],
];
[$bg, $bd, $fg] = $styles[$recon['status']] ?? $styles['clean'];
?> ?>
<div style="padding:12px 18px;background:<?= $bg ?>;border-top:1px solid <?= $bd ?>;font-size:13px;color:<?= $fg ?>;"> <div style="padding:12px 18px;background:<?= $bg ?>;border-top:1px solid <?= $bd ?>;font-size:13px;color:<?= $fg ?>;line-height:1.8;">
<?php if ($ok): ?> <?php if ($recon['status'] === 'matched'): ?>
<strong>الدفتران متطابقان.</strong> <strong>الدفتران متطابقان.</strong>
رصيد دفتر الأستاذ يساوي رصيد الحساب المساعد (<?= money($ledger['closing']) ?>). رصيد الذمم في الدفتر يساوي رصيد الحساب المساعد (<?= money($recon['control_balance']) ?>).
<?php elseif ($recon['status'] === 'clean'): ?>
<strong>مفيش رصيد مستحق.</strong>
الطرف ده كل تعاملاته اتسدّدت وقت العملية، فمالوش رصيد في حساب الذمم ولا في الحساب المساعد.
<?php elseif ($recon['status'] === 'cash_only'): ?>
<strong>تعاملات نقدية — مفيش حساب ذمم.</strong>
الحساب المساعد رصيده <?= money($recon['subledger_closing']) ?>، لكن مفيش أي قيد على حسابات
العملاء/الموردين للطرف ده، يعني العمليات كانت بتتسدّد فورًا. المطابقة هنا مالهاش معنى،
والجدولين تحت بيوضّحوا الحركة.
<?php else: ?> <?php else: ?>
<strong>في فرق بين الدفترين قدره <?= money(abs((float) $recon['difference'])) ?>.</strong> <strong>في فرق قدره <?= money(abs((float) $recon['difference'])) ?> بين حساب الذمم والحساب المساعد.</strong>
دفتر الأستاذ <?= money($recon['ledger_closing']) ?> والحساب المساعد <?= money($recon['subledger_closing']) ?>. الدفتر <?= money($recon['control_balance']) ?> والحساب المساعد <?= money($recon['subledger_closing']) ?>.
معنى كده إن في حركة اتسجّلت في ناحية وما اتقيّدتش في التانية — راجع «سد الفجوات». معنى كده إن في حركة اتسجّلت في ناحية وما اتقيّدتش في التانية — راجع «سد الفجوات».
<?php endif; ?> <?php endif; ?>
</div> </div>
...@@ -95,7 +111,7 @@ ...@@ -95,7 +111,7 @@
<?php <?php
$blocks = [ $blocks = [
['دفتر الأستاذ — القيود المرحّلة', $ledger, true], ['دفتر الأستاذ — كل القيود المرحّلة المرتبطة بالطرف', $ledger, true],
[$type === 'supplier' ? 'الحساب المساعد — الدائنون' : 'الحساب المساعد — المدينون', $subledger, false], [$type === 'supplier' ? 'الحساب المساعد — الدائنون' : 'الحساب المساعد — المدينون', $subledger, false],
]; ];
foreach ($blocks as [$title, $data, $isLedger]): foreach ($blocks as [$title, $data, $isLedger]):
......
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