Files
iotlcm/admin-svr/server/internal/logic/common/t_fin_commission_detail.go
T

436 lines
15 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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
}