From 1a2e7a46273fdb6eb53348f4e06100aa7854c3cf Mon Sep 17 00:00:00 2001
From: zhangqian <zhangqian@123.com>
Date: 星期二, 12 三月 2024 19:35:27 +0800
Subject: [PATCH] 新增或保存纤度登记表后进行纤度检查并保存结果到纤度检查表

---
 constvar/const.go             |    8 +
 models/fineness_check_item.go |   22 +-
 extend/code/code.go           |   25 +-
 service/fineness.go           |  193 +++++++++++++++++++++++++++
 service/silk_rank.go          |  112 ++++++++++++++++
 controllers/fineness.go       |    8 +
 models/fineness_check.go      |    6 
 utils/mathx.go                |   30 ++++
 models/fineness_item.go       |    4 
 9 files changed, 378 insertions(+), 30 deletions(-)

diff --git a/constvar/const.go b/constvar/const.go
index c255f71..1aa8b1b 100644
--- a/constvar/const.go
+++ b/constvar/const.go
@@ -34,3 +34,11 @@
 	CheckItemPurity                            //娲佸噣鍒�
 	CheckItemMaxDeviation                      //鏈�澶у亸宸�
 )
+
+type BadFinenessGrade string
+
+const (
+	BadFinenessGradeA = "badA"
+	BadFinenessGradeB = "badB"
+	BadFinenessGradeC = "badC"
+)
diff --git a/controllers/fineness.go b/controllers/fineness.go
index 6760b3b..43981d1 100644
--- a/controllers/fineness.go
+++ b/controllers/fineness.go
@@ -8,7 +8,9 @@
 	"silkserver/extend/util"
 	"silkserver/models"
 	"silkserver/pkg/convertx"
+	"silkserver/pkg/logx"
 	"silkserver/pkg/structx"
+	"silkserver/service"
 )
 
 type FinenessController struct{}
@@ -52,6 +54,12 @@
 		util.ResponseFormat(c, code.RequestParamError, "淇濆瓨澶辫触")
 	}
 
+	err = service.FinenessCheck(&params)
+	if err != nil {
+		logx.Errorf("service.FinenessCheck err:%v, finenessRegister:%+v", err, params)
+		util.ResponseFormat(c, code.RequestParamError, "鐢熸垚妫�楠岃〃澶辫触")
+	}
+
 	util.ResponseFormat(c, code.Success, "淇濆瓨鎴愬姛")
 }
 
diff --git a/extend/code/code.go b/extend/code/code.go
index 23016bf..6838258 100644
--- a/extend/code/code.go
+++ b/extend/code/code.go
@@ -8,22 +8,21 @@
 	Message string `json:"msg"`    // 鎻忚堪淇℃伅
 }
 
+// 瀹炵幇 error 鎺ュ彛鐨� Error 鏂规硶
+func (c *Code) Error() string {
+	return c.Message
+}
+
 var (
 	Success       = &Code{http.StatusOK, "璇锋眰澶勭悊鎴愬姛"}
 	UpdateSuccess = &Code{http.StatusOK, "鏇存柊鎴愬姛"}
 	DeleteSuccess = &Code{http.StatusOK, "鍒犻櫎鎴愬姛"}
 
-	SaveFail                     = &Code{3001, "鏂板澶辫触"}
-	RequestParamError            = &Code{3002, "璇锋眰鍙傛暟鏈夎"}
-	DeleteUsingError             = &Code{3003, "鍒犻櫎澶辫触"}
-	NameExistedError             = &Code{3004, "鍚嶇О宸插瓨鍦�"}
-	OrderSchedulingError         = &Code{3005, "璁㈠崟姝e湪鎺掔▼涓�"}
-	InventoryNotEnoughError      = &Code{3006, "鐗╂枡搴撳瓨涓嶈冻"}
-	UseAmountNotEnoughError      = &Code{3007, "浣跨敤鏁伴噺涓嶈冻"}
-	OrderProductNoProcedureError = &Code{3008, "璁㈠崟浜у搧鏃犲伐搴�"}
-	SetStatusError               = &Code{3009, "璁剧疆鐘舵�佸け璐�"}
-	NoTemplateError              = &Code{3010, "鏈厤缃鍗曟ā鏉�"}
-	InternalError                = &Code{3011, "鍐呴儴閿欒"}
-	NoProductionRequiredError    = &Code{3012, "褰撳墠搴撳瓨婊¤冻姣涢渶姹傞噺锛屾殏鏃舵棤闇�杩涜鐢熶骇"}
-	SelectError                  = &Code{3013, "鏌ヨ澶辫触"}
+	SaveFail          = &Code{3001, "鏂板澶辫触"}
+	RequestParamError = &Code{3002, "璇锋眰鍙傛暟鏈夎"}
+	DeleteUsingError  = &Code{3003, "鍒犻櫎澶辫触"}
+	NameExistedError  = &Code{3004, "鍚嶇О宸插瓨鍦�"}
+	SelectError       = &Code{3013, "鏌ヨ澶辫触"}
+
+	SilkRankStandardNotSetError = &Code{4101, "鐢熶笣鏍囨敞鏈瀹�"}
 )
diff --git a/models/fineness_check.go b/models/fineness_check.go
index 3bdecfe..ebe9d70 100644
--- a/models/fineness_check.go
+++ b/models/fineness_check.go
@@ -18,9 +18,9 @@
 		Deviation                decimal.Decimal  `gorm:"type:decimal(12,2);not null;comment:鍋忓樊" json:"deviation"`                    //鍋忓樊
 		TotalDeviation           decimal.Decimal  `gorm:"type:decimal(12,2);not null;comment:鎬诲樊" json:"totalDeviation"`               //鎬诲樊
 		FinenessGrade            string           `gorm:"type:varchar(255);not null;comment:绾ゅ害绛夌骇" json:"finenessGrade"`               //绾ゅ害绛夌骇
-		Cleanliness              string           `gorm:"type:varchar(255);not null;comment:娓呮磥搴�" json:"cleanliness"`                  //娓呮磥搴�
-		Purity                   string           `gorm:"type:varchar(255);not null;comment:娲佸噣搴�" json:"purity"`                       //娲佸噣搴�
-		TwiceChange              string           `gorm:"type:varchar(255);not null;comment:浜屽害鍙樺寲" json:"twiceChange"`                 //浜屽害鍙樺寲
+		Cleanliness              decimal.Decimal  `gorm:"type:varchar(255);not null;comment:娓呮磥搴�" json:"cleanliness"`                  //娓呮磥搴�
+		Purity                   decimal.Decimal  `gorm:"type:varchar(255);not null;comment:娲佸噣搴�" json:"purity"`                       //娲佸噣搴�
+		TwiceChange              decimal.Decimal  `gorm:"type:varchar(255);not null;comment:浜屽害鍙樺寲" json:"twiceChange"`                 //浜屽害鍙樺寲
 		MarketProcessOrderNumber string           `gorm:"type:varchar(255);not null;comment:搴勫彛宸ヨ壓鍗曠紪鍙�" json:"marketProcessOrderNumber"` //搴勫彛宸ヨ壓鍗曠紪鍙�
 		Inspector                string           `gorm:"type:varchar(255);not null;comment:妫�楠屽憳" json:"inspector"`                    //妫�楠屽憳
 	}
diff --git a/models/fineness_check_item.go b/models/fineness_check_item.go
index 0efd875..9a22f55 100644
--- a/models/fineness_check_item.go
+++ b/models/fineness_check_item.go
@@ -13,22 +13,20 @@
 		gorm.Model
 		FinenessRegisterID   uint `gorm:"not null;comment:绾ゅ害鐧昏琛↖D" json:"finenessRegisterID"` //绾ゅ害鐧昏琛↖D
 		FinenessCheckID      uint `gorm:"not null;comment:绾ゅ害妫�楠岃〃ID" json:"finenessCheckID"`    //绾ゅ害妫�楠岃〃ID
-		Position             int8 `json:"position"`                                           //杞﹀彿
-		FinenessRoundingItem FinenessRoundingItem
-		AverageFineness      decimal.Decimal `gorm:"type:decimal(12,2);not null;comment:骞冲潎绾ゅ害" json:"averageFineness"` //骞冲潎绾ゅ害
-		MeasureFineness      decimal.Decimal `gorm:"type:decimal(12,2);not null;comment:鍏噺绾ゅ害" json:"measureFineness"` //鍏噺绾ゅ害
-		Deviation            decimal.Decimal `gorm:"type:decimal(12,2);not null;comment:鍋忓樊" json:"deviation"`         //鍋忓樊
-		TotalDeviation       decimal.Decimal `gorm:"type:decimal(12,2);not null;comment:鎬诲樊" json:"totalDeviation"`    //鎬诲樊
-		FinenessGrade        string          `gorm:"type:varchar(255);not null;comment:绾ゅ害绛夌骇" json:"finenessGrade"`    //绾ゅ害绛夌骇
-		Cleanliness          string          `gorm:"type:varchar(255);not null;comment:娓呮磥搴�" json:"cleanliness"`       //娓呮磥搴�
-		Purity               string          `gorm:"type:varchar(255);not null;comment:娲佸噣搴�" json:"purity"`            //娲佸噣搴�
-		TwiceChange          string          `gorm:"type:varchar(255);not null;comment:浜屽害鍙樺寲" json:"twiceChange"`      //浜屽害鍙樺寲
-		Remark               string          `gorm:"type:varchar(255);not null;comment:澶囨敞" json:"remark"`             //澶囨敞
+		Position             int  `json:"position"`                                           //杞﹀彿
+		FinenessRoundingItem []*FinenessRoundingItem
+		Deviation            decimal.Decimal `gorm:"type:decimal(12,2);not null;comment:鍋忓樊" json:"deviation"`      //鍋忓樊
+		TotalDeviation       decimal.Decimal `gorm:"type:decimal(12,2);not null;comment:鎬诲樊" json:"totalDeviation"` //鎬诲樊
+		FinenessGrade        string          `gorm:"type:varchar(255);not null;comment:绾ゅ害绛夌骇" json:"finenessGrade"` //绾ゅ害绛夌骇
+		Cleanliness          decimal.Decimal `gorm:"type:varchar(255);not null;comment:娓呮磥搴�" json:"cleanliness"`    //娓呮磥搴�
+		Purity               decimal.Decimal `gorm:"type:varchar(255);not null;comment:娲佸噣搴�" json:"purity"`         //娲佸噣搴�
+		TwiceChange          decimal.Decimal `gorm:"type:varchar(255);not null;comment:浜屽害鍙樺寲" json:"twiceChange"`   //浜屽害鍙樺寲
+		Remark               string          `gorm:"type:varchar(255);not null;comment:澶囨敞" json:"remark"`          //澶囨敞
 	}
 
 	FinenessRoundingItem struct {
 		Fineness decimal.Decimal `json:"fineness"` //绾ゅ害
-		Quantity decimal.Decimal `json:"quantity"` //鏁伴噺
+		Quantity int             `json:"quantity"` //鏁伴噺
 	}
 	FinenessCheckItemSearch struct {
 		FinenessCheckItem
diff --git a/models/fineness_item.go b/models/fineness_item.go
index e6cc5db..5b74633 100644
--- a/models/fineness_item.go
+++ b/models/fineness_item.go
@@ -12,8 +12,8 @@
 	FinenessItem struct {
 		gorm.Model
 		FinenessRegisterID uint            `json:"finenessRegisterID"`
-		Position           int8            `json:"position"` //杞﹀彿
-		Fineness           decimal.Decimal `json:"fineness"` //绾ゅ害
+		Position           int             `json:"position"` //杞﹀彿
+		Fineness           float32         `json:"fineness"` //绾ゅ害
 		Quantity           decimal.Decimal `json:"quantity"` //鏁伴噺
 		Sum                decimal.Decimal `json:"sum"`      //绾ゅ害鍚堣
 	}
diff --git a/service/fineness.go b/service/fineness.go
new file mode 100644
index 0000000..fc3635b
--- /dev/null
+++ b/service/fineness.go
@@ -0,0 +1,193 @@
+package service
+
+import (
+	"github.com/shopspring/decimal"
+	"gorm.io/gorm"
+	"math"
+	"silkserver/constvar"
+	"silkserver/models"
+	"silkserver/utils"
+	"sort"
+)
+
+func FinenessCheck(finenessRegister *models.FinenessRegister) (err error) {
+	standardMap, err := GetSilkRankStandard()
+	if err != nil {
+		return err
+	}
+	//鏁寸悊鎴愭楠岃〃鐨勬暟鎹粨鏋�
+	finenessRoundingItemMap := make(map[int]map[float32]*models.FinenessRoundingItem)
+	for _, item := range finenessRegister.FinenessList {
+		if finenessRoundingItemMap[item.Position] == nil {
+			finenessRoundingItemMap[item.Position] = make(map[float32]*models.FinenessRoundingItem, 0)
+		}
+		roundedHalfFineness := ToRoundedHalfFineness(item.Fineness)
+		if finenessRoundingItemMap[item.Position][roundedHalfFineness] == nil {
+			finenessRoundingItemMap[item.Position][roundedHalfFineness] = &models.FinenessRoundingItem{
+				Fineness: decimal.NewFromFloat32(roundedHalfFineness),
+				Quantity: 1,
+			}
+		} else {
+			finenessRoundingItemMap[item.Position][roundedHalfFineness].Quantity++
+		}
+	}
+	finenessCheckItems := make([]*models.FinenessCheckItem, 0)
+	var allFinenessList []decimal.Decimal
+	var personEndFlag bool //璧板埌浜嗘煇涓汉鏈�鍚庣殑杞﹀彿
+	var finenessList []decimal.Decimal
+	var step = 3 //涓存椂鎸変竴涓汉涓変釜杞﹀彿绠椼��
+	for pos, roundingItemMap := range finenessRoundingItemMap {
+		roundingItems := make([]*models.FinenessRoundingItem, 0, len(roundingItemMap))
+		for _, v := range roundingItemMap {
+			roundingItems = append(roundingItems, v)
+			finenessList = append(finenessList, v.Fineness)
+			allFinenessList = append(allFinenessList, v.Fineness)
+		}
+
+		item := &models.FinenessCheckItem{
+			FinenessRegisterID:   finenessRegister.ID,
+			Position:             pos,
+			FinenessRoundingItem: roundingItems,
+			Remark:               "",
+		}
+		if pos%step == 0 {
+			personEndFlag = true
+		} else {
+			personEndFlag = false
+		}
+		if personEndFlag {
+			item.Deviation = utils.Deviation(finenessList)
+			item.FinenessGrade = CalcFinenessGrade(item.Deviation, item.TotalDeviation, item.Cleanliness, item.Purity, item.TwiceChange, standardMap)
+			finenessList = finenessList[:0]
+		}
+
+		finenessCheckItems = append(finenessCheckItems, item)
+	}
+	finenessCheck := models.FinenessCheck{
+		FinenessRegisterID:       finenessRegister.ID,
+		AverageFineness:          utils.Average(allFinenessList),
+		Deviation:                utils.Deviation(allFinenessList),
+		TotalDeviation:           decimal.Decimal{},
+		Cleanliness:              decimal.Decimal{},
+		Purity:                   decimal.Decimal{},
+		TwiceChange:              decimal.Decimal{},
+		MarketProcessOrderNumber: "",
+		Inspector:                "",
+	}
+	finenessCheck.FinenessGrade = CalcFinenessGrade(finenessCheck.Deviation, finenessCheck.TotalDeviation, finenessCheck.Cleanliness, finenessCheck.Purity, finenessCheck.TwiceChange, standardMap)
+
+	err = models.WithTransaction(func(db *gorm.DB) error {
+		err := models.NewFinenessCheckSearch().SetOrm(db).Create(&finenessCheck)
+		if err != nil {
+			return err
+		}
+		return models.NewFinenessCheckItemSearch().SetOrm(db).CreateBatch(finenessCheckItems)
+	})
+	return err
+}
+
+type gradeRank struct {
+	gradeName string
+	gradeRank int
+}
+
+func CalcFinenessGrade(deviation, totalDeviation, cleanliness, purity, twiceChange decimal.Decimal, standardMap map[string]*Standard) (gradeName string) {
+	checkItemGradeMap := make(map[constvar.CheckItem]string, 5)
+	gradeRanks := make([]gradeRank, 0)
+	for _, st := range standardMap {
+		if st.StartFineness.GreaterThan(deviation) || st.EndFineness.LessThan(deviation) {
+			continue
+		}
+		grade := ""
+		for _, pair := range st.ValueList {
+			switch st.CheckItem {
+			case constvar.CheckItemDeviation:
+				if st.SortType == SortTypeAsc {
+					if deviation.LessThanOrEqual(pair.RankValue) {
+						grade = pair.RankName
+					}
+				} else {
+					if deviation.GreaterThanOrEqual(pair.RankValue) {
+						grade = pair.RankName
+					}
+				}
+			case constvar.CheckItemMaxDeviation:
+				if st.SortType == SortTypeAsc {
+					if totalDeviation.LessThanOrEqual(pair.RankValue) {
+						grade = pair.RankName
+					}
+				} else {
+					if totalDeviation.GreaterThanOrEqual(pair.RankValue) {
+						grade = pair.RankName
+					}
+				}
+			case constvar.CheckItemTwiceChange:
+				if st.SortType == SortTypeAsc {
+					if twiceChange.LessThanOrEqual(pair.RankValue) {
+						grade = pair.RankName
+					}
+				} else {
+					if twiceChange.GreaterThanOrEqual(pair.RankValue) {
+						grade = pair.RankName
+					}
+				}
+			case constvar.CheckItemCleanliness:
+				if st.SortType == SortTypeAsc {
+					if cleanliness.LessThanOrEqual(pair.RankValue) {
+						grade = pair.RankName
+					}
+				} else {
+					if cleanliness.GreaterThanOrEqual(pair.RankValue) {
+						grade = pair.RankName
+					}
+				}
+			case constvar.CheckItemPurity:
+				if st.SortType == SortTypeAsc {
+					if purity.LessThanOrEqual(pair.RankValue) {
+						grade = pair.RankName
+					}
+				} else {
+					if purity.GreaterThanOrEqual(pair.RankValue) {
+						grade = pair.RankName
+					}
+				}
+			}
+			if grade != "" {
+				break
+			}
+		}
+		if grade != "" {
+			checkItemGradeMap[st.CheckItem] = grade
+			gradeRanks = append(gradeRanks, gradeRank{
+				gradeName: grade,
+				gradeRank: st.GradeRank[grade],
+			})
+		}
+	}
+	if len(gradeRanks) == 0 {
+		return ""
+	}
+	sort.Slice(gradeRanks, func(i, j int) bool {
+		return gradeRanks[i].gradeRank < gradeRanks[j].gradeRank
+	})
+	return gradeRanks[0].gradeName
+}
+
+func ToRoundedHalfFineness(fineness float32) float32 {
+	intPart := int(fineness)
+	diff := fineness - float32(intPart)
+
+	var result float32
+
+	if diff < 0.25 {
+		result = float32(intPart)
+	} else if diff < 0.75 {
+		result = float32(intPart) + 0.5
+	} else {
+		result = float32(intPart + 1)
+	}
+
+	// 淇濈暀涓�浣嶅皬鏁帮紝骞跺湪鏁存暟鎯呭喌涓嬪湪灏忔暟鐐瑰悗鍔犱竴涓浂
+	result = float32(math.Round(float64(result)*10) / 10)
+	return result
+}
diff --git a/service/silk_rank.go b/service/silk_rank.go
new file mode 100644
index 0000000..a694467
--- /dev/null
+++ b/service/silk_rank.go
@@ -0,0 +1,112 @@
+package service
+
+import (
+	"github.com/shopspring/decimal"
+	"silkserver/constvar"
+	"silkserver/extend/code"
+	"silkserver/models"
+	"sort"
+)
+
+type Standard struct {
+	CheckItem     constvar.CheckItem
+	StartFineness decimal.Decimal
+	EndFineness   decimal.Decimal
+	GradeMap      map[string]struct{}
+	ValueList     []*Pair
+	SortType      SortType
+	GradeRank     map[string]int
+}
+
+type Pair struct {
+	RankName  string
+	RankValue decimal.Decimal
+}
+
+type SortType int
+
+const (
+	SortTypeAsc  SortType = 0
+	SortTypeDesc SortType = 1
+)
+
+var sortTypeMap = map[constvar.CheckItem]SortType{
+	constvar.CheckItemDeviation:    SortTypeAsc,
+	constvar.CheckItemTwiceChange:  SortTypeAsc,
+	constvar.CheckItemCleanliness:  SortTypeDesc,
+	constvar.CheckItemPurity:       SortTypeDesc,
+	constvar.CheckItemMaxDeviation: SortTypeAsc,
+}
+
+func GetSilkRankStandard() (map[string]*Standard, error) {
+	rankStandards, err := models.NewRawSilkRankStandardSearch().FindNotTotal()
+	if err != nil {
+		return nil, err
+	}
+	if len(rankStandards) == 0 {
+		return nil, code.SilkRankStandardNotSetError
+	}
+	standardMap := make(map[string]*Standard)
+	for _, v := range rankStandards {
+		if standardMap[v.LineId] == nil {
+			standardMap[v.LineId] = &Standard{
+				CheckItem:     v.CheckItem,
+				StartFineness: v.StartFineness,
+				EndFineness:   v.EndFineness,
+				GradeMap:      make(map[string]struct{}),
+				ValueList:     make([]*Pair, 0),
+			}
+		}
+		if _, ok := standardMap[v.LineId].GradeMap[constvar.BadFinenessGradeA]; !ok {
+			standardMap[v.LineId].ValueList = append(standardMap[v.LineId].ValueList, &Pair{
+				RankName:  constvar.BadFinenessGradeA,
+				RankValue: v.RankA,
+			})
+			standardMap[v.LineId].GradeMap[constvar.BadFinenessGradeA] = struct{}{}
+		}
+		if _, ok := standardMap[v.LineId].GradeMap[constvar.BadFinenessGradeB]; !ok {
+			standardMap[v.LineId].ValueList = append(standardMap[v.LineId].ValueList, &Pair{
+				RankName:  constvar.BadFinenessGradeB,
+				RankValue: v.RankB,
+			})
+			standardMap[v.LineId].GradeMap[constvar.BadFinenessGradeB] = struct{}{}
+		}
+		if _, ok := standardMap[v.LineId].GradeMap[constvar.BadFinenessGradeC]; !ok {
+			standardMap[v.LineId].ValueList = append(standardMap[v.LineId].ValueList, &Pair{
+				RankName:  constvar.BadFinenessGradeC,
+				RankValue: v.RankC,
+			})
+			standardMap[v.LineId].GradeMap[constvar.BadFinenessGradeC] = struct{}{}
+		}
+		if _, ok := standardMap[v.LineId].GradeMap[v.RankName]; !ok {
+			standardMap[v.LineId].ValueList = append(standardMap[v.LineId].ValueList, &Pair{
+				RankName:  v.RankName,
+				RankValue: v.RankValue,
+			})
+			standardMap[v.LineId].GradeMap[v.RankName] = struct{}{}
+		}
+	}
+	//value鎺掑簭
+	for k := range standardMap {
+		sort.Slice(standardMap[k].ValueList, func(i, j int) bool {
+			sortType := sortTypeMap[standardMap[k].CheckItem]
+			standardMap[k].SortType = sortType
+			if sortType == SortTypeAsc {
+				return standardMap[k].ValueList[i].RankValue.LessThan(standardMap[k].ValueList[j].RankValue)
+			} else {
+				return standardMap[k].ValueList[i].RankValue.GreaterThan(standardMap[k].ValueList[j].RankValue)
+			}
+		})
+	}
+	//绛夌骇鎺掑悕
+	for lineId, standard := range standardMap {
+		for k, pair := range standard.ValueList {
+			if standard.SortType == SortTypeAsc {
+				standardMap[lineId].GradeRank[pair.RankName] = k + 1
+			} else {
+				standardMap[lineId].GradeRank[pair.RankName] = len(standard.ValueList) - k
+			}
+		}
+	}
+	return standardMap, nil
+}
diff --git a/utils/mathx.go b/utils/mathx.go
new file mode 100644
index 0000000..3bbf646
--- /dev/null
+++ b/utils/mathx.go
@@ -0,0 +1,30 @@
+package utils
+
+import "github.com/shopspring/decimal"
+
+func Average(numbers []decimal.Decimal) decimal.Decimal {
+	if len(numbers) == 0 {
+		return decimal.Decimal{}
+	}
+	if len(numbers) == 1 {
+		return numbers[0]
+	}
+	var sum decimal.Decimal
+	for _, d := range numbers {
+		sum = sum.Add(d)
+	}
+	return sum.Div(decimal.NewFromInt(int64(len(numbers))))
+}
+
+func Deviation(numbers []decimal.Decimal) decimal.Decimal {
+	if len(numbers) == 0 || len(numbers) == 1 {
+		return decimal.Decimal{}
+	}
+	avgNum := Average(numbers)
+	var diffSquaredSum decimal.Decimal
+	for _, n := range numbers {
+		diff := n.Sub(avgNum)
+		diffSquaredSum = diffSquaredSum.Add(diff.Mul(diff))
+	}
+	return diffSquaredSum.Div(decimal.NewFromInt(int64(len(numbers))))
+}

--
Gitblit v1.8.0