71 lines
1.5 KiB
Go
71 lines
1.5 KiB
Go
package invoice
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// Quantity stores hundredths (e.g. 0.5 => 50).
|
|
func ParseQuantity(input string) (Quantity, error) {
|
|
clean := strings.TrimSpace(input)
|
|
if clean == "" {
|
|
return 0, errors.New("empty quantity")
|
|
}
|
|
clean = strings.ReplaceAll(clean, " ", "")
|
|
clean = strings.ReplaceAll(clean, ",", ".")
|
|
if strings.HasPrefix(clean, ".") || strings.HasSuffix(clean, ".") {
|
|
return 0, fmt.Errorf("invalid quantity: %q", input)
|
|
}
|
|
parts := strings.Split(clean, ".")
|
|
if len(parts) > 2 {
|
|
return 0, fmt.Errorf("invalid quantity: %q", input)
|
|
}
|
|
whole := parts[0]
|
|
frac := ""
|
|
if len(parts) == 2 {
|
|
frac = parts[1]
|
|
}
|
|
if whole == "" {
|
|
whole = "0"
|
|
}
|
|
for _, r := range whole {
|
|
if r < '0' || r > '9' {
|
|
return 0, fmt.Errorf("invalid quantity: %q", input)
|
|
}
|
|
}
|
|
for _, r := range frac {
|
|
if r < '0' || r > '9' {
|
|
return 0, fmt.Errorf("invalid quantity: %q", input)
|
|
}
|
|
}
|
|
if len(frac) > 2 {
|
|
return 0, fmt.Errorf("invalid quantity: %q", input)
|
|
}
|
|
for len(frac) < 2 {
|
|
frac += "0"
|
|
}
|
|
var wholeValue int64
|
|
for _, r := range whole {
|
|
wholeValue = wholeValue*10 + int64(r-'0')
|
|
}
|
|
var fracValue int64
|
|
for _, r := range frac {
|
|
fracValue = fracValue*10 + int64(r-'0')
|
|
}
|
|
return Quantity(wholeValue*100 + fracValue), nil
|
|
}
|
|
|
|
func FormatQuantity(q Quantity) string {
|
|
value := int64(q)
|
|
whole := value / 100
|
|
frac := value % 100
|
|
if frac == 0 {
|
|
return fmt.Sprintf("%d", whole)
|
|
}
|
|
if frac%10 == 0 {
|
|
return fmt.Sprintf("%d.%d", whole, frac/10)
|
|
}
|
|
return fmt.Sprintf("%d.%02d", whole, frac)
|
|
}
|