-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreceipt.go
141 lines (123 loc) · 3.49 KB
/
receipt.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package monzo
import (
"encoding/json"
"fmt"
)
// Item represents a single line on a Receipt.
type Item struct {
description string
amount int
currency Currency
quantity int
unit string
// subItems can only be nested one level deep.
//
// Monzo does not complain if a nested subItem is passed,
// but this should probably be checked at library-level.
// TODO: Prevent subItems being nested.
subItems []*Item
}
// Receipt represents a summary of spending against a transaction.
type Receipt struct {
TransactionID string
ExternalID string
Total int
Currency Currency
Items []*Item
}
// MakeReceiptItem creates an Item representing a single line
// of a receipt.
func MakeReceiptItem(desc string, amount int, currency Currency) *Item {
return &Item{
description: desc,
amount: amount,
currency: currency,
unit: "unit",
quantity: 1,
}
}
// AddSubItem adds a sub item to an existing Item. Monzo only
// supports one level of nesting Items.
func (i *Item) AddSubItem(subitem *Item) {
i.subItems = append(i.subItems, subitem)
}
// Unit adds a unit measurement to an Item.
// For example, "kgs" or "piece".
func (i *Item) Unit(unit string) {
i.unit = unit
}
// Quantity adds a quantity to an Item. The default quantity
// when creating an item is one.
func (i *Item) Quantity(quant int) {
i.quantity = quant
}
// MakeReceipt creates a Receipt to store against a Transaction.
func MakeReceipt(externalID string) *Receipt {
return &Receipt{
ExternalID: externalID,
}
}
// AddItem adds a number of Items to a Receipt.
func (r *Receipt) AddItem(is ...*Item) {
r.Items = append(r.Items, is...)
}
// SetTransaction determines which Transaction the Receipt
// should be saved against.
func (r *Receipt) SetTransaction(transaction string) {
r.TransactionID = transaction
}
// MarshalJSON converts the Receipt into a format usable by
// the Monzo API.
func (r *Receipt) MarshalJSON() ([]byte, error) {
if len(r.Items) == 0 {
return nil, fmt.Errorf("a receipt must contain at least one item")
}
r.calculateTotal()
r.determineCurrency()
return json.Marshal(struct {
TransactionID string `json:"transaction_id"`
ExternalID string `json:"external_id"`
Total int `json:"total"`
Currency Currency `json:"currency"`
Items []*Item `json:"items"`
}{
TransactionID: r.TransactionID,
ExternalID: r.ExternalID,
Total: r.Total,
Currency: r.Currency,
Items: r.Items,
})
}
// calculateTotal saves the total cost of all receipt Items
// in the Receipt's Total field.
func (r *Receipt) calculateTotal() {
r.Total = 0
for _, item := range r.Items {
r.Total = r.Total + item.amount
}
}
// determineCurrency sets the currency for the receipt. A receipt
// can only be for a single currency, so just grab the first
// item's currency and use that.
func (r *Receipt) determineCurrency() {
r.Currency = r.Items[0].currency
}
// MarshalJSON converts the Item into a json object that can
// be read by the Monzo API.
func (i *Item) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Description string `json:"description"`
Quantity int `json:"quantity"`
Unit string `json:"unit"`
Amount int `json:"amount"`
Currency Currency `json:"currency"`
SubItems []*Item `json:"sub_items"`
}{
Description: i.description,
Quantity: i.quantity,
Unit: i.unit,
Amount: i.amount,
Currency: i.currency,
SubItems: i.subItems,
})
}