90 lines
2.2 KiB
Go
90 lines
2.2 KiB
Go
package business
|
|
|
|
import (
|
|
"math/big"
|
|
"time"
|
|
)
|
|
|
|
func GoalMetric(goal *PerformanceGoal, key string) *int64 {
|
|
if goal == nil {
|
|
return nil
|
|
}
|
|
switch key {
|
|
case "open":
|
|
return goal.Open
|
|
case "effective":
|
|
return goal.Effective
|
|
case "pay":
|
|
return goal.Amount
|
|
}
|
|
return nil
|
|
}
|
|
func GoalPeriodTarget(goal *PerformanceGoal, key, period, grain string) *string {
|
|
if len(period) < 7 {
|
|
return nil
|
|
}
|
|
value := GoalMetric(goal, key)
|
|
if value == nil {
|
|
return nil
|
|
}
|
|
target := big.NewRat(*value, 1)
|
|
if grain == "day" {
|
|
month, err := time.Parse("2006-01", period[:7])
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
target.Quo(target, big.NewRat(int64(month.AddDate(0, 1, -1).Day()), 1))
|
|
}
|
|
return stringPointer(portraitDecimal(target, 2))
|
|
}
|
|
func GoalCompletion(periods map[string]PerformanceMetrics, goals map[string]*PerformanceGoal, key string) *string {
|
|
actual, target := new(big.Rat), new(big.Rat)
|
|
months := map[string]bool{}
|
|
for period, value := range periods {
|
|
if len(period) < 7 {
|
|
continue
|
|
}
|
|
month := period[:7]
|
|
goal := GoalMetric(goals[month], key)
|
|
if goal == nil {
|
|
continue
|
|
}
|
|
if !months[month] {
|
|
target.Add(target, big.NewRat(*goal, 1))
|
|
months[month] = true
|
|
}
|
|
switch key {
|
|
case "open":
|
|
actual.Add(actual, big.NewRat(value.Open, 1))
|
|
case "effective":
|
|
actual.Add(actual, big.NewRat(value.Effective, 1))
|
|
case "pay":
|
|
amount, err := portraitNumber(value.Pay)
|
|
if err == nil {
|
|
actual.Add(actual, amount)
|
|
}
|
|
}
|
|
}
|
|
if target.Sign() <= 0 {
|
|
return nil
|
|
}
|
|
return stringPointer(portraitDecimal(actual.Quo(actual, target).Mul(actual, big.NewRat(100, 1)), 1))
|
|
}
|
|
func PerformanceChange(current, previous PerformanceMetrics, key string) *string {
|
|
var a, b *big.Rat
|
|
switch key {
|
|
case "open":
|
|
a, b = big.NewRat(current.Open, 1), big.NewRat(previous.Open, 1)
|
|
case "effective":
|
|
a, b = big.NewRat(current.Effective, 1), big.NewRat(previous.Effective, 1)
|
|
case "pay":
|
|
a, _ = portraitNumber(current.Pay)
|
|
b, _ = portraitNumber(previous.Pay)
|
|
}
|
|
if a == nil || b == nil || b.Sign() == 0 {
|
|
return nil
|
|
}
|
|
return stringPointer(portraitDecimal(a.Sub(a, b).Quo(a, b).Mul(a, big.NewRat(100, 1)), 1))
|
|
}
|
|
func PerformanceRate(value PerformanceMetrics) *string { return performanceRate(value) }
|