新增扣税
This commit is contained in:
		| @@ -2,6 +2,7 @@ package agent | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"database/sql" | ||||
| 	"fmt" | ||||
| 	"time" | ||||
| 	"tydata-server/app/main/model" | ||||
| @@ -53,7 +54,7 @@ func (l *AgentWithdrawalLogic) AgentWithdrawal(req *types.WithdrawalReq) (*types | ||||
| 		outBizNo    string | ||||
| 		withdrawRes = &types.WithdrawalResp{} | ||||
| 	) | ||||
|  | ||||
| 	var finalWithdrawAmount float64 // 实际到账金额 | ||||
| 	// 使用事务处理核心操作 | ||||
| 	err := l.svcCtx.AgentModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error { | ||||
| 		userID, err := ctxdata.GetUidFromCtx(l.ctx) | ||||
| @@ -93,16 +94,82 @@ func (l *AgentWithdrawalLogic) AgentWithdrawal(req *types.WithdrawalReq) (*types | ||||
| 		// 生成交易号 | ||||
| 		outBizNo = "W_" + l.svcCtx.AlipayService.GenerateOutTradeNo() | ||||
|  | ||||
| 		// 创建提现记录(初始状态为处理中) | ||||
| 		if err = l.createWithdrawalRecord(session, agentModel.Id, req, outBizNo); err != nil { | ||||
| 			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建提现记录失败: %v", err) | ||||
| 		} | ||||
|  | ||||
| 		// 冻结资金(事务内操作) | ||||
| 		if err = l.freezeFunds(session, agentWallet, req.Amount); err != nil { | ||||
| 			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "资金冻结失败: %v", err) | ||||
| 		} | ||||
| 		yearMonth := int64(time.Now().Year()*100 + int(time.Now().Month())) | ||||
| 		// 计算税务额度 | ||||
| 		taxExemption, err := l.svcCtx.AgentWithdrawalTaxExemptionModel.FindOneByAgentIdYearMonth(l.ctx, agentModel.Id, yearMonth) | ||||
| 		if err != nil { | ||||
| 			if errors.Is(err, model.ErrNotFound) { | ||||
| 				taxExemption, err = l.createMonthlyExemption(session, agentModel.Id, yearMonth) | ||||
| 				if err != nil { | ||||
| 					return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建代理税务额度失败: %v", err) | ||||
| 				} | ||||
| 			} else { | ||||
| 				return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理税务额度失败: %v", err) | ||||
| 			} | ||||
| 		} | ||||
| 		var taxAmount float64        // 应缴税费 | ||||
| 		var taxDeductionPart float64 // 应税金额 | ||||
| 		var TaxStatus int64          // 扣税状态 | ||||
| 		var exemptionAmount float64  // 免税金额 | ||||
| 		taxRate := l.svcCtx.Config.TaxConfig.TaxRate | ||||
|  | ||||
| 		if taxExemption.RemainingExemptionAmount < req.Amount { | ||||
| 			// 超过免税额度需要扣税 | ||||
| 			exemptionAmount = taxExemption.RemainingExemptionAmount               // 免税金额 = 剩余免税额度 | ||||
| 			TaxStatus = model.TaxStatusPending                                    // 扣税状态 = 待扣税 | ||||
| 			taxDeductionPart = req.Amount - taxExemption.RemainingExemptionAmount // 应税金额 = 提现金额 - 剩余免税额度 | ||||
| 			taxAmount = taxDeductionPart * taxRate                                // 应缴税费 = 应税金额 * 税率 | ||||
| 			finalWithdrawAmount = req.Amount - taxAmount                          // 实际到账金额 = 提现金额 - 应缴税费 | ||||
|  | ||||
| 			taxExemption.UsedExemptionAmount += exemptionAmount      // 已使用免税额度 = 已使用免税额度 + 免税金额 | ||||
| 			taxExemption.RemainingExemptionAmount -= exemptionAmount // 剩余免税额度 = 剩余免税额度 - 免税金额 | ||||
| 			err = l.svcCtx.AgentWithdrawalTaxExemptionModel.UpdateWithVersion(l.ctx, session, taxExemption) | ||||
| 			if err != nil { | ||||
| 				return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新代理税务额度失败: %v", err) | ||||
| 			} | ||||
| 		} else { | ||||
| 			// 未超过免税额度,免税 | ||||
| 			exemptionAmount = req.Amount                             // 免税金额 = 提现金额 | ||||
| 			TaxStatus = model.TaxStatusExempt                        // 扣税状态 = 免税 | ||||
| 			taxDeductionPart = 0                                     // 应税金额 = 0 | ||||
| 			finalWithdrawAmount = req.Amount                         // 实际到账金额 = 提现金额 | ||||
| 			taxAmount = 0                                            // 应缴税费 = 0 | ||||
| 			taxExemption.UsedExemptionAmount += exemptionAmount      // 已使用免税额度 = 已使用免税额度 + 免税金额 | ||||
| 			taxExemption.RemainingExemptionAmount -= exemptionAmount // 剩余免税额度 = 剩余免税额度 - 免税金额 | ||||
| 			err = l.svcCtx.AgentWithdrawalTaxExemptionModel.UpdateWithVersion(l.ctx, session, taxExemption) | ||||
| 			if err != nil { | ||||
| 				return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新代理税务额度失败: %v", err) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// 创建提现记录(初始状态为处理中) | ||||
| 		withdrawalID, err := l.createWithdrawalRecord(session, agentModel.Id, req.PayeeAccount, req.Amount, finalWithdrawAmount, taxAmount, outBizNo) | ||||
| 		if err != nil { | ||||
| 			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建提现记录失败: %v", err) | ||||
| 		} | ||||
| 		// 扣税记录 | ||||
| 		taxModel := &model.AgentWithdrawalTax{ | ||||
| 			AgentId:           agentModel.Id, | ||||
| 			YearMonth:         yearMonth, | ||||
| 			WithdrawalId:      withdrawalID, | ||||
| 			WithdrawalAmount:  req.Amount, | ||||
| 			ExemptionAmount:   exemptionAmount, | ||||
| 			TaxableAmount:     taxDeductionPart, | ||||
| 			TaxRate:           taxRate, | ||||
| 			TaxAmount:         taxAmount, | ||||
| 			ActualAmount:      finalWithdrawAmount, | ||||
| 			TaxStatus:         TaxStatus, | ||||
| 			Remark:            sql.NullString{String: "提现成功自动扣税", Valid: true}, | ||||
| 			ExemptionRecordId: taxExemption.Id, | ||||
| 		} | ||||
| 		_, err = l.svcCtx.AgentWithdrawalTaxModel.Insert(ctx, session, taxModel) | ||||
| 		if err != nil { | ||||
| 			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建扣税记录失败: %v", err) | ||||
| 		} | ||||
| 		return nil | ||||
| 	}) | ||||
|  | ||||
| @@ -111,7 +178,7 @@ func (l *AgentWithdrawalLogic) AgentWithdrawal(req *types.WithdrawalReq) (*types | ||||
| 	} | ||||
|  | ||||
| 	// 同步调用支付宝转账 | ||||
| 	transferResp, err := l.svcCtx.AlipayService.AliTransfer(l.ctx, req.PayeeAccount, req.PayeeName, req.Amount, "代理提现", outBizNo) | ||||
| 	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, "支付宝接口调用失败") | ||||
| @@ -181,17 +248,22 @@ func (l *AgentWithdrawalLogic) mapAlipayError(code string) string { | ||||
| } | ||||
|  | ||||
| // 创建提现记录(事务内操作) | ||||
| func (l *AgentWithdrawalLogic) createWithdrawalRecord(session sqlx.Session, agentID int64, req *types.WithdrawalReq, outBizNo string) error { | ||||
| func (l *AgentWithdrawalLogic) createWithdrawalRecord(session sqlx.Session, agentID int64, payeeAccount string, amount float64, finalWithdrawAmount float64, taxAmount float64, outBizNo string) (int64, error) { | ||||
| 	record := &model.AgentWithdrawal{ | ||||
| 		AgentId:      agentID, | ||||
| 		WithdrawNo:   outBizNo, | ||||
| 		PayeeAccount: req.PayeeAccount, | ||||
| 		Amount:       req.Amount, | ||||
| 		PayeeAccount: payeeAccount, | ||||
| 		Amount:       amount, | ||||
| 		ActualAmount: finalWithdrawAmount, | ||||
| 		TaxAmount:    taxAmount, | ||||
| 		Status:       StatusProcessing, | ||||
| 	} | ||||
|  | ||||
| 	_, err := l.svcCtx.AgentWithdrawalModel.Insert(l.ctx, session, record) | ||||
| 	return err | ||||
| 	result, err := l.svcCtx.AgentWithdrawalModel.Insert(l.ctx, session, record) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return result.LastInsertId() | ||||
| } | ||||
|  | ||||
| // 冻结资金(事务内操作) | ||||
| @@ -266,7 +338,6 @@ func (l *AgentWithdrawalLogic) updateWithdrawalStatus(outBizNo string, status in | ||||
| 		if _, err = l.svcCtx.AgentWithdrawalModel.Update(ctx, session, record); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		// 失败时解冻资金 | ||||
| 		if status == StatusFailed { | ||||
| 			wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(ctx, record.AgentId) | ||||
| @@ -279,6 +350,27 @@ func (l *AgentWithdrawalLogic) updateWithdrawalStatus(outBizNo string, status in | ||||
| 			if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(ctx, session, wallet); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			taxModel, err := l.svcCtx.AgentWithdrawalTaxModel.FindOneByWithdrawalId(ctx, record.Id) | ||||
| 			if err != nil { | ||||
| 				return 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) | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			taxExemption, err := l.svcCtx.AgentWithdrawalTaxExemptionModel.FindOne(ctx, taxModel.ExemptionRecordId) | ||||
| 			if err != nil { | ||||
| 				return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理税务额度失败: %v", err) | ||||
| 			} | ||||
| 			taxExemption.UsedExemptionAmount -= taxModel.ExemptionAmount | ||||
| 			taxExemption.RemainingExemptionAmount += taxModel.ExemptionAmount | ||||
| 			if err := l.svcCtx.AgentWithdrawalTaxExemptionModel.UpdateWithVersion(ctx, session, taxExemption); err != nil { | ||||
| 				return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新代理税务额度失败: %v", err) | ||||
| 			} | ||||
| 		} | ||||
| 		if status == StatusSuccess { | ||||
| 			wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(ctx, record.AgentId) | ||||
| @@ -290,6 +382,17 @@ func (l *AgentWithdrawalLogic) updateWithdrawalStatus(outBizNo string, status in | ||||
| 			if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(ctx, session, wallet); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			taxModel, err := l.svcCtx.AgentWithdrawalTaxModel.FindOneByWithdrawalId(ctx, record.Id) | ||||
| 			if err != nil { | ||||
| 				return 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) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return nil | ||||
| 	}) | ||||
| @@ -326,3 +429,22 @@ func (l *AgentWithdrawalLogic) handleTransferError(outBizNo string, err error, c | ||||
| 	l.updateWithdrawalStatus(outBizNo, StatusFailed, "系统处理异常") | ||||
| 	l.Logger.Errorf("%s outBizNo:%s error:%v", contextMsg, outBizNo, err) | ||||
| } | ||||
|  | ||||
| func (l *AgentWithdrawalLogic) createMonthlyExemption(session sqlx.Session, agentId int64, yearMonth int64) (*model.AgentWithdrawalTaxExemption, error) { | ||||
| 	exemption := &model.AgentWithdrawalTaxExemption{ | ||||
| 		AgentId:                  agentId, | ||||
| 		YearMonth:                yearMonth, | ||||
| 		TotalExemptionAmount:     l.svcCtx.Config.TaxConfig.TaxExemptionAmount, | ||||
| 		UsedExemptionAmount:      0.00, | ||||
| 		RemainingExemptionAmount: l.svcCtx.Config.TaxConfig.TaxExemptionAmount, | ||||
| 	} | ||||
|  | ||||
| 	result, err := l.svcCtx.AgentWithdrawalTaxExemptionModel.Insert(l.ctx, session, exemption) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	id, _ := result.LastInsertId() | ||||
| 	exemption.Id = id | ||||
| 	return exemption, nil | ||||
| } | ||||
|   | ||||
| @@ -151,6 +151,20 @@ func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *type | ||||
| 		if insertAgentWalletModelErr != nil { | ||||
| 			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 新增代理钱包失败: %+v", insertAgentWalletModelErr) | ||||
| 		} | ||||
|  | ||||
| 		// 新增税务额度 | ||||
| 		agentWithdrawalTaxExemption := model.AgentWithdrawalTaxExemption{ | ||||
| 			AgentId:                  agentID, | ||||
| 			YearMonth:                int64(time.Now().Year()*100 + int(time.Now().Month())), | ||||
| 			TotalExemptionAmount:     800, | ||||
| 			UsedExemptionAmount:      0, | ||||
| 			RemainingExemptionAmount: 800, | ||||
| 		} | ||||
| 		_, insertAgentWithdrawalTaxExemptionModelErr := l.svcCtx.AgentWithdrawalTaxExemptionModel.Insert(transCtx, session, &agentWithdrawalTaxExemption) | ||||
| 		if insertAgentWithdrawalTaxExemptionModelErr != nil { | ||||
| 			return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 新增代理税务额度失败: %+v", insertAgentWithdrawalTaxExemptionModelErr) | ||||
| 		} | ||||
|  | ||||
| 		return nil | ||||
| 	}) | ||||
| 	if transErr != nil { | ||||
|   | ||||
| @@ -0,0 +1,79 @@ | ||||
| package agent | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"time" | ||||
|  | ||||
| 	"tydata-server/app/main/api/internal/svc" | ||||
| 	"tydata-server/app/main/api/internal/types" | ||||
| 	"tydata-server/app/main/model" | ||||
| 	"tydata-server/common/ctxdata" | ||||
| 	"tydata-server/common/xerr" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/zeromicro/go-zero/core/logx" | ||||
| ) | ||||
|  | ||||
| type GetAgentWithdrawalTaxExemptionLogic struct { | ||||
| 	logx.Logger | ||||
| 	ctx    context.Context | ||||
| 	svcCtx *svc.ServiceContext | ||||
| } | ||||
|  | ||||
| func NewGetAgentWithdrawalTaxExemptionLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAgentWithdrawalTaxExemptionLogic { | ||||
| 	return &GetAgentWithdrawalTaxExemptionLogic{ | ||||
| 		Logger: logx.WithContext(ctx), | ||||
| 		ctx:    ctx, | ||||
| 		svcCtx: svcCtx, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (l *GetAgentWithdrawalTaxExemptionLogic) GetAgentWithdrawalTaxExemption(req *types.GetWithdrawalTaxExemptionReq) (resp *types.GetWithdrawalTaxExemptionResp, err error) { | ||||
| 	userID, err := ctxdata.GetUidFromCtx(l.ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户ID失败: %+v", err) | ||||
| 	} | ||||
| 	agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理ID失败: %+v", err) | ||||
| 	} | ||||
| 	yearMonth := int64(time.Now().Year()*100 + int(time.Now().Month())) | ||||
|  | ||||
| 	agentWithdrawalTaxExemption, err := l.svcCtx.AgentWithdrawalTaxExemptionModel.FindOneByAgentIdYearMonth(l.ctx, agent.Id, yearMonth) | ||||
| 	if err != nil { | ||||
| 		if errors.Is(err, model.ErrNotFound) { | ||||
| 			agentWithdrawalTaxExemption, err = l.createMonthlyExemption(agent.Id, yearMonth) | ||||
| 			if err != nil { | ||||
| 				return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建代理税务额度失败: %v", err) | ||||
| 			} | ||||
| 		} else { | ||||
| 			return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理税务额度失败: %+v", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return &types.GetWithdrawalTaxExemptionResp{ | ||||
| 		TotalExemptionAmount:     agentWithdrawalTaxExemption.TotalExemptionAmount, | ||||
| 		UsedExemptionAmount:      agentWithdrawalTaxExemption.UsedExemptionAmount, | ||||
| 		RemainingExemptionAmount: agentWithdrawalTaxExemption.RemainingExemptionAmount, | ||||
| 		TaxRate:                  l.svcCtx.Config.TaxConfig.TaxRate, | ||||
| 	}, nil | ||||
| } | ||||
| ``` | ||||
| func (l *GetAgentWithdrawalTaxExemptionLogic) createMonthlyExemption(agentId int64, yearMonth int64) (*model.AgentWithdrawalTaxExemption, error) { | ||||
| 	exemption := &model.AgentWithdrawalTaxExemption{ | ||||
| 		AgentId:                  agentId, | ||||
| 		YearMonth:                yearMonth, | ||||
| 		TotalExemptionAmount:     l.svcCtx.Config.TaxConfig.TaxExemptionAmount, | ||||
| 		UsedExemptionAmount:      0.00, | ||||
| 		RemainingExemptionAmount: l.svcCtx.Config.TaxConfig.TaxExemptionAmount, | ||||
| 	} | ||||
|  | ||||
| 	result, err := l.svcCtx.AgentWithdrawalTaxExemptionModel.Insert(l.ctx, nil, exemption) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	id, _ := result.LastInsertId() | ||||
| 	exemption.Id = id | ||||
| 	return exemption, nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user