improve entezar bazdid

This commit is contained in:
javad committed 2026-10-20 19:02:34 +03:30
1 parent 1fd27d0445
commit 2aee85593f
18 files changed
+10271 -7558

No files matched your search

+83 -60
View File
@@ -1,13 +1,19 @@
import datetime
from django.core.exceptions import ValidationError
from django.db.models import Q
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse
from django.contrib import messages
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.utils import timezone
from ..models import Action, Customer
from ..sms.triggers import notify_visit_scheduled
from ..visit_policy import (REASON_CANCEL, REASON_CREATE, REASON_EDIT,
as_aware, normalize_finish_datetime,
refresh_last_bazdid, validate_action_payload)
@login_required(login_url='/panel/p_login/')
@@ -54,46 +60,68 @@ def customerNazar(request ,c_id):
data = {'customer': customer, 'actions': actions, 'allUsers': allUsers}
return render(request, 'admin_panel/customer/nazar.html', data)
def _parse_form_datetime(raw):
"""timestamp میلی‌ثانیه‌ای فرم → دیتاتایم aware (یا ``None``).
کد قبلی ``datetime.datetime.fromtimestamp`` (naive) می‌ساخت که هنگام ذخیره
با ``USE_TZ=True`` هشدار ``RuntimeWarning`` می‌داد؛ اینجا صریح aware می‌شود.
"""
try:
return as_aware(datetime.datetime.fromtimestamp(int(raw) / 1e3))
except (TypeError, ValueError, OverflowError, OSError):
return None
def _action_payload_from_request(request):
"""استخراج و نرمال‌سازی ورودی فرم اقدام (مشترک ایجاد و ویرایش)."""
is_done = bool(request.POST.get('is_done'))
return {
'actionType': (request.POST.get('actionType') or '').strip(),
'status': Action.Status.FINISH if is_done else Action.Status.WAITE,
'actionDateTime': _parse_form_datetime(request.POST.get('dateTimeAnjam')),
'finishDateTime': _parse_form_datetime(request.POST.get('FinishDateTime')),
'desc': request.POST.get('desc', None),
'result': request.POST.get('result', None),
'userID': request.POST.get('userID', None),
'is_done': is_done,
}
def _reject(request, error, redirect_to):
"""پیام فارسی خطا به کاربر و بازگشت بدون ذخیرهٔ چیزی."""
messages.error(request, '؛ '.join(error.messages))
return redirect(redirect_to)
@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"))
payload = _action_payload_from_request(request)
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
validate_action_payload(payload)
except ValidationError as error:
return _reject(request, error, '/panel/customer/' + str(c_id) + '/action')
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.actionType = payload['actionType']
newAction.actionDateTime = payload['actionDateTime']
newAction.desc = payload['desc']
newAction.forUser = User.objects.get(id=int(payload['userID']))
newAction.customer = customer_obj
if is_done:
newAction.status = 'finish'
newAction.finishDateTime = FinishDateTime
newAction.result = result
if payload['is_done']:
newAction.status = Action.Status.FINISH
# تاریخ اتمام خالی نباید None ذخیره شود (سابقه را پاک می‌کرد).
newAction.finishDateTime = normalize_finish_datetime(payload['finishDateTime'])
newAction.result = payload['result']
else:
newAction.status = 'waite'
newAction.status = Action.Status.WAITE
newAction.save()
if newAction.status == 'finish' and newAction.actionType == 'bazdid':
customer_obj.last_bazdid_dt = newAction.finishDateTime
customer_obj.save()
# last_bazdid_dt فقط از تابع واحد بازمحاسبه می‌شود؛ نه از finishDateTime.
refresh_last_bazdid(customer_obj, reason=REASON_CREATE, user=request.user)
# پیامک «بازدید شما برای تاریخ … ثبت شد» فقط برای اقدام از نوع بازدید.
if newAction.actionType == 'bazdid':
if newAction.actionType == Action.ActionType.BAZDID:
notify_visit_scheduled(customer_obj, newAction, created_by=request.user)
return redirect('/panel/customer/'+str(c_id)+'/action')
@@ -116,42 +144,37 @@ def ActionListUser(request, u_id):
@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"))
payload = _action_payload_from_request(request)
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
validate_action_payload(payload)
except ValidationError as error:
return _reject(
request, error,
request.META.get('HTTP_REFERER', '/panel/customer/' + str(c_id) + '/action'),
)
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))
was_done = newAction.status == Action.Status.FINISH
newAction.actionType = payload['actionType']
newAction.actionDateTime = payload['actionDateTime']
newAction.desc = payload['desc']
newAction.forUser = User.objects.get(id=int(payload['userID']))
newAction.customer = customer_obj
if is_done:
newAction.status = 'finish'
newAction.finishDateTime = FinishDateTime
newAction.result = result
if payload['is_done']:
newAction.status = Action.Status.FINISH
newAction.finishDateTime = normalize_finish_datetime(payload['finishDateTime'])
newAction.result = payload['result']
else:
newAction.status = 'waite'
newAction.status = Action.Status.WAITE
newAction.save()
if newAction.status == 'finish' and newAction.actionType == 'bazdid':
customer_obj.last_bazdid_dt = newAction.finishDateTime
customer_obj.save()
# بازمحاسبهٔ واحد: هم پس از ویرایش، هم وقتی رکورد از «انجام‌شده» برگشت می‌خورد
# (تا مقداری که این رکورد ساخته بود با منبع حقیقت هم‌راستا شود).
reason = REASON_CANCEL if (was_done and not payload['is_done']) else REASON_EDIT
refresh_last_bazdid(customer_obj, reason=reason, user=request.user)
#return redirect('/panel/customer/'+str(c_id)+'/action')
return redirect(request.META.get('HTTP_REFERER', 'redirect_if_referer_not_found'))
@@ -205,7 +228,7 @@ def ActionListUserToday(request, u_id):
@login_required(login_url='/panel/p_login/')
def rezayat(request):
statusRezayat = request.GET.get('status', 'waite')
now = datetime.datetime.now()
now = timezone.now()
# محاسبه بازه‌های زمانی ۳۰ روز و ۶۰ روز قبل
dt_30_days_ago = now - datetime.timedelta(days=30)
@@ -246,20 +269,20 @@ def rezayatEdit(request, ac_id):
# عدم موفقیت: تنظیم nextNazarDT برای ۳ روز بعد (nazarDT پر نمی‌شود تا نهایی نشود)
action.nazar = csDesc
action.grade = int(csGrade)
action.nextNazarDT = datetime.datetime.now() + datetime.timedelta(days=3)
action.nextNazarDT = timezone.now() + datetime.timedelta(days=3)
elif csGrade == '-2':
# کنسل کردن: پر کردن nazarDT برای خروج کامل از لیست کارهای در انتظار
action.nazar = csDesc
action.grade = int(csGrade)
action.nazarDT = datetime.datetime.now()
action.nazarDT = timezone.now()
action.nextNazarDT = None
else:
# ثبت امتیاز عادی
action.nazar = csDesc
action.grade = int(csGrade)
action.nazarDT = datetime.datetime.now()
action.nazarDT = timezone.now()
action.nextNazarDT = None
action.save()