from django.shortcuts import redirect, render, get_object_or_404 from django.urls.base import reverse from django.urls import reverse # تکراری در کد اصلی شما بود، اما جهت عدم تغییر حفظ شد from persiantools.jdatetime import JalaliDate from persiantools import characters, digits import datetime from django.utils import timezone # جدید from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage from django.core.exceptions import ValidationError # جدید 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 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 import os import json # جدید import logging # جدید from .models import * logger = logging.getLogger(__name__) class InventoryException(Exception): """خطای اختصاصی برای کنترل موجودی انبار""" pass def _safe_int(value, default=0): """تابع امن برای تبدیل مقادیر دریافتی از جاوااسکریپت به عدد""" if value is None: return default try: clean_val = str(value).strip() return int(clean_val) if clean_val else default except (ValueError, TypeError): return default def _parse_jalali_date(date_str): """تبدیل امن تاریخ ارسالی از pDatepicker به میلادی""" if not date_str or not str(date_str).strip(): return None try: clean_date = digits.fa_to_en(digits.ar_to_fa(str(date_str).strip())) y, m, d = map(int, clean_date.split("/")) return JalaliDate(y, m, d).to_gregorian() except Exception as e: logger.warning(f"Error parsing Jalali date '{date_str}': {e}") return None def _parse_timestamp(ts_value): """تبدیل یونیکس تایم‌استمپ‌های ارسالی از جاوااسکریپت""" if not ts_value: return None try: # تبدیل میلی‌ثانیه جاوااسکریپت به ثانیه پایتون return datetime.datetime.fromtimestamp(int(ts_value) / 1000.0, tz=timezone.get_current_timezone()) except (ValueError, TypeError): return None def p_login(request): username = request.POST.get('username', None ) password = request.POST.get('password', None ) if username != None and password != None: if not request.user.is_authenticated: user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect("/panel/ActionList/"+str(request.user.id)+"/today") else: data = {'message': 'یوزنیم یا پسورد اشتباه است'} return render(request, 'admin_panel/login.html', data) else: return redirect("/panel/") else: if request.user.is_authenticated: return redirect("/panel/") else: return render(request, 'admin_panel/login.html') #return logout(request) def p_logout(request): logout(request) return redirect("/panel/p_login/") @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewReportMali', raise_exception=True) def report(request): nahvePardakhat = [ {'fa': 'تخفیف', 'en': 'تخفیف'}, {'fa': 'نسیه', 'en': 'نسیه'}, {'fa': 'چک', 'en': 'چک'}, {'fa': 'کارتخوان', 'en': 'کارت خوان'}, {'fa': 'کارت به کارت', 'en': 'کارت به کارت'}, {'fa': 'نقدی', 'en': 'نقد'}, ] userHa = User.objects.filter() if request.method == "GET": nahvePardakht = request.GET.get("nahvepardakht", None) user = request.GET.get("user", None) azTarikh = request.GET.get("azTarikh", None) taTarikh = request.GET.get("taTarikh", None) pagenumber = request.GET.get("page", None) if azTarikh and nahvePardakht: query_data = { 'nahvePardakht': nahvePardakht, 'user': user, 'azTarikh': azTarikh, 'taTarikh': taTarikh, } azDateTime = datetime.datetime.fromtimestamp(int(azTarikh) / 1e3) azDateTime = azDateTime.strftime('%Y-%m-%d 00:00:00') taDateTime = datetime.datetime.fromtimestamp(int(taTarikh) / 1e3) taDateTime = taDateTime.strftime('%Y-%m-%d 23:59:59') print("b") user_a = User.objects.get(username=user) print(user_a) if nahvePardakht == "نسیه" or nahvePardakht == "چک": if nahvePardakht == 'نسیه': typeSarresid = 'nesiye' elif nahvePardakht == 'چک': typeSarresid = 'check' sumSarresidha = Sarresid.objects.filter( type=typeSarresid, user=user_a, createdDT__lte=taDateTime, createdDT__gte=azDateTime, payStatus='false' ).aggregate(Sum('price')) sarresidha = Sarresid.objects.filter( type=typeSarresid, user=user_a, createdDT__lte=taDateTime, createdDT__gte=azDateTime, payStatus='false' ) paginator = Paginator(sarresidha, 25) # Show 25 contacts per page. page_number = request.GET.get('page', None) all_sarresidha = paginator.get_page(pagenumber) data = {'sarresidha': all_sarresidha ,'sumSarresidha': sumSarresidha, 'nahvePardakhat': nahvePardakhat, 'userHa':userHa, 'query_data': query_data} return render(request, 'admin_panel/reportCheckNesiye.html', data) else: sumAricles = Article.objects.filter( nahvePardakht=nahvePardakht, user=user_a, createdDT__lte=taDateTime, createdDT__gte=azDateTime, ).aggregate(Sum('credit')) aricles1 = Article.objects.filter( nahvePardakht=nahvePardakht, user=user_a, createdDT__lte=taDateTime, createdDT__gte=azDateTime, ) paginator = Paginator(aricles1, 25) # Show 25 contacts per page. page_number = request.GET.get('page', None) all_aricles = paginator.get_page(page_number) data = {'aricles': all_aricles,'sum_credit': sumAricles, 'nahvePardakhat': nahvePardakhat, 'userHa':userHa, 'query_data': query_data} return render(request, 'admin_panel/report.html', data) else: data = {'nahvePardakhat': nahvePardakhat, 'userHa':userHa} return render(request, 'admin_panel/report.html', data) 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 inventory_movements_report(request): """ گزارش جامع گردش و خروج کالا از انبار به همراه فیلتر متنی نام کالا، نوع تراکنش، کاربر، انبار و بازه زمانی شمسی. """ all_users = User.objects.all().order_by('first_name') all_stores = StoreRoom.objects.all() movement_choices = ProductInStore.MovementType.choices # دریافت پارامترهای فیلتر از فرانت‌اند selected_type = request.GET.get('movement_type', '') selected_user = request.GET.get('user_id', '') selected_store = request.GET.get('store_id', '') selected_product_name = request.GET.get('product_name', '').strip() # فیلد جدید جستجوی نام کالا az_tarikh = request.GET.get('azTarikh', '') ta_tarikh = request.GET.get('taTarikh', '') # ۱. کوئری پایه بهینه movements_list = ProductInStore.objects.select_related( 'Product', 'StoreRoom', 'factor__customer', 'factor__user' ).filter(year=1400).order_by('-createdDT') # ۲. اعمال فیلترهای پویا if selected_type: movements_list = movements_list.filter(movement_type=selected_type) if selected_user: movements_list = movements_list.filter(factor__user__id=_safe_int(selected_user)) if selected_store: movements_list = movements_list.filter(StoreRoom__id=_safe_int(selected_store)) if selected_product_name: # فیلتر متنی حساس نبودن به حروف بزرگ و کوچک (Case-Insensitive Contains) movements_list = movements_list.filter(Product__product_name__icontains=selected_product_name) # ۳. پردازش بازه زمانی if az_tarikh: try: az_dt = datetime.datetime.fromtimestamp(int(az_tarikh) / 1000.0) movements_list = movements_list.filter(createdDT__gte=az_dt.strftime('%Y-%m-%d 00:00:00')) except (ValueError, TypeError): pass if ta_tarikh: try: ta_dt = datetime.datetime.fromtimestamp(int(ta_tarikh) / 1000.0) movements_list = movements_list.filter(createdDT__lte=ta_dt.strftime('%Y-%m-%d 23:59:59')) except (ValueError, TypeError): pass # ۴. محاسبه آماری سریع دیتابیس روی نتایج فیلتر شده summary_stats = movements_list.aggregate( total_out_qty=Sum('s_out'), total_in_qty=Sum('s_in') ) # ۵. صفحه‌بندی نتایج paginator = Paginator(movements_list, 50) page_number = request.GET.get('page') page_obj = paginator.get_page(page_number) context = { 'page_obj': page_obj, 'all_users': all_users, 'all_stores': all_stores, 'movement_choices': movement_choices, 'summary_stats': summary_stats, 'filters': { 'movement_type': selected_type, 'user_id': _safe_int(selected_user) if selected_user else '', 'store_id': _safe_int(selected_store) if selected_store else '', 'product_name': selected_product_name, # ارسال فیلد جدید به قالب برای حفظ مقدار ورودی 'azTarikh': az_tarikh, 'taTarikh': ta_tarikh, } } return render(request, 'admin_panel/report_inventory_movements.html', context) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewReportMali', raise_exception=True) def financial_dashboard(request): """ داشبورد هوش مالی و مدیریت نقدینگی سطح Enterprise (BI Dashboard) همراه با روند ۱۲ ماهه جمع کل بدهی مشتریان (تفاضل debit و credit). """ # دریافت تایم‌استمپ‌های ارسالی از تقویم شمسی فرانت‌اند az_tarikh = request.GET.get('azTarikh', '') ta_tarikh = request.GET.get('taTarikh', '') az_dt = None ta_dt = None if az_tarikh: try: az_dt = datetime.datetime.fromtimestamp(int(az_tarikh) / 1000.0) az_dt = az_dt.replace(hour=0, minute=0, second=0) except (ValueError, TypeError): pass if ta_tarikh: try: ta_dt = datetime.datetime.fromtimestamp(int(ta_tarikh) / 1000.0) ta_dt = ta_dt.replace(hour=23, minute=59, second=59) except (ValueError, TypeError): pass # نقطه اتکا (لنگر) محاسبات: زمان انتخابی کاربر یا زمان حال anchor_dt = ta_dt if ta_dt else datetime.datetime.now() # ========================================================================= # محاسبه روند ۱۲ ماهه غلتان (TTM) - نسخه اصلاح‌شده و امن # ========================================================================= jalali_months = ['فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور', 'مهر', 'آبان', 'آذر', 'دی', 'بهمن', 'اسفند'] trend_labels = [] trend_data = [] # روش استاندارد و بدون باگ برای تبدیل تاریخ میلادی به شمسی در persiantools # با این کار مطمئن می‌شویم مقادیر حتماً عدد صحیح و مجاز هستند anchor_jd = JalaliDate(anchor_dt.date()) curr_y = int(anchor_jd.year) curr_m = int(anchor_jd.month) # حلقه استخراج داده برای ۱۲ ماه گذشته for _ in range(12): if curr_m < 1: curr_m = 12 curr_y -= 1 label = f"{jalali_months[curr_m - 1]} {curr_y}" trend_labels.insert(0, label) # ❗️ اصلاح اساسی: ترتیب آرگومان‌ها در این تابع باید (month, year) باشد last_day = JalaliDate.days_in_month(curr_m, curr_y) # اما ترتیب سازنده کلاس اصلی همچنان (year, month, day) است end_of_month_jd = JalaliDate(curr_y, curr_m, last_day) end_of_month_gd = end_of_month_jd.to_gregorian() # ساخت رشته زمان برای پایان آن ماه (تا ساعت 23:59:59) end_dt_str = end_of_month_gd.strftime('%Y-%m-%d 23:59:59') # محاسبه مانده حساب کل تا پایان این ماه totals = Article.objects.filter(createdDT__lte=end_dt_str).aggregate( t_deb=Sum('debit'), t_cred=Sum('credit') ) t_deb = totals['t_deb'] or 0 t_cred = totals['t_cred'] or 0 month_total_debt = t_deb - t_cred trend_data.insert(0, month_total_debt) # شیفت به ماه قبل برای دور بعدی حلقه curr_m -= 1 # ========================================================================= # قرنطینه داده‌های سایر بخش‌های داشبورد بر اساس سال مالی ۱۴۰۰ # ========================================================================= sarresid_qs = Sarresid.objects.filter(factor__productinstore__year=1400).distinct() factor_qs = Factor.objects.filter(productinstore__year=1400, is_active=True).distinct() article_qs = Article.objects.filter(factor__productinstore__year=1400).distinct() store_qs = ProductInStore.objects.filter(year=1400) if az_dt: sarresid_qs = sarresid_qs.filter(createdDT__gte=az_dt) factor_qs = factor_qs.filter(create_date__gte=az_dt) article_qs = article_qs.filter(createdDT__gte=az_dt) store_qs = store_qs.filter(createdDT__gte=az_dt) if ta_dt: sarresid_qs = sarresid_qs.filter(createdDT__lte=ta_dt) factor_qs = factor_qs.filter(create_date__lte=ta_dt) article_qs = article_qs.filter(createdDT__lte=ta_dt) store_qs = store_qs.filter(createdDT__lte=ta_dt) # ۱. محاسبات کارت‌های شاخص عملکرد (KPI Cards) total_unpaid_debts = sarresid_qs.filter(payStatus="false").aggregate(Sum('price'))['price__sum'] or 0 total_sales_period = factor_qs.aggregate(Sum('amount'))['amount__sum'] or 0 overdue_checks_count = sarresid_qs.filter(payStatus="false", type="check", sarresidDT__lte=anchor_dt).count() # ۲. نمودار اول: تحلیل پویای سن مطالبات debt_future = sarresid_qs.filter(payStatus="false", sarresidDT__gt=anchor_dt).aggregate(Sum('price'))['price__sum'] or 0 dt_30_days_ago = anchor_dt - datetime.timedelta(days=30) debt_0_30 = sarresid_qs.filter(payStatus="false", sarresidDT__lte=anchor_dt, sarresidDT__gte=dt_30_days_ago).aggregate(Sum('price'))['price__sum'] or 0 dt_90_days_ago = anchor_dt - datetime.timedelta(days=90) debt_30_90 = sarresid_qs.filter(payStatus="false", sarresidDT__lt=dt_30_days_ago, sarresidDT__gte=dt_90_days_ago).aggregate(Sum('price'))['price__sum'] or 0 debt_above_90 = sarresid_qs.filter(payStatus="false", sarresidDT__lt=dt_90_days_ago).aggregate(Sum('price'))['price__sum'] or 0 # ۳. نمودار دوم: ماتریس کیفیت ورودی پول payment_articles = article_qs.filter(credit__gt=0).values('nahvePardakht').annotate(total_amount=Sum('credit')).order_by('-total_amount') pay_labels = [] pay_data = [] for item in payment_articles: label = item['nahvePardakht'] or 'سایر/نامشخص' pay_labels.append(label) pay_data.append(item['total_amount']) # ۴. نمودار سوم: مانیتورینگ نشت انبار store_leaks = store_qs.filter( movement_type__in=[ProductInStore.MovementType.WARRANTY, ProductInStore.MovementType.PROMOTION] ).values('movement_type').annotate(total_qty=Sum('s_out')) leak_data = {'WARRANTY': 0, 'PROMOTION': 0} for leak in store_leaks: leak_data[leak['movement_type']] = leak['total_qty'] # ارسال ساختار داده به تمپلیت context = { 'kpi_total_unpaid': total_unpaid_debts, 'kpi_total_sales': total_sales_period, 'kpi_overdue_checks': overdue_checks_count, 'trend_labels': trend_labels, # نام ماه‌ها برای محور X 'trend_data': trend_data, # جمع کل بدهی‌ها برای محور Y 'aging_data': [debt_future, debt_0_30, debt_30_90, debt_above_90], 'pay_labels': pay_labels, 'pay_data': pay_data, 'warranty_qty': leak_data['WARRANTY'], 'promotion_qty': leak_data['PROMOTION'], 'filters': { 'azTarikh': az_tarikh, 'taTarikh': ta_tarikh, } } return render(request, 'admin_panel/financial_dashboard.html', context) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewReportMali', raise_exception=True) def bedehi(request): try: debit = Article.objects.filter().aggregate(Sum('debit'))['debit__sum'] credit = Article.objects.filter().aggregate(Sum('credit'))['credit__sum'] mandehesabCs = debit - credit articls = Article.objects.filter().order_by('-createdDT') articlsPaginator = Paginator(articls, 10) pageNumber = request.GET.get("page", 1) articl_objs = articlsPaginator.get_page(pageNumber) except: articls =None mandehesabCs = 0 data = {'articls': articl_objs, 'mandehesabKP': mandehesabCs} return render(request, 'admin_panel/bedehi.html', data) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewReportMali', raise_exception=True) def hesabdari(request): page_name = 'sarresidShodeha' anchor_dt = datetime.datetime.now() # تعریف محدوده‌های زمانی ماتریس ریسک (سن مطالبات) dt_30_days_ago = anchor_dt - datetime.timedelta(days=30) dt_90_days_ago = anchor_dt - datetime.timedelta(days=90) # کوئری پایه: تمام سررسیدهای پرداخت‌نشده که از موعد آن‌ها گذشته است base_qs = Sarresid.objects.filter(payStatus="false", sarresidDT__lte=anchor_dt) # محاسبه پرسرعت مجموع مبالغ در هر دسته (توسط موتور دیتابیس) matrix_totals = base_qs.aggregate( minor_delay=Sum('price', filter=Q(sarresidDT__gte=dt_30_days_ago)), high_risk=Sum('price', filter=Q(sarresidDT__lt=dt_30_days_ago, sarresidDT__gte=dt_90_days_ago)), critical=Sum('price', filter=Q(sarresidDT__lt=dt_90_days_ago)), total_sum=Sum('price') ) # دریافت فیلتر انتخابی کاربر از URL risk_filter = request.GET.get('risk_level', 'all') # اعمال فیلتر روی لیست نمایش داده شده if risk_filter == 'minor': filtered_qs = base_qs.filter(sarresidDT__gte=dt_30_days_ago) elif risk_filter == 'high': filtered_qs = base_qs.filter(sarresidDT__lt=dt_30_days_ago, sarresidDT__gte=dt_90_days_ago) elif risk_filter == 'critical': filtered_qs = base_qs.filter(sarresidDT__lt=dt_90_days_ago) else: filtered_qs = base_qs # مرتب‌سازی: قدیمی‌ترین‌ها (خطرناک‌ترین‌ها) در صدر جدول قرار می‌گیرند filtered_qs = filtered_qs.order_by('sarresidDT') page_number = request.GET.get('page', 1) paginator = Paginator(filtered_qs, per_page=50) all_sarresid_pgi = paginator.get_page(page_number) data = { 'page_name': page_name, 'dateNow': anchor_dt.strftime('%Y-%m-%d %H:%M:%S'), 'all_sarresid': all_sarresid_pgi, 'current_filter': risk_filter, # متغیرهای ماتریس ریسک 'sum_sarresid': matrix_totals['total_sum'] or 0, 'minor_sum': matrix_totals['minor_delay'] or 0, 'high_sum': matrix_totals['high_risk'] or 0, 'critical_sum': matrix_totals['critical'] or 0, } return render(request, 'admin_panel/hesabdari.html', data) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewReportMali', raise_exception=True) def hesabdari_checkPass(request): page_name = 'checkPass' dateNow = datetime.datetime.today().strftime('%Y-%m-%d 23:59:59') all_sarresid = Sarresid.objects.filter(payStatus="true", type='check').order_by('-sarresidDT') page_number = request.GET.get('page', None) paginator = Paginator(all_sarresid, per_page=50) all_sarresid_pgi = paginator.get_page(page_number) #paginator = Paginator(all_sarresid, per_page=200) data = {'all_sarresid': all_sarresid_pgi, "dateNow":dateNow, "page_name":page_name} return render(request, 'admin_panel/hesabdari.html', data) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewReportMali', raise_exception=True) def hesabdari_checkPassFail(request): page_name = 'checkPassFaild' dateNow = datetime.datetime.today().strftime('%Y-%m-%d 23:59:59') all_sarresid = Sarresid.objects.filter(payStatus="false", type='check').order_by('sarresidDT') count_check_passfail = all_sarresid.count() sum_check_passfail = all_sarresid.aggregate(Sum('price'))['price__sum'] page_number = request.GET.get('page', None) paginator = Paginator(all_sarresid, per_page=50) all_sarresid_pgi = paginator.get_page(page_number) #paginator = Paginator(all_sarresid, per_page=200) data = {'all_sarresid': all_sarresid_pgi, 'sum_check_passfail':sum_check_passfail, 'count_check_passfail': count_check_passfail, "dateNow":dateNow, "page_name":page_name} return render(request, 'admin_panel/hesabdari.html', data) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewReportMali', raise_exception=True) def hesabdari_residnashone(request): page_name = 'sarresidNaShodeha' dateNow = datetime.datetime.today().strftime('%Y-%m-%d 23:59:59') all_sarresid = Sarresid.objects.filter(payStatus="false", sarresidDT__gte=dateNow).order_by('sarresidDT') sarresidNashode = all_sarresid.aggregate(Sum('price'))['price__sum'] page_number = request.GET.get('page', None) paginator = Paginator(all_sarresid, per_page=50) all_sarresid_pgi = paginator.get_page(page_number) #paginator = Paginator(all_sarresid, per_page=200) data = {'sarresidNashode': sarresidNashode,'all_sarresid': all_sarresid_pgi, "dateNow":dateNow, "page_name":page_name} return render(request, 'admin_panel/hesabdari.html', data) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewReportMali', raise_exception=True) def bedehiKhadamat(request): #bedehiKhadamat try: debit = Article.objects.filter(typePy='khadamat').aggregate(Sum('debit'))['debit__sum'] credit = Article.objects.filter(typePy='khadamat').aggregate(Sum('credit'))['credit__sum'] mandehesabCs = debit - credit articls = Article.objects.filter(typePy='khadamat').order_by('-createdDT')[:100] except: articls =None mandehesabCs = 0 data = {'articls': articls, 'mandehesabKP': mandehesabCs} return render(request, 'admin_panel/bedehi.html', data) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewReportMali', raise_exception=True) def bedehiNasb(request): try: debit = Article.objects.filter(typePy='nasb').aggregate(Sum('debit'))['debit__sum'] credit = Article.objects.filter(typePy='nasb').aggregate(Sum('credit'))['credit__sum'] mandehesabCs = debit - credit articls = Article.objects.filter(typePy='nasb').order_by('-createdDT')[:100] except: articls =None mandehesabCs = 0 data = {'articls': articls, 'mandehesabKP': mandehesabCs} return render(request, 'admin_panel/bedehi.html', data) @csrf_exempt @login_required(login_url='/panel/p_login/') def customers(request): searchVal = request.GET.get('searchVal', '') searchOn = request.GET.get('searchOn', '') searchStatus = True full_path = request.get_full_path() if searchOn == 'code': all_customers = Customer.objects.filter(idCode__contains=searchVal).order_by('-create_date') elif searchOn == 'phone': all_customers = Customer.objects.filter(Q(phone1__contains=searchVal) | Q(phone2__contains=searchVal) | Q(phone3__contains=searchVal) ).order_by('-create_date') elif searchOn == 'name': all_customers = Customer.objects.filter(name_family__contains=searchVal).order_by('-create_date') elif searchOn == 'address': all_customers = Customer.objects.filter(address__contains=searchVal).order_by('-create_date') elif searchOn == 'laghv': all_customers = Customer.objects.filter(laghv_bazdid=True).order_by('-create_date') else: searchStatus = False all_customers = Customer.objects.all().order_by('-create_date') paginator = Paginator(all_customers, 25) # Show 25 contacts per page. page_number = request.GET.get('page', None) all_customers = paginator.get_page(page_number) data = {'customersD': all_customers, 'searchStatus': searchStatus, 'full_path': full_path, 'searchVal': searchVal, 'searchOn':searchOn} return render(request, 'admin_panel/customers.html', data) @login_required(login_url='/panel/p_login/') def customersSearch(request, searchVal,searchOn): searchStatus = True if searchOn == 'code': all_customers = Customer.objects.filter(idCode__contains=searchVal).order_by('-create_date') elif searchOn == 'phone': all_customers = Customer.objects.filter(phone1__contains=searchVal).order_by('-create_date') elif searchOn == 'name': all_customers = Customer.objects.filter(name_family__contains=searchVal).order_by('-create_date') elif searchOn == 'address': all_customers = Customer.objects.filter(address__contains=searchVal).order_by('-create_date') else: searchStatus = False all_customers = Customer.objects.all().order_by('-create_date') paginator = Paginator(all_customers, 25) # Show 25 contacts per page. page_number = request.GET.get('page', None) all_customers = paginator.get_page(page_number) data = {'customersD': all_customers, 'searchStatus': searchStatus} return render(request, 'admin_panel/customers.html', data) @login_required(login_url='/panel/p_login/') def customer(request ,c_id): customer = Customer.objects.get(id=c_id) categorys = ProductCategory.objects.all() factorha = Factor.objects.filter(customer__id = c_id) #all_prd = serializers.serialize("json", all_prda) #return JsonResponse(all_prd,safe = False) dateNow = datetime.datetime.now().date data = {'customer': customer, 'categorys': categorys, 'dateNow': dateNow, 'factorha': factorha} return render(request, 'admin_panel/customerID.html', data) @login_required(login_url='/panel/p_login/') def customerNew(request ,c_id): customer = Customer.objects.get(id=c_id) categorys = ProductCategory.objects.all() factorha = Factor.objects.filter(customer__id = c_id) #all_prd = serializers.serialize("json", all_prda) #return JsonResponse(all_prd,safe = False) dateNow = datetime.datetime.now().date data = {'customer': customer, 'categorys': categorys, 'dateNow': dateNow, 'factorha': factorha} return render(request, 'admin_panel/customerNew.html', data) @login_required(login_url='/panel/p_login/') def customerNew2(request ,c_id): customer = Customer.objects.get(id=c_id) categorys = ProductCategory.objects.all() factorha = Factor.objects.filter(customer__id = c_id) debit = Article.objects.filter(customer=customer).aggregate(Sum('debit'))['debit__sum'] credit = Article.objects.filter(customer=customer).aggregate(Sum('credit'))['credit__sum'] mandehesabCs = 0 try: if (debit - credit) < 0: mandehesabCs = abs(debit - credit) except: pass #all_prd = serializers.serialize("json", all_prda) #return JsonResponse(all_prd,safe = False) dateNow = datetime.datetime.now().date data = {'customer': customer, 'categorys': categorys, 'dateNow': dateNow, 'factorha': factorha, 'mandehesabCs':mandehesabCs} return render(request, 'admin_panel/customerNew2.html', data) @login_required(login_url='/panel/p_login/') def customerFactors(request ,c_id): customer = Customer.objects.get(id=c_id) categorys = ProductCategory.objects.all() factorha = Factor.objects.filter(customer__id = c_id).order_by('-create_date') #all_prd = serializers.serialize("json", all_prda) #return JsonResponse(all_prd,safe = False) dateNow = datetime.datetime.now().date data = {'customer': customer, 'categorys': categorys, 'dateNow': dateNow, 'factorha': factorha} return render(request, 'admin_panel/customerIDFactor.html', data) @login_required(login_url='/panel/p_login/') def customerFactor(request ,c_id, f_id): customer = Customer.objects.get(id=c_id) categorys = ProductCategory.objects.all() factorO = Factor.objects.get(customer=customer, id=f_id) fiteam = FactorIteam.objects.filter(factor=factorO) #all_prd = serializers.serialize("json", all_prda) #return JsonResponse(all_prd,safe = False) dateNow = datetime.datetime.now().date data = {'customer': customer, 'categorys': categorys, 'dateNow': dateNow, 'factorO': factorO, 'fiteam': fiteam} return render(request, 'admin_panel/customerFactor.html', data) def productsJson(request): from django.core import serializers from django.http import JsonResponse all_prd = Product.objects.all() all_prd = serializers.serialize("json", all_prd) return JsonResponse(all_prd,safe = False) def ActionJson(request, action_id): from django.core import serializers from django.http import JsonResponse AcJson = Action.objects.filter(id=action_id) AcJson = serializers.serialize("json", AcJson) return JsonResponse(AcJson,safe = False) def CustomerJson(request, c_id): from django.core import serializers from django.http import JsonResponse customerJson = Customer.objects.filter(id=c_id) customerJson = serializers.serialize("json", customerJson) return JsonResponse(customerJson,safe = False) @login_required(login_url='/panel/p_login/') def productMojodi(request, p_id): storeUser = StoreRoom.objects.get(user__id=request.user.id) # ۱. تجمیع ورودی و خروجی در یک کوئری بهینه برای افزایش سرعت دیتابیس totals = ProductInStore.objects.filter( Product__id=p_id, StoreRoom=storeUser, year=1400 ).aggregate(total_in=Sum('s_in'), total_out=Sum('s_out')) # ۲. رفع باگ قطعی NoneType: اگر رکوردی نباشد، مقدار None را به 0 تبدیل می‌کند total_in = totals['total_in'] or 0 total_out = totals['total_out'] or 0 # ۳. محاسبه دقیق موجودی بدون ریسک بروز خطای ریاضی پایتون mojodi_prd = total_in - total_out # ۴. بازگشت خروجی دقیقاً متناسب با ساختار متنی فرانت‌اَند شما return HttpResponse(str(mojodi_prd)) @login_required(login_url='/panel/p_login/') def customersAdd(request): an_name = request.POST.get('an_name', '') an_address = request.POST.get('an_address', '') phone1 = request.POST.get('phone1', '') phone2 = request.POST.get('phone2', '') phone3 = request.POST.get('phone3', '') installDate = request.POST.get('installDate', '') idnCode = request.POST.get('idnCode', '') an_name = request.POST.get('an_name', '') year = int(installDate.split('/')[0]) month = int(installDate.split('/')[1]) day = int(installDate.split('/')[2]) #return HttpResponse(year) installDate = JalaliDate(year, month, day).to_gregorian() newCs = Customer() newCs.name_family = an_name newCs.address = an_address newCs.phone1 = phone1 newCs.phone2 = phone2 newCs.phone3 = phone3 newCs.installDate = installDate newCs.idCode = idnCode newCs.save() #return HttpResponse(installDate) return redirect('/panel/customers/') #return render(request, 'admin_panel/customersAdd.html') @login_required(login_url='/panel/p_login/') def customerEdit(request, c_id): an_name = request.POST.get('an_name', '') an_address = request.POST.get('an_address', '') phone1 = request.POST.get('phone1', '') phone2 = request.POST.get('phone2', '') phone3 = request.POST.get('phone3', '') installDate = request.POST.get('installDate', '') idnCode = request.POST.get('idnCode', '') laghv_bazdid = request.POST.get('laghv_bazdid', False) an_name = request.POST.get('an_name', '') year = int(installDate.split('/')[0]) month = int(installDate.split('/')[1]) day = int(installDate.split('/')[2]) #return HttpResponse(year) installDate = JalaliDate(year, month, day).to_gregorian() newCs = Customer.objects.get(id=c_id) newCs.name_family = an_name newCs.address = an_address newCs.phone1 = phone1 newCs.phone2 = phone2 newCs.phone3 = phone3 newCs.installDate = installDate newCs.idCode = idnCode if laghv_bazdid == 'true': newCs.laghv_bazdid = True else: newCs.laghv_bazdid = False newCs.save() #return HttpResponse(installDate) return redirect('/panel/customer/'+str(c_id)) @login_required(login_url='/panel/p_login/') def entezar(request): a = datetime.datetime.now() searchVal = request.GET.get('searchVal', '') searchOn = request.GET.get('searchOn', '') searchStatus = True full_path = request.get_full_path() from django.db.models import Q bazdid = os.environ.get('bazdid', 9) bazdid = int ( int(bazdid) * 4.3 ) dateTime6MonthAgo = a - datetime.timedelta(weeks=bazdid) ''' customers = Customer.objects.filter(name_family__isnull=False) m6mbazdid = [] for customerObj in customers: try: actionAa = Action.objects.filter(customer=customerObj, actionType='bazdid', status='finish').last() if actionAa.status == 'finish': customerObj.last_bazdid_dt = actionAa.actionDateTime customerObj.save() if actionAa.actionDateTime.date() < dateTime6MonthAgo.date(): m6mbazdid.append(actionAa) except: pass ''' if searchOn == 'address': print("addressaddressaddressaddressaddress") customers_objj = Customer.objects.filter(Q(last_bazdid_dt__lte=dateTime6MonthAgo) | Q(last_bazdid_dt__isnull=True), installDate__lte=dateTime6MonthAgo, laghv_bazdid=False, name_family__isnull=False, address__contains=searchVal).order_by('last_bazdid_dt') else: searchStatus = False customers_objj = Customer.objects.filter(Q(last_bazdid_dt__lte=dateTime6MonthAgo) | Q(last_bazdid_dt__isnull=True), installDate__lte=dateTime6MonthAgo, laghv_bazdid=False, name_family__isnull=False).order_by('last_bazdid_dt') #customers_objj = Customer.objects.filter(name_family__isnull=False, last_bazdid_dt__lte=dateTime6MonthAgo) try: entezar_bazdid = CacheTable.objects.get(key='9mahbazdid') entezar_bazdid.value = Customer.objects.filter( Q(last_bazdid_dt__lte=dateTime6MonthAgo) | Q(last_bazdid_dt__isnull=True), installDate__lte=dateTime6MonthAgo, laghv_bazdid=False, name_family__isnull=False).count() entezar_bazdid.save() except: pass paginator = Paginator(customers_objj, 20) # Show 25 contacts per page. page_number = request.GET.get('page', None) customerHa = paginator.get_page(page_number) return render(request, 'admin_panel/entezar.html', {'customers': customerHa, 'searchStatus': searchStatus, 'full_path': full_path, 'searchVal': searchVal, 'searchOn':searchOn}) @login_required(login_url='/panel/p_login/') def stores(request): if request.user.username not in ('admin', 'office1', 'office2', 'office3', 'khatibi'): all_store = StoreRoom.objects.filter(user__id=request.user.id).order_by('id')[:20] else: all_store = StoreRoom.objects.all().order_by('id')[:20] data = {'all_store': all_store} return render(request, 'admin_panel/stores.html', data) @login_required(login_url='/panel/p_login/') def store(request, s_id): productCategory = ProductCategory.objects.all() storeO = StoreRoom.objects.get(id=s_id) searchStatus = False searchQS = request.POST.get('searchQS', '') mojodi = request.POST.get('mojodi', '') #return HttpResponse(mojodi) if searchQS !='': productSum = Product.objects.filter(productinstore__StoreRoom=storeO ,productinstore__year=1400,product_name__contains=searchQS).annotate(mojodi=( Sum('productinstore__s_in') - Sum('productinstore__s_out') )) if mojodi == "0": productSum = productSum.filter(mojodi__lte=0) searchStatus = True else: productSum = Product.objects.filter(productinstore__StoreRoom=storeO ,productinstore__year=1400).annotate(mojodi=( Sum('productinstore__s_in') - Sum('productinstore__s_out') )) if mojodi == "0": searchStatus = True productSum = productSum.filter(mojodi__lte=0) data = {'storeO': storeO,'productSum': productSum, 's_id': s_id, 'searchStatus': searchStatus, "mojodi": mojodi, 'djsearchQS':searchQS, 'productCategory': productCategory} return render(request, 'admin_panel/store.html', data) @login_required(login_url='/panel/p_login/') #@permission_required('admin_panel.ViewStore', raise_exception=True) def operations(request, s_id): page = request.GET.get('page', 1) productCategory = ProductCategory.objects.all() storeO = get_object_or_404(StoreRoom, id=s_id) # بهینه‌سازی کلیدی: استفاده از select_related برای جلوگیری از کندی و پر شدن RAM دیتابیس operationsList = ProductInStore.objects.filter( StoreRoom=storeO, year=1400 ).select_related('Product').order_by('-createdDT') paginator = Paginator(operationsList, 25) try: data_list = paginator.page(page) except PageNotAnInteger: data_list = paginator.page(1) except EmptyPage: data_list = paginator.page(paginator.num_pages) data = { 'storeO': storeO, 'operationsList': data_list, 's_id': s_id, 'productCategory': productCategory } return render(request, 'admin_panel/operations.html', data) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewStore', raise_exception=True) def operationProduct(request, s_id, p_id): productCategory = ProductCategory.objects.all() storeO = get_object_or_404(StoreRoom, id=s_id) # بهینه‌سازی کلیدی در فیلتر اختصاصی محصول operationsList = ProductInStore.objects.filter( StoreRoom=storeO, year=1400, Product__id=p_id ).select_related('Product').order_by('-createdDT') data = { 'storeO': storeO, 'operationsList': operationsList, 's_id': s_id, 'productCategory': productCategory } return render(request, 'admin_panel/operations.html', data) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewStore', raise_exception=True) def newOperation(request, s_id, p_id): productCategory = ProductCategory.objects.all() storeO = StoreRoom.objects.get(id=s_id) allStores = StoreRoom.objects.exclude(id=s_id) product = Product.objects.get(id=p_id) data = {'s_id': s_id,'p_id': p_id, 'allStores': allStores, 'storeO': storeO, 'product':product, 'productCategory': productCategory} return render(request, 'admin_panel/newOperation.html', data ) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewStore', raise_exception=True) def newStore(request): storeName = request.POST.get('storeName', '') newStore = StoreRoom() newStore.store_name = storeName newStore.save() return redirect('/panel/store/') @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewStore', raise_exception=True) def productAdd(request): namePrd = request.POST.get('namePrd', '') category = request.POST.get('category', '') price = request.POST.get('price', '') mojodiAval = request.POST.get('mojodiAval', '') storeroom = request.POST.get('storeroom', '') newProduct = Product() newProduct.product_name = namePrd newProduct.ProductCategory = ProductCategory.objects.get(id=category) newProduct.product_price = price newProduct.save() prd_in_store = ProductInStore() prd_in_store.Product = newProduct prd_in_store.StoreRoom = StoreRoom.objects.get(id=storeroom) prd_in_store.s_in = mojodiAval prd_in_store.desc = "موجودی اولیه: "+str(mojodiAval) prd_in_store.movement_type = ProductInStore.MovementType.INITIAL prd_in_store.save() #return HttpResponse(installDate) return redirect('/panel/store/1') @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewStore', raise_exception=True) def productEdit(request): prd_code = request.POST.get('prd_code', '') namePrd = request.POST.get('namePrd', '') category = request.POST.get('category', '') price = request.POST.get('price', '') #return HttpResponse(prd_code) editProduct = Product.objects.get(id=prd_code) editProduct.product_name = namePrd editProduct.ProductCategory = ProductCategory.objects.get(id=category) editProduct.product_price = price editProduct.save() return redirect('/panel/store/1') @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewStore', raise_exception=True) def productDel(request, p_id, s_id): Product.objects.get(id=p_id).delete() return redirect('/panel/store/'+str(s_id)) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewStore', raise_exception=True) def operation(request): if request.method != 'POST': return HttpResponseBadRequest("متد ارسالی نامعتبر است.") # استفاده از توابع امن اختصاصی پروژه شما برای جداسازی مقادیر عددی prd_id = _safe_int(request.POST.get('prd_id')) actionType = request.POST.get('actionType', '') tedad = _safe_int(request.POST.get('tedad')) azanbar = _safe_int(request.POST.get('azanbar')) beanbar = _safe_int(request.POST.get('beanbar')) desc = request.POST.get('desc', '') if tedad <= 0: return HttpResponseBadRequest("تعداد وارد شده باید بیشتر از صفر باشد.") sRoom = get_object_or_404(StoreRoom, id=azanbar) productO = get_object_or_404(Product, id=prd_id) try: with transaction.atomic(): # ساخت کوئری پایه برای دریافت تراکنش‌های سال جاری کالا qs = ProductInStore.objects.filter( Product=productO, StoreRoom=sRoom, year=1400 ) # بررسی هوشمند پشتیبانی دیتابیس از قابلیت قفل ردیف (سازگار با SQLite و PostgreSQL) if connection.features.has_select_for_update: qs = qs.select_for_update() # بارگذاری امن تراکنش‌ها در حافظه (RAM) جهت جلوگیری از خطای توابع تجمیعی همزمان با قفل دیتابیس locked_records = list(qs) # --- عملیات ورود دستی --- if actionType == 'vorod': pInStore = ProductInStore( StoreRoom=sRoom, Product=productO, year=1400 ) pInStore.s_in = tedad pInStore.desc = "ورود: "+str(tedad)+" به انبار " + str(sRoom.store_name) + "#" + str(desc) pInStore.movement_type = ProductInStore.MovementType.DIRECT_IN pInStore.save() # --- عملیات خروج دستی یا انتقال بین انبارها --- elif actionType in ['khoroj', 'transfer']: # محاسبات دقیق و سریع موجودی کالا در سطح پایتون بدون درگیر کردن دیسک total_in = sum(item.s_in for item in locked_records if item.s_in) total_out = sum(item.s_out for item in locked_records if item.s_out) mojodi_prd = total_in - total_out if mojodi_prd < tedad: # تطابق ۱۰۰ درصدی پاسخ کدهای قدیمی با فرانت‌اند شما return HttpResponse("موجودی کافی نیست، موجودی فعلی: "+ str(mojodi_prd)) # الف) خروج دستی ساده if actionType == 'khoroj': pInStore = ProductInStore( StoreRoom=sRoom, Product=productO, year=1400 ) pInStore.s_out = tedad pInStore.desc = "خروج: "+str(tedad)+" از انبار " + str(sRoom.store_name) + "#" + str(desc) pInStore.movement_type = ProductInStore.MovementType.DIRECT_OUT pInStore.save() # ب) انتقال بین دو انبار مجزا elif actionType == 'transfer': if not beanbar: return HttpResponse("انبار مقصد مشخص نشده است.") beanbarOjb = get_object_or_404(StoreRoom, id=_safe_int(beanbar)) # ردیف اول: ثبت تراکنش خروج از انبار مبدأ pInStore = ProductInStore( StoreRoom=sRoom, Product=productO, year=1400 ) pInStore.s_out = tedad pInStore.desc = "خروج: "+str(tedad)+" از انبار " + str(sRoom.store_name) + " جهت انتقال به انبار " + str(beanbarOjb.store_name) + "#" + str(desc) pInStore.movement_type = ProductInStore.MovementType.TRANSFER pInStore.save() # ردیف دوم: ثبت تراکنش ورود به انبار مقصد (محافظت شده در بلاک اتمیک) ProductInStore.objects.create( StoreRoom=beanbarOjb, Product=productO, s_in=tedad, year=1400, desc="ورود: "+str(tedad)+" از انبار " + str(sRoom.store_name) + "#" + str(desc), movement_type=ProductInStore.MovementType.TRANSFER ) except Exception as e: logger.error(f"Error in store operation view: {str(e)}", exc_info=True) return HttpResponse("خطای سیستمی رخ داد. تراکنش لغو شد.") return redirect('/panel/store/'+str(sRoom.id)) @login_required(login_url='/panel/p_login/') def newFactor(request, c_id): prdsList = request.POST.get('prdsList', '') sarResidDate = request.POST.get('sarResidDate', None) pardakhti = request.POST.get('pardakhti', None) #return HttpResponse(pardakhti) if pardakhti: pardakhti=int(pardakhti) if pardakhti>=1: pass else: pardakhti = None #return HttpResponse(sarResidDate) try: sarResidDate = digits.fa_to_en(digits.ar_to_fa(sarResidDate)) #return HttpResponse(sarResidDate) sarResidDate = sarResidDate.split("/") #return HttpResponse(sarResidDate[2]) sarResidDate = JalaliDate(int(sarResidDate[0]), int(sarResidDate[1]), int(sarResidDate[2])).to_gregorian() #return HttpResponse(sarResidDate) except: sarResidDate = None #return HttpResponse(sarResidDate[1]) #sarResidDate = JalaliDate(sarResidDate[0], sarResidDate[1], sarResidDate[2]).to_gregorian() payType = request.POST.get('payType', '') FactorDate = request.POST.get('FactorDate', '') FactorType = request.POST.get('FactorType', '') FactorDesc = request.POST.get('FactorDesc', '') Factorfail = False customerObj=Customer.objects.get(id=c_id) storeUser = StoreRoom.objects.get(user__id=request.user.id) import json prdsList = json.loads(prdsList) sum_price = 0 for prd in prdsList: if prd['garanty_Esh'] == ' ' or prd['garanty_Esh'] == '' or prd['garanty_Esh'] == None: sum_price += prd['prd_count'] * prd['price'] #return HttpResponse(prd_code) try: newFactor = Factor() newFactor.customer= customerObj newFactor.amount = sum_price if payType in ('naghd', 'kartKhan', 'cardToCard'): newFactor.pay_status = 'paid' else: newFactor.pay_status = 'unpaid' newFactor.FactorType = FactorType newFactor.PayType = payType newFactor.desc = FactorDesc if sarResidDate != None: newFactor.deadline = sarResidDate newFactor.user = User.objects.get(id=request.user.id) newFactor.save() except: try: Factorfail=True newFactor.delete() except: pass if Factorfail != True: #accFactor To article is_naghd = False articleHesabDari = Article() articleHesabDari.debit = newFactor.amount articleHesabDari.credit = 0 articleHesabDari.customer = customerObj articleHesabDari.factor = newFactor if payType in ('naghd', 'kartKhan', 'cardToCard'): is_naghd = True articleHesabDari.type = payType articleHesabDari.desc = str(FactorType) + " " + str(customerObj.name_family) + " طی فاکتور شماره: " + str(newFactor.id) articleHesabDari.save() if is_naghd: articleHesabDari2 = Article() articleHesabDari2.debit = 0 articleHesabDari2.credit = newFactor.amount articleHesabDari2.customer = customerObj articleHesabDari2.type = payType articleHesabDari2.factor = newFactor articleHesabDari2.desc = str(FactorType) + " " + str(customerObj.name_family) + " تسویه نقدی فاکتور شماره: " + str(newFactor.id) articleHesabDari2.save() elif pardakhti != None and pardakhti!='' and pardakhti != ' ': articleHesabDari2 = Article() articleHesabDari2.debit = 0 articleHesabDari2.credit = pardakhti articleHesabDari2.customer = customerObj articleHesabDari2.type = payType articleHesabDari2.factor = newFactor articleHesabDari2.desc = str(customerObj.name_family) + " پرداخت نقد در محل برا فاکتور " + str(newFactor.id) articleHesabDari2.save() for prd in prdsList: try: fIteams = FactorIteam() fIteams.factor = newFactor if prd['prd_id'] == 9999: Gproduct = None fIteams.product = Gproduct fIteams.product_name = prd['product_name'] fIteams.num = prd['prd_count'] fIteams.amount = int(prd['priceKol']) else: Gproduct = Product.objects.get(id=prd['prd_id']) fIteams.product = Gproduct fIteams.product_name = Gproduct.product_name fIteams.num = prd['prd_count'] fIteams.amount = prd['prd_count'] * Gproduct.product_price fIteams.garantyEsh = prd['garanty_Esh'] fIteams.save() except: Factorfail = True newFactor.delete() break if Factorfail != True: for prd in prdsList: if prd['prd_id'] != 9999: pInStore = ProductInStore() sRoom = storeUser productO = Product.objects.get(id=prd['prd_id']) pInStore.StoreRoom = sRoom pInStore.Product = productO pInStore.factor = newFactor productS_in = ProductInStore.objects.filter(Product=productO, StoreRoom=sRoom, year=1400).aggregate(Sum('s_in'))['s_in__sum'] productS_out = ProductInStore.objects.filter(Product=productO, StoreRoom=sRoom, year=1400).aggregate(Sum('s_out'))['s_out__sum'] mojodi_prd = productS_in - productS_out if mojodi_prd >= prd['prd_count']: pInStore.s_out = prd['prd_count'] if prd['garanty_Esh'] != ' ' and prd['garanty_Esh'] != '' and prd['garanty_Esh'] != None: pInStore.desc = "خروج: " + str(prd['prd_count']) + "#"+str(prd['garanty_Esh'])+ "#" + str(customerObj.name_family) + " * " + str(request.user.first_name) + " " + str(request.user.last_name) else: pInStore.desc = "خروج: " + str(prd['prd_count']) + "#فروش" + "#" + str(customerObj.name_family) + " * " + str(request.user.first_name) + " " + str(request.user.last_name) pInStore.save() else: return HttpResponse("موجودی کافی نیست، موجودی فعلی: "+ str(mojodi_prd)) return redirect('/panel/customer/'+str(c_id)+'/factors/') @login_required(login_url='/panel/p_login/') def newFactor2(request, c_id): if request.method != 'POST': return HttpResponseBadRequest("متد ارسالی باید POST باشد.") user_op = request.user try: prds_list = json.loads(request.POST.get('prdsList') or '[]') json_pardakht_ha = json.loads(request.POST.get('PardakhtHa') or '{}') except json.JSONDecodeError: return HttpResponseBadRequest("فرمت داده‌های ارسالی JSON نامعتبر است.") factor_type = request.POST.get('FactorType', '') factor_desc = request.POST.get('FactorDesc', '') sar_resid_date = _parse_jalali_date(request.POST.get('sarResidDate')) customer_obj = get_object_or_404(Customer, id=c_id) store_room = get_object_or_404(StoreRoom, user=user_op) # رفع مشکل متنی/عددی در استخراج شناسه کالاها product_ids = [] for item in prds_list: p_id = item.get('prd_id') if p_id and _safe_int(p_id) != 9999: product_ids.append(_safe_int(p_id)) products_by_id = {p.id: p for p in Product.objects.filter(id__in=product_ids)} sum_price = sum( _safe_int(item.get('prd_count')) * _safe_int(item.get('price')) for item in prds_list if not str(item.get('garanty_Esh', '')).strip() ) try: with transaction.atomic(): new_factor = Factor.objects.create( customer=customer_obj, amount=sum_price, FactorType=factor_type, desc=factor_desc, deadline=sar_resid_date, user=user_op ) Article.objects.create( debit=sum_price, credit=0, customer=customer_obj, factor=new_factor, desc=f"{customer_obj.name_family} فاکتور شماره: {new_factor.id}", user=user_op ) payment_map = { 'l_naghd': 'نقد', 'l_kartbekart': 'کارت به کارت', 'l_kartKhan': 'کارت خوان', 'l_takhfif': 'تخفیف' } for key, amount_raw in json_pardakht_ha.items(): amount = _safe_int(amount_raw) if amount <= 0: continue if key in payment_map: nahve_pardakht = payment_map[key] Article.objects.create( debit=0, credit=amount, customer=customer_obj, factor=new_factor, desc=f"{nahve_pardakht} {customer_obj.name_family} فاکتور شماره: {new_factor.id}", nahvePardakht=nahve_pardakht, payStatus="true", user=user_op ) elif key in ['l_nesiye', 'l_checkPrice']: is_nesiye = (key == 'l_nesiye') type_str = 'nesiye' if is_nesiye else 'check' ts_key = 'l_nesiyeSarResid' if is_nesiye else 'l_checkPriceSarResid' sar_resid_dt = _parse_timestamp(json_pardakht_ha.get(ts_key)) Sarresid.objects.create( customer=customer_obj, price=amount, payStatus="false", type=type_str, user=user_op, factor=new_factor, sarresidDT=sar_resid_dt ) factor_items_pool = [] user_fullname = f"{user_op.first_name} {user_op.last_name}".strip() or user_op.username for item in prds_list: # تبدیل امن شناسه به عدد prd_id = _safe_int(item.get('prd_id')) prd_count = _safe_int(item.get('prd_count')) garanty_esh = item.get('garanty_Esh', '') if prd_id == 9999: factor_items_pool.append(FactorIteam( factor=new_factor, product=None, product_name=item.get('product_name', ''), num=prd_count, amount=_safe_int(item.get('priceKol')), garantyEsh=garanty_esh )) else: product_obj = products_by_id.get(prd_id) if not product_obj: raise InventoryException(f"خطا در دریافت محصول: محصولی با شناسه {prd_id} در سیستم وجود ندارد.") factor_items_pool.append(FactorIteam( factor=new_factor, product=product_obj, product_name=product_obj.product_name, num=prd_count, amount=prd_count * _safe_int(product_obj.product_price), garantyEsh=garanty_esh )) FactorIteam.objects.bulk_create(factor_items_pool, batch_size=500) # فرآیند کسر از انبار (Enterprise Level) for item in prds_list: prd_id = _safe_int(item.get('prd_id')) if prd_id == 9999: continue prd_count = _safe_int(item.get('prd_count')) garanty_esh = item.get('garanty_Esh', '') product_obj = products_by_id.get(prd_id) if not product_obj: continue # ۱. کوئری پایه qs = ProductInStore.objects.filter( Product=product_obj, StoreRoom=store_room, year=1400 ) # ۲. قفل دیتابیس هوشمند و سازگار با تمام پایگاه‌های داده if connection.features.has_select_for_update: qs = qs.select_for_update() # ۳. بارگذاری امن در رم برای جلوگیری از خطای Aggregate در دیتابیس قفل‌شده locked_records = list(qs) # ۴. محاسبه دقیق و پرسرعت در پایتون total_in = sum(rec.s_in for rec in locked_records if rec.s_in) total_out = sum(rec.s_out for rec in locked_records if rec.s_out) mojodi_prd = total_in - total_out if mojodi_prd < prd_count: # استفاده از متن دقیق خطای قبلی جهت حفظ سازگاری با فرانت‌اند raise InventoryException(f"موجودی کافی نیست، موجودی فعلی {product_obj.product_name}: {mojodi_prd}") # ۵. تشخیص نوع تراکنش برای سیستم گزارش‌گیری جدید انبار if garanty_esh and str(garanty_esh).strip(): desc_text = f"خروج: {prd_count}#{garanty_esh}#{customer_obj.name_family} * {user_fullname}" if "اشانتیون" in str(garanty_esh): m_type = ProductInStore.MovementType.PROMOTION else: m_type = ProductInStore.MovementType.WARRANTY else: desc_text = f"خروج: {prd_count}#فروش#{customer_obj.name_family} * {user_fullname}" m_type = ProductInStore.MovementType.SALE # ۶. ثبت تراکنش خروجی انبار ProductInStore.objects.create( StoreRoom=store_room, Product=product_obj, factor=new_factor, s_out=prd_count, desc=desc_text, movement_type=m_type, # ثبت ساختاریافته نوع خروج برای سرعت در گزارش‌گیری year=1400 ) except InventoryException as e: return HttpResponse(str(e), status=400) except Exception as e: logger.error(f"Error creating factor for customer {c_id}: {str(e)}", exc_info=True) return HttpResponse("خطایی غیرمنتظره در سرور رخ داد. اطلاعات ذخیره نشد.", status=500) return redirect(f'/panel/customer/{c_id}/factors/') @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.DelFactor', raise_exception=True) @require_POST def FactorDel(request, c_id, f_id): customer_obj = get_object_or_404(Customer, id=c_id) factor_initial = get_object_or_404(Factor, id=f_id, customer=customer_obj) if factor_initial.pay_status == 'cancell' or not factor_initial.is_active: return HttpResponseBadRequest("این فاکتور قبلاً باطل یا برگشت داده شده است.") user_fullname = f"{request.user.first_name} {request.user.last_name}".strip() or request.user.username cancel_reason = request.POST.get('cancel_reason', 'error') payment_action = request.POST.get('payment_action', 'keep') if cancel_reason == 'return': reason_text = "برگشت از فروش (مرجوعی مشتری)" inv_movement = ProductInStore.MovementType.RETURN else: reason_text = "اصلاح خطای کاربری" inv_movement = ProductInStore.MovementType.ERROR_CORRECTION try: with transaction.atomic(): if connection.features.has_select_for_update: factor = Factor.objects.select_for_update().get(pk=factor_initial.pk) else: factor = Factor.objects.get(pk=factor_initial.pk) if factor.pay_status == 'cancell' or not factor.is_active: return HttpResponseBadRequest("خطای همزمانی: این فاکتور در لحظه فرستادن درخواست باطل شده بود.") factor.is_active = False factor.pay_status = 'cancell' factor.save(update_fields=['is_active', 'pay_status']) # واکشی اسناد پرداخت قبل از ایجاد سند جدید (جلوگیری از باگ تکرار سند) payments_to_reverse = [] if payment_action == 'reverse' or cancel_reason == 'error': payments_to_reverse = list(Article.objects.filter( Q(debit=0) | Q(debit__isnull=True), factor=factor, credit__gt=0 )) # ۱. صدور سند معکوس مالی برای کل مبلغ فاکتور factor_amount = int(factor.amount or 0) if factor_amount > 0: Article.objects.create( debit=0, credit=factor_amount, customer=customer_obj, factor=factor, type=factor.PayType, desc=f"برگشت از فروش و ابطال فاکتور شماره {factor.id} (مرجوعی کالا توسط مشتری) - کاربر: {user_fullname}" if cancel_reason == 'return' else f"اصلاح خطای سیستم: ابطال فاکتور اشتباه شماره {factor.id} (بدون جابجایی واقعی کالا) - کاربر: {user_fullname}", user=request.user, payStatus="true" ) # ۲. خنثی کردن پرداخت‌های اولیه فاکتور for p in payments_to_reverse: Article.objects.create( debit=p.credit, credit=0, customer=customer_obj, factor=factor, type=p.type, nahvePardakht=p.nahvePardakht, desc=f"عودت وجه پرداخت شده / ابطال رسید فاکتور {factor.id} (به دلیل مرجوعی کالا) - کاربر: {user_fullname}" if cancel_reason == 'return' else f"اصلاح خطای سیستم: ابطال رسید پرداخت فاکتور اشتباه شماره {factor.id} - کاربر: {user_fullname}", user=request.user, payStatus="true" ) # ۳. 🛠️ اصلاح انبار (حل باگ عدم تغییر موجودی سیستم) stock_movements = list(ProductInStore.objects.filter(factor=factor, s_out__gt=0)) for movement in stock_movements: pInStore = ProductInStore( StoreRoom=movement.StoreRoom, Product=movement.Product, factor=factor, s_in=movement.s_out, # برگرداندن تعداد کسر شده به ستون ورودی s_out=0, year=movement.year, # 💡 فیکس قطعی: استفاده دقیق از سال مالی تراکنش اصلی (۱۴۰۰) جهت همخوانی با توابع سیستم desc=f"ورود به انبار بابت برگشت از فروش کالا (فاکتور {factor.id}) - کاربر: {user_fullname}" if cancel_reason == 'return' else f"ورود به انبار بابت اصلاح خطای ثبت فاکتور {factor.id} - کاربر: {user_fullname}", movement_type=inv_movement ) pInStore.save() # فراخوانی متد save مدل شما که محاسبات تاریخچه و موجودی لحظه‌ای را انجام می‌دهد # ۴. ابطال اقساط و سررسیدهای پاس نشده Sarresid.objects.filter(factor=factor, payStatus="false").update( payStatus="cancell", desc=f"ابطال بابت {reason_text} فاکتور {factor.id}" ) logger.info(f"Factor {factor.id} successfully cancelled. Reason: {cancel_reason}, Payment: {payment_action}") except Exception as e: logger.error(f"Critical error in FactorDel for factor {f_id}: {str(e)}", exc_info=True) return HttpResponse("خطای سیستمی در فرآیند ابطال و صدور اسناد اصلاحی رخ داد.", status=500) return redirect('admin_panel:customerFactors', c_id=c_id) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.DelCustomer', raise_exception=True) def customerDel(request, c_id): try: Customer.objects.get(id=c_id).delete() return redirect('/panel/customers/') except: return HttpResponse("خطا در حذف مشتری") @login_required(login_url='/panel/p_login/') def customerHesabdari(request ,c_id): customer = Customer.objects.get(id=c_id) try: debit = Article.objects.filter(customer=customer).aggregate(Sum('debit'))['debit__sum'] credit = Article.objects.filter(customer=customer).aggregate(Sum('credit'))['credit__sum'] mandehesabCs = debit - credit articls = Article.objects.filter(customer=customer).order_by('-createdDT') except: articls =None mandehesabCs = 0 dateNow = datetime.datetime.now().date data = {'customer': customer, 'mandehesabCs': mandehesabCs, 'articls': articls} return render(request, 'admin_panel/customerHesabDari.html', data) @login_required(login_url='/panel/p_login/') def sarresidh(request ,c_id): customer = Customer.objects.get(id=c_id) try: all_sarresid = Sarresid.objects.filter(customer=customer).order_by('-sarresidDT') except: all_sarresid = None data = {'customer': customer, 'all_sarresid': all_sarresid} return render(request, 'admin_panel/customerSarresid.html', data) @login_required(login_url='/panel/p_login/') def customerHesabdariAdd(request ,c_id): user_op = request.user price = request.POST.get('price', None) type = request.POST.get('type', None) typePy = request.POST.get('typePy', None) desc = request.POST.get('desc', None) nahvePardakhat = request.POST.get('nahvePardakhat', None) newArticl = Article() newArticl.customer = Customer.objects.get(id=c_id) newArticl.desc = desc newArticl.typePy = typePy if type == 'credit': newArticl.credit = price newArticl.debit = 0 elif type == 'debit': newArticl.debit = price newArticl.credit = 0 newArticl.user = user_op newArticl.nahvePardakht = nahvePardakhat newArticl.save() return redirect('/panel/customer/'+str(c_id)+'/hesabdari') @login_required(login_url='/panel/p_login/') def customerAction(request ,c_id): customer = Customer.objects.get(id=c_id) actions = Action.objects.filter(customer=customer).order_by("-createdDT") allUsers = User.objects.filter().exclude(username='admin').exclude(username='fesahat') data = {'customer': customer, 'actions': actions, 'allUsers': allUsers} return render(request, 'admin_panel/customerAction.html', data) @login_required(login_url='/panel/p_login/') def customerNazar(request ,c_id): customer = Customer.objects.get(id=c_id) actions = Action.objects.filter(customer=customer, nazarDT__isnull=False).order_by("-createdDT") allUsers = User.objects.filter().exclude(username='admin').exclude(username='fesahat') data = {'customer': customer, 'actions': actions, 'allUsers': allUsers} return render(request, 'admin_panel/customer/nazar.html', data) @login_required(login_url='/panel/p_login/') def customerNewAction(request ,c_id): actionType = request.POST.get('actionType', None) dateTimeAnjam = request.POST.get('dateTimeAnjam', None) #return HttpResponse(float(dateTimeAnjam+".0")) try: dateTimeAnjam = datetime.datetime.fromtimestamp(int(dateTimeAnjam)/1e3) except: pass desc = request.POST.get('desc', None) userID = request.POST.get('userID', None) is_done = request.POST.get('is_done', None) result = request.POST.get('result', None) FinishDateTime = request.POST.get('FinishDateTime', None) try: FinishDateTime = datetime.datetime.fromtimestamp(int(FinishDateTime)/1e3) except: pass customer_obj = Customer.objects.get(id=int(c_id)) newAction = Action() newAction.actionType = actionType newAction.actionDateTime = dateTimeAnjam newAction.desc = desc newAction.forUser = User.objects.get(id=int(userID)) newAction.customer = customer_obj if is_done: newAction.status = 'finish' newAction.finishDateTime = FinishDateTime newAction.result = result else: newAction.status = 'waite' newAction.save() if newAction.status == 'finish' and newAction.actionType == 'bazdid': customer_obj.last_bazdid_dt = newAction.finishDateTime customer_obj.save() return redirect('/panel/customer/'+str(c_id)+'/action') @login_required(login_url='/panel/p_login/') def ActionList(request): actions = Action.objects.filter(forUser__id=request.user.id, status='waite').order_by("-createdDT") allUsers = User.objects.filter().exclude(username='admin').exclude(username='fesahat') data = {'actions': actions, 'allUsers': allUsers} return render(request, 'admin_panel/ActionList.html', data) @login_required(login_url='/panel/p_login/') def ActionListUser(request, u_id): actions = Action.objects.filter(forUser__id=u_id, status='waite').order_by("-createdDT") allUsers = User.objects.filter().exclude(username='admin').exclude(username='fesahat') data = {'actions': actions, 'allUsers': allUsers} return render(request, 'admin_panel/ActionList.html', data) @login_required(login_url='/panel/p_login/') def customerEditAction(request ,c_id, action_id): actionType = request.POST.get('actionType', None) dateTimeAnjam = request.POST.get('dateTimeAnjam', None) print("ok") #return HttpResponse(float(dateTimeAnjam+".0")) try: dateTimeAnjam = datetime.datetime.fromtimestamp(int(dateTimeAnjam)/1e3) except: pass desc = request.POST.get('desc', None) userID = request.POST.get('userID', None) is_done = request.POST.get('is_done', None) result = request.POST.get('result', None) FinishDateTime = request.POST.get('FinishDateTime', None) try: FinishDateTime = datetime.datetime.fromtimestamp(int(FinishDateTime)/1e3) except: pass customer_obj = Customer.objects.get(id=int(c_id)) newAction = Action.objects.get(id=action_id) newAction.actionType = actionType newAction.actionDateTime = dateTimeAnjam newAction.desc = desc newAction.forUser = User.objects.get(id=int(userID)) newAction.customer = customer_obj if is_done: newAction.status = 'finish' newAction.finishDateTime = FinishDateTime newAction.result = result else: newAction.status = 'waite' newAction.save() if newAction.status == 'finish' and newAction.actionType == 'bazdid': customer_obj.last_bazdid_dt = newAction.finishDateTime customer_obj.save() #return redirect('/panel/customer/'+str(c_id)+'/action') return redirect(request.META.get('HTTP_REFERER', 'redirect_if_referer_not_found')) @login_required(login_url='/panel/p_login/') def ActionListAll(request): actions = Action.objects.filter().order_by("-id") allUsers = User.objects.filter().exclude(username='admin').exclude(username='fesahat') data = {'actions': actions, 'allUsers': allUsers} return render(request, 'admin_panel/ActionList.html', data) @login_required(login_url='/panel/p_login/') def ActionListToday(request): startTodayDT= datetime.datetime.today().strftime('%Y-%m-%d 00:00:00') endTodayDT= datetime.datetime.today().strftime('%Y-%m-%d 23:59:59') #startTodayDT = datetime.datetime.strptime(startTodayDT, '%Y-%m-%d-00:00:00') #endTodayDT = datetime.datetime.strptime(endTodayDT, '%Y-%m-%d-23:59:59') #return HttpResponse(todayDT) actions = Action.objects.filter(actionDateTime__gte=startTodayDT,actionDateTime__lte=endTodayDT, forUser__id=request.user.id, status='waite').order_by("-actionDateTime")[:50] allUsers = User.objects.filter().exclude(username='admin').exclude(username='fesahat') data = {'actions': actions, 'allUsers': allUsers} return render(request, 'admin_panel/ActionList.html', data) @login_required(login_url='/panel/p_login/') def ActionListUserToday(request, u_id): dateTimeAction = request.GET.get('dateTime', None) status = request.GET.get('status', None) unixADT = dateTimeAction if dateTimeAction: dateTimeAction = datetime.datetime.fromtimestamp(int(dateTimeAction)/1e3) startTodayDT = dateTimeAction.strftime('%Y-%m-%d 00:00:00') endTodayDT= dateTimeAction.strftime('%Y-%m-%d 23:59:59') else: startTodayDT= datetime.datetime.today().strftime('%Y-%m-%d 00:00:00') endTodayDT= datetime.datetime.today().strftime('%Y-%m-%d 23:59:59') #startTodayDT = datetime.datetime.strptime(startTodayDT, '%Y-%m-%d-00:00:00') #endTodayDT = datetime.datetime.strptime(endTodayDT, '%Y-%m-%d-23:59:59') #return HttpResponse(todayDT) if status == 'waite' or status == None or status == '' or status == ' ': status = 'waite' actions = Action.objects.filter(actionDateTime__gte=startTodayDT,actionDateTime__lte=endTodayDT, forUser__id=u_id, status=status).order_by("-actionDateTime")[:50] actionPr = Action.objects.filter(actionDateTime__lt=startTodayDT, forUser__id=u_id, status=status).order_by("-actionDateTime")[:200] elif status == 'finish': actionPr = None actions = Action.objects.filter(actionDateTime__gte=startTodayDT,actionDateTime__lte=endTodayDT, forUser__id=u_id, status=status).order_by("-actionDateTime")[:50] allUsers = User.objects.filter().exclude(username='admin').exclude(username='fesahat') data = {'actions': actions, 'allUsers': allUsers, 'u_id': u_id, "unixADT": unixADT, "status": status, 'actionPr': actionPr} return render(request, 'admin_panel/ActionList.html', data) @login_required(login_url='/panel/p_login/') def rezayat(request): dateTimeAction = request.GET.get('dateTime', None) statusRezayat = request.GET.get('status', None) status='finish' if statusRezayat=='finish': actions = Action.objects.exclude(actionType='vosol').exclude(Q(nazar='') | Q(nazar=None)).filter(status='finish').order_by("-id")[:50] else: statusRezayat='waite' actions = Action.objects.filter(Q(nazar='') | Q(nazar=None) & Q(status='finish')).exclude(actionType='vosol').order_by("id")[:50] data = {'actions': actions, "status": statusRezayat} return render(request, 'admin_panel/customerRezayat.html', data) @login_required(login_url='/panel/p_login/') def rezayatEdit(request, ac_id): csGrade = request.POST.get('csGrade', None) csDesc = request.POST.get('csDesc', None) if csDesc and csGrade: action = Action.objects.get(id=ac_id) action.nazar = csDesc action.grade = csGrade action.nazarDT = datetime.datetime.now() action.save() return redirect('/panel/rezayat/') else: return HttpResponse('لطفا همه فیلد ها را پر کنید') #data = {'actions': actions, "status": status} #return render(request, 'admin_panel/customerRezayat.html', data) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewStore', raise_exception=True) def passCheck(request, articl_id): sarresidINC = Sarresid.objects.get(id=articl_id) user_op = request.user desc = request.POST.get('message') articleHesabDari2 = Article() articleHesabDari2.debit = 0 articleHesabDari2.credit = sarresidINC.price articleHesabDari2.customer = sarresidINC.customer articleHesabDari2.factor = sarresidINC.factor articleHesabDari2.desc = 'وصول چک' + " " + str(sarresidINC.customer.name_family) if sarresidINC.factor: articleHesabDari2.desc += " فاکتور شماره: " + str(sarresidINC.factor.id) articleHesabDari2.nahvePardakht = 'وصول چک' articleHesabDari2.payStatus = "true" articleHesabDari2.user = user_op articleHesabDari2.save() sarresidINC.payStatus = "true" sarresidINC.desc = desc sarresidINC.save() return HttpResponse("ok") #return redirect(request.META.get('HTTP_REFERER')) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewStore', raise_exception=True) def addSarresid(request, cs_id): try: customerObj = Customer.objects.get(id=cs_id) sarrresidUNIX = request.POST.get('n_sarresidDateTime', None) sarresidPrice = request.POST.get('n_sarresidPrice', None) sarresidType = request.POST.get('n_sarresidType', None) sarResidDateTime01 = datetime.datetime.fromtimestamp(int(sarrresidUNIX)/1000.0) articleHesabDariObj = Article() articleHesabDariObj.debit = int(sarresidPrice) articleHesabDariObj.credit = 0 articleHesabDariObj.desc = "بدهی بابت ثبت " if sarresidType == "check": articleHesabDariObj.desc += " چک به صورت دستی " elif sarresidType == "nesiye": articleHesabDariObj.desc += " نسیه به صورت دستی " articleHesabDariObj.customer = customerObj articleHesabDariObj.save() sarresidINC = Sarresid() sarresidINC.customer = customerObj sarresidINC.price = int(sarresidPrice) sarresidINC.payStatus = "false" #check ya nesiye sarresidINC.type = sarresidType sarresidINC.user = request.user sarresidINC.sarresidDT = sarResidDateTime01 sarresidINC.save() return redirect(request.META.get('HTTP_REFERER')) except: return HttpResponse("خطا در ثبت ") #return HttpResponse(customerObj.id) @login_required(login_url='/panel/p_login/') @permission_required('admin_panel.ViewStore', raise_exception=True) def pardakhtNesiye(request, cs_id): try: customerObj = Customer.objects.get(id=cs_id) user_op = request.user sarrresidUNIX = request.POST.get('next_sarresidDateTime', None) sarresidPrice = int(request.POST.get('next_sarresidPrice', None)) sr_articlID = request.POST.get('sr_articlID', None) nahvePardakht = request.POST.get('nahvePardakht', None) desc_sar = request.POST.get('desc_sar', None) sarResidDateTime01 = datetime.datetime.fromtimestamp(int(sarrresidUNIX)/1000.0) SarresidObj = Sarresid.objects.get(id=sr_articlID) #return HttpResponse(sarresidPrice) debitNow = SarresidObj.price - sarresidPrice #return HttpResponse(debitNow) if debitNow==0: #توسیه بدهی بخورد SarresidObj.price = 0 SarresidObj.payStatus = "true" elif debitNow >= 1: SarresidObj.price = debitNow SarresidObj.sarresidDT = sarResidDateTime01 else: return HttpResponse("خطا در مورد مبلغ") SarresidObj.save() if str(nahvePardakht) == 'naghd': nahvePardakht = 'نقد' elif str(nahvePardakht) == 'kartbekart': nahvePardakht = 'کارت به کارت' elif str(nahvePardakht) == 'kartkhan': nahvePardakht = 'کارت خوان' elif str(nahvePardakht) == 'takhfif': nahvePardakht = 'تخفیف' elif str(nahvePardakht) == 'check': nahvePardakht = 'چک' articleHesabDariObj = Article() articleHesabDariObj.debit = 0 articleHesabDariObj.credit = int(sarresidPrice) if desc_sar: articleHesabDariObj.desc = "پرداختی بابت نسیه" + " | " + desc_sar else: articleHesabDariObj.desc = "پرداختی بابت نسیه" articleHesabDariObj.customer = customerObj articleHesabDariObj.nahvePardakht = nahvePardakht articleHesabDariObj.user = user_op articleHesabDariObj.save() return redirect(request.META.get('HTTP_REFERER')) except: return HttpResponse("خطا در ثبت ") #return HttpResponse(customerObj.id)