Implement client cost attribution

This commit is contained in:
tegwick 2026-08-10 20:32:09 +02:00
parent d2b9bc4b32
commit 33883e0977
15 changed files with 362 additions and 21 deletions

View file

@ -25,6 +25,10 @@ class LedgerEntry:
period_month: str
incurred_on: date | None
source_path: str
client_id: str | None = None
application_id: str | None = None
app_instance_id: str | None = None
cost_attribution_key: str | None = None
@dataclass(frozen=True)
@ -92,6 +96,15 @@ def _ensure_schema(conn: sqlite3.Connection) -> None:
);
"""
)
columns = {row["name"] for row in conn.execute("PRAGMA table_info(ledger_entries)")}
for name in (
"client_id",
"application_id",
"app_instance_id",
"cost_attribution_key",
):
if name not in columns:
conn.execute(f"ALTER TABLE ledger_entries ADD COLUMN {name} TEXT")
def _utc_now() -> str:
@ -171,6 +184,10 @@ def _entries_from_hosteurope(path: Path) -> list[LedgerEntry]:
period_month=row.period_month,
incurred_on=row.incurred_on,
source_path=resolved,
client_id=row.client_id,
application_id=row.application_id,
app_instance_id=row.app_instance_id,
cost_attribution_key=row.cost_attribution_key,
)
for row in parse_hosteurope_csv(path)
]
@ -217,8 +234,9 @@ def import_csv(
"""
INSERT INTO ledger_entries (
source_type, category, label, amount, currency,
period_month, incurred_on, source_path, imported_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
period_month, incurred_on, source_path, imported_at,
client_id, application_id, app_instance_id, cost_attribution_key
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
entry.source_type,
@ -230,6 +248,10 @@ def import_csv(
entry.incurred_on.isoformat() if entry.incurred_on else None,
entry.source_path,
imported_at,
entry.client_id,
entry.application_id,
entry.app_instance_id,
entry.cost_attribution_key,
),
)
conn.execute(
@ -300,4 +322,4 @@ def ledger_stats(*, ledger_path: Path | None = None) -> dict:
def ledger_stats_json(*, ledger_path: Path | None = None) -> str:
return json.dumps(ledger_stats(ledger_path=ledger_path), indent=2)
return json.dumps(ledger_stats(ledger_path=ledger_path), indent=2)