diff --git a/.gitignore b/.gitignore index 426169a..0a1dce3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ # vendor/ .~lock.*.ods# +out.txt diff --git a/MatrixBerechnung.ods b/MatrixBerechnung.ods index f212f51..8d819c0 100644 Binary files a/MatrixBerechnung.ods and b/MatrixBerechnung.ods differ diff --git a/matrix.go b/matrix.go index 2982b0d..5d634e9 100644 --- a/matrix.go +++ b/matrix.go @@ -1,5 +1,10 @@ package goodcalc +import ( + "fmt" + "math" +) + // Matrix contains the stakeholders and the maximal // allowed points of the calculation. The calculation // is pretty simple. Inside each aspect ValuationPoints @@ -16,7 +21,38 @@ type Matrix struct { MaxNegValuationPoints int `json:"max_neg_valuation_points"` // -200 NegPointsFactor int `json:"neg_points_factor"` // 50 Stakeholders []*Stakeholder `json:"stakeholders"` - Calculation MatrixCalc `json:"calculation"` + Calculation *MatrixCalc `json:"calculation"` +} + +func (m *Matrix) String() string { + if m == nil { + return "" + } + var s string + s += fmt.Sprintf("MaxPoints: %d\n", m.MaxPoints) + s += fmt.Sprintf("MaxValuationPoints: %d\n", m.MaxValuationPoints) + s += fmt.Sprintf("MaxNegValuationPoints: %d\n", m.MaxNegValuationPoints) + s += fmt.Sprintf("NegPointsFactor: %d\n", m.NegPointsFactor) + s += fmt.Sprintf("Calculation: %#v\n", m.Calculation) + s += fmt.Sprintf("Stakeholders: {\n%s\n}\n", m.Stakeholders) + return s +} + +func (m *Matrix) BalancePoints() int { + var balancePoints float64 + m.calcWeightFactor() + m.setMaxValuationPoints() + m.forall(func(t *Theme) { + t.Calc.calcMaxPoints() + t.calcNrPosAspects() + t.calcValPoints() + t.calcEstPercentage() + t.calcBalancePoints() + balancePoints += float64(t.Calc.BalancePoints) + balancePoints += float64(t.Calc.NegativeBlancePoints) + }) + balancePoints = math.Round(balancePoints) + return int(balancePoints) } // MatrixCalc contains calculated values @@ -34,7 +70,14 @@ func (m *Matrix) forall(f func(t *Theme)) { } } +// sumCalcWeight sums all the calculated weights of +// the matrix. func (m *Matrix) sumCalcWeight() { + // calculate the stakeholder weight to each + // theme + for _, s := range m.Stakeholders { + s.calcWeight() + } m.Calculation.SumCalcWeight = 0 m.forall(func(t *Theme) { m.Calculation.SumCalcWeight += t.Calc.CalcWeight @@ -63,7 +106,7 @@ func (m *Matrix) setMaxValuationPoints() { maxThemeValPoints := 0 for _, a := range t.Aspects { a.MaxValuationPoints = m.MaxValuationPoints * int(a.Weight) - maxThemeValPoints += m.MaxNegValuationPoints * int(a.Weight) + maxThemeValPoints += m.MaxValuationPoints * int(a.Weight) } t.Calc.MaxValuationPoints = maxThemeValPoints for _, na := range t.NegativeAspects { diff --git a/matrix_test.go b/matrix_test.go new file mode 100644 index 0000000..2a80471 --- /dev/null +++ b/matrix_test.go @@ -0,0 +1,76 @@ +package goodcalc + +import ( + "fmt" + "testing" +) + +func emptyMatrix() *Matrix { + m := Matrix{ + MaxPoints: 1000, + MaxValuationPoints: 10, + MaxNegValuationPoints: -200, + NegPointsFactor: 50, + Stakeholders: []*Stakeholder{}, + Calculation: &MatrixCalc{ + SumCalcWeight: 0, + WeightFactor: 0, + }, + } + + stakeholderDefault := []Stakeholder{ + {"A", 1.5, []*Theme{}}, + {"B", 0.5, []*Theme{}}, + {"C", 0.5, []*Theme{}}, + {"D", 1, []*Theme{}}, + {"E", 1, []*Theme{}}, + } + + themeDefault := []string{"1", "2", "3", "4"} + for _, st := range stakeholderDefault { + s := st + for _, th := range themeDefault { + t := Theme{ + No: st.No + th, + Weight: 1, + Aspects: []Aspect{}, + NegativeAspects: []NegativeAspect{}, + NegPointsFactor: 0, + Calc: &ThemeCalc{}, + } + for i := 1; i <= 2; i++ { + a := Aspect{ + No: fmt.Sprintf("%s.%d", t.No, i), + Weight: 1, + ValuationPoints: 5, + } + t.Aspects = append(t.Aspects, a) + } + s.Themes = append(s.Themes, &t) + } + m.Stakeholders = append(m.Stakeholders, &s) + } + return &m +} + +func TestMatrix_BalancePoints(t *testing.T) { + tests := []struct { + name string + m *Matrix + want int + }{ + { + "", + emptyMatrix(), + 500, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.m.BalancePoints(); got != tt.want { + t.Errorf("Matrix.BalancePoints() = %v, want %v", got, tt.want) + } + //fmt.Printf("%s", tt.m) + }) + } +} diff --git a/stakeholder.go b/stakeholder.go index 3b766b8..c9a068f 100644 --- a/stakeholder.go +++ b/stakeholder.go @@ -1,5 +1,7 @@ package goodcalc +import "fmt" + // Stakeholder can define a weight, which is calculated to // all containing themes. // No is the id like in the excel @@ -10,6 +12,17 @@ type Stakeholder struct { Themes []*Theme `json:"themes"` } +func (s *Stakeholder) String() string { + var str string + str += fmt.Sprintf("\n No: %s\n", s.No) + str += fmt.Sprintf(" Weight: %.1f\n", s.Weight) + str += fmt.Sprintf(" Themes: %v\n", s.Themes) + return str +} + +// calcWeight takes the weight of the stakeholder level +// and calculates that weight for each theme +// iteration 1 inside the example table func (s *Stakeholder) calcWeight() { for _, t := range s.Themes { t.Calc.CalcWeight = s.Weight * t.Weight diff --git a/theme.go b/theme.go index 73ba742..ec065f2 100644 --- a/theme.go +++ b/theme.go @@ -1,5 +1,7 @@ package goodcalc +import "fmt" + // Theme is the basic element of the matrix. // No defines the id of the excel balance. // A1 for Human dignity in the supply chain @@ -12,6 +14,17 @@ type Theme struct { Calc *ThemeCalc `json:"calculation"` } +func (t *Theme) String() string { + var s string + s += fmt.Sprintf(" No: %s\n", t.No) + s += fmt.Sprintf(" Weight: %.1f\n", t.Weight) + s += fmt.Sprintf(" Aspects: %v\n", t.Aspects) + s += fmt.Sprintf(" NegativeAspects: %v\n", t.NegativeAspects) + s += fmt.Sprintf(" NegPointsFactor: %v\n", t.NegPointsFactor) + s += fmt.Sprintf(" Calc: %s\n", t.Calc) + return s +} + func (t *Theme) calcNrPosAspects() { t.Calc.NrPositiveAspects = len(t.Aspects) } @@ -28,10 +41,10 @@ func (t *Theme) calcValPoints() { } func (t *Theme) calcEstPercentage() { - t.Calc.EstPercentage = 0 + t.Calc.EstPercentage = 1 if t.Calc.MaxValuationPoints != 0 { t.Calc.EstPercentage = - float32(t.Calc.ValuationPoints / t.Calc.MaxValuationPoints) + float32(t.Calc.ValuationPoints) / float32(t.Calc.MaxValuationPoints) } } @@ -57,6 +70,24 @@ type ThemeCalc struct { NegativeBlancePoints float32 `json:"negative_blance_points"` } +func (tc *ThemeCalc) String() string { + if tc == nil { + return "" + } + var s string + s += fmt.Sprintf("\t\tCalcWeight: %.1f\n", tc.CalcWeight) + s += fmt.Sprintf("\t\tWeightFactor: %.1f\n", tc.WeightFactor) + s += fmt.Sprintf("\t\tMaxBalancePoints: %.1f\n", tc.MaxBalancePoints) + s += fmt.Sprintf("\t\tNrPositiveAspects: %d\n", tc.NrPositiveAspects) + s += fmt.Sprintf("\t\tValuationPoints: %d\n", tc.ValuationPoints) + s += fmt.Sprintf("\t\tMaxValuationPoints: %d\n", tc.MaxValuationPoints) + s += fmt.Sprintf("\t\tEstPercentage: %.1f\n", tc.EstPercentage) + s += fmt.Sprintf("\t\tBalancePoints: %.1f\n", tc.BalancePoints) + s += fmt.Sprintf("\t\tNegativeValuationPoints: %d\n", tc.NegativeValuationPoints) + s += fmt.Sprintf("\t\tNegativeBlancePoints: %.1f\n", tc.NegativeBlancePoints) + return s +} + // calcMaxPoints // Stakeholder.calcWeight needs to run first func (c *ThemeCalc) calcMaxPoints() {