This commit is contained in:
Aliaksandr Pliutau 2015-12-17 14:50:25 +07:00
parent 7913ad67ae
commit 61cd126fbe
8 changed files with 356 additions and 115 deletions

View File

@ -14,6 +14,10 @@
* GET /v1/payments/sale/**ID** * GET /v1/payments/sale/**ID**
* POST /v1/payments/sale/**ID**/refund * POST /v1/payments/sale/**ID**/refund
* GET /v1/payments/refund/**ID** * GET /v1/payments/refund/**ID**
* GET /v1/payments/orders/**ID**
* POST /v1/payments/orders/**ID**/authorize
* POST /v1/payments/orders/**ID**/capture
* POST /v1/payments/orders/**ID**/do-void
#### Create client #### Create client
@ -23,7 +27,7 @@ import "github.com/logpacker/paypalsdk"
```go ```go
// Create a client instance // Create a client instance
c, err := paypalsdk.NewClient("clietnid", "secret", paypalsdk.APIBaseSandBox) c, err := paypalsdk.NewClient("clientID", "secretID", paypalsdk.APIBaseSandBox)
c.SetLogFile("/tpm/paypal-debug.log") // Set log file if necessary c.SetLogFile("/tpm/paypal-debug.log") // Set log file if necessary
``` ```
@ -136,20 +140,44 @@ auth, err := c.ReauthorizeAuthorization("AUTH-1", &paypalsdk.Amount{Total: "200"
#### Get Sale by ID #### Get Sale by ID
```go ```go
sale, err := c.GetSale("1") sale, err := c.GetSale("SALE-1")
``` ```
#### Refund Sale by ID #### Refund Sale by ID
```go ```go
// Full // Full
refund, err := c.RefundSale("1", nil) refund, err := c.RefundSale("SALE-1", nil)
// Partial // Partial
refund, err := c.RefundSale("1", &paypalsdk.Amount{Total: "100", Currency: "USD"}) refund, err := c.RefundSale("SALE-1", &paypalsdk.Amount{Total: "100", Currency: "USD"})
``` ```
#### Get Refund by ID #### Get Refund by ID
```go ```go
refund, err := c.GetRefund("1") refund, err := c.GetRefund("ORDER-1")
```
#### Get Order by ID
```go
order, err := c.GetOrder("ORDER-1")
```
#### Authorize Order
```go
auth, err := c.AuthorizeOrder("ORDER-1", &paypalsdk.Amount{Total: "100", Currency: "USD"})
```
#### Capture Order
```go
capture, err := c.CaptureOrder("ORDER-1", &paypalsdk.Amount{Total: "100", Currency: "USD"}, true, nil)
```
#### Void Order
```go
order, err := c.VoidOrder("ORDER-1")
``` ```

View File

@ -1,6 +1,7 @@
package paypalsdk package paypalsdk
import ( import (
"fmt"
"testing" "testing"
) )
@ -17,6 +18,8 @@ func TestGetAuthorization(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("Error must be returned for invalid Auth ID") t.Errorf("Error must be returned for invalid Auth ID")
} else {
fmt.Println(err.Error())
} }
} }
@ -28,6 +31,8 @@ func TestCaptureAuthorization(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("Error must be returned for invalid Auth ID") t.Errorf("Error must be returned for invalid Auth ID")
} else {
fmt.Println(err.Error())
} }
} }
@ -39,6 +44,8 @@ func TestVoidAuthorization(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("Error must be returned for invalid Auth ID") t.Errorf("Error must be returned for invalid Auth ID")
} else {
fmt.Println(err.Error())
} }
} }
@ -50,5 +57,7 @@ func TestReauthorizeAuthorization(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("Error must be returned for invalid Auth ID") t.Errorf("Error must be returned for invalid Auth ID")
} else {
fmt.Println(err.Error())
} }
} }

View File

@ -91,4 +91,36 @@ func main() {
fmt.Println("ERROR: " + err.Error()) fmt.Println("ERROR: " + err.Error())
} }
fmt.Println("OK") fmt.Println("OK")
order, err := client.GetOrder("1")
if err == nil {
fmt.Println("DEBUG: OrderID=" + order.ID)
} else {
fmt.Println("ERROR: " + err.Error())
}
fmt.Println("OK")
auth, err := client.AuthorizeOrder("1", &paypalsdk.Amount{Total: "100", Currency: "USD"})
if err == nil {
fmt.Println("DEBUG: AuthID=" + auth.ID)
} else {
fmt.Println("ERROR: " + err.Error())
}
fmt.Println("OK")
capture, err := client.CaptureOrder("1", &paypalsdk.Amount{Total: "100", Currency: "USD"}, true, nil)
if err == nil {
fmt.Println("DEBUG: CaptureID=" + capture.ID)
} else {
fmt.Println("ERROR: " + err.Error())
}
fmt.Println("OK")
order, err = client.VoidOrder("1")
if err == nil {
fmt.Println("DEBUG: OrderID=" + order.ID)
} else {
fmt.Println("ERROR: " + err.Error())
}
fmt.Println("OK")
} }

81
order.go Normal file
View File

@ -0,0 +1,81 @@
package paypalsdk
import "fmt"
// GetOrder retreives order
func (c *Client) GetOrder(orderID string) (*Order, error) {
order := &Order{}
req, err := c.NewRequest("GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/orders/"+orderID), nil)
if err != nil {
return order, err
}
err = c.SendWithAuth(req, order)
if err != nil {
return order, err
}
return order, nil
}
// AuthorizeOrder POST /v1/payments/orders/<Order-Id>/authorize
func (c *Client) AuthorizeOrder(orderID string, amount *Amount) (*Authorization, error) {
type authRequest struct {
Amount *Amount `json:"amount"`
}
auth := &Authorization{}
req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/orders/"+orderID+"/authorize"), authRequest{Amount: amount})
if err != nil {
return auth, err
}
err = c.SendWithAuth(req, auth)
if err != nil {
return auth, err
}
return auth, nil
}
// CaptureOrder POST /v1/payments/orders/<Order-Id>/capture
func (c *Client) CaptureOrder(orderID string, amount *Amount, isFinalCapture bool, currency *Currency) (*Capture, error) {
type captureRequest struct {
Amount *Amount `json:"amount"`
IsFinalCapture bool `json:"is_final_capture"`
Currency *Currency `json:"transaction_fee"`
}
capture := &Capture{}
req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/orders/"+orderID+"/capture"), captureRequest{Amount: amount, IsFinalCapture: isFinalCapture, Currency: currency})
if err != nil {
return capture, err
}
err = c.SendWithAuth(req, capture)
if err != nil {
return capture, err
}
return capture, nil
}
// VoidOrder POST /v1/payments/orders/<Order-Id>/do-void
func (c *Client) VoidOrder(orderID string) (*Order, error) {
order := &Order{}
req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/orders/"+orderID+"/do-void"), nil)
if err != nil {
return order, err
}
err = c.SendWithAuth(req, order)
if err != nil {
return order, err
}
return order, nil
}

55
order_test.go Normal file
View File

@ -0,0 +1,55 @@
package paypalsdk
import (
"fmt"
"testing"
)
func TestGetOrder(t *testing.T) {
c, _ := NewClient("clid", "secret", APIBaseSandBox)
c.GetAccessToken()
_, err := c.GetOrder("1")
if err == nil {
t.Errorf("GetOrder must be failed")
} else {
fmt.Println(err.Error())
}
}
func TestAuthorizeOrder(t *testing.T) {
c, _ := NewClient("clid", "secret", APIBaseSandBox)
c.GetAccessToken()
_, err := c.AuthorizeOrder("1", &Amount{Total: "100", Currency: "USD"})
if err == nil {
t.Errorf("AuthorizeOrder must be failed")
} else {
fmt.Println(err.Error())
}
}
func TestCaptureOrder(t *testing.T) {
c, _ := NewClient("clid", "secret", APIBaseSandBox)
c.GetAccessToken()
_, err := c.CaptureOrder("1", &Amount{Total: "100", Currency: "USD"}, true, nil)
if err == nil {
t.Errorf("CaptureOrder must be failed")
} else {
fmt.Println(err.Error())
}
}
func TestVoidOrder(t *testing.T) {
c, _ := NewClient("clid", "secret", APIBaseSandBox)
c.GetAccessToken()
_, err := c.VoidOrder("1")
if err == nil {
t.Errorf("VoidOrder must be failed")
} else {
fmt.Println(err.Error())
}
}

View File

@ -1,6 +1,7 @@
package paypalsdk package paypalsdk
import ( import (
"fmt"
"testing" "testing"
) )
@ -19,6 +20,8 @@ func TestCreateDirectPaypalPayment(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("Error must be returned for invalid token") t.Errorf("Error must be returned for invalid token")
} else {
fmt.Println(err.Error())
} }
} }
@ -32,6 +35,8 @@ func TestGetPayment(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("Error must be returned for invalid ID") t.Errorf("Error must be returned for invalid ID")
} else {
fmt.Println(err.Error())
} }
} }
@ -58,5 +63,7 @@ func TestExecuteApprovedPayment(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("Error must be returned for invalid token") t.Errorf("Error must be returned for invalid token")
} else {
fmt.Println(err.Error())
} }
} }

View File

@ -1,6 +1,9 @@
package paypalsdk package paypalsdk
import "testing" import (
"fmt"
"testing"
)
func TestGetSale(t *testing.T) { func TestGetSale(t *testing.T) {
c, _ := NewClient("clid", "secret", APIBaseSandBox) c, _ := NewClient("clid", "secret", APIBaseSandBox)
@ -9,6 +12,8 @@ func TestGetSale(t *testing.T) {
_, err := c.GetSale("1") _, err := c.GetSale("1")
if err == nil { if err == nil {
t.Errorf("GetSale must be failed") t.Errorf("GetSale must be failed")
} else {
fmt.Println(err.Error())
} }
} }
@ -19,11 +24,15 @@ func TestRefundSale(t *testing.T) {
_, err := c.RefundSale("1", nil) _, err := c.RefundSale("1", nil)
if err == nil { if err == nil {
t.Errorf("RefundSale must be failed") t.Errorf("RefundSale must be failed")
} else {
fmt.Println(err.Error())
} }
_, err = c.RefundSale("1", &Amount{Total: "100", Currency: "USD"}) _, err = c.RefundSale("1", &Amount{Total: "100", Currency: "USD"})
if err == nil { if err == nil {
t.Errorf("RefundSale must be failed") t.Errorf("RefundSale must be failed")
} else {
fmt.Println(err.Error())
} }
} }
@ -34,5 +43,7 @@ func TestGetRefund(t *testing.T) {
_, err := c.GetRefund("1") _, err := c.GetRefund("1")
if err == nil { if err == nil {
t.Errorf("GetRefund must be failed") t.Errorf("GetRefund must be failed")
} else {
fmt.Println(err.Error())
} }
} }

234
types.go
View File

@ -15,17 +15,24 @@ const (
) )
type ( type (
// Client represents a Paypal REST API Client // Address struct
Client struct { Address struct {
client *http.Client Line1 string `json:"line1"`
ClientID string Line2 string `json:"line2,omitempty"`
Secret string City string `json:"city"`
APIBase string CountryCode string `json:"country_code"`
LogFile string // If user set log file name all requests will be logged there PostalCode string `json:"postal_code,omitempty"`
Token *TokenResponse State string `json:"state,omitempty"`
Phone string `json:"phone,omitempty"`
} }
// Authorization maps to the authorization object // Amount to pay
Amount struct {
Currency string `json:"currency"`
Total string `json:"total"`
}
// Authorization represetns PayPal authorization
Authorization struct { Authorization struct {
Amount *Amount `json:"amount,omitempty"` Amount *Amount `json:"amount,omitempty"`
CreateTime *time.Time `json:"create_time,omitempty"` CreateTime *time.Time `json:"create_time,omitempty"`
@ -40,7 +47,7 @@ type (
ProtectionEligibilityType string `json:"protection_eligibility_type,omitempty"` ProtectionEligibilityType string `json:"protection_eligibility_type,omitempty"`
} }
// Capture maps to the capture object // Capture struct
Capture struct { Capture struct {
Amount *Amount `json:"amount,omitempty"` Amount *Amount `json:"amount,omitempty"`
IsFinalCapture bool `json:"is_final_capture"` IsFinalCapture bool `json:"is_final_capture"`
@ -52,18 +59,17 @@ type (
Links []Links `json:"links,omitempty"` Links []Links `json:"links,omitempty"`
} }
// Address maps to address object // Client represents a Paypal REST API Client
Address struct { Client struct {
Line1 string `json:"line1"` client *http.Client
Line2 string `json:"line2,omitempty"` ClientID string
City string `json:"city"` Secret string
CountryCode string `json:"country_code"` APIBase string
PostalCode string `json:"postal_code,omitempty"` LogFile string // If user set log file name all requests will be logged there
State string `json:"state,omitempty"` Token *TokenResponse
Phone string `json:"phone,omitempty"`
} }
// CreditCard maps to credit_card object // CreditCard struct
CreditCard struct { CreditCard struct {
ID string `json:"id,omitempty"` ID string `json:"id,omitempty"`
PayerID string `json:"payer_id,omitempty"` PayerID string `json:"payer_id,omitempty"`
@ -79,7 +85,7 @@ type (
ValidUntil string `json:"valid_until,omitempty"` ValidUntil string `json:"valid_until,omitempty"`
} }
// CreditCardToken maps to credit_card_token object // CreditCardToken struct
CreditCardToken struct { CreditCardToken struct {
CreditCardID string `json:"credit_card_id"` CreditCardID string `json:"credit_card_id"`
PayerID string `json:"payer_id,omitempty"` PayerID string `json:"payer_id,omitempty"`
@ -88,17 +94,10 @@ type (
ExpireMonth string `json:"expire_month,omitempty"` ExpireMonth string `json:"expire_month,omitempty"`
} }
// FundingInstrument maps to funding_instrument object // Currency https://developer.paypal.com/webapps/developer/docs/api/#currency-object
FundingInstrument struct { Currency struct {
CreditCard *CreditCard `json:"credit_card,omitempty"` Currency string `json:"currency,omitempty"`
CreditCardToken *CreditCardToken `json:"credit_card_token,omitempty"` Value string `json:"value,omitempty"`
}
// TokenResponse maps to the API response for the /oauth2/token endpoint
TokenResponse struct {
RefreshToken string `json:"refresh_token"`
Token string `json:"access_token"`
Type string `json:"token_type"`
} }
// ErrorResponse is used when a response has errors // ErrorResponse is used when a response has errors
@ -117,13 +116,57 @@ type (
Issue string `json:"issue"` Issue string `json:"issue"`
} }
// PaymentResponse structure // ExecuteResponse structure
PaymentResponse struct { ExecuteResponse struct {
ID string `json:"id"` ID string `json:"id"`
Links []PaymentLink `json:"links"` Links []PaymentLink `json:"links"`
State string `json:"state"`
} }
// Payer maps to payer object // FundingInstrument struct
FundingInstrument struct {
CreditCard *CreditCard `json:"credit_card,omitempty"`
CreditCardToken *CreditCardToken `json:"credit_card_token,omitempty"`
}
// Item struct
Item struct {
Quantity int `json:"quantity"`
Name string `json:"name"`
Price string `json:"price"`
Currency string `json:"currency"`
SKU string `json:"sku,omitempty"`
Description string `json:"description,omitempty"`
Tax string `json:"tax,omitempty"`
}
// ItemList struct
ItemList struct {
Items []Item `json:"items,omitempty"`
ShippingAddress *ShippingAddress `json:"shipping_address,omitempty"`
}
// Links struct
Links struct {
Href string `json:"href"`
Rel string `json:"rel"`
Method string `json:"method"`
Enctype string `json:"enctype"`
}
// Order https://developer.paypal.com/webapps/developer/docs/api/#order-object
Order struct {
ID string `json:"id,omitempty"`
CreateTime *time.Time `json:"create_time,omitempty"`
UpdateTime *time.Time `json:"update_time,omitempty"`
State string `json:"state,omitempty"`
Amount *Amount `json:"amount,omitempty"`
PendingReason string `json:"pending_reason,omitempty"`
ParentPayment string `json:"parent_payment,omitempty"`
Links []Links `json:"links,omitempty"`
}
// Payer struct
Payer struct { Payer struct {
PaymentMethod string `json:"payment_method"` PaymentMethod string `json:"payment_method"`
FundingInstruments []FundingInstrument `json:"funding_instruments,omitempty"` FundingInstruments []FundingInstrument `json:"funding_instruments,omitempty"`
@ -131,7 +174,7 @@ type (
Status string `json:"payer_status,omitempty"` Status string `json:"payer_status,omitempty"`
} }
// PayerInfo maps to payer_info object // PayerInfo struct
PayerInfo struct { PayerInfo struct {
Email string `json:"email,omitempty"` Email string `json:"email,omitempty"`
FirstName string `json:"first_name,omitempty"` FirstName string `json:"first_name,omitempty"`
@ -143,34 +186,7 @@ type (
TaxID string `json:"tax_id,omitempty"` TaxID string `json:"tax_id,omitempty"`
} }
// ShippingAddress maps to shipping_address object // Payment struct
ShippingAddress struct {
RecipientName string `json:"recipient_name,omitempty"`
Type string `json:"type,omitempty"`
Line1 string `json:"line1"`
Line2 string `json:"line2,omitempty"`
City string `json:"city"`
CountryCode string `json:"country_code"`
PostalCode string `json:"postal_code,omitempty"`
State string `json:"state,omitempty"`
Phone string `json:"phone,omitempty"`
}
// RedirectURLs maps to redirect_urls object
RedirectURLs struct {
ReturnURL string `json:"return_url,omitempty"`
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 { Payment struct {
Intent string `json:"intent"` Intent string `json:"intent"`
Payer *Payer `json:"payer"` Payer *Payer `json:"payer"`
@ -183,50 +199,33 @@ type (
ExperienceProfileID string `json:"experience_profile_id,omitempty"` ExperienceProfileID string `json:"experience_profile_id,omitempty"`
} }
// Item maps to item object
Item struct {
Quantity int `json:"quantity"`
Name string `json:"name"`
Price string `json:"price"`
Currency string `json:"currency"`
SKU string `json:"sku,omitempty"`
Description string `json:"description,omitempty"`
Tax string `json:"tax,omitempty"`
}
// ItemList maps to item_list object
ItemList struct {
Items []Item `json:"items,omitempty"`
ShippingAddress *ShippingAddress `json:"shipping_address,omitempty"`
}
// Transaction maps to transaction object
Transaction struct {
Amount *Amount `json:"amount"`
Description string `json:"description,omitempty"`
ItemList *ItemList `json:"item_list,omitempty"`
InvoiceNumber string `json:"invoice_number,omitempty"`
Custom string `json:"custom,omitempty"`
SoftDescriptor string `json:"soft_descriptor,omitempty"`
}
// PaymentLink structure // PaymentLink structure
PaymentLink struct { PaymentLink struct {
Href string `json:"href"` Href string `json:"href"`
Rel string `json:"rel"` Rel string `json:"rel"`
} }
// Amount to pay // PaymentResponse structure
Amount struct { PaymentResponse struct {
Currency string `json:"currency"`
Total string `json:"total"`
}
// ExecuteResponse structure
ExecuteResponse struct {
ID string `json:"id"` ID string `json:"id"`
Links []PaymentLink `json:"links"` Links []PaymentLink `json:"links"`
State string `json:"state"` }
// RedirectURLs for redirect_urls
RedirectURLs struct {
ReturnURL string `json:"return_url,omitempty"`
CancelURL string `json:"cancel_url,omitempty"`
}
// Refund will be returned by RefundSale
Refund struct {
ID string `json:"id,omitempty"`
Amount *Amount `json:"amount,omitempty"`
CreateTime *time.Time `json:"create_time,omitempty"`
State string `json:"state,omitempty"`
CaptureID string `json:"capture_id,omitempty"`
ParentPayment string `json:"parent_payment,omitempty"`
UpdateTime *time.Time `json:"update_time,omitempty"`
} }
// Sale will be returned by GetSale // Sale will be returned by GetSale
@ -247,15 +246,34 @@ type (
Links []Links `json:"links,omitempty"` Links []Links `json:"links,omitempty"`
} }
// Refund will be returned by RefundSale // ShippingAddress for shipping_address
Refund struct { ShippingAddress struct {
ID string `json:"id,omitempty"` RecipientName string `json:"recipient_name,omitempty"`
Amount *Amount `json:"amount,omitempty"` Type string `json:"type,omitempty"`
CreateTime *time.Time `json:"create_time,omitempty"` Line1 string `json:"line1"`
Line2 string `json:"line2,omitempty"`
City string `json:"city"`
CountryCode string `json:"country_code"`
PostalCode string `json:"postal_code,omitempty"`
State string `json:"state,omitempty"` State string `json:"state,omitempty"`
CaptureID string `json:"capture_id,omitempty"` Phone string `json:"phone,omitempty"`
ParentPayment string `json:"parent_payment,omitempty"` }
UpdateTime *time.Time `json:"update_time,omitempty"`
// TokenResponse is for API response for the /oauth2/token endpoint
TokenResponse struct {
RefreshToken string `json:"refresh_token"`
Token string `json:"access_token"`
Type string `json:"token_type"`
}
// Transaction is for transaction object
Transaction struct {
Amount *Amount `json:"amount"`
Description string `json:"description,omitempty"`
ItemList *ItemList `json:"item_list,omitempty"`
InvoiceNumber string `json:"invoice_number,omitempty"`
Custom string `json:"custom,omitempty"`
SoftDescriptor string `json:"soft_descriptor,omitempty"`
} }
) )