Add tenant-safe value, telemetry, connector, commercial, and production-readiness foundations.
608 lines
26 KiB
Python
608 lines
26 KiB
Python
from __future__ import annotations
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
from decimal import Decimal
|
|
from typing import Any
|
|
|
|
from sqlalchemy import (
|
|
Boolean,
|
|
CheckConstraint,
|
|
DateTime,
|
|
ForeignKeyConstraint,
|
|
Index,
|
|
Integer,
|
|
Numeric,
|
|
String,
|
|
UniqueConstraint,
|
|
func,
|
|
text,
|
|
)
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
from sqlalchemy.types import JSON
|
|
|
|
from app.db.base_class import Base
|
|
|
|
|
|
def _new_id() -> str:
|
|
return str(uuid.uuid4())
|
|
|
|
|
|
class TenantCommercialPlan(Base):
|
|
"""租户已协商的商业套餐版本,不与平台内部成本或客户节省事实混用。"""
|
|
|
|
__tablename__ = "tenant_commercial_plans"
|
|
__table_args__ = (
|
|
UniqueConstraint("tenant_id", "id", name="uq_tenant_commercial_plans_tenant_id"),
|
|
UniqueConstraint(
|
|
"tenant_id",
|
|
"plan_code",
|
|
"version",
|
|
name="uq_tenant_commercial_plans_tenant_code_version",
|
|
),
|
|
CheckConstraint(
|
|
"pricing_model IN ('subscription', 'usage', 'hybrid', 'pilot', 'custom')",
|
|
name="ck_tenant_commercial_plans_pricing_model",
|
|
),
|
|
CheckConstraint(
|
|
"billing_interval IN ('monthly', 'quarterly', 'annual', 'contract')",
|
|
name="ck_tenant_commercial_plans_billing_interval",
|
|
),
|
|
CheckConstraint(
|
|
"status IN ('draft', 'active', 'retired')",
|
|
name="ck_tenant_commercial_plans_status",
|
|
),
|
|
CheckConstraint(
|
|
"base_fee >= 0 AND included_seats >= 0 AND version >= 1",
|
|
name="ck_tenant_commercial_plans_values",
|
|
),
|
|
CheckConstraint(
|
|
"length(trim(plan_code)) > 0 AND length(trim(name)) > 0",
|
|
name="ck_tenant_commercial_plans_keys",
|
|
),
|
|
CheckConstraint(
|
|
"length(trim(currency)) = 3",
|
|
name="ck_tenant_commercial_plans_currency",
|
|
),
|
|
CheckConstraint(
|
|
"effective_to IS NULL OR effective_to > effective_from",
|
|
name="ck_tenant_commercial_plans_effective_window",
|
|
),
|
|
Index(
|
|
"uq_tenant_commercial_plans_active_code",
|
|
"tenant_id",
|
|
"plan_code",
|
|
unique=True,
|
|
postgresql_where=text("status = 'active'"),
|
|
),
|
|
Index(
|
|
"ix_tenant_commercial_plans_tenant_status",
|
|
"tenant_id",
|
|
"status",
|
|
"effective_from",
|
|
),
|
|
)
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_new_id)
|
|
tenant_id: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
plan_code: Mapped[str] = mapped_column(String(80), nullable=False)
|
|
name: Mapped[str] = mapped_column(String(160), nullable=False)
|
|
pricing_model: Mapped[str] = mapped_column(String(24), nullable=False)
|
|
billing_interval: Mapped[str] = mapped_column(String(20), nullable=False)
|
|
currency: Mapped[str] = mapped_column(String(3), nullable=False)
|
|
base_fee: Mapped[Decimal] = mapped_column(Numeric(20, 4), nullable=False)
|
|
included_seats: Mapped[int] = mapped_column(
|
|
Integer, nullable=False, default=0, server_default="0"
|
|
)
|
|
overage_enabled: Mapped[bool] = mapped_column(
|
|
Boolean, nullable=False, default=False, server_default="false"
|
|
)
|
|
status: Mapped[str] = mapped_column(
|
|
String(16), nullable=False, default="draft", server_default="draft"
|
|
)
|
|
effective_from: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
|
|
effective_to: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1, server_default="1")
|
|
contract_terms_json: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False, default=dict)
|
|
created_by: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), nullable=False, server_default=func.now()
|
|
)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now()
|
|
)
|
|
|
|
subscriptions = relationship("TenantSubscription", back_populates="plan", passive_deletes=True)
|
|
|
|
|
|
class TenantSubscription(Base):
|
|
"""租户订阅及当期计费快照,避免套餐后续变化污染历史账期。"""
|
|
|
|
__tablename__ = "tenant_subscriptions"
|
|
__table_args__ = (
|
|
UniqueConstraint("tenant_id", "id", name="uq_tenant_subscriptions_tenant_id"),
|
|
UniqueConstraint(
|
|
"tenant_id", "subscription_key", name="uq_tenant_subscriptions_tenant_key"
|
|
),
|
|
UniqueConstraint(
|
|
"tenant_id",
|
|
"external_provider",
|
|
"external_subscription_id",
|
|
name="uq_tenant_subscriptions_external_ref",
|
|
),
|
|
ForeignKeyConstraint(
|
|
["tenant_id", "plan_id"],
|
|
["tenant_commercial_plans.tenant_id", "tenant_commercial_plans.id"],
|
|
name="fk_tenant_subscriptions_tenant_plan",
|
|
ondelete="RESTRICT",
|
|
),
|
|
CheckConstraint(
|
|
"status IN ('trialing', 'active', 'past_due', 'suspended', 'canceled', 'expired')",
|
|
name="ck_tenant_subscriptions_status",
|
|
),
|
|
CheckConstraint(
|
|
"billing_interval IN ('monthly', 'quarterly', 'annual', 'contract')",
|
|
name="ck_tenant_subscriptions_billing_interval",
|
|
),
|
|
CheckConstraint(
|
|
"seats > 0 AND base_fee_snapshot >= 0 AND version >= 1",
|
|
name="ck_tenant_subscriptions_values",
|
|
),
|
|
CheckConstraint(
|
|
"length(trim(subscription_key)) > 0 AND length(trim(currency)) = 3",
|
|
name="ck_tenant_subscriptions_keys",
|
|
),
|
|
CheckConstraint(
|
|
"current_period_end > current_period_start",
|
|
name="ck_tenant_subscriptions_period",
|
|
),
|
|
CheckConstraint(
|
|
"ends_at IS NULL OR ends_at > starts_at",
|
|
name="ck_tenant_subscriptions_contract_window",
|
|
),
|
|
CheckConstraint(
|
|
"(external_provider IS NULL AND external_subscription_id IS NULL) OR "
|
|
"(external_provider IS NOT NULL AND external_subscription_id IS NOT NULL)",
|
|
name="ck_tenant_subscriptions_external_pair",
|
|
),
|
|
CheckConstraint(
|
|
"status != 'canceled' OR canceled_at IS NOT NULL",
|
|
name="ck_tenant_subscriptions_cancellation",
|
|
),
|
|
Index(
|
|
"uq_tenant_subscriptions_current",
|
|
"tenant_id",
|
|
unique=True,
|
|
postgresql_where=text("status IN ('trialing', 'active', 'past_due', 'suspended')"),
|
|
),
|
|
Index(
|
|
"ix_tenant_subscriptions_tenant_status_period",
|
|
"tenant_id",
|
|
"status",
|
|
"current_period_end",
|
|
),
|
|
)
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_new_id)
|
|
tenant_id: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
subscription_key: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
plan_id: Mapped[str] = mapped_column(String(36), nullable=False)
|
|
status: Mapped[str] = mapped_column(String(20), nullable=False)
|
|
starts_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
|
|
ends_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
current_period_start: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
|
|
current_period_end: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
|
|
seats: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
base_fee_snapshot: Mapped[Decimal] = mapped_column(Numeric(20, 4), nullable=False)
|
|
currency: Mapped[str] = mapped_column(String(3), nullable=False)
|
|
billing_interval: Mapped[str] = mapped_column(String(20), nullable=False)
|
|
auto_renew: Mapped[bool] = mapped_column(
|
|
Boolean, nullable=False, default=False, server_default="false"
|
|
)
|
|
external_provider: Mapped[str | None] = mapped_column(String(60))
|
|
external_subscription_id: Mapped[str | None] = mapped_column(String(160))
|
|
canceled_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1, server_default="1")
|
|
metadata_json: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False, default=dict)
|
|
created_by: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), nullable=False, server_default=func.now()
|
|
)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now()
|
|
)
|
|
|
|
plan = relationship("TenantCommercialPlan", back_populates="subscriptions")
|
|
entitlements = relationship(
|
|
"CommercialEntitlement", back_populates="subscription", passive_deletes=True
|
|
)
|
|
|
|
|
|
class CommercialEntitlement(Base):
|
|
"""订阅的功能权益与可计量配额定义。"""
|
|
|
|
__tablename__ = "commercial_entitlements"
|
|
__table_args__ = (
|
|
UniqueConstraint("tenant_id", "id", name="uq_commercial_entitlements_tenant_id"),
|
|
UniqueConstraint(
|
|
"tenant_id",
|
|
"subscription_id",
|
|
"id",
|
|
name="uq_commercial_entitlements_tenant_subscription_id",
|
|
),
|
|
UniqueConstraint(
|
|
"tenant_id",
|
|
"subscription_id",
|
|
"entitlement_key",
|
|
name="uq_commercial_entitlements_subscription_key",
|
|
),
|
|
ForeignKeyConstraint(
|
|
["tenant_id", "subscription_id"],
|
|
["tenant_subscriptions.tenant_id", "tenant_subscriptions.id"],
|
|
name="fk_commercial_entitlements_tenant_subscription",
|
|
ondelete="RESTRICT",
|
|
),
|
|
CheckConstraint(
|
|
"entitlement_type IN ('feature', 'metered', 'unlimited')",
|
|
name="ck_commercial_entitlements_type",
|
|
),
|
|
CheckConstraint(
|
|
"reset_interval IN ('none', 'monthly', 'quarterly', 'annual', 'contract')",
|
|
name="ck_commercial_entitlements_reset_interval",
|
|
),
|
|
CheckConstraint(
|
|
"overage_policy IN ('block', 'allow', 'alert')",
|
|
name="ck_commercial_entitlements_overage_policy",
|
|
),
|
|
CheckConstraint(
|
|
"status IN ('active', 'suspended', 'expired')",
|
|
name="ck_commercial_entitlements_status",
|
|
),
|
|
CheckConstraint(
|
|
"version >= 1 AND (included_quantity IS NULL OR included_quantity >= 0) "
|
|
"AND (hard_limit_quantity IS NULL OR hard_limit_quantity >= 0)",
|
|
name="ck_commercial_entitlements_values",
|
|
),
|
|
CheckConstraint(
|
|
"(entitlement_type = 'unlimited' AND included_quantity IS NULL "
|
|
"AND hard_limit_quantity IS NULL) OR "
|
|
"(entitlement_type = 'feature' AND included_quantity IN (0, 1) "
|
|
"AND (hard_limit_quantity IS NULL OR hard_limit_quantity IN (0, 1))) OR "
|
|
"(entitlement_type = 'metered' AND included_quantity IS NOT NULL "
|
|
"AND (hard_limit_quantity IS NULL OR hard_limit_quantity >= included_quantity))",
|
|
name="ck_commercial_entitlements_quota_shape",
|
|
),
|
|
CheckConstraint(
|
|
"length(trim(entitlement_key)) > 0 AND length(trim(metric_key)) > 0 "
|
|
"AND length(trim(unit)) > 0",
|
|
name="ck_commercial_entitlements_keys",
|
|
),
|
|
CheckConstraint(
|
|
"effective_to IS NULL OR effective_to > effective_from",
|
|
name="ck_commercial_entitlements_effective_window",
|
|
),
|
|
Index(
|
|
"ix_commercial_entitlements_subscription_status",
|
|
"tenant_id",
|
|
"subscription_id",
|
|
"status",
|
|
),
|
|
)
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_new_id)
|
|
tenant_id: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
subscription_id: Mapped[str] = mapped_column(String(36), nullable=False)
|
|
entitlement_key: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
metric_key: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
entitlement_type: Mapped[str] = mapped_column(String(20), nullable=False)
|
|
unit: Mapped[str] = mapped_column(String(40), nullable=False)
|
|
included_quantity: Mapped[Decimal | None] = mapped_column(Numeric(20, 6))
|
|
hard_limit_quantity: Mapped[Decimal | None] = mapped_column(Numeric(20, 6))
|
|
reset_interval: Mapped[str] = mapped_column(String(20), nullable=False)
|
|
overage_policy: Mapped[str] = mapped_column(String(16), nullable=False)
|
|
status: Mapped[str] = mapped_column(String(16), nullable=False)
|
|
effective_from: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
|
|
effective_to: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
|
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1, server_default="1")
|
|
config_json: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False, default=dict)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), nullable=False, server_default=func.now()
|
|
)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now()
|
|
)
|
|
|
|
subscription = relationship("TenantSubscription", back_populates="entitlements")
|
|
|
|
|
|
class UsageMeterEvent(Base):
|
|
"""追加只读的客户用量事实;同一来源幂等键只能产生一条事件。"""
|
|
|
|
__tablename__ = "usage_meter_events"
|
|
__table_args__ = (
|
|
UniqueConstraint("tenant_id", "id", name="uq_usage_meter_events_tenant_id"),
|
|
UniqueConstraint(
|
|
"tenant_id",
|
|
"subscription_id",
|
|
"id",
|
|
name="uq_usage_meter_events_tenant_subscription_id",
|
|
),
|
|
UniqueConstraint(
|
|
"tenant_id",
|
|
"subscription_id",
|
|
"entitlement_id",
|
|
"id",
|
|
name="uq_usage_meter_events_entitlement_id",
|
|
),
|
|
UniqueConstraint(
|
|
"tenant_id",
|
|
"source_system",
|
|
"idempotency_key",
|
|
name="uq_usage_meter_events_source_request",
|
|
),
|
|
ForeignKeyConstraint(
|
|
["tenant_id", "subscription_id"],
|
|
["tenant_subscriptions.tenant_id", "tenant_subscriptions.id"],
|
|
name="fk_usage_meter_events_tenant_subscription",
|
|
ondelete="RESTRICT",
|
|
),
|
|
ForeignKeyConstraint(
|
|
["tenant_id", "subscription_id", "entitlement_id"],
|
|
[
|
|
"commercial_entitlements.tenant_id",
|
|
"commercial_entitlements.subscription_id",
|
|
"commercial_entitlements.id",
|
|
],
|
|
name="fk_usage_meter_events_tenant_entitlement",
|
|
ondelete="RESTRICT",
|
|
),
|
|
ForeignKeyConstraint(
|
|
["tenant_id", "subscription_id", "billing_period_id"],
|
|
[
|
|
"commercial_billing_periods.tenant_id",
|
|
"commercial_billing_periods.subscription_id",
|
|
"commercial_billing_periods.id",
|
|
],
|
|
name="fk_usage_meter_events_tenant_billing_period",
|
|
ondelete="RESTRICT",
|
|
),
|
|
ForeignKeyConstraint(
|
|
["tenant_id", "subscription_id", "entitlement_id", "reversal_of_event_id"],
|
|
[
|
|
"usage_meter_events.tenant_id",
|
|
"usage_meter_events.subscription_id",
|
|
"usage_meter_events.entitlement_id",
|
|
"usage_meter_events.id",
|
|
],
|
|
name="fk_usage_meter_events_tenant_reversal",
|
|
ondelete="RESTRICT",
|
|
),
|
|
CheckConstraint(
|
|
"event_type IN ('usage', 'credit', 'adjustment', 'reversal')",
|
|
name="ck_usage_meter_events_type",
|
|
),
|
|
CheckConstraint(
|
|
"(event_type = 'usage' AND quantity > 0) OR "
|
|
"(event_type = 'credit' AND quantity < 0) OR "
|
|
"(event_type IN ('adjustment', 'reversal') AND quantity <> 0)",
|
|
name="ck_usage_meter_events_quantity",
|
|
),
|
|
CheckConstraint(
|
|
"(event_type = 'reversal' AND reversal_of_event_id IS NOT NULL) OR "
|
|
"(event_type != 'reversal' AND reversal_of_event_id IS NULL)",
|
|
name="ck_usage_meter_events_reversal",
|
|
),
|
|
CheckConstraint(
|
|
"(subject_type IS NULL AND subject_id IS NULL) OR "
|
|
"(subject_type IS NOT NULL AND subject_id IS NOT NULL)",
|
|
name="ck_usage_meter_events_subject_pair",
|
|
),
|
|
CheckConstraint(
|
|
"actor_type IN ('system', 'user', 'integration', 'admin')",
|
|
name="ck_usage_meter_events_actor_type",
|
|
),
|
|
CheckConstraint(
|
|
"length(trim(metric_key)) > 0 AND length(trim(unit)) > 0 "
|
|
"AND length(trim(period_key)) > 0 AND length(trim(source_system)) > 0 "
|
|
"AND length(trim(quota_period_key)) > 0 "
|
|
"AND length(trim(idempotency_key)) > 0 "
|
|
"AND length(trim(request_fingerprint)) > 0",
|
|
name="ck_usage_meter_events_keys",
|
|
),
|
|
Index(
|
|
"ix_usage_meter_events_quota_window",
|
|
"tenant_id",
|
|
"subscription_id",
|
|
"metric_key",
|
|
"quota_period_key",
|
|
"occurred_at",
|
|
),
|
|
Index(
|
|
"ix_usage_meter_events_billing_period",
|
|
"tenant_id",
|
|
"billing_period_id",
|
|
"occurred_at",
|
|
),
|
|
Index(
|
|
"ix_usage_meter_events_correlation",
|
|
"tenant_id",
|
|
"correlation_id",
|
|
"occurred_at",
|
|
),
|
|
)
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_new_id)
|
|
tenant_id: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
subscription_id: Mapped[str] = mapped_column(String(36), nullable=False)
|
|
entitlement_id: Mapped[str] = mapped_column(String(36), nullable=False)
|
|
billing_period_id: Mapped[str] = mapped_column(String(36), nullable=False)
|
|
event_type: Mapped[str] = mapped_column(String(16), nullable=False)
|
|
metric_key: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
quantity: Mapped[Decimal] = mapped_column(Numeric(20, 6), nullable=False)
|
|
unit: Mapped[str] = mapped_column(String(40), nullable=False)
|
|
period_key: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
quota_period_key: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
occurred_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
|
|
source_system: Mapped[str] = mapped_column(String(80), nullable=False)
|
|
idempotency_key: Mapped[str] = mapped_column(String(160), nullable=False)
|
|
request_fingerprint: Mapped[str] = mapped_column(String(80), nullable=False)
|
|
reversal_of_event_id: Mapped[str | None] = mapped_column(String(36))
|
|
subject_type: Mapped[str | None] = mapped_column(String(60))
|
|
subject_id: Mapped[str | None] = mapped_column(String(160))
|
|
actor_type: Mapped[str] = mapped_column(String(20), nullable=False)
|
|
actor_id: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
correlation_id: Mapped[str | None] = mapped_column(String(120))
|
|
trace_id: Mapped[str | None] = mapped_column(String(120))
|
|
metadata_json: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False, default=dict)
|
|
recorded_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), nullable=False, server_default=func.now()
|
|
)
|
|
|
|
|
|
class CommercialCostEvent(Base):
|
|
"""平台内部成本事实;物理上独立于客户节省、价值机会和价值实现。"""
|
|
|
|
__tablename__ = "commercial_cost_events"
|
|
__table_args__ = (
|
|
UniqueConstraint("tenant_id", "id", name="uq_commercial_cost_events_tenant_id"),
|
|
UniqueConstraint(
|
|
"tenant_id",
|
|
"source_system",
|
|
"idempotency_key",
|
|
name="uq_commercial_cost_events_source_request",
|
|
),
|
|
ForeignKeyConstraint(
|
|
["tenant_id", "subscription_id"],
|
|
["tenant_subscriptions.tenant_id", "tenant_subscriptions.id"],
|
|
name="fk_commercial_cost_events_tenant_subscription",
|
|
ondelete="RESTRICT",
|
|
),
|
|
ForeignKeyConstraint(
|
|
["tenant_id", "subscription_id", "usage_event_id"],
|
|
[
|
|
"usage_meter_events.tenant_id",
|
|
"usage_meter_events.subscription_id",
|
|
"usage_meter_events.id",
|
|
],
|
|
name="fk_commercial_cost_events_tenant_usage",
|
|
ondelete="RESTRICT",
|
|
),
|
|
ForeignKeyConstraint(
|
|
["tenant_id", "subscription_id", "billing_period_id"],
|
|
[
|
|
"commercial_billing_periods.tenant_id",
|
|
"commercial_billing_periods.subscription_id",
|
|
"commercial_billing_periods.id",
|
|
],
|
|
name="fk_commercial_cost_events_tenant_billing_period",
|
|
ondelete="RESTRICT",
|
|
),
|
|
ForeignKeyConstraint(
|
|
["tenant_id", "reversal_of_cost_event_id"],
|
|
["commercial_cost_events.tenant_id", "commercial_cost_events.id"],
|
|
name="fk_commercial_cost_events_tenant_reversal",
|
|
ondelete="RESTRICT",
|
|
),
|
|
CheckConstraint(
|
|
"event_type IN ('incurred', 'credit', 'adjustment', 'reversal')",
|
|
name="ck_commercial_cost_events_type",
|
|
),
|
|
CheckConstraint(
|
|
"cost_category IN ('ai_inference', 'ocr', 'storage', 'connector', "
|
|
"'support', 'implementation', 'infrastructure', 'payment', 'other')",
|
|
name="ck_commercial_cost_events_category",
|
|
),
|
|
CheckConstraint(
|
|
"quantity > 0 AND unit_cost >= 0 AND fx_rate > 0",
|
|
name="ck_commercial_cost_events_values",
|
|
),
|
|
CheckConstraint(
|
|
"(event_type = 'incurred' AND cost_amount >= 0 AND reporting_amount >= 0) OR "
|
|
"(event_type = 'credit' AND cost_amount <= 0 AND reporting_amount <= 0) OR "
|
|
"(event_type IN ('adjustment', 'reversal') AND cost_amount <> 0 "
|
|
"AND reporting_amount <> 0)",
|
|
name="ck_commercial_cost_events_amount_direction",
|
|
),
|
|
CheckConstraint(
|
|
"(event_type = 'reversal' AND reversal_of_cost_event_id IS NOT NULL) OR "
|
|
"(event_type != 'reversal' AND reversal_of_cost_event_id IS NULL)",
|
|
name="ck_commercial_cost_events_reversal",
|
|
),
|
|
CheckConstraint(
|
|
"usage_event_id IS NULL OR subscription_id IS NOT NULL",
|
|
name="ck_commercial_cost_events_usage_pair",
|
|
),
|
|
CheckConstraint(
|
|
"(subscription_id IS NULL AND billing_period_id IS NULL) OR "
|
|
"(subscription_id IS NOT NULL AND billing_period_id IS NOT NULL)",
|
|
name="ck_commercial_cost_events_billing_period_pair",
|
|
),
|
|
CheckConstraint(
|
|
"length(trim(unit)) > 0 AND length(trim(source_system)) > 0 "
|
|
"AND length(trim(idempotency_key)) > 0 "
|
|
"AND length(trim(request_fingerprint)) > 0 "
|
|
"AND length(trim(original_currency)) = 3 "
|
|
"AND length(trim(reporting_currency)) = 3",
|
|
name="ck_commercial_cost_events_keys",
|
|
),
|
|
Index(
|
|
"ix_commercial_cost_events_tenant_period",
|
|
"tenant_id",
|
|
"occurred_at",
|
|
"cost_category",
|
|
),
|
|
Index(
|
|
"ix_commercial_cost_events_subscription_period",
|
|
"tenant_id",
|
|
"subscription_id",
|
|
"billing_period_id",
|
|
"occurred_at",
|
|
),
|
|
Index(
|
|
"ix_commercial_cost_events_allocation",
|
|
"tenant_id",
|
|
"allocation_key",
|
|
"occurred_at",
|
|
),
|
|
)
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_new_id)
|
|
tenant_id: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
subscription_id: Mapped[str | None] = mapped_column(String(36))
|
|
billing_period_id: Mapped[str | None] = mapped_column(String(36))
|
|
usage_event_id: Mapped[str | None] = mapped_column(String(36))
|
|
event_type: Mapped[str] = mapped_column(String(16), nullable=False)
|
|
cost_category: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
quantity: Mapped[Decimal] = mapped_column(Numeric(20, 6), nullable=False)
|
|
unit: Mapped[str] = mapped_column(String(40), nullable=False)
|
|
unit_cost: Mapped[Decimal] = mapped_column(Numeric(20, 8), nullable=False)
|
|
cost_amount: Mapped[Decimal] = mapped_column(Numeric(20, 4), nullable=False)
|
|
original_currency: Mapped[str] = mapped_column(String(3), nullable=False)
|
|
reporting_amount: Mapped[Decimal] = mapped_column(Numeric(20, 4), nullable=False)
|
|
reporting_currency: Mapped[str] = mapped_column(String(3), nullable=False)
|
|
fx_rate: Mapped[Decimal] = mapped_column(Numeric(20, 8), nullable=False)
|
|
provider: Mapped[str | None] = mapped_column(String(120))
|
|
sku: Mapped[str | None] = mapped_column(String(120))
|
|
model_name: Mapped[str | None] = mapped_column(String(120))
|
|
allocation_key: Mapped[str] = mapped_column(String(160), nullable=False)
|
|
occurred_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
|
|
source_system: Mapped[str] = mapped_column(String(80), nullable=False)
|
|
idempotency_key: Mapped[str] = mapped_column(String(160), nullable=False)
|
|
request_fingerprint: Mapped[str] = mapped_column(String(80), nullable=False)
|
|
reversal_of_cost_event_id: Mapped[str | None] = mapped_column(String(36))
|
|
correlation_id: Mapped[str | None] = mapped_column(String(120))
|
|
trace_id: Mapped[str | None] = mapped_column(String(120))
|
|
metadata_json: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False, default=dict)
|
|
recorded_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), nullable=False, server_default=func.now()
|
|
)
|
|
|
|
|
|
__all__ = [
|
|
"CommercialCostEvent",
|
|
"CommercialEntitlement",
|
|
"TenantCommercialPlan",
|
|
"TenantSubscription",
|
|
"UsageMeterEvent",
|
|
]
|