Files
adaptive-pricing/projects/coulomb-pricing/observatory/models.py
tegwick 31db9f8f31 Refactor economics to expense-record ledger with correct Bubble cost
Replace pre-aggregated costs.json with expense_records.json (48 line-item
records) and payment_records.json. All monthly and cumulative totals are
computed deterministically in observatory/ledger.py. Correct Bubble.io to
$32/mo (since Feb 2025) — infrastructure €69.44/mo not €72.20.
2026-06-22 02:03:22 +02:00

119 lines
2.6 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from decimal import Decimal
from typing import Literal
ExpenseClass = Literal["infrastructure", "payment_processing"]
MemberStatus = Literal["active", "churned", "paused"]
PricingModelStatus = Literal["active", "candidate", "retired"]
LiquidityStatus = Literal["burning", "neutral", "generating"]
@dataclass(frozen=True)
class Product:
id: str
name: str
lifecycle_phase: str
currency: str
description: str
active_pricing_model_id: str
@dataclass(frozen=True)
class PricingModel:
id: str
name: str
model_type: str
lifecycle_phase: str
currency: str
access_fee_amount: Decimal
access_fee_cadence: str
status: PricingModelStatus
@dataclass(frozen=True)
class ExpenseRecord:
id: str
period: str
vendor: str
description: str
cost_class: ExpenseClass
amount: Decimal
currency: str
source: str
@dataclass(frozen=True)
class PaymentRecord:
id: str
period: str
gross_amount: Decimal
fees_amount: Decimal
refunds_amount: Decimal
net_amount: Decimal
currency: str
source: str
member_count: int = 0
@dataclass(frozen=True)
class MonthlyPlatformCost:
period: str
infrastructure_cost: Decimal
payment_processing_cost: Decimal
active_members: int
gross_revenue: Decimal
@property
def total_platform_cost(self) -> Decimal:
return self.infrastructure_cost + self.payment_processing_cost
@dataclass(frozen=True)
class Budget:
currency: str
initial_budget: Decimal
started: str
@dataclass(frozen=True)
class MembershipRecord:
id: str
status: MemberStatus
joined_at: str
plan_id: str
churned_at: str | None = None
@dataclass(frozen=True)
class EconomicsSnapshot:
period: str
currency: str
active_members: int
monthly_revenue: Decimal
monthly_infrastructure_cost: Decimal
monthly_payment_processing_cost: Decimal
monthly_total_platform_cost: Decimal
cost_per_member: Decimal
gross_margin: Decimal
gross_margin_pct: Decimal
pricing_model_count: int
revenue_source: str
period_net_liquidity: Decimal
liquidity_status: LiquidityStatus
@dataclass(frozen=True)
class LiquiditySummary:
currency: str
through_period: str
initial_budget: Decimal
cumulative_member_payments: Decimal
cumulative_infrastructure_cost: Decimal
cumulative_payment_processing_cost: Decimal
cumulative_total_platform_cost: Decimal
cumulative_net_liquidity: Decimal
remaining_budget: Decimal
liquidity_status: LiquidityStatus
months_tracked: int