fix: 优化负利润分析和缓存处理逻辑
This commit is contained in:
parent
ecd2490a24
commit
fab60c6fc8
|
|
@ -1,11 +1,15 @@
|
||||||
package do
|
package do
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"ai_scheduler/internal/config"
|
||||||
"ai_scheduler/internal/data/impl"
|
"ai_scheduler/internal/data/impl"
|
||||||
"ai_scheduler/internal/data/model"
|
"ai_scheduler/internal/data/model"
|
||||||
"ai_scheduler/internal/pkg"
|
"ai_scheduler/internal/pkg"
|
||||||
|
"ai_scheduler/internal/pkg/lsxd"
|
||||||
"ai_scheduler/internal/tools/bbxt"
|
"ai_scheduler/internal/tools/bbxt"
|
||||||
|
"ai_scheduler/utils"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
@ -23,19 +27,25 @@ import (
|
||||||
type Macro struct {
|
type Macro struct {
|
||||||
botGroupImpl *impl.BotGroupImpl
|
botGroupImpl *impl.BotGroupImpl
|
||||||
reportDailyCacheImpl *impl.ReportDailyCacheImpl
|
reportDailyCacheImpl *impl.ReportDailyCacheImpl
|
||||||
|
config *config.Config
|
||||||
|
rdb *utils.Rdb
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMacro(
|
func NewMacro(
|
||||||
botGroupImpl *impl.BotGroupImpl,
|
botGroupImpl *impl.BotGroupImpl,
|
||||||
reportDailyCacheImpl *impl.ReportDailyCacheImpl,
|
reportDailyCacheImpl *impl.ReportDailyCacheImpl,
|
||||||
|
config *config.Config,
|
||||||
|
rdb *utils.Rdb,
|
||||||
) *Macro {
|
) *Macro {
|
||||||
return &Macro{
|
return &Macro{
|
||||||
botGroupImpl: botGroupImpl,
|
botGroupImpl: botGroupImpl,
|
||||||
reportDailyCacheImpl: reportDailyCacheImpl,
|
reportDailyCacheImpl: reportDailyCacheImpl,
|
||||||
|
config: config,
|
||||||
|
rdb: rdb,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type MacroFunc func(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool)
|
type MacroFunc func(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig, config *config.Config) (successMsg string, err error, isFinish bool)
|
||||||
|
|
||||||
func (m *Macro) Router(ctx context.Context, reqContent string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
|
func (m *Macro) Router(ctx context.Context, reqContent string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
|
||||||
reqContent = strings.TrimSpace(reqContent)
|
reqContent = strings.TrimSpace(reqContent)
|
||||||
|
|
@ -47,16 +57,16 @@ func (m *Macro) Router(ctx context.Context, reqContent string, groupConfig *mode
|
||||||
case strings.HasPrefix(reqContent, "[负利润分析]导出"):
|
case strings.HasPrefix(reqContent, "[负利润分析]导出"):
|
||||||
return m.NegativeProfitGet(ctx)
|
return m.NegativeProfitGet(ctx)
|
||||||
case strings.HasPrefix(reqContent, "[负利润分析]更新"):
|
case strings.HasPrefix(reqContent, "[负利润分析]更新"):
|
||||||
return m.NegativeProfitUpdate(ctx, reqContent, groupConfig)
|
return m.NegativeProfitUpdate(ctx, reqContent)
|
||||||
case strings.HasPrefix(reqContent, "[负利润分析]清理"):
|
case strings.HasPrefix(reqContent, "[负利润分析]清理"):
|
||||||
return m.NegativeProfitClear(ctx, reqContent, groupConfig)
|
return m.NegativeProfitClear()
|
||||||
default:
|
default:
|
||||||
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Macro) NegativeProfitClear(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
|
func (m *Macro) NegativeProfitClear() (successMsg string, err error, isFinish bool) {
|
||||||
dayDate := time.Now().Format(time.DateOnly)
|
dayDate := time.Now().Format(time.DateOnly)
|
||||||
cond := builder.NewCond()
|
cond := builder.NewCond()
|
||||||
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
|
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
|
||||||
|
|
@ -74,53 +84,88 @@ func (m *Macro) NegativeProfitClear(ctx context.Context, content string, groupCo
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Macro) NegativeProfitUpdate(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
|
func (m *Macro) NegativeProfitUpdate(ctx context.Context, content string) (successMsg string, err error, isFinish bool) {
|
||||||
//newContent := strings.ReplaceAll(strings.TrimSpace(content), "[负利润分析]更新:", "")
|
//newContent := strings.ReplaceAll(strings.TrimSpace(content), "[负利润分析]更新:", "")
|
||||||
jsonData, err := ParseLossData(content)
|
jsonData, err := ParseLossData(content)
|
||||||
|
b, err := bbxt.NewBbxtTools(m.config, lsxd.NewLogin(m.config, m.rdb))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("解析失败:%v", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dayDate := time.Now().Format(time.DateOnly)
|
now := time.Now()
|
||||||
|
dayData := now.Format(time.DateOnly)
|
||||||
|
value, err := b.GetMapResellerLossSumProductRelation(ctx, now, m.GetReportCache)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var setData = make(map[int32]*bbxt.ResellerLossSumProductRelation)
|
||||||
|
for k, v := range jsonData {
|
||||||
|
if _, ok := value[k]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for productId, product := range v.Products {
|
||||||
|
if _, ok := value[k].Products[productId]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if value[k].Products[productId].LossReason == product.LossReason {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ex := setData[k]; !ex {
|
||||||
|
setData[k] = &bbxt.ResellerLossSumProductRelation{
|
||||||
|
ResellerName: value[k].ResellerName,
|
||||||
|
AfterSaleName: value[k].AfterSaleName,
|
||||||
|
Products: make(map[int32]*bbxt.LossReason),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setData[k].Products[productId] = &bbxt.LossReason{
|
||||||
|
ProductName: product.ProductName,
|
||||||
|
LossReason: product.LossReason,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cond := builder.NewCond()
|
cond := builder.NewCond()
|
||||||
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
|
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
|
||||||
cond = cond.And(builder.Eq{"cache_key": dayDate})
|
cond = cond.And(builder.Eq{"cache_key": dayData})
|
||||||
err = m.reportDailyCacheImpl.UpdateByCond(&cond, &model.AiReportDailyCache{
|
cond = cond.And(builder.Eq{"status": 1})
|
||||||
Value: pkg.JsonStringIgonErr(jsonData),
|
var cache model.AiReportDailyCache
|
||||||
})
|
err = m.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("解析失败:%v", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if cache.ID == 0 {
|
||||||
|
|
||||||
|
cache = model.AiReportDailyCache{
|
||||||
|
CacheKey: dayData,
|
||||||
|
CacheIndex: bbxt.IndexLossSumDetail,
|
||||||
|
Value: pkg.JsonStringIgonErr(setData),
|
||||||
|
}
|
||||||
|
_, err = m.reportDailyCacheImpl.Add(&cache)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = m.reportDailyCacheImpl.UpdateByCond(&cond, &model.AiReportDailyCache{
|
||||||
|
Value: pkg.JsonStringIgonErr(setData),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
isFinish = true
|
isFinish = true
|
||||||
successMsg = "更新成功"
|
successMsg = "更新成功"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Macro) NegativeProfitGet(ctx context.Context) (successMsg string, err error, isFinish bool) {
|
func (m *Macro) NegativeProfitGet(ctx context.Context) (successMsg string, err error, isFinish bool) {
|
||||||
var (
|
b, err := bbxt.NewBbxtTools(m.config, lsxd.NewLogin(m.config, m.rdb))
|
||||||
data model.AiReportDailyCache
|
|
||||||
value map[int32]*bbxt.ResellerLossSumProductRelation
|
|
||||||
)
|
|
||||||
isFinish = true
|
|
||||||
cond := builder.NewCond()
|
|
||||||
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
|
|
||||||
cond = cond.And(builder.Eq{"cache_key": time.Now().Format(time.DateOnly)})
|
|
||||||
err = m.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &data)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("获取失败:%v", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if data.ID == 0 {
|
now := time.Now()
|
||||||
successMsg = "暂未获取今日负利润分析数据,请先呼出报表数据"
|
value, err := b.GetMapResellerLossSumProductRelation(ctx, now, m.GetReportCache)
|
||||||
return
|
|
||||||
}
|
|
||||||
err = json.Unmarshal([]byte(data.Value), &value)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("获取失败,格式解析错误:%v", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//将value转为string
|
//将value转为string
|
||||||
//**[供应商id]供应商名称->商务名称**\n
|
//**[供应商id]供应商名称->商务名称**\n
|
||||||
//└──商品名称:亏损原因\n
|
//└──商品名称:亏损原因\n
|
||||||
|
|
@ -136,6 +181,7 @@ func (m *Macro) NegativeProfitGet(ctx context.Context) (successMsg string, err e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
successMsg = valueString.String()
|
successMsg = valueString.String()
|
||||||
|
isFinish = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,3 +352,109 @@ func ParseLossData(input string) (map[int32]*bbxt.ResellerLossSumProductRelation
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Macro) GetReportCache(ctx context.Context, day time.Time, totalDetail []*bbxt.ResellerLoss, bbxtObj *bbxt.BbxtTools) error {
|
||||||
|
dayDate := day.Format(time.DateOnly)
|
||||||
|
|
||||||
|
// 1. 从 API 获取数据并填充
|
||||||
|
apiRelations, err := bbxtObj.GetResellerLossMannagerAndLossReasonFromApi(ctx, totalDetail)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get API data failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 API 数据填充损失原因
|
||||||
|
fillLossReasonFromData(totalDetail, apiRelations, "未填写")
|
||||||
|
|
||||||
|
// 2. 从缓存获取数据并覆盖
|
||||||
|
cachedRelations, err := m.getCachedRelations(dayDate)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get cache data failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用缓存数据覆盖损失原因
|
||||||
|
if cachedRelations != nil {
|
||||||
|
fillLossReasonFromData(totalDetail, cachedRelations, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从缓存获取关系数据
|
||||||
|
func (m *Macro) getCachedRelations(dayDate string) (map[int32]*bbxt.ResellerLossSumProductRelation, error) {
|
||||||
|
cond := builder.NewCond().
|
||||||
|
And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail}).
|
||||||
|
And(builder.Eq{"cache_key": dayDate}).
|
||||||
|
And(builder.Eq{"status": 1})
|
||||||
|
|
||||||
|
var cache model.AiReportDailyCache
|
||||||
|
err := m.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
// 缓存不存在是正常情况
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("query cache failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cache.ID == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var relations map[int32]*bbxt.ResellerLossSumProductRelation
|
||||||
|
if err := json.Unmarshal([]byte(cache.Value), &relations); err != nil {
|
||||||
|
return nil, fmt.Errorf("unmarshal cache failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return relations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用指定数据源填充损失原因
|
||||||
|
func fillLossReasonFromData(
|
||||||
|
totalDetail []*bbxt.ResellerLoss,
|
||||||
|
relations map[int32]*bbxt.ResellerLossSumProductRelation,
|
||||||
|
defaultReason string, // 当数据不存在时使用的默认值
|
||||||
|
) {
|
||||||
|
for _, detail := range totalDetail {
|
||||||
|
resellerRelation, exists := relations[detail.ResellerId]
|
||||||
|
if !exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置售后经理(只有在有值时才设置)
|
||||||
|
if resellerRelation.AfterSaleName != "" {
|
||||||
|
detail.Manager = resellerRelation.AfterSaleName
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为每个产品设置损失原因
|
||||||
|
for _, product := range detail.ProductLoss {
|
||||||
|
setProductLossReason(product, resellerRelation, defaultReason)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置单个产品的损失原因
|
||||||
|
func setProductLossReason(
|
||||||
|
product *bbxt.ProductLoss,
|
||||||
|
resellerRelation *bbxt.ResellerLossSumProductRelation,
|
||||||
|
defaultReason string,
|
||||||
|
) {
|
||||||
|
// 如果该经销商没有产品数据,跳过
|
||||||
|
if resellerRelation.Products == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
productRelation, exists := resellerRelation.Products[product.ProductId]
|
||||||
|
if !exists {
|
||||||
|
if defaultReason != "" {
|
||||||
|
product.LossReason = defaultReason
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有损失原因则设置,否则使用默认值
|
||||||
|
if productRelation.LossReason != "" {
|
||||||
|
product.LossReason = productRelation.LossReason
|
||||||
|
} else if defaultReason != "" {
|
||||||
|
product.LossReason = defaultReason
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package biz
|
package biz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"ai_scheduler/internal/biz/do"
|
||||||
"ai_scheduler/internal/biz/tools_regis"
|
"ai_scheduler/internal/biz/tools_regis"
|
||||||
"ai_scheduler/internal/config"
|
"ai_scheduler/internal/config"
|
||||||
"ai_scheduler/internal/data/constants"
|
"ai_scheduler/internal/data/constants"
|
||||||
|
|
@ -9,7 +10,6 @@ import (
|
||||||
"ai_scheduler/internal/domain/workflow/recharge"
|
"ai_scheduler/internal/domain/workflow/recharge"
|
||||||
"ai_scheduler/internal/domain/workflow/runtime"
|
"ai_scheduler/internal/domain/workflow/runtime"
|
||||||
"ai_scheduler/internal/entitys"
|
"ai_scheduler/internal/entitys"
|
||||||
"ai_scheduler/internal/pkg"
|
|
||||||
"ai_scheduler/internal/pkg/l_request"
|
"ai_scheduler/internal/pkg/l_request"
|
||||||
"ai_scheduler/internal/pkg/lsxd"
|
"ai_scheduler/internal/pkg/lsxd"
|
||||||
"ai_scheduler/internal/pkg/utils_oss"
|
"ai_scheduler/internal/pkg/utils_oss"
|
||||||
|
|
@ -41,6 +41,7 @@ type GroupConfigBiz struct {
|
||||||
toolManager *tools.Manager
|
toolManager *tools.Manager
|
||||||
conf *config.Config
|
conf *config.Config
|
||||||
rdb *utils.Rdb
|
rdb *utils.Rdb
|
||||||
|
macro *do.Macro
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDingTalkBotBiz
|
// NewDingTalkBotBiz
|
||||||
|
|
@ -52,6 +53,7 @@ func NewGroupConfigBiz(
|
||||||
conf *config.Config,
|
conf *config.Config,
|
||||||
reportDailyCacheImpl *impl.ReportDailyCacheImpl,
|
reportDailyCacheImpl *impl.ReportDailyCacheImpl,
|
||||||
rdb *utils.Rdb,
|
rdb *utils.Rdb,
|
||||||
|
macro *do.Macro,
|
||||||
) *GroupConfigBiz {
|
) *GroupConfigBiz {
|
||||||
return &GroupConfigBiz{
|
return &GroupConfigBiz{
|
||||||
botTools: tools.BootTools,
|
botTools: tools.BootTools,
|
||||||
|
|
@ -61,6 +63,7 @@ func NewGroupConfigBiz(
|
||||||
conf: conf,
|
conf: conf,
|
||||||
reportDailyCacheImpl: reportDailyCacheImpl,
|
reportDailyCacheImpl: reportDailyCacheImpl,
|
||||||
rdb: rdb,
|
rdb: rdb,
|
||||||
|
macro: macro,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,7 +89,7 @@ func (g *GroupConfigBiz) GetReportLists(ctx context.Context, groupConfig *model.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
reports, err = reportList.DailyReport(ctx, time.Now(), bbxt.DownWardValue, product, bbxt.SumFilter, g.ossClient, g.GetReportCache)
|
reports, err = reportList.DailyReport(ctx, time.Now(), bbxt.DownWardValue, product, bbxt.SumFilter, g.ossClient, g.macro.GetReportCache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -163,7 +166,7 @@ func (g *GroupConfigBiz) handleReport(ctx context.Context, rec *entitys.Recogniz
|
||||||
var reports []*bbxt.ReportRes
|
var reports []*bbxt.ReportRes
|
||||||
switch rec.Match.Index {
|
switch rec.Match.Index {
|
||||||
case "report_loss_analysis":
|
case "report_loss_analysis":
|
||||||
repo, _err := rep.StatisOursProductLossSum(ctx, t, g.GetReportCache)
|
repo, _err := rep.StatisOursProductLossSum(ctx, t, g.macro.GetReportCache)
|
||||||
if _err != nil {
|
if _err != nil {
|
||||||
return _err
|
return _err
|
||||||
}
|
}
|
||||||
|
|
@ -184,7 +187,7 @@ func (g *GroupConfigBiz) handleReport(ctx context.Context, rec *entitys.Recogniz
|
||||||
reports = append(reports, repo)
|
reports = append(reports, repo)
|
||||||
case "report_daily":
|
case "report_daily":
|
||||||
product := strings.Split(groupConfig.ProductName, ",")
|
product := strings.Split(groupConfig.ProductName, ",")
|
||||||
repo, _err := rep.DailyReport(ctx, t, bbxt.DownWardValue, product, bbxt.SumFilter, nil, g.GetReportCache)
|
repo, _err := rep.DailyReport(ctx, t, bbxt.DownWardValue, product, bbxt.SumFilter, nil, g.macro.GetReportCache)
|
||||||
if _err != nil {
|
if _err != nil {
|
||||||
return _err
|
return _err
|
||||||
}
|
}
|
||||||
|
|
@ -413,55 +416,3 @@ func (g *GroupConfigBiz) otherTask(ctx context.Context, rec *entitys.Recognize)
|
||||||
entitys.ResText(rec.Ch, "", rec.Match.Reasoning)
|
entitys.ResText(rec.Ch, "", rec.Match.Reasoning)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupConfigBiz) GetReportCache(ctx context.Context, day time.Time, totalDetail []*bbxt.ResellerLoss, bbxtObj *bbxt.BbxtTools) error {
|
|
||||||
var ResellerProductRelation map[int32]*bbxt.ResellerLossSumProductRelation
|
|
||||||
|
|
||||||
dayDate := day.Format(time.DateOnly)
|
|
||||||
cond := builder.NewCond()
|
|
||||||
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
|
|
||||||
cond = cond.And(builder.Eq{"cache_key": dayDate})
|
|
||||||
cond = cond.And(builder.Eq{"status": 1})
|
|
||||||
var cache model.AiReportDailyCache
|
|
||||||
err := g.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if cache.ID == 0 {
|
|
||||||
ResellerProductRelation, err = bbxtObj.GetResellerLossMannagerAndLossReasonFromApi(ctx, totalDetail)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cache = model.AiReportDailyCache{
|
|
||||||
CacheKey: dayDate,
|
|
||||||
CacheIndex: bbxt.IndexLossSumDetail,
|
|
||||||
Value: pkg.JsonStringIgonErr(ResellerProductRelation),
|
|
||||||
}
|
|
||||||
_, err = g.reportDailyCacheImpl.Add(&cache)
|
|
||||||
} else {
|
|
||||||
err = json.Unmarshal([]byte(cache.Value), &ResellerProductRelation)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, v := range totalDetail {
|
|
||||||
if _, ex := ResellerProductRelation[v.ResellerId]; !ex {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
v.Manager = ResellerProductRelation[v.ResellerId].AfterSaleName
|
|
||||||
for _, vv := range v.ProductLoss {
|
|
||||||
if _, ex := ResellerProductRelation[v.ResellerId].Products[vv.ProductId]; !ex {
|
|
||||||
vv.LossReason = "未填写"
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(ResellerProductRelation[v.ResellerId].Products[vv.ProductId].LossReason) == 0 {
|
|
||||||
vv.LossReason = "未填写"
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
vv.LossReason = ResellerProductRelation[v.ResellerId].Products[vv.ProductId].LossReason
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ var (
|
||||||
SumFilter int32 = -150
|
SumFilter int32 = -150
|
||||||
)
|
)
|
||||||
|
|
||||||
var resellerBlackListProduct = []string{
|
var ResellerBlackListProduct = []string{
|
||||||
"悦跑",
|
"悦跑",
|
||||||
"电商-独立",
|
"电商-独立",
|
||||||
"蓝星严选连续包月",
|
"蓝星严选连续包月",
|
||||||
|
|
@ -103,9 +103,7 @@ func (b *BbxtTools) DailyReport(
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (b *BbxtTools) ResellerLossSort(ctx context.Context, now time.Time) ([]*ResellerLoss, error) {
|
||||||
// StatisOursProductLossSum 负利润分析
|
|
||||||
func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time, initFunc LossSumInitFunc) (report []*ReportRes, err error) {
|
|
||||||
ct := []string{
|
ct := []string{
|
||||||
time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Format("2006-01-02 15:04:05"),
|
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())),
|
adjustedTime(now), //adjustedTime(time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location())),
|
||||||
|
|
@ -115,13 +113,10 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time,
|
||||||
Ct: ct,
|
Ct: ct,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
resellerMap = make(map[int32]*ResellerLoss)
|
resellerMap = make(map[int32]*ResellerLoss)
|
||||||
total [][]string
|
|
||||||
gt []*ResellerLoss
|
|
||||||
totalDetail []*ResellerLoss
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, info := range data.List {
|
for _, info := range data.List {
|
||||||
|
|
@ -166,14 +161,66 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time,
|
||||||
sort.Slice(resellers, func(i, j int) bool {
|
sort.Slice(resellers, func(i, j int) bool {
|
||||||
return resellers[i].Total < resellers[j].Total
|
return resellers[i].Total < resellers[j].Total
|
||||||
})
|
})
|
||||||
var (
|
return resellers, nil
|
||||||
totalSum float64
|
}
|
||||||
|
|
||||||
|
func (b *BbxtTools) GetMapResellerLossSumProductRelation(ctx context.Context, now time.Time, initFunc LossSumInitFunc) (map[int32]*ResellerLossSumProductRelation, error) {
|
||||||
|
resellers, err := b.ResellerLossSort(ctx, now)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var totalDetail []*ResellerLoss
|
||||||
|
for _, v := range resellers {
|
||||||
|
if v.Total <= -100 && !slices.Contains(ResellerBlackListProduct, v.ResellerName) {
|
||||||
|
|
||||||
|
totalDetail = append(totalDetail, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if len(totalDetail) > 0 {
|
||||||
|
err = initFunc(ctx, now, totalDetail, b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value := b.ResellerLossToMapResellerLossSumProductRelation(totalDetail)
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BbxtTools) ResellerLossToMapResellerLossSumProductRelation(totalDetail []*ResellerLoss) map[int32]*ResellerLossSumProductRelation {
|
||||||
|
relations := make(map[int32]*ResellerLossSumProductRelation)
|
||||||
|
for _, detail := range totalDetail {
|
||||||
|
if _, ok := relations[detail.ResellerId]; !ok {
|
||||||
|
relations[detail.ResellerId] = &ResellerLossSumProductRelation{
|
||||||
|
ResellerName: detail.ResellerName,
|
||||||
|
AfterSaleName: detail.Manager,
|
||||||
|
Products: make(map[int32]*LossReason),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, product := range detail.ProductLoss {
|
||||||
|
relations[detail.ResellerId].Products[product.ProductId] = &LossReason{
|
||||||
|
ProductName: product.ProductName,
|
||||||
|
LossReason: product.LossReason,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return relations
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatisOursProductLossSum 负利润分析
|
||||||
|
func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time, initFunc LossSumInitFunc) (report []*ReportRes, err error) {
|
||||||
|
resellers, err := b.ResellerLossSort(ctx, now)
|
||||||
|
var (
|
||||||
|
total [][]string
|
||||||
|
gt []*ResellerLoss
|
||||||
|
totalDetail []*ResellerLoss
|
||||||
|
totalSum float64
|
||||||
totalSum500 float64
|
totalSum500 float64
|
||||||
)
|
)
|
||||||
// 构建分组
|
// 构建分组
|
||||||
for _, v := range resellers {
|
for _, v := range resellers {
|
||||||
if v.Total <= -100 && !slices.Contains(resellerBlackListProduct, v.ResellerName) {
|
if v.Total <= -100 && !slices.Contains(ResellerBlackListProduct, v.ResellerName) {
|
||||||
total = append(total, []string{
|
total = append(total, []string{
|
||||||
fmt.Sprintf("%s", v.ResellerName),
|
fmt.Sprintf("%s", v.ResellerName),
|
||||||
fmt.Sprintf("%.2f", v.Total),
|
fmt.Sprintf("%.2f", v.Total),
|
||||||
|
|
@ -181,7 +228,7 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time,
|
||||||
totalSum += v.Total
|
totalSum += v.Total
|
||||||
totalDetail = append(totalDetail, v)
|
totalDetail = append(totalDetail, v)
|
||||||
}
|
}
|
||||||
if v.Total <= -500 && !slices.Contains(resellerBlackListProduct, v.ResellerName) {
|
if v.Total <= -500 && !slices.Contains(ResellerBlackListProduct, v.ResellerName) {
|
||||||
gt = append(gt, v)
|
gt = append(gt, v)
|
||||||
totalSum500 += v.Total
|
totalSum500 += v.Total
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue