MatchMaster/server/laf-cloud/functions/wx/payCallBack.ts
2026-08-07 10:59:22 +08:00

211 lines
7.1 KiB
TypeScript
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.

import cloud from '@lafjs/cloud';
import * as JungleConfigModule from "@/jungleConfig";
const JungleConfig: any = JungleConfigModule as any;
const db = cloud.database();
const ThinkingData = require('thinkingdata-node');
export default async function (ctx: FunctionContext) {
let data: any;
try {
data = JSON.parse(ctx.body?.MiniGame?.Payload || "");
} catch {
console.error("微信发货回调 Payload 解析失败");
return { "ErrCode": -1, "ErrMsg": "Invalid Payload" };
}
const outTradeNo = String(data.OutTradeNo || "");
const orderResult = await db.collection("order").where({ outTradeNo }).getOne();
const order = orderResult.data;
if (!order) {
console.error("微信发货回调未找到订单:" + outTradeNo);
return { "ErrCode": -1, "ErrMsg": "Order Not Found" };
}
const jungleTier = JungleConfig.getJunglePaidTierByProductId(order.itemid);
if (jungleTier) {
const callbackProductId = String(data.GoodsInfo?.ProductId || "");
const callbackQuantity = Number(data.GoodsInfo?.Quantity);
const callbackOriginalPrice = Number(data.GoodsInfo?.OrigPrice);
if ((data.OpenId && data.OpenId !== order.openid)
|| (callbackProductId && callbackProductId !== order.itemid)
|| (Number.isFinite(callbackQuantity) && callbackQuantity !== Number(order.itemCount))
|| (Number.isFinite(callbackOriginalPrice) && callbackOriginalPrice !== Number(order.goodsPrice))) {
console.error("Jungle 支付回调与订单信息不一致:" + outTradeNo);
return { "ErrCode": -1, "ErrMsg": "Order Mismatch" };
}
}
const userResult = await db.collection("users").where({ openid: order.openid }).getOne();
const user = userResult.data;
if (!user) {
console.error("微信发货回调未找到玩家:" + order.openid);
return { "ErrCode": -1, "ErrMsg": "User Not Found" };
}
const firstPaidCallback = order.state === 0;
if (order.state !== 2) {
await db.collection("order").where({ outTradeNo }).update({
state: 1,
chargeTime: new Date(Date.now() + 8 * 3600000),
});
}
const userUpdate: any = {};
let jungleUnlockedFromLocked = false;
if (jungleTier) {
const storedState = JungleConfig.normalizeStoredJungleState(user.jungleTreasureState);
const wasLocked = Number(storedState?.tierStates?.[jungleTier.id - 1]) === 0;
const unlockResult = JungleConfig.unlockJungleTierByProductId(
user.jungleTreasureState,
order.itemid,
outTradeNo,
);
if (unlockResult.ok && unlockResult.changed && unlockResult.state) {
userUpdate.jungleTreasureState = JungleConfig.serializeJungleState(unlockResult.state);
jungleUnlockedFromLocked = wasLocked
&& Number(unlockResult.state.tierStates?.[jungleTier.id - 1]) === 1;
}
}
if (order.itemid === "starter_pack") {
userUpdate.starter_packState = 1;
}
if (!user.pay_user) {
userUpdate.pay_user = true;
}
if (Object.keys(userUpdate).length > 0) {
await db.collection("users").where({ _id: user._id }).update(userUpdate);
}
if (firstPaidCallback) {
await sead(order, user, getClientIp(ctx));
}
if (jungleTier && jungleUnlockedFromLocked) {
await db.collection("order").where({ outTradeNo }).update({
state: 2,
getTime: new Date(Date.now() + 8 * 3600000),
});
}
// let query={
// signature: '1c1b5c1c72058436e2f1214e6aeafd258e50acd4',
// timestamp: '1751291889',
// nonce: '3122546041'
// }
/**
* ToUserName: 'gh_1092576a6ce7',
FromUserName: 'orm8I7IA-pMesygmTc5HPufGZHvA',
CreateTime: 1751292233,
MsgType: 'event',
MiniGame: {
Payload: '{"OpenId":"orm8I7BRTjhdQ3Mz9V9cg1jzTUcQ","OutTradeNo":"wcx_92778691620421751292218408","WeChatPayInfo":{"MchOrderNo":"20250630714915544","TransactionId":"4200002678202506307565098431"},"Env":0,"GoodsInfo":{"ProductId":"10011","Quantity":1,"ZoneId":"1","OrigPrice":100,"ActualPrice":100,"Attach":"购买道具","OrderSource":1},"PayChannel":0}',
PayEventSig: 'ecdaf472c239894706e28ab941d2aebf727b5bed45fe4073c645e922b6eefc1a',
IsMock: false
},
Event: 'minigame_game_pay_goods_deliver_notify'
*/
//return ctx.query.echostr;
return { "ErrCode": 0, "ErrMsg": "Success" };
}
async function sead1(outTradeNo) {
let res = await db.collection("order").where({ outTradeNo: outTradeNo }).getOne();
if (res.data.state == 1) {
return {
code: 1, data: {
pay_state: 2
}, msg: "成功"
};
} else if (res.data.state == 2) {
let userInfo = await db.collection("users").where({ openid: res.data.openid }).getOne();
await sead(outTradeNo, userInfo.data, "")
console.log("1");
return {
code: 1, data: {
pay_state: 1,
}, msg: "已领取奖励"
}
} else {
return {
code: 1, data: {
pay_state: 1,
}, msg: "充值未成功"
}
};
}
const getClientIp = (req) => {
return (
req.headers['x-forwarded-for']?.split(',')[0]?.trim() || // 代理链中的第一个 IP
req.headers['x-real-ip'] || // Nginx 配置的 real-ip
req.socket.remoteAddress // 原始 IP可能是代理
);
};
async function sead(order, userInfo, ip) {
db.collection("susu").add({
order: order,
time: Date.now()
});
if (!userInfo.distinctId) {
console.log("未找到distinctId无法上传数数")
return;
}
let id = '95993f9ab6f1402a87abe5147827e5e0';
if (userInfo.isDebug != "true") {
id = '40e3d5c5f2af49a4a074205564ce5dbb';
}
let teSDK = ThinkingData.initWithBatchMode(id, 'https://data.nika4fun.com/sync_data', {
dryRun: false, // report data to TE or not
deviceId: "123456789",//设备唯一标识
});
let trackEvent = {
accountId: order.openid,
distinctId: userInfo.distinctId,//访客id
event: 'payment',
time: new Date(Date.now() + 8 * 3600000),
ip: ip,
properties: {
order_id: order.outTradeNo,
pay_amount: order.goodsPrice,
payment_name: order.itemid,
payment_num: order.itemCount,
payment_type: order.type == "ios" ? "ios" : "Android",
is_on_table: Number(userInfo.addLevel) >= 5,
current_level: userInfo.levelAmount, //当前关卡等级 number
current_health: userInfo.healthAmount, //当前体力值
tmp_coin: userInfo.coinAmount,//当前金币
version: "1.6",
user_id: userInfo._id, //用户id
pay_user: userInfo.pay_user,
register_time: userInfo.register_time,
abTest_layer_one: getABTestGroupValue(userInfo.abTests, "layer_1"),
abTest_layer_two: getABTestGroupValue(userInfo.abTests, "layer_2"),
abTest_layer_three: getABTestGroupValue(userInfo.abTests, "layer_3")
},
callback(e) {
if (e) {
}
}
};
teSDK.track(trackEvent);
teSDK.close();
return;
}
function getABTestGroupValue(abTests: any, layerKey: string) {
if (!abTests) {
return 0;
}
if (typeof abTests === "string") {
try {
abTests = JSON.parse(abTests);
} catch {
return 0;
}
}
const groupMap = { A: 1, B: 2, C: 3, D: 4, E: 5 };
const group = String(abTests[layerKey]?.group || "").toUpperCase();
return groupMap[group] || 0;
}