diff --git a/app/main/api/desc/admin/admin_agent.api b/app/main/api/desc/admin/admin_agent.api index 12a9d45..76dd028 100644 --- a/app/main/api/desc/admin/admin_agent.api +++ b/app/main/api/desc/admin/admin_agent.api @@ -50,6 +50,10 @@ service main { @handler AdminGetAgentWallet get /wallet/:agent_id (AdminGetAgentWalletReq) returns (AdminGetAgentWalletResp) + // 修改代理钱包余额 + @handler AdminUpdateAgentWalletBalance + post /wallet/update-balance (AdminUpdateAgentWalletBalanceReq) returns (AdminUpdateAgentWalletBalanceResp) + // 平台抽佣分页查询 @handler AdminGetAgentPlatformDeductionList get /agent-platform-deduction/list (AdminGetAgentPlatformDeductionListReq) returns (AdminGetAgentPlatformDeductionListResp) @@ -93,6 +97,7 @@ service main { // 获取代理链接产品统计 @handler AdminGetAgentLinkProductStatistics get /agent-link/product-statistics (AdminGetAgentLinkProductStatisticsReq) returns (AdminGetAgentLinkProductStatisticsResp) + } type ( @@ -157,12 +162,14 @@ type ( // 代理佣金分页查询请求 AdminGetAgentCommissionListReq { - Page int64 `form:"page"` // 页码 - PageSize int64 `form:"pageSize"` // 每页数量 - AgentId *int64 `form:"agent_id,optional"` // 代理ID(可选) - OrderId *int64 `form:"order_id,optional"` // 订单ID(可选) - ProductName *string `form:"product_name,optional"` // 产品名(可选) - Status *int64 `form:"status,optional"` // 状态(可选) + Page int64 `form:"page"` // 页码 + PageSize int64 `form:"pageSize"` // 每页数量 + AgentId *int64 `form:"agent_id,optional"` // 代理ID(可选) + OrderId *int64 `form:"order_id,optional"` // 订单ID(可选) + ProductName *string `form:"product_name,optional"` // 产品名(可选) + Status *int64 `form:"status,optional"` // 状态(可选) + CreateTimeStart *string `form:"create_time_start,optional"` // 创建时间开始(可选) + CreateTimeEnd *string `form:"create_time_end,optional"` // 创建时间结束(可选) } // 代理佣金列表项 @@ -232,11 +239,12 @@ type ( // 代理提现分页查询请求 AdminGetAgentWithdrawalListReq { - Page int64 `form:"page"` // 页码 - PageSize int64 `form:"pageSize"` // 每页数量 - AgentId *int64 `form:"agent_id,optional"` // 代理ID(可选) - Status *int64 `form:"status,optional"` // 状态(可选) - WithdrawNo *string `form:"withdraw_no,optional"` // 提现单号(可选) + Page int64 `form:"page"` // 页码 + PageSize int64 `form:"pageSize"` // 每页数量 + AgentId *int64 `form:"agent_id,optional"` // 代理ID(可选) + Status *int64 `form:"status,optional"` // 状态(可选) + WithdrawNo *string `form:"withdraw_no,optional"` // 提现单号(可选) + WithdrawType *int64 `form:"withdraw_type,optional"` // 提现类型(可选)1-支付宝,2-银行卡 } // 代理提现列表项 @@ -516,4 +524,17 @@ type ( FrozenBalance float64 `json:"frozen_balance"` // 冻结余额 TotalEarnings float64 `json:"total_earnings"` // 总收益 } + + // 修改代理钱包余额请求 + AdminUpdateAgentWalletBalanceReq { + AgentId int64 `json:"agent_id"` // 代理ID + Amount float64 `json:"amount"` // 修改金额(正数增加,负数减少) + } + + // 修改代理钱包余额响应 + AdminUpdateAgentWalletBalanceResp { + Success bool `json:"success"` // 是否成功 + Balance float64 `json:"balance"` // 修改后的余额 + } + ) \ No newline at end of file diff --git a/app/main/api/internal/handler/admin_agent/adminupdateagentwalletbalancehandler.go b/app/main/api/internal/handler/admin_agent/adminupdateagentwalletbalancehandler.go new file mode 100644 index 0000000..b5d7458 --- /dev/null +++ b/app/main/api/internal/handler/admin_agent/adminupdateagentwalletbalancehandler.go @@ -0,0 +1,30 @@ +package admin_agent + +import ( + "net/http" + + "tydata-server/app/main/api/internal/logic/admin_agent" + "tydata-server/app/main/api/internal/svc" + "tydata-server/app/main/api/internal/types" + "tydata-server/common/result" + "tydata-server/pkg/lzkit/validator" + + "github.com/zeromicro/go-zero/rest/httpx" +) + +func AdminUpdateAgentWalletBalanceHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.AdminUpdateAgentWalletBalanceReq + 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 := admin_agent.NewAdminUpdateAgentWalletBalanceLogic(r.Context(), svcCtx) + resp, err := l.AdminUpdateAgentWalletBalance(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/main/api/internal/handler/routes.go b/app/main/api/internal/handler/routes.go index ae101eb..f61b267 100644 --- a/app/main/api/internal/handler/routes.go +++ b/app/main/api/internal/handler/routes.go @@ -137,6 +137,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/wallet/:agent_id", Handler: admin_agent.AdminGetAgentWalletHandler(serverCtx), }, + { + Method: http.MethodPost, + Path: "/wallet/update-balance", + Handler: admin_agent.AdminUpdateAgentWalletBalanceHandler(serverCtx), + }, }..., ), rest.WithPrefix("/api/v1/admin/agent"), diff --git a/app/main/api/internal/logic/admin_agent/admingetagentcommissionlistlogic.go b/app/main/api/internal/logic/admin_agent/admingetagentcommissionlistlogic.go index cc8f7f5..eb71f97 100644 --- a/app/main/api/internal/logic/admin_agent/admingetagentcommissionlistlogic.go +++ b/app/main/api/internal/logic/admin_agent/admingetagentcommissionlistlogic.go @@ -2,6 +2,7 @@ package admin_agent import ( "context" + "time" "tydata-server/app/main/api/internal/svc" "tydata-server/app/main/api/internal/types" @@ -37,6 +38,20 @@ func (l *AdminGetAgentCommissionListLogic) AdminGetAgentCommissionList(req *type builder = builder.Where(squirrel.Eq{"status": *req.Status}) } + // 时间范围筛选 + if req.CreateTimeStart != nil && *req.CreateTimeStart != "" { + startTime, err := time.Parse("2006-01-02 15:04:05", *req.CreateTimeStart) + if err == nil { + builder = builder.Where(squirrel.GtOrEq{"create_time": startTime}) + } + } + if req.CreateTimeEnd != nil && *req.CreateTimeEnd != "" { + endTime, err := time.Parse("2006-01-02 15:04:05", *req.CreateTimeEnd) + if err == nil { + builder = builder.Where(squirrel.LtOrEq{"create_time": endTime}) + } + } + // 先查出所有product_id对应的product_name(如有product_name筛选,需反查id) if req.ProductName != nil && *req.ProductName != "" { // 支持模糊匹配产品名称 diff --git a/app/main/api/internal/logic/admin_agent/admingetagentwithdrawallistlogic.go b/app/main/api/internal/logic/admin_agent/admingetagentwithdrawallistlogic.go index 423277f..5930ab2 100644 --- a/app/main/api/internal/logic/admin_agent/admingetagentwithdrawallistlogic.go +++ b/app/main/api/internal/logic/admin_agent/admingetagentwithdrawallistlogic.go @@ -36,6 +36,9 @@ func (l *AdminGetAgentWithdrawalListLogic) AdminGetAgentWithdrawalList(req *type if req.WithdrawNo != nil && *req.WithdrawNo != "" { builder = builder.Where(squirrel.Eq{"withdraw_no": *req.WithdrawNo}) } + if req.WithdrawType != nil { + builder = builder.Where(squirrel.Eq{"withdraw_type": *req.WithdrawType}) + } list, total, err := l.svcCtx.AgentWithdrawalModel.FindPageListByPageWithTotal(l.ctx, builder, req.Page, req.PageSize, "create_time DESC") if err != nil { return nil, err @@ -49,7 +52,7 @@ func (l *AdminGetAgentWithdrawalListLogic) AdminGetAgentWithdrawalList(req *type item.Remark = v.Remark.String } item.CreateTime = v.CreateTime.Format("2006-01-02 15:04:05") - + // 手动设置银行卡信息(copier不会自动处理sql.NullString) item.WithdrawType = v.WithdrawType if v.BankCardNo.Valid { @@ -61,7 +64,7 @@ func (l *AdminGetAgentWithdrawalListLogic) AdminGetAgentWithdrawalList(req *type if v.PayeeName.Valid { item.PayeeName = v.PayeeName.String } - + items = append(items, item) } resp = &types.AdminGetAgentWithdrawalListResp{ diff --git a/app/main/api/internal/logic/admin_agent/adminreviewbankcardwithdrawallogic.go b/app/main/api/internal/logic/admin_agent/adminreviewbankcardwithdrawallogic.go index a60004a..5ea45c3 100644 --- a/app/main/api/internal/logic/admin_agent/adminreviewbankcardwithdrawallogic.go +++ b/app/main/api/internal/logic/admin_agent/adminreviewbankcardwithdrawallogic.go @@ -24,9 +24,9 @@ const ( // 状态常量 const ( - StatusPending = 1 // 申请中/处理中 - StatusSuccess = 2 // 成功 - StatusFailed = 3 // 失败 + StatusPending = 1 // 申请中/处理中 + StatusSuccess = 2 // 成功 + StatusFailed = 3 // 失败 ) // 提现类型常量 @@ -80,9 +80,9 @@ func (l *AdminReviewBankCardWithdrawalLogic) AdminReviewBankCardWithdrawal(req * return errors.Wrapf(xerr.NewErrMsg("该提现记录已处理,无法重复操作"), "状态验证失败") } - // 验证提现类型 - if record.WithdrawType != WithdrawTypeBankCard { - return errors.Wrapf(xerr.NewErrMsg("该记录不是银行卡提现,无法审核"), "提现类型验证失败") + // 验证提现类型(支持银行卡和支付宝提现) + if record.WithdrawType != WithdrawTypeBankCard && record.WithdrawType != WithdrawTypeAlipay { + return errors.Wrapf(xerr.NewErrMsg("提现类型不正确"), "提现类型验证失败") } if req.Action == ReviewActionApprove { @@ -104,6 +104,49 @@ func (l *AdminReviewBankCardWithdrawalLogic) AdminReviewBankCardWithdrawal(req * // 确认提现 func (l *AdminReviewBankCardWithdrawalLogic) approveWithdrawal(ctx context.Context, session sqlx.Session, record *model.AgentWithdrawal) error { + // 根据提现类型执行不同的操作 + if record.WithdrawType == WithdrawTypeAlipay { + // 支付宝提现:先调用支付宝转账接口 + return l.approveAlipayWithdrawal(ctx, session, record) + } else { + // 银行卡提现:直接更新状态为成功(线下转账) + return l.approveBankCardWithdrawal(ctx, session, record) + } +} + +// 确认支付宝提现 +func (l *AdminReviewBankCardWithdrawalLogic) approveAlipayWithdrawal(ctx context.Context, session sqlx.Session, record *model.AgentWithdrawal) error { + // 同步调用支付宝转账 + transferResp, err := l.svcCtx.AlipayService.AliTransfer(ctx, record.PayeeAccount, record.PayeeName.String, record.ActualAmount, "公司提现", record.WithdrawNo) + if err != nil { + l.Logger.Errorf("【支付宝转账失败】withdrawNo:%s error:%v", record.WithdrawNo, err) + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "支付宝接口调用失败: %v", err) + } + + switch { + case transferResp.Status == "SUCCESS": + // 立即处理成功状态 + return l.completeWithdrawalSuccess(ctx, session, record) + case transferResp.Status == "FAIL" || transferResp.SubCode != "": + // 处理明确失败 + errorMsg := l.mapAlipayError(transferResp.SubCode) + return l.completeWithdrawalFailure(ctx, session, record, errorMsg) + case transferResp.Status == "DEALING": + // 处理中状态,更新为处理中但不标记为最终状态 + record.Remark = sql.NullString{String: "支付宝转账处理中", Valid: true} + if _, err := l.svcCtx.AgentWithdrawalModel.Update(ctx, session, record); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新提现记录失败: %v", err) + } + l.Logger.Infof("支付宝提现审核通过,转账处理中 withdrawalId:%d withdrawNo:%s", record.Id, record.WithdrawNo) + return nil + default: + // 未知状态按失败处理 + return l.completeWithdrawalFailure(ctx, session, record, "支付宝返回未知状态") + } +} + +// 确认银行卡提现 +func (l *AdminReviewBankCardWithdrawalLogic) approveBankCardWithdrawal(ctx context.Context, session sqlx.Session, record *model.AgentWithdrawal) error { // 更新提现记录状态为成功 record.Status = StatusSuccess record.Remark = sql.NullString{String: "管理员确认提现", Valid: true} @@ -185,3 +228,126 @@ func (l *AdminReviewBankCardWithdrawalLogic) rejectWithdrawal(ctx context.Contex l.Logger.Infof("银行卡提现拒绝 withdrawalId:%d amount:%f reason:%s", record.Id, record.Amount, remark) return nil } + +// 完成提现成功(支付宝转账成功后调用) +func (l *AdminReviewBankCardWithdrawalLogic) completeWithdrawalSuccess(ctx context.Context, session sqlx.Session, record *model.AgentWithdrawal) error { + // 更新提现记录状态为成功 + record.Status = StatusSuccess + record.Remark = sql.NullString{String: "支付宝转账成功", Valid: true} + if _, err := l.svcCtx.AgentWithdrawalModel.Update(ctx, session, record); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新提现记录失败: %v", err) + } + + // 解冻资金并扣除(FrozenBalance -= amount, Balance不变) + wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(ctx, record.AgentId) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询钱包失败: %v", err) + } + + wallet.FrozenBalance -= record.Amount + if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(ctx, session, wallet); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新钱包失败: %v", err) + } + + // 更新扣税记录状态为成功 + taxModel, err := l.svcCtx.AgentWithdrawalTaxModel.FindOneByWithdrawalId(ctx, record.Id) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err) + } + if taxModel.TaxStatus == model.TaxStatusPending { + taxModel.TaxStatus = model.TaxStatusSuccess // 扣税状态 = 成功 + taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true} + if err := l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(ctx, session, taxModel); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err) + } + } + + // 提现成功后,给上级代理发放提现奖励 + withdrawRewardErr := l.svcCtx.AgentService.GiveWithdrawReward(ctx, record.AgentId, record.Amount, session) + if withdrawRewardErr != nil { + l.Logger.Errorf("发放提现奖励失败,代理ID:%d,提现金额:%f,错误:%+v", record.AgentId, record.Amount, withdrawRewardErr) + // 提现奖励失败不影响主流程,只记录日志 + } else { + l.Logger.Infof("发放提现奖励成功,代理ID:%d,提现金额:%f", record.AgentId, record.Amount) + } + + l.Logger.Infof("支付宝提现成功 withdrawalId:%d withdrawNo:%s", record.Id, record.WithdrawNo) + return nil +} + +// 完成提现失败(支付宝转账失败后调用) +func (l *AdminReviewBankCardWithdrawalLogic) completeWithdrawalFailure(ctx context.Context, session sqlx.Session, record *model.AgentWithdrawal, errorMsg string) error { + // 更新提现记录状态为失败 + record.Status = StatusFailed + record.Remark = sql.NullString{String: errorMsg, Valid: true} + if _, err := l.svcCtx.AgentWithdrawalModel.Update(ctx, session, record); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新提现记录失败: %v", err) + } + + // 解冻资金(FrozenBalance -= amount, Balance += amount) + wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(ctx, record.AgentId) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询钱包失败: %v", err) + } + + wallet.Balance += record.Amount + wallet.FrozenBalance -= record.Amount + if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(ctx, session, wallet); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新钱包失败: %v", err) + } + + // 更新扣税记录状态为失败 + taxModel, err := l.svcCtx.AgentWithdrawalTaxModel.FindOneByWithdrawalId(ctx, record.Id) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err) + } + if taxModel.TaxStatus == model.TaxStatusPending { + taxModel.TaxStatus = model.TaxStatusFailed // 扣税状态 = 失败 + taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true} + if err := l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(ctx, session, taxModel); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err) + } + } + + l.Logger.Infof("支付宝提现失败 withdrawalId:%d withdrawNo:%s reason:%s", record.Id, record.WithdrawNo, errorMsg) + return nil +} + +// 错误类型映射 +func (l *AdminReviewBankCardWithdrawalLogic) mapAlipayError(code string) string { + errorMapping := map[string]string{ + // 账户存在性错误 + "PAYEE_ACCOUNT_NOT_EXSIT": "收款账户不存在,请检查账号是否正确", + "PAYEE_NOT_EXIST": "收款账户不存在或姓名有误,请核实信息", + "PAYEE_ACC_OCUPIED": "收款账号存在多个账户,无法确认唯一性", + "PAYEE_MID_CANNOT_SAME": "收款方和中间方不能是同一个人,请修改收款方或者中间方信息", + + // 实名认证问题 + "PAYEE_CERTIFY_LEVEL_LIMIT": "收款方未完成实名认证", + "PAYEE_NOT_RELNAME_CERTIFY": "收款方未完成实名认证", + "PAYEE_CERT_INFO_ERROR": "收款方证件信息不匹配", + + // 账户状态异常 + "PAYEE_ACCOUNT_STATUS_ERROR": "收款账户状态异常,请更换账号", + "PAYEE_USERINFO_STATUS_ERROR": "收款账户状态异常,无法收款", + "PERMIT_LIMIT_PAYEE": "收款账户异常,请更换账号", + "BLOCK_USER_FORBBIDEN_RECIEVE": "账户冻结无法收款", + "PAYEE_TRUSTEESHIP_ACC_OVER_LIMIT": "收款方托管子户累计收款金额超限", + + // 账户信息错误 + "PAYEE_USERINFO_ERROR": "收款方姓名或信息不匹配", + "PAYEE_CARD_INFO_ERROR": "收款支付宝账号及户名不一致", + "PAYEE_IDENTITY_NOT_MATCH": "收款方身份信息不匹配", + "PAYEE_USER_IS_INST": "收款方为金融机构,不能使用提现功能,请更换收款账号", + "PAYEE_USER_TYPE_ERROR": "该支付宝账号类型不支持提现,请更换收款账号", + + // 权限与限制 + "PAYEE_RECEIVE_COUNT_EXCEED_LIMIT": "收款次数超限,请明日再试", + "PAYEE_OUT_PERMLIMIT_CHECK_FAILURE": "收款方权限校验不通过", + "PERMIT_NON_BANK_LIMIT_PAYEE": "收款方未完善身份信息,无法收款", + } + if msg, ok := errorMapping[code]; ok { + return msg + } + return "系统错误,请联系客服" +} diff --git a/app/main/api/internal/logic/admin_agent/adminupdateagentwalletbalancelogic.go b/app/main/api/internal/logic/admin_agent/adminupdateagentwalletbalancelogic.go new file mode 100644 index 0000000..2106afe --- /dev/null +++ b/app/main/api/internal/logic/admin_agent/adminupdateagentwalletbalancelogic.go @@ -0,0 +1,83 @@ +package admin_agent + +import ( + "context" + "errors" + "fmt" + + "tydata-server/app/main/api/internal/svc" + "tydata-server/app/main/api/internal/types" + "tydata-server/app/main/model" + "tydata-server/common/xerr" + + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) + +type AdminUpdateAgentWalletBalanceLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewAdminUpdateAgentWalletBalanceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateAgentWalletBalanceLogic { + return &AdminUpdateAgentWalletBalanceLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *AdminUpdateAgentWalletBalanceLogic) AdminUpdateAgentWalletBalance(req *types.AdminUpdateAgentWalletBalanceReq) (resp *types.AdminUpdateAgentWalletBalanceResp, err error) { + // 参数校验 + if req.AgentId <= 0 { + return nil, xerr.NewErrMsg("代理ID无效") + } + if req.Amount == 0 { + return nil, xerr.NewErrMsg("修改金额不能为0") + } + + // 查询代理钱包信息 + wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(l.ctx, req.AgentId) + if err != nil { + if errors.Is(err, model.ErrNotFound) { + return nil, xerr.NewErrMsg("代理钱包不存在") + } + return nil, err + } + + // 计算新余额 + newBalance := wallet.Balance + req.Amount + + // 校验余额不能为负数 + if newBalance < 0 { + return nil, xerr.NewErrMsg(fmt.Sprintf("操作后余额不能为负数,当前余额: %.2f,操作金额: %.2f", wallet.Balance, req.Amount)) + } + + // 更新余额 + updateErr := l.svcCtx.AgentWalletModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error { + // 使用版本号更新 + wallet.Balance = newBalance + err := l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet) + if err != nil { + return err + } + + // TODO: 这里可以添加记录余额变更日志的逻辑 + l.Logger.Infof("代理钱包余额变更 - AgentId: %d, 原余额: %.2f, 变更金额: %.2f, 新余额: %.2f", + req.AgentId, wallet.Balance-req.Amount, req.Amount, newBalance) + + return nil + }) + + if updateErr != nil { + l.Logger.Errorf("更新代理钱包余额失败: %+v", updateErr) + return nil, xerr.NewErrMsg("更新余额失败") + } + + resp = &types.AdminUpdateAgentWalletBalanceResp{ + Success: true, + Balance: newBalance, + } + return +} diff --git a/app/main/api/internal/logic/agent/agentwithdrawallogic.go b/app/main/api/internal/logic/agent/agentwithdrawallogic.go index 5914108..998a66d 100644 --- a/app/main/api/internal/logic/agent/agentwithdrawallogic.go +++ b/app/main/api/internal/logic/agent/agentwithdrawallogic.go @@ -53,6 +53,7 @@ func (l *AgentWithdrawalLogic) AgentWithdrawal(req *types.WithdrawalReq) (*types var ( outBizNo string withdrawRes = &types.WithdrawalResp{} + agentID int64 ) var finalWithdrawAmount float64 // 实际到账金额 // 使用事务处理核心操作 @@ -67,6 +68,7 @@ func (l *AgentWithdrawalLogic) AgentWithdrawal(req *types.WithdrawalReq) (*types if err != nil { return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败: %v", err) } + agentID = agentModel.Id // 保存agentId用于日志 agentRealName, err := l.svcCtx.AgentRealNameModel.FindOneByAgentId(l.ctx, agentModel.Id) if err != nil { if errors.Is(err, model.ErrNotFound) { @@ -109,14 +111,14 @@ func (l *AgentWithdrawalLogic) AgentWithdrawal(req *types.WithdrawalReq) (*types ) // 统一扣税逻辑:所有提现都按6%收取税收 - exemptionAmount = 0 // 免税金额 = 0 - TaxStatus = model.TaxStatusPending // 扣税状态 = 待扣税 - taxDeductionPart = req.Amount // 应税金额 = 提现金额 - taxAmount = taxDeductionPart * taxRate // 应缴税费 = 应税金额 * 税率 - finalWithdrawAmount = req.Amount - taxAmount // 实际到账金额 = 提现金额 - 应缴税费 + exemptionAmount = 0 // 免税金额 = 0 + TaxStatus = model.TaxStatusPending // 扣税状态 = 待扣税 + taxDeductionPart = req.Amount // 应税金额 = 提现金额 + taxAmount = taxDeductionPart * taxRate // 应缴税费 = 应税金额 * 税率 + finalWithdrawAmount = req.Amount - taxAmount // 实际到账金额 = 提现金额 - 应缴税费 // 创建提现记录(初始状态为处理中) - withdrawalID, err := l.createWithdrawalRecord(session, agentModel.Id, req.PayeeAccount, req.Amount, finalWithdrawAmount, taxAmount, outBizNo) + withdrawalID, err := l.createWithdrawalRecord(session, agentModel.Id, req.PayeeAccount, req.PayeeName, req.Amount, finalWithdrawAmount, taxAmount, outBizNo) if err != nil { return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建提现记录失败: %v", err) } @@ -146,34 +148,12 @@ func (l *AgentWithdrawalLogic) AgentWithdrawal(req *types.WithdrawalReq) (*types return nil, err } - // 同步调用支付宝转账 - transferResp, err := l.svcCtx.AlipayService.AliTransfer(l.ctx, req.PayeeAccount, req.PayeeName, finalWithdrawAmount, "公司提现", outBizNo) - if err != nil { - l.Logger.Errorf("【支付宝转账失败】outBizNo:%s error:%v", outBizNo, err) - l.handleTransferError(outBizNo, err, "支付宝接口调用失败") - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "支付宝接口调用失败: %v", err) - } + // 支付宝提现不再直接调用转账接口,改为先申请后审核 + // 直接返回申请中状态,等待管理员审核 + withdrawRes.Status = WithdrawStatusProcessing + withdrawRes.FailMsg = "" - switch { - case transferResp.Status == "SUCCESS": - // 立即处理成功状态 - l.handleTransferSuccess(outBizNo, transferResp) - withdrawRes.Status = WithdrawStatusSuccess - case transferResp.Status == "FAIL" || transferResp.SubCode != "": - // 处理明确失败 - errorMsg := l.mapAlipayError(transferResp.SubCode) - l.handleTransferFailure(outBizNo, transferResp) - withdrawRes.Status = WithdrawStatusFailed - withdrawRes.FailMsg = errorMsg - case transferResp.Status == "DEALING": - // 处理中状态,启动异步轮询 - go l.startAsyncPolling(outBizNo) - withdrawRes.Status = WithdrawStatusProcessing - default: - // 未知状态按失败处理 - l.handleTransferError(outBizNo, fmt.Errorf("未知状态:%s", transferResp.Status), "支付宝返回未知状态") - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "支付宝接口调用失败: %v", err) - } + l.Logger.Infof("支付宝提现申请成功 outBizNo:%s agentId:%d amount:%f", outBizNo, agentID, req.Amount) return withdrawRes, nil } @@ -217,12 +197,13 @@ func (l *AgentWithdrawalLogic) mapAlipayError(code string) string { } // 创建提现记录(事务内操作) -func (l *AgentWithdrawalLogic) createWithdrawalRecord(session sqlx.Session, agentID int64, payeeAccount string, amount float64, finalWithdrawAmount float64, taxAmount float64, outBizNo string) (int64, error) { +func (l *AgentWithdrawalLogic) createWithdrawalRecord(session sqlx.Session, agentID int64, payeeAccount string, payeeName string, amount float64, finalWithdrawAmount float64, taxAmount float64, outBizNo string) (int64, error) { record := &model.AgentWithdrawal{ AgentId: agentID, WithdrawType: 1, // 支付宝提现 WithdrawNo: outBizNo, PayeeAccount: payeeAccount, + PayeeName: sql.NullString{String: payeeName, Valid: true}, // 设置收款人姓名 Amount: amount, ActualAmount: finalWithdrawAmount, TaxAmount: taxAmount, diff --git a/app/main/api/internal/logic/agent/bankcardwithdrawallogic.go b/app/main/api/internal/logic/agent/bankcardwithdrawallogic.go index b17eed7..14ddfb5 100644 --- a/app/main/api/internal/logic/agent/bankcardwithdrawallogic.go +++ b/app/main/api/internal/logic/agent/bankcardwithdrawallogic.go @@ -118,11 +118,11 @@ func (l *BankCardWithdrawalLogic) BankCardWithdrawal(req *types.BankCardWithdraw ) // 统一扣税逻辑:所有提现都按6%收取税收 - exemptionAmount = 0 // 免税金额 = 0 - TaxStatus = model.TaxStatusPending // 扣税状态 = 待扣税 - taxDeductionPart = req.Amount // 应税金额 = 提现金额 - taxAmount = taxDeductionPart * taxRate // 应缴税费 = 应税金额 * 税率 - finalWithdrawAmount = req.Amount - taxAmount // 实际到账金额 = 提现金额 - 应缴税费 + exemptionAmount = 0 // 免税金额 = 0 + TaxStatus = model.TaxStatusPending // 扣税状态 = 待扣税 + taxDeductionPart = req.Amount // 应税金额 = 提现金额 + taxAmount = taxDeductionPart * taxRate // 应缴税费 = 应税金额 * 税率 + finalWithdrawAmount = req.Amount - taxAmount // 实际到账金额 = 提现金额 - 应缴税费 // 创建提现记录(初始状态为申请中,提现类型为银行卡) withdrawalID, err := l.createBankCardWithdrawalRecord(session, agentModel.Id, req.BankCardNo, req.BankName, agentRealName.Name, req.Amount, finalWithdrawAmount, taxAmount, outBizNo) diff --git a/app/main/api/internal/logic/agent/getbankcardinfologic.go b/app/main/api/internal/logic/agent/getbankcardinfologic.go index 58f965a..6e7df40 100644 --- a/app/main/api/internal/logic/agent/getbankcardinfologic.go +++ b/app/main/api/internal/logic/agent/getbankcardinfologic.go @@ -62,7 +62,7 @@ func (l *GetBankCardInfoLogic) GetBankCardInfo(req *types.GetBankCardInfoReq) (r builder := l.svcCtx.AgentWithdrawalModel.SelectBuilder() builder = builder.Where(squirrel.Eq{"agent_id": agentModel.Id}) builder = builder.Where(squirrel.Eq{"withdraw_type": 2}) // 银行卡提现 - builder = builder.Where(squirrel.Eq{"status": 2}) // 成功状态 + builder = builder.Where(squirrel.Eq{"status": 2}) // 成功状态 builder = builder.OrderBy("create_time DESC") builder = builder.Limit(1) diff --git a/app/main/api/internal/queue/unfreezeCommission.go b/app/main/api/internal/queue/unfreezeCommission.go index 67ddb49..2862c7c 100644 --- a/app/main/api/internal/queue/unfreezeCommission.go +++ b/app/main/api/internal/queue/unfreezeCommission.go @@ -35,7 +35,6 @@ func NewUnfreezeCommissionHandler(svcCtx *svc.ServiceContext) *UnfreezeCommissio func (l *UnfreezeCommissionHandler) ProcessTask(ctx context.Context, t *asynq.Task) error { now := time.Now() logx.Infof("%s - 开始执行佣金解冻任务", now.Format("2006-01-02 15:04:05")) - // 解析任务payload,获取佣金ID var payload types.MsgUnfreezeCommissionPayload if err := json.Unmarshal(t.Payload(), &payload); err != nil { diff --git a/app/main/api/internal/types/types.go b/app/main/api/internal/types/types.go index c3c1eb3..4b5c5d6 100644 --- a/app/main/api/internal/types/types.go +++ b/app/main/api/internal/types/types.go @@ -224,12 +224,14 @@ type AdminGetAgentCommissionDeductionListResp struct { } type AdminGetAgentCommissionListReq struct { - Page int64 `form:"page"` // 页码 - PageSize int64 `form:"pageSize"` // 每页数量 - AgentId *int64 `form:"agent_id,optional"` // 代理ID(可选) - OrderId *int64 `form:"order_id,optional"` // 订单ID(可选) - ProductName *string `form:"product_name,optional"` // 产品名(可选) - Status *int64 `form:"status,optional"` // 状态(可选) + Page int64 `form:"page"` // 页码 + PageSize int64 `form:"pageSize"` // 每页数量 + AgentId *int64 `form:"agent_id,optional"` // 代理ID(可选) + OrderId *int64 `form:"order_id,optional"` // 订单ID(可选) + ProductName *string `form:"product_name,optional"` // 产品名(可选) + Status *int64 `form:"status,optional"` // 状态(可选) + CreateTimeStart *string `form:"create_time_start,optional"` // 创建时间开始(可选) + CreateTimeEnd *string `form:"create_time_end,optional"` // 创建时间结束(可选) } type AdminGetAgentCommissionListResp struct { @@ -362,11 +364,12 @@ type AdminGetAgentWalletResp struct { } type AdminGetAgentWithdrawalListReq struct { - Page int64 `form:"page"` // 页码 - PageSize int64 `form:"pageSize"` // 每页数量 - AgentId *int64 `form:"agent_id,optional"` // 代理ID(可选) - Status *int64 `form:"status,optional"` // 状态(可选) - WithdrawNo *string `form:"withdraw_no,optional"` // 提现单号(可选) + Page int64 `form:"page"` // 页码 + PageSize int64 `form:"pageSize"` // 每页数量 + AgentId *int64 `form:"agent_id,optional"` // 代理ID(可选) + Status *int64 `form:"status,optional"` // 状态(可选) + WithdrawNo *string `form:"withdraw_no,optional"` // 提现单号(可选) + WithdrawType *int64 `form:"withdraw_type,optional"` // 提现类型(可选)1-支付宝,2-银行卡 } type AdminGetAgentWithdrawalListResp struct { @@ -849,6 +852,16 @@ type AdminUpdateAgentProductionConfigResp struct { Success bool `json:"success"` // 是否成功 } +type AdminUpdateAgentWalletBalanceReq struct { + AgentId int64 `json:"agent_id"` // 代理ID + Amount float64 `json:"amount"` // 修改金额(正数增加,负数减少) +} + +type AdminUpdateAgentWalletBalanceResp struct { + Success bool `json:"success"` // 是否成功 + Balance float64 `json:"balance"` // 修改后的余额 +} + type AdminUpdateApiReq struct { Id int64 `path:"id"` ApiName string `json:"api_name"`