init: hgmj server initial commit
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,463 @@
|
||||
package daichongser
|
||||
|
||||
import (
|
||||
"91jd-server/app/service/reportser"
|
||||
"91jd-server/models/v/advanceordermod"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
|
||||
"91jd-server/app/appg"
|
||||
"91jd-server/app/service"
|
||||
"91jd-server/app/service/rechargeser"
|
||||
"91jd-server/common/crypt"
|
||||
"91jd-server/common/daichong"
|
||||
"91jd-server/common/db"
|
||||
"91jd-server/common/log"
|
||||
"91jd-server/models/e/daichongmod"
|
||||
"91jd-server/models/v/goldcfgmod"
|
||||
"91jd-server/models/v/productmod"
|
||||
"91jd-server/models/v/rchgordmod"
|
||||
"91jd-server/models/v/txnmod"
|
||||
"91jd-server/models/v/usermod"
|
||||
"91jd-server/models/v/walletmod"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
const (
|
||||
rate_yinse_coin = 10 //金额转换成金币的单位 1元=10音色币
|
||||
rate_yuan_feng = 100 //将元转换为分
|
||||
)
|
||||
|
||||
func SeekScoreBaseOnAmount(customerId uint64, amount string) error {
|
||||
amt, err := strconv.Atoi(amount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
localAmount := covert2Amount(int64(amt), rate_yinse_coin)
|
||||
if err = appg.VideoDB.Trans(func(tool *db.MongoTool) error {
|
||||
//转换成本地项目中金币单位
|
||||
wallet, err := walletmod.DebitAmount(tool, localAmount, customerId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tl := txnmod.TransactionLog{
|
||||
TransNo: primitive.NewObjectID(),
|
||||
UID: customerId,
|
||||
Amount: -localAmount,
|
||||
ActualAmount: float64(-amt),
|
||||
TranType: txnmod.ChaseScore.Key(),
|
||||
TranTypeInt: int64(txnmod.ChaseScore),
|
||||
Desc: fmt.Sprintf("官方代充追分-%d", amt),
|
||||
RealAmount: walletmod.GetRealAmount(wallet),
|
||||
}
|
||||
return txnmod.InsertTransactionLog(tool, &tl)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandlerNewOrder 处理代充平台回掉调新订单通知
|
||||
func HandlerNewOrder(ctx context.Context, newOrderSign daichongmod.NewOrderSign, user usermod.User) (int, error) {
|
||||
log.Info("HandlerNewOrder start", log.Any("parameter", newOrderSign))
|
||||
//兼容时间为空的情况
|
||||
if newOrderSign.SuccessAt.IsZero() {
|
||||
newOrderSign.SuccessAt = time.Now()
|
||||
}
|
||||
//更新订单信息
|
||||
var rechargeType = string(rchgordmod.Rech_DaiChong)
|
||||
//转换成本地项目中金币单位
|
||||
localAmount := covert2Amount(newOrderSign.Amount, rate_yinse_coin)
|
||||
localMoney := covert2Amount(newOrderSign.Amount, rate_yuan_feng)
|
||||
upsert := rchgordmod.UpserSelector{
|
||||
UID: &user.UID,
|
||||
DevID: &user.DevID,
|
||||
DevType: &user.DevType,
|
||||
OID: &newOrderSign.OrderId,
|
||||
TraderId: &newOrderSign.FromId,
|
||||
Name: &user.Name,
|
||||
Tel: &user.Mobile,
|
||||
Amount: localAmount,
|
||||
NotifyTime: &newOrderSign.Time,
|
||||
PayMoney: &localMoney,
|
||||
Money: &localMoney,
|
||||
RechargeType: &rechargeType,
|
||||
Channel: &rechargeType,
|
||||
DiscDoc: user.DiscDoc,
|
||||
}
|
||||
processing := rchgordmod.Processing
|
||||
upsert.Status = &processing
|
||||
statusDesc := rchgordmod.Status(processing).Desc()
|
||||
upsert.StatusDesc = &statusDesc
|
||||
lock := rchgordmod.Lock
|
||||
upsert.LockStatus = &lock
|
||||
if _, err := rchgordmod.Upsert(nil, newOrderSign.OrderId, upsert); err != nil {
|
||||
log.ErrorX(ctx, "daichong order inset into local db failed", log.Any("param", newOrderSign), log.E(err))
|
||||
return daichong.Failed, err
|
||||
}
|
||||
order, err := rchgordmod.FindRechargeOrderByThirdOrderId(newOrderSign.OrderId)
|
||||
if err != nil {
|
||||
log.ErrorX(ctx, "daichong rechargeCoin FindRechargeOrderByThirdOrderId failed",
|
||||
log.Any("orderId", newOrderSign.OrderId), log.E(err))
|
||||
return daichong.Failed, err
|
||||
}
|
||||
var (
|
||||
fn func(t *db.MongoTool) error
|
||||
csm int // 分成模式
|
||||
vipExpireTime time.Time
|
||||
gold int64
|
||||
)
|
||||
// 商品信息解析
|
||||
res := selectProduct(newOrderSign.ProductInfo, user.SysType)
|
||||
switch res.Type {
|
||||
case Gold:
|
||||
// 新版充值金币
|
||||
if res.Version == newVersion {
|
||||
csm = rchgordmod.ChanShareCoin
|
||||
order.ProductID = res.ID
|
||||
if fn, gold, err = service.BuyGold(ctx, order, newOrderSign.Amount*100); err != nil {
|
||||
log.ErrorX(ctx, fmt.Sprintf("官方充值-订单号[%s] 购买金币异常[%v]", order.ID, err))
|
||||
}
|
||||
} else {
|
||||
err = rechargeCoin(ctx, localAmount, localMoney, user.SysType, newOrderSign.OrderId, newOrderSign.SuccessAt)
|
||||
}
|
||||
case VIP:
|
||||
// 新版购买会员卡
|
||||
if res.Version == newVersion {
|
||||
order.ProductID = res.ID
|
||||
if !res.Product.ID.IsZero() && res.Product.ProductType == productmod.AdvanceCard {
|
||||
err = handleAdvanceDCOrder(order, res.Product, user)
|
||||
if err != nil {
|
||||
log.ErrorX(ctx, fmt.Sprintf("官方充值-订单号[%s] 购买预售卡异常[%v]", order.ID, err))
|
||||
}
|
||||
}
|
||||
if fn, csm, vipExpireTime, err = service.BuyProduct(ctx, order, newOrderSign.Amount*100); err != nil {
|
||||
log.ErrorX(ctx, fmt.Sprintf("官方充值-订单号[%s] 购买商品异常[%v]", order.ID, err))
|
||||
}
|
||||
} else {
|
||||
log.Info("官方代充购买会员卡[旧版]")
|
||||
err = buyProduct(ctx, localAmount, newOrderSign.OrderId, res.Product)
|
||||
}
|
||||
case FruitCoin:
|
||||
order.ProductID = res.ID
|
||||
if fn, err = service.BuyFruitCoin(ctx, order, newOrderSign.Amount*100); err != nil {
|
||||
log.ErrorX(ctx, fmt.Sprintf("官方充值-订单号[%s] 购买果币异常[%v]", order.ID, err))
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
log.ErrorX(ctx, "HandlerNewOrder trans error", log.E(err), log.Any("orderId", newOrderSign.OrderId))
|
||||
selector := rchgordmod.ReplaceEditSelector{}
|
||||
failure := rchgordmod.FAILURE
|
||||
selector.Status = &failure
|
||||
statusDesc := rchgordmod.Status(failure).Desc()
|
||||
selector.StatusDesc = &statusDesc
|
||||
failureAt := time.Now()
|
||||
selector.FailureAt = &failureAt
|
||||
unlock := rchgordmod.UnLock
|
||||
selector.LockStatus = &unlock
|
||||
_ = rchgordmod.UpdateBaseOnOidAndStatus(nil, newOrderSign.OrderId, rchgordmod.Processing, selector)
|
||||
}
|
||||
if err = appg.VideoDB.Trans(func(t *db.MongoTool) error {
|
||||
selector := rchgordmod.ReplaceEditSelector{}
|
||||
if fn != nil && res.Version == newVersion {
|
||||
if err = fn(t); err != nil {
|
||||
log.ErrorX(ctx, "充值金币新版执行事务异常", log.Any("order id", order.ID), log.Any("uid", order.UID),
|
||||
log.E(err))
|
||||
return err
|
||||
}
|
||||
selector.ChanShareMod = &csm
|
||||
}
|
||||
success := rchgordmod.SUCCESS
|
||||
selector.Status = &success
|
||||
statusDesc := rchgordmod.Status(success).Desc()
|
||||
selector.StatusDesc = &statusDesc
|
||||
successAt := newOrderSign.SuccessAt
|
||||
selector.SuccessAt = &successAt
|
||||
unlock := rchgordmod.UnLock
|
||||
selector.LockStatus = &unlock
|
||||
selector.PaymentAt = &successAt
|
||||
selector.ProductID = res.ID
|
||||
selector.ServiceID = res.ServiceID
|
||||
//更新订单状态
|
||||
if err = rchgordmod.UpdateBaseOnOidAndStatus(t, newOrderSign.OrderId, rchgordmod.Processing, selector); err != nil {
|
||||
log.ErrorX(ctx, "HandlerNewOrder UpdateBaseOnOidAndStatus error", log.Any("orderId", newOrderSign.OrderId),
|
||||
log.E(err))
|
||||
return err
|
||||
}
|
||||
err = reportser.ReportOrderPaidEvent(t, order, newOrderSign.OrderId, localMoney, gold, vipExpireTime, newOrderSign.SuccessAt)
|
||||
if err != nil {
|
||||
log.ErrorX(ctx, "ReportOrderPaidEvent fail", log.E(err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.ErrorX(ctx, "HandlerNewOrder trans error", log.E(err), log.Any("orderId", newOrderSign.OrderId))
|
||||
err = reportser.ReportOrderPaidEvent(nil, order, newOrderSign.OrderId, localMoney, gold, vipExpireTime, newOrderSign.SuccessAt)
|
||||
if err != nil {
|
||||
log.ErrorX(ctx, "ReportOrderPaidEvent fail", log.E(err))
|
||||
return daichong.Failed, err
|
||||
}
|
||||
selector := rchgordmod.ReplaceEditSelector{}
|
||||
failure := rchgordmod.FAILURE
|
||||
selector.Status = &failure
|
||||
statusDesc := rchgordmod.Status(failure).Desc()
|
||||
selector.StatusDesc = &statusDesc
|
||||
failureAt := time.Now()
|
||||
selector.FailureAt = &failureAt
|
||||
unlock := rchgordmod.UnLock
|
||||
selector.LockStatus = &unlock
|
||||
err = rchgordmod.UpdateBaseOnOidAndStatus(nil, newOrderSign.OrderId, rchgordmod.Processing, selector)
|
||||
if err != nil {
|
||||
log.ErrorX(ctx, "UpdateBaseOnOidAndStatus failed", log.Any("order id", newOrderSign.OrderId), log.Any("selector", selector), log.E(err))
|
||||
}
|
||||
return daichong.Failed, err
|
||||
}
|
||||
//消息通知 充值到账成功
|
||||
log.InfoX(ctx, "HandlerNewOrder success")
|
||||
// common.Go(func() {
|
||||
// //代充扣量
|
||||
// executionDaiChongDeduction(ctx, newOrderSign.OrderId)
|
||||
// })
|
||||
|
||||
return daichong.Success, nil
|
||||
}
|
||||
|
||||
func handleAdvanceDCOrder(order rchgordmod.RechargeOrder, product productmod.Product, u usermod.User) error {
|
||||
data, err := advanceordermod.IsExist(bson.M{"productID": product.ID, "uid": u.UID})
|
||||
if err != nil {
|
||||
return errors.New("advance order query IsExist err")
|
||||
}
|
||||
// 预付订单
|
||||
var advanceOrder advanceordermod.AdvanceOrder
|
||||
var advanceStatus = advanceordermod.DEFAULT
|
||||
if order.PayMoney == product.AdvanceAmount*10 {
|
||||
advanceStatus = advanceordermod.AdvanceProcessing
|
||||
}
|
||||
if order.PayMoney == product.BalanceAmount*10 {
|
||||
advanceStatus = advanceordermod.BalanceProcessing
|
||||
}
|
||||
|
||||
if advanceStatus == advanceordermod.BalanceProcessing && (data == nil || data.ID.IsZero()) {
|
||||
return errors.New("advance order is null")
|
||||
}
|
||||
|
||||
if advanceStatus == advanceordermod.DEFAULT {
|
||||
return errors.New("advance order status is err")
|
||||
}
|
||||
|
||||
if data == nil || data.ID.IsZero() {
|
||||
// 创建预售订单
|
||||
now := time.Now()
|
||||
advanceOrder.UID = u.UID
|
||||
advanceOrder.CreatedAt = now
|
||||
advanceOrder.Status = advanceordermod.AdvanceProcessing
|
||||
advanceOrder.AdvanceAmount = product.AdvanceAmount * 10
|
||||
advanceOrder.BalanceAmount = product.BalanceAmount * 10
|
||||
advanceOrder.StartTime = product.StartTime
|
||||
advanceOrder.EndTime = product.EndTime
|
||||
advanceOrder.ProductID = product.ID
|
||||
advanceOrder.TotalAmount = (product.AdvanceAmount + product.BalanceAmount) * 10
|
||||
|
||||
advanceOrder.AdvOid = order.ID.Hex()
|
||||
_, err = advanceordermod.CreditOrder(nil, &advanceOrder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if (advanceStatus == advanceordermod.AdvanceProcessing && data.Status != advanceordermod.AdvanceProcessing) ||
|
||||
(advanceStatus == advanceordermod.BalanceProcessing && (data.Status != advanceordermod.BalanceProcessing &&
|
||||
data.Status != advanceordermod.AdvanceSUCCESS)) {
|
||||
return errors.New("advance order status is err")
|
||||
}
|
||||
if data.Status == advanceordermod.AdvanceProcessing {
|
||||
// 修改订单号
|
||||
err := advanceordermod.Update(nil, data.ID, bson.M{"advOid": order.ID.Hex()})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if data.Status == advanceordermod.BalanceProcessing || data.Status == advanceordermod.AdvanceSUCCESS {
|
||||
// 尾款订单
|
||||
err := advanceordermod.Update(nil, data.ID, bson.M{"status": advanceordermod.BalanceProcessing, "balOid": order.ID.Hex()})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 产品选择
|
||||
func selectProduct(productInfo string, sys string) (e ExtraInfo) {
|
||||
if productInfo == "" {
|
||||
return
|
||||
}
|
||||
if err := crypt.JSON2Struct(productInfo, &e); err != nil {
|
||||
log.Error(fmt.Sprintf("商品信息[%s]解析异常[%v]", productInfo, err))
|
||||
return
|
||||
}
|
||||
switch e.Type {
|
||||
case VIP:
|
||||
// 查询产品信息
|
||||
p, err := productmod.FindProduct(e.ID, sys)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("商品信息[%s]查询产品信息异常[%v]", productInfo, err))
|
||||
e.Type = Gold
|
||||
}
|
||||
e.Product = *p
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 根据商人回调过来的amount 转换本项目用户的分数
|
||||
// 商人的数量是10 单位为元 本地项目用户的金额 单位为角
|
||||
func covert2Amount(amount, rate int64) int64 {
|
||||
d1 := decimal.NewFromInt(amount)
|
||||
d2 := decimal.NewFromInt(rate)
|
||||
return d1.Mul(d2).IntPart()
|
||||
}
|
||||
|
||||
// 充值金币
|
||||
func rechargeCoin(ctx context.Context, localAmount, localMoney int64, sysType, orderId string, successAt time.Time) error {
|
||||
order, err := rchgordmod.FindRechargeOrderByThirdOrderId(orderId)
|
||||
if err != nil {
|
||||
log.Error("daichong rechargeCoin FindRechargeOrderByThirdOrderId failed", log.Any("orderId", orderId), log.E(err))
|
||||
return err
|
||||
}
|
||||
csm := rchgordmod.ChanShareCoin
|
||||
err = appg.VideoDB.Trans(func(trans *db.MongoTool) error {
|
||||
//查询金币优惠
|
||||
disCount, err := goldcfgmod.GetGoldCgfByAmountAndType(ctx, localAmount, string(rchgordmod.Rech_DaiChong))
|
||||
if disCount != nil && err == nil {
|
||||
if disCount.IncrAmount != 0 {
|
||||
localAmount = localAmount + disCount.IncrAmount
|
||||
} else if disCount.IncTax != 0.0 {
|
||||
incr := decimal.NewFromFloat(disCount.IncTax)
|
||||
local := decimal.NewFromInt(localAmount)
|
||||
localAmount = localAmount + local.Mul(incr).IntPart()
|
||||
}
|
||||
}
|
||||
//用户增加货币
|
||||
wallet, err := walletmod.Credit(trans, walletmod.CreditPlan{Amount: &localAmount, Consumption: &localMoney}, order.UID)
|
||||
if err != nil {
|
||||
log.Error("HandlerNewOrder CreditAmount error", log.E(err), log.Any("orderId", order.OID))
|
||||
return err
|
||||
}
|
||||
selector := rchgordmod.ReplaceEditSelector{}
|
||||
success := rchgordmod.SUCCESS
|
||||
selector.Status = &success
|
||||
selector.ChanShareMod = &csm
|
||||
statusDesc := rchgordmod.Status(success).Desc()
|
||||
selector.StatusDesc = &statusDesc
|
||||
selector.SuccessAt = &successAt
|
||||
unlock := rchgordmod.UnLock
|
||||
selector.LockStatus = &unlock
|
||||
selector.PaymentAt = &successAt
|
||||
//更新订单状态
|
||||
if err = rchgordmod.UpdateBaseOnOidAndStatus(trans, order.OID, rchgordmod.Processing, selector); err != nil {
|
||||
log.Error("HandlerNewOrder UpdateBaseOnOidAndStatus error", log.E(err), log.Any("orderId", order.OID))
|
||||
return err
|
||||
}
|
||||
tl := txnmod.TransactionLog{
|
||||
TransNo: order.ID,
|
||||
UID: order.UID,
|
||||
Amount: localAmount,
|
||||
ActualAmount: float64(localAmount),
|
||||
TranType: txnmod.OfficialRech.Key(),
|
||||
TranTypeInt: int64(txnmod.OfficialRech),
|
||||
Desc: txnmod.OfficialRech.Key() + "-" + fmt.Sprintf("到账%d金币", localAmount),
|
||||
SysType: sysType,
|
||||
RealAmount: walletmod.GetRealAmount(wallet),
|
||||
}
|
||||
if err = txnmod.InsertTransactionLog(trans, &tl); err != nil {
|
||||
log.Error("HandlerNewOrder InsertTransactionLog error", log.E(err), log.Any("orderId", order.ID))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// 购买会员卡
|
||||
func buyProduct(ctx context.Context, localAmount int64, orderId string, p productmod.Product) error {
|
||||
order, err := rchgordmod.FindRechargeOrderByThirdOrderId(orderId)
|
||||
if err != nil {
|
||||
log.Error("daichong buyProduct FindRechargeOrderByThirdOrderId failed", log.Any("orderId", orderId), log.E(err))
|
||||
return err
|
||||
}
|
||||
disCount, err := goldcfgmod.GetGoldCgfByAmountAndType(ctx, localAmount, string(rchgordmod.Rech_DaiChong))
|
||||
if disCount != nil && err == nil {
|
||||
if disCount.IncrAmount != 0 {
|
||||
localAmount = localAmount + disCount.IncrAmount
|
||||
} else if disCount.IncTax != 0.0 {
|
||||
incr := decimal.NewFromFloat(disCount.IncTax)
|
||||
local := decimal.NewFromInt(localAmount)
|
||||
localAmount = localAmount + local.Mul(incr).IntPart()
|
||||
}
|
||||
}
|
||||
disMoney := localAmount - p.DiscountedPrice
|
||||
if disMoney < -10 {
|
||||
tdesc := "购买「" + p.Name + "」实际支付" + strconv.Itoa(int(localAmount)) + ",全额转为「" + strconv.Itoa(int(localAmount)) + "」金币"
|
||||
return appg.VideoDB.Trans(func(t *db.MongoTool) error {
|
||||
set := rchgordmod.EditSelector{}
|
||||
csm := rchgordmod.ChanShareCoin
|
||||
set.ChanShareMod = &csm
|
||||
now := time.Now()
|
||||
set.SuccessAt = &now
|
||||
set.Status = rchgordmod.SUCCESS
|
||||
desc := rchgordmod.Status(rchgordmod.SUCCESS).Desc()
|
||||
set.StatusDesc = &desc
|
||||
set.PaymentAt = &now
|
||||
if err = rchgordmod.CallBackModifyWithProcessing(ctx, t, order.ID, set); err != nil {
|
||||
return err
|
||||
}
|
||||
return rechargeser.CallbackAddCoins(ctx, t, localAmount, localAmount, tdesc, order)
|
||||
})
|
||||
}
|
||||
cms := 0
|
||||
if p.ChanSplitMod == 1 {
|
||||
cms = rchgordmod.ChanShareModVIP
|
||||
}
|
||||
return appg.VideoDB.Trans(func(t *db.MongoTool) error {
|
||||
selector := rchgordmod.ReplaceEditSelector{}
|
||||
selector.ChanShareMod = &cms
|
||||
success := rchgordmod.SUCCESS
|
||||
selector.Status = &success
|
||||
statusDesc := rchgordmod.Status(success).Desc()
|
||||
selector.StatusDesc = &statusDesc
|
||||
successAt := time.Now()
|
||||
selector.SuccessAt = &successAt
|
||||
selector.VipID = p.ID
|
||||
unlock := rchgordmod.UnLock
|
||||
selector.LockStatus = &unlock
|
||||
selector.PaymentAt = &successAt
|
||||
if err = rchgordmod.UpdateBaseOnOidAndStatus(t, order.OID, rchgordmod.Processing, selector); err != nil {
|
||||
return err
|
||||
}
|
||||
creditPlan := walletmod.CreditPlan{
|
||||
Consumption: &localAmount,
|
||||
}
|
||||
if _, err = walletmod.Credit(t, creditPlan, order.UID); err != nil {
|
||||
return err
|
||||
}
|
||||
fPayMoney := float32(localAmount)
|
||||
if disMoney > 0 {
|
||||
tdesc := "购买「" + p.Name + "」实际支付" + strconv.FormatFloat(float64(fPayMoney), 'f', 2, 64) + ",超额部分转为「" + strconv.FormatInt(disMoney, 10) + "」金币"
|
||||
if err = rechargeser.CallbackAddCoins(ctx, t, disMoney, 0, tdesc, order); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err = rechargeser.RechargeBuy_p(t, order.UID, p, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user