This commit is contained in:
javad committed 2026-10-10 14:21:04 +03:30
1 parent 250cdbab7f
commit 5c6069c3ef
87 files changed
+29209 -3697

No files matched your search

+80 -46
View File
@@ -11,8 +11,13 @@ from django.contrib.auth.decorators import login_required, permission_required
from persiantools.jdatetime import JalaliDate
from ..models import (Customer, PhoneNumber, ProductCategory, Product, Factor,
FactorIteam, Article, Sarresid, Action, CacheTable)
from ._helpers import logger, _parse_jalali_date
FactorIteam, Article, Sarresid, Action, CacheTable, SMSType)
from ..sms.enqueue import enqueue_sms
from ..sms.phones import (customer_phone_entries, normalize_primary_values,
save_primary_normalized)
from ..sms.recipients import resolve_recipients
from ..sms.rules import customer_toggle_map
from ._helpers import logger, _parse_jalali_date, _parse_phone_rows
@csrf_exempt
@@ -23,19 +28,21 @@ def customers(request):
searchStatus = True
full_path = request.get_full_path()
# مشتریان غیرفعال هرگز نمایش داده نمی‌شوند — نه در فهرست کامل و نه در جستجو.
all_customers = Customer.objects.filter(is_active=True)
if searchOn == 'code':
all_customers = Customer.objects.filter(idCode__contains=searchVal).order_by('-create_date')
all_customers = all_customers.filter(idCode__contains=searchVal)
elif searchOn == 'phone':
all_customers = Customer.objects.filter(Q(phone1__contains=searchVal) | Q(phone2__contains=searchVal) | Q(phone3__contains=searchVal) ).order_by('-create_date')
all_customers = all_customers.filter(Q(phone1__contains=searchVal) | Q(phone2__contains=searchVal) | Q(phone3__contains=searchVal))
elif searchOn == 'name':
all_customers = Customer.objects.filter(name_family__contains=searchVal).order_by('-create_date')
all_customers = all_customers.filter(name_family__contains=searchVal)
elif searchOn == 'address':
all_customers = Customer.objects.filter(address__contains=searchVal).order_by('-create_date')
all_customers = all_customers.filter(address__contains=searchVal)
elif searchOn == 'laghv':
all_customers = Customer.objects.filter(laghv_bazdid=True).order_by('-create_date')
all_customers = all_customers.filter(laghv_bazdid=True)
else:
searchStatus = False
all_customers = Customer.objects.filter(is_active=True).order_by('-create_date')
all_customers = all_customers.order_by('-create_date')
paginator = Paginator(all_customers, 25) # Show 25 contacts per page.
page_number = request.GET.get('page', None)
@@ -50,17 +57,19 @@ def customers(request):
def customersSearch(request, searchVal,searchOn):
searchStatus = True
# همان قاعدهٔ فهرست اصلی: مشتری غیرفعال در هیچ نتیجه‌ای نمایش داده نمی‌شود.
all_customers = Customer.objects.filter(is_active=True)
if searchOn == 'code':
all_customers = Customer.objects.filter(idCode__contains=searchVal).order_by('-create_date')
all_customers = all_customers.filter(idCode__contains=searchVal)
elif searchOn == 'phone':
all_customers = Customer.objects.filter(phone1__contains=searchVal).order_by('-create_date')
all_customers = all_customers.filter(phone1__contains=searchVal)
elif searchOn == 'name':
all_customers = Customer.objects.filter(name_family__contains=searchVal).order_by('-create_date')
all_customers = all_customers.filter(name_family__contains=searchVal)
elif searchOn == 'address':
all_customers = Customer.objects.filter(address__contains=searchVal).order_by('-create_date')
all_customers = all_customers.filter(address__contains=searchVal)
else:
searchStatus = False
all_customers = Customer.objects.all().order_by('-create_date')
all_customers = all_customers.order_by('-create_date')
paginator = Paginator(all_customers, 25) # Show 25 contacts per page.
page_number = request.GET.get('page', None)
@@ -112,7 +121,17 @@ def customerNew2(request ,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, 'mandehesabCs':mandehesabCs}
sms_toggles = customer_toggle_map(customer)
# همهٔ شماره‌ها از هر منبعی که ذخیره شده‌اند (PhoneNumber و phone1/2/3 قدیمی).
sms_phone_entries = customer_phone_entries(customer)
sms_effective = {n for n in resolve_recipients(customer)}
data = {
'customer': customer, 'categorys': categorys, 'dateNow': dateNow,
'factorha': factorha, 'mandehesabCs': mandehesabCs,
'sms_toggles': sms_toggles, 'sms_phone_entries': sms_phone_entries,
'sms_effective': sms_effective,
'sms_recipients': sorted(sms_effective),
}
return render(request, 'admin_panel/customerNew2.html', data)
@@ -223,18 +242,8 @@ def customersAdd(request):
installDate = request.POST.get('installDate', '')
idnCode = request.POST.get('idnCode', '')
# دریافت آرایه‌های عنوان و شماره تلفن
titles_list = request.POST.getlist('phone_titles')
phones_list = request.POST.getlist('phones')
# ترکیب عنوان‌ها و شماره‌ها و حذف ردیف‌های خالی
valid_phones = []
for title, phone in zip(titles_list, phones_list):
if phone.strip():
valid_phones.append({
'title': title.strip() if title.strip() else 'تلفن',
'phone': phone.strip()
})
# آرایه‌های عنوان/شمارهٔ فرم + ایندکس ردیف‌های علامت‌خورده به‌عنوان «اصلی»
valid_phones, phones_list, primary_indices = _parse_phone_rows(request)
year, month, day = map(int, installDate.split('/'))
installDate_gregorian = JalaliDate(year, month, day).to_gregorian()
@@ -249,34 +258,43 @@ def customersAdd(request):
newCs.phone1 = valid_phones[0]['phone'] if len(valid_phones) > 0 else ''
newCs.phone2 = valid_phones[1]['phone'] if len(valid_phones) > 1 else ''
newCs.phone3 = valid_phones[2]['phone'] if len(valid_phones) > 2 else ''
# شماره‌های «اصلی» پیامک، بر مبنای مقدارِ نرمال‌شدهٔ خودِ شماره‌ها (پایدار در بازسازی‌ها).
newCs.sms_primary_phones = normalize_primary_values(
phones_list[i] for i in primary_indices if i < len(phones_list)
)
newCs.save()
# ذخیره شماره‌ها به صورت نامحدود در جدول PhoneNumber
for item in valid_phones:
PhoneNumber.objects.create(customer=newCs, title=item['title'], phone_number=item['phone'])
PhoneNumber.objects.create(
customer=newCs, title=item['title'], phone_number=item['phone'],
)
# پیامک خوش‌آمدگویی (در صورت فعال بودن قالب و تنظیم مشتری)
enqueue_sms(
customer=newCs, sms_type=SMSType.WELCOME,
context={'name': newCs.name_family},
dedup_key=f'welcome:{newCs.id}',
created_by=request.user,
)
return redirect('/panel/customers/')
@login_required(login_url='/panel/p_login/')
def customerEdit(request, c_id):
# این مسیر فقط endpoint فرم ویرایش است؛ دسترسی مستقیم با GET نباید ۵۰۰ بدهد.
if request.method != 'POST':
return redirect('/panel/customer/' + str(c_id))
an_name = request.POST.get('an_name', '')
an_address = request.POST.get('an_address', '')
installDate = request.POST.get('installDate', '')
idnCode = request.POST.get('idnCode', '')
laghv_bazdid = request.POST.get('laghv_bazdid', False)
# دریافت آرایه‌های عنوان و شماره تلفن
titles_list = request.POST.getlist('phone_titles')
phones_list = request.POST.getlist('phones')
valid_phones = []
for title, phone in zip(titles_list, phones_list):
if phone.strip():
valid_phones.append({
'title': title.strip() if title.strip() else 'تلفن',
'phone': phone.strip()
})
# آرایه‌های عنوان/شمارهٔ فرم + ایندکس ردیف‌های علامت‌خورده به‌عنوان «اصلی»
valid_phones, phones_list, primary_indices = _parse_phone_rows(request)
year, month, day = map(int, installDate.split('/'))
installDate_gregorian = JalaliDate(year, month, day).to_gregorian()
@@ -287,17 +305,33 @@ def customerEdit(request, c_id):
newCs.installDate = installDate_gregorian
newCs.idCode = idnCode
newCs.laghv_bazdid = True if laghv_bazdid == 'true' else False
# فقط وقتی فرم فیلد توضیحات را فرستاده باشد مقدارش عوض می‌شود؛ فرم‌های قدیمی
# که این فیلد را ندارند نباید یادداشت‌های پاک‌سازی را پاک کنند.
if 'notes' in request.POST:
newCs.notes = request.POST.get('notes', '')
# آپدیت فیلدهای قدیمی جهت حفظ سازگاری
newCs.phone1 = valid_phones[0]['phone'] if len(valid_phones) > 0 else ''
newCs.phone2 = valid_phones[1]['phone'] if len(valid_phones) > 1 else ''
newCs.phone3 = valid_phones[2]['phone'] if len(valid_phones) > 2 else ''
# آپدیت فیلدهای قدیمی جهت حفظ سازگاری (تنها وقتی شماره‌ای ارسال شده باشد)
if valid_phones:
newCs.phone1 = valid_phones[0]['phone'] if len(valid_phones) > 0 else ''
newCs.phone2 = valid_phones[1]['phone'] if len(valid_phones) > 1 else ''
newCs.phone3 = valid_phones[2]['phone'] if len(valid_phones) > 2 else ''
newCs.save()
# بروزرسانی جدول بی‌نهایت (حذف قبلی‌ها و درج مجدد)
PhoneNumber.objects.filter(customer=newCs).delete()
for item in valid_phones:
PhoneNumber.objects.create(customer=newCs, title=item['title'], phone_number=item['phone'])
# بروزرسانی جدول شماره‌ها فقط در صورت ارسال شماره‌های جدید.
# اگر فرم شماره‌ای نفرستاده باشد (فیلدهای غیرفعال)، شماره‌های فعلی دست‌نخورده می‌مانند.
if valid_phones:
PhoneNumber.objects.filter(customer=newCs).delete()
for item in valid_phones:
PhoneNumber.objects.create(
customer=newCs, title=item['title'], phone_number=item['phone'],
)
# اگر فرم ویرایش ردیف‌های «اصلی» را مشخص کرده باشد، همان‌ها ذخیره می‌شوند
# (مبتنی بر خودِ شماره، نه ایندکس رکورد).
if primary_indices:
save_primary_normalized(
newCs, [phones_list[i] for i in primary_indices if i < len(phones_list)],
)
return redirect('/panel/customer/'+str(c_id))