96 lines
4.2 KiB
Python
96 lines
4.2 KiB
Python
"""基金模型。
|
||
|
||
管理基金类型、存续期、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)
|
||
)
|