/** * XorPay 订单状态直接查询(兜底) * salonapi 不可用时,前端直接向 xorpay 查询,保证本地支付能检测到 */ import { createHash } from "crypto"; /** 与 salonapi 保持一致,用于直接查询 xorpay 兜底 */ const XORPAY_AID = process.env.XORPAY_AID || process.env.NEXT_PUBLIC_XORPAY_AID || "8220"; const XORPAY_SECRET = process.env.XORPAY_SECRET || process.env.NEXT_PUBLIC_XORPAY_SECRET || "afcacd99570945f88de62624aaa3578e"; const XORPAY_QUERY_URL = process.env.XORPAY_QUERY_URL || process.env.NEXT_PUBLIC_XORPAY_QUERY_URL || "https://xorpay.com/api/query2"; const XORPAY_QUERY_TIMEOUT_MS = Number( process.env.XORPAY_QUERY_TIMEOUT_MS || 5000 ); export type XorPayStatusResult = { ok: boolean; paid: boolean; status?: string; payPrice?: string; error?: string; url: string; }; function buildXorPaySign(orderId: string): string { return createHash("md5") .update(`${orderId}${XORPAY_SECRET}`, "utf8") .digest("hex") .toLowerCase(); } export async function queryXorPayOrderStatus( orderId: string, timeoutMs = XORPAY_QUERY_TIMEOUT_MS ): Promise { const normalizedOrderId = orderId.trim(); if (!normalizedOrderId || !XORPAY_AID || !XORPAY_SECRET) { return null; } const url = new URL( `${XORPAY_QUERY_URL.replace(/\/$/, "")}/${encodeURIComponent(XORPAY_AID)}` ); url.searchParams.set("order_id", normalizedOrderId); url.searchParams.set("sign", buildXorPaySign(normalizedOrderId)); try { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), timeoutMs); const res = await fetch(url.toString(), { cache: "no-store", signal: controller.signal, }).finally(() => clearTimeout(timeout)); const data = await res.json().catch(() => ({})); const status = String(data?.status ?? "") .trim() .toLowerCase(); return { ok: res.ok, paid: res.ok && (status === "payed" || status === "success"), status, payPrice: String(data?.pay_price ?? data?.price ?? "").trim() || undefined, url: url.toString(), error: res.ok ? undefined : `status=${res.status}`, }; } catch (error) { return { ok: false, paid: false, url: url.toString(), error: error instanceof Error ? error.message : String(error), }; } }