优化了部分支付宝界面
This commit is contained in:
@@ -212,6 +212,80 @@ def save_payment_status(path: Path, document: dict, baseline: dict[str, bool], m
|
||||
path.write_text(json.dumps(record, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def save_payment_meta(path: Path, order: dict[str, str], baseline: dict[str, bool], document: dict) -> None:
|
||||
"""Persist the order identifiers and pre-payment baseline needed by a later check.
|
||||
|
||||
``check`` only re-reads this file and never touches web_save, so re-running a
|
||||
check is side-effect free.
|
||||
"""
|
||||
from pyvm.order_status import order_ids
|
||||
|
||||
record = {
|
||||
"order_identifiers": {
|
||||
"token_id": order.get("token_id", ""),
|
||||
"transaction_id": order.get("transaction_id", ""),
|
||||
"out_trade_no": order.get("out_trade_no", ""),
|
||||
},
|
||||
"baseline_order_states": baseline,
|
||||
"baseline_order_ids": sorted(order_ids(document)),
|
||||
"qr_created_at": int(time.time()),
|
||||
}
|
||||
path.write_text(json.dumps(record, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def _match_finished_by_identifiers(listed: list[dict], identifiers: dict[str, str]) -> dict | None:
|
||||
"""Match a finished order by the identifiers recorded at QR creation time.
|
||||
|
||||
The official order list may not carry token_id/out_trade_no, so no fallback
|
||||
to "any newly completed order" is allowed: an unrelated order finishing on
|
||||
the same account must not be reported as this payment.
|
||||
"""
|
||||
from pyvm.order_status import is_finished
|
||||
|
||||
for item in listed:
|
||||
if is_finished(item) and any(
|
||||
identifiers.get(key) and str(item.get(key, "")) == str(identifiers[key])
|
||||
for key in identifiers
|
||||
):
|
||||
return item
|
||||
return None
|
||||
|
||||
|
||||
def cmd_check_only(session_path: Path, out_dir: Path) -> int:
|
||||
"""Read-only payment completion check bound to a previously created QR.
|
||||
|
||||
Only an order identifier recorded at QR creation time counts as a match;
|
||||
a fallback to "any newly completed order" is intentionally NOT used because
|
||||
the order list cannot be proven to carry our token/out_trade_no fields,
|
||||
and another order completing on the same account could be misjudged.
|
||||
|
||||
Exit codes: 0 = confirmed, 1 = not confirmed yet, 2 = check failed.
|
||||
"""
|
||||
from pyvm.order_status import (
|
||||
completion_summary,
|
||||
get_official_orders,
|
||||
is_finished,
|
||||
)
|
||||
|
||||
session = load_json(session_path)
|
||||
cookies = dict(session.get("cookies", {}))
|
||||
if not cookies:
|
||||
raise ValueError("会话 cookies 为空,无法检测到账")
|
||||
meta = load_json(out_dir / "payment-meta.json")
|
||||
baseline = meta.get("baseline_order_states", {})
|
||||
print("[jsdom-pay:check] 拉取官方订单列表...")
|
||||
document = get_official_orders(cookies)
|
||||
listed = [item for item in document.get("list", []) if isinstance(item, dict)]
|
||||
matched = _match_finished_by_identifiers(listed, meta.get("order_identifiers", {}))
|
||||
status_path = out_dir / "payment-status.json"
|
||||
save_payment_status(status_path, document, baseline, matched)
|
||||
if matched:
|
||||
print(f"[jsdom-pay:check] 已按订单标识确认到账: {completion_summary(matched)}")
|
||||
return 0
|
||||
print("[jsdom-pay:check] 未匹配到本次订单标识,保持未确认状态,请人工核对")
|
||||
return 1
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="YYB: jsdom DeviceFP + web_save -> 微信付款码")
|
||||
parser.add_argument("--session", default=str(ROOT / "config/mall-session.json"))
|
||||
@@ -228,12 +302,20 @@ def main() -> int:
|
||||
parser.add_argument("--payment-interval", type=float, default=3,
|
||||
help="订单完成状态检查间隔秒数")
|
||||
parser.add_argument("--skip-payment-check", action="store_true", help="仅生成付款码,不等待订单完成")
|
||||
parser.add_argument("--check-only", action="store_true",
|
||||
help="只读检测到账(依赖 --out-dir 下已保存的 payment-meta.json),不创建订单")
|
||||
args = parser.parse_args()
|
||||
if args.payment_timeout <= 0 or args.payment_interval <= 0:
|
||||
raise ValueError("--payment-timeout 和 --payment-interval 必须为正数")
|
||||
|
||||
session_path = Path(args.session).resolve()
|
||||
response_path = Path(args.mall_response).resolve()
|
||||
stamp = time.strftime("%Y%m%d-%H%M%S")
|
||||
out_dir = Path(args.out_dir) if args.out_dir else ROOT / "config" / f"jsdom-order-{stamp}"
|
||||
if args.check_only:
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
return cmd_check_only(session_path, out_dir)
|
||||
|
||||
session = load_json(session_path)
|
||||
cookies = dict(session.get("cookies", {}))
|
||||
if not cookies:
|
||||
@@ -312,6 +394,17 @@ def main() -> int:
|
||||
order, cookies, web_token, anti_token, encrypt_msg,
|
||||
args.zone_id, payment_pf, args.amount_fen,
|
||||
)
|
||||
from pyvm.order_status import order_completion_states, get_official_orders
|
||||
|
||||
# 尽量在发起支付前建立基线,缩小极快支付造成的检测窗口;失败不阻塞支付,付款码生成后重试。
|
||||
baseline_document = None
|
||||
baseline_states = None
|
||||
try:
|
||||
baseline_document = get_official_orders(cookies)
|
||||
baseline_states = order_completion_states(baseline_document)
|
||||
print("[jsdom-pay] 支付前订单基线已建立")
|
||||
except Exception as exc: # noqa: BLE001
|
||||
print(f"[jsdom-pay] 支付前建立基线失败({exc}),将在付款码生成后重试")
|
||||
print("[jsdom-pay] 提交 web_save...")
|
||||
raw = request_bytes(SAVE_URL, cookies, body.encode())
|
||||
(out_dir / "web-save-response.json").write_text(raw, encoding="utf-8")
|
||||
@@ -331,23 +424,36 @@ def main() -> int:
|
||||
make_qr(sign, qr_path)
|
||||
print("[jsdom-pay] 微信付款码已生成")
|
||||
print(f"[jsdom-pay] PNG: {qr_path}")
|
||||
print(f"[jsdom-pay] 付款链接: {sign}")
|
||||
|
||||
if baseline_document is None:
|
||||
try:
|
||||
baseline_document = get_official_orders(cookies)
|
||||
baseline_states = order_completion_states(baseline_document)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
# 付款码已生成,基线缺失只影响确认精度(仅按订单标识确认),不能阻断付款。
|
||||
print(f"[jsdom-pay] 基线获取失败: {exc};将仅按订单标识确认到账")
|
||||
baseline_document = {"list": []}
|
||||
baseline_states = {}
|
||||
print("[jsdom-pay] 记录付款前订单基线与本次订单标识...")
|
||||
save_payment_meta(out_dir / "payment-meta.json", order, baseline_states, baseline_document)
|
||||
if args.skip_payment_check:
|
||||
print("[jsdom-pay] 已跳过付款结果检查。")
|
||||
print("[jsdom-pay] 已保存基线;后台将单独执行只读到账检测")
|
||||
return 0
|
||||
|
||||
from pyvm.order_status import find_completed_order, get_official_orders, order_completion_states
|
||||
|
||||
print("[jsdom-pay] 记录付款前订单列表,等待微信付款完成...")
|
||||
baseline_document = get_official_orders(cookies)
|
||||
baseline_states = order_completion_states(baseline_document)
|
||||
status_path = out_dir / "payment-status.json"
|
||||
save_payment_status(status_path, baseline_document, baseline_states)
|
||||
identifiers = {key: value for key, value in {
|
||||
"token_id": order.get("token_id", ""),
|
||||
"transaction_id": order.get("transaction_id", ""),
|
||||
"out_trade_no": order.get("out_trade_no", ""),
|
||||
}.items() if value}
|
||||
deadline = time.monotonic() + args.payment_timeout
|
||||
while time.monotonic() < deadline:
|
||||
time.sleep(args.payment_interval)
|
||||
document = get_official_orders(cookies)
|
||||
completed = find_completed_order(document, baseline_states)
|
||||
completed = _match_finished_by_identifiers(
|
||||
[item for item in document.get("list", []) if isinstance(item, dict)], identifiers)
|
||||
save_payment_status(status_path, document, baseline_states, completed)
|
||||
if completed:
|
||||
print("[jsdom-pay] 微信付款成功,商城订单已完成。")
|
||||
|
||||
Reference in New Issue
Block a user