This repository has been archived by the owner on Dec 29, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
money.go
119 lines (98 loc) · 2.73 KB
/
money.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package money
import (
"fmt"
"math/big"
"strings"
"github.com/juju/errors"
)
// Money represents a monetary value
type Money struct {
rat *big.Rat
}
// New creates a new instance with a zero value.
func New() *Money {
return &Money{
rat: big.NewRat(0, 1),
}
}
// NewFromCents creates a new instance with a cents value.
func NewFromCents(cents int64) *Money {
return &Money{
rat: big.NewRat(cents, 100),
}
}
// Parse a string to create a new money value. It can read `XX.YY` and `XX,YY`.
// An empty string is parsed as zero.
func Parse(s string) (*Money, error) {
if len(s) == 0 {
return New(), nil
}
s = strings.Replace(s, ",", ".", -1)
rat := new(big.Rat)
if _, err := fmt.Sscan(s, rat); err != nil {
return nil, errors.Trace(err)
}
return &Money{rat}, nil
}
// Cents returns the value with cents precision (2 decimal places) as a number.
func (money *Money) Cents() int64 {
cents := big.NewInt(100)
v := new(big.Int)
v.Mul(money.rat.Num(), cents)
v.Quo(v, money.rat.Denom())
return v.Int64()
}
// Format the money value with a specific decimal precision.
func (money *Money) Format(prec int) string {
return money.rat.FloatString(prec)
}
// Mul multiplies the money value n times and returns the result.
func (money *Money) Mul(n int64) *Money {
b := big.NewRat(n, 1)
result := New()
result.rat.Mul(money.rat, b)
return result
}
// Add two money values together and returns the result.
func (money *Money) Add(other *Money) *Money {
result := New()
result.rat.Add(money.rat, other.rat)
return result
}
// Sub subtracts two money values and returns the result.
func (money *Money) Sub(other *Money) *Money {
result := New()
result.rat.Sub(money.rat, other.rat)
return result
}
// Div divides two money values and returns the result.
func (money *Money) Div(other *Money) *Money {
result := New()
result.rat.Quo(money.rat, other.rat)
return result
}
// LessThan returns true if a money value is less than the other.
func (money *Money) LessThan(other *Money) bool {
return money.rat.Cmp(other.rat) == -1
}
// AddTaxPercent adds a percentage of the price to itself.
func (money *Money) AddTaxPercent(tax int64) *Money {
result := New()
result.rat.Set(money.rat)
ratTax := big.NewRat(tax, 100)
result.rat.Add(result.rat, ratTax.Mul(ratTax, money.rat))
return result
}
// IsZero returns true if there is no money.
func (money *Money) IsZero() bool {
return money.Cents() == 0
}
// Markup adds a percentage with decimals of the price to itself. The
// percentage should be pre-multiplied by 100 to avoid floating point issues.
func (money *Money) Markup(tax int64) *Money {
result := New()
result.rat.Set(money.rat)
ratTax := big.NewRat(tax, 10000)
result.rat.Add(result.rat, ratTax.Mul(ratTax, money.rat))
return result
}