84 lines
1.5 KiB
Go
84 lines
1.5 KiB
Go
package tariff
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/evcc-io/evcc/provider/golang"
|
|
"github.com/evcc-io/evcc/provider/golang/stdlib"
|
|
"github.com/traefik/yaegi/interp"
|
|
)
|
|
|
|
type embed struct {
|
|
Charges float64 `mapstructure:"charges"`
|
|
Tax float64 `mapstructure:"tax"`
|
|
Formula string `mapstructure:"formula"`
|
|
|
|
calc func(float64, time.Time) (float64, error)
|
|
}
|
|
|
|
func (t *embed) init() (err error) {
|
|
defer func() {
|
|
if r := recover(); r != nil && err == nil {
|
|
err = fmt.Errorf("panic: %v", r)
|
|
}
|
|
}()
|
|
|
|
if t.Formula == "" {
|
|
return nil
|
|
}
|
|
|
|
vm := interp.New(interp.Options{})
|
|
if err := vm.Use(stdlib.Symbols); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := vm.Eval(fmt.Sprintf(`%s
|
|
var (
|
|
price float64
|
|
charges float64 = %f
|
|
tax float64 = %f
|
|
ts time.Time
|
|
)`, golang.Imports, t.Charges, t.Tax)); err != nil {
|
|
return err
|
|
}
|
|
|
|
prg, err := vm.Compile(t.Formula)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
t.calc = func(price float64, ts time.Time) (float64, error) {
|
|
if _, err := vm.Eval(fmt.Sprintf(`
|
|
price = %f
|
|
ts = time.Unix(%d, 0).Local()
|
|
`, price, ts.Unix())); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
res, err := vm.Execute(prg)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
if !res.CanFloat() {
|
|
return 0, errors.New("formula did not return a float value")
|
|
}
|
|
|
|
return res.Float(), nil
|
|
}
|
|
|
|
// test the formula
|
|
_, err = t.calc(0, time.Now())
|
|
|
|
return err
|
|
}
|
|
|
|
func (t *embed) totalPrice(price float64, ts time.Time) float64 {
|
|
if t.calc != nil {
|
|
res, _ := t.calc(price, ts)
|
|
return res
|
|
}
|
|
return (price + t.Charges) * (1 + t.Tax)
|
|
}
|