459 lines
15 KiB
Go
459 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"
|
|
"database/sql"
|
|
"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/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"
|
|
"math"
|
|
"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"
|
|
)
|
|
|
|
type sCommonConsumeAccountMonthBill struct{}
|
|
|
|
func NewCommonConsumeAccountMonthBill() *sCommonConsumeAccountMonthBill {
|
|
return &sCommonConsumeAccountMonthBill{}
|
|
}
|
|
|
|
func init() {
|
|
service.RegisterCommonConsumeAccountMonthBill(NewCommonConsumeAccountMonthBill())
|
|
}
|
|
|
|
// Model 消费账户月账单表ORM模型
|
|
func (s *sCommonConsumeAccountMonthBill) 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.TConsumeAccountMonthBill.Ctx(ctx), option...)
|
|
}
|
|
|
|
// List 获取消费账户月账单表列表
|
|
func (s *sCommonConsumeAccountMonthBill) List(ctx context.Context, in *model.TConsumeAccountMonthBillListParam) (list []*model.TConsumeAccountMonthBillListModel, totalCount int, err error) {
|
|
mod := s.Model(ctx)
|
|
|
|
// 字段过滤
|
|
mod = mod.Fields(model.TConsumeAccountMonthBillListModel{})
|
|
|
|
// 查询账单ID
|
|
if in.Id > 0 {
|
|
mod = mod.Where(dao.TConsumeAccountMonthBill.Columns().Id, in.Id)
|
|
}
|
|
|
|
// 查询账单状态:1正常,2已调整,3已作废
|
|
if in.BillStatus > 0 {
|
|
mod = mod.Where(dao.TConsumeAccountMonthBill.Columns().BillStatus, in.BillStatus)
|
|
}
|
|
|
|
// 查询创建时间
|
|
if len(in.CreatedAt) == 2 {
|
|
in.CreatedAt[1] = in.CreatedAt[1].EndOfDay()
|
|
}
|
|
if len(in.CreatedAt) == 2 {
|
|
mod = mod.WhereBetween(dao.TConsumeAccountMonthBill.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1])
|
|
}
|
|
|
|
// 分页
|
|
mod = mod.Page(in.Page, in.PageSize)
|
|
|
|
// 排序
|
|
mod = mod.OrderDesc(dao.TConsumeAccountMonthBill.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 *sCommonConsumeAccountMonthBill) Export(ctx context.Context, in *model.TConsumeAccountMonthBillListParam) (err error) {
|
|
list, totalCount, err := s.List(ctx, in)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// 字段的排序是依据tags的字段顺序,如果你不想使用默认的排序方式,可以直接定义 tags = []string{"字段名称", "字段名称2", ...}
|
|
tags, err := convert.GetEntityDescTags(model.TConsumeAccountMonthBillExportModel{})
|
|
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.TConsumeAccountMonthBillExportModel
|
|
)
|
|
|
|
if err = gconv.Scan(list, &exports); err != nil {
|
|
return
|
|
}
|
|
|
|
err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName)
|
|
return
|
|
}
|
|
|
|
// Edit 修改/新增消费账户月账单表
|
|
func (s *sCommonConsumeAccountMonthBill) Edit(ctx context.Context, in *model.TConsumeAccountMonthBillEditParam) (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.TConsumeAccountMonthBillUpdateFields{}).
|
|
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.TConsumeAccountMonthBillInsertFields{}).
|
|
Data(in).Insert(); err != nil {
|
|
err = gerror.Wrap(err, "新增消费账户月账单表失败,请稍后重试!")
|
|
}
|
|
return
|
|
})
|
|
}
|
|
|
|
// Delete 删除消费账户月账单表
|
|
func (s *sCommonConsumeAccountMonthBill) Delete(ctx context.Context, in *model.TConsumeAccountMonthBillDeleteParam) (err error) {
|
|
|
|
if _, err = s.Model(ctx).WherePri(in.Id).Unscoped().Delete(); err != nil {
|
|
err = gerror.Wrap(err, "删除消费账户月账单表失败,请稍后重试!")
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// View 获取消费账户月账单表指定信息
|
|
func (s *sCommonConsumeAccountMonthBill) View(ctx context.Context, in *model.TConsumeAccountMonthBillViewParam) (res *model.TConsumeAccountMonthBillViewModel, err error) {
|
|
if err = s.Model(ctx).WherePri(in.Id).Hook(hook.MemberSummary).Scan(&res); err != nil {
|
|
err = gerror.Wrap(err, "获取消费账户月账单表信息,请稍后重试!")
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// GetSummary 获取月账单消费账户汇总信息
|
|
func (s *sCommonConsumeAccountMonthBill) GetConsumptionBillSummary(ctx context.Context, month string) (res *model.TConsumptionBillSummaryModel, err error) {
|
|
// 计算上月账期(基于当前时间)
|
|
// now := time.Now()
|
|
// lastMonthTime := now.AddDate(0, -1, 0)
|
|
// lastMonthPeriod := lastMonthTime.Format("2006-01")
|
|
deptId := contexts.GetDeptId(ctx)
|
|
|
|
var bill *model.TConsumeAccountMonthBillViewModel
|
|
if err = dao.TConsumeAccountMonthBill.Ctx(ctx).
|
|
Where(dao.TConsumeAccountMonthBill.Columns().AccountPeriod, month).
|
|
Where(dao.TConsumeAccountMonthBill.Columns().DeptId, deptId).
|
|
Scan(&bill); err != nil {
|
|
err = gerror.Wrap(err, "查询上月账单失败,请稍后重试!")
|
|
return
|
|
}
|
|
if bill == nil {
|
|
return
|
|
}
|
|
|
|
res = &model.TConsumptionBillSummaryModel{}
|
|
res.TotalIncome = bill.TotalIncome
|
|
res.TotalExpense = bill.TotalExpense
|
|
|
|
return
|
|
}
|
|
|
|
// SettleConsumeAccountMonthBill 按账期统计消费账户月账单。
|
|
func (s *sCommonConsumeAccountMonthBill) SettleConsumeAccountMonthBill(ctx context.Context, in *model.TConsumeAccountMonthBillSettleParam) (res *model.TConsumeAccountMonthBillSettleResult, err error) {
|
|
if in == nil {
|
|
in = &model.TConsumeAccountMonthBillSettleParam{}
|
|
}
|
|
if err = in.Filter(ctx); err != nil {
|
|
return nil, gerror.Wrap(err, "账期格式错误,请使用YYYY-MM")
|
|
}
|
|
if _, err = time.Parse("2006-01", in.AccountPeriod); err != nil {
|
|
return nil, gerror.Wrap(err, "账期格式错误,请使用YYYY-MM")
|
|
}
|
|
|
|
startTime, err := time.Parse("2006-01", in.AccountPeriod)
|
|
if err != nil {
|
|
return nil, gerror.Wrap(err, "账期格式错误,请使用YYYY-MM")
|
|
}
|
|
endTime := startTime.AddDate(0, 1, 0)
|
|
now := gtime.Now()
|
|
userId := contexts.GetUserId(ctx)
|
|
tenantId := contexts.GetTenantId(ctx)
|
|
billColumns := dao.TConsumeAccountMonthBill.Columns()
|
|
detailColumns := dao.TBalanceDetail.Columns()
|
|
|
|
type detailRow struct {
|
|
Id int64 `orm:"id"`
|
|
DeptId int64 `orm:"dept_id"`
|
|
TenantId string `orm:"tenant_id"`
|
|
CreatedDept int64 `orm:"created_dept"`
|
|
IncomeExpenseType int `orm:"income_expense_type"`
|
|
TransactionType int `orm:"transaction_type"`
|
|
Amount float64 `orm:"amount"`
|
|
BeforeBalance float64 `orm:"before_balance"`
|
|
BalanceAfter float64 `orm:"balance_after"`
|
|
TransactionTime *gtime.Time `orm:"transaction_time"`
|
|
}
|
|
|
|
var rows []*detailRow
|
|
mod := handler.Model(dao.TBalanceDetail.Ctx(ctx), &handler.Option{
|
|
FilterTenant: false,
|
|
FilterAuth: false,
|
|
}).
|
|
Fields(
|
|
detailColumns.Id,
|
|
detailColumns.DeptId,
|
|
detailColumns.TenantId,
|
|
detailColumns.CreatedDept,
|
|
detailColumns.IncomeExpenseType,
|
|
detailColumns.TransactionType,
|
|
detailColumns.TransactionStatus,
|
|
detailColumns.Amount,
|
|
detailColumns.BeforeBalance,
|
|
detailColumns.BalanceAfter,
|
|
detailColumns.TransactionTime,
|
|
).
|
|
WhereGTE(detailColumns.TransactionTime, startTime).
|
|
WhereLT(detailColumns.TransactionTime, endTime).
|
|
Where(detailColumns.TransactionStatus, 1)
|
|
if tenantId != "" {
|
|
mod = mod.Where(detailColumns.TenantId, tenantId)
|
|
}
|
|
if err = mod.OrderAsc(detailColumns.TenantId).OrderAsc(detailColumns.DeptId).OrderAsc(detailColumns.TransactionTime).OrderAsc(detailColumns.Id).Scan(&rows); err != nil {
|
|
return nil, gerror.Wrap(err, "查询消费流水失败,请稍后重试!")
|
|
}
|
|
|
|
type billGroup struct {
|
|
DeptId int64
|
|
TenantId string
|
|
CreatedDept int64
|
|
AccountPeriod string
|
|
OpeningBalance float64
|
|
ClosingBalance float64
|
|
RechargeIncome float64
|
|
WithdrawableTransferInIncome float64
|
|
ManualAdjustIncome float64
|
|
RefundIncome float64
|
|
ConsumeExpense float64
|
|
BalanceTransferOutExpense float64
|
|
ManualAdjustExpense float64
|
|
ConsumeCreditRepayExpense float64
|
|
TotalIncome float64
|
|
TotalExpense float64
|
|
IncomeCount int
|
|
ExpenseCount int
|
|
DetailCount int
|
|
}
|
|
|
|
groups := make(map[string]*billGroup)
|
|
keys := make([]string, 0, 16)
|
|
for _, row := range rows {
|
|
if row == nil || row.DeptId <= 0 || row.TransactionTime == nil {
|
|
continue
|
|
}
|
|
switch row.TransactionType {
|
|
case 0, 1, 2, 3, 4:
|
|
default:
|
|
continue
|
|
}
|
|
|
|
key := fmt.Sprintf("%s:%d", row.TenantId, row.DeptId)
|
|
group := groups[key]
|
|
if group == nil {
|
|
group = &billGroup{
|
|
DeptId: row.DeptId,
|
|
TenantId: row.TenantId,
|
|
CreatedDept: row.CreatedDept,
|
|
AccountPeriod: in.AccountPeriod,
|
|
OpeningBalance: row.BeforeBalance,
|
|
}
|
|
groups[key] = group
|
|
keys = append(keys, key)
|
|
}
|
|
group.ClosingBalance = row.BalanceAfter
|
|
group.DetailCount++
|
|
|
|
switch row.TransactionType {
|
|
case 0:
|
|
if row.IncomeExpenseType == 0 {
|
|
group.RechargeIncome += row.Amount
|
|
}
|
|
case 1:
|
|
if row.IncomeExpenseType == 1 {
|
|
group.ConsumeExpense += row.Amount
|
|
}
|
|
case 2:
|
|
if row.IncomeExpenseType == 1 {
|
|
group.BalanceTransferOutExpense += row.Amount
|
|
}
|
|
case 3:
|
|
if row.IncomeExpenseType == 0 {
|
|
group.WithdrawableTransferInIncome += row.Amount
|
|
}
|
|
case 4:
|
|
if row.IncomeExpenseType == 0 {
|
|
group.ManualAdjustIncome += row.Amount
|
|
} else if row.IncomeExpenseType == 1 {
|
|
group.ManualAdjustExpense += row.Amount
|
|
}
|
|
}
|
|
|
|
if row.IncomeExpenseType == 0 {
|
|
group.TotalIncome += row.Amount
|
|
group.IncomeCount++
|
|
} else if row.IncomeExpenseType == 1 {
|
|
group.TotalExpense += row.Amount
|
|
group.ExpenseCount++
|
|
}
|
|
}
|
|
|
|
res = &model.TConsumeAccountMonthBillSettleResult{
|
|
AccountPeriod: in.AccountPeriod,
|
|
}
|
|
if len(groups) == 0 {
|
|
return res, nil
|
|
}
|
|
|
|
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
|
for _, key := range keys {
|
|
group := groups[key]
|
|
if group == nil {
|
|
continue
|
|
}
|
|
|
|
closingBalance := group.OpeningBalance + group.TotalIncome - group.TotalExpense
|
|
if math.Abs(closingBalance-group.ClosingBalance) > 0.01 {
|
|
return gerror.New(fmt.Sprintf("消费账单余额勾稽失败:部门 %d,账期 %s,计算余额 %.2f,流水余额 %.2f", group.DeptId, group.AccountPeriod, closingBalance, group.ClosingBalance))
|
|
}
|
|
|
|
lookup := tx.Ctx(ctx).Model(dao.TConsumeAccountMonthBill.Table()).
|
|
Fields(billColumns.Id).
|
|
Where(billColumns.DeptId, group.DeptId).
|
|
Where(billColumns.AccountPeriod, group.AccountPeriod)
|
|
if group.TenantId != "" {
|
|
lookup = lookup.Where(billColumns.TenantId, group.TenantId)
|
|
}
|
|
|
|
var existing struct {
|
|
Id int64 `orm:"id"`
|
|
}
|
|
if err := lookup.LockUpdate().Scan(&existing); err != nil && err != sql.ErrNoRows {
|
|
return gerror.Wrap(err, "查询消费月账单失败,请稍后重试!")
|
|
}
|
|
|
|
tenantValue := group.TenantId
|
|
if tenantValue == "" {
|
|
tenantValue = tenantId
|
|
}
|
|
if tenantValue == "" {
|
|
return gerror.New("租户ID不能为空")
|
|
}
|
|
|
|
createdDeptValue := group.CreatedDept
|
|
if createdDeptValue == 0 {
|
|
createdDeptValue = contexts.GetDeptId(ctx)
|
|
}
|
|
if createdDeptValue == 0 {
|
|
return gerror.New("创建部门不能为空")
|
|
}
|
|
|
|
data := g.Map{
|
|
billColumns.DeptId: group.DeptId,
|
|
billColumns.AccountPeriod: group.AccountPeriod,
|
|
billColumns.OpeningBalance: group.OpeningBalance,
|
|
billColumns.RechargeIncome: group.RechargeIncome,
|
|
billColumns.WithdrawableTransferInIncome: group.WithdrawableTransferInIncome,
|
|
billColumns.ManualAdjustIncome: group.ManualAdjustIncome,
|
|
billColumns.RefundIncome: 0,
|
|
billColumns.ConsumeExpense: group.ConsumeExpense,
|
|
billColumns.BalanceTransferOutExpense: group.BalanceTransferOutExpense,
|
|
billColumns.ManualAdjustExpense: group.ManualAdjustExpense,
|
|
billColumns.ConsumeCreditRepayExpense: group.ConsumeCreditRepayExpense,
|
|
billColumns.TotalIncome: group.TotalIncome,
|
|
billColumns.TotalExpense: group.TotalExpense,
|
|
billColumns.ClosingBalance: closingBalance,
|
|
billColumns.IncomeCount: group.IncomeCount,
|
|
billColumns.ExpenseCount: group.ExpenseCount,
|
|
billColumns.CreditUsed: 0,
|
|
billColumns.CreditRepaid: 0,
|
|
billColumns.BillStatus: 1,
|
|
billColumns.SettleTime: now,
|
|
billColumns.Remark: "根据余额明细统计生成",
|
|
billColumns.TenantId: tenantValue,
|
|
billColumns.UpdatedBy: userId,
|
|
billColumns.UpdatedAt: now,
|
|
}
|
|
|
|
if existing.Id > 0 {
|
|
if _, err := tx.Ctx(ctx).Model(dao.TConsumeAccountMonthBill.Table()).
|
|
WherePri(existing.Id).
|
|
Data(data).
|
|
Update(); err != nil {
|
|
return gerror.Wrap(err, "更新消费月账单失败,请稍后重试!")
|
|
}
|
|
res.UpdateCount++
|
|
} else {
|
|
data[billColumns.CreatedDept] = createdDeptValue
|
|
data[billColumns.CreatedBy] = userId
|
|
data[billColumns.CreatedAt] = now
|
|
if _, err := tx.Ctx(ctx).Model(dao.TConsumeAccountMonthBill.Table()).
|
|
Data(data).
|
|
Insert(); err != nil {
|
|
return gerror.Wrap(err, "新增消费月账单失败,请稍后重试!")
|
|
}
|
|
res.InsertCount++
|
|
}
|
|
|
|
res.DeptCount++
|
|
res.DetailCount += group.DetailCount
|
|
res.TotalIncome += group.TotalIncome
|
|
res.TotalExpense += group.TotalExpense
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return res, nil
|
|
}
|