Integrate starter pack timing, reactivation, purchase analytics, payment routing and atomic user IDs. Resolve iOS conflicts by preserving both battle pass delivery and starter pack snapshots. Add coexistence regression checks and record remaining compatibility risks. Validation: 118/125 tests passed; 7 existing failures remain, plus a separately reproduced pre-existing V2 task login failure.
86 lines
3.5 KiB
TypeScript
86 lines
3.5 KiB
TypeScript
import * as StarterPackModule from "@/limitedTimeEvent";
|
|
const StarterPack: any = StarterPackModule as any;
|
|
import cloud from '@lafjs/cloud'
|
|
import { passOrderFields, PASS_PRICES } from '@/passCheckUpgrade';
|
|
import * as crypto from 'crypto';
|
|
import * as JungleConfigModule from "@/jungleConfig";
|
|
const JungleConfig: any = JungleConfigModule as any;
|
|
const db = cloud.database();
|
|
export default async function (ctx: FunctionContext) {
|
|
// Deployment configuration owns routing; never trust client isDebug/envVersion.
|
|
const paymentAppEnv = process.env.PAYMENT_APP_ENV || "production";
|
|
if (!["production", "test"].includes(paymentAppEnv)
|
|
|| (paymentAppEnv === "test" && !process.env.WX_MIDAS_PAY_SIGN_KEY)) {
|
|
return { code: 0, data: null, msg: "支付环境配置不完整" };
|
|
}
|
|
let uid = ctx.body.uid;
|
|
let itemid = ctx.body.itemid;
|
|
let itemCount = ctx.body.itemCount;
|
|
let itemPrice = ctx.body.itemPrice;
|
|
let user = await db.collection("users").where({ _id: uid }).getOne();
|
|
if (user.data == null) {
|
|
return { code: 0, data: null, msg: "未获取到玩家数据" };
|
|
}
|
|
const jungleTier = JungleConfig.getJunglePaidTierByProductId(itemid);
|
|
let passFields: any = {};
|
|
try {
|
|
passFields = passOrderFields(user.data, ctx.body);
|
|
if (passFields.passVersion) { itemCount = 1; itemPrice = PASS_PRICES[itemid]; }
|
|
} catch (error) { return { code: 0, msg: error.message }; }
|
|
if (jungleTier) {
|
|
if (!JungleConfig.isJungleActivityPurchasable(user.data.jungleTreasureState)) {
|
|
return { code: 0, data: null, msg: "Jungle 活动已结束,无法创建订单" };
|
|
}
|
|
const state = JungleConfig.normalizeStoredJungleState(user.data.jungleTreasureState);
|
|
if (state.tierStates[jungleTier.id - 1] !== 0) {
|
|
return { code: 0, data: null, msg: "该 Jungle 付费档位已经解锁或领取" };
|
|
}
|
|
itemCount = 1;
|
|
itemPrice = Math.round(jungleTier.price * 100);
|
|
}
|
|
const outTradeNo = (paymentAppEnv === "test" ? "wct_" : "wcx_") + Math.round(Math.random() * 10 ** 13) + Date.now();
|
|
let signData = JSON.stringify({
|
|
"mode": "goods",
|
|
"offerId": "1450527458",
|
|
"buyQuantity": Number(itemCount),//购买数量
|
|
"env": 0,//正式环境
|
|
"currencyType": "CNY",//人民币
|
|
"platform": "android",
|
|
"zoneId": "1",//分区id
|
|
"productId": itemid,
|
|
"goodsPrice": Number(itemPrice),
|
|
"outTradeNo": outTradeNo,
|
|
"attach": "购买道具"
|
|
});
|
|
let session_key = user.data.session_key;
|
|
const signature = hmacSha256(session_key, signData);
|
|
let data = 'requestMidasPaymentGameItem' + '&' + signData;
|
|
const paySig = hmacSha256(process.env.WX_MIDAS_PAY_SIGN_KEY, data);
|
|
await db.collection("order").add({
|
|
...passFields,
|
|
openid: user.data.openid,
|
|
outTradeNo: outTradeNo,
|
|
paymentAppEnv,
|
|
...StarterPack.starterPackOrderSnapshot(user.data, itemid),
|
|
itemid: itemid,
|
|
itemCount: itemCount,
|
|
goodsPrice: Number(itemPrice),
|
|
time: Date.now(),//申请订单时间
|
|
orderTime: new Date(Date.now() + 8 * 3600000),
|
|
chargeTime: 0,
|
|
getTime: 0,
|
|
type: "ios",
|
|
state: 0,
|
|
...(jungleTier ? { jungleTierId: jungleTier.id } : {}),
|
|
});
|
|
console.log("申请订单");
|
|
console.log(outTradeNo);
|
|
// 计算哈希值并转换为十六进制字符串
|
|
return { code: 1, data: { paySig: paySig, signature: signature, signData: signData, outTradeNo: outTradeNo }, msg: "成功" }
|
|
}
|
|
function hmacSha256(sessionKey, signData) {
|
|
const hmac = crypto.createHmac('sha256', sessionKey);
|
|
hmac.update(signData);
|
|
return hmac.digest('hex');
|
|
}
|