import { associateLegacyOrder, matchesCustomerLinkTime } from "@/goldMiner/legacyPayment"; import cloud from '@lafjs/cloud' const db = cloud.database(); export default async function (ctx: FunctionContext) { const body = ctx.body || {}; const paymentAppEnv = process.env.PAYMENT_APP_ENV || "production"; if (!["production", "test"].includes(paymentAppEnv) || typeof body.outTradeNo !== "string" || !body.outTradeNo) return false; const testOrder = body.outTradeNo.startsWith("wct_"); if (testOrder && paymentAppEnv === "production") return forwardTestCheckIos(ctx); if (!testOrder && paymentAppEnv === "test") return false; console.log("检查提醒"); let openid = ctx.body.openid; let time = ctx.body.time; let outTradeNo = ctx.body.outTradeNo; const canonical = typeof outTradeNo === "string" ? (await db.collection("order").where({ outTradeNo }).getOne()).data : null; const compatibility = typeof outTradeNo === "string" ? (await db.collection("iosOrder").where({ outTradeNo }).getOne()).data : null; if (canonical?.goldMiner || compatibility?.goldMiner || String(canonical?.itemid || compatibility?.itemid || "").startsWith("gold_miner")) { try { return await associateLegacyOrder(ctx.body, canonical, compatibility); } catch (error) { const order = canonical || compatibility; const errorCode = typeof error?.errorCode === "string" ? error.errorCode : "RETRYABLE"; const runtimeMessage = typeof error?.message === "string" && /^[A-Za-z_$][A-Za-z0-9_$.]*( is not defined| is not a function)$/.test(error.message) ? error.message : null; const message = errorCode !== "RETRYABLE" && typeof error?.message === "string" ? error.message : runtimeMessage || "转单发生内部异常,请检查服务端调用链"; console.error("[GoldMiner checkIos] rejected", { outTradeNo, errorCode, message, errorName: error?.name, paymentAppEnv: process.env.PAYMENT_APP_ENV || "production", orderEnv: order.paymentAppEnv, orderFound: !!canonical, iosOrderFound: !!compatibility, timeMatches: matchesCustomerLinkTime(time, order), serverTime: Date.now(), startsAt: order.goldMiner?.startsAt, endsAt: order.goldMiner?.endsAt, }); return false; } } if (!canonical && !compatibility) { console.error("[checkIos] order not found", { outTradeNo, paymentAppEnv: process.env.PAYMENT_APP_ENV || "production", testOrder: typeof outTradeNo === "string" && outTradeNo.startsWith("wct_"), }); } if (!openid || !time) { return false; } let user = await db.collection("users").where({ openid: openid }).getOne(); if (user.data) { if (user.data.iosTime == time) { let res = await db.collection("iosOrder").where({ outTradeNo: outTradeNo }).getOne(); if (res.data) { await db.collection("order").add({ ...(res.data.passVersion === 2 ? { passVersion: 2, passEnd: res.data.passEnd } : {}), openid: res.data.openid, outTradeNo: res.data.outTradeNo, itemid: res.data.itemid, ...(res.data.activityType ? { activityType: res.data.activityType } : {}), ...(res.data.rewardVersion ? { rewardVersion: res.data.rewardVersion } : {}), ...(res.data.paymentAppEnv ? { paymentAppEnv: res.data.paymentAppEnv } : {}), itemCount: res.data.itemCount, goodsPrice: res.data.goodsPrice, time: res.data.time, orderTime: res.data.time, chargeTime: 0, getTime: 0, type: "ios", state: 0, }); db.collection("iosOrder").where({ outTradeNo: outTradeNo }).remove({ multi: true }); return true; } else { let res = await db.collection("order").where({ outTradeNo: outTradeNo }).getOne(); if (res.data) { console.log("验证成功"); return true; } return false; } } } return false; } async function forwardTestCheckIos(ctx: FunctionContext): Promise { if (Object.keys(ctx.headers || {}).some(name => name.toLowerCase() === "x-payment-forwarded")) return false; try { // Server-owned destination only. Preserve credentials/tickets for validation by the test app. const configured = process.env.TEST_WX_CHECK_IOS_URL; const target = configured ? new URL(configured) : new URL("/wx/checkIos", process.env.TEST_WX_PAY_NOTIFY_URL); if (target.protocol !== "https:" || target.username || target.password || target.hash || target.search || target.pathname !== "/wx/checkIos") return false; const response = await cloud.fetch({ url: target.href, method: "POST", data: ctx.body, headers: { "content-type": "application/json", "x-payment-forwarded": "1" }, timeout: 3000, maxRedirects: 0, }); // Association success is not payment confirmation; retain the existing boolean protocol. return response.status === 200 && response.data === true; } catch { console.error("测试订单 checkIos 转发失败"); return false; } }