// Package gen
// @Link https://github.com/xiujiecn/xiu-admin
// @Copyright Copyright (c) 2026 LiXiujie
// @Author Lxj
// @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
}