diff --git a/README.md b/README.md index 3f8b73e..632d156 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,9 @@ * POST /v1/identity/openidconnect/tokenservice * GET /v1/identity/openidconnect/userinfo/?schema=**SCHEMA** * POST /v1/payments/payouts + * GET /v1/payments/payouts/**ID** + * GET /v1/payments/payouts-item/**ID** + * POST /v1/payments/payouts-item/**ID**/cancel * GET /v1/payment-experience/web-profiles * POST /v1/payment-experience/web-profiles * GET /v1/payment-experience/web-profiles/**ID** @@ -228,6 +231,24 @@ payout := paypalsdk.Payout{ payoutResp, err := c.CreateSinglePayout(payout) ``` +### Get payout by ID + +```go +payout, err := c.GetPayout("PayoutBatchID") +``` + +### Get payout item by ID + +```go +payoutItem, err := c.GetPayoutItem("PayoutItemID") +``` + +### Cancel unclaimed payout item by ID + +```go +payoutItem, err := c.CancelPayoutItem("PayoutItemID") +``` + ### Create web experience profile ```go diff --git a/payout.go b/payout.go index 7e51c59..a0420e1 100644 --- a/payout.go +++ b/payout.go @@ -1,6 +1,8 @@ package paypalsdk -import "fmt" +import ( + "fmt" +) // CreateSinglePayout submits a payout with an asynchronous API call, which immediately returns the results of a PayPal payment. // For email payout set RecipientType: "EMAIL" and receiver email into Receiver @@ -20,3 +22,63 @@ func (c *Client) CreateSinglePayout(p Payout) (*PayoutResponse, error) { return response, nil } + +// GetPayout shows the latest status of a batch payout along with the transaction status and other data for individual items. +// Also, returns IDs for the individual payout items. You can use these item IDs in other calls. +// Endpoint: GET /v1/payments/payouts/ID +func (c *Client) GetPayout(payoutBatchID string) (*PayoutResponse, error) { + req, err := c.NewRequest("GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/payouts/"+payoutBatchID), nil) + + if err != nil { + return &PayoutResponse{}, err + } + + response := &PayoutResponse{} + + err = c.SendWithAuth(req, response) + if err != nil { + return response, err + } + + return response, nil +} + +// GetPayoutItem shows the details for a payout item. +// Use this call to review the current status of a previously unclaimed, or pending, payout item. +// Endpoint: GET /v1/payments/payouts-item/ID +func (c *Client) GetPayoutItem(payoutItemID string) (*PayoutItemResponse, error) { + req, err := c.NewRequest("GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/payouts-item/"+payoutItemID), nil) + + if err != nil { + return &PayoutItemResponse{}, err + } + + response := &PayoutItemResponse{} + + err = c.SendWithAuth(req, response) + if err != nil { + return response, err + } + + return response, nil +} + +// CancelPayoutItem cancels an unclaimed Payout Item. If no one claims the unclaimed item within 30 days, +// the funds are automatically returned to the sender. Use this call to cancel the unclaimed item before the automatic 30-day refund. +// Endpoint: POST /v1/payments/payouts-item/ID/cancel +func (c *Client) CancelPayoutItem(payoutItemID string) (*PayoutItemResponse, error) { + req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/payouts-item/"+payoutItemID+"/cancel"), nil) + + if err != nil { + return &PayoutItemResponse{}, err + } + + response := &PayoutItemResponse{} + + err = c.SendWithAuth(req, response) + if err != nil { + return response, err + } + + return response, nil +} diff --git a/types.go b/types.go index f63cfcd..314e09d 100644 --- a/types.go +++ b/types.go @@ -389,6 +389,7 @@ type ( PayoutItem *PayoutItem `json:"payout_item"` TimeProcessed *time.Time `json:"time_processed,omitempty"` Links []Link `json:"links"` + Error ErrorResponse `json:"errors,omitempty"` } // PayoutResponse struct diff --git a/unit_test.go b/unit_test.go index 779bcda..327a7e6 100644 --- a/unit_test.go +++ b/unit_test.go @@ -144,6 +144,148 @@ func TestTypeErrorResponseTwo(t *testing.T) { } } +func TestTypePayoutResponse(t *testing.T) { + response := `{ + "batch_header":{ + "payout_batch_id":"G4E6WJE6Y4853", + "batch_status":"SUCCESS", + "time_created":"2017-11-01T23:08:25Z", + "time_completed":"2017-11-01T23:08:46Z", + "sender_batch_header":{ + "sender_batch_id":"2017110109", + "email_subject":"Payment" + }, + "amount":{ + "currency":"USD", + "value":"6.37" + }, + "fees":{ + "currency":"USD", + "value":"0.25" + } + }, + "items":[ + { + "payout_item_id":"9T35G83YA546X", + "transaction_id":"4T328230B1D337285", + "transaction_status":"UNCLAIMED", + "payout_item_fee":{ + "currency":"USD", + "value":"0.25" + }, + "payout_batch_id":"G4E6WJE6Y4853", + "payout_item":{ + "recipient_type":"EMAIL", + "amount":{ + "currency":"USD", + "value":"6.37" + }, + "note":"Optional note", + "receiver":"ppuser@example.com", + "sender_item_id":"1" + }, + "time_processed":"2017-11-01T23:08:43Z", + "errors":{ + "name":"RECEIVER_UNREGISTERED", + "message":"Receiver is unregistered", + "information_link":"https://developer.paypal.com/docs/api/payments.payouts-batch/#errors", + "details":[] + }, + "links":[ + { + "href":"https://api.sandbox.paypal.com/v1/payments/payouts-item/9T35G83YA546X", + "rel":"item", + "method":"GET", + "encType":"application/json" + } + ] + } + ], + "links":[ + { + "href":"https://api.sandbox.paypal.com/v1/payments/payouts/G4E6WJE6Y4853?page_size=1000&page=1", + "rel":"self", + "method":"GET", + "encType":"application/json" + } + ] + }` + + pr := &PayoutResponse{} + err := json.Unmarshal([]byte(response), pr) + if err != nil { + t.Errorf("PayoutResponse Unmarshal failed") + } + + if pr.BatchHeader.BatchStatus != "SUCCESS" || + pr.BatchHeader.PayoutBatchID != "G4E6WJE6Y4853" || + len(pr.Items) != 1 || + pr.Items[0].PayoutItemID != "9T35G83YA546X" || + pr.Items[0].TransactionID != "4T328230B1D337285" || + pr.Items[0].TransactionStatus != "UNCLAIMED" || + pr.Items[0].Error.Name != "RECEIVER_UNREGISTERED" { + t.Errorf("PayoutResponse decoded result is incorrect, Given: %v", pr) + } +} + +func TestTypePayoutItemResponse(t *testing.T) { + response := `{ + "payout_item_id":"9T35G83YA546X", + "transaction_id":"4T328230B1D337285", + "transaction_status":"UNCLAIMED", + "payout_item_fee":{ + "currency":"USD", + "value":"0.25" + }, + "payout_batch_id":"G4E6WJE6Y4853", + "payout_item":{ + "recipient_type":"EMAIL", + "amount":{ + "currency":"USD", + "value":"6.37" + }, + "note":"Optional note", + "receiver":"ppuser@example.com", + "sender_item_id":"1" + }, + "time_processed":"2017-11-01T23:08:43Z", + "errors":{ + "name":"RECEIVER_UNREGISTERED", + "message":"Receiver is unregistered", + "information_link":"https://developer.paypal.com/docs/api/payments.payouts-batch/#errors", + "details":[] + }, + "links":[ + { + "href":"https://api.sandbox.paypal.com/v1/payments/payouts-item/3YA546X9T35G8", + "rel":"self", + "method":"GET", + "encType":"application/json" + }, + { + "href":"https://api.sandbox.paypal.com/v1/payments/payouts/6Y4853G4E6WJE", + "rel":"batch", + "method":"GET", + "encType":"application/json" + } + ] + }` + + pir := &PayoutItemResponse{} + err := json.Unmarshal([]byte(response), pir) + if err != nil { + t.Errorf("PayoutItemResponse Unmarshal failed") + } + + if pir.PayoutItemID != "9T35G83YA546X" || + pir.PayoutBatchID != "G4E6WJE6Y4853" || + pir.TransactionID != "4T328230B1D337285" || + pir.TransactionStatus != "UNCLAIMED" || + pir.Error.Name != "RECEIVER_UNREGISTERED" { + t.Errorf("PayoutItemResponse decoded result is incorrect, Given: %+v", pir) + } +} + // ServeHTTP implements http.Handler func (ts *webprofileTestServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { ts.t.Log(r.RequestURI)