feat: 添加飞书用户模块和订阅功能支持 - 新增feishu_users模块用于处理飞书用户身份验证和权限管理 - 新增subscriptions模块用于处理订阅相关功能 - 新增personalization模块用于个性化服务 - 在alembic迁移配置中注册新的模型模块 - 在API路由器中添加feishu_users和subscriptions路由 - 实现事件调度服务的改进,包括错误处理和状态更新优化 - 添加飞书命令处理的权限检查机制 - 实现飞书应用票据事件处理 - 改进审计日志记录功能 ```
106 lines
5.3 KiB
Python
106 lines
5.3 KiB
Python
from datetime import date, datetime
|
|
from decimal import Decimal
|
|
|
|
from sqlalchemy import (
|
|
Boolean,
|
|
Date,
|
|
DateTime,
|
|
ForeignKey,
|
|
Integer,
|
|
Numeric,
|
|
String,
|
|
UniqueConstraint,
|
|
)
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.core.database import Base
|
|
from app.modules.feishu_users.models import FeishuUser
|
|
from app.modules.business.models.common import TimestampMixin
|
|
|
|
|
|
class MarketInstrument(Base, TimestampMixin):
|
|
__tablename__ = "market_instruments"
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
symbol: Mapped[str] = mapped_column(String(32), unique=True, index=True)
|
|
name: Mapped[str] = mapped_column(String(128), index=True)
|
|
exchange: Mapped[str | None] = mapped_column(String(16), nullable=True, index=True)
|
|
instrument_type: Mapped[str] = mapped_column(String(16), default="stock", index=True)
|
|
industry: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True)
|
|
list_date: Mapped[date | None] = mapped_column(Date, nullable=True)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, index=True)
|
|
source_updated_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
|
|
|
|
class MarketDailyQuote(Base, TimestampMixin):
|
|
__tablename__ = "market_daily_quotes"
|
|
__table_args__ = (UniqueConstraint("symbol", "trade_date", name="uq_market_quote_day"),)
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
symbol: Mapped[str] = mapped_column(String(32), index=True)
|
|
trade_date: Mapped[date] = mapped_column(Date, index=True)
|
|
open_price: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True)
|
|
high_price: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True)
|
|
low_price: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True)
|
|
close_price: Mapped[Decimal] = mapped_column(Numeric(18, 4))
|
|
pre_close: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True)
|
|
pct_change: Mapped[Decimal | None] = mapped_column(Numeric(12, 4), nullable=True)
|
|
volume: Mapped[Decimal | None] = mapped_column(Numeric(20, 2), nullable=True)
|
|
amount_cny: Mapped[Decimal | None] = mapped_column(Numeric(20, 2), nullable=True)
|
|
pe: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True)
|
|
pb: Mapped[Decimal | None] = mapped_column(Numeric(18, 4), nullable=True)
|
|
total_market_value: Mapped[Decimal | None] = mapped_column(Numeric(20, 2), nullable=True)
|
|
|
|
|
|
class MarketFinancialMetric(Base, TimestampMixin):
|
|
__tablename__ = "market_financial_metrics"
|
|
__table_args__ = (UniqueConstraint("symbol", "period_end", name="uq_market_financial_period"),)
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
symbol: Mapped[str] = mapped_column(String(32), index=True)
|
|
period_end: Mapped[date] = mapped_column(Date, index=True)
|
|
revenue_yoy: Mapped[Decimal | None] = mapped_column(Numeric(12, 4), nullable=True)
|
|
net_profit_yoy: Mapped[Decimal | None] = mapped_column(Numeric(12, 4), nullable=True)
|
|
roe: Mapped[Decimal | None] = mapped_column(Numeric(12, 4), nullable=True)
|
|
debt_to_assets: Mapped[Decimal | None] = mapped_column(Numeric(12, 4), nullable=True)
|
|
operating_cashflow_yoy: Mapped[Decimal | None] = mapped_column(Numeric(12, 4), nullable=True)
|
|
|
|
|
|
class MarketMacroIndicator(Base, TimestampMixin):
|
|
__tablename__ = "market_macro_indicators"
|
|
__table_args__ = (UniqueConstraint("code", "period_date", name="uq_market_macro_period"),)
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
code: Mapped[str] = mapped_column(String(64), index=True)
|
|
name: Mapped[str] = mapped_column(String(128))
|
|
period_date: Mapped[date] = mapped_column(Date, index=True)
|
|
value: Mapped[Decimal] = mapped_column(Numeric(20, 6))
|
|
unit: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
source: Mapped[str] = mapped_column(String(64), default="tushare")
|
|
|
|
|
|
class MarketAnnouncement(Base, TimestampMixin):
|
|
__tablename__ = "market_announcements"
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
source_key: Mapped[str] = mapped_column(String(64), unique=True, index=True)
|
|
symbol: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
|
announcement_date: Mapped[date] = mapped_column(Date, index=True)
|
|
published_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
title: Mapped[str] = mapped_column(String(512))
|
|
category: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True)
|
|
source_url: Mapped[str | None] = mapped_column(String(1024), nullable=True)
|
|
source: Mapped[str] = mapped_column(String(64), default="tushare")
|
|
|
|
|
|
class MarketWatchlist(Base, TimestampMixin):
|
|
__tablename__ = "market_watchlists"
|
|
__table_args__ = (
|
|
UniqueConstraint("owner_id", "symbol", name="uq_market_watchlist_owner_symbol"),
|
|
)
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
owner_id: Mapped[int | None] = mapped_column(
|
|
ForeignKey("feishu_users.id", ondelete="CASCADE"),
|
|
nullable=True,
|
|
index=True,
|
|
)
|
|
owner: Mapped[FeishuUser | None] = relationship()
|
|
actor: Mapped[str] = mapped_column(String(128), index=True)
|
|
symbol: Mapped[str] = mapped_column(String(32), index=True)
|
|
enabled: Mapped[bool] = mapped_column(Boolean, default=True, index=True)
|