110 lines
5.5 KiB
Python
110 lines
5.5 KiB
Python
import os
|
|
import csv
|
|
import datetime
|
|
|
|
# ============================================================================
|
|
# ۱. تنظیمات محیطی جنگو (بسیار مهم)
|
|
# ============================================================================
|
|
# نام 'myproject' را با نام پوشه اصلی پروژه خود (که فایل settings.py در آنجاست) عوض کنید
|
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'khatibi.settings')
|
|
|
|
import django
|
|
django.setup()
|
|
|
|
from django.db.models import Sum, Subquery, OuterRef, F, IntegerField
|
|
from django.db.models.functions import Coalesce
|
|
from admin_panel.models import Article, Sarresid, Customer
|
|
|
|
# ============================================================================
|
|
# ۲. هسته اصلی محاسبات (الگوریتم پرسرعت با Subquery)
|
|
# ============================================================================
|
|
def run_audit():
|
|
print("\n" + "="*65)
|
|
print(" 🚀 در حال اسکن دیتابیس و اجرای عملیات مغایرتگیری هوشمند...")
|
|
print("="*65 + "\n")
|
|
|
|
# واکشی سریع مجموع بدهکاری مشتریان
|
|
sq_debit = Article.objects.filter(
|
|
customer=OuterRef('pk')
|
|
).values('customer').annotate(s=Sum('debit')).values('s')
|
|
|
|
# واکشی سریع مجموع بستانکاری مشتریان
|
|
sq_credit = Article.objects.filter(
|
|
customer=OuterRef('pk')
|
|
).values('customer').annotate(s=Sum('credit')).values('s')
|
|
|
|
# واکشی سریع مجموع اسناد (چک/نسیه) پرداختنشده
|
|
sq_sarresid = Sarresid.objects.filter(
|
|
customer=OuterRef('pk'), payStatus="false"
|
|
).values('customer').annotate(s=Sum('price')).values('s')
|
|
|
|
# پردازش نهایی در لایه دیتابیس (بدون نیاز به لود کردن دیتا در RAM سرور)
|
|
base_customers = Customer.objects.filter(is_active=True).annotate(
|
|
t_debit=Coalesce(Subquery(sq_debit, output_field=IntegerField()), 0),
|
|
t_credit=Coalesce(Subquery(sq_credit, output_field=IntegerField()), 0),
|
|
t_sarresid=Coalesce(Subquery(sq_sarresid, output_field=IntegerField()), 0),
|
|
).annotate(
|
|
net_debt=F('t_debit') - F('t_credit') # تراز نهایی
|
|
).annotate(
|
|
diff=F('net_debt') - F('t_sarresid') # اختلاف تراز و اسناد
|
|
)
|
|
|
|
# استخراج گروه اول: بدهکاران مطلقاً بدون چک
|
|
group1 = base_customers.filter(net_debt__gt=0, t_sarresid=0).order_by('-net_debt')
|
|
|
|
# استخراج گروه دوم: دارای خطای چک اضافی در سیستم
|
|
group2 = base_customers.filter(diff__lt=0, t_sarresid__gt=0).annotate(
|
|
fake_amount=F('t_sarresid') - F('net_debt')
|
|
).order_by('-fake_amount')
|
|
|
|
# ============================================================================
|
|
# ۳. نمایش گزارش در کنسول
|
|
# ============================================================================
|
|
print(f"🔴 گروه اول: بدهکاران فاقد سند/چک (تعداد: {group1.count()})")
|
|
print("-" * 65)
|
|
for c in group1[:10]: # نمایش ۱۰ نفر اول در کنسول
|
|
print(f"👤 {c.name_family} | موبایل: {c.phone1} | بدهی روی هوا: {c.net_debt:,} ریال")
|
|
if group1.count() > 10:
|
|
print(f" ... و {group1.count() - 10} نفر دیگر (لیست کامل در فایل خروجی)")
|
|
|
|
print("\n" + f"🟡 گروه دوم: دارای خطای ثبت چک اضافه (تعداد: {group2.count()})")
|
|
print("-" * 65)
|
|
for c in group2[:10]:
|
|
print(f"👤 {c.name_family} | تراز واقعی: {c.net_debt:,} | مبلغ چک تو سیستم: {c.t_sarresid:,} | ❌ چک اضافی: {c.fake_amount:,}")
|
|
if group2.count() > 10:
|
|
print(f" ... و {group2.count() - 10} نفر دیگر (لیست کامل در فایل خروجی)")
|
|
|
|
# ============================================================================
|
|
# ۴. تولید فایل خروجی CSV برای حسابدار
|
|
# ============================================================================
|
|
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
filename = f"financial_audit_{timestamp}.csv"
|
|
|
|
with open(filename, mode='w', newline='', encoding='utf-8-sig') as file:
|
|
writer = csv.writer(file)
|
|
|
|
# هدر فایل
|
|
writer.writerow(["شناسه مشتری", "نام و نام خانوادگی", "شماره تماس", "گروه خطا", "شرح خطا", "تراز واقعی (Article)", "جمع اسناد در دست (Sarresid)", "مبلغ مغایرت"])
|
|
|
|
# نوشتن دیتای گروه اول
|
|
for c in group1:
|
|
writer.writerow([
|
|
c.id, c.name_family, c.phone1,
|
|
"گروه 1 (خطرناک)", "بدهی دفتری باز - بدون چک یا موعد نسیه",
|
|
c.net_debt, c.t_sarresid, c.diff
|
|
])
|
|
|
|
# نوشتن دیتای گروه دوم
|
|
for c in group2:
|
|
writer.writerow([
|
|
c.id, c.name_family, c.phone1,
|
|
"گروه 2 (خطای ثبتی)", "چک پاس نشده در سیستم بیشتر از بدهی واقعی است",
|
|
c.net_debt, c.t_sarresid, c.fake_amount
|
|
])
|
|
|
|
print("\n" + "="*65)
|
|
print(f"✅ عملیات با موفقیت انجام شد. فایل گزارش تولید شد: {filename}")
|
|
print("="*65 + "\n")
|
|
|
|
if __name__ == '__main__':
|
|
run_audit() |