交易流水对账明细导出完成
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from sqlalchemy import Float, ForeignKey, Index, String
|
||||
from sqlalchemy import Float, ForeignKey, Index, Integer, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.models.base import Base, TimestampMixin
|
||||
@@ -12,13 +12,17 @@ class CreditRecord(Base, TimestampMixin):
|
||||
Index("uq_credit_records_user_biz_key", "user_id", "biz_key", unique=True),
|
||||
Index("ix_credit_records_user_refund_for_biz_key", "user_id", "refund_for_biz_key"),
|
||||
Index("ix_credit_records_related_type", "related_id", "type"),
|
||||
Index("ix_credit_records_owner", "owner_type", "owner_id"),
|
||||
Index("ix_credit_records_subject_media", "credit_subject", "media_type"),
|
||||
Index("ix_credit_records_source_module_scene", "source_module", "billing_scene"),
|
||||
Index("ix_credit_records_user_kind_time", "user_type_snapshot", "frontend_user_kind_snapshot", "created_at"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(32), primary_key=True)
|
||||
user_id: Mapped[str] = mapped_column(
|
||||
String(32), ForeignKey("users.id", ondelete="CASCADE"), index=True
|
||||
)
|
||||
type: Mapped[str] = mapped_column(String(16))
|
||||
type: Mapped[str] = mapped_column(String(16), index=True)
|
||||
amount: Mapped[float] = mapped_column(Float)
|
||||
balance_after: Mapped[float] = mapped_column(Float)
|
||||
description: Mapped[str] = mapped_column(String(256))
|
||||
@@ -31,3 +35,34 @@ class CreditRecord(Base, TimestampMixin):
|
||||
# 如果当前流水是退款,记录它退的是哪一次扣费。
|
||||
# 例如:generation_record:{record_id}:attempt:1:media:charge
|
||||
refund_for_biz_key: Mapped[str | None] = mapped_column(String(160), nullable=True, index=True)
|
||||
|
||||
# 账务快照字段:保证业务步骤/资源软删后,流水仍可独立展示。
|
||||
owner_type: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
owner_id: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
attempt_no: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
|
||||
charge_kind: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
||||
charge_action: Mapped[str | None] = mapped_column(String(16), nullable=True)
|
||||
credit_subject: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
||||
media_type: Mapped[str | None] = mapped_column(String(16), nullable=True, index=True)
|
||||
billing_scene: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
|
||||
source_module: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
source_project_id: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
source_step_id: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
source_step_code: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
|
||||
token_usage_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
||||
input_tokens: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
output_tokens: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
total_tokens: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
|
||||
|
||||
engine_type: Mapped[str | None] = mapped_column(String(16), nullable=True)
|
||||
engine_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
||||
engine_name: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
||||
engine_provider: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
||||
engine_model_name: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
||||
|
||||
user_type_snapshot: Mapped[str | None] = mapped_column(String(16), nullable=True, index=True)
|
||||
frontend_user_kind_snapshot: Mapped[str | None] = mapped_column(String(16), nullable=True, index=True)
|
||||
|
||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, ForeignKey, Index, Integer, JSON, String, Text
|
||||
from sqlalchemy import Boolean, DateTime, Float, ForeignKey, Index, Integer, JSON, String, Text
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
@@ -72,3 +72,11 @@ class ModuleGenerationStep(Base, TimestampMixin, SoftDeleteMixin):
|
||||
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
# 提词优化成本快照,避免后台/详情页反复解析 output_json.usage。
|
||||
token_usage_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
||||
model_config_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
||||
input_tokens: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
output_tokens: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
total_tokens: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
text_credits_cost: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, Integer, String
|
||||
from sqlalchemy import ForeignKey, Index, Integer, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.models.base import Base, TimestampMixin
|
||||
@@ -8,6 +6,10 @@ from app.models.base import Base, TimestampMixin
|
||||
|
||||
class TokenUsage(Base, TimestampMixin):
|
||||
__tablename__ = "token_usage"
|
||||
__table_args__ = (
|
||||
Index("ix_token_usage_owner", "owner_type", "owner_id"),
|
||||
Index("ix_token_usage_biz_key", "biz_key"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(32), primary_key=True)
|
||||
model_config_id: Mapped[str | None] = mapped_column(
|
||||
@@ -19,3 +21,9 @@ class TokenUsage(Base, TimestampMixin):
|
||||
input_tokens: Mapped[int] = mapped_column(Integer, default=0)
|
||||
output_tokens: Mapped[int] = mapped_column(Integer, default=0)
|
||||
total_tokens: Mapped[int] = mapped_column(Integer, default=0)
|
||||
|
||||
owner_type: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
owner_id: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
biz_key: Mapped[str | None] = mapped_column(String(160), nullable=True, index=True)
|
||||
source_module: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
source_step_code: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, Float, Integer, String, JSON
|
||||
from sqlalchemy import Boolean, DateTime, Float, String, JSON
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.enums.user import FrontendUserKind
|
||||
from app.models.base import Base, TimestampMixin
|
||||
|
||||
|
||||
@@ -19,7 +20,15 @@ class User(Base, TimestampMixin):
|
||||
credits: Mapped[float] = mapped_column(Float, default=0.0)
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
is_admin: Mapped[bool] = mapped_column(Boolean, default=False)
|
||||
user_type: Mapped[str] = mapped_column(String(16), default="frontend")
|
||||
user_type: Mapped[str] = mapped_column(String(16), default="frontend", index=True)
|
||||
# 仅前台用户有业务意义;默认外部用户。取消内部标记时也设置回 external。
|
||||
frontend_user_kind: Mapped[str] = mapped_column(
|
||||
String(16),
|
||||
default=FrontendUserKind.EXTERNAL.value,
|
||||
server_default=FrontendUserKind.EXTERNAL.value,
|
||||
index=True,
|
||||
nullable=False,
|
||||
)
|
||||
last_login_at: Mapped[datetime | None] = mapped_column(
|
||||
DateTime(timezone=True), nullable=True
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user