chore: 并入 iotlcm-admin-svr 历史到 admin-svr/(原提交 49818c6)
This commit is contained in:
@@ -0,0 +1,837 @@
|
||||
// Package gen
|
||||
// @Link https://github.com/xiujiecn/xiu-admin
|
||||
// @Copyright Copyright (c) 2026 LiXiujie
|
||||
// @Author Lxj <xxx@example.com>
|
||||
// @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
||||
// @AutoGenerate Version
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/dao"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/batchimport"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm/handler"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm/hook"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/entity"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/service"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/convert"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/excel"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type sCommonAgentBalance struct{}
|
||||
|
||||
func NewCommonAgentBalance() *sCommonAgentBalance {
|
||||
return &sCommonAgentBalance{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
service.RegisterCommonAgentBalance(NewCommonAgentBalance())
|
||||
}
|
||||
|
||||
// Model 企业客户财务信息ORM模型
|
||||
func (s *sCommonAgentBalance) Model(ctx context.Context, option ...*handler.Option) *gdb.Model {
|
||||
if len(option) == 0 {
|
||||
option = append(option, &handler.Option{
|
||||
FilterTenant: true,
|
||||
FilterAuth: true,
|
||||
})
|
||||
}
|
||||
return handler.Model(dao.TAgentBalance.Ctx(ctx), option...)
|
||||
}
|
||||
|
||||
// List 获取企业客户财务信息列表
|
||||
func (s *sCommonAgentBalance) List(ctx context.Context, in *model.TAgentBalanceListParam) (list []*model.TAgentBalanceListModel, totalCount int, err error) {
|
||||
mod := s.Model(ctx)
|
||||
deptId := contexts.GetDeptId(ctx)
|
||||
|
||||
mod = mod.Fields(model.TAgentBalanceListModel{})
|
||||
mod = mod.Where(dao.TAgentBalance.Columns().DeptId, deptId)
|
||||
|
||||
if in.Id > 0 {
|
||||
mod = mod.Where(dao.TAgentBalance.Columns().Id, in.Id)
|
||||
}
|
||||
if in.WithdrawAmountStatus > 0 {
|
||||
mod = mod.Where(dao.TAgentBalance.Columns().WithdrawAmountStatus, in.WithdrawAmountStatus)
|
||||
}
|
||||
if in.Status > 0 {
|
||||
mod = mod.Where(dao.TAgentBalance.Columns().Status, in.Status)
|
||||
}
|
||||
if len(in.CreatedAt) == 2 {
|
||||
in.CreatedAt[1] = in.CreatedAt[1].EndOfDay()
|
||||
}
|
||||
if len(in.CreatedAt) == 2 {
|
||||
mod = mod.WhereBetween(dao.TAgentBalance.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1])
|
||||
}
|
||||
|
||||
mod = mod.Page(in.Page, in.PageSize)
|
||||
mod = mod.OrderDesc(dao.TAgentBalance.Columns().Id)
|
||||
mod = mod.Hook(hook.MemberSummary)
|
||||
|
||||
if err = mod.ScanAndCount(&list, &totalCount, false); err != nil {
|
||||
err = gerror.Wrap(err, "获取企业客户财务信息列表失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Export 导出企业客户财务信息
|
||||
func (s *sCommonAgentBalance) Export(ctx context.Context, in *model.TAgentBalanceListParam) (err error) {
|
||||
list, totalCount, err := s.List(ctx, in)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tags, err := convert.GetEntityDescTags(model.TAgentBalanceExportModel{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
fileName = "导出企业客户财务信息-" + gctx.CtxId(ctx)
|
||||
sheetName = fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", totalCount, (totalCount+in.PageSize-1)/in.PageSize, in.Page, len(list))
|
||||
exports []model.TAgentBalanceExportModel
|
||||
)
|
||||
|
||||
if err = gconv.Scan(list, &exports); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName)
|
||||
return
|
||||
}
|
||||
|
||||
// Edit 修改/新增企业客户财务信息
|
||||
func (s *sCommonAgentBalance) Edit(ctx context.Context, in *model.TAgentBalanceEditParam) (err error) {
|
||||
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
|
||||
if in.Id > 0 {
|
||||
updatedBy := contexts.GetUserId(ctx)
|
||||
in.UpdatedBy = &updatedBy
|
||||
in.UpdatedAt = gtime.Now()
|
||||
if _, err = s.Model(ctx).
|
||||
Fields(model.TAgentBalanceUpdateFields{}).
|
||||
WherePri(in.Id).Data(in).Update(); err != nil {
|
||||
err = gerror.Wrap(err, "修改企业客户财务信息失败,请稍后重试!")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
tenantId := contexts.GetTenantId(ctx)
|
||||
in.TenantId = &tenantId
|
||||
createdDept := contexts.GetDeptId(ctx)
|
||||
in.CreatedDept = &createdDept
|
||||
createdBy := contexts.GetUserId(ctx)
|
||||
in.CreatedBy = &createdBy
|
||||
in.CreatedAt = gtime.Now()
|
||||
if _, err = s.Model(ctx, &handler.Option{FilterAuth: false}).
|
||||
Fields(model.TAgentBalanceInsertFields{}).
|
||||
Data(in).Insert(); err != nil {
|
||||
err = gerror.Wrap(err, "新增企业客户财务信息失败,请稍后重试!")
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
// Delete 删除企业客户财务信息
|
||||
func (s *sCommonAgentBalance) Delete(ctx context.Context, in *model.TAgentBalanceDeleteParam) (err error) {
|
||||
if _, err = s.Model(ctx).WherePri(in.Id).Unscoped().Delete(); err != nil {
|
||||
err = gerror.Wrap(err, "删除企业客户财务信息失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// View 获取企业客户财务信息指定信息
|
||||
func (s *sCommonAgentBalance) View(ctx context.Context, in *model.TAgentBalanceViewParam) (res *model.TAgentBalanceViewModel, err error) {
|
||||
if err = s.Model(ctx).WherePri(in.Id).Hook(hook.MemberSummary).Scan(&res); err != nil {
|
||||
err = gerror.Wrap(err, "获取企业客户财务信息信息,请稍后重试!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Status 更新企业客户财务信息状态
|
||||
func (s *sCommonAgentBalance) Status(ctx context.Context, in *model.TAgentBalanceStatusParam) (err error) {
|
||||
if _, err = s.Model(ctx).WherePri(in.Id).Data(g.Map{
|
||||
dao.TAgentBalance.Columns().Status: in.Status,
|
||||
dao.TAgentBalance.Columns().UpdatedBy: contexts.GetUserId(ctx),
|
||||
}).Update(); err != nil {
|
||||
err = gerror.Wrap(err, "更新企业客户财务信息状态失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetAccountBalance 获取当前登录企业的账户余额信息。
|
||||
func (s *sCommonAgentBalance) GetAccountBalance(ctx context.Context, in *model.TAgentBalanceTrendParam) (res *model.TAgentBalanceChartData, err error) {
|
||||
res = &model.TAgentBalanceChartData{}
|
||||
deptId := contexts.GetDeptId(ctx)
|
||||
|
||||
months, startTime, endTime, err := agentBalanceMonthRange(in.StartMonth, in.EndMonth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
balanceMap, err := s.getMonthlyLastBalance(ctx, dao.TBalanceDetail.Ctx(ctx),
|
||||
dao.TBalanceDetail.Columns().TransactionTime, dao.TBalanceDetail.Columns().BalanceAfter,
|
||||
dao.TBalanceDetail.Columns().DeptId, deptId, startTime, endTime, "余额趋势")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
withdrawableMap, err := s.getMonthlyLastBalance(ctx, dao.TFinWithdrawableChange.Ctx(ctx),
|
||||
dao.TFinWithdrawableChange.Columns().CreatedAt, dao.TFinWithdrawableChange.Columns().AfterBalance,
|
||||
dao.TFinWithdrawableChange.Columns().DeptId, deptId, startTime, endTime, "可提现金额趋势")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
creditMap, err := s.getMonthlyLastBalance(ctx, dao.TCreditDetail.Ctx(ctx),
|
||||
dao.TCreditDetail.Columns().TransactionTime, dao.TCreditDetail.Columns().CreditBalanceAfter,
|
||||
dao.TCreditDetail.Columns().DeptId, deptId, startTime, endTime, "信用额度趋势")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
balanceValues := make([]float64, 0, len(months))
|
||||
withdrawableValues := make([]float64, 0, len(months))
|
||||
creditValues := make([]float64, 0, len(months))
|
||||
for _, month := range months {
|
||||
balanceValues = append(balanceValues, balanceMap[month])
|
||||
withdrawableValues = append(withdrawableValues, withdrawableMap[month])
|
||||
creditValues = append(creditValues, creditMap[month])
|
||||
}
|
||||
|
||||
res.Labels = months
|
||||
res.Series = []*model.TAgentBalanceChartSeries{
|
||||
{Name: "余额", Values: balanceValues},
|
||||
{Name: "可提现金额", Values: withdrawableValues},
|
||||
{Name: "信用额度", Values: creditValues},
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getMonthlyLastBalance 查询指定月份范围内每月最后一条记录的余额。
|
||||
func (s *sCommonAgentBalance) getMonthlyLastBalance(ctx context.Context, mod *gdb.Model, timeColumn string, balanceColumn string, deptIdColumn string, deptId interface{}, startTime, endTime time.Time, errMsg string) (map[string]float64, error) {
|
||||
type maxTimeRow struct {
|
||||
AccountPeriod string `orm:"account_period"`
|
||||
MaxTime string `orm:"max_time"`
|
||||
}
|
||||
var maxTimes []*maxTimeRow
|
||||
if err := mod.Fields("DATE_FORMAT("+timeColumn+", '%Y-%m') as account_period, MAX("+timeColumn+") as max_time").
|
||||
Where(deptIdColumn, deptId).
|
||||
WhereGTE(timeColumn, startTime).
|
||||
WhereLT(timeColumn, endTime.AddDate(0, 1, 0)).
|
||||
Group("DATE_FORMAT(" + timeColumn + ", '%Y-%m')").
|
||||
Scan(&maxTimes); err != nil {
|
||||
return nil, gerror.Wrap(err, "查询"+errMsg+"失败,请稍后重试!")
|
||||
}
|
||||
|
||||
result := make(map[string]float64)
|
||||
if len(maxTimes) == 0 {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
maxTimeList := make([]string, len(maxTimes))
|
||||
for i, mt := range maxTimes {
|
||||
maxTimeList[i] = mt.MaxTime
|
||||
}
|
||||
|
||||
type balanceRow struct {
|
||||
AccountPeriod string `orm:"account_period"`
|
||||
BalanceAfter float64 `orm:"balance_after"`
|
||||
}
|
||||
var allResults []*balanceRow
|
||||
if err := mod.Fields("DATE_FORMAT("+timeColumn+", '%Y-%m') as account_period, "+balanceColumn+" as balance_after").
|
||||
Where(deptIdColumn, deptId).
|
||||
WhereIn(timeColumn, maxTimeList).
|
||||
Order(timeColumn + " ASC").
|
||||
Scan(&allResults); err != nil {
|
||||
return nil, gerror.Wrap(err, "查询"+errMsg+"失败,请稍后重试!")
|
||||
}
|
||||
|
||||
for _, item := range allResults {
|
||||
result[item.AccountPeriod] = item.BalanceAfter
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// AccountTrend 获取收入金额、支出金额折线图。
|
||||
func (s *sCommonAgentBalance) AccountTrend(ctx context.Context, in *model.TAgentBalanceTrendParam) (res *model.TAgentBalanceChartData, err error) {
|
||||
months, startMonth, endMonth, err := agentBalanceMonthRange(in.StartMonth, in.EndMonth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deptId := contexts.GetDeptId(ctx)
|
||||
|
||||
type billRow struct {
|
||||
AccountPeriod string `orm:"account_period"`
|
||||
TotalIncome float64 `orm:"total_income"`
|
||||
TotalExpense float64 `orm:"total_expense"`
|
||||
}
|
||||
var bills []*billRow
|
||||
|
||||
accountPeriodColumn := dao.TProfitAccountMonthBill.Columns().AccountPeriod
|
||||
deptIdColumn := dao.TProfitAccountMonthBill.Columns().DeptId
|
||||
totalIncomeColumn := dao.TProfitAccountMonthBill.Columns().TotalIncome
|
||||
totalExpenseColumn := dao.TProfitAccountMonthBill.Columns().TotalExpense
|
||||
mod := handler.Model(dao.TProfitAccountMonthBill.Ctx(ctx))
|
||||
|
||||
if in.AccountType == "2" {
|
||||
accountPeriodColumn = dao.TConsumeAccountMonthBill.Columns().AccountPeriod
|
||||
deptIdColumn = dao.TConsumeAccountMonthBill.Columns().DeptId
|
||||
totalIncomeColumn = dao.TConsumeAccountMonthBill.Columns().TotalIncome
|
||||
totalExpenseColumn = dao.TConsumeAccountMonthBill.Columns().TotalExpense
|
||||
mod = handler.Model(dao.TConsumeAccountMonthBill.Ctx(ctx))
|
||||
}
|
||||
|
||||
if err = mod.Fields(accountPeriodColumn, totalIncomeColumn, totalExpenseColumn).
|
||||
Where(deptIdColumn, deptId).
|
||||
WhereBetween(accountPeriodColumn, startMonth, endMonth).
|
||||
Scan(&bills); err != nil {
|
||||
return nil, gerror.Wrap(err, "查询账户总览趋势失败,请稍后重试!")
|
||||
}
|
||||
|
||||
billMap := make(map[string]*billRow, len(bills))
|
||||
for _, item := range bills {
|
||||
billMap[item.AccountPeriod] = item
|
||||
}
|
||||
|
||||
incomeValues := make([]float64, 0, len(months))
|
||||
expenseValues := make([]float64, 0, len(months))
|
||||
for _, month := range months {
|
||||
if item, ok := billMap[month]; ok {
|
||||
incomeValues = append(incomeValues, item.TotalIncome)
|
||||
expenseValues = append(expenseValues, item.TotalExpense)
|
||||
continue
|
||||
}
|
||||
incomeValues = append(incomeValues, 0)
|
||||
expenseValues = append(expenseValues, 0)
|
||||
}
|
||||
|
||||
return &model.TAgentBalanceChartData{
|
||||
Labels: months,
|
||||
Series: []*model.TAgentBalanceChartSeries{
|
||||
{Name: "收入金额", Values: incomeValues},
|
||||
{Name: "支出金额", Values: expenseValues},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// agentBalanceMonthRange 返回月份范围。
|
||||
func agentBalanceMonthRange(startMonth, endMonth string) (months []string, startTime time.Time, endTime time.Time, err error) {
|
||||
now := time.Now()
|
||||
if endMonth == "" {
|
||||
endMonth = now.Format("2006-01")
|
||||
}
|
||||
if startMonth == "" {
|
||||
tempEndTime, parseErr := time.Parse("2006-01", endMonth)
|
||||
if parseErr != nil {
|
||||
err = gerror.New("结束月份格式不正确,应为YYYY-MM")
|
||||
return
|
||||
}
|
||||
startMonth = tempEndTime.AddDate(0, -11, 0).Format("2006-01")
|
||||
}
|
||||
|
||||
startTime, err = time.Parse("2006-01", startMonth)
|
||||
if err != nil {
|
||||
err = gerror.New("开始月份格式不正确,应为YYYY-MM")
|
||||
return
|
||||
}
|
||||
endTime, err = time.Parse("2006-01", endMonth)
|
||||
if err != nil {
|
||||
err = gerror.New("结束月份格式不正确,应为YYYY-MM")
|
||||
return
|
||||
}
|
||||
if startTime.After(endTime) {
|
||||
err = gerror.New("开始月份不能大于结束月份")
|
||||
return
|
||||
}
|
||||
|
||||
for t := startTime; !t.After(endTime); t = t.AddDate(0, 1, 0) {
|
||||
months = append(months, t.Format("2006-01"))
|
||||
}
|
||||
return months, startTime, endTime, nil
|
||||
}
|
||||
|
||||
const (
|
||||
financeIncomeExpenseIncome = 0
|
||||
financeIncomeExpenseExpense = 1
|
||||
|
||||
financeBalanceTransactionTypeTransferToWithdraw = 2
|
||||
financeBalanceTransactionTypeManualAdjust = 4
|
||||
financeBalanceTransactionChannelBalance = 3
|
||||
|
||||
financeWithdrawableChangeTypeCommission = 0
|
||||
financeWithdrawableChangeTypeBalanceTransferIn = 3
|
||||
|
||||
financeApplyTypeBalanceToWithdraw = 2
|
||||
financeAuditTypeFirst = 1
|
||||
financeApplyStatusPending = 0
|
||||
financeApplyStatusApproved = 1
|
||||
financeApplyStatusRejected = 2
|
||||
financeAuditResultPass = 0
|
||||
financeAuditResultReject = 1
|
||||
financeAccountStatusNormal = 0
|
||||
financeWithdrawAmountStatusNormal = 0
|
||||
financeCommissionStatusPending = 0
|
||||
financeCommissionStatusSettled = 1
|
||||
)
|
||||
|
||||
// BalanceTransferApply 发起余额转可提现申请。申请时先扣余额并写余额明细,申请单保持待审核。
|
||||
func (s *sCommonAgentBalance) BalanceTransferApply(ctx context.Context, in *model.TAgentBalanceTransferApplyParam) (*model.TAgentBalanceTransferApplyModel, error) {
|
||||
if in == nil {
|
||||
in = &model.TAgentBalanceTransferApplyParam{}
|
||||
}
|
||||
if err := in.Filter(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
applyNo := "BWT" + strings.ReplaceAll(uuid.New().String(), "-", "")
|
||||
deptId := contexts.GetDeptId(ctx)
|
||||
tenantId := contexts.GetTenantId(ctx)
|
||||
userId := contexts.GetUserId(ctx)
|
||||
now := gtime.Now()
|
||||
|
||||
res := &model.TAgentBalanceTransferApplyModel{
|
||||
ApplyNo: applyNo,
|
||||
ApplyAmount: in.Amount,
|
||||
}
|
||||
|
||||
err := g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
account := &entity.TAgentBalance{}
|
||||
columns := dao.TAgentBalance.Columns()
|
||||
if err := tx.Ctx(ctx).Model(dao.TAgentBalance.Table()).
|
||||
Where(columns.DeptId, deptId).
|
||||
Where(columns.TenantId, tenantId).
|
||||
Scan(account); err != nil {
|
||||
return gerror.Wrap(err, "查询企业客户财务账户失败,请稍后重试!")
|
||||
}
|
||||
if account.Id == 0 {
|
||||
return gerror.New("企业客户财务账户不存在")
|
||||
}
|
||||
if account.Status != financeAccountStatusNormal {
|
||||
return gerror.New("企业客户财务账户状态异常")
|
||||
}
|
||||
if account.WithdrawAmountStatus != financeWithdrawAmountStatusNormal {
|
||||
return gerror.New("可提现金额已冻结")
|
||||
}
|
||||
if account.Balance < in.Amount {
|
||||
return gerror.New("账户余额不足")
|
||||
}
|
||||
|
||||
balanceAfter := account.Balance - in.Amount
|
||||
result, err := tx.Ctx(ctx).Model(dao.TAgentBalance.Table()).
|
||||
WherePri(account.Id).
|
||||
Data(g.Map{
|
||||
columns.Balance: balanceAfter,
|
||||
columns.UpdatedBy: userId,
|
||||
columns.UpdatedAt: now,
|
||||
}).
|
||||
Update()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "扣减账户余额失败,请稍后重试!")
|
||||
}
|
||||
affected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "获取账户余额更新结果失败")
|
||||
}
|
||||
if affected == 0 {
|
||||
return gerror.New("账户余额未更新,请稍后重试")
|
||||
}
|
||||
|
||||
if err = service.CommonTBalanceDetail().CreateBalanceTransferDetail(ctx, tx, &model.TBalanceTransferDetailCreateParam{
|
||||
DeptId: deptId,
|
||||
SerialNo: applyNo,
|
||||
TransactionTime: now,
|
||||
IncomeExpenseType: financeIncomeExpenseExpense,
|
||||
TransactionType: financeBalanceTransactionTypeTransferToWithdraw,
|
||||
TransactionChannel: financeBalanceTransactionChannelBalance,
|
||||
Amount: in.Amount,
|
||||
BeforeBalance: account.Balance,
|
||||
BalanceAfter: balanceAfter,
|
||||
OrderSn: applyNo,
|
||||
Remark: "余额转可提现申请扣减余额",
|
||||
TenantId: tenantId,
|
||||
CreatedDept: deptId,
|
||||
CreatedBy: userId,
|
||||
CreatedAt: now,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var topDept entity.SysDept
|
||||
if err := dao.SysDept.Ctx(ctx).
|
||||
Fields(dao.SysDept.Columns().DeptId, dao.SysDept.Columns().ParentId).
|
||||
Where(dao.SysDept.Columns().ParentId, 0).
|
||||
Scan(&topDept); err != nil {
|
||||
return gerror.Wrap(err, "查询审核机构失败,请稍后重试!")
|
||||
}
|
||||
if topDept.DeptId == 0 {
|
||||
return gerror.New("审核机构不存在")
|
||||
}
|
||||
|
||||
if err = service.CommonTFinanceApply().CreateBalanceTransferApply(ctx, tx, &model.TFinanceApplyCreateBalanceTransferParam{
|
||||
ApplyNo: applyNo,
|
||||
ApplyDeptId: deptId,
|
||||
AuditDeptId: topDept.DeptId,
|
||||
AvailableAmountSnapshot: account.WithdrawAmount,
|
||||
ApplyAmount: in.Amount,
|
||||
Remark: in.Remark,
|
||||
TenantId: tenantId,
|
||||
CreatedDept: deptId,
|
||||
CreatedBy: userId,
|
||||
CreatedAt: now,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res.BalanceAfter = balanceAfter
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "余额转可提现申请失败,请稍后重试!")
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// BalanceTransferAudit 审核余额转可提现申请。通过时加可提现金额,驳回时退回申请时扣掉的余额。
|
||||
func (s *sCommonAgentBalance) BalanceTransferAudit(ctx context.Context, in *model.TAgentBalanceTransferAuditParam) error {
|
||||
if in == nil {
|
||||
in = &model.TAgentBalanceTransferAuditParam{}
|
||||
}
|
||||
if err := in.Filter(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
auditNo, err := batchimport.NextRandomNo("BTA")
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "生成审核单号失败")
|
||||
}
|
||||
tenantId := contexts.GetTenantId(ctx)
|
||||
currentDeptId := contexts.GetDeptId(ctx)
|
||||
currentUserId := contexts.GetUserId(ctx)
|
||||
if tenantId == "" {
|
||||
return gerror.New("当前租户不能为空")
|
||||
}
|
||||
if currentDeptId <= 0 {
|
||||
return gerror.New("当前登录机构不能为空")
|
||||
}
|
||||
|
||||
now := gtime.Now()
|
||||
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
apply, err := service.CommonTFinanceApply().GetPendingByApplyNo(ctx, tx, in.ApplyNo, tenantId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = service.CommonTFinanceAuditRecord().CreateRecord(ctx, tx, &model.TFinanceAuditRecordCreateParam{
|
||||
AuditNo: auditNo,
|
||||
ApplyNo: apply.ApplyNo,
|
||||
AuditDeptId: currentDeptId,
|
||||
AuditorUserId: currentUserId,
|
||||
AuditResult: in.AuditResult,
|
||||
AuditOpinion: in.AuditOpinion,
|
||||
AuditTime: now,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
applyStatus := financeApplyStatusApproved
|
||||
if in.AuditResult == financeAuditResultReject {
|
||||
applyStatus = financeApplyStatusRejected
|
||||
}
|
||||
if err = service.CommonTFinanceApply().UpdateAuditStatus(ctx, tx, &model.TFinanceApplyUpdateAuditStatusParam{
|
||||
ApplyNo: apply.ApplyNo,
|
||||
ApplyStatus: applyStatus,
|
||||
AuditTime: now,
|
||||
UpdatedBy: currentUserId,
|
||||
UpdatedAt: now,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
account := &entity.TAgentBalance{}
|
||||
columns := dao.TAgentBalance.Columns()
|
||||
if err := tx.Ctx(ctx).Model(dao.TAgentBalance.Table()).
|
||||
Where(columns.DeptId, apply.ApplyDeptId).
|
||||
Where(columns.TenantId, apply.TenantId).
|
||||
Scan(account); err != nil {
|
||||
return gerror.Wrap(err, "查询企业客户财务账户失败,请稍后重试!")
|
||||
}
|
||||
if account.Id == 0 {
|
||||
return gerror.New("企业客户财务账户不存在")
|
||||
}
|
||||
if account.Status != financeAccountStatusNormal {
|
||||
return gerror.New("企业客户财务账户状态异常")
|
||||
}
|
||||
|
||||
if in.AuditResult == financeAuditResultPass {
|
||||
if account.WithdrawAmountStatus != financeWithdrawAmountStatusNormal {
|
||||
return gerror.New("可提现金额已冻结")
|
||||
}
|
||||
before := account.WithdrawAmount
|
||||
after := before + apply.ApplyAmount
|
||||
result, err := tx.Ctx(ctx).Model(dao.TAgentBalance.Table()).
|
||||
WherePri(account.Id).
|
||||
Data(g.Map{
|
||||
columns.WithdrawAmount: after,
|
||||
columns.UpdatedBy: currentUserId,
|
||||
columns.UpdatedAt: now,
|
||||
}).
|
||||
Update()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "增加可提现金额失败,请稍后重试!")
|
||||
}
|
||||
affected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "获取账户余额更新结果失败")
|
||||
}
|
||||
if affected == 0 {
|
||||
return gerror.New("账户余额未更新,请稍后重试")
|
||||
}
|
||||
|
||||
return service.CommonTFinWithdrawableChange().CreateBalanceTransferInChange(ctx, tx, &model.TFinWithdrawableBalanceTransferInParam{
|
||||
DeptId: apply.ApplyDeptId,
|
||||
ChangeAmount: apply.ApplyAmount,
|
||||
BeforeBalance: before,
|
||||
AfterBalance: after,
|
||||
AccountType: apply.AccountType,
|
||||
BankName: apply.BankName,
|
||||
BankAccount: apply.BankAccount,
|
||||
AccountName: apply.AccountName,
|
||||
IdentityCard: apply.IdentityCard,
|
||||
SourceNo: apply.ApplyNo,
|
||||
Remark: "余额转可提现审核通过",
|
||||
AccountPeriod: now.Format("Y-m"),
|
||||
TenantId: apply.TenantId,
|
||||
CreatedDept: apply.ApplyDeptId,
|
||||
CreatedBy: currentUserId,
|
||||
CreatedAt: now,
|
||||
})
|
||||
}
|
||||
|
||||
before := account.Balance
|
||||
after := before + apply.ApplyAmount
|
||||
result, err := tx.Ctx(ctx).Model(dao.TAgentBalance.Table()).
|
||||
WherePri(account.Id).
|
||||
Data(g.Map{
|
||||
columns.Balance: after,
|
||||
columns.UpdatedBy: currentUserId,
|
||||
columns.UpdatedAt: now,
|
||||
}).
|
||||
Update()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "退回账户余额失败,请稍后重试!")
|
||||
}
|
||||
affected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "获取账户余额更新结果失败")
|
||||
}
|
||||
if affected == 0 {
|
||||
return gerror.New("账户余额未更新,请稍后重试")
|
||||
}
|
||||
|
||||
remark := "余额转可提现申请驳回退款"
|
||||
if in.AuditOpinion != "" {
|
||||
remark += ":" + in.AuditOpinion
|
||||
}
|
||||
return service.CommonTBalanceDetail().CreateBalanceTransferDetail(ctx, tx, &model.TBalanceTransferDetailCreateParam{
|
||||
DeptId: apply.ApplyDeptId,
|
||||
SerialNo: apply.ApplyNo,
|
||||
TransactionTime: now,
|
||||
IncomeExpenseType: financeIncomeExpenseIncome,
|
||||
TransactionType: financeBalanceTransactionTypeManualAdjust,
|
||||
TransactionChannel: financeBalanceTransactionChannelBalance,
|
||||
Amount: apply.ApplyAmount,
|
||||
BeforeBalance: before,
|
||||
BalanceAfter: after,
|
||||
OrderSn: apply.ApplyNo,
|
||||
Remark: remark,
|
||||
TenantId: apply.TenantId,
|
||||
CreatedDept: apply.ApplyDeptId,
|
||||
CreatedBy: currentUserId,
|
||||
CreatedAt: now,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// SettleCommissionByPeriod 按账期区间结算待结算分润,同步到企业账户可提现金额并写入可提现明细。
|
||||
func (s *sCommonAgentBalance) SettleCommissionByPeriod(ctx context.Context, in *model.TAgentBalanceCommissionSettlementParam) (*model.TAgentBalanceCommissionSettlementResult, error) {
|
||||
if in == nil {
|
||||
in = &model.TAgentBalanceCommissionSettlementParam{}
|
||||
}
|
||||
if err := in.Filter(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := &model.TAgentBalanceCommissionSettlementResult{
|
||||
StartPeriod: in.StartPeriod,
|
||||
EndPeriod: in.EndPeriod,
|
||||
}
|
||||
|
||||
endPeriodTime, _ := time.Parse("2006-01", in.EndPeriod)
|
||||
endNextPeriod := endPeriodTime.AddDate(0, 1, 0).Format("2006-01")
|
||||
var lastId int64
|
||||
tenantId := contexts.GetTenantId(ctx)
|
||||
commissionColumns := dao.TFinCommissionDetail.Columns()
|
||||
for {
|
||||
var details []*entity.TFinCommissionDetail
|
||||
mod := handler.Model(dao.TFinCommissionDetail.Ctx(ctx), &handler.Option{
|
||||
FilterTenant: false,
|
||||
FilterAuth: false,
|
||||
}).
|
||||
Fields(
|
||||
commissionColumns.Id,
|
||||
commissionColumns.BenefitDeptId,
|
||||
commissionColumns.CommissionAmount,
|
||||
commissionColumns.AccountPeriod,
|
||||
commissionColumns.TenantId,
|
||||
commissionColumns.CreatedDept,
|
||||
).
|
||||
Where(commissionColumns.CommissionStatus, financeCommissionStatusPending).
|
||||
WhereGTE(commissionColumns.AccountPeriod, in.StartPeriod).
|
||||
WhereLT(commissionColumns.AccountPeriod, endNextPeriod).
|
||||
WhereGT(commissionColumns.Id, lastId).
|
||||
OrderAsc(commissionColumns.Id).
|
||||
Limit(1000)
|
||||
if tenantId != "" {
|
||||
mod = mod.Where(commissionColumns.TenantId, tenantId)
|
||||
}
|
||||
if err := mod.Scan(&details); err != nil {
|
||||
return res, gerror.Wrap(err, "扫描待结算分润明细失败,请稍后重试!")
|
||||
}
|
||||
if len(details) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
res.ScanCount += len(details)
|
||||
for _, item := range details {
|
||||
if item.Id > lastId {
|
||||
lastId = item.Id
|
||||
}
|
||||
}
|
||||
|
||||
groups := make(map[model.TAgentBalanceCommissionSettlementGroupKey]*model.TAgentBalanceCommissionSettlementGroup)
|
||||
for _, item := range details {
|
||||
if item.BenefitDeptId <= 0 || item.AccountPeriod == "" || item.CommissionAmount <= 0 {
|
||||
continue
|
||||
}
|
||||
key := model.TAgentBalanceCommissionSettlementGroupKey{
|
||||
DeptId: item.BenefitDeptId,
|
||||
AccountPeriod: item.AccountPeriod,
|
||||
TenantId: item.TenantId,
|
||||
}
|
||||
group := groups[key]
|
||||
if group == nil {
|
||||
group = &model.TAgentBalanceCommissionSettlementGroup{
|
||||
DeptId: item.BenefitDeptId,
|
||||
AccountPeriod: item.AccountPeriod,
|
||||
TenantId: item.TenantId,
|
||||
CreatedDept: item.CreatedDept,
|
||||
}
|
||||
groups[key] = group
|
||||
}
|
||||
group.Ids = append(group.Ids, item.Id)
|
||||
group.Amount += item.CommissionAmount
|
||||
}
|
||||
|
||||
for _, group := range groups {
|
||||
if err := s.settleCommissionGroup(ctx, group); err != nil {
|
||||
res.FailGroupCount++
|
||||
g.Log().Errorf(ctx, "分润结算失败 deptId:%d accountPeriod:%s amount:%v err:%+v", group.DeptId, group.AccountPeriod, group.Amount, err)
|
||||
continue
|
||||
}
|
||||
res.SuccessGroupCount++
|
||||
res.SettledCount += len(group.Ids)
|
||||
res.SettledAmount += group.Amount
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *sCommonAgentBalance) settleCommissionGroup(ctx context.Context, group *model.TAgentBalanceCommissionSettlementGroup) error {
|
||||
if group == nil || len(group.Ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
now := gtime.Now()
|
||||
userId := contexts.GetUserId(ctx)
|
||||
accountColumns := dao.TAgentBalance.Columns()
|
||||
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
account := &entity.TAgentBalance{}
|
||||
if err := tx.Ctx(ctx).Model(dao.TAgentBalance.Table()).
|
||||
Where(accountColumns.DeptId, group.DeptId).
|
||||
Where(accountColumns.TenantId, group.TenantId).
|
||||
LockUpdate().
|
||||
Scan(account); err != nil {
|
||||
return gerror.Wrap(err, "锁定企业客户财务账户失败,请稍后重试!")
|
||||
}
|
||||
if account.Id == 0 {
|
||||
return gerror.New("企业客户财务账户不存在")
|
||||
}
|
||||
if account.Status != financeAccountStatusNormal {
|
||||
return gerror.New("企业客户财务账户状态异常")
|
||||
}
|
||||
if account.WithdrawAmountStatus != financeWithdrawAmountStatusNormal {
|
||||
return gerror.New("可提现金额已冻结")
|
||||
}
|
||||
|
||||
if err := service.CommonTFinCommissionDetail().MarkSettled(ctx, tx, &model.TFinCommissionSettleUpdateParam{
|
||||
Ids: group.Ids,
|
||||
SettlementTime: now,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
before := account.WithdrawAmount
|
||||
after := before + group.Amount
|
||||
sourceNo := fmt.Sprintf("CMS%sD%d%s", strings.ReplaceAll(group.AccountPeriod, "-", ""), group.DeptId, now.Format("150405"))
|
||||
if err := service.CommonTFinWithdrawableChange().CreateCommissionSettlementChange(ctx, tx, &model.TFinWithdrawableCommissionSettlementParam{
|
||||
DeptId: group.DeptId,
|
||||
ChangeAmount: group.Amount,
|
||||
BeforeBalance: before,
|
||||
AfterBalance: after,
|
||||
SourceNo: sourceNo,
|
||||
Remark: "分润结算转可提现",
|
||||
AccountPeriod: group.AccountPeriod,
|
||||
TenantId: group.TenantId,
|
||||
CreatedDept: group.CreatedDept,
|
||||
CreatedBy: userId,
|
||||
CreatedAt: now,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := tx.Ctx(ctx).Model(dao.TAgentBalance.Table()).
|
||||
WherePri(account.Id).
|
||||
Data(g.Map{
|
||||
accountColumns.WithdrawAmount: after,
|
||||
accountColumns.UpdatedBy: userId,
|
||||
accountColumns.UpdatedAt: now,
|
||||
}).
|
||||
Update()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "更新企业客户可提现金额失败,请稍后重试!")
|
||||
}
|
||||
affected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "获取企业客户可提现金额更新结果失败")
|
||||
}
|
||||
if affected == 0 {
|
||||
return gerror.New("企业客户可提现金额未更新,请稍后重试")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user