ai_scheduler/internal/tools/bbxt/bbxt.go

330 lines
8.8 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 bbxt
import (
"ai_scheduler/internal/pkg/utils_oss"
"ai_scheduler/pkg"
"fmt"
"math/rand"
"sort"
"time"
)
const (
RedStyle = "${color: FF0000;horizontal:center;vertical:center;borderColor:#000000}"
GreenStyle = "${color: 00B050;horizontal:center;vertical:center;borderColor:#000000}"
)
type BbxtTools struct {
cacheDir string
excelTempDir string
ossClient *utils_oss.Client
}
func NewBbxtTools() (*BbxtTools, error) {
cache, err := pkg.GetCacheDir()
if err != nil {
return nil, err
}
tempDir, err := pkg.GetTmplDir()
if err != nil {
return nil, err
}
return &BbxtTools{
cacheDir: cache,
excelTempDir: fmt.Sprintf("%s/excel_temp", tempDir),
}, nil
}
func (b *BbxtTools) DailyReport(now time.Time, productName []string, ossClient *utils_oss.Client) (reports []*ReportRes, err error) {
reports = make([]*ReportRes, 0, 4)
productLossReport, err := b.StatisOursProductLossSum(now)
if err != nil {
return
}
profitRankingSum, err := b.GetProfitRankingSum(now)
if err != nil {
return
}
statisOfficialProductSum, err := b.GetStatisOfficialProductSum(now, productName)
if err != nil {
return
}
reports = append(reports, productLossReport...)
reports = append(reports, statisOfficialProductSum, profitRankingSum)
if ossClient != nil {
uploader := NewUploader(ossClient)
for _, report := range reports {
_ = uploader.Run(report)
}
}
return
}
// StatisOursProductLossSum 负利润分析
func (b *BbxtTools) StatisOursProductLossSum(now time.Time) (report []*ReportRes, err error) {
ct := []string{
time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Format("2006-01-02 15:04:05"),
adjustedTime(now), //adjustedTime(time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location())),
}
data, err := StatisOursProductLossSumApi(&StatisOursProductLossSumReq{
Ct: ct,
})
if err != nil {
return
}
var (
resellerMap = make(map[int32]*ResellerLoss)
total [][]string
gt []*ResellerLoss
)
for _, info := range data.List {
// 检查经销商是否已存在
if _, ok := resellerMap[info.ResellerId]; !ok {
// 创建新的经销商记录
resellerMap[info.ResellerId] = &ResellerLoss{
ResellerId: info.ResellerId,
ResellerName: info.ResellerName,
Total: 0, // 初始化为0后续累加
ProductLoss: make(map[int32]ProductLoss), // 初始化map
}
}
// 获取当前经销商
reseller := resellerMap[info.ResellerId]
// 累加经销商总亏损
reseller.Total += info.Loss
// 检查产品是否已存在
if _, ok := reseller.ProductLoss[info.OursProductId]; !ok {
// 创建新的产品亏损记录
reseller.ProductLoss[info.OursProductId] = ProductLoss{
ProductId: info.OursProductId,
ProductName: info.OursProductName,
Loss: info.Loss, // 初始化为当前产品的亏损
}
} else {
// 已存在产品记录,累加亏损
productLoss := reseller.ProductLoss[info.OursProductId]
productLoss.Loss += info.Loss
reseller.ProductLoss[info.OursProductId] = productLoss
}
}
// 按经销商总亏损排序
resellers := make([]*ResellerLoss, 0, len(resellerMap))
for _, v := range resellerMap {
resellers = append(resellers, v)
}
sort.Slice(resellers, func(i, j int) bool {
return resellers[i].Total < resellers[j].Total
})
var (
totalSum float64
totalSum500 float64
)
// 构建分组
for _, v := range resellers {
if v.Total <= -100 {
total = append(total, []string{
fmt.Sprintf("%s", v.ResellerName),
fmt.Sprintf("%.2f", v.Total),
})
}
if v.Total <= -500 {
gt = append(gt, v)
totalSum500 += v.Total
}
totalSum += v.Total
}
report = make([]*ReportRes, 2)
timeCh := now.Format("1月2日15点")
//总量生成excel
if len(total) > 0 {
filePath := b.cacheDir + "/kshj_total" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx"
err = b.SimpleFillExcelWithTitle(b.excelTempDir+"/"+"kshj_total.xlsx", filePath, total, "")
report[0] = &ReportRes{
ReportName: "负利润分析(合计表)",
Title: "截至今日" + timeCh + "利润累计亏损" + fmt.Sprintf("%.2f", totalSum),
Path: filePath,
Data: total,
}
}
if err != nil {
return
}
if len(gt) > 0 {
filePath := b.cacheDir + "/kshj_gt" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx"
err = b.resellerDetailFillExcelV2(b.excelTempDir+"/"+"kshj_gt.xlsx", filePath, gt)
report[1] = &ReportRes{
ReportName: "负利润分析(亏损500以上)",
Title: "截至今日" + timeCh + "亏顺500以上利润累计亏损" + fmt.Sprintf("%.2f", totalSum500),
Path: filePath,
Data: total,
}
}
if err != nil {
return
}
return report, nil
}
// GetProfitRankingSum 利润同比分销商排行榜
func (b *BbxtTools) GetProfitRankingSum(now time.Time) (report *ReportRes, err error) {
ct := []string{
time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Format("2006-01-02 15:04:05"),
adjustedTime(now),
}
data, err := GetProfitRankingSumApi(&GetProfitRankingSumRequest{
Ct: ct,
})
timeCh := now.Format("1月2日15点")
title := "截至" + timeCh + "利润同比分销商排行榜"
if err != nil {
return
}
//排序
sort.Slice(data.List, func(i, j int) bool {
return data.List[i].HistoryOneDiff > data.List[j].HistoryOneDiff
})
//取前20和后20
var (
total [][]string
top = data.List[:20]
bottom = data.List[len(data.List)-20:]
)
//合并前20和后20
top = append(top, bottom...)
// 构建分组
for _, v := range top {
var diff string
if v.HistoryOneDiff > 0 {
diff = fmt.Sprintf("%s↑%.4f", RedStyle, v.HistoryOneDiff)
} else {
diff = fmt.Sprintf("%s↓%.4f", GreenStyle, v.HistoryOneDiff)
}
total = append(total, []string{
fmt.Sprintf("%s", v.ResellerName),
fmt.Sprintf("%.4f", v.CurrentProfit),
fmt.Sprintf("%.4f", v.HistoryOneProfit),
diff,
})
}
//总量生成excel
if len(total) == 0 {
return
}
filePath := b.cacheDir + "/lrtb_rank" + fmt.Sprintf("%d", time.Now().Unix()) + ".xlsx"
err = b.SimpleFillExcelWithTitle(b.excelTempDir+"/"+"lrtb_rank.xlsx", filePath, total, title)
return &ReportRes{
ReportName: "利润同比分销商排行榜",
Title: title,
Path: filePath,
Data: total,
}, err
}
// GetStatisOfficialProductSum 利润同比分销商排行榜
func (b *BbxtTools) GetStatisOfficialProductSum(now time.Time, productName []string) (report *ReportRes, err error) {
ct := []string{
time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Format("2006-01-02 15:04:05"),
adjustedTime(now),
}
var ids []int32
if len(productName) > 0 {
ids, err = b.getProductIdFromProductName(productName)
if err != nil {
return
}
}
reqParam := &GetStatisOfficialProductSumRequest{
Ct: ct,
}
if len(ids) > 0 {
reqParam.OfficialProductId = ids
}
data, err := GetStatisOfficialProductSumApi(reqParam)
if err != nil {
return
}
var total [][]string
for _, v := range data.OfficialProductSum {
var (
yeterDatyDiff string
lastWeekDiff string
)
if v.HistoryOneDiff > 0 {
yeterDatyDiff = fmt.Sprintf("%s↑%d", RedStyle, v.HistoryOneDiff)
} else {
yeterDatyDiff = fmt.Sprintf("%s↓%d", GreenStyle, v.HistoryOneDiff)
}
if v.HistoryTwoDiff > 0 {
lastWeekDiff = fmt.Sprintf("%s↑%d", RedStyle, v.HistoryTwoDiff)
} else {
lastWeekDiff = fmt.Sprintf("%s↓%d", GreenStyle, v.HistoryTwoDiff)
}
total = append(total, []string{
fmt.Sprintf("%s", v.OfficialProductName),
fmt.Sprintf("%d", v.CurrentNum),
fmt.Sprintf("%d", v.HistoryOneNum),
yeterDatyDiff,
fmt.Sprintf("%d", v.HistoryTwoNum),
lastWeekDiff,
})
}
timeCh := now.Format("1月2日15点")
title := "截至" + timeCh + "销售同比分析"
//总量生成excel
if len(total) == 0 {
return
}
filePath := b.cacheDir + "/xstb_ana" + fmt.Sprintf("%d", time.Now().Unix()) + ".xlsx"
err = b.SimpleFillExcelWithTitle(b.excelTempDir+"/"+"xstb_ana.xlsx", filePath, total, title)
return &ReportRes{
ReportName: "利润同比分销商排行榜",
Title: title,
Path: filePath,
Data: total,
}, err
}
func (b *BbxtTools) getProductIdFromProductName(productNames []string) ([]int32, error) {
data, err := GetStatisFilterOfficialProductApi(&GetStatisFilterOfficialProductRequest{})
if err != nil {
return nil, err
}
var product2IdMap = make(map[string]int32)
for _, v := range data.List {
product2IdMap[v.OfficialProductName] = v.OfficialProductId
}
var ids []int32
for _, v := range productNames {
if id, ok := product2IdMap[v]; ok {
ids = append(ids, id)
}
}
return ids, nil
}
func adjustedTime(t time.Time) string {
adjusted := time.Date(
t.Year(), t.Month(), t.Day(),
t.Hour(), t.Minute(), 59, 999_000_000,
t.Location(),
)
return adjusted.Format("2006-01-02 15:04:05.999")
}