-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaccounting.go
351 lines (294 loc) · 15.1 KB
/
accounting.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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
package axcelerate
import (
"encoding/json"
"fmt"
)
// CoursesService handles all interactions with Contact
type AccountingService struct {
client *Client
}
type Items struct {
TotalTax float32 `json:"TOTALTAX"`
Children struct {
} `json:"CHILDREN"`
UnitPriceTax float32 `json:"UNITPRICETAX"`
DomainID int `json:"DOMAINID"`
HasChildren int `json:"HASCHILDREN"`
PartID int `json:"PARTID"`
UnitPriceNet float32 `json:"UNITPRICENETT"`
Qty int `json:"QTY"`
TaxPercent int `json:"TAXPERCENT"`
TotalGross float32 `json:"TOTALGROSS"`
ItemCode string `json:"ITEMCODE"`
FinanceCode string `json:"FINANCECODE"`
TotalNet float32 `json:"TOTALNETT"`
SourceID int `json:"SOURCEID"`
ServiceDate string `json:"SERVICEDATE" time_format:"axc_date"`
UnitPriceGross float32 `json:"UNITPRICEGROSS"`
ItemID int `json:"ITEMID"`
Description string `json:"DESCRIPTION"`
CostCentreCode interface{} `json:"COSTCENTRECODE"`
}
// Invoice object with the full Invoice information
type Invoice struct {
InvoiceNumber string `json:"INVOICENR"`
PriceGross float32 `json:"PRICEGROSS"`
Address2 string `json:"ADDRESS2"`
OwnerContactID int `json:"OWNERCONTACTID"`
Organisation string `json:"ORGANISATION"`
ShipLastName string `json:"SHIPLASTNAME"`
ShipHousenr string `json:"SHIPHOUSENR"`
ShipOrgID int `json:"SHIPORGID"`
ShipPostCode string `json:"SHIPPOSTCODE"`
Comment string `json:"COMMENT"`
PhoneNumber string `json:"PHONENR"`
OrgID int `json:"ORGID"`
Payments []PaymentDetails `json:"PAYMENTS"`
ShipCountry string `json:"SHIPCOUNTRY"`
DueDate string `json:"DUEDATE" time_format:"axc_date"`
ShipOrganisation string `json:"SHIPORGANISATION"`
InvoiceID int `json:"INVOICEID"`
DueDateOffset int `json:"DUEDATEOFFSET"`
AreItemsLocked bool `json:"AREITEMSLOCKED"`
LastName string `json:"LASTNAME"`
Street string `json:"STREET"`
Items []Items `json:"ITEMS"`
InvoiceDate string `json:"INVOICEDATE" time_format:"axc_date"`
Currency string `json:"CURRENCY"`
ShipPriceNett float32 `json:"SHIPPRICENETT"`
ShipState string `json:"SHIPSTATE"`
ContactName string `json:"CONTACTNAME"`
ShipCountryISO3166 string `json:"SHIPCOUNTRYISO3166"`
Shipstreet string `json:"SHIPSTREET"`
Housenr string `json:"HOUSENR"`
Isarchived bool `json:"ISARCHIVED"`
OrderDate string `json:"ORDERDATE" time_format:"axc_date"`
ContactID int `json:"CONTACTID"`
ShipCity string `json:"SHIPCITY"`
Shippricegross float32 `json:"SHIPPRICEGROSS"`
CountryISO3166 string `json:"COUNTRYISO3166"`
Isinvoicenrlocked bool `json:"ISINVOICENRLOCKED"`
Shiptaxpercent int `json:"SHIPTAXPERCENT"`
Shippricetax int `json:"SHIPPRICETAX"`
State string `json:"STATE"`
FirstName string `json:"FIRSTNAME"`
Shipaddress2 string `json:"SHIPADDRESS2"`
ShipFirstName string `json:"SHIPFIRSTNAME"`
City string `json:"CITY"`
OrderNumber string `json:"ORDERNR"`
Email string `json:"EMAIL"`
PriceNett float32 `json:"PRICENETT"`
Country string `json:"COUNTRY"`
InvGUID string `json:"INVGUID"`
Balance float32 `json:"BALANCE"`
Postcode string `json:"POSTCODE"`
IsPaid bool `json:"ISPAID"`
}
type PaymentRequestDetails struct {
CancelURL string `json:"CANCELURL"` // URL to cancel the payment process
WebhookURL string `json:"WEBHOOKURL"` // URL for webhook notifications
RedirectURL string `json:"REDIRECTURL"` // URL to redirect after payment
InvoiceGUID string `json:"INVOICEGUID"` // GUID of the invoice
}
type PaymentErrorDetails struct {
ErrorCode int `json:"ERROR_CODE"` // Error code
ErrorMessage string `json:"ERROR_MSG"` // Error message
Code int `json:"CODE"` // Error code
Msg string `json:"MSG"` // Error message
}
type PaymentResultDetails struct {
Error PaymentErrorDetails `json:"ERROR"` // Details of any error encountered
TransactionGUID string `json:"TRANSACTIONGUID"` // GUID of the transaction
TransactionID string `json:"TRANSACTIONID"` // ID of the transaction
IsSuccessful bool `json:"OK"` // Indicates if the transaction was successful
PlatformName string `json:"PLATFORM"` // Platform used for the transaction
}
type FullPaymentResponse struct {
RequestDetails PaymentRequestDetails `json:"REQUEST"` // Details of the payment request
CurrentState string `json:"STATE"` // Current state of the payment
PaymentPlatform string `json:"PLATFORM"` // Platform used for payment
ResultDetails PaymentResultDetails `json:"RESULT"` // Result details of the payment process
PlatformRefGUID string `json:"PLATFORMREFERENCE"` // Reference for the platform transaction
ErrorResponse *PaymentErrorResponse `json:"-"` // Populated if an error response is detected
}
// PaymentErrorResponse represents an alternative error response structure
type PaymentErrorResponse struct {
Data string `json:"DATA"` // Encoded metadata and variables
Error bool `json:"ERROR"` // Indicates if the response is an error
Messages string `json:"MESSAGES"` // Error messages
Code string `json:"CODE"` // Error code
Details string `json:"DETAILS"` // Error details
}
type PaymentRequest struct {
Meta map[string]interface{} `json:"META"` // Metadata (deprecated; avoid use in new implementations)
FormMethod string `json:"FORMMETHOD"` // Form method, e.g., POST
Script string `json:"SCRIPT"` // Script field (deprecated; avoid use in new implementations)
HTML string `json:"HTML"` // The HTML that should be rendered inside of an HTML form tag
Action string `json:"ACTION"` // The action attribute for the form into which the returned HTML is inserted
}
type PaymentResponse struct {
Data PaymentRequest `json:"DATA"` // Contains the payment request details
Success bool `json:"SUCCESS"` // Returns true if a checkout form could be generated
}
type PaymentDetails struct {
TransactionDate string `json:"TRANSACTIONDATE" time_format:"axc_date_hours"` // Date and time of the transaction
TransactionProviderID int `json:"TRANSACTIONPROVIDERID"` // Provider ID for the transaction
GUID string `json:"GUID"` // Unique transaction GUID
ProviderName string `json:"TRANSACTIONPROVIDER"` // Name of the transaction provider
FragmentAmount float32 `json:"FRAGMENT_AMOUNT"` // Partial amount of the transaction
}
type PaymentURL struct {
URL string `json:"PAYMENTURL"` // URL to proceed with the payment
}
type InvoiceSummary struct {
InvoiceNr string `json:"INVOICENR"` // Invoice number
PriceGross string `json:"PRICEGROSS"` // Gross price of the invoice
DueDate string `json:"DUEDATE"` // Due date of the invoice
InvoiceID string `json:"INVOICEID"` // Unique identifier for the invoice
AreItemsLocked bool `json:"AREITEMSLOCKED"` // Indicates if items in the invoice are locked
LastName string `json:"LASTNAME"` // Last name associated with the invoice
IsCancelled bool `json:"ISCANCELLED"` // Indicates if the invoice is cancelled
ExternalReference *string `json:"EXTERNALREFERENCE"` // External reference, nullable
Balance string `json:"BALANCE"` // Remaining balance on the invoice
FirstName string `json:"FIRSTNAME"` // First name associated with the invoice
InvoiceDate string `json:"INVOICEDATE"` // Invoice creation date
IsVoid bool `json:"ISVOID"` // Indicates if the invoice is void
IsPaid bool `json:"ISPAID"` // Indicates if the invoice is paid
}
type InvoiceCollection []InvoiceSummary
// GetInvoice will get the details of an invoice / Update an invoice (NOTE: Currently you can only Lock Items and Finalise)
// Header Type Required Default Description
// invoiceID numeric true The invoiceID to retrieve. Note that this is NOT the same as the invoice number
func (s *AccountingService) GetInvoice(invoiceID int) (*Invoice, *Response, error) {
var obj Invoice
parms := map[string]string{"invoiceID": fmt.Sprintf("/%d", invoiceID)}
url := fmt.Sprintf("/accounting/invoice/%d", invoiceID)
resp, err := do(s.client, "GET", Params{parms: parms, u: url}, obj)
if err != nil {
return nil, resp, err
}
err = json.Unmarshal([]byte(resp.Body), &obj)
return &obj, resp, err
}
// Invoices will get an array of invoices for an account
// Header Type Required Default Description
// contactID numeric true The contactID to return invoices for that contact
func (s *AccountingService) Invoices(contactID int, extra *map[string]string) ([]InvoiceSummary, *Response, error) {
var obj []InvoiceSummary
// Initialize parms as an empty map
parms := map[string]string{}
// If extra is not nil, merge its contents into parms
if extra != nil {
for key, value := range *extra {
parms[key] = value
}
}
// Add contactID to parms
parms["contactID"] = fmt.Sprintf("%d", contactID)
resp, err := do(s.client, "GET", Params{parms: parms, u: "/accounting/invoice"}, obj)
if err != nil {
return obj, resp, err
}
err = json.Unmarshal([]byte(resp.Body), &obj)
return obj, resp, err
}
// PaymentAxcelerateURL Get a payable URL for an invoice.
// Header Type Required Default Description
// invoiceID numeric true The invoiceID to pay
func (s *AccountingService) PaymentAxcelerateURL(invoiceID int) (*PaymentURL, *Response, error) {
var obj PaymentURL
parms := map[string]string{}
url := fmt.Sprintf("/accounting/invoice/%d/paymenturl", invoiceID)
resp, err := do(s.client, "GET", Params{parms: parms, u: url}, obj)
if err != nil {
return nil, resp, err
}
err = json.Unmarshal([]byte(resp.Body), &obj)
return &obj, resp, err
}
// PaymentURL will get an array of invoices for an account
// Header Type Required Default Description
// reference string true The external identifier for the payment flow process.
// invoiceGUID string true The GUID of the aXcelerate invoice for which payment should be collected.
// redirectURL string true The URL to which the client will be redirected after payment processing.
// cancelURL string true The URL to which the client is redirected if the client decides to cancel payment processing.
func (s *AccountingService) PaymentURL(reference, invoiceGUID, redirectURL, cancelURL string) (*PaymentRequest, *Response, error) {
var obj PaymentRequest
parms := map[string]string{}
parms["reference"] = reference
parms["invoiceGUID"] = invoiceGUID
parms["redirectURL"] = redirectURL
parms["cancelURL"] = cancelURL
url := "/accounting/ecommerce/payment/url"
resp, err := do(s.client, "GET", Params{parms: parms, u: url}, obj)
if err != nil {
return nil, resp, err
}
err = json.Unmarshal([]byte(resp.Body), &obj)
return &obj, resp, err
}
// PaymentForm will get an array of invoices for an account
// Header Type Required Default Description
// reference string true The external identifier for the payment flow process.
// invoiceGUID string true The GUID of the aXcelerate invoice for which payment should be collected.
// redirectURL string true The URL to which the client will be redirected after payment processing.
// cancelURL string true The URL to which the client is redirected if the client decides to cancel payment processing.
func (s *AccountingService) PaymentForm(reference, invoiceGUID, redirectURL, cancelURL string) (*PaymentResponse, *Response, error) {
var obj PaymentResponse
parms := map[string]string{}
parms["reference"] = reference
parms["invoiceGUID"] = invoiceGUID
parms["redirectURL"] = redirectURL
parms["cancelURL"] = cancelURL
url := "/accounting/ecommerce/payment/url"
resp, err := do(s.client, "GET", Params{parms: parms, u: url}, obj)
if err != nil {
return nil, resp, err
}
err = json.Unmarshal([]byte(resp.Body), &obj)
return &obj, resp, err
}
// UnmarshalJSON custom unmarshals PaymentResultDetails to handle string or object cases
func (r *PaymentResultDetails) UnmarshalJSON(data []byte) error {
if string(data) == `""` { // Handle the case where RESULT is an empty string
return nil
}
// Otherwise, unmarshal into the struct as usual
type Alias PaymentResultDetails
aux := (*Alias)(r)
return json.Unmarshal(data, aux)
}
// PaymentVerify Returns the current state of a payment flow process.
// Header Type Required Default Description
// reference string true The external identifier for the payment flow process.
// PaymentVerify returns the current state of a payment flow process, handling dynamic JSON structures
func (s *AccountingService) PaymentVerify(reference string) (*FullPaymentResponse, *Response, error) {
url := fmt.Sprintf("/accounting/ecommerce/payment/ref/%s", reference)
// Make the request
resp, err := do(s.client, "GET", Params{parms: nil, u: url}, nil)
if err != nil {
return nil, resp, err
}
// Initialize the FullPaymentResponse struct
var fullPaymentResp FullPaymentResponse
// Try to unmarshal into FullPaymentResponse
if err := json.Unmarshal([]byte(resp.Body), &fullPaymentResp); err == nil {
// Handle cases where RESULT is an empty string
if fullPaymentResp.ResultDetails == (PaymentResultDetails{}) && resp.Body != "" {
var errorResp PaymentErrorResponse
if json.Unmarshal([]byte(resp.Body), &errorResp) == nil && errorResp.Error {
fullPaymentResp.ErrorResponse = &errorResp
return &fullPaymentResp, resp, fmt.Errorf("error: %s (code: %s, details: %s)", errorResp.Messages, errorResp.Code, errorResp.Details)
}
}
return &fullPaymentResp, resp, nil
}
// Handle direct error response format
var errorResp PaymentErrorResponse
if err := json.Unmarshal([]byte(resp.Body), &errorResp); err == nil {
fullPaymentResp.ErrorResponse = &errorResp
return &fullPaymentResp, resp, fmt.Errorf("error: %s (code: %s, details: %s)", errorResp.Messages, errorResp.Code, errorResp.Details)
}
// Fallback for unknown formats
return nil, resp, fmt.Errorf("unknown response format: %s", resp.Body)
}