Files
fonrey/apps/client/models/core.py
Sisyphus ed40de4050 feat(client,setting): complete Phase 2 with partitioned client_follow_logs
- apps/client (11 models): Client, ClientContact, ClientRequirement,
  ClientSchoolPreference, ClientFollowLog (partitioned),
  ClientFollowLogAttachment, ClientViewing, ClientPropertyMatch,
  ClientStatusLog, ClientFavoriteFolder, ClientFolderItem
- apps/client/0002 RunSQL: PARTITION BY RANGE(created_at) for
  client_follow_logs + monthly partitions + default; triggers
  update_client_last_follow + update_client_viewing_progress;
  partial unique index on client_no WHERE deleted_at IS NULL
- apps/setting (4 models): LookupGroup, LookupItem, TenantSetting,
  FieldRequirementRule (tenant schema only per spec)

manage.py check green; all 9 Phase 2 apps complete.
2026-04-29 17:33:58 +08:00

148 lines
4.8 KiB
Python

from django.contrib.postgres.fields import ArrayField
from django.db import models
from core.enums import (
ClientActivityLevel,
ClientBuyingPurpose,
ClientGrade,
ClientIdType,
ClientInvalidReason,
ClientPaymentMethod,
ClientPropertiesOwned,
ClientPropertyUsage,
ClientStatus,
ClientTransactedPropertyType,
ClientTransactedType,
ClientTransferToPublicType,
ClientType,
)
from core.models.base import AuditedModel
class Client(AuditedModel):
client_no = models.CharField(max_length=30, unique=True)
client_type = models.CharField(
max_length=20, choices=ClientType.choices, default=ClientType.PRIVATE
)
status = models.CharField(
max_length=20, choices=ClientStatus.choices, default=ClientStatus.BUYING
)
grade = models.CharField(
max_length=5, choices=ClientGrade.choices, default=ClientGrade.C
)
property_usage = models.CharField(
max_length=30,
choices=ClientPropertyUsage.choices,
default=ClientPropertyUsage.RESIDENTIAL,
)
buying_purpose = ArrayField(
models.CharField(max_length=20, choices=ClientBuyingPurpose.choices),
blank=True,
default=list,
)
payment_method = models.CharField(
max_length=30, choices=ClientPaymentMethod.choices, blank=True, default=""
)
properties_owned = models.CharField(
max_length=20, choices=ClientPropertiesOwned.choices, blank=True, default=""
)
has_loan_record = models.BooleanField(null=True, blank=True)
id_type = models.CharField(
max_length=20, choices=ClientIdType.choices, blank=True, default=""
)
id_number_enc = models.BinaryField(null=True, blank=True)
source = models.CharField(max_length=50, blank=True, default="")
remarks = models.TextField(blank=True, default="")
is_starred = models.BooleanField(default=False)
is_pinned = models.BooleanField(default=False)
is_big_value = models.BooleanField(default=False)
is_protected = models.BooleanField(default=False)
prefers_new_house = models.BooleanField(null=True, blank=True)
transfer_to_public_type = models.CharField(
max_length=20,
choices=ClientTransferToPublicType.choices,
blank=True,
default="",
)
transferred_public_at = models.DateTimeField(null=True, blank=True)
invalid_reason = models.CharField(
max_length=30, choices=ClientInvalidReason.choices, blank=True, default=""
)
invalidated_at = models.DateTimeField(null=True, blank=True)
transacted_at = models.DateField(null=True, blank=True)
transacted_property = models.ForeignKey(
"fonrey_property.Property",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="transacted_clients",
)
transacted_price = models.DecimalField(
max_digits=12, decimal_places=2, null=True, blank=True
)
transacted_type = models.CharField(
max_length=20, choices=ClientTransactedType.choices, blank=True, default=""
)
transacted_property_type = models.CharField(
max_length=20,
choices=ClientTransactedPropertyType.choices,
blank=True,
default="",
)
first_recorder = models.ForeignKey(
"org.Staff",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="first_recorded_clients",
)
owner = models.ForeignKey(
"org.Staff",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="owned_clients",
)
org_unit = models.ForeignKey(
"org.OrgUnit",
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="clients",
)
activity_level = models.CharField(
max_length=20, choices=ClientActivityLevel.choices, blank=True, default=""
)
last_active_at = models.DateTimeField(null=True, blank=True)
last_follow_at = models.DateTimeField(null=True, blank=True)
commission_date = models.DateField(null=True, blank=True)
entrust_count = models.SmallIntegerField(default=1)
version = models.IntegerField(default=1)
class Meta:
db_table = "clients"
indexes = [
models.Index(fields=["client_type", "status"], name="idx_clients_type_stat"),
models.Index(fields=["owner"], name="idx_clients_owner"),
models.Index(fields=["org_unit"], name="idx_clients_org_unit"),
models.Index(
fields=["activity_level", "-last_active_at"],
name="idx_clients_activity",
),
models.Index(fields=["grade"], name="idx_clients_grade"),
models.Index(
fields=["-transferred_public_at"], name="idx_clients_transferred"
),
models.Index(fields=["-last_follow_at"], name="idx_clients_last_follow"),
]