fix del customer and phone number feild

This commit is contained in:
javad committed 2026-07-15 22:54:29 +03:30
1 parent 8d5665a1dc
commit c33184a996
5 files changed
+296 -68

No files matched your search

@@ -0,0 +1,29 @@
# Generated by Django 3.2.25 on 2026-07-15 19:20
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('admin_panel', '0053_storeroom_owners'),
]
operations = [
migrations.AddField(
model_name='phonenumber',
name='title',
field=models.CharField(blank=True, default='تلفن', help_text='عنوان شماره (مثل: موبایل پدر)', max_length=50, null=True),
),
migrations.AlterField(
model_name='phonenumber',
name='customer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='phones', to='admin_panel.customer'),
),
migrations.AlterField(
model_name='phonenumber',
name='phone_number',
field=models.CharField(max_length=20),
),
]
+6 -3
View File
@@ -58,9 +58,12 @@ class Customer(models.Model):
self.save()
class PhoneNumber(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
phone_number = models.CharField(max_length=11)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='phones')
title = models.CharField(max_length=50, default='تلفن', blank=True, null=True, help_text="عنوان شماره (مثل: موبایل پدر)")
phone_number = models.CharField(max_length=20)
def __str__(self):
return f"{self.title}: {self.phone_number}"
class StoreRoom(models.Model):
class Meta:
@@ -3,6 +3,18 @@
{% load static %}
{% block bodyPage %}
{% if messages %}
<div class="columns m-0">
<div class="column is-12 px-2 pt-3 pb-0">
{% for message in messages %}
<div class="notification {% if message.tags == 'error' %}is-danger{% elif message.tags == 'success' %}is-success{% else %}is-info{% endif %} is-light mb-2">
<button class="delete close-notification" type="button"></button>
<strong>{{ message }}</strong>
</div>
{% endfor %}
</div>
</div>
{% endif %}
<div class="">
<div class="columns m-0">
<div class="column is-12-mobile is-4-desktop">
@@ -14,6 +26,7 @@
</p>
<span id="showUserDT" class="button level-item">مشاهده مشخصات</span>
</div>
<div id="userDT" class="is-hidden-mobile">
<div class="field column is-12-desktop is-12-mobile m-0">
<label class="label">نام ونام خانوادگی</label>
@@ -29,24 +42,83 @@
</div>
</div>
<div class="field column is-9-desktop is-9-mobile m-0">
<label class="label">تلفن همراه</label>
<div class="control">
<input disabled value="{{ customer.phone1 }}" name="phone1" id="phone-1" class="input ss02 {% if not perms.admin_panel.ViewStore %}is-hidden{% endif %} an_phone" type="text" placeholder="تلفن 1">
<input disabled value="{{ customer.phone2 }}" name="phone2" id="phone-2" class="input ss02 {% if not perms.admin_panel.ViewStore %}is-hidden{% endif %} an_phone" type="text" placeholder="تلفن 2">
<input disabled value="{{ customer.phone3 }}" name="phone3" id="phone-3" class="input ss02 {% if not perms.admin_panel.ViewStore %}is-hidden{% endif %} an_phone" type="text" placeholder="تلفن 3">
{% if not perms.admin_panel.ViewStore %}
<p class="pb-4 ss02 ">
<a href="tel:{% if customer.phone1|first in '0' %}{{ customer.phone1 }}{% else %}0{{ customer.phone1 }}{% endif %}">{{ customer.phone1 }}</a>
</p>
<p class="pb-4 ss02 ">
<a href="tel:{% if customer.phone2|first in '0' %}{{ customer.phone2 }}{% else %}0{{ customer.phone2 }}{% endif %}">{{ customer.phone2 }}</a>
</p>
<p class="pb-4 ss02 ">
<a href="tel:{% if customer.phone3|first in '0' %}{{ customer.phone3 }}{% else %}0{{ customer.phone3 }}{% endif %}">{{ customer.phone3 }}</a>
</p>
<div class="field column is-12-desktop is-12-mobile m-0">
<label class="label">شماره‌های تماس</label>
<div id="dynamic-phones-edit">
{% if customer.phones.all %}
{% for phone_obj in customer.phones.all %}
<div class="field has-addons mt-2 ss02">
<div class="control" style="width: 35%;">
<input disabled value="{{ phone_obj.title }}" name="phone_titles" class="input" type="text" placeholder="عنوان">
</div>
<div class="control is-expanded">
<input disabled value="{{ phone_obj.phone_number }}" name="phones" class="input an_phone" type="text" placeholder="تلفن">
</div>
{% if perms.admin_panel.ViewStore %}
<div class="control">
<button type="button" disabled class="button is-danger remove-phone-btn">-</button>
</div>
{% endif %}
</div>
{% if not perms.admin_panel.ViewStore %}
<p class="pb-1 ss02">
<small class="has-text-grey">{{ phone_obj.title }}:</small> <a href="tel:{{ phone_obj.phone_number }}">{{ phone_obj.phone_number }}</a>
</p>
{% endif %}
{% endfor %}
{% else %}
{% if customer.phone1 %}
<div class="field has-addons ss02 mt-2">
<div class="control" style="width: 35%;">
<input disabled value="تلفن 1" name="phone_titles" class="input" type="text" placeholder="عنوان">
</div>
<div class="control is-expanded">
<input disabled value="{{ customer.phone1 }}" name="phones" class="input an_phone" type="text" placeholder="تلفن">
</div>
{% if perms.admin_panel.ViewStore %}
<div class="control"><button type="button" disabled class="button is-danger remove-phone-btn">-</button></div>
{% endif %}
</div>
{% endif %}
{% if customer.phone2 %}
<div class="field has-addons ss02 mt-2">
<div class="control" style="width: 35%;">
<input disabled value="تلفن 2" name="phone_titles" class="input" type="text">
</div>
<div class="control is-expanded">
<input disabled value="{{ customer.phone2 }}" name="phones" class="input an_phone" type="text">
</div>
{% if perms.admin_panel.ViewStore %}
<div class="control"><button type="button" disabled class="button is-danger remove-phone-btn">-</button></div>
{% endif %}
</div>
{% endif %}
{% if customer.phone3 %}
<div class="field has-addons ss02 mt-2">
<div class="control" style="width: 35%;">
<input disabled value="تلفن 3" name="phone_titles" class="input" type="text">
</div>
<div class="control is-expanded">
<input disabled value="{{ customer.phone3 }}" name="phones" class="input an_phone" type="text">
</div>
{% if perms.admin_panel.ViewStore %}
<div class="control"><button type="button" disabled class="button is-danger remove-phone-btn">-</button></div>
{% endif %}
</div>
{% endif %}
{% endif %}
</div>
{% if perms.admin_panel.ViewStore %}
<button type="button" disabled id="add-more-phone-edit" class="button is-small is-info mt-2 w-100 add-phone-btn">
+ افزودن شماره دیگر
</button>
{% endif %}
</div>
@@ -84,6 +156,7 @@
</div>
</div>
</form>
</div>
@@ -586,14 +659,49 @@
$(document).ready(function() {
var test = 0
// فعال‌سازی دکمه بستن برای پیام‌های سیستم (جدید)
$(".close-notification").click(function(){
$(this).parent().fadeOut(300, function() {
$(this).remove();
});
});
var test = 0;
$("#enEdit").click(function(){
$("#formcsEdit").find("input").prop('disabled', false);
// فعال کردن دکمه‌های کنترل تلفن
$("#formcsEdit").find("button.remove-phone-btn, button.add-phone-btn").prop('disabled', false);
$("#enEdit").addClass("is-hidden");
$("#editCs").removeClass("is-hidden");
});
// توابع داینامیک فرم ویرایش
$(document).on('click', '.add-phone-btn', function() {
var phoneRow = `
<div class="field has-addons mt-2 ss02">
<div class="control" style="width: 35%;">
<input name="phone_titles" class="input" type="text" placeholder="عنوان">
</div>
<div class="control is-expanded">
<input name="phones" class="input an_phone" type="text" placeholder="شماره تماس جدید">
</div>
<div class="control">
<button type="button" class="button is-danger remove-phone-btn">-</button>
</div>
</div>`;
$("#dynamic-phones-edit").append(phoneRow);
});
$(document).on('click', '.remove-phone-btn', function() {
if ($("#dynamic-phones-edit .has-addons").length > 1) {
$(this).closest('.field.has-addons').remove();
} else {
alert("حداقل یک شماره تماس باید وجود داشته باشد.");
}
});
$("#showUserDT").click(function(){
if( $(this).html()=='مشاهده مشخصات' ){
$(this).html('مخفی کردن');
@@ -155,14 +155,22 @@
</div>
</div>
<div class="field column is-4-desktop is-12-mobile m-0">
<label class="label">تلفن همراه</label>
<div class="control">
<input name="phone1" id="phone-1" class="input an_phone" type="text" placeholder="تلفن 1">
<input name="phone2" id="phone-2" class="input an_phone" type="text" placeholder="تلفن 2">
<input name="phone3" id="phone-3" class="input an_phone" type="text" placeholder="تلفن 3">
<div class="field column is-6-desktop is-12-mobile m-0">
<label class="label">شماره‌های تماس</label>
<div id="dynamic-phones-add">
<div class="field has-addons">
<div class="control" style="width: 35%;">
<input name="phone_titles" class="input" type="text" placeholder="عنوان (مثلاً موبایل)">
</div>
<div class="control is-expanded">
<input name="phones" class="input an_phone" type="text" placeholder="شماره تماس">
</div>
<div class="control">
<button type="button" class="button is-info add-phone-btn">+</button>
</div>
</div>
</div>
</div>
</div>
<div class="field column is-4-desktop is-12-mobile m-0">
<label class="label">تاریخ نصب</label>
@@ -251,6 +259,25 @@ $(document).ready(function() {
kamaDatepicker('persianDateP', { buttonsColor: "red", forceFarsiDigits: true });
$(document).on('click', '.add-phone-btn', function() {
var phoneRow = `
<div class="field has-addons mt-2">
<div class="control" style="width: 35%;">
<input name="phone_titles" class="input" type="text" placeholder="عنوان">
</div>
<div class="control is-expanded">
<input name="phones" class="input an_phone" type="text" placeholder="شماره تماس">
</div>
<div class="control">
<button type="button" class="button is-danger remove-phone-btn">-</button>
</div>
</div>`;
$(this).closest('div[id^="dynamic-phones"]').append(phoneRow);
});
$(document).on('click', '.remove-phone-btn', function() {
$(this).closest('.field.has-addons').remove();
});
$("#createCS").click(function(){
var u_name = $(".addNewUser").find('.an_name').val();
+102 -41
View File
@@ -611,7 +611,7 @@ def customers(request):
all_customers = Customer.objects.filter(laghv_bazdid=True).order_by('-create_date')
else:
searchStatus = False
all_customers = Customer.objects.all().order_by('-create_date')
all_customers = Customer.objects.filter(is_active=True).order_by('-create_date')
paginator = Paginator(all_customers, 25) # Show 25 contacts per page.
page_number = request.GET.get('page', None)
@@ -671,7 +671,7 @@ def customerNew(request ,c_id):
@login_required(login_url='/panel/p_login/')
def customerNew2(request ,c_id):
customer = Customer.objects.get(id=c_id)
customer = get_object_or_404(Customer, id=c_id, is_active=True)
categorys = ProductCategory.objects.all()
factorha = Factor.objects.filter(customer__id = c_id)
@@ -767,70 +767,86 @@ def productMojodi(request, p_id):
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', '')
# دریافت آرایه‌های عنوان و شماره تلفن
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()
})
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()
year, month, day = map(int, installDate.split('/'))
installDate_gregorian = 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.installDate = installDate_gregorian
newCs.idCode = idnCode
# حفظ سازگاری با کدهای قدیمی (ریختن ۳ شماره اول در فیلدهای قدیمی)
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()
#return HttpResponse(installDate)
# ذخیره شماره‌ها به صورت نامحدود در جدول PhoneNumber
for item in valid_phones:
PhoneNumber.objects.create(customer=newCs, title=item['title'], phone_number=item['phone'])
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])
# دریافت آرایه‌های عنوان و شماره تلفن
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()
})
#return HttpResponse(year)
installDate = JalaliDate(year, month, day).to_gregorian()
year, month, day = map(int, installDate.split('/'))
installDate_gregorian = JalaliDate(year, month, day).to_gregorian()
newCs = Customer.objects.get(id=c_id)
newCs = get_object_or_404(Customer, 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.installDate = installDate_gregorian
newCs.idCode = idnCode
if laghv_bazdid == 'true':
newCs.laghv_bazdid = True
else:
newCs.laghv_bazdid = False
newCs.laghv_bazdid = True if laghv_bazdid == 'true' else False
# آپدیت فیلدهای قدیمی جهت حفظ سازگاری
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()
#return HttpResponse(installDate)
return redirect('/panel/customer/'+str(c_id))
# بروزرسانی جدول بی‌نهایت (حذف قبلی‌ها و درج مجدد)
PhoneNumber.objects.filter(customer=newCs).delete()
for item in valid_phones:
PhoneNumber.objects.create(customer=newCs, title=item['title'], phone_number=item['phone'])
return redirect('/panel/customer/'+str(c_id))
@login_required(login_url='/panel/p_login/')
def entezar(request):
@@ -1752,14 +1768,59 @@ def FactorDel(request, c_id, f_id):
return redirect('admin_panel:customerFactors', c_id=c_id)
from django.contrib import messages
from django.shortcuts import get_object_or_404, redirect
import logging
logger = logging.getLogger(__name__)
@login_required(login_url='/panel/p_login/')
@permission_required('admin_panel.DelCustomer', raise_exception=True)
def customerDel(request, c_id):
customer_obj = get_object_or_404(Customer, id=c_id)
try:
Customer.objects.get(id=c_id).delete()
# ۱. بررسی وجود هرگونه سابقه مالی/حسابداری (حتی با مانده صفر)
has_articles = Article.objects.filter(customer=customer_obj).exists()
# ۲. بررسی وجود هرگونه سابقه چک یا نسیه (حتی در صورت پاس شدن و تسویه کامل)
has_sarresids = Sarresid.objects.filter(customer=customer_obj).exists()
# ۳. بررسی وجود هرگونه فاکتور ثبت شده برای این مشتری
has_factors = Factor.objects.filter(customer=customer_obj).exists()
# ۴. بررسی وجود هرگونه سابقه اقدام، بازدید یا نظرسنجی
has_actions = Action.objects.filter(customer=customer_obj).exists()
# ۵. اگر هر کدام از این سوابق وجود داشته باشد، به هیچ عنوان اجازه غیرفعال‌سازی/حذف نمی‌دهیم
if has_articles or has_sarresids or has_factors or has_actions:
error_msg = f"عملیات ناموفق: مشتری '{customer_obj.name_family}' به دلیل داشتن سابقه در سیستم قابل حذف نیست! دلایل: "
reasons = []
if has_articles:
reasons.append("داشتن تراکنش مالی یا گردش حسابداری")
if has_sarresids:
reasons.append("داشتن سابقه چک یا نسیه (حتی تسویه شده)")
if has_factors:
reasons.append("داشتن فاکتور ثبت‌شده")
if has_actions:
reasons.append("داشتن سابقه اقدامات، بازدید یا نظرسنجی")
error_msg += "، ".join(reasons) + "."
# ارسال پیام خطا به تمپلیت و بازگرداندن کاربر به صفحه قبلی
messages.error(request, error_msg)
return redirect(request.META.get('HTTP_REFERER', '/panel/customers/'))
# ۶. در صورتی که مشتری کاملاً خام بود و هیچ سابقه‌ای در هیچ بخشی نداشت، حذف می‌شود
customer_obj.delete()
messages.success(request, f"مشتری '{customer_obj.name_family}' که فاقد هرگونه سابقه‌ای بود، با موفقیت از سیستم حذف شد.")
return redirect('/panel/customers/')
except:
return HttpResponse("خطا در حذف مشتری")
except Exception as e:
logger.error(f"Error in deleting customer {c_id}: {str(e)}", exc_info=True)
messages.error(request, "خطای سیستمی در بررسی سوابق و حذف مشتری رخ داد.")
return redirect(request.META.get('HTTP_REFERER', '/panel/customers/'))
@login_required(login_url='/panel/p_login/')