436 lines
15 KiB
Go
436 lines
15 KiB
Go
// 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/contexts"
|
||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm"
|
||
"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/service"
|
||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/convert"
|
||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/excel"
|
||
"strconv"
|
||
|
||
"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"
|
||
)
|
||
|
||
type sCommonTFinCommissionDetail struct{}
|
||
|
||
func NewCommonTFinCommissionDetail() *sCommonTFinCommissionDetail {
|
||
return &sCommonTFinCommissionDetail{}
|
||
}
|
||
|
||
func init() {
|
||
service.RegisterCommonTFinCommissionDetail(NewCommonTFinCommissionDetail())
|
||
}
|
||
|
||
// Model 分润明细表ORM模型
|
||
func (s *sCommonTFinCommissionDetail) 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.TFinCommissionDetail.Ctx(ctx), option...)
|
||
}
|
||
|
||
// List 获取分润明细表列表
|
||
func (s *sCommonTFinCommissionDetail) List(ctx context.Context, in *model.TFinCommissionDetailListParam) (list []*model.TFinCommissionDetailListModel, totalCount int, err error) {
|
||
mod := s.Model(ctx)
|
||
|
||
// 字段过滤
|
||
mod = mod.Fields(model.TFinCommissionDetailListModel{})
|
||
|
||
// 查询主键ID
|
||
if in.Id > 0 {
|
||
mod = mod.Where(dao.TFinCommissionDetail.Columns().Id, in.Id)
|
||
}
|
||
|
||
// 查询分润状态:0待结算,1可提现
|
||
if in.CommissionStatus > 0 {
|
||
mod = mod.Where(dao.TFinCommissionDetail.Columns().CommissionStatus, in.CommissionStatus)
|
||
}
|
||
|
||
// 查询创建时间
|
||
if len(in.CreatedAt) == 2 {
|
||
in.CreatedAt[1] = in.CreatedAt[1].EndOfDay()
|
||
}
|
||
if len(in.CreatedAt) == 2 {
|
||
mod = mod.WhereBetween(dao.TFinCommissionDetail.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1])
|
||
}
|
||
|
||
// 分页
|
||
mod = mod.Page(in.Page, in.PageSize)
|
||
|
||
// 排序
|
||
mod = mod.OrderDesc(dao.TFinCommissionDetail.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 *sCommonTFinCommissionDetail) Export(ctx context.Context, in *model.TFinCommissionDetailListParam) (err error) {
|
||
list, totalCount, err := s.List(ctx, in)
|
||
if err != nil {
|
||
return
|
||
}
|
||
|
||
// 字段的排序是依据tags的字段顺序,如果你不想使用默认的排序方式,可以直接定义 tags = []string{"字段名称", "字段名称2", ...}
|
||
tags, err := convert.GetEntityDescTags(model.TFinCommissionDetailExportModel{})
|
||
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.TFinCommissionDetailExportModel
|
||
)
|
||
|
||
if err = gconv.Scan(list, &exports); err != nil {
|
||
return
|
||
}
|
||
|
||
err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName)
|
||
return
|
||
}
|
||
|
||
// Edit 修改/新增分润明细表
|
||
func (s *sCommonTFinCommissionDetail) Edit(ctx context.Context, in *model.TFinCommissionDetailEditParam) (err error) {
|
||
// 验证'CommissionNo'唯一
|
||
if err = xgorm.IsUnique(ctx, &dao.TFinCommissionDetail, g.Map{dao.TFinCommissionDetail.Columns().CommissionNo: in.CommissionNo}, "分润明细编号已存在", in.Id); err != nil {
|
||
return
|
||
}
|
||
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.TFinCommissionDetailUpdateFields{}).
|
||
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.TFinCommissionDetailInsertFields{}).
|
||
Data(in).Insert(); err != nil {
|
||
err = gerror.Wrap(err, "新增分润明细表失败,请稍后重试!")
|
||
}
|
||
return
|
||
})
|
||
}
|
||
|
||
// Delete 删除分润明细表
|
||
func (s *sCommonTFinCommissionDetail) Delete(ctx context.Context, in *model.TFinCommissionDetailDeleteParam) (err error) {
|
||
|
||
if _, err = s.Model(ctx).WherePri(in.Id).Unscoped().Delete(); err != nil {
|
||
err = gerror.Wrap(err, "删除分润明细表失败,请稍后重试!")
|
||
return
|
||
}
|
||
return
|
||
}
|
||
|
||
// View 获取分润明细表指定信息
|
||
func (s *sCommonTFinCommissionDetail) View(ctx context.Context, in *model.TFinCommissionDetailViewParam) (res *model.TFinCommissionDetailViewModel, err error) {
|
||
if err = s.Model(ctx).WherePri(in.Id).Hook(hook.MemberSummary).Scan(&res); err != nil {
|
||
err = gerror.Wrap(err, "获取分润明细表信息,请稍后重试!")
|
||
return
|
||
}
|
||
return
|
||
}
|
||
|
||
// MarkSettled 批量标记分润明细为可提现状态。
|
||
func (s *sCommonTFinCommissionDetail) MarkSettled(ctx context.Context, tx gdb.TX, in *model.TFinCommissionSettleUpdateParam) error {
|
||
if in == nil {
|
||
return gerror.New("分润结算更新参数不能为空")
|
||
}
|
||
if len(in.Ids) == 0 {
|
||
return gerror.New("分润明细ID不能为空")
|
||
}
|
||
settlementTime := in.SettlementTime
|
||
if settlementTime == nil {
|
||
settlementTime = gtime.Now()
|
||
}
|
||
userId := contexts.GetUserId(ctx)
|
||
columns := dao.TFinCommissionDetail.Columns()
|
||
result, err := tx.Ctx(ctx).Model(dao.TFinCommissionDetail.Table()).
|
||
WhereIn(columns.Id, in.Ids).
|
||
Where(columns.CommissionStatus, financeCommissionStatusPending).
|
||
Data(g.Map{
|
||
columns.CommissionStatus: financeCommissionStatusSettled,
|
||
columns.SettlementTime: settlementTime,
|
||
columns.UpdatedBy: userId,
|
||
columns.UpdatedAt: settlementTime,
|
||
}).
|
||
Update()
|
||
if err != nil {
|
||
return gerror.Wrap(err, "更新分润明细结算状态失败,请稍后重试!")
|
||
}
|
||
affected, err := result.RowsAffected()
|
||
if err != nil {
|
||
return gerror.Wrap(err, "获取分润明细结算状态更新结果失败")
|
||
}
|
||
if affected != int64(len(in.Ids)) {
|
||
return gerror.New("部分分润明细状态已变化,请下次任务重试")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 分层分润概览 分润表
|
||
// 一级客户收入 benefit_dept_level=1 commission_amount相加
|
||
// 二级客户收入 benefit_dept_level=2 commission_amount相加
|
||
// 三级客户收入 benefit_dept_level=3 commission_amount相加
|
||
// 总收入 一级二级三级加起来总和
|
||
func (s *sCommonTFinCommissionDetail) GetCommissionOverview(ctx context.Context, in *model.TCommissionOverviewParam) (res *model.TCommissionOverviewModel, err error) {
|
||
res = &model.TCommissionOverviewModel{}
|
||
deptId := contexts.GetDeptId(ctx)
|
||
|
||
// 解析账期参数
|
||
var startPeriod, endPeriod string
|
||
if in.Type == 1 { // 年
|
||
startPeriod = in.Year + "-01"
|
||
endPeriod = in.Year + "-12"
|
||
} else if in.Type == 2 { // 月
|
||
startPeriod = in.Month
|
||
endPeriod = in.Month
|
||
}
|
||
|
||
// 查询一级客户收入
|
||
type levelRow struct {
|
||
CommissionAmount float64 `orm:"commission_amount"`
|
||
}
|
||
var level1Result *levelRow
|
||
if err = handler.Model(dao.TFinCommissionDetail.Ctx(ctx)).
|
||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptId, deptId).
|
||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptLevel, 1).
|
||
WhereGTE(dao.TFinCommissionDetail.Columns().AccountPeriod, startPeriod).
|
||
WhereLTE(dao.TFinCommissionDetail.Columns().AccountPeriod, endPeriod).
|
||
Fields("SUM(" + dao.TFinCommissionDetail.Columns().CommissionAmount + ") as commission_amount").
|
||
Scan(&level1Result); err != nil {
|
||
err = gerror.Wrap(err, "查询一级客户收入失败,请稍后重试!")
|
||
return
|
||
}
|
||
if level1Result != nil {
|
||
res.Level1Income = level1Result.CommissionAmount
|
||
}
|
||
|
||
// 查询二级客户收入
|
||
var level2Result *levelRow
|
||
if err = handler.Model(dao.TFinCommissionDetail.Ctx(ctx)).
|
||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptId, deptId).
|
||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptLevel, 2).
|
||
WhereGTE(dao.TFinCommissionDetail.Columns().AccountPeriod, startPeriod).
|
||
WhereLTE(dao.TFinCommissionDetail.Columns().AccountPeriod, endPeriod).
|
||
Fields("SUM(" + dao.TFinCommissionDetail.Columns().CommissionAmount + ") as commission_amount").
|
||
Scan(&level2Result); err != nil {
|
||
err = gerror.Wrap(err, "查询二级客户收入失败,请稍后重试!")
|
||
return
|
||
}
|
||
if level2Result != nil {
|
||
res.Level2Income = level2Result.CommissionAmount
|
||
}
|
||
|
||
// 查询三级客户收入
|
||
var level3Result *levelRow
|
||
if err = handler.Model(dao.TFinCommissionDetail.Ctx(ctx)).
|
||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptId, deptId).
|
||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptLevel, 3).
|
||
WhereGTE(dao.TFinCommissionDetail.Columns().AccountPeriod, startPeriod).
|
||
WhereLTE(dao.TFinCommissionDetail.Columns().AccountPeriod, endPeriod).
|
||
Fields("SUM(" + dao.TFinCommissionDetail.Columns().CommissionAmount + ") as commission_amount").
|
||
Scan(&level3Result); err != nil {
|
||
err = gerror.Wrap(err, "查询三级客户收入失败,请稍后重试!")
|
||
return
|
||
}
|
||
if level3Result != nil {
|
||
res.Level3Income = level3Result.CommissionAmount
|
||
}
|
||
|
||
// 计算总收入
|
||
res.TotalIncome = res.Level1Income + res.Level2Income + res.Level3Income
|
||
|
||
return
|
||
}
|
||
|
||
// GetLevelSummary 获取层级汇总表
|
||
// 客户数 根据 benefit_dept_level 收益机构层级分组
|
||
// 收入金额 根据收益机构id去 t_profit_account_month_bill 查,dept_id=收益机构id,收入=分润结算+余额转提现
|
||
// 分润金额 根据收益机构id去 t_profit_account_month_bill 查,commission_income
|
||
// 顶级利润贡献 等于分润金额
|
||
// 收入占比
|
||
// 环比 选年与去年对比,选月与上个月对比
|
||
func (s *sCommonTFinCommissionDetail) GetLevelSummary(ctx context.Context, in *model.TLevelSummaryParam) (res *model.TLevelSummaryModel, err error) {
|
||
res = &model.TLevelSummaryModel{}
|
||
deptId := contexts.GetDeptId(ctx)
|
||
|
||
// 解析账期参数
|
||
var startPeriod, endPeriod string
|
||
if in.Type == 1 { // 年
|
||
startPeriod = in.Year + "-01"
|
||
endPeriod = in.Year + "-12"
|
||
} else if in.Type == 2 { // 月
|
||
startPeriod = in.Month
|
||
endPeriod = in.Month
|
||
}
|
||
|
||
// 查询各层级的客户数和分润金额(从分润表)
|
||
type levelData struct {
|
||
Level int `orm:"level"`
|
||
CustomerCount int `orm:"customer_count"`
|
||
CommissionAmount float64 `orm:"commission_amount"`
|
||
}
|
||
var levelResults []*levelData
|
||
if err = handler.Model(dao.TFinCommissionDetail.Ctx(ctx)).
|
||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptId, deptId).
|
||
WhereGTE(dao.TFinCommissionDetail.Columns().AccountPeriod, startPeriod).
|
||
WhereLTE(dao.TFinCommissionDetail.Columns().AccountPeriod, endPeriod).
|
||
Fields("SUM(" + dao.TFinCommissionDetail.Columns().CommissionAmount + ") as commission_amount, COUNT(DISTINCT " + dao.TFinCommissionDetail.Columns().PayerDeptId + ") as customer_count, " + dao.TFinCommissionDetail.Columns().BenefitDeptLevel + " as level").
|
||
Group(dao.TFinCommissionDetail.Columns().BenefitDeptLevel).
|
||
Scan(&levelResults); err != nil {
|
||
err = gerror.Wrap(err, "查询层级数据失败,请稍后重试!")
|
||
return
|
||
}
|
||
|
||
// 构建层级与分润金额的映射
|
||
levelCommissionMap := make(map[int]float64)
|
||
for _, lr := range levelResults {
|
||
levelCommissionMap[lr.Level] = lr.CommissionAmount
|
||
}
|
||
|
||
// 查询各层级的收入金额(从盈利月账单表:total_income)
|
||
// 先从分润表获取各层级的机构ID列表
|
||
type deptLevelRow struct {
|
||
Level int `orm:"level"`
|
||
DeptId int64 `orm:"dept_id"`
|
||
}
|
||
var deptLevelResults []*deptLevelRow
|
||
if err = handler.Model(dao.TFinCommissionDetail.Ctx(ctx)).
|
||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptId, deptId).
|
||
WhereGTE(dao.TFinCommissionDetail.Columns().AccountPeriod, startPeriod).
|
||
WhereLTE(dao.TFinCommissionDetail.Columns().AccountPeriod, endPeriod).
|
||
Fields("DISTINCT " + dao.TFinCommissionDetail.Columns().BenefitDeptLevel + " as level, " + dao.TFinCommissionDetail.Columns().BenefitDeptId + " as dept_id").
|
||
Scan(&deptLevelResults); err != nil {
|
||
err = gerror.Wrap(err, "查询层级机构失败,请稍后重试!")
|
||
return
|
||
}
|
||
|
||
// 根据层级汇总机构ID
|
||
levelDeptMap := make(map[int][]int64)
|
||
for _, dlr := range deptLevelResults {
|
||
levelDeptMap[dlr.Level] = append(levelDeptMap[dlr.Level], dlr.DeptId)
|
||
}
|
||
|
||
// 构建收入金额映射
|
||
incomeMap := make(map[int]float64)
|
||
for level, deptIds := range levelDeptMap {
|
||
if len(deptIds) == 0 {
|
||
continue
|
||
}
|
||
incomeResult, err := s.getProfitAccountIncome(ctx, &model.IncomeQueryParams{
|
||
DeptIds: deptIds,
|
||
StartPeriod: startPeriod,
|
||
EndPeriod: endPeriod,
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
incomeMap[level] = incomeResult
|
||
}
|
||
|
||
// 计算总收入
|
||
var totalIncome float64
|
||
for _, item := range levelResults {
|
||
totalIncome += item.CommissionAmount
|
||
}
|
||
|
||
// 构建结果
|
||
for level := 1; level <= 3; level++ {
|
||
item := model.TLevelSummaryItem{
|
||
Level: level,
|
||
}
|
||
|
||
// 设置客户数、分润金额
|
||
for _, lr := range levelResults {
|
||
if lr.Level == level {
|
||
item.CustomerCount = lr.CustomerCount
|
||
item.CommissionAmount = lr.CommissionAmount
|
||
break
|
||
}
|
||
}
|
||
|
||
// 设置收入金额
|
||
item.IncomeAmount = incomeMap[level]
|
||
|
||
// 计算收入占比
|
||
if totalIncome > 0 {
|
||
item.IncomeRatio = item.CommissionAmount / totalIncome * 100
|
||
}
|
||
|
||
res.Items = append(res.Items, item)
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
// getProfitAccountIncome 查询盈利账户收入
|
||
func (s *sCommonTFinCommissionDetail) getProfitAccountIncome(ctx context.Context, params *model.IncomeQueryParams) (float64, error) {
|
||
type incomeRow struct {
|
||
TotalIncome float64 `orm:"total_income"`
|
||
}
|
||
var row *incomeRow
|
||
if err := handler.Model(dao.TProfitAccountMonthBill.Ctx(ctx)).
|
||
WhereIn(dao.TProfitAccountMonthBill.Columns().DeptId, params.DeptIds).
|
||
WhereGTE(dao.TProfitAccountMonthBill.Columns().AccountPeriod, params.StartPeriod).
|
||
WhereLTE(dao.TProfitAccountMonthBill.Columns().AccountPeriod, params.EndPeriod).
|
||
Fields("SUM(" + dao.TProfitAccountMonthBill.Columns().TotalIncome + ") as total_income").
|
||
Scan(&row); err != nil {
|
||
return 0, gerror.Wrap(err, "查询盈利账户收入失败")
|
||
}
|
||
if row == nil {
|
||
return 0, nil
|
||
}
|
||
return row.TotalIncome, nil
|
||
}
|
||
|
||
// mustAtoi 安全转换字符串为int
|
||
func mustAtoi(s string) int {
|
||
i, _ := strconv.Atoi(s)
|
||
return i
|
||
}
|