Files
adaptive-pricing/projects/coulomb-pricing/observatory/credits.py
tegwick 0a38def5a5 Complete Economic Observatory MVP (ADAPTIVE-WP-0002)
Add file-based Bubble, Stripe, and OpenRouter importers; usage attribution,
cost allocation, pricing simulator, credit wallets, and recommendations in the
dashboard API. Document whynot-design UI workflow and archive the finished
workplan with all ten tasks marked done.
2026-06-22 23:23:31 +02:00

48 lines
1.6 KiB
Python

from __future__ import annotations
from decimal import Decimal, ROUND_HALF_UP
from pathlib import Path
from typing import Any
from .load import _read_json, default_data_dir
TWOPLACES = Decimal("0.01")
def _money(value: Decimal) -> Decimal:
return value.quantize(TWOPLACES, rounding=ROUND_HALF_UP)
def load_credit_wallets(data_dir=None) -> dict[str, Any]:
root = data_dir or default_data_dir()
path = Path(root) / "credit_wallets.json"
if not path.exists():
return {"version": 1, "currency": "EUR", "wallets": []}
return _read_json(path)
def build_credit_summary(raw: dict, usage_by_member: dict[str, Decimal], period: str) -> dict:
wallets = []
for item in raw.get("wallets", []):
member_id = item["member_id"]
allowance = Decimal(str(item.get("monthly_allowance_eur", "0")))
used = usage_by_member.get(member_id, Decimal(str(item.get("used_eur", "0"))))
remaining = max(Decimal("0"), allowance - used)
wallets.append(
{
"member_id": member_id,
"period": period,
"monthly_allowance_eur": _money(allowance),
"used_eur": _money(used),
"remaining_eur": _money(remaining),
"overage_eur": _money(max(Decimal("0"), used - allowance)),
}
)
return {
"period": period,
"currency": raw.get("currency", "EUR"),
"wallet_count": len(wallets),
"wallets": wallets,
"notes": "Observatory-only credit accounting; no customer billing in MVP.",
}