Files
aza/AzA march 2026/_live_test_postcheck.py

169 lines
5.8 KiB
Python
Raw Permalink Normal View History

2026-05-23 21:31:34 +02:00
#!/usr/bin/env python3
"""Post-check auto-topup live test + optional restore (no charges)."""
import json
import sqlite3
import sys
import time
from pathlib import Path
DB = Path("/root/aza-app/data/stripe_webhook.sqlite")
PRACTICE = "prac_883ddc21fb6a"
SUB = "wc_sub_1502"
TEST_REQUEST_ID = "test_popup_budget_20260521_exhaust"
BACKUP = "/root/aza-app/backups/auto_topup_trigger_live_test_20260521_195425"
AUTO_COOLDOWN = 86400
sys.path.insert(0, "/root/aza-app")
from aza_ai_budget import LicenseBudgetRow, check_allows_openai_call, compute_budget_snapshot
from aza_ai_credit import (
AUTO_TOPUP_COOLDOWN_SEC,
get_topup_settings,
last_successful_auto_topup_ts,
sum_topups_chf_this_month,
)
def mask_stripe_id(val: str | None, prefix: str) -> str | None:
s = (val or "").strip()
if not s.startswith(prefix):
return None
if len(s) <= 10:
return f"{prefix}***"
return f"{s[:7]}...{s[-4:]}"
def load_lic(con):
row = con.execute(
"SELECT subscription_id, customer_email, customer_id, practice_id, lookup_key, status, "
"current_period_start, current_period_end FROM licenses WHERE subscription_id=? AND practice_id=?",
(SUB, PRACTICE),
).fetchone()
return LicenseBudgetRow(
subscription_id=row[0],
customer_email=row[1] or "",
customer_id=row[2],
practice_id=row[3],
lookup_key=row[4],
status=row[5] or "",
period_start=int(row[6]),
period_end=int(row[7]),
)
def budget_json(con, lic):
snap = compute_budget_snapshot(con, lic)
ok, _ = check_allows_openai_call(con, lic)
return {
"monthly_budget": snap.get("budget_usd"),
"used_usd": snap.get("used_usd"),
"monthly_remaining": snap.get("remaining_usd"),
"extra_credit_remaining": snap.get("extra_credit_remaining_usd"),
"total_available": snap.get("total_available_usd"),
"available_percent": snap.get("available_percent"),
"allows_call": ok,
}
def check_auto_topups(con):
rows = con.execute(
"""
SELECT id, created_at, event_type, status, amount_paid_chf, amount_internal_usd,
stripe_payment_intent_id, stripe_checkout_session_id
FROM ai_credit_ledger
WHERE practice_id=? AND event_type IN ('auto_topup_purchase','failed_auto_topup')
ORDER BY created_at ASC
""",
(PRACTICE,),
).fetchall()
auto = [r for r in rows if r[2] == "auto_topup_purchase"]
failed = [r for r in rows if r[2] == "failed_auto_topup"]
return auto, failed
def main():
mode = (sys.argv[1] if len(sys.argv) > 1 else "check").strip().lower()
con = sqlite3.connect(str(DB))
lic = load_lic(con)
settings = get_topup_settings(con, PRACTICE)
print("=== BACKUP ===")
print(BACKUP)
print("\n=== AUTO TOPUP SETTINGS ===")
print(
"enabled=", settings.auto_topup_enabled,
"trigger=", settings.trigger_below_percent,
"monthly_limit_chf=", settings.monthly_limit_chf,
"cus=", mask_stripe_id(settings.stripe_customer_id, "cus_"),
"pm=", mask_stripe_id(settings.default_payment_method_id, "pm_"),
)
auto, failed = check_auto_topups(con)
print("\n=== LEDGER auto_topup / failed ===")
print("auto_topup_purchase count=", len(auto))
print("failed_auto_topup count=", len(failed))
for r in auto:
print(
" auto:",
"status=", r[3],
"chf=", r[4],
"usd=", r[5],
"pi=", mask_stripe_id(r[6], "pi_"),
"created_at=", r[1],
)
for r in failed:
print(" failed:", r[3], "chf=", r[4], "created_at=", r[1])
auto24 = con.execute(
"SELECT COUNT(*) FROM ai_credit_ledger WHERE practice_id=? "
"AND event_type='auto_topup_purchase' AND status='succeeded' "
"AND created_at >= ?",
(PRACTICE, int(time.time()) - AUTO_COOLDOWN),
).fetchone()[0]
print("auto_topup_succeeded_last_24h=", auto24)
last_ts = last_successful_auto_topup_ts(con, PRACTICE)
cooldown_active = bool(last_ts and (time.time() - last_ts) < AUTO_TOPUP_COOLDOWN_SEC)
print("cooldown_active=", cooldown_active)
if last_ts:
print("last_auto_topup_age_sec=", int(time.time() - last_ts))
spent_month = sum_topups_chf_this_month(con, PRACTICE)
print("auto_topups_chf_this_month=", spent_month, "limit=", settings.monthly_limit_chf)
print("monthly_limit_ok=", spent_month <= settings.monthly_limit_chf + 1e-9)
snap_before_restore = budget_json(con, lic)
print("\n=== BUDGET (before restore) ===")
print(json.dumps(snap_before_restore, ensure_ascii=False))
print("\n=== 24H BLOCK (read-only) ===")
print("would_block_retrigger=", cooldown_active)
test_events = con.execute(
"SELECT COUNT(*) FROM ai_usage_events WHERE request_id=? AND practice_id=?",
(TEST_REQUEST_ID, PRACTICE),
).fetchone()[0]
print("\n=== TEST EVENT ===")
print("test_popup_events=", test_events)
if mode == "restore":
cur = con.execute(
"DELETE FROM ai_usage_events WHERE request_id=? AND subscription_id=? AND practice_id=?",
(TEST_REQUEST_ID, SUB, PRACTICE),
)
con.commit()
print("RESTORE_OK deleted=", cur.rowcount)
snap_after = budget_json(con, lic)
print("\n=== BUDGET (after restore) ===")
print(json.dumps(snap_after, ensure_ascii=False))
settings2 = get_topup_settings(con, PRACTICE)
print("\n=== SETTINGS AFTER RESTORE ===")
print("auto_topup_enabled=", settings2.auto_topup_enabled)
last_ts2 = last_successful_auto_topup_ts(con, PRACTICE)
cooldown2 = bool(last_ts2 and (time.time() - last_ts2) < AUTO_TOPUP_COOLDOWN_SEC)
print("cooldown_still_active=", cooldown2)
if __name__ == "__main__":
main()