"""基金模型。 管理基金类型、存续期、LP 构成等信息,支撑评价指标体系的动态权重计算。 """ import uuid from datetime import date, datetime, timezone from sqlalchemy import Boolean, Date, DateTime, Float, ForeignKey, Integer, String from sqlalchemy.orm import Mapped, mapped_column from app.core.database import Base from app.core.types import JSONBType class Fund(Base): """基金信息 — 管理基金类型和存续期。""" __tablename__ = "funds" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) tenant_id: Mapped[str] = mapped_column(String(36), ForeignKey("tenants.id"), nullable=False, index=True) name: Mapped[str] = mapped_column(String(200), nullable=False, comment="基金名称") # 基金类型:angel/early_vc/growth_vc/pe/cvc/fof/distress/esg fund_type: Mapped[str] = mapped_column(String(50), nullable=False, comment="基金类型") # 投资策略:growth/value/empowerment/turnaround strategy: Mapped[str] = mapped_column(String(50), nullable=False, default="growth", comment="投资策略") # 存续期信息 established_date: Mapped[date | None] = mapped_column(Date, nullable=True, comment="基金成立日") total_lifespan_months: Mapped[int] = mapped_column(Integer, nullable=False, default=84, comment="总存续期(月)") investment_period_months: Mapped[int] = mapped_column(Integer, nullable=False, default=48, comment="投资期(月)") # LP 构成 — {government: 30, market: 50, corporate: 20} lp_composition_json: Mapped[dict | None] = mapped_column(JSONBType, nullable=True, comment="LP 构成百分比") # 地域 primary_market: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="主要市场:china_mainland/us/sea/europe") # 状态 is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, comment="是否活跃") # 元数据 created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=lambda: datetime.now(timezone.utc) ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc), ) @property def current_lifecycle(self) -> str: """根据当前日期自动计算基金存续期阶段。 返回:investment / growth / exit_preparation / liquidation """ if not self.established_date: return "investment" today = date.today() months_elapsed = (today.year - self.established_date.year) * 12 + (today.month - self.established_date.month) if months_elapsed < self.investment_period_months: return "investment" elif months_elapsed < self.total_lifespan_months - 24: return "growth" elif months_elapsed < self.total_lifespan_months - 12: return "exit_preparation" else: return "liquidation" class CompanyFundLink(Base): """企业-基金关联 — 一个企业可能被多支基金投资。""" __tablename__ = "company_fund_links" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) company_id: Mapped[str] = mapped_column(String(36), ForeignKey("companies.id"), nullable=False, index=True) fund_id: Mapped[str] = mapped_column(String(36), ForeignKey("funds.id"), nullable=False, index=True) investment_date: Mapped[date | None] = mapped_column(Date, nullable=True, comment="投资日期") investment_stage: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="投资时企业阶段") round: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="轮次") amount: Mapped[float | None] = mapped_column(Float, nullable=True, comment="投资金额(万元)") ownership_pct: Mapped[float | None] = mapped_column(Float, nullable=True, comment="持股比例(%)") is_current: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, comment="当前是否持有") created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=lambda: datetime.now(timezone.utc) )