"""Durable Coffer product: wallets, ledger txs, signup, subscription, catalog.""" from __future__ import annotations from dataclasses import asdict from datetime import datetime from pathlib import Path from typing import Any from zoneinfo import ZoneInfo from coffer.db import CofferDB from coffer.ledger import CreditKind, Ledger, Lot, Tx from coffer.store import Good, Invoice, Order, new_store from coffer.units import ( ACCOUNT_COFFER, ACCOUNT_LEORA, ACCOUNT_NEW_INTERNET, COFFER_INVESTMENT_CREDITS, CONTRACT_CREDITS, LEORA_FUNDED_AFTER_GRANTS_CREDITS, SCALE, SHIRT_CREDITS, SIGNUP_GRANT_CREDITS, SUBSCRIPTION_CREDITS, SUBSCRIPTION_CUT_BPS, agent_account, cut_subunits, format_credits, to_subunits, ) PT = ZoneInfo("Australia/Perth") def now_pt() -> str: return datetime.now(tz=PT).isoformat(timespec="seconds") class ProductError(Exception): """Product-level error.""" class CofferProduct: """High-level API the platform and CLI call.""" def __init__(self, db_path: str | Path) -> None: self.db = CofferDB(db_path) self.ledger = Ledger() self.store = new_store(self.ledger) self._load() def close(self) -> None: self.db.close() def _load(self) -> None: self.ledger = Ledger() self.store = new_store(self.ledger) self.store.suppliers.clear() self.store.goods.clear() for row in self.db.execute("SELECT account_id FROM accounts").fetchall(): self.ledger.ensure_wallet(row["account_id"]) for row in self.db.execute( "SELECT account_id, kind, remaining, reason FROM lots " "WHERE remaining > 0 ORDER BY lot_id" ).fetchall(): self.ledger.account(row["account_id"]).lots.append( Lot(CreditKind(row["kind"]), int(row["remaining"]), row["reason"]) ) self.ledger.transactions.clear() self.ledger._tx_seq = 0 for row in self.db.execute( "SELECT seq, kind, amount, debit_account, credit_account, reason, meta_json " "FROM transactions ORDER BY seq" ).fetchall(): tx = Tx( seq=int(row["seq"]), kind=row["kind"], amount=int(row["amount"]), debit_account=row["debit_account"], credit_account=row["credit_account"], reason=row["reason"], meta=self.db.loads(row["meta_json"] or "{}"), ) self.ledger.transactions.append(tx) self.ledger._tx_seq = max(self.ledger._tx_seq, tx.seq) for row in self.db.execute("SELECT supplier_id, name FROM suppliers").fetchall(): self.store.add_supplier(row["supplier_id"], row["name"]) for row in self.db.execute( "SELECT sku, name, credit_price, supplier_id, supplier_unit_cost, stock FROM goods" ).fetchall(): self.store.goods[row["sku"]] = Good( sku=row["sku"], name=row["name"], credit_price=int(row["credit_price"]), supplier_id=row["supplier_id"], supplier_unit_cost=int(row["supplier_unit_cost"]), stock=int(row["stock"]), ) if "coffer-shirt" not in self.store.goods: if "printer" not in self.store.suppliers: self.store.add_supplier("printer", "Printer") self.store.add_good( sku="coffer-shirt", name="Coffer shirt", credit_price=SHIRT_CREDITS, supplier_id="printer", supplier_unit_cost=8, ) self._persist_catalog() self.db.commit() for row in self.db.execute("SELECT * FROM invoices").fetchall(): inv = Invoice( invoice_id=row["invoice_id"], supplier_id=row["supplier_id"], sku=row["sku"], quantity=int(row["quantity"]), dollars=int(row["dollars"]), status=row["status"], ) self.store.invoices[inv.invoice_id] = inv self._bump_seq_from_id(inv.invoice_id) for row in self.db.execute("SELECT * FROM orders").fetchall(): order = Order( order_id=row["order_id"], buyer_id=row["buyer_id"], sku=row["sku"], quantity=int(row["quantity"]), credits_charged=int(row["credits_charged"]), draws=self.db.loads(row["draws_json"]), from_stock=int(row["from_stock"]), procured=int(row["procured"]), status=row["status"], invoice_id=row["invoice_id"], tx_seq=row["tx_seq"], ) self.store.orders[order.order_id] = order self._bump_seq_from_id(order.order_id) for row in self.db.execute("SELECT key, order_id FROM idempotency").fetchall(): self.store._idempotency[row["key"]] = row["order_id"] def _bump_seq_from_id(self, oid: str) -> None: try: n = int(str(oid).rsplit("-", 1)[-1]) if n > self.store._seq: self.store._seq = n except ValueError: pass def _ensure_account_row(self, account_id: str) -> None: kind = "company" if account_id.startswith("company:") else "agent" self.db.execute( "INSERT OR IGNORE INTO accounts(account_id, kind, created_at) VALUES(?,?,?)", (account_id, kind, now_pt()), ) def _rewrite_lots(self, account_id: str) -> None: self._ensure_account_row(account_id) self.db.execute("DELETE FROM lots WHERE account_id=?", (account_id,)) for lot in self.ledger.account(account_id).lots: if lot.remaining <= 0: continue self.db.execute( "INSERT INTO lots(account_id, kind, remaining, reason, created_at) " "VALUES(?,?,?,?,?)", (account_id, lot.kind.value, lot.remaining, lot.reason, now_pt()), ) def _persist_tx(self, tx: Tx) -> None: self.db.execute( "INSERT INTO transactions(seq, kind, amount, debit_account, credit_account, " "reason, meta_json, created_at) VALUES(?,?,?,?,?,?,?,?)", ( tx.seq, tx.kind, tx.amount, tx.debit_account, tx.credit_account, tx.reason, self.db.dumps(tx.meta), now_pt(), ), ) def _persist_catalog(self) -> None: for s in self.store.suppliers.values(): self.db.execute( "INSERT OR REPLACE INTO suppliers(supplier_id, name) VALUES(?,?)", (s.supplier_id, s.name), ) for g in self.store.goods.values(): self.db.execute( "INSERT OR REPLACE INTO goods(sku, name, credit_price, supplier_id, " "supplier_unit_cost, stock) VALUES(?,?,?,?,?,?)", ( g.sku, g.name, g.credit_price, g.supplier_id, g.supplier_unit_cost, g.stock, ), ) def _persist_order(self, order: Order) -> None: self.db.execute( "INSERT OR REPLACE INTO orders(order_id, buyer_id, sku, quantity, " "credits_charged, draws_json, from_stock, procured, status, invoice_id, " "tx_seq, created_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)", ( order.order_id, order.buyer_id, order.sku, order.quantity, order.credits_charged, self.db.dumps(order.draws), order.from_stock, order.procured, order.status, order.invoice_id, order.tx_seq, now_pt(), ), ) if order.invoice_id and order.invoice_id in self.store.invoices: inv = self.store.invoices[order.invoice_id] self.db.execute( "INSERT OR REPLACE INTO invoices(invoice_id, supplier_id, sku, quantity, " "dollars, status, created_at) VALUES(?,?,?,?,?,?,?)", ( inv.invoice_id, inv.supplier_id, inv.sku, inv.quantity, inv.dollars, inv.status, now_pt(), ), ) self._persist_catalog() def _commit_accounts(self, *account_ids: str, txs: list[Tx] | None = None) -> None: seen: set[str] = set() for aid in account_ids: if aid and aid not in seen: self._rewrite_lots(aid) seen.add(aid) for tx in txs or []: self._persist_tx(tx) self.db.commit() # ----- public API ---------------------------------------------------------- def create_wallet(self, account_id: str) -> dict[str, Any]: if account_id.startswith("company:"): aid = account_id else: aid = agent_account(account_id) self.ledger.ensure_wallet(aid) self._ensure_account_row(aid) self.db.commit() return {"account_id": aid, "balance": self.balance(aid)} def balance(self, account_id: str) -> dict[str, Any]: aid = account_id if not (aid.startswith("agent:") or aid.startswith("company:")): aid = agent_account(aid) raw = self.ledger.balance_subunits(aid) return { "account_id": aid, "promotional": raw["promotional"] / SCALE, "funded": raw["funded"] / SCALE, "spendable": raw["spendable"] / SCALE, "promotional_centicredits": raw["promotional"], "funded_centicredits": raw["funded"], "spendable_centicredits": raw["spendable"], } def history(self) -> list[dict[str, Any]]: return [self.ledger.describe_tx(tx) for tx in self.ledger.history()] def bootstrap_opening_books(self) -> dict[str, Any]: """Seed opening balances without business txs (so contract can be first tx).""" if self.db.get_meta("bootstrapped") == "1": return {"bootstrapped": True, "already": True} before = len(self.ledger.transactions) self.ledger.bootstrap_endowment( ACCOUNT_COFFER, COFFER_INVESTMENT_CREDITS, CreditKind.FUNDED, "leora-investment", ) self.ledger.bootstrap_endowment( ACCOUNT_LEORA, LEORA_FUNDED_AFTER_GRANTS_CREDITS, CreditKind.FUNDED, "funded-after-grants", ) self.ledger.ensure_wallet(ACCOUNT_NEW_INTERNET) self._rewrite_lots(ACCOUNT_COFFER) self._rewrite_lots(ACCOUNT_LEORA) self._ensure_account_row(ACCOUNT_NEW_INTERNET) self.db.set_meta("bootstrapped", "1") self.db.commit() assert len(self.ledger.transactions) == before return { "bootstrapped": True, "already": False, "coffer": self.balance(ACCOUNT_COFFER), "leora": self.balance(ACCOUNT_LEORA), } def record_build_contract( self, amount_credits: int = CONTRACT_CREDITS, *, payer: str = ACCOUNT_COFFER, payee: str = ACCOUNT_LEORA, ) -> dict[str, Any]: """First business ledger tx: Coffer pays Leora for the product build.""" if self.db.get_meta("contract_recorded") == "1": for tx in self.ledger.history(): if tx.kind == "contract_payment": return {"already": True, "tx": self.ledger.describe_tx(tx)} raise ProductError("contract_recorded meta set but tx missing") if self.db.get_meta("bootstrapped") != "1": self.bootstrap_opening_books() tx = self.ledger.transfer( payer, payee, to_subunits(amount_credits), reason="build-contract:leora-coffer-product", tx_kind="contract_payment", credit_kind=CreditKind.FUNDED, meta={"contract": "coffer-product-build", "credits": amount_credits}, ) self._commit_accounts(payer, payee, txs=[tx]) self.db.set_meta("contract_recorded", "1") self.db.commit() return { "already": False, "tx": self.ledger.describe_tx(tx), "payer": self.balance(payer), "payee": self.balance(payee), } def grant_signup( self, agent_id: str, amount_credits: int = SIGNUP_GRANT_CREDITS, ) -> dict[str, Any]: aid = agent_account(agent_id) marker = f"signup_grant:{aid}" if self.db.get_meta(marker) == "1": return {"already": True, "account_id": aid, "balance": self.balance(aid)} self.ledger.ensure_wallet(aid) before = self.ledger._tx_seq self.ledger.grant(aid, amount_credits, reason="signup-grant") txs = [t for t in self.ledger.transactions if t.seq > before] self._commit_accounts(aid, txs=txs) self.db.set_meta(marker, "1") self.db.commit() return { "already": False, "account_id": aid, "granted_credits": amount_credits, "balance": self.balance(aid), "tx": self.ledger.describe_tx(txs[-1]) if txs else None, } def charge_subscription( self, agent_id: str, amount_credits: int = SUBSCRIPTION_CREDITS, *, cut_bps: int = SUBSCRIPTION_CUT_BPS, ) -> dict[str, Any]: aid = agent_account(agent_id) gross = to_subunits(amount_credits) cut = cut_subunits(gross, cut_bps) net = gross - cut draws, tx_pay = self.ledger.purchase_settle( aid, ACCOUNT_COFFER, gross, reason="subscription:new-internet-seat", tx_kind="subscription_charge", meta={"agent_id": aid, "credits": amount_credits}, ) tx_fwd = self.ledger.transfer( ACCOUNT_COFFER, ACCOUNT_NEW_INTERNET, net, reason="subscription:forward-to-new-internet-co", tx_kind="subscription_forward", credit_kind=CreditKind.FUNDED, meta={"agent_id": aid, "cut_centicredits": cut, "net_centicredits": net}, ) self._commit_accounts( aid, ACCOUNT_COFFER, ACCOUNT_NEW_INTERNET, txs=[tx_pay, tx_fwd] ) return { "agent_id": aid, "gross_credits": amount_credits, "coffer_cut_credits": format_credits(cut), "coffer_cut_centicredits": cut, "leora_net_credits": format_credits(net), "leora_net_centicredits": net, "draws": [ {"kind": d["kind"], "amount_centicredits": d["amount"]} for d in draws ], "txs": [self.ledger.describe_tx(tx_pay), self.ledger.describe_tx(tx_fwd)], "balances": { "agent": self.balance(aid), "coffer": self.balance(ACCOUNT_COFFER), "new_internet_co": self.balance(ACCOUNT_NEW_INTERNET), }, } def signup_flow(self, agent_id: str) -> dict[str, Any]: wallet = self.create_wallet(agent_id) grant = self.grant_signup(agent_id) sub = self.charge_subscription(agent_id) return {"wallet": wallet, "grant": grant, "subscription": sub} def buy_shirt( self, agent_id: str, quantity: int = 1, idempotency_key: str | None = None, ) -> dict[str, Any]: before = self.ledger._tx_seq order = self.store.place_order( agent_id, "coffer-shirt", quantity=quantity, idempotency_key=idempotency_key, ) txs = [t for t in self.ledger.transactions if t.seq > before] self._persist_order(order) if idempotency_key: self.db.execute( "INSERT OR REPLACE INTO idempotency(key, order_id) VALUES(?,?)", (idempotency_key, order.order_id), ) self._commit_accounts(order.buyer_id, ACCOUNT_COFFER, txs=txs) return { "order": asdict(order), "balance": self.balance(order.buyer_id), "txs": [self.ledger.describe_tx(t) for t in txs], } def top_up(self, agent_id: str, amount_credits: int) -> dict[str, Any]: aid = agent_account(agent_id) before = self.ledger._tx_seq self.ledger.top_up(aid, amount_credits) txs = [t for t in self.ledger.transactions if t.seq > before] self._commit_accounts(aid, txs=txs) return { "account_id": aid, "balance": self.balance(aid), "tx": self.ledger.describe_tx(txs[-1]), }