gozaresh vosol motalebat
This commit is contained in:
1 parent
0d867367f9
commit
99a86c7073
4 files changed
+404
-1
No files matched your search
+112
-1
@@ -22,7 +22,7 @@ from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.decorators.http import require_POST
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest # بخشBadRequest جدید
|
||||
from django.db import transaction, connection
|
||||
from django.db.models import Count, Sum, Q, Avg, F, Subquery, OuterRef, IntegerField
|
||||
from django.db.models import Count, Sum, Q, Avg, F, Subquery, OuterRef, IntegerField, Exists, Min, Max, Case, When
|
||||
from django.contrib.auth.models import Permission, User
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
@@ -196,6 +196,117 @@ def report(request):
|
||||
data = {'nahvePardakhat': nahvePardakhat, 'userHa':userHa}
|
||||
return render(request, 'admin_panel/report.html', data)
|
||||
|
||||
|
||||
@login_required(login_url='/panel/p_login/')
|
||||
@permission_required('admin_panel.ViewReportMali', raise_exception=True)
|
||||
def report_debtors_no_vosol(request):
|
||||
now = datetime.datetime.now()
|
||||
|
||||
# --- ۱. دریافت و اعتبارسنجی پارامترهای فیلتر از فرانتاند ---
|
||||
try:
|
||||
days_threshold = int(request.GET.get('days', 20))
|
||||
if days_threshold < 0:
|
||||
days_threshold = 20
|
||||
except ValueError:
|
||||
days_threshold = 20
|
||||
|
||||
filter_type = request.GET.get('filter_type', 'all') # all, never, expired
|
||||
sort_field = request.GET.get('sort', 'amount') # amount, oldest_date, last_action
|
||||
sort_dir = request.GET.get('dir', 'desc') # asc, desc
|
||||
|
||||
threshold_date = now - datetime.timedelta(days=days_threshold)
|
||||
|
||||
# --- ۲. ساخت Subquery های فوقسریع و ایمن ---
|
||||
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_overdue_amt = Sarresid.objects.filter(
|
||||
customer=OuterRef('pk'), payStatus='false', sarresidDT__lte=now
|
||||
).values('customer').annotate(s=Sum('price')).values('s')
|
||||
|
||||
sq_oldest_date = Sarresid.objects.filter(
|
||||
customer=OuterRef('pk'), payStatus='false', sarresidDT__lte=now
|
||||
).values('customer').annotate(min_dt=Min('sarresidDT')).values('min_dt')
|
||||
|
||||
sq_overdue_count = Sarresid.objects.filter(
|
||||
customer=OuterRef('pk'), payStatus='false', sarresidDT__lte=now
|
||||
).values('customer').annotate(c=Count('id')).values('c')
|
||||
|
||||
# استخراج آخرین سابقه اکشن وصول
|
||||
latest_vosol_qs = Action.objects.filter(
|
||||
customer=OuterRef('pk'), actionType='vosol'
|
||||
).order_by('-createdDT')
|
||||
|
||||
# --- ۳. ساخت کوئری پایه (فقط مشتریان فعال و دارای معوقه) ---
|
||||
base_qs = Customer.objects.filter(is_active=True).annotate(
|
||||
t_debit=Coalesce(Subquery(sq_debit, output_field=IntegerField()), Value(0)),
|
||||
t_credit=Coalesce(Subquery(sq_credit, output_field=IntegerField()), Value(0)),
|
||||
overdue_amount=Coalesce(Subquery(sq_overdue_amt, output_field=IntegerField()), Value(0)),
|
||||
overdue_count=Coalesce(Subquery(sq_overdue_count, output_field=IntegerField()), Value(0)),
|
||||
oldest_overdue_date=Subquery(sq_oldest_date),
|
||||
last_vosol_date=Subquery(latest_vosol_qs.values('createdDT')[:1]),
|
||||
last_vosol_desc=Subquery(latest_vosol_qs.values('desc')[:1])
|
||||
).annotate(
|
||||
net_debt=F('t_debit') - F('t_credit')
|
||||
).filter(
|
||||
overdue_amount__gt=0 # شرط اساسی: فقط کسانی که معوقه سررسید گذشته دارند
|
||||
)
|
||||
|
||||
# استخراج مشتریانی که نیازمند پیگیری هستند (هرگز پیگیری نشدهاند یا موعد پیگیریشان گذشته است)
|
||||
action_needed_qs = base_qs.filter(
|
||||
Q(last_vosol_date__isnull=True) | Q(last_vosol_date__lt=threshold_date)
|
||||
)
|
||||
|
||||
# --- ۴. محاسبه آمار دقیق (بدون خطا) برای داشبورد ---
|
||||
# استفاده از Case/When برای جلوگیری کامل از خطای None در Aggregate
|
||||
stats = action_needed_qs.aggregate(
|
||||
never_count=Coalesce(Sum(Case(When(last_vosol_date__isnull=True, then=1), default=Value(0), output_field=IntegerField())), Value(0)),
|
||||
never_amount=Coalesce(Sum(Case(When(last_vosol_date__isnull=True, then=F('overdue_amount')), default=Value(0), output_field=IntegerField())), Value(0)),
|
||||
expired_count=Coalesce(Sum(Case(When(last_vosol_date__isnull=False, then=1), default=Value(0), output_field=IntegerField())), Value(0)),
|
||||
expired_amount=Coalesce(Sum(Case(When(last_vosol_date__isnull=False, then=F('overdue_amount')), default=Value(0), output_field=IntegerField())), Value(0)),
|
||||
)
|
||||
|
||||
# --- ۵. اعمال فیلتر کشویی (Dropdown) ---
|
||||
if filter_type == 'never':
|
||||
final_qs = action_needed_qs.filter(last_vosol_date__isnull=True)
|
||||
elif filter_type == 'expired':
|
||||
final_qs = action_needed_qs.filter(last_vosol_date__isnull=False)
|
||||
else: # all
|
||||
final_qs = action_needed_qs
|
||||
|
||||
# --- ۶. اعمال مرتبسازی (Sorting) پویا ---
|
||||
if sort_field == 'amount':
|
||||
order_expr = F('overdue_amount').desc() if sort_dir == 'desc' else F('overdue_amount').asc()
|
||||
elif sort_field == 'oldest_date':
|
||||
order_expr = F('oldest_overdue_date').desc(nulls_last=True) if sort_dir == 'desc' else F('oldest_overdue_date').asc(nulls_last=True)
|
||||
elif sort_field == 'last_action':
|
||||
order_expr = F('last_vosol_date').desc(nulls_last=True) if sort_dir == 'desc' else F('last_vosol_date').asc(nulls_first=True)
|
||||
else:
|
||||
order_expr = F('overdue_amount').desc()
|
||||
|
||||
final_qs = final_qs.order_by(order_expr)
|
||||
|
||||
# --- ۷. صفحهبندی ایمن ---
|
||||
paginator = Paginator(final_qs, 50)
|
||||
page_number = request.GET.get('page', 1)
|
||||
try:
|
||||
page_obj = paginator.page(page_number)
|
||||
except (PageNotAnInteger, EmptyPage):
|
||||
page_obj = paginator.page(1)
|
||||
|
||||
context = {
|
||||
'page_obj': page_obj,
|
||||
'page_name': 'debtors_no_vosol',
|
||||
'stats': stats,
|
||||
# پارامترهای کنترل پنل
|
||||
'current_days': days_threshold,
|
||||
'current_filter': filter_type,
|
||||
'current_sort': sort_field,
|
||||
'current_dir': sort_dir,
|
||||
}
|
||||
|
||||
return render(request, 'admin_panel/report_debtors_no_vosol.html', context)
|
||||
|
||||
@login_required(login_url='/panel/p_login/')
|
||||
@permission_required('admin_panel.ViewReportMali', raise_exception=True)
|
||||
def inventory_movements_report(request):
|
||||
|
||||
Reference in new issue
Block a user