#!/bin/bash set -e STAMP="$(date +%Y%m%d-%H%M%S)" cp app.py "app.py.auto-expire-pending.${STAMP}.bak" python3 <<'PY' from pathlib import Path p = Path("app.py") text = p.read_text() anchor = "def portal_invoice" if anchor not in text: raise SystemExit("FAILED: portal_invoice route not found") # find insertion point (start of function body) idx = text.index(anchor) start = text.index(":", idx) + 1 inject_code = ''' # === AUTO-EXPIRE STALE PENDING CRYPTO PAYMENTS === try: from datetime import datetime, timedelta conn2 = get_db_connection() cur2 = conn2.cursor(dictionary=True) cur2.execute( "SELECT id, payment_status, txid, created_at " "FROM payments " "WHERE invoice_id = %s AND payment_method = 'crypto' " "ORDER BY id DESC LIMIT 1", (invoice_id,) ) last_payment = cur2.fetchone() if last_payment: is_pending = str(last_payment.get("payment_status") or "").lower() == "pending" has_tx = bool(last_payment.get("txid")) created_at = last_payment.get("created_at") is_expired = False if created_at: is_expired = datetime.utcnow() > (created_at + timedelta(minutes=15)) if is_pending and not has_tx and is_expired: cur2.execute( "UPDATE payments SET payment_status = 'expired' WHERE id = %s", (last_payment["id"],) ) conn2.commit() print(f"[auto-expire] expired stale payment id={last_payment['id']} invoice_id={invoice_id}") conn2.close() except Exception as e: print(f"[auto-expire] error: {e}") # === END AUTO-EXPIRE === ''' text = text[:start] + inject_code + text[start:] p.write_text(text) print("OK: auto-expire logic injected cleanly") PY python3 -m py_compile app.py echo "PY_COMPILE_OK" sudo systemctl restart otb_billing sudo systemctl status otb_billing --no-pager -l