daShangDao_psiServer/service/StatistTaskService.go

260 lines
8.5 KiB
Go

package service
import (
"fmt"
"gorm.io/gorm"
"psi/database"
"psi/models"
"psi/utils"
"time"
)
type StatistTaskService struct{}
// GenerateDailyStat 生成每日统计数据(定时任务调用)
// GenerateDailyStat 生成每日统计数据(定时任务调用)
// GenerateDailyStat 生成每日统计数据(定时任务调用)
func (s *StatistTaskService) GenerateDailyStat(db ...*gorm.DB) error {
now := time.Now()
yesterday := now.AddDate(0, 0, -1)
statDateStr := yesterday.Format("20060102")
var statDate int64
if _, err := fmt.Sscanf(statDateStr, "%d", &statDate); err != nil {
return fmt.Errorf("日期格式化失败: %v", err)
}
yesterdayStart := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, yesterday.Location()).Unix()
yesterdayEnd := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 23, 59, 59, 0, yesterday.Location()).Unix()
mainDB := database.DB
if len(db) > 0 && db[0] != nil {
mainDB = db[0]
}
var aboutIDs []int64
if err := mainDB.Model(&models.Employee{}).Where("deleted_at = ?", 0).Distinct().Pluck("about_id", &aboutIDs).Error; err != nil {
return fmt.Errorf("查询租户列表失败: %v", err)
}
if len(aboutIDs) == 0 {
utils.InfoLog("work", map[string]interface{}{
"source": "定时任务-生成每日统计",
"stat_date": statDate,
"message": "没有找到任何租户",
})
return nil
}
for _, aboutID := range aboutIDs {
if aboutID == 0 {
continue
}
tenantDB, err := database.GetTenantDB(aboutID)
if err != nil {
utils.ErrorLog("work", map[string]interface{}{
"source": "定时任务-生成每日统计",
"about_id": aboutID,
"error": fmt.Sprintf("获取租户数据库失败: %v", err),
})
continue
}
tx := tenantDB.Begin()
func() {
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
_, err := s.generateDashboardDailyStat(tx, statDate, yesterdayStart, yesterdayEnd)
if err != nil {
tx.Rollback()
utils.ErrorLog("work", map[string]interface{}{
"source": "定时任务-生成每日统计",
"about_id": aboutID,
"stat_date": statDate,
"error": fmt.Sprintf("生成全局统计失败: %v", err),
})
return
}
if err := s.generateUserDailyStat(tx, aboutID, statDate, yesterdayStart, yesterdayEnd); err != nil {
tx.Rollback()
utils.ErrorLog("work", map[string]interface{}{
"source": "定时任务-生成每日统计",
"about_id": aboutID,
"stat_date": statDate,
"error": fmt.Sprintf("生成用户统计失败: %v", err),
})
return
}
if err := tx.Commit().Error; err != nil {
utils.ErrorLog("work", map[string]interface{}{
"source": "定时任务-生成每日统计",
"about_id": aboutID,
"stat_date": statDate,
"error": fmt.Sprintf("提交事务失败: %v", err),
})
return
}
utils.InfoLog("work", map[string]interface{}{
"source": "定时任务-生成每日统计",
"about_id": aboutID,
"stat_date": statDate,
"message": fmt.Sprintf("成功生成%s的统计数据", yesterday.Format("2006-01-02")),
})
}()
}
return nil
}
// generateDashboardDailyStat 生成全局每日统计
func (s *StatistTaskService) generateDashboardDailyStat(tx *gorm.DB, statDate int64, startDate, endDate int64) (*models.DashboardDailyStat, error) {
var existingStat models.DashboardDailyStat
err := tx.Where("stat_date = ? AND is_del = ?", statDate, 0).First(&existingStat).Error
if err == nil {
if err := tx.Model(&models.DashboardDailyStat{}).Where("id = ?", existingStat.ID).Update("is_del", 1).Error; err != nil {
return nil, err
}
}
var totalReceivingNum, totalOutboundNum int64
tx.Model(&models.Statist{}).
Where("stat_date <= ? AND is_del = ?", endDate, 0).
Select("COALESCE(SUM(receiving_num), 0), COALESCE(SUM(outbound_num), 0)").
Row().Scan(&totalReceivingNum, &totalOutboundNum)
var todayInbound, todayOutbound int64
tx.Model(&models.Statist{}).
Where("stat_date >= ? AND stat_date <= ? AND is_del = ?", startDate, endDate, 0).
Select("COALESCE(SUM(receiving_num), 0), COALESCE(SUM(outbound_num), 0)").
Row().Scan(&todayInbound, &todayOutbound)
beforeYesterdayStart := time.Date(time.Unix(startDate, 0).Year(), time.Unix(startDate, 0).Month(), time.Unix(startDate, 0).Day()-1, 0, 0, 0, 0, time.Unix(startDate, 0).Location()).Unix()
beforeYesterdayEnd := time.Date(time.Unix(startDate, 0).Year(), time.Unix(startDate, 0).Month(), time.Unix(startDate, 0).Day()-1, 23, 59, 59, 0, time.Unix(startDate, 0).Location()).Unix()
var yesterdayInbound, yesterdayOutbound int64
tx.Model(&models.Statist{}).
Where("stat_date >= ? AND stat_date <= ? AND is_del = ?", beforeYesterdayStart, beforeYesterdayEnd, 0).
Select("COALESCE(SUM(receiving_num), 0), COALESCE(SUM(outbound_num), 0)").
Row().Scan(&yesterdayInbound, &yesterdayOutbound)
var totalSalesCount int64
tx.Model(&models.SalesOrder{}).
Where("created_at <= ? AND is_del = ?", endDate, 0).
Count(&totalSalesCount)
var todaySalesCount int64
tx.Model(&models.SalesOrder{}).
Where("created_at >= ? AND created_at <= ? AND is_del = ?", startDate, endDate, 0).
Count(&todaySalesCount)
var yesterdaySalesCount int64
tx.Model(&models.SalesOrder{}).
Where("created_at >= ? AND created_at <= ? AND is_del = ?", beforeYesterdayStart, beforeYesterdayEnd, 0).
Count(&yesterdaySalesCount)
var productTotal int64
tx.Model(&models.Product{}).
Where("is_del = ?", 0).
Count(&productTotal)
var inventoryTotal int64
tx.Model(&models.Inventory{}).
Where("is_del = ?", 0).
Select("COALESCE(SUM(quantity), 0)").
Row().Scan(&inventoryTotal)
now := time.Now().Unix()
dashboardStat := &models.DashboardDailyStat{
StatDate: statDate,
TotalReceivingNum: totalReceivingNum,
TotalOutboundNum: totalOutboundNum,
TotalSalesCount: totalSalesCount,
ProductTotal: productTotal,
InventoryTotal: inventoryTotal,
TodayInbound: todayInbound,
TodayOutbound: todayOutbound,
YesterdayInbound: yesterdayInbound,
YesterdayOutbound: yesterdayOutbound,
TodaySalesCount: todaySalesCount,
YesterdaySalesCount: yesterdaySalesCount,
CreatedAt: now,
UpdatedAt: now,
IsDel: 0,
}
if err := tx.Create(dashboardStat).Error; err != nil {
return nil, err
}
return dashboardStat, nil
}
// generateUserDailyStat 生成用户每日统计
func (s *StatistTaskService) generateUserDailyStat(tx *gorm.DB, aboutID int64, statDate int64, startDate, endDate int64) error {
type UserStatGroup struct {
UserID int64 `gorm:"column:user_id"`
UserName string `gorm:"column:user_name"`
ReceivingNum int64 `gorm:"column:receiving_num"`
OutboundNum int64 `gorm:"column:outbound_num"`
SalesCount int64 `gorm:"column:sales_count"`
}
var userStats []UserStatGroup
tx.Table("employee").
Select(`
employee.id as user_id,
employee.username as user_name,
COALESCE((SELECT SUM(receiving_num) FROM statist WHERE create_by = employee.id AND stat_date >= ? AND stat_date <= ? AND is_del = ?), 0) as receiving_num,
COALESCE((SELECT SUM(outbound_num) FROM statist WHERE create_by = employee.id AND stat_date >= ? AND stat_date <= ? AND is_del = ?), 0) as outbound_num,
COALESCE((SELECT COUNT(*) FROM sales_order WHERE create_by = employee.id AND created_at >= ? AND created_at <= ? AND is_del = ?), 0) as sales_count
`, startDate, endDate, 0, startDate, endDate, 0, startDate, endDate, 0).
Where("employee.about_id = ? AND employee.is_del = ?", aboutID, 0).
Scan(&userStats)
if len(userStats) == 0 {
return nil
}
now := time.Now().Unix()
for _, userStat := range userStats {
var existingStat models.UserDailyStat
err := tx.Where("user_id = ? AND stat_date = ? AND is_del = ?", userStat.UserID, statDate, 0).First(&existingStat).Error
if err == nil {
if err := tx.Model(&models.UserDailyStat{}).Where("id = ?", existingStat.ID).Update("is_del", 1).Error; err != nil {
continue
}
}
newStat := &models.UserDailyStat{
UserID: userStat.UserID,
UserName: userStat.UserName,
StatDate: statDate,
ReceivingNum: userStat.ReceivingNum,
OutboundNum: userStat.OutboundNum,
SalesCount: userStat.SalesCount,
CreatedAt: now,
UpdatedAt: now,
IsDel: 0,
}
if err := tx.Create(newStat).Error; err != nil {
utils.ErrorLog("work", map[string]interface{}{
"source": "生成用户统计",
"user_id": userStat.UserID,
"error": fmt.Sprintf("创建用户统计记录失败: %v", err),
})
}
}
return nil
}