Code

< 40 %
40-60 %
> 60 %
1
package money
2
3
import "errors"
4
5
// Money stores amount and currency value
6
type Money struct {
7
	amount   *Amount
8
	currency *Currency
9
}
10
11
var calc = &calculator{}
12
13
const (
14
	greaterThanCheckResult = 1
15
	equalCheckResult       = 0
16
	lessThanCheckResult    = -1
17
)
18
19
// New creates and returns a new Money instance
20
func New(amount int64, currency *Currency) *Money {
21 1
	return &Money{
22
		amount:   &Amount{val: amount},
23
		currency: currency,
24
	}
25
}
26
27
// Currency returns the currency used by Money
28
func (m *Money) Currency() *Currency {
29 1
	return m.currency
30
}
31
32
// Amount returns the amount value as int64
33
func (m *Money) Amount() *Amount {
34 1
	return m.amount
35
}
36
37
// Add returns new Money struct with value representing sum of Self and Other Money
38
func (m *Money) Add(money *Money) (*Money, error) {
39 1
	if err := m.assertSameCurrency(money); err != nil {
40 1
		return nil, err
41
	}
42
43 1
	return &Money{amount: calc.add(m.Amount(), money.Amount()), currency: m.currency}, nil
44
}
45
46
// Subtract returns new Money struct with value representing difference of Self and Other Money
47
func (m *Money) Subtract(money *Money) (*Money, error) {
48 1
	if err := m.assertSameCurrency(money); err != nil {
49 1
		return nil, err
50
	}
51
52 1
	return &Money{amount: calc.subtract(m.Amount(), money.Amount()), currency: m.currency}, nil
53
}
54
55
// Multiply returns new Money struct with value representing Self multiplied value by multiplier
56
func (m *Money) Multiply(mul int64) *Money {
57 1
	return &Money{amount: calc.multiply(m.Amount(), mul), currency: m.currency}
58
}
59
60
// Allocate returns slice of Money structs with split Self value in given ratios.
61
// It lets split money by given ratios without losing pennies and as Split operations distributes
62
// leftover pennies amongst the parties with round-robin principle.
63
func (m *Money) Allocate(rs ...int) ([]*Money, error) {
64 1
	if len(rs) == 0 {
65 1
		return nil, errors.New("No ratios specified")
66
	}
67
68
	// Calculate total of ratios
69 1
	var total int
70 1
	for _, r := range rs {
71 1
		total += r
72
	}
73
74 1
	var remainder = m.Amount().Value()
75 1
	var ms []*Money
76 1
	for _, r := range rs {
77 1
		m := &Money{
78
			amount:   calc.allocate(m.Amount(), r, total),
79
			currency: m.currency,
80
		}
81
82 1
		ms = append(ms, m)
83 1
		remainder -= m.Amount().Value()
84
	}
85
86 1
	for i := 0; i < int(remainder); i++ {
87 1
		ms[i] = &Money{
88
			amount:   calc.add(ms[i].Amount(), &Amount{1}),
89
			currency: ms[i].Currency(),
90
		}
91
	}
92
93 1
	return ms, nil
94
}
95
96
// Equals checkes equality between two Money instances
97
func (m *Money) Equals(money *Money) (bool, error) {
98 1
	if err := m.assertSameCurrency(money); err != nil {
99 1
		return false, err
100
	}
101
102 1
	return m.compare(money) == 0, nil
103
}
104
105
// GreaterThan checks whether the value of Money is greater than the other
106
func (m *Money) GreaterThan(money *Money) (bool, error) {
107 1
	if err := m.assertSameCurrency(money); err != nil {
108 1
		return false, err
109
	}
110
111 1
	return m.compare(money) == greaterThanCheckResult, nil
112
}
113
114
// GreaterThanOrEqual checks whether the value of Money is greater or equal than the other
115
func (m *Money) GreaterThanOrEqual(money *Money) (bool, error) {
116 1
	if err := m.assertSameCurrency(money); err != nil {
117 1
		return false, err
118
	}
119
120 1
	return m.compare(money) >= equalCheckResult, nil
121
}
122
123
// LessThan checks whether the value of Money is less than the other
124
func (m *Money) LessThan(money *Money) (bool, error) {
125 1
	if err := m.assertSameCurrency(money); err != nil {
126 1
		return false, err
127
	}
128
129 1
	return m.compare(money) == lessThanCheckResult, nil
130
}
131
132
// LessThanOrEqual checks whether the value of Money is less or equal than the other
133
func (m *Money) LessThanOrEqual(money *Money) (bool, error) {
134 1
	if err := m.assertSameCurrency(money); err != nil {
135 1
		return false, err
136
	}
137
138 1
	return m.compare(money) <= equalCheckResult, nil
139
}
140
141
// Display returns a formatted amount string for the current currency
142
func (m *Money) Display() string {
143 1
	return m.currency.Format(m.Amount().Value())
144
}
145
146
func (m *Money) assertSameCurrency(money *Money) error {
147 1
	if !m.currency.equals(money.currency) {
148 1
		return errors.New("Currency don't match")
149
	}
150
151 1
	return nil
152
}
153
154
func (m *Money) compare(money *Money) int {
155 1
	if m.Amount().Value() > money.Amount().Value() {
156 1
		return greaterThanCheckResult
157
	}
158
159 1
	if m.Amount().Value() < money.Amount().Value() {
160 1
		return lessThanCheckResult
161
	}
162
163 1
	return equalCheckResult
164
}
165