"""مانده حساب مشتری برای استفاده در قالب‌های پیامک. تعریف (همان قاعدهٔ صفحهٔ حسابداری مشتری و گزارش مالی):: مانده حساب = مجموع بدهکار (debit) − مجموع بستانکار (credit) نکتهٔ مهم — تفاوت با «مانده سررسیدشده»: * **مانده حساب** (این ماژول): تراز کل همهٔ اسناد حسابداری مشتری (``Article``). منبع: ``admin_panel/models/finance.py::Article``. * **مانده/مبلغ سررسیدشده**: مبلغ چک‌ها و نسیه‌های پرداخت‌نشده در جدول ``Sarresid`` (``payStatus='false'``). بسیار متفاوت از مانده حساب است و جای دیگری (``views/finance.py``) محاسبه می‌شود. به همین دلیل این مقدار با کلید مستقل ``{balance}`` در قالب‌ها منتشر می‌شود و هرگز با مبلغ سررسید (``{amount}`` در پیامک چک/نسیه) قاطی نمی‌شود. """ import logging logger = logging.getLogger(__name__) def customer_balance(customer): """مانده حساب مشتری (``debit − credit``) به‌صورت عدد صحیح. اگر مشتری یا اسنادش وجود نداشته باشد ``0`` برمی‌گردد. هیچ استثنایی پرتاب نمی‌کند تا مسیر ساخت پیامک هرگز مختل نشود. """ if customer is None or getattr(customer, "pk", None) is None: return 0 try: from django.db.models import Sum from ..models import Article agg = Article.objects.filter(customer=customer).aggregate( d=Sum("debit"), c=Sum("credit"), ) debit = agg["d"] or 0 credit = agg["c"] or 0 return debit - credit except Exception: logger.exception("محاسبهٔ مانده حساب مشتری %s شکست خورد", customer.pk) return 0