from django.db import models class Customer(models.Model): class Meta: permissions = [ ("AddCustomer", "AddCustomer"), ("DelCustomer", "DelCustomer"), ("EditCustomer", "EditCustomer"), ("ViewCustomer", "ViewCustomer") ] name_family = models.CharField(max_length=200) address = models.CharField(max_length=200) # توضیحات آزاد مشتری؛ متن‌های غیرشماره‌ای که از فیلدهای تلفن پاک‌سازی می‌شوند # اینجا نگه داشته می‌شوند تا هیچ داده‌ای از سیستم حذف نشود. notes = models.TextField( blank=True, default="", verbose_name="توضیحات", help_text="یادداشت آزاد دربارهٔ مشتری؛ متن‌های حذف‌شدهٔ فیلدهای تلفن هم اینجا ثبت می‌شوند.", ) phone1 = models.CharField(max_length=20, default='') phone2 = models.CharField(max_length=20, default='', null=True, blank=True) phone3 = models.CharField(max_length=20, default='', null=True, blank=True) idCode = models.CharField(max_length=20, default='', null=True, blank=True) installDate = models.DateField(auto_now_add=True) create_date = models.DateTimeField(auto_now_add=True) last_bazdid_dt = models.DateTimeField(null=True, blank=True) laghv_bazdid = models.BooleanField(null=True, blank=True, default=False) # فیلد جدید برای حذف نرم (بدون تداخل با داده‌های قبلی) is_active = models.BooleanField(default=True, null=True, blank=True, help_text="وضعیت فعالیت مشتری") # شماره‌های «اصلی» گیرندهٔ پیامک، به‌صورت مقدارِ خودِ شماره (نرمال‌شده، جدا با کاما). # چرا مقدار و نه کلیدِ رکورد؟ چون دادهٔ مشتریان دائماً افزوده/ویرایش/حذف می‌شود و # کلید رکورد در بازسازی‌ها از بین می‌رود؛ ولی شماره پایدار است. اگر شماره‌ای حذف یا # ویرایش شود، این انتخاب خودبه‌خود بی‌اثر می‌شود و سیستم به شمارهٔ اول برمی‌گردد. sms_primary_phones = models.CharField( max_length=100, blank=True, default="", verbose_name="شماره‌های اصلی پیامک", help_text="شماره‌های نرمال‌شده (+98…) جدا‌شده با کاما؛ خالی = شمارهٔ اول مشتری.", ) # ------------------------------------------------------------------ # «قرار بعدی» — تعویقِ دستیِ بازدید (تصمیم محصولی) # ------------------------------------------------------------------ # این ستون **اعتبار مستقل ندارد**: فقط وقتی اثر دارد که یک اقدام «هماهنگی» # فعال (``waite``/``finish``) با تاریخ آینده برای همان مشتری وجود داشته باشد. # منبع حقیقت همچنان جدول ``Action`` است و این مقدار یک میان‌بر سریع برای # نمایش/فیلتر است. اگر هماهنگی حذف/لغو شود، این مقدار خودبه‌خود بی‌اثر می‌شود # (نگاه کنید به ``visit_policy.manual_holds_map``). visit_hold_until = models.DateTimeField( null=True, blank=True, verbose_name="قرار بعدی (تعویق بازدید)", help_text="تا پایان این روز پیگیری لازم نیست؛ از فرم «هماهنگی» تنظیم می‌شود.", ) visit_hold_set_at = models.DateTimeField( null=True, blank=True, verbose_name="زمان ثبت قرار", help_text="برای حسابرسی: آخرین باری که مقدار «قرار بعدی» نوشته شد.", ) def __str__(self): return self.name_family # بازنویسی متد حذف: جلوگیری از فاجعه در دیتابیس def delete(self, *args, **kwargs): # به جای حذف فیزیکی که انبار و فاکتورها را نابود می‌کند، مشتری را غیرفعال می‌کنیم self.is_active = False self.save() class PhoneNumber(models.Model): 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) # توجه: «شمارهٔ اصلی پیامک» روی خودِ Customer.sms_primary_phones نگه داشته می‌شود # (کلیدش مقدار شماره است، نه رکورد) تا با افزودن/حذف/ویرایش مداوم مشتریان از بین نرود. def __str__(self): return f"{self.title}: {self.phone_number}"