simbiot-harness/scripts/alipay_watch.py

129 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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())