from django.contrib.postgres.fields import ArrayField from django.db import models from core.enums import ( ClientPropertyMatchGroup, ClientPropertyMatchSource, ClientPropertyMatchStatus, ClientStatusLogChangeType, ClientViewingIntent, ClientViewingType, ) from core.models.base import UUIDPrimaryKeyModel class ClientViewing(UUIDPrimaryKeyModel): client = models.ForeignKey( "fonrey_client.Client", on_delete=models.RESTRICT, related_name="viewings" ) property = models.ForeignKey( "fonrey_property.Property", on_delete=models.RESTRICT, related_name="client_viewings", ) viewing_type = models.CharField( max_length=20, choices=ClientViewingType.choices, default=ClientViewingType.VIEWING ) agent = models.ForeignKey( "org.Staff", null=True, blank=True, on_delete=models.SET_NULL, related_name="led_viewings", ) companion_ids = ArrayField(models.UUIDField(), blank=True, default=list) cooperator_ids = ArrayField(models.UUIDField(), blank=True, default=list) scheduled_at = models.DateTimeField(null=True, blank=True) viewing_start_at = models.DateTimeField(null=True, blank=True) viewing_end_at = models.DateTimeField(null=True, blank=True) situation = models.TextField(blank=True, default="") client_intent = models.CharField( max_length=20, choices=ClientViewingIntent.choices, blank=True, default="" ) viewing_progress = models.SmallIntegerField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) deleted_at = models.DateTimeField(null=True, blank=True) created_by = models.ForeignKey( "org.Staff", null=True, blank=True, on_delete=models.SET_NULL, related_name="created_client_viewings", ) class Meta: db_table = "client_viewings" verbose_name = "带看记录" verbose_name_plural = "带看记录" indexes = [ models.Index( fields=["client", "-viewing_start_at"], name="idx_cv_client_time" ), models.Index(fields=["property"], name="idx_cv_property"), models.Index(fields=["agent"], name="idx_cv_agent"), ] class ClientPropertyMatch(UUIDPrimaryKeyModel): client = models.ForeignKey( "fonrey_client.Client", on_delete=models.CASCADE, related_name="property_matches" ) property = models.ForeignKey( "fonrey_property.Property", on_delete=models.CASCADE, related_name="client_matches", ) match_source = models.CharField( max_length=20, choices=ClientPropertyMatchSource.choices, default=ClientPropertyMatchSource.RECORDED, ) match_group = models.CharField( max_length=30, choices=ClientPropertyMatchGroup.choices, blank=True, default="" ) match_score = models.DecimalField( max_digits=5, decimal_places=2, null=True, blank=True ) match_reasons = models.JSONField(null=True, blank=True) status = models.CharField( max_length=20, choices=ClientPropertyMatchStatus.choices, default=ClientPropertyMatchStatus.SUGGESTED, ) shared_at = models.DateTimeField(null=True, blank=True) feedback = models.CharField(max_length=50, blank=True, default="") calculated_at = models.DateTimeField(auto_now_add=True) created_by = models.ForeignKey( "org.Staff", null=True, blank=True, on_delete=models.SET_NULL, related_name="created_matches", ) class Meta: db_table = "client_property_matches" verbose_name = "智能配房" verbose_name_plural = "智能配房" constraints = [ models.UniqueConstraint( fields=["client", "property"], name="uq_client_match_pair" ), ] indexes = [ models.Index( fields=["client", "match_source", "match_group"], name="idx_cpm_client_grp", ), models.Index(fields=["client", "status"], name="idx_cpm_status"), ] class ClientStatusLog(models.Model): """Audit log; record-level immutable (no deleted_at).""" id = models.UUIDField(primary_key=True) client = models.ForeignKey( "fonrey_client.Client", on_delete=models.RESTRICT, related_name="status_logs" ) change_type = models.CharField( max_length=30, choices=ClientStatusLogChangeType.choices ) old_value = models.JSONField(null=True, blank=True) new_value = models.JSONField(null=True, blank=True) reason = models.TextField(blank=True, default="") operator = models.ForeignKey( "org.Staff", on_delete=models.RESTRICT, related_name="client_status_changes" ) operated_at = models.DateTimeField(auto_now_add=True) class Meta: db_table = "client_status_logs" verbose_name = "客源状态变更日志" verbose_name_plural = "客源状态变更日志" indexes = [ models.Index(fields=["client", "-operated_at"], name="idx_csl_client"), models.Index(fields=["change_type", "-operated_at"], name="idx_csl_type"), ]