v2.0
This commit is contained in:
parent
0d0ad3bee8
commit
26c403732a
@ -57,6 +57,14 @@ service main {
|
||||
// 获取推广定价配置
|
||||
@handler GetAgentProductConfig
|
||||
get /product_config returns (AgentProductConfigResp)
|
||||
|
||||
// 获取下级分页列表
|
||||
@handler GetAgentSubordinateList
|
||||
get /subordinate/list (GetAgentSubordinateListReq) returns (GetAgentSubordinateListResp)
|
||||
|
||||
// 下级贡献详情
|
||||
@handler GetAgentSubordinateContributionDetail
|
||||
get /subordinate/contribution/detail (GetAgentSubordinateContributionDetailReq) returns (GetAgentSubordinateContributionDetailResp)
|
||||
}
|
||||
|
||||
type (
|
||||
@ -85,6 +93,63 @@ type (
|
||||
AgentProductConfigResp {
|
||||
AgentProductConfig []AgentProductConfig
|
||||
}
|
||||
GetAgentSubordinateListReq {
|
||||
Page int64 `form:"page"` // 页码
|
||||
PageSize int64 `form:"page_size"` // 每页数据量
|
||||
}
|
||||
GetAgentSubordinateListResp {
|
||||
Total int64 `json:"total"` // 总记录数
|
||||
List []AgentSubordinateList `json:"list"` // 查询列表
|
||||
}
|
||||
AgentSubordinateList {
|
||||
ID int64 `json:"id"`
|
||||
Mobile string `json:"mobile"`
|
||||
CreateTime string `json:"create_time"`
|
||||
LevelName string `json:"level_name"`
|
||||
TotalOrders int64 `json:"total_orders"` // 总单量
|
||||
TotalEarnings float64 `json:"total_earnings"` // 总金额
|
||||
TotalContribution float64 `json:"total_contribution"` // 总贡献
|
||||
}
|
||||
GetAgentSubordinateContributionDetailReq {
|
||||
Page int64 `form:"page"` // 页码
|
||||
PageSize int64 `form:"page_size"` // 每页数据量
|
||||
SubordinateID int64 `form:"subordinate_id"` // 下级ID
|
||||
}
|
||||
GetAgentSubordinateContributionDetailResp {
|
||||
Mobile string `json:"mobile"`
|
||||
Total int64 `json:"total"` // 总记录数
|
||||
CreateTime string `json:"create_time"`
|
||||
TotalEarnings float64 `json:"total_earnings"` // 总金额
|
||||
TotalContribution float64 `json:"total_contribution"` // 总贡献
|
||||
TotalOrders int64 `json:"total_orders"` // 总单量
|
||||
LevelName string `json:"level_name"` // 等级名称
|
||||
List []AgentSubordinateContributionDetail `json:"list"` // 查询列表
|
||||
Stats AgentSubordinateContributionStats `json:"stats"` // 统计数据
|
||||
}
|
||||
AgentSubordinateContributionDetail {
|
||||
ID int64 `json:"id"`
|
||||
CreateTime string `json:"create_time"`
|
||||
Amount float64 `json:"amount"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
AgentSubordinateContributionStats {
|
||||
CostCount int64 `json:"cost_count"` // 成本扣除次数
|
||||
CostAmount float64 `json:"cost_amount"` // 成本扣除总额
|
||||
PricingCount int64 `json:"pricing_count"` // 定价扣除次数
|
||||
PricingAmount float64 `json:"pricing_amount"` // 定价扣除总额
|
||||
DescendantPromotionCount int64 `json:"descendant_promotion_count"` // 下级推广次数
|
||||
DescendantPromotionAmount float64 `json:"descendant_promotion_amount"` // 下级推广总额
|
||||
DescendantUpgradeVipCount int64 `json:"descendant_upgrade_vip_count"` // 下级升级VIP次数
|
||||
DescendantUpgradeVipAmount float64 `json:"descendant_upgrade_vip_amount"` // 下级升级VIP总额
|
||||
DescendantUpgradeSvipCount int64 `json:"descendant_upgrade_svip_count"` // 下级升级SVIP次数
|
||||
DescendantUpgradeSvipAmount float64 `json:"descendant_upgrade_svip_amount"` // 下级升级SVIP总额
|
||||
DescendantStayActiveCount int64 `json:"descendant_stay_active_count"` // 下级保持活跃次数
|
||||
DescendantStayActiveAmount float64 `json:"descendant_stay_active_amount"` // 下级保持活跃总额
|
||||
DescendantNewActiveCount int64 `json:"descendant_new_active_count"` // 下级新增活跃次数
|
||||
DescendantNewActiveAmount float64 `json:"descendant_new_active_amount"` // 下级新增活跃总额
|
||||
DescendantWithdrawCount int64 `json:"descendant_withdraw_count"` // 下级提现次数
|
||||
DescendantWithdrawAmount float64 `json:"descendant_withdraw_amount"` // 下级提现总额
|
||||
}
|
||||
)
|
||||
|
||||
@server (
|
||||
|
@ -45,6 +45,8 @@ Wxpay:
|
||||
MchCertificateSerialNumber: "5369B8AEEBDCF7AF274510252E6A8C0659C30F61"
|
||||
MchApiv3Key: "e3ea4cf0765f1e71b01bb387dfcdbc9f"
|
||||
MchPrivateKeyPath: "etc/merchant/apiclient_key.pem"
|
||||
MchPublicKeyID: "XXXXXX"
|
||||
MchPublicKeyPath: "etc/merchant/pub_key.pem"
|
||||
NotifyUrl: "https://6m4685017o.goho.co/api/v1/pay/wechat/callback"
|
||||
RefundNotifyUrl: "https://6m4685017o.goho.co/api/v1/wechat/refund_callback"
|
||||
Applepay:
|
||||
|
@ -46,6 +46,8 @@ Wxpay:
|
||||
MchCertificateSerialNumber: "5369B8AEEBDCF7AF274510252E6A8C0659C30F61"
|
||||
MchApiv3Key: "e3ea4cf0765f1e71b01bb387dfcdbc9f"
|
||||
MchPrivateKeyPath: "etc/merchant/apiclient_key.pem"
|
||||
MchPublicKeyID: "XXXXXX"
|
||||
MchPublicKeyPath: "etc/merchant/pub_key.pem"
|
||||
NotifyUrl: "https://www.quannengcha.com/api/v1/pay/wechat/callback"
|
||||
RefundNotifyUrl: "https://www.quannengcha.com/api/v1/wechat/refund_callback"
|
||||
Applepay:
|
||||
|
@ -56,6 +56,8 @@ type WxpayConfig struct {
|
||||
MchCertificateSerialNumber string
|
||||
MchApiv3Key string
|
||||
MchPrivateKeyPath string
|
||||
MchPublicKeyID string
|
||||
MchPublicKeyPath string
|
||||
NotifyUrl string
|
||||
RefundNotifyUrl string
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"qnc-server/app/user/cmd/api/internal/logic/agent"
|
||||
"qnc-server/app/user/cmd/api/internal/svc"
|
||||
"qnc-server/app/user/cmd/api/internal/types"
|
||||
"qnc-server/common/result"
|
||||
"qnc-server/pkg/lzkit/validator"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GetAgentSubordinateContributionDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.GetAgentSubordinateContributionDetailReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
result.ParamErrorResult(r, w, err)
|
||||
return
|
||||
}
|
||||
if err := validator.Validate(req); err != nil {
|
||||
result.ParamValidateErrorResult(r, w, err)
|
||||
return
|
||||
}
|
||||
l := agent.NewGetAgentSubordinateContributionDetailLogic(r.Context(), svcCtx)
|
||||
resp, err := l.GetAgentSubordinateContributionDetail(&req)
|
||||
result.HttpResult(r, w, resp, err)
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"qnc-server/app/user/cmd/api/internal/logic/agent"
|
||||
"qnc-server/app/user/cmd/api/internal/svc"
|
||||
"qnc-server/app/user/cmd/api/internal/types"
|
||||
"qnc-server/common/result"
|
||||
"qnc-server/pkg/lzkit/validator"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func GetAgentSubordinateListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.GetAgentSubordinateListReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
result.ParamErrorResult(r, w, err)
|
||||
return
|
||||
}
|
||||
if err := validator.Validate(req); err != nil {
|
||||
result.ParamValidateErrorResult(r, w, err)
|
||||
return
|
||||
}
|
||||
l := agent.NewGetAgentSubordinateListLogic(r.Context(), svcCtx)
|
||||
resp, err := l.GetAgentSubordinateList(&req)
|
||||
result.HttpResult(r, w, resp, err)
|
||||
}
|
||||
}
|
@ -3,12 +3,13 @@ package pay
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"qnc-server/app/user/cmd/api/internal/logic/pay"
|
||||
"qnc-server/app/user/cmd/api/internal/svc"
|
||||
"qnc-server/app/user/cmd/api/internal/types"
|
||||
"qnc-server/common/result"
|
||||
"qnc-server/pkg/lzkit/validator"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func PaymentCheckHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
|
@ -40,6 +40,16 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
Path: "/product_config",
|
||||
Handler: agent.GetAgentProductConfigHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/subordinate/contribution/detail",
|
||||
Handler: agent.GetAgentSubordinateContributionDetailHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/subordinate/list",
|
||||
Handler: agent.GetAgentSubordinateListHandler(serverCtx),
|
||||
},
|
||||
},
|
||||
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/agent"),
|
||||
|
@ -3,12 +3,13 @@ package user
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"qnc-server/app/user/cmd/api/internal/logic/user"
|
||||
"qnc-server/app/user/cmd/api/internal/svc"
|
||||
"qnc-server/app/user/cmd/api/internal/types"
|
||||
"qnc-server/common/result"
|
||||
"qnc-server/pkg/lzkit/validator"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func BindMobileHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
|
@ -0,0 +1,200 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"qnc-server/app/user/cmd/api/internal/svc"
|
||||
"qnc-server/app/user/cmd/api/internal/types"
|
||||
"qnc-server/common/ctxdata"
|
||||
"qnc-server/common/xerr"
|
||||
"qnc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetAgentSubordinateContributionDetailLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetAgentSubordinateContributionDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAgentSubordinateContributionDetailLogic {
|
||||
return &GetAgentSubordinateContributionDetailLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetAgentSubordinateContributionDetailLogic) GetAgentSubordinateContributionDetail(req *types.GetAgentSubordinateContributionDetailReq) (resp *types.GetAgentSubordinateContributionDetailResp, err error) {
|
||||
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理下级贡献详情, 获取用户ID%v", err)
|
||||
}
|
||||
|
||||
// 获取当前代理信息
|
||||
agentModel, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 获取代理信息%v", err)
|
||||
}
|
||||
|
||||
// 获取下级代理信息
|
||||
subordinateAgent, err := l.svcCtx.AgentModel.FindOne(l.ctx, req.SubordinateID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 获取下级代理信息%v", err)
|
||||
}
|
||||
|
||||
// 验证是否是当前代理的下级
|
||||
closureBuilder := l.svcCtx.AgentClosureModel.SelectBuilder().Where(squirrel.Eq{
|
||||
"ancestor_id": agentModel.Id,
|
||||
"descendant_id": req.SubordinateID,
|
||||
})
|
||||
closureList, err := l.svcCtx.AgentClosureModel.FindAll(l.ctx, closureBuilder, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 验证代理关系%v", err)
|
||||
}
|
||||
if len(closureList) == 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理下级贡献详情, 非法的代理关系")
|
||||
}
|
||||
closure := closureList[0]
|
||||
|
||||
// 获取佣金扣除记录
|
||||
deductionBuilder := l.svcCtx.AgentCommissionDeductionModel.SelectBuilder().Where(squirrel.Eq{
|
||||
"agent_id": agentModel.Id,
|
||||
"deducted_agent_id": req.SubordinateID,
|
||||
})
|
||||
deductionList, err := l.svcCtx.AgentCommissionDeductionModel.FindAll(l.ctx, deductionBuilder, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 获取佣金扣除记录%v", err)
|
||||
}
|
||||
|
||||
// 获取奖励记录
|
||||
rewardsBuilder := l.svcCtx.AgentRewardsModel.SelectBuilder().Where(squirrel.Eq{
|
||||
"agent_id": agentModel.Id,
|
||||
"relation_agent_id": req.SubordinateID,
|
||||
})
|
||||
rewards, err := l.svcCtx.AgentRewardsModel.FindAll(l.ctx, rewardsBuilder, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 获取奖励记录%v", err)
|
||||
}
|
||||
|
||||
// 计算总贡献
|
||||
var totalContribution float64
|
||||
for _, v := range deductionList {
|
||||
totalContribution += v.Amount
|
||||
}
|
||||
// 加上奖励金额
|
||||
for _, v := range rewards {
|
||||
totalContribution += v.Amount
|
||||
}
|
||||
|
||||
// 获取佣金记录
|
||||
commissionBuilder := l.svcCtx.AgentCommissionModel.SelectBuilder().Where(squirrel.Eq{
|
||||
"agent_id": req.SubordinateID,
|
||||
})
|
||||
commissionList, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, commissionBuilder, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 获取佣金记录%v", err)
|
||||
}
|
||||
|
||||
// 计算总收益和总单量
|
||||
var totalEarnings float64
|
||||
for _, v := range commissionList {
|
||||
totalEarnings += v.Amount
|
||||
}
|
||||
|
||||
// 初始化统计数据
|
||||
stats := types.AgentSubordinateContributionStats{
|
||||
CostCount: 0,
|
||||
CostAmount: 0,
|
||||
PricingCount: 0,
|
||||
PricingAmount: 0,
|
||||
DescendantPromotionCount: 0,
|
||||
DescendantPromotionAmount: 0,
|
||||
DescendantUpgradeVipCount: 0,
|
||||
DescendantUpgradeVipAmount: 0,
|
||||
DescendantUpgradeSvipCount: 0,
|
||||
DescendantUpgradeSvipAmount: 0,
|
||||
DescendantStayActiveCount: 0,
|
||||
DescendantStayActiveAmount: 0,
|
||||
DescendantNewActiveCount: 0,
|
||||
DescendantNewActiveAmount: 0,
|
||||
DescendantWithdrawCount: 0,
|
||||
DescendantWithdrawAmount: 0,
|
||||
}
|
||||
|
||||
// 统计佣金扣除记录
|
||||
for _, v := range deductionList {
|
||||
switch v.Type {
|
||||
case "cost":
|
||||
stats.CostCount++
|
||||
stats.CostAmount += v.Amount
|
||||
case "pricing":
|
||||
stats.PricingCount++
|
||||
stats.PricingAmount += v.Amount
|
||||
}
|
||||
}
|
||||
|
||||
// 统计奖励记录
|
||||
for _, v := range rewards {
|
||||
switch v.Type {
|
||||
case "descendant_promotion":
|
||||
stats.DescendantPromotionCount++
|
||||
stats.DescendantPromotionAmount += v.Amount
|
||||
case "descendant_upgrade_vip":
|
||||
stats.DescendantUpgradeVipCount++
|
||||
stats.DescendantUpgradeVipAmount += v.Amount
|
||||
case "descendant_upgrade_svip":
|
||||
stats.DescendantUpgradeSvipCount++
|
||||
stats.DescendantUpgradeSvipAmount += v.Amount
|
||||
case "descendant_stay_active":
|
||||
stats.DescendantStayActiveCount++
|
||||
stats.DescendantStayActiveAmount += v.Amount
|
||||
case "descendant_new_active":
|
||||
stats.DescendantNewActiveCount++
|
||||
stats.DescendantNewActiveAmount += v.Amount
|
||||
case "descendant_withdraw":
|
||||
stats.DescendantWithdrawCount++
|
||||
stats.DescendantWithdrawAmount += v.Amount
|
||||
}
|
||||
}
|
||||
|
||||
// 解密手机号
|
||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||
mobile, err := crypto.DecryptMobile(subordinateAgent.Mobile, secretKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理下级贡献详情, 解密手机号失败: %v", err)
|
||||
}
|
||||
|
||||
// 获取合并后的分页列表
|
||||
unionDetails, total, err := l.svcCtx.AgentClosureModel.FindUnionPageListByPageWithTotal(l.ctx, agentModel.Id, req.SubordinateID, req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 获取分页列表%v", err)
|
||||
}
|
||||
|
||||
// 转换为响应类型
|
||||
detailList := make([]types.AgentSubordinateContributionDetail, 0, len(unionDetails))
|
||||
for _, v := range unionDetails {
|
||||
detail := types.AgentSubordinateContributionDetail{
|
||||
ID: v.Id,
|
||||
CreateTime: v.CreateTime,
|
||||
Amount: v.Amount,
|
||||
Type: v.Type,
|
||||
}
|
||||
detailList = append(detailList, detail)
|
||||
}
|
||||
|
||||
return &types.GetAgentSubordinateContributionDetailResp{
|
||||
Mobile: maskPhone(mobile),
|
||||
Total: total,
|
||||
CreateTime: closure.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
TotalEarnings: totalEarnings,
|
||||
TotalContribution: totalContribution,
|
||||
TotalOrders: int64(len(commissionList)),
|
||||
LevelName: subordinateAgent.LevelName,
|
||||
List: detailList,
|
||||
Stats: stats,
|
||||
}, nil
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"qnc-server/app/user/cmd/api/internal/svc"
|
||||
"qnc-server/app/user/cmd/api/internal/types"
|
||||
"qnc-server/app/user/model"
|
||||
"qnc-server/common/ctxdata"
|
||||
"qnc-server/common/xerr"
|
||||
"qnc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
)
|
||||
|
||||
type GetAgentSubordinateListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetAgentSubordinateListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAgentSubordinateListLogic {
|
||||
return &GetAgentSubordinateListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetAgentSubordinateListLogic) GetAgentSubordinateList(req *types.GetAgentSubordinateListReq) (resp *types.GetAgentSubordinateListResp, err error) {
|
||||
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理下级列表, 获取用户ID%v", err)
|
||||
}
|
||||
agentModel, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级列表, 获取代理信息%v", err)
|
||||
}
|
||||
agentID := agentModel.Id
|
||||
|
||||
builder := l.svcCtx.AgentClosureModel.SelectBuilder().Where(squirrel.Eq{
|
||||
"ancestor_id": agentID,
|
||||
})
|
||||
agentClosureModelList, total, err := l.svcCtx.AgentClosureModel.FindPageListByPageWithTotal(l.ctx, builder, req.Page, req.PageSize, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级列表, 获取代理关系%v", err)
|
||||
}
|
||||
|
||||
// 构建ID到CreateTime的映射
|
||||
createTimeMap := make(map[int64]time.Time)
|
||||
descendantIDs := make([]int64, 0)
|
||||
for _, v := range agentClosureModelList {
|
||||
descendantIDs = append(descendantIDs, v.DescendantId)
|
||||
createTimeMap[v.DescendantId] = v.CreateTime
|
||||
}
|
||||
|
||||
// 并发查询代理信息
|
||||
agentMap := make(map[int64]*model.Agent)
|
||||
var descendantList []types.AgentSubordinateList
|
||||
err = mr.Finish(func() error {
|
||||
return mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
for _, id := range descendantIDs {
|
||||
source <- id
|
||||
}
|
||||
}, func(item interface{}, writer mr.Writer[interface{}], cancel func(error)) {
|
||||
id := item.(int64)
|
||||
agent, err := l.svcCtx.AgentModel.FindOne(l.ctx, id)
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
writer.Write(agent)
|
||||
}, func(pipe <-chan interface{}, cancel func(error)) {
|
||||
for item := range pipe {
|
||||
agent := item.(*model.Agent)
|
||||
agentMap[agent.Id] = agent
|
||||
}
|
||||
})
|
||||
}, func() error {
|
||||
// 并发查询佣金扣除信息
|
||||
deductionBuilder := l.svcCtx.AgentCommissionDeductionModel.SelectBuilder().
|
||||
Where(squirrel.Eq{"agent_id": agentID}).
|
||||
Where(squirrel.Eq{"deducted_agent_id": descendantIDs})
|
||||
deductionList, err := l.svcCtx.AgentCommissionDeductionModel.FindAll(l.ctx, deductionBuilder, "")
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级列表, 获取代理佣金扣除信息%v", err)
|
||||
}
|
||||
deductionMap := make(map[int64]float64)
|
||||
for _, v := range deductionList {
|
||||
deductionMap[v.DeductedAgentId] += v.Amount
|
||||
}
|
||||
|
||||
// 并发查询奖励信息
|
||||
rewardsBuilder := l.svcCtx.AgentRewardsModel.SelectBuilder().
|
||||
Where(squirrel.Eq{"agent_id": agentID}).
|
||||
Where(squirrel.Eq{"relation_agent_id": descendantIDs})
|
||||
rewardsList, err := l.svcCtx.AgentRewardsModel.FindAll(l.ctx, rewardsBuilder, "")
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级列表, 获取代理奖励信息%v", err)
|
||||
}
|
||||
rewardsMap := make(map[int64]float64)
|
||||
for _, v := range rewardsList {
|
||||
if v.RelationAgentId.Valid {
|
||||
rewardsMap[v.RelationAgentId.Int64] += v.Amount
|
||||
}
|
||||
}
|
||||
|
||||
// 并发查询佣金信息
|
||||
commissionBuilder := l.svcCtx.AgentCommissionModel.SelectBuilder().
|
||||
Where(squirrel.Eq{"agent_id": descendantIDs})
|
||||
commissionList, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, commissionBuilder, "")
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级列表, 获取代理佣金信息%v", err)
|
||||
}
|
||||
commissionMap := make(map[int64]float64)
|
||||
orderCountMap := make(map[int64]int64)
|
||||
for _, v := range commissionList {
|
||||
commissionMap[v.AgentId] += v.Amount
|
||||
orderCountMap[v.AgentId]++
|
||||
}
|
||||
|
||||
// 构建返回结果
|
||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||
descendantList = make([]types.AgentSubordinateList, 0, len(descendantIDs))
|
||||
for _, id := range descendantIDs {
|
||||
agent, exists := agentMap[id]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
mobile, err := crypto.DecryptMobile(agent.Mobile, secretKey)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理信息, 解密手机号失败: %v", err)
|
||||
}
|
||||
|
||||
subordinate := types.AgentSubordinateList{
|
||||
ID: id,
|
||||
Mobile: maskPhone(mobile),
|
||||
LevelName: agent.LevelName,
|
||||
CreateTime: createTimeMap[id].Format("2006-01-02 15:04:05"),
|
||||
TotalContribution: deductionMap[id] + rewardsMap[id],
|
||||
TotalEarnings: commissionMap[id],
|
||||
TotalOrders: orderCountMap[id],
|
||||
}
|
||||
descendantList = append(descendantList, subordinate)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.GetAgentSubordinateListResp{
|
||||
Total: total,
|
||||
List: descendantList,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 手机号脱敏
|
||||
func maskPhone(phone string) string {
|
||||
length := len(phone)
|
||||
if length < 8 {
|
||||
return phone // 如果长度太短,可能不是手机号,不处理
|
||||
}
|
||||
// 保留前3位和后4位
|
||||
return phone[:3] + strings.Repeat("*", length-7) + phone[length-4:]
|
||||
}
|
@ -34,6 +34,14 @@ const (
|
||||
TradeStatePayError = "PAYERROR" // 支付失败(其他原因,如银行返回失败)
|
||||
)
|
||||
|
||||
// InitType 初始化类型
|
||||
type InitType string
|
||||
|
||||
const (
|
||||
InitTypePlatformCert InitType = "platform_cert" // 平台证书初始化
|
||||
InitTypeWxPayPubKey InitType = "wxpay_pubkey" // 微信支付公钥初始化
|
||||
)
|
||||
|
||||
type WechatPayService struct {
|
||||
config config.WxpayConfig
|
||||
wechatClient *core.Client
|
||||
@ -41,8 +49,21 @@ type WechatPayService struct {
|
||||
userAuthModel model.UserAuthModel
|
||||
}
|
||||
|
||||
// NewWechatPayService 初始化微信支付服务
|
||||
func NewWechatPayService(c config.Config, userAuthModel model.UserAuthModel) *WechatPayService {
|
||||
// NewWechatPayService 创建微信支付服务实例
|
||||
func NewWechatPayService(c config.Config, userAuthModel model.UserAuthModel, initType InitType) *WechatPayService {
|
||||
switch initType {
|
||||
case InitTypePlatformCert:
|
||||
return newWechatPayServiceWithPlatformCert(c, userAuthModel)
|
||||
case InitTypeWxPayPubKey:
|
||||
return newWechatPayServiceWithWxPayPubKey(c, userAuthModel)
|
||||
default:
|
||||
logx.Errorf("不支持的初始化类型: %s", initType)
|
||||
panic(fmt.Sprintf("初始化失败,服务停止: %s", initType))
|
||||
}
|
||||
}
|
||||
|
||||
// newWechatPayServiceWithPlatformCert 使用平台证书初始化微信支付服务
|
||||
func newWechatPayServiceWithPlatformCert(c config.Config, userAuthModel model.UserAuthModel) *WechatPayService {
|
||||
// 从配置中加载商户信息
|
||||
mchID := c.Wxpay.MchID
|
||||
mchCertificateSerialNumber := c.Wxpay.MchCertificateSerialNumber
|
||||
@ -64,14 +85,62 @@ func NewWechatPayService(c config.Config, userAuthModel model.UserAuthModel) *We
|
||||
logx.Errorf("创建微信支付客户端失败: %v", err)
|
||||
panic(fmt.Sprintf("初始化失败,服务停止: %v", err)) // 记录错误并停止程序
|
||||
}
|
||||
|
||||
// 在初始化时获取证书访问器并创建 notifyHandler
|
||||
certificateVisitor := downloader.MgrInstance().GetCertificateVisitor(mchID)
|
||||
notifyHandler, err := notify.NewRSANotifyHandler(mchAPIv3Key, verifiers.NewSHA256WithRSAVerifier(certificateVisitor))
|
||||
if err != nil {
|
||||
logx.Errorf("获取证书访问器失败: %v", err)
|
||||
panic(fmt.Sprintf("初始化失败,服务停止: %v", err)) // 记录错误并停止程序
|
||||
panic(fmt.Sprintf("初始化失败,服务停止: %v", err))
|
||||
}
|
||||
logx.Infof("微信支付客户端初始化成功")
|
||||
|
||||
logx.Infof("微信支付客户端初始化成功(平台证书方式)")
|
||||
return &WechatPayService{
|
||||
config: c.Wxpay,
|
||||
wechatClient: client,
|
||||
notifyHandler: notifyHandler,
|
||||
userAuthModel: userAuthModel,
|
||||
}
|
||||
}
|
||||
|
||||
// newWechatPayServiceWithWxPayPubKey 使用微信支付公钥初始化微信支付服务
|
||||
func newWechatPayServiceWithWxPayPubKey(c config.Config, userAuthModel model.UserAuthModel) *WechatPayService {
|
||||
// 从配置中加载商户信息
|
||||
mchID := c.Wxpay.MchID
|
||||
mchCertificateSerialNumber := c.Wxpay.MchCertificateSerialNumber
|
||||
mchAPIv3Key := c.Wxpay.MchApiv3Key
|
||||
mchPrivateKeyPath := c.Wxpay.MchPrivateKeyPath
|
||||
mchPublicKeyID := c.Wxpay.MchPublicKeyID
|
||||
mchPublicKeyPath := c.Wxpay.MchPublicKeyPath
|
||||
// 从文件中加载商户私钥
|
||||
mchPrivateKey, err := utils.LoadPrivateKeyWithPath(mchPrivateKeyPath)
|
||||
if err != nil {
|
||||
logx.Errorf("加载商户私钥失败: %v", err)
|
||||
panic(fmt.Sprintf("初始化失败,服务停止: %v", err))
|
||||
}
|
||||
|
||||
// 从文件中加载微信支付平台证书
|
||||
mchPublicKey, err := utils.LoadPublicKeyWithPath(mchPublicKeyPath)
|
||||
if err != nil {
|
||||
logx.Errorf("加载微信支付平台证书失败: %v", err)
|
||||
panic(fmt.Sprintf("初始化失败,服务停止: %v", err))
|
||||
}
|
||||
|
||||
// 使用商户私钥和其他参数初始化微信支付客户端
|
||||
opts := []core.ClientOption{
|
||||
option.WithWechatPayPublicKeyAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchPublicKeyID, mchPublicKey),
|
||||
}
|
||||
client, err := core.NewClient(context.Background(), opts...)
|
||||
if err != nil {
|
||||
logx.Errorf("创建微信支付客户端失败: %v", err)
|
||||
panic(fmt.Sprintf("初始化失败,服务停止: %v", err))
|
||||
}
|
||||
|
||||
// 初始化 notify.Handler
|
||||
notifyHandler := notify.NewNotifyHandler(
|
||||
mchAPIv3Key,
|
||||
verifiers.NewSHA256WithRSAPubkeyVerifier(mchPublicKeyID, *mchPublicKey))
|
||||
logx.Infof("微信支付客户端初始化成功(微信支付公钥方式)")
|
||||
return &WechatPayService{
|
||||
config: c.Wxpay,
|
||||
wechatClient: client,
|
||||
|
@ -105,7 +105,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||
exampleModel := model.NewExampleModel(db, c.CacheRedis)
|
||||
|
||||
alipayService := service.NewAliPayService(c)
|
||||
wechatPayService := service.NewWechatPayService(c, userAuthModel)
|
||||
wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTypePlatformCert)
|
||||
applePayService := service.NewApplePayService(c)
|
||||
apiRequestService := service.NewApiRequestService(c, westDexService, yushanService, featureModel, productFeatureModel)
|
||||
verificationService := service.NewVerificationService(c, westDexService, apiRequestService)
|
||||
|
@ -98,6 +98,42 @@ type AgentProductConfigResp struct {
|
||||
AgentProductConfig []AgentProductConfig
|
||||
}
|
||||
|
||||
type AgentSubordinateContributionDetail struct {
|
||||
ID int64 `json:"id"`
|
||||
CreateTime string `json:"create_time"`
|
||||
Amount float64 `json:"amount"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type AgentSubordinateContributionStats struct {
|
||||
CostCount int64 `json:"cost_count"` // 成本扣除次数
|
||||
CostAmount float64 `json:"cost_amount"` // 成本扣除总额
|
||||
PricingCount int64 `json:"pricing_count"` // 定价扣除次数
|
||||
PricingAmount float64 `json:"pricing_amount"` // 定价扣除总额
|
||||
DescendantPromotionCount int64 `json:"descendant_promotion_count"` // 下级推广次数
|
||||
DescendantPromotionAmount float64 `json:"descendant_promotion_amount"` // 下级推广总额
|
||||
DescendantUpgradeVipCount int64 `json:"descendant_upgrade_vip_count"` // 下级升级VIP次数
|
||||
DescendantUpgradeVipAmount float64 `json:"descendant_upgrade_vip_amount"` // 下级升级VIP总额
|
||||
DescendantUpgradeSvipCount int64 `json:"descendant_upgrade_svip_count"` // 下级升级SVIP次数
|
||||
DescendantUpgradeSvipAmount float64 `json:"descendant_upgrade_svip_amount"` // 下级升级SVIP总额
|
||||
DescendantStayActiveCount int64 `json:"descendant_stay_active_count"` // 下级保持活跃次数
|
||||
DescendantStayActiveAmount float64 `json:"descendant_stay_active_amount"` // 下级保持活跃总额
|
||||
DescendantNewActiveCount int64 `json:"descendant_new_active_count"` // 下级新增活跃次数
|
||||
DescendantNewActiveAmount float64 `json:"descendant_new_active_amount"` // 下级新增活跃总额
|
||||
DescendantWithdrawCount int64 `json:"descendant_withdraw_count"` // 下级提现次数
|
||||
DescendantWithdrawAmount float64 `json:"descendant_withdraw_amount"` // 下级提现总额
|
||||
}
|
||||
|
||||
type AgentSubordinateList struct {
|
||||
ID int64 `json:"id"`
|
||||
Mobile string `json:"mobile"`
|
||||
CreateTime string `json:"create_time"`
|
||||
LevelName string `json:"level_name"`
|
||||
TotalOrders int64 `json:"total_orders"` // 总单量
|
||||
TotalEarnings float64 `json:"total_earnings"` // 总金额
|
||||
TotalContribution float64 `json:"total_contribution"` // 总贡献
|
||||
}
|
||||
|
||||
type BindMobileReq struct {
|
||||
Mobile string `json:"mobile" validate:"required,mobile"`
|
||||
Code string `json:"code" validate:"required"`
|
||||
@ -137,6 +173,34 @@ type GetAgentRevenueInfoResp struct {
|
||||
ActiveReward ActiveReward `json:"active_reward"` // 活跃下级奖励数据
|
||||
}
|
||||
|
||||
type GetAgentSubordinateContributionDetailReq struct {
|
||||
Page int64 `form:"page"` // 页码
|
||||
PageSize int64 `form:"page_size"` // 每页数据量
|
||||
SubordinateID int64 `form:"subordinate_id"` // 下级ID
|
||||
}
|
||||
|
||||
type GetAgentSubordinateContributionDetailResp struct {
|
||||
Mobile string `json:"mobile"`
|
||||
Total int64 `json:"total"` // 总记录数
|
||||
CreateTime string `json:"create_time"`
|
||||
TotalEarnings float64 `json:"total_earnings"` // 总金额
|
||||
TotalContribution float64 `json:"total_contribution"` // 总贡献
|
||||
TotalOrders int64 `json:"total_orders"` // 总单量
|
||||
LevelName string `json:"level_name"` // 等级名称
|
||||
List []AgentSubordinateContributionDetail `json:"list"` // 查询列表
|
||||
Stats AgentSubordinateContributionStats `json:"stats"` // 统计数据
|
||||
}
|
||||
|
||||
type GetAgentSubordinateListReq struct {
|
||||
Page int64 `form:"page"` // 页码
|
||||
PageSize int64 `form:"page_size"` // 每页数据量
|
||||
}
|
||||
|
||||
type GetAgentSubordinateListResp struct {
|
||||
Total int64 `json:"total"` // 总记录数
|
||||
List []AgentSubordinateList `json:"list"` // 查询列表
|
||||
}
|
||||
|
||||
type GetCommissionReq struct {
|
||||
Page int64 `form:"page"` // 页码
|
||||
PageSize int64 `form:"page_size"` // 每页数据量
|
||||
|
@ -1,6 +1,12 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"qnc-server/common/globalkey"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
@ -12,11 +18,20 @@ type (
|
||||
// and implement the added methods in customAgentClosureModel.
|
||||
AgentClosureModel interface {
|
||||
agentClosureModel
|
||||
FindUnionPageListByPageWithTotal(ctx context.Context, agentId, subordinateId int64, page, pageSize int64) ([]*UnionDetail, int64, error)
|
||||
}
|
||||
|
||||
customAgentClosureModel struct {
|
||||
*defaultAgentClosureModel
|
||||
}
|
||||
|
||||
// UnionDetail 合并后的详情结构
|
||||
UnionDetail struct {
|
||||
Id int64 `db:"id"`
|
||||
CreateTime string `db:"create_time"`
|
||||
Amount float64 `db:"amount"`
|
||||
Type string `db:"type"`
|
||||
}
|
||||
)
|
||||
|
||||
// NewAgentClosureModel returns a model for the database table.
|
||||
@ -25,3 +40,61 @@ func NewAgentClosureModel(conn sqlx.SqlConn, c cache.CacheConf) AgentClosureMode
|
||||
defaultAgentClosureModel: newAgentClosureModel(conn, c),
|
||||
}
|
||||
}
|
||||
|
||||
// FindUnionPageListByPageWithTotal 获取合并后的分页列表
|
||||
func (m *customAgentClosureModel) FindUnionPageListByPageWithTotal(ctx context.Context, agentId, subordinateId int64, page, pageSize int64) ([]*UnionDetail, int64, error) {
|
||||
// 构建UNION ALL查询
|
||||
deductionQuery := fmt.Sprintf(`
|
||||
SELECT id, create_time, amount, type
|
||||
FROM agent_commission_deduction
|
||||
WHERE agent_id = ? AND deducted_agent_id = ? AND del_state = ?
|
||||
`)
|
||||
|
||||
rewardsQuery := fmt.Sprintf(`
|
||||
SELECT id, create_time, amount, type
|
||||
FROM agent_rewards
|
||||
WHERE agent_id = ? AND relation_agent_id = ? AND del_state = ?
|
||||
`)
|
||||
|
||||
// 计算总记录数
|
||||
countQuery := fmt.Sprintf(`
|
||||
SELECT COUNT(*) FROM (
|
||||
%s
|
||||
UNION ALL
|
||||
%s
|
||||
) AS union_table
|
||||
`, deductionQuery, rewardsQuery)
|
||||
|
||||
var total int64
|
||||
err := m.QueryRowNoCacheCtx(ctx, &total, countQuery, agentId, subordinateId, globalkey.DelStateNo, agentId, subordinateId, globalkey.DelStateNo)
|
||||
if err != nil {
|
||||
return nil, 0, errors.Wrapf(err, "查询总记录数失败")
|
||||
}
|
||||
|
||||
// 构建分页查询
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
unionQuery := fmt.Sprintf(`
|
||||
SELECT * FROM (
|
||||
%s
|
||||
UNION ALL
|
||||
%s
|
||||
) AS union_table
|
||||
ORDER BY create_time DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`, deductionQuery, rewardsQuery)
|
||||
|
||||
var resp []*UnionDetail
|
||||
err = m.QueryRowsNoCacheCtx(ctx, &resp, unionQuery,
|
||||
agentId, subordinateId, globalkey.DelStateNo,
|
||||
agentId, subordinateId, globalkey.DelStateNo,
|
||||
pageSize, offset)
|
||||
if err != nil {
|
||||
return nil, 0, errors.Wrapf(err, "查询分页数据失败")
|
||||
}
|
||||
|
||||
return resp, total, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user