- 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.
148 lines
4.8 KiB
Python
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"),
|
|
]
|