from django.db import models class CustomerNameFixJob(models.Model): """وضعیت و checkpoint عملیات «افزودن پیشوند آقای/خانم به نام مشتریان». این مدل **فقط** برای مدیریت/بازیابی job است و هیچ اطلاعاتی دربارهٔ جنسیت یا هویت مشتری نگه نمی‌دارد. مدل ``Customer`` هیچ تغییر ساختاری نمی‌گیرد. """ class Status(models.TextChoices): RUNNING = "running", "در حال اجرا" PAUSED = "paused", "متوقف‌شده (قابل ادامه)" COMPLETED = "completed", "تکمیل‌شده" FAILED = "failed", "ناموفق" # شناسهٔ فایل ورودی: اگر hash تغییر کند، ادامهٔ job رد می‌شود. source_hash = models.CharField(max_length=64) algorithm_version = models.CharField(max_length=16, default="1") status = models.CharField(max_length=16, choices=Status.choices, default=Status.PAUSED) batch_size = models.PositiveIntegerField(default=200) # دامنهٔ job: بیشترین primary key مشتریان در لحظهٔ آغاز. مشتریان جدیدتر # (pk > initial_max_pk) عمداً خارج از دامنه می‌مانند. initial_max_pk = models.BigIntegerField(null=True, blank=True) # checkpoint: آخرین pk پردازش‌شده (به‌صورت اتمیک با تغییرات همان batch ثبت می‌شود). last_processed_pk = models.BigIntegerField(default=0) stats = models.JSONField(default=dict, blank=True) note = models.CharField(max_length=255, blank=True, default="") started_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) finished_at = models.DateTimeField(null=True, blank=True) # ضربان قفل: برای تشخیص job رهاشده پس از crash و جلوگیری از اجرای هم‌زمان. heartbeat_at = models.DateTimeField(null=True, blank=True) class Meta: verbose_name = "job اصلاح نام مشتری" verbose_name_plural = "jobهای اصلاح نام مشتری" def __str__(self): return f"job#{self.pk} {self.status} hash={self.source_hash[:8]} pk<={self.last_processed_pk}" class CacheTable(models.Model): key = models.CharField(max_length=50, unique=True) value = models.CharField(max_length=400) def __str__(self): return f'{self.key} # {self.value}'