Skip to content

Commit

Permalink
Accept thousands separators in value (#158)
Browse files Browse the repository at this point in the history
Closes #155
  • Loading branch information
LucaBernstein authored Jul 23, 2022
1 parent b6b228c commit fa2954e
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 28 deletions.
93 changes: 66 additions & 27 deletions bot/transactionBuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ type Input struct {

func HandleFloat(m *tb.Message) (string, error) {
input := strings.TrimSpace(m.Text)
input = strings.ReplaceAll(input, ",", ".")
split := strings.Split(input, " ")
var (
value = split[0]
Expand All @@ -45,42 +44,82 @@ func HandleFloat(m *tb.Message) (string, error) {
if strings.HasSuffix(value, "+") && currency != "" {
return "", fmt.Errorf("for transactions being kept open with trailing '+' operator, no additionally specified currency is allowed")
}
operator := ""
amounts := []string{value}
if strings.Contains(value, "+") {
additionsSplit := strings.Split(value, "+")
sum := 0.0
for _, add := range additionsSplit {
v, err := strconv.ParseFloat(add, 64)
if err != nil {
return "", fmt.Errorf("tried to sum up values due to '%s' operator found, failed at value '%s': %s", "+", add, err.Error())
}
sum += v
}
return ParseAmount(sum) + currency, nil
amounts = strings.Split(value, "+")
operator = "+"
} else if strings.Contains(value, "*") {
multiplicationsSplit := strings.Split(value, "*")
if len(multiplicationsSplit) != 2 {
amounts = strings.Split(value, "*")
operator = "*"
if len(amounts) != 2 {
return "", fmt.Errorf("expected exactly two multiplicators ('a*b')")
}
}
values := []float64{}
for _, amount := range amounts {
value, err := handleThousandsSeparators(amount)
if err != nil {
return "", err
}
v, err := strconv.ParseFloat(value, 64)
if err != nil {
return "", fmt.Errorf("parsing failed at value '%s': %s", value, err.Error())
}
if v < 0 {
c.LogLocalf(INFO, nil, "Got negative value. Inverting.")
v *= -1
}
c.LogLocalf(TRACE, nil, "Handled float: '%s' -> %f", amount, v)
values = append(values, v)
}
finalAmount := 0.0
if operator == "+" {
sum := 0.0
for _, v := range values {
sum += v
}
finalAmount = sum
} else if operator == "*" {
product := 1.0
for _, multiplicator := range multiplicationsSplit {
v, err := strconv.ParseFloat(multiplicator, 64)
if err != nil {
return "", fmt.Errorf("tried to sum up values due to '%s' operator found, failed at value '%s': %s", "*", multiplicator, err.Error())
}
for _, v := range values {
product *= v
}
return ParseAmount(product) + currency, nil
finalAmount = product
} else {
finalAmount = values[0]
}
v, err := strconv.ParseFloat(value, 64)
if err != nil {
return "", err
return ParseAmount(finalAmount) + currency, nil
}

func handleThousandsSeparators(value string) (cleanValue string, err error) {
err = fmt.Errorf("invalid separators in value '%s'", value)
if !(strings.Contains(value, ".") && strings.Contains(value, ",")) {
return strings.ReplaceAll(value, ",", "."), nil
}

thousandsSeparator := '.'
decimalSeparator := ','
if strings.IndexRune(value, ',') < strings.IndexRune(value, '.') {
thousandsSeparator = ','
decimalSeparator = '.'
}
if v < 0 {
c.LogLocalf(INFO, nil, "Got negative value. Inverting.")
v *= -1
if strings.Count(value, string(decimalSeparator)) > 1 {
return
}
if strings.Contains(strings.SplitN(value, string(decimalSeparator), 2)[1], string(thousandsSeparator)) {
return
}
const DIGITS_PER_BLOCK = 3
for idx, block := range strings.Split(strings.Split(value, string(decimalSeparator))[0], string(thousandsSeparator)) {
if len(block) < DIGITS_PER_BLOCK && idx != 0 {
return
}
}
c.LogLocalf(TRACE, nil, "Handled float: '%s' -> %f", m.Text, v)
return ParseAmount(v) + currency, nil
newValue := value
newValue = strings.ReplaceAll(newValue, string(thousandsSeparator), "")
newValue = strings.ReplaceAll(newValue, ",", ".")
return newValue, nil
}

func HandleRaw(m *tb.Message) (string, error) {
Expand Down
40 changes: 39 additions & 1 deletion bot/transactionBuilder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func TestHandleFloatSimpleCalculations(t *testing.T) {
// Mixed calculation operators
_, err = bot.HandleFloat(&tb.Message{Text: "1+1*2"})
if err == nil || !strings.Contains(err.Error(), "failed at value '1*2'") {
t.Errorf("Error message should state that mixing operators is not allowed")
t.Errorf("Error message should state that mixing operators is not allowed: %e", err)
}
// Too many spaces in input
_, err = bot.HandleFloat(&tb.Message{Text: "some many spaces"})
Expand All @@ -107,6 +107,44 @@ func TestHandleFloatSimpleCalculations(t *testing.T) {
}
}

func TestHandleFloatThousandsSeparator(t *testing.T) {
handledFloat, err := bot.HandleFloat(&tb.Message{Text: "100,000,000.00"})
helpers.TestExpect(t, err, nil, "Should not throw an error for 100 million with comma thousands separator")
helpers.TestExpect(t, handledFloat, "100000000.00", "")

handledFloat, err = bot.HandleFloat(&tb.Message{Text: "100.000.000,00"})
helpers.TestExpect(t, err, nil, "Should not throw an error for 100 million with dot thousands separator")
helpers.TestExpect(t, handledFloat, "100000000.00", "")

handledFloat, err = bot.HandleFloat(&tb.Message{Text: "24,123.7"})
helpers.TestExpect(t, err, nil, "Should not throw an error for 24,123.7")
helpers.TestExpect(t, handledFloat, "24123.70", "")

_, err = bot.HandleFloat(&tb.Message{Text: "24,24.7"})
if err == nil || !strings.Contains(err.Error(), "invalid separators in value '24,24.7'") {
t.Errorf("Error message should state that separators used were invalid: %e", err)
}

_, err = bot.HandleFloat(&tb.Message{Text: "1.,23"})
if err == nil || !strings.Contains(err.Error(), "invalid separators in value '1.,23'") {
t.Errorf("Error message should state that separators used were invalid: %e", err)
}

_, err = bot.HandleFloat(&tb.Message{Text: "100,000.000,000"})
if err == nil || !strings.Contains(err.Error(), "invalid separators in value '100,000.000,000'") {
t.Errorf("Error message should state that separators used were invalid: %e", err)
}

_, err = bot.HandleFloat(&tb.Message{Text: "100,000.000,000.000"})
if err == nil || !strings.Contains(err.Error(), "invalid separators in value '100,000.000,000.000'") {
t.Errorf("Error message should state that separators used were invalid: %e", err)
}

handledFloat, err = bot.HandleFloat(&tb.Message{Text: "1,000.00+24"})
helpers.TestExpect(t, err, nil, "Should not throw an error for 1,000.00+24")
helpers.TestExpect(t, handledFloat, "1024.00", "")
}

func TestTransactionBuilding(t *testing.T) {
tx, err := bot.CreateSimpleTx("", bot.TEMPLATE_SIMPLE_DEFAULT)
if err != nil {
Expand Down

0 comments on commit fa2954e

Please sign in to comment.