"""用户私有产品小册子模型。""" import json from sqlalchemy import BigInteger, Column, Integer, SmallInteger, String, Text, TIMESTAMP, func from insurance.db.compat import db class UserProductMaterial(db.Model): """用户上传、解析并确认的产品小册子。""" __tablename__ = "insurance_user_product_materials" id = Column(BigInteger, primary_key=True, autoincrement=True) owner_user_id = Column(String(64), nullable=False, index=True, comment="上传用户 ID") tenant_id = Column(String(64), nullable=False, default="default", comment="租户 ID") company_id = Column(String(50), nullable=True, comment="关联保司 ID") company_name = Column(String(100), nullable=True, comment="保司名称") product_name = Column(String(150), nullable=True, comment="产品名称") plan_type = Column(String(20), nullable=True, comment="savings/ci/iul/other") original_name = Column(String(200), nullable=False, comment="原始文件名") file_key = Column(String(500), nullable=False, comment="相对 storage 根目录的文件键") file_size = Column(BigInteger, nullable=False, default=0, comment="文件字节数") page_count = Column(Integer, nullable=True, comment="PDF 页数") sha256 = Column(String(64), nullable=False, comment="文件 SHA-256") parse_status = Column(String(20), nullable=False, default="pending") parse_message = Column(String(500), nullable=False, default="") parse_error = Column(Text, nullable=True) parse_task_id = Column(String(200), nullable=True) parse_started_at = Column(TIMESTAMP, nullable=True) parse_finished_at = Column(TIMESTAMP, nullable=True) parsed_rules = Column(Text, nullable=True, comment="系统解析结果 JSON") confirmed_rules = Column(Text, nullable=True, comment="用户确认结果 JSON") confirmed_by = Column(String(64), nullable=True) confirmed_at = Column(TIMESTAMP, nullable=True) review_status = Column(String(20), nullable=False, default="private") status = Column(SmallInteger, nullable=False, default=1) deleted_at = Column(TIMESTAMP, nullable=True) created_at = Column(TIMESTAMP, server_default=func.now()) updated_at = Column(TIMESTAMP, server_default=func.now(), onupdate=func.now()) @staticmethod def _safe_json(value): if not value: return None try: return json.loads(value) except (json.JSONDecodeError, TypeError): return None def to_dict(self): return { "id": self.id, "ownerUserId": self.owner_user_id, "tenantId": self.tenant_id, "companyId": self.company_id, "companyName": self.company_name or "", "productName": self.product_name or "", "displayName": self.product_name or self.original_name, "planType": self.plan_type or "other", "originalName": self.original_name, "fileSize": self.file_size or 0, "pageCount": self.page_count, "parseStatus": self.parse_status, "parseMessage": self.parse_message or "", "parseError": self.parse_error or "", "parsedRules": self._safe_json(self.parsed_rules), "confirmedRules": self._safe_json(self.confirmed_rules), "confirmedBy": self.confirmed_by, "confirmedAt": self.confirmed_at.isoformat() if self.confirmed_at else None, "reviewStatus": self.review_status, "status": self.status, "createdAt": self.created_at.isoformat() if self.created_at else None, "updatedAt": self.updated_at.isoformat() if self.updated_at else None, }