-
Notifications
You must be signed in to change notification settings - Fork 1
/
credit_card.go
94 lines (81 loc) · 2.61 KB
/
credit_card.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
package lib
import (
"bytes"
"encoding/json"
"errors"
"net/url"
"github.com/BytemarkHosting/bytemark-client/lib/billing"
"github.com/BytemarkHosting/bytemark-client/lib/spp"
"github.com/BytemarkHosting/bytemark-client/util/log"
)
type sppTokenResponse struct {
Token string `json:"token"`
}
// GetSPPToken requests a token to use with SPP from bmbilling.
// If owner is nil, authenticates against bmbilling.
func (c *bytemarkClient) GetSPPToken(cc spp.CreditCard, owner billing.Person) (token string, err error) {
r, err := c.BuildRequestNoAuth("POST", BillingEndpoint, "/api/v1/accounts/spp_token")
if err != nil {
return
}
// i'm not really interested in whether a card number is valid, just whether it's long enough to have a last 4 digits.
if len(cc.Number) < 4 {
err = errors.New("credit card number too short")
return
}
tokenRequest := billing.SPPTokenRequest{
Owner: &owner,
CardEnding: cc.Number[len(cc.Number)-4:],
}
if !owner.IsValid() {
tokenRequest.Owner = nil
// rebuild the request so it has auth
r, err = c.BuildRequest("POST", BillingEndpoint, "/api/v1/accounts/spp_token")
if err != nil {
return
}
}
js, err := json.Marshal(&tokenRequest)
if err != nil {
return "", err
}
res := sppTokenResponse{}
_, _, err = r.Run(bytes.NewBuffer(js), &res)
token = res.Token
return
}
// CreateCreditCard creates a credit card on SPP using the given token. Tokens must be acquired by using GetSPPToken or GetSPPTokenWithAccount first.
func (c *bytemarkClient) CreateCreditCardWithToken(cc spp.CreditCard, token string) (ref string, err error) {
req, err := c.BuildRequestNoAuth("POST", SPPEndpoint, "/card.ref")
if err != nil {
return
}
values := url.Values{}
values.Add("token", token)
values.Add("account_number", cc.Number)
values.Add("name", cc.Name)
values.Add("expiry", cc.Expiry)
values.Add("cvv", cc.CVV)
if cc.Street != "" {
values.Add("street", cc.Street)
values.Add("city", cc.City)
values.Add("postcode", cc.Postcode)
values.Add("country", cc.Country)
}
// prevent CC details and card reference being written to log
// this is a bit of a sledgehammer
// TODO make it not a sledgehammer somehow
oldfile := log.LogFile
log.LogFile = nil
_, response, err := req.Run(bytes.NewBufferString(values.Encode()), nil)
log.LogFile = oldfile
return string(response), err
}
// CreateCreditCard creates a credit card on SPP. It uses GetSPPToken to get a token.
func (c *bytemarkClient) CreateCreditCard(cc spp.CreditCard) (ref string, err error) {
token, err := c.GetSPPToken(cc, billing.Person{})
if err != nil {
return
}
return c.CreateCreditCardWithToken(cc, token)
}