feat: add percentage loyalti setting mode
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -240,14 +241,20 @@ func loyaltySettingChangeModel(row entities.LoyaltySettingChange) models.Loyalty
|
||||
func outletLoyaltyFields(s *models.OutletLoyaltySettings) []loyaltyField {
|
||||
return []loyaltyField{
|
||||
boolLoyaltyField(constants.LoyaltyPointEnabledKey, &s.Point.Enabled, false),
|
||||
enumLoyaltyField(constants.LoyaltyPointEarnModeKey, &s.Point.EarnMode, constants.LoyaltyEarnModeDefault,
|
||||
constants.LoyaltyEarnModePerAmount, constants.LoyaltyEarnModePercentage),
|
||||
intLoyaltyField(constants.LoyaltyPointEarnPerAmountKey, &s.Point.EarnPerAmount, constants.LoyaltyPointEarnPerAmountDefault, 1, noLoyaltyMax),
|
||||
intLoyaltyField(constants.LoyaltyPointEarnValueKey, &s.Point.EarnValue, constants.LoyaltyEarnValueDefault, 0, noLoyaltyMax),
|
||||
percentLoyaltyField(constants.LoyaltyPointEarnPercentKey, &s.Point.EarnPercent, constants.LoyaltyEarnPercentDefault),
|
||||
intLoyaltyField(constants.LoyaltyPointMinOrderAmountKey, &s.Point.MinOrderAmount, 0, 0, noLoyaltyMax),
|
||||
optionalIntLoyaltyField(constants.LoyaltyPointMaxPerOrderKey, &s.Point.MaxPerOrder, 0),
|
||||
|
||||
boolLoyaltyField(constants.LoyaltyCoinEnabledKey, &s.Coin.Enabled, false),
|
||||
enumLoyaltyField(constants.LoyaltyCoinEarnModeKey, &s.Coin.EarnMode, constants.LoyaltyEarnModeDefault,
|
||||
constants.LoyaltyEarnModePerAmount, constants.LoyaltyEarnModePercentage),
|
||||
intLoyaltyField(constants.LoyaltyCoinEarnPerAmountKey, &s.Coin.EarnPerAmount, constants.LoyaltyCoinEarnPerAmountDefault, 1, noLoyaltyMax),
|
||||
intLoyaltyField(constants.LoyaltyCoinEarnValueKey, &s.Coin.EarnValue, constants.LoyaltyEarnValueDefault, 0, noLoyaltyMax),
|
||||
percentLoyaltyField(constants.LoyaltyCoinEarnPercentKey, &s.Coin.EarnPercent, constants.LoyaltyEarnPercentDefault),
|
||||
intLoyaltyField(constants.LoyaltyCoinMinOrderAmountKey, &s.Coin.MinOrderAmount, 0, 0, noLoyaltyMax),
|
||||
optionalIntLoyaltyField(constants.LoyaltyCoinMaxPerOrderKey, &s.Coin.MaxPerOrder, 0),
|
||||
|
||||
@@ -329,6 +336,35 @@ func intLoyaltyField(key string, v *int64, def, min, max int64) loyaltyField {
|
||||
}
|
||||
}
|
||||
|
||||
// percentLoyaltyField is a percentage from 0 to 100 with at most two decimals, so it
|
||||
// is whole in hundredths and calculations with it stay in integers.
|
||||
func percentLoyaltyField(key string, v *float64, def float64) loyaltyField {
|
||||
check := func(n float64) error {
|
||||
// The negated form also rejects NaN.
|
||||
if !(n >= 0 && n <= 100) {
|
||||
return fmt.Errorf("%w: %s must be between 0 and 100", ErrInvalidLoyaltySettings, key)
|
||||
}
|
||||
if math.Abs(n*100-math.Round(n*100)) > 1e-6 {
|
||||
return fmt.Errorf("%w: %s must have at most two decimals", ErrInvalidLoyaltySettings, key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return loyaltyField{
|
||||
key: key,
|
||||
parse: func(raw string) bool {
|
||||
n, err := strconv.ParseFloat(strings.TrimSpace(raw), 64)
|
||||
if err != nil || check(n) != nil {
|
||||
return false
|
||||
}
|
||||
*v = n
|
||||
return true
|
||||
},
|
||||
reset: func() { *v = def },
|
||||
validate: func() error { return check(*v) },
|
||||
format: func() *string { s := strconv.FormatFloat(*v, 'f', -1, 64); return &s },
|
||||
}
|
||||
}
|
||||
|
||||
// optionalIntLoyaltyField is a limit that may be unset, meaning no limit.
|
||||
func optionalIntLoyaltyField(key string, v **int64, min int64) loyaltyField {
|
||||
return loyaltyField{
|
||||
|
||||
Reference in New Issue
Block a user