This repository has been archived by the owner on Apr 20, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 28
/
payment.go
210 lines (165 loc) · 6.72 KB
/
payment.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
package accounting
import (
"encoding/json"
"encoding/xml"
"time"
"github.com/XeroAPI/xerogolang"
"github.com/XeroAPI/xerogolang/helpers"
"github.com/markbates/goth"
)
//Payment details payments against invoices and CreditNotes
type Payment struct {
// Number of invoice or credit note you are applying payment to e.g. INV-4003
Invoice *Invoice `json:"Invoice,omitempty" xml:"Invoice,omitempty"`
// Number of invoice or credit note you are applying payment to e.g. INV-4003
CreditNote *CreditNote `json:"CreditNote,omitempty" xml:"CreditNote,omitempty"`
//Account of payment
Account *Account `json:"Account,omitempty" xml:"Account,omitempty"`
// Date the payment is being made (YYYY-MM-DD) e.g. 2009-09-06
Date string `json:"Date,omitempty" xml:"Date,omitempty"`
// Exchange rate when payment is received. Only used for non base currency invoices and credit notes e.g. 0.7500
CurrencyRate float32 `json:"CurrencyRate,omitempty" xml:"CurrencyRate,omitempty"`
// The amount of the payment. Must be less than or equal to the outstanding amount owing on the invoice e.g. 200.00
Amount float32 `json:"Amount,omitempty" xml:"Amount,omitempty"`
// An optional description for the payment e.g. Direct Debit
Reference string `json:"Reference,omitempty" xml:"Reference,omitempty"`
// An optional parameter for the payment. A boolean indicating whether you would like the payment to be created as reconciled when using PUT, or whether a payment has been reconciled when using GET
IsReconciled bool `json:"IsReconciled,omitempty" xml:"IsReconciled,omitempty"`
// The status of the payment.
Status string `json:"Status,omitempty" xml:"Status,omitempty"`
// See Payment Types.
PaymentType string `json:"PaymentType,omitempty" xml:"-"`
// UTC timestamp of last update to the payment
UpdatedDateUTC string `json:"UpdatedDateUTC,omitempty" xml:"-"`
// The Xero identifier for an Payment e.g. 297c2dc5-cc47-4afd-8ec8-74990b8761e9
PaymentID string `json:"PaymentID,omitempty" xml:"PaymentID,omitempty"`
}
//Payments is a collection of Payments
type Payments struct {
Payments []Payment `json:"Payments" xml:"Payment"`
}
//The Xero API returns Dates based on the .Net JSON date format available at the time of development
//We need to convert these to a more usable format - RFC3339 for consistency with what the API expects to recieve
func (p *Payments) convertDates() error {
var err error
for n := len(p.Payments) - 1; n >= 0; n-- {
p.Payments[n].Date, err = helpers.DotNetJSONTimeToRFC3339(p.Payments[n].Date, false)
if err != nil {
return err
}
p.Payments[n].UpdatedDateUTC, err = helpers.DotNetJSONTimeToRFC3339(p.Payments[n].UpdatedDateUTC, true)
if err != nil {
return err
}
}
return nil
}
func unmarshalPayment(paymentResponseBytes []byte) (*Payments, error) {
var paymentResponse *Payments
err := json.Unmarshal(paymentResponseBytes, &paymentResponse)
if err != nil {
return nil, err
}
err = paymentResponse.convertDates()
if err != nil {
return nil, err
}
return paymentResponse, err
}
//Create will create payments given an Payments struct
func (p *Payments) Create(provider *xerogolang.Provider, session goth.Session) (*Payments, error) {
additionalHeaders := map[string]string{
"Accept": "application/json",
"Content-Type": "application/xml",
}
body, err := xml.MarshalIndent(p, " ", " ")
if err != nil {
return nil, err
}
paymentResponseBytes, err := provider.Create(session, "Payments", additionalHeaders, body)
if err != nil {
return nil, err
}
return unmarshalPayment(paymentResponseBytes)
}
//Update will update an payment given an Payments struct
//This will only handle single payment - you cannot update multiple payments in a single call
//Payments cannot be modified, only created and deleted.
func (p *Payments) Update(provider *xerogolang.Provider, session goth.Session) (*Payments, error) {
additionalHeaders := map[string]string{
"Accept": "application/json",
"Content-Type": "application/xml",
}
//we can only update the status on a payment so we must strip out all the other values in order to update it
paymentToMarshal := Payment{
Status: p.Payments[0].Status,
}
body, err := xml.MarshalIndent(paymentToMarshal, " ", " ")
if err != nil {
return nil, err
}
paymentResponseBytes, err := provider.Update(session, "Payments/"+p.Payments[0].PaymentID, additionalHeaders, body)
if err != nil {
return nil, err
}
return unmarshalPayment(paymentResponseBytes)
}
//FindPaymentsModifiedSince will get all payments modified after a specified date.
//additional querystringParameters such as where, page, order can be added as a map
func FindPaymentsModifiedSince(provider *xerogolang.Provider, session goth.Session, modifiedSince time.Time, querystringParameters map[string]string) (*Payments, error) {
additionalHeaders := map[string]string{
"Accept": "application/json",
}
if !modifiedSince.Equal(dayZero) {
additionalHeaders["If-Modified-Since"] = modifiedSince.Format(time.RFC3339)
}
paymentResponseBytes, err := provider.Find(session, "Payments", additionalHeaders, querystringParameters)
if err != nil {
return nil, err
}
return unmarshalPayment(paymentResponseBytes)
}
//FindPayments will get all payments.
func FindPayments(provider *xerogolang.Provider, session goth.Session, querystringParameters map[string]string) (*Payments, error) {
return FindPaymentsModifiedSince(provider, session, dayZero, querystringParameters)
}
//FindPayment will get a single payment - paymentID must be a GUID for an payment
func FindPayment(provider *xerogolang.Provider, session goth.Session, paymentID string) (*Payments, error) {
additionalHeaders := map[string]string{
"Accept": "application/json",
}
paymentResponseBytes, err := provider.Find(session, "Payments/"+paymentID, additionalHeaders, nil)
if err != nil {
return nil, err
}
return unmarshalPayment(paymentResponseBytes)
}
//RemovePayment will get a single payment - paymentID must be a GUID for an payment
func RemovePayment(provider *xerogolang.Provider, session goth.Session, paymentID string) (*Payments, error) {
additionalHeaders := map[string]string{
"Accept": "application/json",
}
paymentResponseBytes, err := provider.Remove(session, "Payments/"+paymentID, additionalHeaders)
if err != nil {
return nil, err
}
return unmarshalPayment(paymentResponseBytes)
}
//GenerateExamplePayment Creates an Example payment
func GenerateExamplePayment(invoiceID string, amount float32) *Payments {
payment := Payment{
Date: helpers.TodayRFC3339(),
Amount: amount,
Invoice: &Invoice{
InvoiceID: invoiceID,
},
Account: &Account{
Code: "200",
},
}
paymentCollection := &Payments{
Payments: []Payment{},
}
paymentCollection.Payments = append(paymentCollection.Payments, payment)
return paymentCollection
}