GetAuthorization, CreatePayment, tests, README

This commit is contained in:
Aliaksandr Pliutau 2015-12-01 11:35:25 +07:00
parent 04214cbc33
commit 0c8d78e8a2
7 changed files with 303 additions and 2 deletions

View File

@ -6,10 +6,18 @@
* POST /v1/oauth2/token
* POST /v1/payments/payment
* GET /v1/payments/payment/%ID%
- GET /v1/payments/payment
* GET /v1/payments/payment
* GET /v1/payments/authorization/%ID%
* POST /v1/payments/authorization/%ID%/capture
* POST /v1/payments/authorization/%ID%/void
* POST /v1/payments/authorization/%ID%/reauthorize
#### Create client
```go
import "github.com/logpacker/paypalsdk"
```
```go
// Create a client instance
c, err := paypalsdk.NewClient("clietnid", "secret", paypalsdk.APIBaseSandBox)
@ -40,6 +48,39 @@ paymentResult, err := c.CreateDirectPaypalPayment(amount, redirectURI, cancelURI
// After approval user will be redirected to return_url from Request with PaymentID
```
### Create any payment
```go
p := paypalsdk.Payment{
Intent: "sale",
Payer: &paypalsdk.Payer{
PaymentMethod: "credit_card",
FundingInstruments: []paypalsdk.FundingInstrument{paypalsdk.FundingInstrument{
CreditCard: &paypalsdk.CreditCard{
Number: "4111111111111111",
Type: "visa",
ExpireMonth: "11",
ExpireYear: "2020",
CVV2: "777",
FirstName: "John",
LastName: "Doe",
},
}},
},
Transactions: []paypalsdk.Transaction{paypalsdk.Transaction{
Amount: &paypalsdk.Amount{
Currency: "USD",
Total: "200",
},
Description: "My Payment",
}},
RedirectURLs: &paypalsdk.RedirectURLs{
ReturnURL: "http://...",
CancelURL: "http://...",
},
}
paymentResponse, err := client.CreatePayment(p)
```
#### Execute approved payment
```go
@ -64,3 +105,27 @@ payment, err := c.GetPayment(paymentID)
// Get all payments slice
payments, err := c.GetPayments()
```
#### Get authorization by ID
```go
auth, err := c.GetAuthorization("AUTH-1")
```
#### Capture authorization
```go
capture, err := c.CaptureAuthorization("AUTH-1", &paypalsdk.Amount{Total: "200", Currency: "USD"}, true)
```
#### Void authorization
```go
auth, err := c.VoidAuthorization("AUTH-1")
```
#### Reauthorize authorization
```go
auth, err := c.ReauthorizeAuthorization("AUTH-1", &paypalsdk.Amount{Total: "200", Currency: "USD"})
```

79
auth.go
View File

@ -27,3 +27,82 @@ func (c *Client) GetAccessToken() (*TokenResponse, error) {
return &t, err
}
// GetAuthorization returns an authorization by ID
func (c *Client) GetAuthorization(authID string) (*Authorization, error) {
buf := bytes.NewBuffer([]byte(""))
req, err := http.NewRequest("GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/authorization/"+authID), buf)
if err != nil {
return &Authorization{}, err
}
auth := &Authorization{}
err = c.SendWithAuth(req, auth)
if err != nil {
return auth, err
}
return auth, nil
}
// CaptureAuthorization captures and process an existing authorization.
// To use this method, the original payment must have Intent set to "authorize"
func (c *Client) CaptureAuthorization(authID string, a *Amount, isFinalCapture bool) (*Capture, error) {
isFinalStr := "false"
if isFinalCapture {
isFinalStr = "true"
}
buf := bytes.NewBuffer([]byte("{\"amount\":{\"currency\":\"" + a.Currency + "\",\"total\":\"" + a.Total + "\"},\"is_final_capture\":" + isFinalStr + "}"))
req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/authorization/"+authID+"/capture"), buf)
if err != nil {
return &Capture{}, err
}
capture := &Capture{}
err = c.SendWithAuth(req, capture)
if err != nil {
return capture, err
}
return capture, nil
}
// VoidAuthorization voids a previously authorized payment
func (c *Client) VoidAuthorization(authID string) (*Authorization, error) {
buf := bytes.NewBuffer([]byte(""))
req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/authorization/"+authID+"/void"), buf)
if err != nil {
return &Authorization{}, err
}
auth := &Authorization{}
err = c.SendWithAuth(req, auth)
if err != nil {
return auth, err
}
return auth, nil
}
// ReauthorizeAuthorization reauthorize a Paypal account payment.
// PayPal recommends to reauthorize payment after ~3 days
func (c *Client) ReauthorizeAuthorization(authID string, a *Amount) (*Authorization, error) {
buf := bytes.NewBuffer([]byte("{\"amount\":{\"currency\":\"" + a.Currency + "\",\"total\":\"" + a.Total + "\"}}"))
req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/authorization/"+authID+"/reauthorize"), buf)
if err != nil {
return &Authorization{}, err
}
auth := &Authorization{}
err = c.SendWithAuth(req, auth)
if err != nil {
return auth, err
}
return auth, nil
}

View File

@ -8,3 +8,47 @@ func TestGetAccessToken(t *testing.T) {
c, _ := NewClient("clid", "secret", APIBaseSandBox)
c.GetAccessToken()
}
func TestGetAuthorization(t *testing.T) {
c, _ := NewClient("clid", "secret", APIBaseSandBox)
c.GetAccessToken()
_, err := c.GetAuthorization("123")
if err == nil {
t.Errorf("Error must be returned for invalid Auth ID")
}
}
func TestCaptureAuthorization(t *testing.T) {
c, _ := NewClient("clid", "secret", APIBaseSandBox)
c.GetAccessToken()
_, err := c.CaptureAuthorization("123", &Amount{Total: "200", Currency: "USD"}, true)
if err == nil {
t.Errorf("Error must be returned for invalid Auth ID")
}
}
func TestVoidAuthorization(t *testing.T) {
c, _ := NewClient("clid", "secret", APIBaseSandBox)
c.GetAccessToken()
_, err := c.VoidAuthorization("123")
if err == nil {
t.Errorf("Error must be returned for invalid Auth ID")
}
}
func TestReauthorizeAuthorization(t *testing.T) {
c, _ := NewClient("clid", "secret", APIBaseSandBox)
c.GetAccessToken()
_, err := c.ReauthorizeAuthorization("123", &Amount{Total: "200", Currency: "USD"})
if err == nil {
t.Errorf("Error must be returned for invalid Auth ID")
}
}

View File

@ -1,6 +1,7 @@
package paypalsdk
import (
"bytes"
"encoding/json"
"errors"
"io"
@ -92,11 +93,28 @@ func (c *Client) Send(req *http.Request, v interface{}) error {
// If the access token soon to be expired, it will try to get a new one before
// making the main request
func (c *Client) SendWithAuth(req *http.Request, v interface{}) error {
req.Header.Set("Authorization", "Bearer "+c.Token.Token)
if c.Token != nil {
req.Header.Set("Authorization", "Bearer "+c.Token.Token)
}
return c.Send(req, v)
}
// NewRequest constructs a request
// Convert payload to a JSON
func (c *Client) NewRequest(method, url string, payload interface{}) (*http.Request, error) {
var buf io.Reader
if payload != nil {
var b []byte
b, err := json.Marshal(&payload)
if err != nil {
return nil, err
}
buf = bytes.NewBuffer(b)
}
return http.NewRequest(method, url, buf)
}
func (c *Client) log(req *http.Request, resp *http.Response) {
if c.LogFile != "" {
os.OpenFile(c.LogFile, os.O_CREATE, 0755)

View File

@ -35,5 +35,41 @@ func main() {
fmt.Println("ERROR: " + err.Error())
os.Exit(1)
}
p := paypalsdk.Payment{
Intent: "sale",
Payer: &paypalsdk.Payer{
PaymentMethod: "credit_card",
FundingInstruments: []paypalsdk.FundingInstrument{paypalsdk.FundingInstrument{
CreditCard: &paypalsdk.CreditCard{
Number: "4111111111111111",
Type: "visa",
ExpireMonth: "11",
ExpireYear: "2020",
CVV2: "777",
FirstName: "John",
LastName: "Doe",
},
}},
},
Transactions: []paypalsdk.Transaction{paypalsdk.Transaction{
Amount: &paypalsdk.Amount{
Currency: "USD",
Total: "200",
},
Description: "My Payment",
}},
RedirectURLs: &paypalsdk.RedirectURLs{
ReturnURL: "http://...",
CancelURL: "http://...",
},
}
paymentResponse, err := client.CreatePayment(p)
if err == nil {
fmt.Println("DEBUG: CreatedPaymentID=" + paymentResponse.Payment.ID)
} else {
fmt.Println("ERROR: " + err.Error())
os.Exit(1)
}
fmt.Println("OK")
}

View File

@ -12,7 +12,14 @@ type ListPaymentsResp struct {
Payments []Payment `json:"payments"`
}
// CreatePaymentResp returned by CreatePayment
type CreatePaymentResp struct {
*Payment
Links []Links `json:"links"`
}
// CreateDirectPaypalPayment sends request with payment
// CreatePayment is more common function for any kind of payment
func (c *Client) CreateDirectPaypalPayment(amount Amount, redirectURI string, cancelURI string, description string) (*PaymentResponse, error) {
buf := bytes.NewBuffer([]byte("{\"intent\":\"sale\",\"payer\":{\"payment_method\":\"paypal\"}," +
"\"transactions\":[{\"amount\":{\"total\":\"" + amount.Total +
@ -39,6 +46,23 @@ func (c *Client) CreateDirectPaypalPayment(amount Amount, redirectURI string, ca
return &p, err
}
// CreatePayment creates a payment in Paypal
func (c *Client) CreatePayment(p Payment) (*CreatePaymentResp, error) {
req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/payment"), p)
if err != nil {
return &CreatePaymentResp{}, err
}
response := &CreatePaymentResp{}
err = c.SendWithAuth(req, response)
if err != nil {
return response, err
}
return response, nil
}
// ExecuteApprovedPayment executes approved payment
func (c *Client) ExecuteApprovedPayment(paymentID string, payerID string) (*ExecuteResponse, error) {
buf := bytes.NewBuffer([]byte("{\"payer_id\":\"" + payerID + "\"}"))

View File

@ -25,6 +25,33 @@ type (
Token *TokenResponse
}
// Authorization maps to the authorization object
Authorization struct {
Amount *Amount `json:"amount,omitempty"`
CreateTime *time.Time `json:"create_time,omitempty"`
UpdateTime *time.Time `json:"update_time,omitempty"`
State string `json:"state,omitempty"`
ParentPayment string `json:"parent_payment,omitempty"`
ID string `json:"id,omitempty"`
ValidUntil *time.Time `json:"valid_until,omitempty"`
Links []Links `json:"links,omitempty"`
ClearingTime string `json:"clearing_time,omitempty"`
ProtectionEligibility string `json:"protection_eligibility,omitempty"`
ProtectionEligibilityType string `json:"protection_eligibility_type,omitempty"`
}
// Capture maps to the capture object
Capture struct {
Amount *Amount `json:"amount,omitempty"`
IsFinalCapture bool `json:"is_final_capture"`
CreateTime *time.Time `json:"create_time,omitempty"`
UpdateTime *time.Time `json:"update_time,omitempty"`
State string `json:"state,omitempty"`
ParentPayment string `json:"parent_payment,omitempty"`
ID string `json:"id,omitempty"`
Links []Links `json:"links,omitempty"`
}
// Address maps to address object
Address struct {
Line1 string `json:"line1"`
@ -135,6 +162,14 @@ type (
CancelURL string `json:"cancel_url,omitempty"`
}
// Links maps to links object
Links struct {
Href string `json:"href"`
Rel string `json:"rel"`
Method string `json:"method"`
Enctype string `json:"enctype"`
}
// Payment maps to payment object
Payment struct {
Intent string `json:"intent"`