Files
2026-07-03 16:52:04 +03:30

1970 lines
85 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)