Files

75 lines
2.7 KiB
Python

"""消息通知与智能预警模型:
1. Notification 站内消息/通知
2. AlertRule 业务预警规则(库存低限预警、应收账款逾期催收预警等)
"""
from django.conf import settings
from django.db import models
from apps.core.base_models import TenantScopedModel
class Notification(TenantScopedModel):
"""消息通知。"""
CATEGORY_CHOICES = [
("info", "系统通知"),
("warning", "业务预警"),
("error", "异常提醒"),
("audit", "审批待办"),
]
recipient = models.ForeignKey(
settings.AUTH_USER_MODEL,
null=True,
blank=True,
on_delete=models.CASCADE,
related_name="notifications",
help_text="接收人(为空表示租户内广播)",
)
title = models.CharField(max_length=128)
content = models.TextField()
category = models.CharField(max_length=16, choices=CATEGORY_CHOICES, default="info")
link = models.CharField(max_length=255, blank=True, default="", help_text="跳转路由")
is_read = models.BooleanField(default=False)
read_at = models.DateTimeField(null=True, blank=True)
extra_data = models.JSONField(default=dict, blank=True)
class Meta:
db_table = "notify_notification"
indexes = [
models.Index(fields=["tenant", "recipient", "is_read"]),
models.Index(fields=["tenant", "-created_at"]),
]
ordering = ["-created_at"]
def __str__(self):
return f"[{self.get_category_display()}] {self.title} (已读: {self.is_read})"
class AlertRule(TenantScopedModel):
"""业务预警规则配置。"""
RULE_TYPE_CHOICES = [
("inventory_low", "库存缺货/下限预警"),
("receivable_overdue", "应收账款逾期催款预警"),
("stock_backlog", "商品呆滞积压预警"),
("batch_expiry", "批次近效期预警"),
("risk_score", "AI 应收风险预警(threshold=风险分数线)"),
]
code = models.CharField(max_length=64, help_text="规则代码")
name = models.CharField(max_length=128, help_text="预警规则名称")
rule_type = models.CharField(max_length=32, choices=RULE_TYPE_CHOICES)
threshold = models.DecimalField(max_digits=18, decimal_places=4, default=10, help_text="预警阈值(如天数或数量)")
is_enabled = models.BooleanField(default=True)
channels = models.JSONField(default=list, blank=True, help_text="通知渠道 ['in_app', 'webhook']")
class Meta:
db_table = "notify_alert_rule"
unique_together = [("tenant", "code")]
verbose_name_plural = "业务预警规则"
ordering = ["code"]
def __str__(self):
return f"{self.name} (阈值: {self.threshold}) [{ '启用' if self.is_enabled else '停用' }]"