#!/usr/bin/env python3 """Ватчер Alipay на live-счёте Stripe (эскалация e-261005142309-390896). Контекст: Alex включил тумблер Alipay в дашборде (preference=on), но capability ещё not available — счёт ждёт аппрува Stripe («говорит что нужен ещё аппрувал, ждем», m-516173789). Включить через API нельзя (rk_live restricted, available=false). Этот скрипт — детерминированный поллинг без LLM (systemd-таймер, 5 мин): - пока alipay.available=false → тихо выходим (state=waiting); - как только Stripe активирует capability → создаёт Checkout Session $100 one_time (price_1UNCYGBT53G7FGSQya04h28r) с card+alipay и идемпотентно (cli.py tg-notify -k) отправляет ссылку в чат; - после успешной доставки пишет done-маркер и больше не работает. Ключ читается из /root/coop/.env (STRIPE_LIVE_KEY, реестр KEYS-REGISTRY). Состояние: /var/lib/simbiot-harness/alipay-watch.state. Выход: 0 = ждём/отработал, 3 = ошибка конфигурации (для журнала). """ import json import os import subprocess import sys import urllib.error import urllib.parse import urllib.request STATE = "/var/lib/simbiot-harness/alipay-watch.state" ENV_FILE = "/root/coop/.env" PRICE = "price_1UNCYGBT53G7FGSQya04h28r" # $100 USD one_time, live NOTIFY_KEY = "alipay-live-100-link" # идемпотентность доставки (t-260930083937) HARNESS = "/root/simbiot-harness" VENV_PY = f"{HARNESS}/venv/bin/python" def _stripe_key() -> str | None: try: with open(ENV_FILE) as f: for line in f: line = line.strip() if line.startswith("STRIPE_LIVE_KEY="): return line.split("=", 1)[1].strip().strip('"').strip("'") except OSError: pass return os.environ.get("STRIPE_LIVE_KEY") def _call(path: str, method: str = "GET", data: dict | None = None) -> dict: key = _stripe_key() if not key: return {"_error": "no STRIPE_LIVE_KEY"} body = urllib.parse.urlencode(data).encode() if data is not None else None req = urllib.request.Request( "https://api.stripe.com/v1/" + path, headers={"Authorization": f"Bearer {key}"}, method=method, data=body, ) try: with urllib.request.urlopen(req, timeout=25) as r: return json.loads(r.read()) except urllib.error.HTTPError as e: return {"_error": e.code, "body": e.read().decode()[:400]} def _read_state() -> str: try: with open(STATE) as f: return f.read().strip() except OSError: return "" def _write_state(s: str) -> None: os.makedirs(os.path.dirname(STATE), exist_ok=True) with open(STATE, "w") as f: f.write(s) def main() -> int: if _read_state() == "done": return 0 # ссылка создана и доставлена — ватчер отработал cfgs = _call("payment_method_configurations?limit=100") for c in cfgs.get("data", []): alipay = c.get("alipay") or {} if alipay.get("available"): # capability активна — создаём линк card+alipay sess = _call("checkout/sessions", "POST", { "mode": "payment", "line_items[0][price]": PRICE, "line_items[0][quantity]": "1", "success_url": "https://cil.by/thanks", "cancel_url": "https://cil.by/", "payment_method_types[0]": "card", "payment_method_types[1]": "alipay", }) url = sess.get("url") if not url: # доступна, но сессия не собирается — оставить ждущим, # причина в журнале таймера; следующий прогон повторит _write_state("available-but-failed") print("alipay available, session failed:", sess.get("_error"), sess.get("body", "")[:200]) return 0 text = (f"Alipay активирован на live-счёте Stripe. " f"Боевая ссылка $100 (card + Alipay): {url}") r = subprocess.run( [VENV_PY, f"{HARNESS}/cli.py", "tg-notify", text, "-k", NOTIFY_KEY], capture_output=True, text=True, timeout=60, ) out = (r.stdout or "").strip() print("notify:", out) if out.startswith("OK") or "SKIP" in out: _write_state("done") return 0 _write_state("notify-failed") return 0 print(f"waiting: alipay preference={alipay.get('display_preference', {}).get('value')} " f"available={alipay.get('available')} (cfg {c.get('id')})") _write_state("waiting") return 0 print("no live payment_method_configuration found:", cfgs.get("_error", "?")) return 3 if __name__ == "__main__": sys.exit(main())