f
This commit is contained in:
@@ -36,6 +36,9 @@ func (l *AdminGetAgentRewardListLogic) AdminGetAgentRewardList(req *types.AdminG
|
||||
if req.Type != nil && *req.Type != "" {
|
||||
builder = builder.Where(squirrel.Eq{"type": *req.Type})
|
||||
}
|
||||
if req.Status != nil {
|
||||
builder = builder.Where(squirrel.Eq{"status": *req.Status})
|
||||
}
|
||||
list, total, err := l.svcCtx.AgentRewardsModel.FindPageListByPageWithTotal(l.ctx, builder, req.Page, req.PageSize, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -25,7 +25,7 @@ func NewAdminGetSystemConfigLogic(ctx context.Context, svcCtx *svc.ServiceContex
|
||||
|
||||
func (l *AdminGetSystemConfigLogic) AdminGetSystemConfig() (resp *types.AdminGetSystemConfigResp, err error) {
|
||||
resp = &types.AdminGetSystemConfigResp{
|
||||
CommissionSafeMode: l.svcCtx.Config.SystemConfig.CommissionSafeMode,
|
||||
CommissionSafeMode: l.svcCtx.AgentConfigModel.IsCommissionSafeMode(l.ctx),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -24,9 +24,11 @@ func NewAdminUpdateSystemConfigLogic(ctx context.Context, svcCtx *svc.ServiceCon
|
||||
}
|
||||
|
||||
func (l *AdminUpdateSystemConfigLogic) AdminUpdateSystemConfig(req *types.AdminUpdateSystemConfigReq) (resp *types.AdminUpdateSystemConfigResp, err error) {
|
||||
// 更新佣金安全防御模式配置
|
||||
if req.CommissionSafeMode != nil {
|
||||
l.svcCtx.Config.SystemConfig.CommissionSafeMode = *req.CommissionSafeMode
|
||||
if err := l.svcCtx.AgentConfigModel.SetCommissionSafeMode(l.ctx, *req.CommissionSafeMode); err != nil {
|
||||
logx.Errorf("更新佣金安全防御模式失败: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
logx.Infof("更新系统配置:佣金安全防御模式设置为 %v", *req.CommissionSafeMode)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
paylogic "bdrp-server/app/main/api/internal/logic/pay"
|
||||
"bdrp-server/app/main/api/internal/svc"
|
||||
"bdrp-server/app/main/api/internal/types"
|
||||
"bdrp-server/app/main/model"
|
||||
@@ -93,8 +92,8 @@ func (l *AdminRefundOrderLogic) handleAlipayRefund(order *model.Order, req *type
|
||||
}
|
||||
|
||||
// 退款成功后,按本次退款金额更新代理佣金状态并扣除钱包金额
|
||||
// 注意:refundAmount 为本次实际退款金额,可以是部分退款
|
||||
_ = paylogic.HandleCommissionAndWalletDeduction(l.ctx, l.svcCtx, nil, order, req.RefundAmount)
|
||||
// 使用 AgentService 中的共用退款扣款逻辑
|
||||
l.svcCtx.AgentService.HandleOrderRefundDeduction(l.ctx, nil, order, req.RefundAmount)
|
||||
|
||||
return &types.AdminRefundOrderResp{
|
||||
Status: model.OrderStatusRefunded,
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"bdrp-server/app/main/api/internal/service"
|
||||
"bdrp-server/app/main/model"
|
||||
"bdrp-server/common/ctxdata"
|
||||
"bdrp-server/common/xerr"
|
||||
"bdrp-server/pkg/lzkit/lzUtils"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
@@ -40,6 +42,9 @@ func (l *GetAgentMembershipProductConfigLogic) GetAgentMembershipProductConfig(r
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取会员用户报告配置,获取代理信息失败: %v", err)
|
||||
}
|
||||
if service.IsMembershipExpired(agentModel, time.Now()) {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("会员已过期"), "获取会员用户报告配置,会员已过期: agent_id=%d", agentModel.Id)
|
||||
}
|
||||
if agentModel.LevelName == "" {
|
||||
agentModel.LevelName = model.AgentLeveNameNormal
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"bdrp-server/app/main/api/internal/service"
|
||||
"bdrp-server/app/main/model"
|
||||
"bdrp-server/common/ctxdata"
|
||||
"bdrp-server/common/xerr"
|
||||
"context"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
@@ -104,6 +106,10 @@ func (l *GetAgentProductConfigLogic) GetAgentProductConfig() (resp *types.AgentP
|
||||
cancel(findAncestorAgentErr)
|
||||
return
|
||||
}
|
||||
if service.IsMembershipExpired(ancestorAgentModel, time.Now()) {
|
||||
writer.Write(&agentProductConfig)
|
||||
return
|
||||
}
|
||||
if ancestorAgentModel.LevelName == "" {
|
||||
ancestorAgentModel.LevelName = model.AgentLeveNameNormal
|
||||
}
|
||||
|
||||
@@ -175,6 +175,11 @@ func calculateActiveReward(rewards []*model.AgentRewards) types.ActiveReward {
|
||||
last30dStart := now.AddDate(0, 0, -30) // 近30天
|
||||
|
||||
for _, r := range rewards {
|
||||
// 跳过已取消的奖励(退款取消)
|
||||
if r.Status == 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
createTime := r.CreateTime
|
||||
amount := r.Amount
|
||||
|
||||
@@ -219,11 +224,12 @@ func addToPeriods(res *types.ActiveReward, amount float64, today, last7d, last30
|
||||
|
||||
// 分类添加具体字段
|
||||
func addToData(data *types.ActiveRewardData, amount float64, t string) {
|
||||
// 所有类型都累加到总奖励
|
||||
data.NewActiveReward += amount
|
||||
|
||||
switch t {
|
||||
case "withdraw":
|
||||
data.SubWithdrawReward += amount
|
||||
case "new_active":
|
||||
data.NewActiveReward += amount
|
||||
case "upgrade":
|
||||
data.SubUpgradeReward += amount
|
||||
case "promotion":
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"bdrp-server/app/main/api/internal/service"
|
||||
"bdrp-server/app/main/model"
|
||||
"bdrp-server/common/ctxdata"
|
||||
"bdrp-server/common/xerr"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
@@ -37,6 +39,9 @@ func (l *SaveAgentMembershipUserConfigLogic) SaveAgentMembershipUserConfig(req *
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "保存会员代理报告配置: %v", err)
|
||||
}
|
||||
if service.IsMembershipExpired(agentModel, time.Now()) {
|
||||
return errors.Wrapf(xerr.NewErrMsg("会员已过期"), "保存会员代理报告配置,会员已过期: agent_id=%d", agentModel.Id)
|
||||
}
|
||||
|
||||
var agentMembershipUserConfigModel *model.AgentMembershipUserConfig
|
||||
agentMembershipUserConfigModel, err = l.svcCtx.AgentMembershipUserConfigModel.FindOneByAgentIdProductId(l.ctx, agentModel.Id, req.ProductID)
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
@@ -22,153 +21,6 @@ func roundMoney(v float64) float64 {
|
||||
return math.Round(v*100) / 100
|
||||
}
|
||||
|
||||
// HandleCommissionAndWalletDeduction 处理退款后的佣金状态更新和钱包金额扣除
|
||||
// refundAmount 为本次实际退款金额(单位:元),从代理侧总共需要承担的金额
|
||||
// 该函数会优先冲减当前订单相关的佣金(基于 RefundedAmount),不足部分再从钱包余额/冻结余额中扣除
|
||||
func HandleCommissionAndWalletDeduction(ctx context.Context, svcCtx *svc.ServiceContext, session sqlx.Session, order *model.Order, refundAmount float64) error {
|
||||
refundAmount = roundMoney(refundAmount)
|
||||
if refundAmount <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 查询当前订单关联的所有佣金记录(包括已结算和冻结),剔除已经完全退款的
|
||||
commissionBuilder := svcCtx.AgentCommissionModel.SelectBuilder()
|
||||
commissions, commissionsErr := svcCtx.AgentCommissionModel.FindAll(ctx, commissionBuilder.Where(squirrel.And{
|
||||
squirrel.Eq{"order_id": order.Id},
|
||||
squirrel.NotEq{"status": 2}, // 排除已全部退款的佣金
|
||||
}), "")
|
||||
if commissionsErr != nil {
|
||||
logx.Errorf("查询代理佣金失败,订单ID: %d, 错误: %v", order.Id, commissionsErr)
|
||||
return nil // 返回 nil,因为佣金更新失败不应影响退款流程
|
||||
}
|
||||
|
||||
if len(commissions) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 剩余需要由佣金 + 钱包共同承担的退款金额
|
||||
remainRefundAmount := refundAmount
|
||||
|
||||
// 记录每个代理本次需要从钱包扣除的金额,避免同一代理多条佣金时重复查钱包并产生多条流水
|
||||
type walletAdjust struct {
|
||||
agentId int64
|
||||
amount float64 // 需要从该代理钱包扣除的金额(正数)
|
||||
}
|
||||
walletAdjustMap := make(map[int64]*walletAdjust)
|
||||
|
||||
// 1. 先在佣金记录上做冲减:增加 RefundedAmount,必要时将状态置为已退款
|
||||
for _, commission := range commissions {
|
||||
available := roundMoney(commission.Amount - commission.RefundedAmount)
|
||||
if available <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if remainRefundAmount <= 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// 当前这条佣金最多可冲减 available,本次实际冲减 currentRefund
|
||||
currentRefund := available
|
||||
if currentRefund > remainRefundAmount {
|
||||
currentRefund = remainRefundAmount
|
||||
}
|
||||
currentRefund = roundMoney(currentRefund)
|
||||
|
||||
// 更新佣金的已退款金额
|
||||
commission.RefundedAmount = roundMoney(commission.RefundedAmount + currentRefund)
|
||||
// 如果这条佣金已经被完全冲减,则标记为已退款
|
||||
if commission.RefundedAmount >= roundMoney(commission.Amount) {
|
||||
commission.Status = 2
|
||||
}
|
||||
|
||||
// 更新佣金状态到数据库
|
||||
var updateCommissionErr error
|
||||
if session != nil {
|
||||
updateCommissionErr = svcCtx.AgentCommissionModel.UpdateWithVersion(ctx, session, commission)
|
||||
} else {
|
||||
updateCommissionErr = svcCtx.AgentCommissionModel.UpdateWithVersion(ctx, nil, commission)
|
||||
}
|
||||
if updateCommissionErr != nil {
|
||||
logx.Errorf("更新代理佣金状态失败,佣金ID: %d, 订单ID: %d, 错误: %v", commission.Id, order.Id, updateCommissionErr)
|
||||
continue // 如果佣金状态更新失败,就不继续计入本次冲减
|
||||
}
|
||||
|
||||
// 记录该代理需要从钱包扣除的金额(可能后续还有其他佣金叠加)
|
||||
wa, ok := walletAdjustMap[commission.AgentId]
|
||||
if !ok {
|
||||
wa = &walletAdjust{agentId: commission.AgentId}
|
||||
walletAdjustMap[commission.AgentId] = wa
|
||||
}
|
||||
wa.amount = roundMoney(wa.amount + currentRefund)
|
||||
|
||||
remainRefundAmount = roundMoney(remainRefundAmount - currentRefund)
|
||||
}
|
||||
|
||||
// 2. 再按代理维度,从钱包(冻结余额/可用余额)中扣除对应金额
|
||||
for _, wa := range walletAdjustMap {
|
||||
if wa.amount <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 处理用户钱包的金额扣除
|
||||
wallet, err := svcCtx.AgentWalletModel.FindOneByAgentId(ctx, wa.agentId)
|
||||
if err != nil {
|
||||
logx.Errorf("查询代理钱包失败,代理ID: %d, 错误: %v", wa.agentId, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 记录变动前的余额
|
||||
balanceBefore := wallet.Balance
|
||||
frozenBalanceBefore := wallet.FrozenBalance
|
||||
|
||||
// 优先从冻结余额中扣除(与原先“冻结佣金优先使用冻结余额”的设计一致)
|
||||
deduct := roundMoney(wa.amount)
|
||||
if wallet.FrozenBalance >= deduct {
|
||||
wallet.FrozenBalance = roundMoney(wallet.FrozenBalance - deduct)
|
||||
} else {
|
||||
remaining := roundMoney(deduct - wallet.FrozenBalance)
|
||||
wallet.FrozenBalance = 0
|
||||
// 可用余额可以为负数,由业务承担风险
|
||||
wallet.Balance = roundMoney(wallet.Balance - remaining)
|
||||
}
|
||||
|
||||
// 变动后余额和冻结余额
|
||||
balanceAfter := roundMoney(wallet.Balance)
|
||||
frozenBalanceAfter := roundMoney(wallet.FrozenBalance)
|
||||
// 更新钱包
|
||||
var updateWalletErr error
|
||||
if session != nil {
|
||||
updateWalletErr = svcCtx.AgentWalletModel.UpdateWithVersion(ctx, session, wallet)
|
||||
} else {
|
||||
updateWalletErr = svcCtx.AgentWalletModel.UpdateWithVersion(ctx, nil, wallet)
|
||||
}
|
||||
if updateWalletErr != nil {
|
||||
logx.Errorf("更新代理钱包失败,代理ID: %d, 错误: %v", wa.agentId, updateWalletErr)
|
||||
continue
|
||||
}
|
||||
// 创建钱包交易流水记录(退款)
|
||||
transErr := svcCtx.AgentService.CreateWalletTransaction(
|
||||
ctx,
|
||||
session,
|
||||
wa.agentId,
|
||||
model.WalletTransactionTypeRefund,
|
||||
roundMoney(-wa.amount*-1), // 钱包流水金额为负数
|
||||
balanceBefore,
|
||||
balanceAfter,
|
||||
frozenBalanceBefore,
|
||||
frozenBalanceAfter,
|
||||
order.OrderNo,
|
||||
0, // 这里不强绑到某一条具体佣金记录,按订单维度记录
|
||||
"订单退款,佣金已扣除",
|
||||
)
|
||||
if transErr != nil {
|
||||
logx.Errorf("创建代理钱包流水记录失败,代理ID: %d, 错误: %v", wa.agentId, transErr)
|
||||
continue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type WechatPayRefundCallbackLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
@@ -227,8 +79,8 @@ func (l *WechatPayRefundCallbackLogic) handleQueryOrderRefund(orderNo string, st
|
||||
return errors.Wrapf(err, "更新查询订单状态失败: %s", orderNo)
|
||||
}
|
||||
|
||||
// 退款成功时,按本次实际退款金额更新代理佣金状态并扣除钱包金额
|
||||
_ = HandleCommissionAndWalletDeduction(ctx, l.svcCtx, session, order, refundAmountYuan)
|
||||
// 退款成功时,按本次实际退款金额执行共用扣款流程
|
||||
l.svcCtx.AgentService.HandleOrderRefundDeduction(ctx, session, order, refundAmountYuan)
|
||||
}
|
||||
|
||||
// 查找最新的pending状态的退款记录
|
||||
|
||||
Reference in New Issue
Block a user