Commit d46bd960 authored by Mahmoud Aglan's avatar Mahmoud Aglan

fix(installments): guarantee new cheques exactly cover remaining installment amount

- genPreview: compute lastAmt = remaining - amt*(needed-1) to show exact
  total; display grand total (existing + new) when cheques already exist;
  highlight preview red if lastAmt would be ≤ 0
- generateCheques: guard against per-cheque amount too large (lastAmt ≤ 0)
  with clear Arabic error showing max allowed per-cheque value; last cheque
  always = remaining - amt*(needed-1) so existing+new always = PLAN_TOTAL
Co-Authored-By: 's avatarClaude Sonnet 4.6 <noreply@anthropic.com>
parent 7b060cb6
......@@ -302,18 +302,31 @@ $coveragePct = $planTotal > 0 ? min(100, round($uploadedTotal / $planTotal * 10
if (!amt || amt <= 0 || REMAINING_COUNT <= 0) { box.style.display='none'; return; }
// Count is driven by REMAINING_COUNT (cheques still needed), not by amount math
var needed = REMAINING_COUNT;
var endNum = NEXT_NUM_FOR_PLAN + needed - 1;
var lastAmt = Math.round((PLAN_TOTAL - ALREADY_UPLOADED - amt * (needed - 1)) * 100) / 100;
var total = amt * (needed - 1) + lastAmt;
var needed = REMAINING_COUNT;
var remaining = Math.round((PLAN_TOTAL - ALREADY_UPLOADED) * 100) / 100;
var endNum = NEXT_NUM_FOR_PLAN + needed - 1;
var lastAmt = Math.round((remaining - amt * (needed - 1)) * 100) / 100;
// total of new cheques = amt*(needed-1) + lastAmt = exactly remaining amount
var newTotal = Math.round((amt * (needed - 1) + lastAmt) * 100) / 100;
// grand total = existing + new = must equal PLAN_TOTAL
var grandTotal = Math.round((ALREADY_UPLOADED + newTotal) * 100) / 100;
document.getElementById('genCount').textContent = needed;
document.getElementById('genAmtDisplay').textContent = fmt(amt);
document.getElementById('genTotalDisplay').textContent = fmt(total);
document.getElementById('genTotalDisplay').textContent =
fmt(newTotal) + (ALREADY_COUNT > 0 ? ' (إجمالي كل الشيكات: ' + fmt(grandTotal) + ')' : '');
document.getElementById('genNumRange').textContent =
(ALREADY_COUNT > 0)
? 'تكملة من #' + NEXT_NUM_FOR_PLAN + ' ← #' + endNum + ' (الموجود: ' + ALREADY_COUNT + ' شيك)'
? 'تكملة من #' + NEXT_NUM_FOR_PLAN + ' ← #' + endNum + ' (الموجود: ' + ALREADY_COUNT + ' شيك بقيمة ' + fmt(ALREADY_UPLOADED) + ')'
: '#' + NEXT_NUM_FOR_PLAN + ' ← #' + endNum;
if (lastAmt <= 0) {
box.style.background = '#FEF2F2';
box.style.border = '1px solid #FECACA';
} else {
box.style.background = '';
box.style.border = '';
}
box.style.display = '';
};
......@@ -323,13 +336,25 @@ $coveragePct = $planTotal > 0 ? min(100, round($uploadedTotal / $planTotal * 10
var bank = document.getElementById('gen_bank').value.trim();
var startDate = document.getElementById('gen_start_date').value;
if (!amt || amt <= 0) { alert('أدخل قيمة الشيك أولاً'); return; }
if (!bank) { alert('أدخل اسم البنك أولاً'); return; }
if (!startDate) { alert('أدخل تاريخ أول شيك'); return; }
if (!amt || amt <= 0) { alert('أدخل قيمة الشيك أولاً'); return; }
if (!bank) { alert('أدخل اسم البنك أولاً'); return; }
if (!startDate) { alert('أدخل تاريخ أول شيك'); return; }
if (REMAINING_COUNT <= 0) { alert('تم تسليم جميع الشيكات المطلوبة بالفعل'); return; }
var needed = REMAINING_COUNT;
var remaining = PLAN_TOTAL - ALREADY_UPLOADED;
var needed = REMAINING_COUNT;
var remaining = Math.round((PLAN_TOTAL - ALREADY_UPLOADED) * 100) / 100;
// Guard: per-cheque amount * (needed-1) must leave a positive last cheque
var lastAmt = Math.round((remaining - amt * (needed - 1)) * 100) / 100;
if (lastAmt <= 0) {
var maxAmt = Math.round((remaining / needed) * 100) / 100;
alert(
'قيمة الشيك كبيرة جداً — الشيك الأخير سيكون صفراً أو سالباً.\n' +
'الحد الأقصى المسموح: ' + maxAmt.toFixed(2) + ' ج.م لكل شيك\n' +
'(المبلغ المتبقي ' + remaining.toFixed(2) + ' ج.م ÷ ' + needed + ' شيكات)'
);
return;
}
rows = [];
for (var i = 0; i < needed; i++) {
......@@ -338,10 +363,8 @@ $coveragePct = $planTotal > 0 ? min(100, round($uploadedTotal / $planTotal * 10
cheque_number: String(NEXT_NUM_FOR_PLAN + i),
bank_name: bank,
cheque_date: addMonths(startDate, i),
// Last cheque absorbs any rounding difference
cheque_amount: isLast
? Math.round((remaining - amt * (needed - 1)) * 100) / 100
: amt,
// Last cheque absorbs rounding difference to guarantee total = PLAN_TOTAL
cheque_amount: isLast ? lastAmt : amt,
notes: '',
});
}
......
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