From fcccd51161321e23428289c9f5715672e99dc717 Mon Sep 17 00:00:00 2001 From: Aliaksandr Pliutau Date: Wed, 25 Nov 2015 17:30:25 +0700 Subject: [PATCH] GetPayment, GetPayments --- README.md | 12 ++++- examples/main.go | 21 ++++++++ payment.go | 52 ++++++++++++++++++- payment_test.go | 30 ++++++++++- types.go | 126 ++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 234 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 55ff8f0..5097fe7 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ amount := Amount{ Total: 15.1111, Currency: "USD", } -paymentResult, err := c.CreateDirectPaypalPayment(amount, "http://example.com/redirect-uri") +paymentResult, err := c.CreateDirectPaypalPayment(amount, "http://example.com/redirect-uri", "http://example.com/cancel-uri", "Description for this payment") // If paymentResult.ID is not empty and paymentResult.Links is also // we can redirect user to approval page (paymentResult.Links[0]). @@ -36,3 +36,13 @@ paymentID := "PAY-17S8410768582940NKEE66EQ" payerID := "7E7MGXCWTTKK2" executeResult, err := c.ExecuteApprovedPayment(paymentID, payerID) ``` + +```go +// Get created payment info +payment, err := c.GetPayment(paymentID) +``` + +```go +// Get all payments slice +payments, err := c.GetPayments() +``` diff --git a/examples/main.go b/examples/main.go index c17dff9..6dd9c78 100644 --- a/examples/main.go +++ b/examples/main.go @@ -2,6 +2,7 @@ package main import ( "paypalsdk" + "strconv" "fmt" "os" @@ -15,4 +16,24 @@ func main() { fmt.Println("ERROR: " + err.Error()) os.Exit(1) } + + token, err := client.GetAccessToken() + if err == nil { + fmt.Println("DEBUG: AccessToken=" + token.Token) + } else { + fmt.Println("ERROR: " + err.Error()) + os.Exit(1) + } + + payment, err := client.GetPayment("PAY-TEST-123") + fmt.Println("DEBUG: PaymentID=" + payment.ID) + + payments, err := client.GetPayments() + if err == nil { + fmt.Println("DEBUG: PaymentsCount=" + strconv.Itoa(len(payments))) + } else { + fmt.Println("ERROR: " + err.Error()) + os.Exit(1) + } + fmt.Println("OK") } diff --git a/payment.go b/payment.go index 9d2ef89..81aeb30 100644 --- a/payment.go +++ b/payment.go @@ -5,13 +5,17 @@ import ( "errors" "fmt" "net/http" - "strconv" ) +// ListPaymentsResp slice of payments +type ListPaymentsResp struct { + Payments []Payment `json:"payments"` +} + // CreateDirectPaypalPayment sends request with 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\":\"" + strconv.FormatFloat(amount.Total, 'f', 2, 64) + + "\"transactions\":[{\"amount\":{\"total\":\"" + amount.Total + "\",\"currency\":\"" + amount.Currency + "\"},\"description\":\"" + description + "\"}],\"redirect_urls\":{\"return_url\":\"" + redirectURI + "\",\"cancel_url\":\"" + cancelURI + "\"}}")) req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/payment"), buf) @@ -24,6 +28,9 @@ func (c *Client) CreateDirectPaypalPayment(amount Amount, redirectURI string, ca p := PaymentResponse{} err = c.SendWithAuth(req, &p) + if err != nil { + return &p, err + } if p.ID == "" { return &p, errors.New("Unable to create payment with this access token") @@ -45,6 +52,9 @@ func (c *Client) ExecuteApprovedPayment(paymentID string, payerID string) (*Exec e := ExecuteResponse{} err = c.SendWithAuth(req, &e) + if err != nil { + return &e, err + } if e.ID == "" { return &e, errors.New("Unable to execute payment with paymentID=" + paymentID) @@ -52,3 +62,41 @@ func (c *Client) ExecuteApprovedPayment(paymentID string, payerID string) (*Exec return &e, err } + +// GetPayment gets a payment from PayPal +func (c *Client) GetPayment(paymentID string) (*Payment, error) { + p := Payment{} + + req, err := http.NewRequest("GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/payment/"+paymentID), nil) + if err != nil { + return &p, err + } + + err = c.SendWithAuth(req, &p) + if err != nil { + return &p, err + } + + if p.ID == "" { + return &p, errors.New("Unable to get payment with paymentID=" + paymentID) + } + + return &p, nil +} + +// GetPayments retrieve payments resources from Paypal +func (c *Client) GetPayments() ([]Payment, error) { + var p ListPaymentsResp + + req, err := http.NewRequest("GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/payment/"), nil) + if err != nil { + return p.Payments, err + } + + err = c.SendWithAuth(req, &p) + if err != nil { + return p.Payments, err + } + + return p.Payments, nil +} diff --git a/payment_test.go b/payment_test.go index 4926f17..d1f38e6 100644 --- a/payment_test.go +++ b/payment_test.go @@ -11,17 +11,43 @@ func TestCreateDirectPaypalPayment(t *testing.T) { } amount := Amount{ - Total: 15.1111, + Total: "15.1111", Currency: "USD", } - _, err := c.CreateDirectPaypalPayment(amount, "http://example.com", "http://example.com") + _, err := c.CreateDirectPaypalPayment(amount, "http://example.com", "http://example.com", "test payment") if err == nil { t.Errorf("Error must be returned for invalid token") } } +func TestGetPayment(t *testing.T) { + c, _ := NewClient("clid", "secret", APIBaseSandBox) + c.Token = &TokenResponse{ + Token: "invalidtoken", + } + + _, err := c.GetPayment("PAY-TEST-123") + + if err == nil { + t.Errorf("Error must be returned for invalid ID") + } +} + +func TestGetPayments(t *testing.T) { + c, _ := NewClient("clid", "secret", APIBaseSandBox) + c.Token = &TokenResponse{ + Token: "invalidtoken", + } + + payments, _ := c.GetPayments() + + if len(payments) != 0 { + t.Errorf("0 payments must be returned for unautgorized request") + } +} + func TestExecuteApprovedPayment(t *testing.T) { c, _ := NewClient("clid", "secret", APIBaseSandBox) c.Token = &TokenResponse{ diff --git a/types.go b/types.go index 59d4079..a32eae9 100644 --- a/types.go +++ b/types.go @@ -3,6 +3,7 @@ package paypalsdk import ( "fmt" "net/http" + "time" ) const ( @@ -24,6 +25,48 @@ type ( Token *TokenResponse } + // Address maps to address object + Address struct { + 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"` + } + + // CreditCard maps to credit_card object + CreditCard struct { + ID string `json:"id,omitempty"` + PayerID string `json:"payer_id,omitempty"` + Number string `json:"number"` + Type string `json:"type"` + ExpireMonth string `json:"expire_month"` + ExpireYear string `json:"expire_year"` + CVV2 string `json:"cvv2,omitempty"` + FirstName string `json:"first_name,omitempty"` + LastName string `json:"last_name,omitempty"` + BillingAddress *Address `json:"billing_address,omitempty"` + State string `json:"state,omitempty"` + ValidUntil string `json:"valid_until,omitempty"` + } + + // CreditCardToken maps to credit_card_token object + CreditCardToken struct { + CreditCardID string `json:"credit_card_id"` + PayerID string `json:"payer_id,omitempty"` + Last4 string `json:"last4,omitempty"` + ExpireYear string `json:"expire_year,omitempty"` + ExpireMonth string `json:"expire_month,omitempty"` + } + + // FundingInstrument maps to funding_instrument object + FundingInstrument struct { + CreditCard *CreditCard `json:"credit_card,omitempty"` + CreditCardToken *CreditCardToken `json:"credit_card_token,omitempty"` + } + // TokenResponse maps to the API response for the /oauth2/token endpoint TokenResponse struct { RefreshToken string `json:"refresh_token"` @@ -53,6 +96,85 @@ type ( Links []PaymentLink `json:"links"` } + // Payer maps to payer object + Payer struct { + PaymentMethod string `json:"payment_method"` + FundingInstruments []FundingInstrument `json:"funding_instruments,omitempty"` + PayerInfo *PayerInfo `json:"payer_info,omitempty"` + Status string `json:"payer_status,omitempty"` + } + + // PayerInfo maps to payer_info object + PayerInfo struct { + Email string `json:"email,omitempty"` + FirstName string `json:"first_name,omitempty"` + LastName string `json:"last_name,omitempty"` + PayerID string `json:"payer_id,omitempty"` + Phone string `json:"phone,omitempty"` + ShippingAddress *ShippingAddress `json:"shipping_address,omitempty"` + TaxIDType string `json:"tax_id_type,omitempty"` + TaxID string `json:"tax_id,omitempty"` + } + + // ShippingAddress maps to shipping_address object + 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"` + } + + // Payment maps to payment object + Payment struct { + Intent string `json:"intent"` + Payer *Payer `json:"payer"` + Transactions []Transaction `json:"transactions"` + RedirectURLs *RedirectURLs `json:"redirect_urls,omitempty"` + ID string `json:"id,omitempty"` + CreateTime *time.Time `json:"create_time,omitempty"` + State string `json:"state,omitempty"` + UpdateTime *time.Time `json:"update_time,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 struct { Href string `json:"href"` @@ -61,8 +183,8 @@ type ( // Amount to pay Amount struct { - Currency string - Total float64 + Currency string `json:"currency"` + Total string `json:"total"` } // ExecuteResponse structure