Browse Source

fix:修复预测规则年度倒推的bug

Roc 1 year ago
parent
commit
6a95d1bf4f
1 changed files with 99 additions and 22 deletions
  1. 99 22
      services/data/predict_edb_info_rule.go

+ 99 - 22
services/data/predict_edb_info_rule.go

@@ -154,7 +154,7 @@ func TbzDivMul(a, b float64) (result float64) {
 
 	// 计算
 	result, _ = val.Mul(af).RoundCeil(4).Float64()
-	
+
 	return
 }
 
@@ -1609,8 +1609,12 @@ func GetChartPredictEdbInfoDataListByRuleAnnualValueInversion(edbInfoId int, con
 	// 配置的年度值
 	yearValueConfig := annualValueInversionConf.Value
 
+	// 最新数据的日期
+	currDayTime, err := time.ParseInLocation(utils.FormatDate, allDataList[index-1].DataTime, time.Local)
+	if err != nil {
+		return
+	}
 	// 当前年的日期
-	currDayTime := dayList[0]
 	lastDayTime := dayList[len(dayList)-1]
 	if currDayTime.Year() != lastDayTime.Year() {
 		err = errors.New("年度值倒推不支持跨年预测")
@@ -1619,21 +1623,75 @@ func GetChartPredictEdbInfoDataListByRuleAnnualValueInversion(edbInfoId int, con
 
 	// 均值法
 	if annualValueInversionConf.Type == 1 {
+
 		// 当前年的期数
 		currYearN := 0
+		// 当前已经消耗的额度
 		var currYearVal float64
-		for _, v := range allDataList {
-			currTime, tmpErr := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
-			if tmpErr != nil {
-				err = tmpErr
-				return
-			}
-			// 只是计算今年的
-			if currTime.Year() != currDayTime.Year() {
-				continue
+
+		// 计算当前年的期数以及已经消耗的额度
+		{
+			if frequency != "周度" {
+				for _, v := range allDataList {
+					currTime, tmpErr := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
+					if tmpErr != nil {
+						err = tmpErr
+						return
+					}
+					// 只是计算今年的
+					if currTime.Year() != currDayTime.Year() {
+						continue
+					}
+					currYearN++
+					currYearVal = currYearVal + v.Value
+				}
+			} else {
+				tmpDataList := make([]*data_manage.EdbDataList, 0)
+				// 上一期的数据
+				var lastData *data_manage.EdbDataList
+				// 是否第一条数据
+				isFirst := true
+				for _, v := range allDataList {
+					currTime, tmpErr := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
+					if tmpErr != nil {
+						err = tmpErr
+						return
+					}
+					// 只是计算今年的
+					if currTime.Year() != currDayTime.Year() {
+						lastData = v
+						continue
+					}
+
+					if isFirst {
+						tmpDataList = append(tmpDataList, lastData)
+					}
+					isFirst = false
+					tmpDataList = append(tmpDataList, v)
+					currYearN++
+				}
+
+				// 需要插值法处理
+				tmpHandleDataMap := make(map[string]float64)
+				err = handleDataByLinearRegression(tmpDataList, tmpHandleDataMap)
+				if err != nil {
+					return
+				}
+
+				for tmpDate, val := range tmpHandleDataMap {
+					tmpDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
+					if tmpErr != nil {
+						err = tmpErr
+						return
+					}
+					if tmpDateTime.Year() != currDayTime.Year() {
+						continue
+					}
+					currYearVal = currYearVal + val
+				}
+
+				currYearVal = currYearVal / 7
 			}
-			currYearN++
-			currYearVal = currYearVal + v.Value
 		}
 
 		var averageVal float64
@@ -1657,8 +1715,11 @@ func GetChartPredictEdbInfoDataListByRuleAnnualValueInversion(edbInfoId int, con
 			yearLastDay := time.Date(currDayTime.Year(), 12, 31, 0, 0, 0, 0, time.Local)
 			subDay2 := utils.GetTimeSubDay(yearFirstDay, yearLastDay) + 1
 
+			// 剩余期数
 			surplusN := decimal.NewFromInt(int64(subDay2 - subDay)).Div(decimal.NewFromInt(int64(subDay))).Mul(decimal.NewFromInt(int64(currYearN)))
-			averageVal, _ = (decimal.NewFromFloat(annualValueInversionConf.Value).Sub(decimal.NewFromFloat(currYearVal))).Div(surplusN).Round(4).Float64()
+			// 剩余余额
+			balance := decimal.NewFromFloat(annualValueInversionConf.Value).Sub(decimal.NewFromFloat(currYearVal))
+			averageVal, _ = balance.Div(surplusN).Round(4).Float64()
 
 		}
 
@@ -1713,32 +1774,48 @@ func GetChartPredictEdbInfoDataListByRuleAnnualValueInversion(edbInfoId int, con
 	//(同比增速=余额/同比年份相应日期的余额,预测值等于同比年份同期值*同比增速);
 	for k, currentDate := range dayList {
 		currYearBalance := yearValueConfig - yearTotalMap[currentDate.Year()] // 当年的余额
+
+		// 上一期的日期
+		prevDateStr := allDataList[len(allDataList)-1].DataTime
+		prevDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, prevDateStr, time.Local)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
 		//同比年份相应日期
 		lastYear := annualValueInversionConf.Year + (currentDate.Year() - currDayTime.Year())
 
-		var lastDateTime time.Time
+		// 前N年的上一期时间;前N年的当期时间;
+		var lastPrevDateTime, lastDateTime time.Time
 
 		switch frequency {
 		case "半年度", "季度":
 			lastDateTime = time.Date(lastYear, currentDate.Month(), currentDate.Day(), 0, 0, 0, 0, currentDate.Location())
+			lastPrevDateTime = time.Date(lastYear, prevDateTime.Month(), prevDateTime.Day(), 0, 0, 0, 0, prevDateTime.Location())
 		case "月度":
 			lastDateTime = time.Date(lastYear, currentDate.Month()+1, 1, 0, 0, 0, 0, currentDate.Location()).AddDate(0, 0, -1)
+			lastPrevDateTime = time.Date(lastYear, prevDateTime.Month()+1, 1, 0, 0, 0, 0, prevDateTime.Location()).AddDate(0, 0, -1)
 		case "旬度":
-			if currentDate.Day() == 10 || currentDate.Day() == 20 {
+			if prevDateTime.Day() == 10 || prevDateTime.Day() == 20 {
 				lastDateTime = time.Date(lastYear, currentDate.Month(), currentDate.Day(), 0, 0, 0, 0, currentDate.Location())
+				lastPrevDateTime = time.Date(lastYear, prevDateTime.Month(), prevDateTime.Day(), 0, 0, 0, 0, prevDateTime.Location())
 			} else {
 				lastDateTime = time.Date(lastYear, currentDate.Month()+1, 1, 0, 0, 0, 0, currentDate.Location()).AddDate(0, 0, -1)
+				lastPrevDateTime = time.Date(lastYear, prevDateTime.Month()+1, 1, 0, 0, 0, 0, prevDateTime.Location()).AddDate(0, 0, -1)
 			}
 		case "周度", "日度":
 			lastDateTime = time.Date(lastYear, currentDate.Month(), currentDate.Day(), 0, 0, 0, 0, currentDate.Location())
+			lastPrevDateTime = time.Date(lastYear, prevDateTime.Month(), prevDateTime.Day(), 0, 0, 0, 0, prevDateTime.Location())
 		}
 
 		// 同比年份相应日期的累计值
 		var dateTotal float64
-		dateTotal, ok := dateTotalMap[lastDateTime]
+
+		dateTotal, ok := dateTotalMap[lastPrevDateTime]
 		if !ok { //如果没有找到这个日期,那么就往前面找,一直到找到这个累计值,或者找完这一年
-			yearFirstDayTime := time.Date(lastDateTime.Year(), 1, 1, 0, 0, 0, 0, lastDateTime.Location())
-			for tmpDateTime := lastDateTime.AddDate(0, 0, -1); tmpDateTime.After(yearFirstDayTime) || tmpDateTime.Equal(yearFirstDayTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) {
+			yearFirstDayTime := time.Date(lastPrevDateTime.Year(), 1, 1, 0, 0, 0, 0, lastDateTime.Location())
+			for tmpDateTime := lastPrevDateTime.AddDate(0, 0, -1); tmpDateTime.After(yearFirstDayTime) || tmpDateTime.Equal(yearFirstDayTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) {
 				dateTotal, ok = dateTotalMap[tmpDateTime]
 				if ok {
 					break
@@ -1746,10 +1823,10 @@ func GetChartPredictEdbInfoDataListByRuleAnnualValueInversion(edbInfoId int, con
 			}
 		}
 
-		//同比年份相应日期的余额
-		lastYearDateBalance := yearValueConfig - dateTotal
+		//同比年份相应的上一期日期的余额
+		lastYearDateBalance := yearTotalMap[lastPrevDateTime.Year()] - dateTotal
 
-		// 同比增速=余额/同比年份相应日期的余额
+		// 同比增速=当年余额/同比年份上一期日期的余额
 		tbVal := decimal.NewFromFloat(currYearBalance).Div(decimal.NewFromFloat(lastYearDateBalance))
 
 		// 获取同比年份同期值,获取失败的话,就不处理