Browse Source

Bump OTB Billing to v2.0.0 with last reconcile run

main v2.0.0
def 1 month ago
parent
commit
a3ef2170d6
  1. 34
      PROJECT_STATE.md
  2. 24
      README.md
  3. 2
      VERSION
  4. 36
      backend/health.py
  5. 2
      templates/health.html

34
PROJECT_STATE.md

@ -1,5 +1,39 @@
# PROJECT_STATE - OTB Billing
## v2.0.0 - 2026-05-18
Current state:
- OTB Billing is running on outsidethedb.
- Service: otb_billing.service.
- App port: 5050.
- Project path: /home/def/otb_billing.
- Current version: v2.0.0.
- /health renders the standard health grid with Status, Database, Uptime, Load Average, Memory, Disk, Operations Bal, Treasury Bal, and Crypto Reconcile.
- Operations Bal wallet: 0x44f6c44C42e6ae0392E7289F032384C0d37F56D5.
- Treasury Bal wallet: 0xbe1fdc8c69f712d62cfcd3bf23f636de1dbd213f.
- Wallet coin names are clickable explorer links:
- USDC uses Arbiscan
- ETH uses Etherscan
- ETHO uses explorer.ethoprotocol.com
- EGAZ and ETI use explorer.etica-stats.org
- Crypto Reconcile card shows:
- timer status
- service status
- last run timestamp
- last result
- pending payment count
- confirmed today count
- stale pending count
- Reconcile Now button
- Crypto reconciliation worker:
- Timer: otb-billing-crypto-reconcile.timer
- Service: otb-billing-crypto-reconcile.service
- Script: /home/def/otb_billing/scripts/crypto_reconciliation_worker.py
- Timer cadence: every 15 minutes
- The reconcile service is one-shot; inactive between runs is normal when the timer is active.
# PROJECT_STATE - OTB Billing
## v1.4.0 - 2026-05-18
Current state:

24
README.md

@ -1,3 +1,27 @@
# OTB Billing - v2.0.0
Build date: 2026-05-18
## v2.0.0 changes
- Promoted OTB Billing to v2.0.0.
- Added Last Run and Last Result fields to the Crypto Reconcile health card.
- Last Run is read from systemd one-shot service timestamps for otb-billing-crypto-reconcile.service.
- Confirmed Crypto Reconcile remains a normal card in the main /health grid.
- Existing health cards remain:
- Status
- Database
- Uptime
- Load Average
- Memory
- Disk
- Operations Bal
- Treasury Bal
- Crypto Reconcile
- Existing Operations Bal and Treasury Bal cards retain clickable explorer links for USDC, ETH, ETHO, EGAZ, and ETI.
- Reconcile Now button remains available on /health to manually start the crypto reconciliation worker.
- Footer/app version bumped from v1.4.0 to v2.0.0.
# OTB Billing - v1.4.0
Build date: 2026-05-18

2
VERSION

@ -1 +1 @@
v1.4.0
v2.0.0

36
backend/health.py

@ -490,6 +490,18 @@ def _try_payment_stats_from_db(app):
pass
def _parse_systemctl_show(stdout):
parsed = {}
for line in str(stdout or "").splitlines():
if "=" not in line:
continue
key, value = line.split("=", 1)
parsed[key.strip()] = value.strip()
return parsed
def _crypto_reconcile_status(app):
service_name = "otb-billing-crypto-reconcile.service"
timer_name = "otb-billing-crypto-reconcile.timer"
@ -507,16 +519,33 @@ def _crypto_reconcile_status(app):
timer_name,
])
last_logs = _systemctl_value([
service_show = _systemctl_value([
"show",
service_name,
"--property=ActiveEnterTimestamp",
"--property=InactiveEnterTimestamp",
"--property=ExecMainStatus",
"--property=Result",
"--property=NRestarts",
"--no-pager",
])
parsed = _parse_systemctl_show(service_show["stdout"])
active_entered = parsed.get("ActiveEnterTimestamp") or ""
inactive_entered = parsed.get("InactiveEnterTimestamp") or ""
result = parsed.get("Result") or "unknown"
exec_status = parsed.get("ExecMainStatus") or "unknown"
# For a oneshot timer service, InactiveEnterTimestamp is usually the useful
# "last completed" timestamp. Fall back to ActiveEnterTimestamp if needed.
last_run = inactive_entered
if not last_run or last_run.lower() in ("n/a", "never"):
last_run = active_entered
if not last_run:
last_run = "unknown"
return {
"service_name": service_name,
"timer_name": timer_name,
@ -525,7 +554,10 @@ def _crypto_reconcile_status(app):
"service_active": service_active["stdout"] or "unknown",
"service_enabled": service_enabled["stdout"] or "unknown",
"timer_line": timer_list["stdout"],
"service_details": last_logs["stdout"],
"service_details": service_show["stdout"],
"last_run": last_run,
"last_result": result,
"last_exit_status": exec_status,
"payment_stats": _try_payment_stats_from_db(app),
}

2
templates/health.html

@ -222,6 +222,8 @@
{% endif %}
</p>
<p><strong>Service:</strong> {{ health.crypto_reconcile.service_active }}</p>
<p class="monoish"><strong>Last Run:</strong> {{ health.crypto_reconcile.last_run }}</p>
<p><strong>Last Result:</strong> {{ health.crypto_reconcile.last_result }}</p>
{% if health.crypto_reconcile.payment_stats and health.crypto_reconcile.payment_stats.available %}
<p><strong>Pending:</strong> {{ health.crypto_reconcile.payment_stats.pending }}</p>

Loading…
Cancel
Save