fix: 优化负利润分析报表处理逻辑
This commit is contained in:
parent
c96ee6cc38
commit
219df62816
|
|
@ -19,7 +19,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
|
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
|
||||||
|
|
||||||
|
|
@ -45,6 +44,7 @@ type DingTalkBotBiz struct {
|
||||||
qywxGroupHandle *qywx.Group
|
qywxGroupHandle *qywx.Group
|
||||||
groupConfigBiz *GroupConfigBiz
|
groupConfigBiz *GroupConfigBiz
|
||||||
reportDailyCacheImpl *impl.ReportDailyCacheImpl
|
reportDailyCacheImpl *impl.ReportDailyCacheImpl
|
||||||
|
macro *do.Macro
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDingTalkBotBiz
|
// NewDingTalkBotBiz
|
||||||
|
|
@ -60,6 +60,7 @@ func NewDingTalkBotBiz(
|
||||||
conf *config.Config,
|
conf *config.Config,
|
||||||
cardSend *dingtalk.SendCardClient,
|
cardSend *dingtalk.SendCardClient,
|
||||||
groupConfigBiz *GroupConfigBiz,
|
groupConfigBiz *GroupConfigBiz,
|
||||||
|
macro *do.Macro,
|
||||||
) *DingTalkBotBiz {
|
) *DingTalkBotBiz {
|
||||||
return &DingTalkBotBiz{
|
return &DingTalkBotBiz{
|
||||||
do: do,
|
do: do,
|
||||||
|
|
@ -74,6 +75,7 @@ func NewDingTalkBotBiz(
|
||||||
conf: conf,
|
conf: conf,
|
||||||
cardSend: cardSend,
|
cardSend: cardSend,
|
||||||
reportDailyCacheImpl: reportDailyCacheImpl,
|
reportDailyCacheImpl: reportDailyCacheImpl,
|
||||||
|
macro: macro,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,10 +150,14 @@ func (d *DingTalkBotBiz) handleGroupChat(ctx context.Context, requireData *entit
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//宏
|
//宏
|
||||||
err, isFinal := d.Macro(ctx, requireData, groupConfig)
|
sucMsg, err, isFinal := d.macro.Router(ctx, requireData.Req.Text.Content, groupConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
entitys.ResText(requireData.Ch, "", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if len(sucMsg) > 0 {
|
||||||
|
entitys.ResText(requireData.Ch, "", sucMsg)
|
||||||
|
}
|
||||||
if isFinal {
|
if isFinal {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -168,102 +174,6 @@ func (d *DingTalkBotBiz) handleGroupChat(ctx context.Context, requireData *entit
|
||||||
return d.groupConfigBiz.handleMatch(ctx, rec, groupConfig)
|
return d.groupConfigBiz.handleMatch(ctx, rec, groupConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DingTalkBotBiz) Macro(ctx context.Context, requireData *entitys.RequireDataDingTalkBot, groupConfig *model.AiBotGroupConfig) (err error, isFinish bool) {
|
|
||||||
content := processString(requireData.Req.Text.Content)
|
|
||||||
|
|
||||||
if strings.Contains(content, "[利润同比报表]商品修改:") {
|
|
||||||
// 提取冒号后的内容
|
|
||||||
if parts := strings.SplitN(content, ":", 2); len(parts) == 2 {
|
|
||||||
itemInfo := strings.TrimSpace(parts[1])
|
|
||||||
log.Infof("商品修改信息: %s", itemInfo)
|
|
||||||
groupConfig.ProductName = itemInfo
|
|
||||||
cond := builder.NewCond()
|
|
||||||
cond = cond.And(builder.Eq{"config_id": groupConfig.ConfigID})
|
|
||||||
err = d.botGroupImpl.UpdateByCond(&cond, groupConfig)
|
|
||||||
if err != nil {
|
|
||||||
entitys.ResText(requireData.Ch, "", fmt.Sprintf("修改失败:%v", err))
|
|
||||||
}
|
|
||||||
entitys.ResText(requireData.Ch, "", "修改成功")
|
|
||||||
isFinish = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(content, "[利润同比报表]商品列表") {
|
|
||||||
// 提取冒号后的内容
|
|
||||||
if len(groupConfig.ProductName) == 0 {
|
|
||||||
entitys.ResText(requireData.Ch, "", "暂未设置")
|
|
||||||
} else {
|
|
||||||
entitys.ResText(requireData.Ch, "", groupConfig.ProductName)
|
|
||||||
isFinish = true
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(content, "[负利润分析]获取") {
|
|
||||||
var (
|
|
||||||
data model.AiReportDailyCache
|
|
||||||
value map[int32]*bbxt.ResellerLossSumProductRelation
|
|
||||||
)
|
|
||||||
cond := builder.NewCond()
|
|
||||||
cond = cond.And(builder.Eq{"`index`": bbxt.IndexLossSumDetail})
|
|
||||||
cond = cond.And(builder.Eq{"`key`": time.Now().Format(time.DateOnly)})
|
|
||||||
err = d.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &data)
|
|
||||||
if err != nil {
|
|
||||||
entitys.ResText(requireData.Ch, "", "获取失败")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = json.Unmarshal([]byte(data.Value), &value)
|
|
||||||
if err != nil {
|
|
||||||
entitys.ResText(requireData.Ch, "", "获取失败,格式解析错误")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(content, "[负利润分析]更新") {
|
|
||||||
// 提取冒号后的内容
|
|
||||||
if len(groupConfig.ProductName) == 0 {
|
|
||||||
entitys.ResText(requireData.Ch, "", "暂未设置")
|
|
||||||
} else {
|
|
||||||
entitys.ResText(requireData.Ch, "", groupConfig.ProductName)
|
|
||||||
isFinish = true
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(content, "[负利润分析]同步") {
|
|
||||||
// 提取冒号后的内容
|
|
||||||
if len(groupConfig.ProductName) == 0 {
|
|
||||||
entitys.ResText(requireData.Ch, "", "暂未设置")
|
|
||||||
} else {
|
|
||||||
entitys.ResText(requireData.Ch, "", groupConfig.ProductName)
|
|
||||||
isFinish = true
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func processString(s string) string {
|
|
||||||
// 1. 替换中文逗号为英文逗号
|
|
||||||
s = strings.ReplaceAll(s, ",", ",")
|
|
||||||
|
|
||||||
// 2. 过滤控制字符(如 \n, \t, \r 等)
|
|
||||||
var result []rune
|
|
||||||
for _, char := range s {
|
|
||||||
// 判断是否是控制字符(ASCII < 32 或 = 127)
|
|
||||||
if !unicode.IsControl(char) {
|
|
||||||
// 如果需要完全移除 \n 和 \t,可以改成:
|
|
||||||
// if !unicode.IsControl(char)
|
|
||||||
result = append(result, char)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DingTalkBotBiz) initGroup(ctx context.Context, conversationId string, conversationTitle string, robotCode string) (group *model.AiBotGroup, err error) {
|
func (d *DingTalkBotBiz) initGroup(ctx context.Context, conversationId string, conversationTitle string, robotCode string) (group *model.AiBotGroup, err error) {
|
||||||
group, err = d.botGroupImpl.GetByConversationIdAndRobotCode(conversationId, robotCode)
|
group, err = d.botGroupImpl.GetByConversationIdAndRobotCode(conversationId, robotCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,288 @@
|
||||||
|
package do
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ai_scheduler/internal/data/impl"
|
||||||
|
"ai_scheduler/internal/data/model"
|
||||||
|
"ai_scheduler/internal/pkg"
|
||||||
|
|
||||||
|
"ai_scheduler/internal/tools/bbxt"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2/log"
|
||||||
|
"xorm.io/builder"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Macro struct {
|
||||||
|
botGroupImpl *impl.BotGroupImpl
|
||||||
|
reportDailyCacheImpl *impl.ReportDailyCacheImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMacro(
|
||||||
|
botGroupImpl *impl.BotGroupImpl,
|
||||||
|
reportDailyCacheImpl *impl.ReportDailyCacheImpl,
|
||||||
|
) *Macro {
|
||||||
|
return &Macro{
|
||||||
|
botGroupImpl: botGroupImpl,
|
||||||
|
reportDailyCacheImpl: reportDailyCacheImpl,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MacroFunc func(ctx context.Context, content 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)
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(reqContent, "[利润同比报表]商品修改"):
|
||||||
|
return m.ProductModify(ctx, reqContent, groupConfig)
|
||||||
|
case strings.HasPrefix(reqContent, "[利润同比报表]商品列表"):
|
||||||
|
return m.ProductList(ctx, groupConfig)
|
||||||
|
case strings.HasPrefix(reqContent, "[负利润分析]导出"):
|
||||||
|
return m.NegativeProfitGet(ctx)
|
||||||
|
case strings.HasPrefix(reqContent, "[负利润分析]更新"):
|
||||||
|
return m.NegativeProfitUpdate(ctx, reqContent, groupConfig)
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Macro) NegativeProfitUpdate(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
|
||||||
|
//newContent := strings.ReplaceAll(strings.TrimSpace(content), "[负利润分析]更新:", "")
|
||||||
|
jsonData, err := ParseLossData(content)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("解析失败:%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dayDate := time.Now().Format(time.DateOnly)
|
||||||
|
cond := builder.NewCond()
|
||||||
|
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
|
||||||
|
cond = cond.And(builder.Eq{"cache_key": dayDate})
|
||||||
|
err = m.reportDailyCacheImpl.UpdateByCond(&cond, &model.AiReportDailyCache{
|
||||||
|
Value: pkg.JsonStringIgonErr(jsonData),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("解析失败:%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isFinish = true
|
||||||
|
successMsg = "更新成功"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Macro) NegativeProfitGet(ctx context.Context) (successMsg string, err error, isFinish bool) {
|
||||||
|
var (
|
||||||
|
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 {
|
||||||
|
err = fmt.Errorf("获取失败:%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if data.ID == 0 {
|
||||||
|
successMsg = "暂未获取今日负利润分析数据,请先呼出报表数据"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.Unmarshal([]byte(data.Value), &value)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("获取失败,格式解析错误:%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//将value转为string
|
||||||
|
//**[供应商id]供应商名称->商务名称**\n
|
||||||
|
//└──商品名称:亏损原因\n
|
||||||
|
var valueString strings.Builder
|
||||||
|
valueString.WriteString("[负利润分析]更新:\n")
|
||||||
|
for k, v := range value {
|
||||||
|
if len(v.AfterSaleName) == 0 {
|
||||||
|
v.AfterSaleName = "未查找到对应商务"
|
||||||
|
}
|
||||||
|
valueString.WriteString(fmt.Sprintf("**[%d]%s->%s**\n", k, v.ResellerName, v.AfterSaleName))
|
||||||
|
for kk, vv := range v.Products {
|
||||||
|
valueString.WriteString(fmt.Sprintf("└── [%d]%s:%s\n", kk, vv.ProductName, vv.LossReason))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
successMsg = valueString.String()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Macro) ProductModify(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
|
||||||
|
content = processString(content)
|
||||||
|
if parts := strings.SplitN(content, ":", 2); len(parts) == 2 {
|
||||||
|
itemInfo := strings.TrimSpace(parts[1])
|
||||||
|
log.Infof("商品修改信息: %s", itemInfo)
|
||||||
|
groupConfig.ProductName = itemInfo
|
||||||
|
cond := builder.NewCond()
|
||||||
|
cond = cond.And(builder.Eq{"config_id": groupConfig.ConfigID})
|
||||||
|
err = m.botGroupImpl.UpdateByCond(&cond, groupConfig)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("修改失败:%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
successMsg = "修改成功"
|
||||||
|
isFinish = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Macro) ProductList(ctx context.Context, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
|
||||||
|
if len(groupConfig.ProductName) == 0 {
|
||||||
|
successMsg = "暂未设置"
|
||||||
|
} else {
|
||||||
|
successMsg = groupConfig.ProductName
|
||||||
|
isFinish = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func processString(s string) string {
|
||||||
|
// 替换中文逗号为英文逗号
|
||||||
|
s = strings.ReplaceAll(s, ",", ",")
|
||||||
|
|
||||||
|
return string(clearSpacialFormat(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearSpacialFormat(s string) (result []rune) {
|
||||||
|
//过滤控制字符(如 \n, \t, \r 等)
|
||||||
|
for _, char := range s {
|
||||||
|
// 判断是否是控制字符(ASCII < 32 或 = 127)
|
||||||
|
if !unicode.IsControl(char) {
|
||||||
|
// 如果需要完全移除 \n 和 \t,可以改成:
|
||||||
|
// if !unicode.IsControl(char)
|
||||||
|
result = append(result, char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseLossData(input string) (map[int32]*bbxt.ResellerLossSumProductRelation, error) {
|
||||||
|
result := make(map[int32]*bbxt.ResellerLossSumProductRelation)
|
||||||
|
|
||||||
|
// 按行分割
|
||||||
|
lines := strings.Split(input, "\n")
|
||||||
|
|
||||||
|
// 跳过第一行的标题
|
||||||
|
startIdx := 0
|
||||||
|
for i, line := range lines {
|
||||||
|
if strings.HasPrefix(line, "[") && strings.Contains(line, "]") && strings.Contains(line, "->") {
|
||||||
|
startIdx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentResellerID int32
|
||||||
|
var currentReseller *bbxt.ResellerLossSumProductRelation
|
||||||
|
|
||||||
|
for i := startIdx; i < len(lines); i++ {
|
||||||
|
line := strings.TrimSpace(lines[i])
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是供应商行(以 [ 开头)
|
||||||
|
if strings.HasPrefix(line, "[") && strings.Contains(line, "]") {
|
||||||
|
// 解析供应商行:[25131]兴业银行-营销系统->未查找到对应商务
|
||||||
|
|
||||||
|
// 找到第一个 ] 的位置
|
||||||
|
bracketEnd := strings.Index(line, "]")
|
||||||
|
if bracketEnd == -1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取供应商ID
|
||||||
|
idStr := line[1:bracketEnd]
|
||||||
|
id, err := strconv.ParseInt(idStr, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
currentResellerID = int32(id)
|
||||||
|
|
||||||
|
// 提取供应商名称和商务名称
|
||||||
|
remaining := strings.TrimSpace(line[bracketEnd+1:])
|
||||||
|
|
||||||
|
// 分割供应商名称和商务名称
|
||||||
|
var resellerName, afterSaleName string
|
||||||
|
arrowIdx := strings.Index(remaining, "->")
|
||||||
|
if arrowIdx != -1 {
|
||||||
|
resellerName = strings.TrimSpace(remaining[:arrowIdx])
|
||||||
|
afterSaleName = strings.TrimSpace(remaining[arrowIdx+2:])
|
||||||
|
} else {
|
||||||
|
resellerName = remaining
|
||||||
|
afterSaleName = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新的供应商对象
|
||||||
|
currentReseller = &bbxt.ResellerLossSumProductRelation{
|
||||||
|
AfterSaleName: afterSaleName,
|
||||||
|
ResellerName: resellerName,
|
||||||
|
Products: make(map[int32]*bbxt.LossReason),
|
||||||
|
}
|
||||||
|
|
||||||
|
result[currentResellerID] = currentReseller
|
||||||
|
|
||||||
|
} else if strings.Contains(line, "└──") {
|
||||||
|
// 解析商品行:└── [460]全国话费30元:未填写
|
||||||
|
if currentReseller == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除└──前缀
|
||||||
|
productLine := strings.TrimPrefix(line, "└──")
|
||||||
|
productLine = strings.TrimSpace(productLine)
|
||||||
|
|
||||||
|
if !strings.HasPrefix(productLine, "[") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到商品ID的结束位置
|
||||||
|
prodBracketEnd := strings.Index(productLine, "]")
|
||||||
|
if prodBracketEnd == -1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取商品ID
|
||||||
|
prodIDStr := productLine[1:prodBracketEnd]
|
||||||
|
prodID, err := strconv.ParseInt(prodIDStr, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取商品名称和亏损原因
|
||||||
|
prodRemaining := strings.TrimSpace(productLine[prodBracketEnd+1:])
|
||||||
|
|
||||||
|
// 找到冒号分隔符
|
||||||
|
colonIdx := strings.Index(prodRemaining, ":")
|
||||||
|
var productName, lossReason string
|
||||||
|
|
||||||
|
if colonIdx != -1 {
|
||||||
|
productName = strings.TrimSpace(prodRemaining[:colonIdx])
|
||||||
|
lossReason = strings.TrimSpace(prodRemaining[colonIdx+1:])
|
||||||
|
} else {
|
||||||
|
productName = prodRemaining
|
||||||
|
lossReason = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加到当前供应商的商品列表中
|
||||||
|
currentReseller.Products[int32(prodID)] = &bbxt.LossReason{
|
||||||
|
ProductName: productName,
|
||||||
|
LossReason: lossReason,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,6 @@ import (
|
||||||
"ai_scheduler/internal/tools/bbxt"
|
"ai_scheduler/internal/tools/bbxt"
|
||||||
"ai_scheduler/utils"
|
"ai_scheduler/utils"
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -421,26 +420,28 @@ func (g *GroupConfigBiz) GetReportCache(ctx context.Context, day time.Time, tota
|
||||||
|
|
||||||
dayDate := day.Format(time.DateOnly)
|
dayDate := day.Format(time.DateOnly)
|
||||||
cond := builder.NewCond()
|
cond := builder.NewCond()
|
||||||
cond = cond.And(builder.Eq{"index": bbxt.IndexLossSumDetail})
|
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
|
||||||
cond = cond.And(builder.Eq{"key": dayDate})
|
cond = cond.And(builder.Eq{"cache_key": dayDate})
|
||||||
var cache model.AiReportDailyCache
|
var cache model.AiReportDailyCache
|
||||||
err := g.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
|
err := g.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(sql.ErrNoRows, err) {
|
return err
|
||||||
ResellerProductRelation, err = bbxtObj.GetResellerLossMannagerAndLossReasonFromApi(ctx, totalDetail)
|
}
|
||||||
if err != nil {
|
if cache.ID == 0 {
|
||||||
return err
|
ResellerProductRelation, err = bbxtObj.GetResellerLossMannagerAndLossReasonFromApi(ctx, totalDetail)
|
||||||
}
|
if err != nil {
|
||||||
cache = model.AiReportDailyCache{
|
return err
|
||||||
Key: dayDate,
|
|
||||||
Index: bbxt.IndexLossSumDetail,
|
|
||||||
Value: pkg.JsonStringIgonErr(ResellerProductRelation),
|
|
||||||
}
|
|
||||||
_, err = g.reportDailyCacheImpl.Add(&cache)
|
|
||||||
}
|
}
|
||||||
|
cache = model.AiReportDailyCache{
|
||||||
|
CacheKey: dayDate,
|
||||||
|
CacheIndex: bbxt.IndexLossSumDetail,
|
||||||
|
Value: pkg.JsonStringIgonErr(ResellerProductRelation),
|
||||||
|
}
|
||||||
|
_, err = g.reportDailyCacheImpl.Add(&cache)
|
||||||
} else {
|
} else {
|
||||||
err = json.Unmarshal([]byte(cache.Value), &ResellerProductRelation)
|
err = json.Unmarshal([]byte(cache.Value), &ResellerProductRelation)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,4 +20,5 @@ var ProviderSetBiz = wire.NewSet(
|
||||||
NewDingTalkBotBiz,
|
NewDingTalkBotBiz,
|
||||||
NewQywxAppBiz,
|
NewQywxAppBiz,
|
||||||
NewGroupConfigBiz,
|
NewGroupConfigBiz,
|
||||||
|
do.NewMacro,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ const TableNameAiReportDailyCache = "ai_report_daily_cache"
|
||||||
|
|
||||||
// AiReportDailyCache mapped from table <ai_report_daily_cache>
|
// AiReportDailyCache mapped from table <ai_report_daily_cache>
|
||||||
type AiReportDailyCache struct {
|
type AiReportDailyCache struct {
|
||||||
ID int32 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
|
ID int32 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
|
||||||
Key string `gorm:"column:key;not null;default:1;comment:索引方式,可以是任意类型" json:"key"` // 索引方式,可以是任意类型
|
CacheKey string `gorm:"column:cache_key;not null;default:1;comment:索引方式,可以是任意类型" json:"cache_key"` // 索引方式,可以是任意类型
|
||||||
Value string `gorm:"column:value;comment:类型下所需路由以及参数" json:"value"` // 类型下所需路由以及参数
|
Value string `gorm:"column:value;comment:类型下所需路由以及参数" json:"value"` // 类型下所需路由以及参数
|
||||||
Index string `gorm:"column:index;not null;comment:类型" json:"index"` // 类型
|
CacheIndex string `gorm:"column:cache_index;not null;comment:类型" json:"cache_index"` // 类型
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableName AiReportDailyCache's table name
|
// TableName AiReportDailyCache's table name
|
||||||
|
|
|
||||||
|
|
@ -189,53 +189,53 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time,
|
||||||
report = make([]*ReportRes, 3)
|
report = make([]*ReportRes, 3)
|
||||||
timeCh := now.Format("1月2日15点")
|
timeCh := now.Format("1月2日15点")
|
||||||
//总量生成excel
|
//总量生成excel
|
||||||
if len(total) > 0 {
|
//if len(total) > 0 {
|
||||||
filePath := b.cacheDir + "/kshj_total" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx"
|
// 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, "")
|
// err = b.SimpleFillExcelWithTitle(b.excelTempDir+"/"+"kshj_total.xlsx", filePath, total, "")
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
report[0] = &ReportRes{
|
|
||||||
ReportName: "分销商负利润统计",
|
|
||||||
Title: "截至" + timeCh + "利润累计亏损" + fmt.Sprintf("%.2f", totalSum),
|
|
||||||
Path: filePath,
|
|
||||||
Data: total,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(gt) > 0 {
|
|
||||||
filePath := b.cacheDir + "/kshj_gt" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx"
|
|
||||||
title := "截至" + timeCh + "亏损500以上的分销商和产品"
|
|
||||||
err = b.resellerDetailFillExcelV2(b.excelTempDir+"/"+"kshj_gt.xlsx", filePath, gt, title)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
report[1] = &ReportRes{
|
|
||||||
ReportName: "负利润分析(亏损500以上)",
|
|
||||||
Title: "截至" + timeCh + "亏损500以上利润累计亏损" + fmt.Sprintf("%.2f", totalSum500),
|
|
||||||
Path: filePath,
|
|
||||||
Data: total,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if len(totalDetail) > 0 {
|
|
||||||
// err = initFunc(ctx, now, totalDetail, b)
|
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
// filePath := b.cacheDir + "/kshj_total_ana" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx"
|
// report[0] = &ReportRes{
|
||||||
// title := "截至" + timeCh + "亏损100以上的分销商&产品负利润原因"
|
// ReportName: "分销商负利润统计",
|
||||||
// err = b.resellerDetailFillExcelAna(b.excelTempDir+"/"+"kshj_total_ana.xlsx", filePath, totalDetail, title)
|
// Title: "截至" + timeCh + "利润累计亏损" + fmt.Sprintf("%.2f", totalSum),
|
||||||
// if err != nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// report[2] = &ReportRes{
|
|
||||||
// ReportName: "负利润分析(亏损100以上)",
|
|
||||||
// Title: "截至" + timeCh + "亏损100以上利润原因",
|
|
||||||
// Path: filePath,
|
// Path: filePath,
|
||||||
// Data: total,
|
// Data: total,
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
//if len(gt) > 0 {
|
||||||
|
// filePath := b.cacheDir + "/kshj_gt" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx"
|
||||||
|
// title := "截至" + timeCh + "亏损500以上的分销商和产品"
|
||||||
|
// err = b.resellerDetailFillExcelV2(b.excelTempDir+"/"+"kshj_gt.xlsx", filePath, gt, title)
|
||||||
|
// if err != nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// report[1] = &ReportRes{
|
||||||
|
// ReportName: "负利润分析(亏损500以上)",
|
||||||
|
// Title: "截至" + timeCh + "亏损500以上利润累计亏损" + fmt.Sprintf("%.2f", totalSum500),
|
||||||
|
// Path: filePath,
|
||||||
|
// Data: total,
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
if len(totalDetail) > 0 {
|
||||||
|
err = initFunc(ctx, now, totalDetail, b)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
filePath := b.cacheDir + "/kshj_total_ana" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx"
|
||||||
|
title := "截至" + timeCh + "亏损100以上的分销商&产品负利润原因"
|
||||||
|
err = b.resellerDetailFillExcelAna(b.excelTempDir+"/"+"kshj_total_ana.xlsx", filePath, totalDetail, title)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
report[2] = &ReportRes{
|
||||||
|
ReportName: "负利润分析(亏损100以上)",
|
||||||
|
Title: "截至" + timeCh + "亏损100以上利润原因",
|
||||||
|
Path: filePath,
|
||||||
|
Data: total,
|
||||||
|
}
|
||||||
|
}
|
||||||
return report, nil
|
return report, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -283,6 +283,9 @@ func (b *BbxtTools) GetResellerLossMannagerAndLossReasonFromApi(ctx context.Cont
|
||||||
relationMap[v.ResellerInfo.ResellerId].AfterSaleName = v.ResellerInfo.AfterSaleName
|
relationMap[v.ResellerInfo.ResellerId].AfterSaleName = v.ResellerInfo.AfterSaleName
|
||||||
|
|
||||||
for _, vv := range v.ProductList {
|
for _, vv := range v.ProductList {
|
||||||
|
if _, ex := relationMap[v.ResellerInfo.ResellerId].Products[vv.ProductId]; !ex {
|
||||||
|
continue
|
||||||
|
}
|
||||||
relationMap[v.ResellerInfo.ResellerId].Products[vv.ProductId].LossReason = vv.LossReason
|
relationMap[v.ResellerInfo.ResellerId].Products[vv.ProductId].LossReason = vv.LossReason
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue