init: web_hgdjc_server
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"videoweb/pub/common/log"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/common/utils"
|
||||
"videoweb/pub/models/cointransmod"
|
||||
"videoweb/pub/models/usermod"
|
||||
"videoweb/pub/mongos"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
// WriteCoinTransOpt 写流水所需参数
|
||||
type WriteCoinTransOpt struct {
|
||||
UserId int64
|
||||
UserName string // 可为空,自动查询
|
||||
FlowDir cointransmod.FlowDir // FlowIn / FlowOut
|
||||
TranType cointransmod.TranType // 交易类型
|
||||
Amount int64 // 本次交易金币数(正整数)
|
||||
OrderNo string // 关联订单号(可为空)
|
||||
RelatedId int64 // 关联内容ID(可为空)
|
||||
Remark string // 备注
|
||||
}
|
||||
|
||||
// WriteCoinTrans 写一条金币流水记录
|
||||
// balanceBefore 和 balanceAfter 从用户当前余额自动推算:
|
||||
// - 若传入 balanceAfter(>= 0),直接使用;
|
||||
// - 否则查库获取用户当前余额作为 balanceAfter,再反推 balanceBefore。
|
||||
func WriteCoinTrans(ctx context.Context, opt WriteCoinTransOpt, balanceAfter int64) *srvdef.SrvErr {
|
||||
userName := opt.UserName
|
||||
if userName == "" {
|
||||
if u, _ := usermod.FindOneUser(ctx, bson.M{usermod.FN.User.Id: opt.UserId}); u != nil {
|
||||
userName = u.NickName
|
||||
}
|
||||
}
|
||||
|
||||
var balanceBefore int64
|
||||
if opt.FlowDir == cointransmod.FlowIn {
|
||||
balanceBefore = balanceAfter - opt.Amount
|
||||
} else {
|
||||
balanceBefore = balanceAfter + opt.Amount
|
||||
}
|
||||
if balanceBefore < 0 {
|
||||
balanceBefore = 0
|
||||
}
|
||||
|
||||
remark := opt.Remark
|
||||
if remark == "" {
|
||||
remark = opt.TranType.Desc()
|
||||
}
|
||||
|
||||
doc := &cointransmod.CoinTrans{
|
||||
Id: mongos.Lid.CoinTrans.Get(),
|
||||
UserId: opt.UserId,
|
||||
UserName: userName,
|
||||
FlowDir: opt.FlowDir,
|
||||
TranType: opt.TranType,
|
||||
Amount: opt.Amount,
|
||||
BalanceBefore: balanceBefore,
|
||||
BalanceAfter: balanceAfter,
|
||||
OrderNo: opt.OrderNo,
|
||||
RelatedId: opt.RelatedId,
|
||||
Remark: remark,
|
||||
CreatedAt: utils.Now(),
|
||||
}
|
||||
if serr := cointransmod.InsertOneCoinTrans(ctx, doc); serr != nil {
|
||||
log.Error("WriteCoinTrans InsertOneCoinTrans failed",
|
||||
log.Any("userId", opt.UserId), log.Any("tranType", opt.TranType), log.E(serr))
|
||||
return serr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteCoinTransByUser 查询用户当前余额后自动写流水(适合已更新余额后调用)
|
||||
func WriteCoinTransByUser(ctx context.Context, opt WriteCoinTransOpt) *srvdef.SrvErr {
|
||||
u, serr := usermod.FindOneUser(ctx, bson.M{usermod.FN.User.Id: opt.UserId})
|
||||
if serr != nil || u == nil {
|
||||
return srvdef.New(srvdef.ErrNoData, "用户不存在", "")
|
||||
}
|
||||
if opt.UserName == "" {
|
||||
opt.UserName = u.NickName
|
||||
}
|
||||
return WriteCoinTrans(ctx, opt, u.Recharge)
|
||||
}
|
||||
|
||||
// CoinTransRemark 生成标准备注
|
||||
func CoinTransRemark(tranType cointransmod.TranType, extra string) string {
|
||||
name := tranType.Desc()
|
||||
if extra != "" {
|
||||
return fmt.Sprintf("%s:%s", name, extra)
|
||||
}
|
||||
return name
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
"videoweb/pub/common/log"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/rechargepackagemod"
|
||||
"videoweb/pub/models/usermod"
|
||||
"videoweb/pub/pubdef"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
// ActivateVip 支付成功后为用户开通/续期会员。
|
||||
// 若用户已有未过期会员,则从当前到期时间向后顺延;否则从当前时刻起算。
|
||||
// 同时将赠送金币(pkg.GiftCoin)计入用户余额。
|
||||
func ActivateVip(ctx context.Context, userId int64, pkg *rechargepackagemod.RechargePackage) (time.Time, *srvdef.SrvErr) {
|
||||
if pkg == nil {
|
||||
return time.Time{}, srvdef.New(srvdef.ErrParamError, "会员套餐不能为空", "")
|
||||
}
|
||||
user, serr := usermod.FindOneUser(ctx, bson.M{usermod.FN.User.Id: userId})
|
||||
if serr != nil {
|
||||
log.Error("payment:ActivateVip FindOneUser failed", log.Any("userId", userId), log.E(serr))
|
||||
return time.Time{}, serr
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
duration := time.Duration(pkg.DurationDays) * 24 * time.Hour
|
||||
vipType := vipTypeFromDurationDays(pkg.DurationDays)
|
||||
|
||||
baseTime := now
|
||||
if user.CurrentVipExpire.After(now) {
|
||||
baseTime = user.CurrentVipExpire
|
||||
}
|
||||
newExpire := baseTime.Add(duration)
|
||||
|
||||
setDoc := bson.M{
|
||||
usermod.FN.User.VipType: vipType,
|
||||
usermod.FN.User.CurrentVipExpire: newExpire,
|
||||
usermod.FN.User.ShowCardId: pkg.Id,
|
||||
usermod.FN.User.ShowCardName: pkg.Name,
|
||||
usermod.FN.User.UpdatedAt: now,
|
||||
}
|
||||
updateDoc := bson.M{"$set": setDoc}
|
||||
if pkg.GiftCoin > 0 {
|
||||
updateDoc["$inc"] = bson.M{usermod.FN.User.Recharge: pkg.GiftCoin}
|
||||
}
|
||||
|
||||
if serr = usermod.UpdateOneUser(ctx, bson.M{usermod.FN.User.Id: userId}, updateDoc); serr != nil {
|
||||
log.Error("payment:ActivateVip UpdateOneUser failed",
|
||||
log.Any("userId", userId), log.Any("packageId", pkg.Id), log.E(serr))
|
||||
return time.Time{}, serr
|
||||
}
|
||||
|
||||
log.Info("payment:ActivateVip success",
|
||||
log.Any("userId", userId),
|
||||
log.Any("packageId", pkg.Id),
|
||||
log.Any("vipType", vipType),
|
||||
log.Any("newExpire", newExpire),
|
||||
)
|
||||
return newExpire, nil
|
||||
}
|
||||
|
||||
func vipTypeFromDurationDays(days int64) pubdef.VipType {
|
||||
if days >= 365 {
|
||||
return pubdef.VipTypeYear
|
||||
}
|
||||
if days > 0 {
|
||||
return pubdef.VipTypeMonth
|
||||
}
|
||||
return pubdef.VipTypeNone
|
||||
}
|
||||
Reference in New Issue
Block a user