HJ_Server/src/public/pay.ts
2023-12-14 17:01:39 +08:00

477 lines
18 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 {ApiCall} from 'tsrpc';
import {YangChengMuBiaofun} from '../api_s2c/event/yangchengmubiao/fun';
import {MsgPayChange} from '../shared/protocols/msg_s2c/MsgPayChange';
import {payLog} from '../shared/protocols/pay/PtlGetList';
import {player} from '../shared/protocols/user/type';
import {PublicShared} from '../shared/public/public';
import {EmailFun} from './email';
import {HuoDongFun} from './huodongfun';
import {call, PlayerFun} from './player';
import {number} from "mathjs";
import {getGud} from './gud';
import {getConf as zmlbGetConf} from '../api_s2c/event/zhoumolibao/ApiOpen';
async function checkPayIsActive(payId: string, logs: payLog[], payArgs) {
let conf: any = await this.getConf(payId, payArgs);
if (!conf) return false;
let lastLog = logs.last();
if (!lastLog) return false;
if (conf.time == -1) return true;
return G.time < lastLog.eTime;
}
export class PayFun {
static async addPayLog(uid: string, payId: string, type: "system" | "user" | "legu", payArgs) {
let conf: any = await this.getConf(payId, payArgs);
let time = PublicShared.getToDayZeroTime(G.time);
let obj: payLog = {time: G.time, type: type};
if (conf.time != -1) obj.eTime = time + conf.time;
if (payId == 'G123SendGift') {
obj.popup_id = payArgs.popup_id
obj.template_id = payArgs.template_id
obj.buyNumber = conf.buyNumber
}
let result = await G.mongodb.collection('payLogNew').findOneAndUpdate(
{uid: uid, key: payId, del_time: {$exists: false}},
{$push: {values: obj}},
{upsert: true, returnDocument: 'after'}
);
let msg: MsgPayChange = {[payId]: result.value?.values || []};
if (payId == 'G123SendGift') {
G.server.sendMsgByUid(uid, 'msg_s2c/PayChange', R.groupBy(i => i.popup_id)(result.value?.values));
} else {
G.server.sendMsgByUid(uid, 'msg_s2c/PayChange', msg);
}
}
static changeG123GiftLog(uid: string, popupId: string) {
G.mongodb.collection('giftLog').updateOne({popup_id: popupId}, {$inc: {buyNumber: 1}}, {upsert: true});
}
static async delPayLog(uid: string, ...args: { payId: string, val: payLog[]; }[]) {
args.map(a => {
G.mongodb.collection('payLogNew').updateOne(
{uid: uid, key: a.payId, del_time: {$exists: false}},
{$set: {del_time: G.time}},
{upsert: true}
);
})
G.mongodb.collection('payLogNew').insertMany(args.map(i => ({key: i.payId, uid: uid, values: i.val})));
G.server.sendMsgByUid(uid, 'msg_s2c/PayChange', Object.fromEntries(args.map(a => [a.payId, a.val])));
}
static async getPayLog(uid: string, payId: string): Promise<payLog[]>;
static async getPayLog(uid: string, payId: string) {
// let allPlayerPayLog = await G.redis.hGet('player:payLog', uid)
let val = await G.mongodb.collection("payLogNew").findOne({uid: uid, key: payId, del_time: {$exists: false}}, {
projection: {
_id: 0,
uid: 0
}
});
let allPlayerPayLog = {[payId]: val?.values || []}
return allPlayerPayLog?.[payId] || [];
}
static async getPayLogs(uid: string, payIds?: string[]) {
let where = {
uid: uid,
del_time: {$exists: false}
}
if (payIds?.length) where['key'] = {$in: payIds}
let logs = await G.mongodb.collection("payLogNew").find(where, {
projection: {
_id: 0,
uid: 0
}
}).toArray();
if (payIds?.length) {
return Object.fromEntries(payIds.map(id => [id, logs[id] || []]));
}
let allLogs = {}
logs.map(i => allLogs[i.key] = i.values)
return allLogs
}
/**
* 获取支付配置主要是针对G123礼包、GM后台内部充值的特殊处理
* 让这两个不在预设充值挡位内的,可以正常发奖
* @param payId
* @param payArgs
*/
static async getConf(payId, payArgs) {
let conf: any = G.gc.pay[payId]
if (payId == 'G123SendGift') {
let giftInfo = await G.mongodb.collection('giftLog').findOne({popup_id: payArgs.popup_id});
let gPrize = giftInfo.items
let bPrize = []
for (let index in gPrize) {
let args = index.split('^')
bPrize.push({a: args[0], t: args[1], n: gPrize[index]})
}
conf = {
id: 'G123SendGift',
money: giftInfo.price,
payExp: [{"a": "attr", "t": "payExp", "n": giftInfo.vipPoints}],
prize: bPrize,
firstPayPrize: [],
name: 'G123SendGift',
time: -1,
buys: giftInfo.purchaseLimitAmount,
needVip: 0,
front: {},
buyNumber: giftInfo.buyNumber
}
} else if (payId == 'LeguSendGift') {
conf = {
id: 'LeguSendGift',
money: payArgs.money,
payExp: payArgs.payExp,
prize: payArgs.prize,
firstPayPrize: [],
name: 'LeguSendGift',
time: -1,
buys: 0,
needVip: 0,
front: {}
}
}
return conf
}
/**
* 实际作用是支付后发奖
* 针对G123礼包有特殊处理不在游戏配置内预设的充值挡位
* todo 目前还缺验证通道,内部充值可以直接调用
* @param uid
* @param payId
* @param payArgs
* @param type
* @param orderNo
*/
static async pay(uid: string, payId: string, payArgs?: any, type?: "system" | "user" | "legu", orderNo: string = '') {
if (orderNo) {
//判断订单号是否已经支付过
let payed = await G.mongodb.collection('payOrderLog' as any).count({"orderNo": orderNo});
if (payed) {
console.log(uid, payId, payArgs, orderNo);
console.log('订单号已存在');
}
}
let conf: any = await this.getConf(payId, payArgs);
let isReplaceConf = await this.checkBuysAfterPay(uid, payId, conf, payArgs)
if (isReplaceConf) {
let prizePayId = `zuanshi_${conf.money}`
payArgs.toPrizePayId = prizePayId
conf = this.replacePrizeToChongzhi(prizePayId, conf)
}
let prize = [...conf.prize];
//let player = await G.redis.get('user', uid);
let player = await getGud(uid);
if (conf.firstPayPrize.length > 0) {
let logs = await this.getPayLog(uid, payId);
if (!logs || logs.length < 1) {
prize = PublicShared.mergePrize([].concat(conf.prize, conf.firstPayPrize));
}
}
let call = this.getCall(player);
call.req = {
uid: uid,
payId: payId,
payArgs: payArgs,
orderNo: orderNo
}
if (payId.indexOf('zixuanlibao') != -1) {
// 后端唯一标识 htype 4 自选/定制 礼包
// @ts-ignore
let _hdList = await HuoDongFun.gethdList(call, 4)
_hdList.forEach(ele => {
let selectPrize = ele.data.gift.find(v => v.payId == payId)?.prize;
if (prize) {
let index = payArgs instanceof Array ? payArgs : [];
let select = selectPrize.map((v, i) => v[index[i]] ? v[index[i]] : v[0]);
prize.push(...select);
}
})
}
if (payId.indexOf('ycmb') != -1) {
// @ts-ignore // 养成活动充值礼包
let _hdids = await YangChengMuBiaofun.getCon(call);
Object.values(_hdids).forEach(ele => {
let selectPrize = ele.data.gift.find(v => v.payId == payId)?.prize;
if (selectPrize) {
prize.push(...selectPrize);
}
});
}
await PlayerFun.sendPrize(call, prize);
await PlayerFun.addAttr(call, conf.payExp);
if (payId == 'G123SendGift') {
this.changeG123GiftLog(uid, payArgs.popup_id)
}
await this.addPayLog(player.uid, payId, type, payArgs);
// this.addPayLogNew(player.uid, payId, type);
//记录支付信息log
if (orderNo) {
await G.mongodb.collection('payOrderLog' as any).insertOne({
"orderNo": orderNo,
"payId": payId,
"uid": uid,
"payArgs": payArgs,
"type": type,
"ctime": new Date().getTime()
});
}
G.server.sendMsgByUid(uid, 'msg_s2c/Collection', {
fromApi: `pay_${payId}`,
msg: call.eventMsg
});
G.server.sendMsgByUid(uid, 'msg_s2c/PayResult', {
code: 1,
data: {
id: payId,
prize: prize,
price: payArgs?.price
}
});
G.emit('PLAYER_PAY', player, payId, payArgs);
G.emit("Class_task_116", 'Class_task_116', call, 1, 0);
}
/**
* 转换订单奖励成直冲钻石奖励
* @param payId
* @param conf
*/
static async replacePrizeToChongzhi(payId, conf) {
return {
id: payId,
money: conf.money,
payExp: [
{
"a": "attr",
"t": "payExp",
"n": conf.money * 10
}
],
prize: [
{
"a": "attr",
"t": "rmbmoney",
"n": conf.money * 10
}
],
firstPayPrize: [],
name: `replacePrize`,
time: -1,
buys: 0,
needVip: 0,
front: {}
}
}
/**
* 支付成功后,某些情况下会有超出限购次数的限购订单
* 这种情况需检查返回true是需要转换成钻石的订单
* @param uid
* @param payId
* @param conf
* @param payArgs
*/
static async checkBuysAfterPay(uid, payId, conf, payArgs) {
if (payId == 'G123SendGift') {
let giftInfo = await G.mongodb.collection('giftLog').findOne({popup_id: payArgs.popup_id});
if (giftInfo.purchaseLimitAmount && giftInfo.buyNumber >= giftInfo.purchaseLimitAmount && number(giftInfo.price) > 0) {
return true
}
} else {
let buyLog = await this.getPayLog(uid, payId) || [];
if (conf.buys > 0 && conf.time > 0) {
buyLog = buyLog.filter(v => v.time >= PublicShared.getToDayZeroTime(G.time));
}
if (conf.buys > 0 && buyLog.length >= conf.buys) return true;
}
return false
}
/**
* 拉起订单前检查购买前置条件,如符合,通知前端拉起支付
* 针对G123礼包有特殊处理不在游戏配置内预设的充值挡位
* todo 目前没有订单锁,所以会造成限购商品可以二次拉起支付
* @param player
* @param payId
* @param payArgs
*/
static async check(player: player, payId: string, payArgs?: any) {
let conf: any = await this.getConf(payId, payArgs);
if (!conf) return G.server.sendMsgByUid(player.uid, 'msg_s2c/PayResult', {code: 0});
if (player.vip < conf.needVip) return G.server.sendMsgByUid(player.uid, 'msg_s2c/PayResult', {code: -3});
if (conf.front.cond) {
let pays = await this.getPayLogs(player.uid, conf.front.pays);
//@ts-ignore
let actives = Object.entries(pays).map(v => checkPayIsActive(v[0], v[1], payArgs)).filter(v => v);
if (conf.front.cond == '|' && actives.length < 1) return G.server.sendMsgByUid(player.uid, 'msg_s2c/PayResult', {code: -4});
if (conf.front.cond == '&' && actives.length < conf.front.pays.length) return G.server.sendMsgByUid(player.uid, 'msg_s2c/PayResult', {code: -4});
}
if (payId == 'G123SendGift') {
let giftInfo = await G.mongodb.collection('giftLog').findOne({popup_id: payArgs.popup_id});
if (giftInfo.purchaseLimitAmount && giftInfo.buyNumber >= giftInfo.purchaseLimitAmount) {
return G.server.sendMsgByUid(player.uid, 'msg_s2c/PayResult', {code: -1});
}
if (number(giftInfo.price) <= 0) {
await this.pay(player.uid, payId, payArgs, 'user');
return
}
} else {
let buyLog = await this.getPayLog(player.uid, payId) || [];
if (conf.buys > 0 && conf.time > 0) {
buyLog = buyLog.filter(v => v.time >= PublicShared.getToDayZeroTime(G.time));
}
if (conf.buys > 0 && buyLog.length >= conf.buys) return G.server.sendMsgByUid(player.uid, 'msg_s2c/PayResult', {code: -1});
if (conf.time != -1 && buyLog.slice(-1)[0]?.eTime > G.time && conf.buys == 0) return G.server.sendMsgByUid(player.uid, 'msg_s2c/PayResult', {code: -2});
if (payId.indexOf('136Gift') != -1 && payId != '136Gift1') {
buyLog = await this.getPayLog(player.uid, '136Gift1');
if (buyLog.slice(-1)[0]?.eTime > G.time) return G.server.sendMsgByUid(player.uid, 'msg_s2c/PayResult', {code: -3});
}
if (payId.indexOf('wkdlibao') != -1) {
let call = this.getCall(player)
let conf = await zmlbGetConf(call, {payId})
buyLog = await this.getPayLog(player.uid, payId);
if (buyLog.length && buyLog.length >= conf.buyNum) return G.server.sendMsgByUid(player.uid, 'msg_s2c/PayResult', {code: -1});
}
}
if (G.config.debug) {
await this.pay(player.uid, payId, payArgs, 'user', "debuger_" + new Date().getTime());
} else {
G.server.sendMsgByUid(player.uid, 'msg_s2c/PayResult', {code: 200});
}
}
static getCall(player: player): call {
return {
get otherBuff() {
return this.conn.otherBuff;
},
uid: player.uid,
conn: G.server.uid_connections[player.uid] ? G.server.uid_connections[player.uid] : {
id: null,
uid: player.uid,
gud: player,
item: null,
otherBuff: null,
heroPos: null,
refreshPower: null,
sendMsg: null,
},
service: {name: "pay"},
req: {},
eventMsg: null,
addEventMsg() {
return ApiCall.prototype.addEventMsg.call(this, ...arguments);
}
};
}
/**
* 当玩家购买过有时间期效性的礼包 并且在生效期内每天有邮件奖励时 每天首次登陆时根据时间补发邮件 玩家每天首次登陆会进入检查
* @param lastTime 上一次登陆时间
* @param curTime 每日首次登陆时间
*/
static async checkGiftDayEmail(player: player, lastTime: number, curTime: number) {
const buyLogs = await this.getPayLogs(player.uid);
const keys = Object.keys(buyLogs).filter(payId => G.gc.payEmail[payId]?.length > 0);
const curZeroTime = PublicShared.getToDayZeroTime(curTime);
const lastZeroTime = PublicShared.getToDayZeroTime(lastTime);
keys.forEach(payId => {
let payEmailConf = G.gc.payEmail[payId] as _gcType['payEmail']['caifutequan'];
let latelyLog = buyLogs[payId].slice(-1)[0];
if (!latelyLog || (latelyLog.eTime && lastZeroTime >= latelyLog.eTime)) return;
let countDay = 1;
let payZeroTime = PublicShared.getToDayZeroTime(latelyLog.time);
let payZeroEtime = PublicShared.getToDayZeroTime(latelyLog.eTime);
let days: number
if (curZeroTime > payZeroEtime) {
days = (payZeroEtime - lastZeroTime) / (24 * 3600);
} else {
days = (curZeroTime - lastZeroTime) / (24 * 3600);
}
for (let n = 1; n <= days; n++) {
countDay++;
// if (payZeroTime + n * 24 * 3600 <= payZeroEtime) continue;
payEmailConf.forEach(conf => {
if (conf.day == 1 || countDay % conf.day == 0) {
EmailFun.addEmail({
uid: player.uid,
type: 'system',
title: conf.title,
content: conf.content,
prize: conf.prize,
createTime: lastZeroTime + n * 24 * 3600
});
}
});
}
});
}
/**
* 获取某个时间段内 玩家充值x元以上的天数
*/
static async getPayDaysBuyPayNum(uid: string, sTime: number, eTime: number, ckeckNeed: number) {
let logs = await G.mongodb.collection('dayPay').find({uid: uid}).toArray() || [];
return logs.filter(log => log.time >= sTime && log.time <= eTime && log.payNum >= ckeckNeed).length;
}
/**
* 获取某个时间段内 玩家的充值总金额
*/
static async getPayDaysAllPayNum(uid: string, sTime: number, eTime: number) {
let logs = await G.mongodb.collection('dayPay').find({uid: uid}).toArray() || [];
logs = logs.filter(log => log.time >= sTime && log.time < eTime);
if (logs.length <= 0) return 0;
return logs.map(log => log.payNum).reduce((a, b) => a + b);
}
}