diff --git a/.travis.yml b/.travis.yml index 10eefc9..efcc81c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ language: go go: - - 1.11 - - 1.12 + - 1.13 + - 1.14 + - 1.15 install: - export PATH=$PATH:$HOME/gopath/bin script: diff --git a/README.md b/README.md index d817fdc..6e074f1 100644 --- a/README.md +++ b/README.md @@ -82,14 +82,14 @@ It is possible that some endpoints are missing in this SDK Client, but you can u ```go // If using Go Modules -// import "github.com/plutov/paypal/v3" +// import "github.com/plutov/paypal/v4" import "github.com/plutov/paypal" // Create a client instance c, err := paypal.NewClient("clientID", "secretID", paypal.APIBaseSandBox) c.SetLog(os.Stdout) // Set log to terminal stdout -accessToken, err := c.GetAccessToken() +accessToken, err := c.GetAccessToken(context.Background()) ``` ### How to Contribute diff --git a/authorization.go b/authorization.go index 5fc4237..b2481d2 100644 --- a/authorization.go +++ b/authorization.go @@ -2,15 +2,16 @@ package paypal import ( "bytes" + "context" "fmt" "net/http" ) // GetAuthorization returns an authorization by ID // Endpoint: GET /v2/payments/authorizations/ID -func (c *Client) GetAuthorization(authID string) (*Authorization, error) { +func (c *Client) GetAuthorization(ctx context.Context, authID string) (*Authorization, error) { buf := bytes.NewBuffer([]byte("")) - req, err := http.NewRequest("GET", fmt.Sprintf("%s%s%s", c.APIBase, "/v2/payments/authorizations/", authID), buf) + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s%s%s", c.APIBase, "/v2/payments/authorizations/", authID), buf) auth := &Authorization{} if err != nil { @@ -24,19 +25,19 @@ func (c *Client) GetAuthorization(authID string) (*Authorization, error) { // CaptureAuthorization captures and process an existing authorization. // To use this method, the original payment must have Intent set to "authorize" // Endpoint: POST /v2/payments/authorizations/ID/capture -func (c *Client) CaptureAuthorization(authID string, paymentCaptureRequest *PaymentCaptureRequest) (*PaymentCaptureResponse, error) { - return c.CaptureAuthorizationWithPaypalRequestId(authID, paymentCaptureRequest, "") +func (c *Client) CaptureAuthorization(ctx context.Context, authID string, paymentCaptureRequest *PaymentCaptureRequest) (*PaymentCaptureResponse, error) { + return c.CaptureAuthorizationWithPaypalRequestId(ctx, authID, paymentCaptureRequest, "") } // CaptureAuthorization captures and process an existing authorization with idempotency. // To use this method, the original payment must have Intent set to "authorize" // Endpoint: POST /v2/payments/authorizations/ID/capture -func (c *Client) CaptureAuthorizationWithPaypalRequestId( +func (c *Client) CaptureAuthorizationWithPaypalRequestId(ctx context.Context, authID string, paymentCaptureRequest *PaymentCaptureRequest, requestID string, ) (*PaymentCaptureResponse, error) { - req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/authorizations/"+authID+"/capture"), paymentCaptureRequest) + req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/authorizations/"+authID+"/capture"), paymentCaptureRequest) paymentCaptureResponse := &PaymentCaptureResponse{} if err != nil { @@ -53,9 +54,9 @@ func (c *Client) CaptureAuthorizationWithPaypalRequestId( // VoidAuthorization voids a previously authorized payment // Endpoint: POST /v2/payments/authorizations/ID/void -func (c *Client) VoidAuthorization(authID string) (*Authorization, error) { +func (c *Client) VoidAuthorization(ctx context.Context, authID string) (*Authorization, error) { buf := bytes.NewBuffer([]byte("")) - req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/authorizations/"+authID+"/void"), buf) + req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/authorizations/"+authID+"/void"), buf) auth := &Authorization{} if err != nil { @@ -69,9 +70,9 @@ func (c *Client) VoidAuthorization(authID string) (*Authorization, error) { // ReauthorizeAuthorization reauthorize a Paypal account payment. // PayPal recommends to reauthorize payment after ~3 days // Endpoint: POST /v2/payments/authorizations/ID/reauthorize -func (c *Client) ReauthorizeAuthorization(authID string, a *Amount) (*Authorization, error) { +func (c *Client) ReauthorizeAuthorization(ctx context.Context, 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, "/v2/payments/authorizations/"+authID+"/reauthorize"), buf) + req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/authorizations/"+authID+"/reauthorize"), buf) auth := &Authorization{} if err != nil { diff --git a/billing.go b/billing.go index b0f63f2..9e5de73 100644 --- a/billing.go +++ b/billing.go @@ -1,6 +1,7 @@ package paypal import ( + "context" "errors" "fmt" "net/http" @@ -8,8 +9,8 @@ import ( ) type ( - // CreateBillingResp struct - CreateBillingResp struct { + // CreateBillingResponse struct + CreateBillingResponse struct { ID string `json:"id,omitempty"` State string `json:"state,omitempty"` PaymentDefinitions []PaymentDefinition `json:"payment_definitions,omitempty"` @@ -19,33 +20,42 @@ type ( Links []Link `json:"links,omitempty"` } - // CreateAgreementResp struct - CreateAgreementResp struct { + // CreateBillingResp deprecated, use CreateBillingResponse instead. + CreateBillingResp = CreateBillingResponse + + // CreateAgreementResponse struct + CreateAgreementResponse struct { Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` - Plan BillingPlan `json:"plan,omitempty"` + Plan BillingPlan `json:"plan,omitempty"` Links []Link `json:"links,omitempty"` StartTime time.Time `json:"start_time,omitempty"` } + // CreateAgreementResp is deprecated, use CreateAgreementResponse instead. + CreateAgreementResp = CreateAgreementResponse + // BillingPlanListParams struct BillingPlanListParams struct { ListParams Status string `json:"status,omitempty"` //Allowed values: CREATED, ACTIVE, INACTIVE, ALL. } - //BillingPlanListResp struct - BillingPlanListResp struct { + //BillingPlanListResponse struct + BillingPlanListResponse struct { SharedListResponse Plans []BillingPlan `json:"plans,omitempty"` } + + // BillingPlanListResp is deprecated, use BillingPlanListResponse instead. + BillingPlanListResp = BillingPlanListResponse ) // CreateBillingPlan creates a billing plan in Paypal // Endpoint: POST /v1/payments/billing-plans -func (c *Client) CreateBillingPlan(plan BillingPlan) (*CreateBillingResp, error) { - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-plans"), plan) - response := &CreateBillingResp{} +func (c *Client) CreateBillingPlan(ctx context.Context, plan BillingPlan) (*CreateBillingResponse, error) { + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-plans"), plan) + response := &CreateBillingResponse{} if err != nil { return response, err } @@ -55,7 +65,7 @@ func (c *Client) CreateBillingPlan(plan BillingPlan) (*CreateBillingResp, error) // UpdateBillingPlan updates values inside a billing plan // Endpoint: PATCH /v1/payments/billing-plans -func (c *Client) UpdateBillingPlan(planId string, pathValues map[string]map[string]interface{}) error { +func (c *Client) UpdateBillingPlan(ctx context.Context, planId string, pathValues map[string]map[string]interface{}) error { patchData := []Patch{} for path, data := range pathValues { patchData = append(patchData, Patch{ @@ -64,8 +74,8 @@ func (c *Client) UpdateBillingPlan(planId string, pathValues map[string]map[stri Value: data, }) } - - req, err := c.NewRequest(http.MethodPatch, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/payments/billing-plans/", planId), patchData) + + req, err := c.NewRequest(ctx, http.MethodPatch, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/payments/billing-plans/", planId), patchData) if err != nil { return err } @@ -76,22 +86,22 @@ func (c *Client) UpdateBillingPlan(planId string, pathValues map[string]map[stri // ActivatePlan activates a billing plan // By default, a new plan is not activated // Endpoint: PATCH /v1/payments/billing-plans/ -func (c *Client) ActivatePlan(planID string) error { - return c.UpdateBillingPlan(planID, map[string]map[string]interface{}{ +func (c *Client) ActivatePlan(ctx context.Context, planID string) error { + return c.UpdateBillingPlan(ctx, planID, map[string]map[string]interface{}{ "/": {"state": BillingPlanStatusActive}, }) } // CreateBillingAgreement creates an agreement for specified plan // Endpoint: POST /v1/payments/billing-agreements -func (c *Client) CreateBillingAgreement(a BillingAgreement) (*CreateAgreementResp, error) { +func (c *Client) CreateBillingAgreement(ctx context.Context, a BillingAgreement) (*CreateAgreementResponse, error) { // PayPal needs only ID, so we will remove all fields except Plan ID a.Plan = BillingPlan{ ID: a.Plan.ID, } - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-agreements"), a) - response := &CreateAgreementResp{} + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-agreements"), a) + response := &CreateAgreementResponse{} if err != nil { return response, err } @@ -101,8 +111,8 @@ func (c *Client) CreateBillingAgreement(a BillingAgreement) (*CreateAgreementRes // ExecuteApprovedAgreement - Use this call to execute (complete) a PayPal agreement that has been approved by the payer. // Endpoint: POST /v1/payments/billing-agreements/token/agreement-execute -func (c *Client) ExecuteApprovedAgreement(token string) (*ExecuteAgreementResponse, error) { - req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/payments/billing-agreements/%s/agreement-execute", c.APIBase, token), nil) +func (c *Client) ExecuteApprovedAgreement(ctx context.Context, token string) (*ExecuteAgreementResponse, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("%s/v1/payments/billing-agreements/%s/agreement-execute", c.APIBase, token), nil) response := &ExecuteAgreementResponse{} if err != nil { @@ -125,9 +135,9 @@ func (c *Client) ExecuteApprovedAgreement(token string) (*ExecuteAgreementRespon // ListBillingPlans lists billing-plans // Endpoint: GET /v1/payments/billing-plans -func (c *Client) ListBillingPlans(bplp BillingPlanListParams) (*BillingPlanListResp, error) { - req, err := c.NewRequest("GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-plans"), nil) - response := &BillingPlanListResp{} +func (c *Client) ListBillingPlans(ctx context.Context, bplp BillingPlanListParams) (*BillingPlanListResponse, error) { + req, err := c.NewRequest(ctx, "GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-plans"), nil) + response := &BillingPlanListResponse{} if err != nil { return response, err } diff --git a/client.go b/client.go index 6fe98c6..de20087 100644 --- a/client.go +++ b/client.go @@ -2,6 +2,7 @@ package paypal import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -30,9 +31,9 @@ func NewClient(clientID string, secret string, APIBase string) (*Client, error) // GetAccessToken returns struct of TokenResponse // No need to call SetAccessToken to apply new access token for current Client // Endpoint: POST /v1/oauth2/token -func (c *Client) GetAccessToken() (*TokenResponse, error) { +func (c *Client) GetAccessToken(ctx context.Context) (*TokenResponse, error) { buf := bytes.NewBuffer([]byte("grant_type=client_credentials")) - req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/oauth2/token"), buf) + req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/oauth2/token"), buf) if err != nil { return &TokenResponse{}, err } @@ -140,7 +141,7 @@ func (c *Client) SendWithAuth(req *http.Request, v interface{}) error { if c.Token != nil { if !c.tokenExpiresAt.IsZero() && c.tokenExpiresAt.Sub(time.Now()) < RequestNewTokenBeforeExpiresIn { // c.Token will be updated in GetAccessToken call - if _, err := c.GetAccessToken(); err != nil { + if _, err := c.GetAccessToken(req.Context()); err != nil { c.Unlock() return err } @@ -164,7 +165,7 @@ func (c *Client) SendWithBasicAuth(req *http.Request, v interface{}) error { // NewRequest constructs a request // Convert payload to a JSON -func (c *Client) NewRequest(method, url string, payload interface{}) (*http.Request, error) { +func (c *Client) NewRequest(ctx context.Context, method, url string, payload interface{}) (*http.Request, error) { var buf io.Reader if payload != nil { b, err := json.Marshal(&payload) @@ -173,7 +174,7 @@ func (c *Client) NewRequest(method, url string, payload interface{}) (*http.Requ } buf = bytes.NewBuffer(b) } - return http.NewRequest(method, url, buf) + return http.NewRequestWithContext(ctx, method, url, buf) } // log will dump request and response to the log file diff --git a/example_test.go b/example_test.go index e2ac2ff..99eda77 100644 --- a/example_test.go +++ b/example_test.go @@ -1,6 +1,10 @@ package paypal_test -import "github.com/plutov/paypal/v3" +import ( + "context" + + "github.com/plutov/paypal/v4" +) func Example() { // Initialize client @@ -10,13 +14,13 @@ func Example() { } // Retrieve access token - _, err = c.GetAccessToken() + _, err = c.GetAccessToken(context.Background()) if err != nil { panic(err) } } -func ExampleClient_CreateSinglePayout_Venmo() { +func ExampleClient_CreatePayout_Venmo() { // Initialize client c, err := paypal.NewClient("clientID", "secretID", paypal.APIBaseSandBox) if err != nil { @@ -24,7 +28,7 @@ func ExampleClient_CreateSinglePayout_Venmo() { } // Retrieve access token - _, err = c.GetAccessToken() + _, err = c.GetAccessToken(context.Background()) if err != nil { panic(err) } @@ -51,5 +55,5 @@ func ExampleClient_CreateSinglePayout_Venmo() { }, } - c.CreateSinglePayout(payout) + c.CreatePayout(context.Background(), payout) } diff --git a/go.mod b/go.mod index 13768d3..e025f4e 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ -module github.com/plutov/paypal/v3 +module github.com/plutov/paypal/v4 -go 1.12 +go 1.13 require github.com/stretchr/testify v1.6.0 diff --git a/identity.go b/identity.go index 4a7b495..e94a646 100644 --- a/identity.go +++ b/identity.go @@ -1,6 +1,7 @@ package paypal import ( + "context" "fmt" "net/http" "net/url" @@ -9,7 +10,7 @@ import ( // GrantNewAccessTokenFromAuthCode - Use this call to grant a new access token, using the previously obtained authorization code. // Endpoint: POST /v1/identity/openidconnect/tokenservice -func (c *Client) GrantNewAccessTokenFromAuthCode(code, redirectURI string) (*TokenResponse, error) { +func (c *Client) GrantNewAccessTokenFromAuthCode(ctx context.Context, code, redirectURI string) (*TokenResponse, error) { token := &TokenResponse{} q := url.Values{} @@ -17,7 +18,7 @@ func (c *Client) GrantNewAccessTokenFromAuthCode(code, redirectURI string) (*Tok q.Set("code", code) q.Set("redirect_uri", redirectURI) - req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/identity/openidconnect/tokenservice"), strings.NewReader(q.Encode())) + req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/identity/openidconnect/tokenservice"), strings.NewReader(q.Encode())) if err != nil { return token, err } @@ -33,7 +34,7 @@ func (c *Client) GrantNewAccessTokenFromAuthCode(code, redirectURI string) (*Tok // GrantNewAccessTokenFromRefreshToken - Use this call to grant a new access token, using a refresh token. // Endpoint: POST /v1/identity/openidconnect/tokenservice -func (c *Client) GrantNewAccessTokenFromRefreshToken(refreshToken string) (*TokenResponse, error) { +func (c *Client) GrantNewAccessTokenFromRefreshToken(ctx context.Context, refreshToken string) (*TokenResponse, error) { type request struct { GrantType string `json:"grant_type"` RefreshToken string `json:"refresh_token"` @@ -41,7 +42,7 @@ func (c *Client) GrantNewAccessTokenFromRefreshToken(refreshToken string) (*Toke token := &TokenResponse{} - req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/identity/openidconnect/tokenservice"), request{GrantType: "refresh_token", RefreshToken: refreshToken}) + req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/identity/openidconnect/tokenservice"), request{GrantType: "refresh_token", RefreshToken: refreshToken}) if err != nil { return token, err } @@ -56,10 +57,10 @@ func (c *Client) GrantNewAccessTokenFromRefreshToken(refreshToken string) (*Toke // GetUserInfo - Use this call to retrieve user profile attributes. // Endpoint: GET /v1/identity/openidconnect/userinfo/?schema= // Pass the schema that is used to return as per openidconnect protocol. The only supported schema value is openid. -func (c *Client) GetUserInfo(schema string) (*UserInfo, error) { +func (c *Client) GetUserInfo(ctx context.Context, schema string) (*UserInfo, error) { u := &UserInfo{} - req, err := http.NewRequest("GET", fmt.Sprintf("%s%s%s", c.APIBase, "/v1/identity/openidconnect/userinfo/?schema=", schema), nil) + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s%s%s", c.APIBase, "/v1/identity/openidconnect/userinfo/?schema=", schema), nil) if err != nil { return u, err } diff --git a/integration_test.go b/integration_test.go index 9e3abe9..afd1960 100644 --- a/integration_test.go +++ b/integration_test.go @@ -3,6 +3,7 @@ package paypal import ( + "context" "testing" "time" @@ -20,7 +21,7 @@ var testBillingPlan = "" // will be fetched in func TestSubscriptionPlans(t *te func TestGetAccessToken(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - token, err := c.GetAccessToken() + token, err := c.GetAccessToken(context.Background()) if err != nil { t.Errorf("Not expected error for GetAccessToken(), got %s", err.Error()) } @@ -31,9 +32,9 @@ func TestGetAccessToken(t *testing.T) { func TestGetUserInfo(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) - u, err := c.GetUserInfo("openid") + u, err := c.GetUserInfo(context.Background(), "openid") if u.ID != testUserID || err != nil { t.Errorf("GetUserInfo must return valid test ID %s, got %s, error: %v", testUserID, u.ID, err) } @@ -41,7 +42,7 @@ func TestGetUserInfo(t *testing.T) { func TestCreateVenmoPayout(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) payout := Payout{ SenderBatchHeader: &SenderBatchHeader{ @@ -64,14 +65,14 @@ func TestCreateVenmoPayout(t *testing.T) { }, } - res, err := c.CreateSinglePayout(payout) + res, err := c.CreatePayout(context.Background(), payout) assert.NoError(t, err, "should accept venmo wallet") assert.Greater(t, len(res.Items), 0) } -func TestCreateSinglePayout(t *testing.T) { +func TestCreatePayout(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) payout := Payout{ SenderBatchHeader: &SenderBatchHeader{ @@ -93,19 +94,19 @@ func TestCreateSinglePayout(t *testing.T) { }, } - c.CreateSinglePayout(payout) + c.CreatePayout(context.Background(), payout) } func TestStoreCreditCard(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) - r1, e1 := c.StoreCreditCard(CreditCard{}) + r1, e1 := c.StoreCreditCard(context.Background(), CreditCard{}) if e1 == nil || r1 != nil { t.Errorf("Error is expected for invalid CC") } - r2, e2 := c.StoreCreditCard(CreditCard{ + r2, e2 := c.StoreCreditCard(context.Background(), CreditCard{ Number: "4417119669820331", Type: "visa", ExpireMonth: "11", @@ -121,9 +122,9 @@ func TestStoreCreditCard(t *testing.T) { func TestDeleteCreditCard(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) - e1 := c.DeleteCreditCard("") + e1 := c.DeleteCreditCard(context.Background(), "") if e1 == nil { t.Errorf("Error is expected for invalid CC ID") } @@ -131,9 +132,9 @@ func TestDeleteCreditCard(t *testing.T) { func TestGetCreditCard(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) - r1, e1 := c.GetCreditCard("BBGGG") + r1, e1 := c.GetCreditCard(context.Background(), "BBGGG") if e1 == nil || r1 != nil { t.Errorf("Error is expected for invalid CC, got CC %v", r1) } @@ -141,14 +142,14 @@ func TestGetCreditCard(t *testing.T) { func TestGetCreditCards(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) - r1, e1 := c.GetCreditCards(nil) + r1, e1 := c.GetCreditCards(context.Background(), nil) if e1 != nil || r1 == nil { t.Errorf("200 code expected. Error: %v", e1) } - r2, e2 := c.GetCreditCards(&CreditCardsFilter{ + r2, e2 := c.GetCreditCards(context.Background(), &CreditCardsFilter{ Page: 2, PageSize: 7, }) @@ -159,9 +160,9 @@ func TestGetCreditCards(t *testing.T) { func TestPatchCreditCard(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) - r1, e1 := c.PatchCreditCard(testCardID, nil) + r1, e1 := c.PatchCreditCard(context.Background(), testCardID, nil) if e1 == nil || r1 != nil { t.Errorf("Error is expected for empty update info") } @@ -170,7 +171,7 @@ func TestPatchCreditCard(t *testing.T) { // Creates, gets, and deletes single webhook func TestCreateAndGetWebhook(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) payload := &CreateWebhookRequest{ URL: "https://example.com/paypal_webhooks", @@ -181,17 +182,17 @@ func TestCreateAndGetWebhook(t *testing.T) { }, } - createdWebhook, err := c.CreateWebhook(payload) + createdWebhook, err := c.CreateWebhook(context.Background(), payload) if err != nil { t.Errorf("Webhook couldn't be created, error %v", err) } - _, err = c.GetWebhook(createdWebhook.ID) + _, err = c.GetWebhook(context.Background(), createdWebhook.ID) if err != nil { t.Errorf("An error occurred while getting webhook, error %v", err) } - err = c.DeleteWebhook(createdWebhook.ID) + err = c.DeleteWebhook(context.Background(), createdWebhook.ID) if err != nil { t.Errorf("An error occurred while webhooks deletion, error %v", err) } @@ -200,7 +201,7 @@ func TestCreateAndGetWebhook(t *testing.T) { // Creates, updates, and deletes single webhook func TestCreateAndUpdateWebhook(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) creationPayload := &CreateWebhookRequest{ URL: "https://example.com/paypal_webhooks", @@ -211,7 +212,7 @@ func TestCreateAndUpdateWebhook(t *testing.T) { }, } - createdWebhook, err := c.CreateWebhook(creationPayload) + createdWebhook, err := c.CreateWebhook(context.Background(), creationPayload) if err != nil { t.Errorf("Webhook couldn't be created, error %v", err) } @@ -228,12 +229,12 @@ func TestCreateAndUpdateWebhook(t *testing.T) { }, } - _, err = c.UpdateWebhook(createdWebhook.ID, updatePayload) + _, err = c.UpdateWebhook(context.Background(), createdWebhook.ID, updatePayload) if err != nil { t.Errorf("Couldn't update webhook, error %v", err) } - err = c.DeleteWebhook(createdWebhook.ID) + err = c.DeleteWebhook(context.Background(), createdWebhook.ID) if err != nil { t.Errorf("An error occurred while webhooks deletion, error %v", err) } @@ -241,9 +242,9 @@ func TestCreateAndUpdateWebhook(t *testing.T) { func TestListWebhooks(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) - _, err := c.ListWebhooks(AncorTypeApplication) + _, err := c.ListWebhooks(context.Background(), AncorTypeApplication) if err != nil { t.Errorf("Cannot registered list webhooks, error %v", err) } @@ -251,7 +252,7 @@ func TestListWebhooks(t *testing.T) { func TestProduct(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) //create a product productData := Product{ @@ -263,7 +264,7 @@ func TestProduct(t *testing.T) { HomeUrl: "https://example.com", } - productCreateResponse, err := c.CreateProduct(productData) + productCreateResponse, err := c.CreateProduct(context.Background(), productData) assert.Equal(t, nil, err) testProductId = productCreateResponse.ID @@ -272,23 +273,23 @@ func TestProduct(t *testing.T) { productData.ID = productCreateResponse.ID productData.Description = "Updated product" - err = c.UpdateProduct(productData) + err = c.UpdateProduct(context.Background(), productData) assert.Equal(t, nil, err) //get product data - productFetched, err := c.GetProduct(productData.ID) + productFetched, err := c.GetProduct(context.Background(), productData.ID) assert.Equal(t, nil, err) assert.Equal(t, productFetched.Description, "Updated product") //test that lising products have more than one product - productList, err := c.ListProducts(nil) + productList, err := c.ListProducts(context.Background(), nil) assert.Equal(t, nil, err) assert.NotEqual(t, len(productList.Products), 0) } func TestSubscriptionPlans(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) //create a product newSubscriptionPlan := SubscriptionPlan{ @@ -330,35 +331,35 @@ func TestSubscriptionPlans(t *testing.T) { } //test create new plan - planCreateResponse, err := c.CreateSubscriptionPlan(newSubscriptionPlan) + planCreateResponse, err := c.CreateSubscriptionPlan(context.Background(), newSubscriptionPlan) assert.Equal(t, nil, err) testBillingPlan = planCreateResponse.ID // for next test //test update the newly created plan newSubscriptionPlan.ID = planCreateResponse.ID newSubscriptionPlan.Description = "updated description" - err = c.UpdateSubscriptionPlan(newSubscriptionPlan) + err = c.UpdateSubscriptionPlan(context.Background(), newSubscriptionPlan) assert.Equal(t, nil, err) //test get plan information - existingPlan, err := c.GetSubscriptionPlan(newSubscriptionPlan.ID) + existingPlan, err := c.GetSubscriptionPlan(context.Background(), newSubscriptionPlan.ID) assert.Equal(t, nil, err) assert.Equal(t, newSubscriptionPlan.Description, existingPlan.Description) //test activate plan - err = c.ActivateSubscriptionPlan(newSubscriptionPlan.ID) + err = c.ActivateSubscriptionPlan(context.Background(), newSubscriptionPlan.ID) assert.Equal(t, nil, err) //test deactivate plan - err = c.DeactivateSubscriptionPlans(newSubscriptionPlan.ID) + err = c.DeactivateSubscriptionPlans(context.Background(), newSubscriptionPlan.ID) assert.Equal(t, nil, err) //reactivate this plan for next next (subscription) - err = c.ActivateSubscriptionPlan(newSubscriptionPlan.ID) + err = c.ActivateSubscriptionPlan(context.Background(), newSubscriptionPlan.ID) assert.Equal(t, nil, err) //test upadte plan pricing - err = c.UpdateSubscriptionPlanPricing(newSubscriptionPlan.ID, []PricingSchemeUpdate{ + err = c.UpdateSubscriptionPlanPricing(context.Background(), newSubscriptionPlan.ID, []PricingSchemeUpdate{ { BillingCycleSequence: 1, PricingScheme: PricingScheme{ @@ -375,7 +376,7 @@ func TestSubscriptionPlans(t *testing.T) { assert.Equal(t, nil, err) //test update pricing scheme - updatedPricingPlan, err := c.GetSubscriptionPlan(newSubscriptionPlan.ID) + updatedPricingPlan, err := c.GetSubscriptionPlan(context.Background(), newSubscriptionPlan.ID) assert.Equal(t, nil, err) assert.Equal(t, "6.0", updatedPricingPlan.BillingCycles[0].PricingScheme.FixedPrice.Value) @@ -383,20 +384,34 @@ func TestSubscriptionPlans(t *testing.T) { func TestSubscription(t *testing.T) { c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken() + c.GetAccessToken(context.Background()) newSubscription := SubscriptionBase{ PlanID: testBillingPlan, } //create new subscription - newSubResponse, err := c.CreateSubscription(newSubscription) + newSubResponse, err := c.CreateSubscription(context.Background(), newSubscription) assert.Equal(t, nil, err) assert.NotEqual(t, "", newSubResponse.ID) //get subscription details - subDetails, err := c.GetSubscriptionDetails(newSubResponse.ID) + subDetails, err := c.GetSubscriptionDetails(context.Background(), newSubResponse.ID) assert.Equal(t, nil, err) assert.NotEqual(t, "", subDetails.ID) } + +func TestGetWebhookEventTypes(t *testing.T) { + c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) + c.GetAccessToken(context.Background()) + + r, err := c.GetWebhookEventTypes(context.Background()) + assert.Equal(t, nil, err) + assert.GreaterOrEqual(t, len(r.EventTypes), 1) + for _, v := range r.EventTypes { + assert.GreaterOrEqual(t, len(v.Name), 1) + assert.GreaterOrEqual(t, len(v.Description), 1) + assert.GreaterOrEqual(t, len(v.Status), 1) + } +} diff --git a/order.go b/order.go index 9b732bf..dc5772a 100644 --- a/order.go +++ b/order.go @@ -1,13 +1,16 @@ package paypal -import "fmt" +import ( + "context" + "fmt" +) // GetOrder retrieves order by ID // Endpoint: GET /v2/checkout/orders/ID -func (c *Client) GetOrder(orderID string) (*Order, error) { +func (c *Client) GetOrder(ctx context.Context, orderID string) (*Order, error) { order := &Order{} - req, err := c.NewRequest("GET", fmt.Sprintf("%s%s%s", c.APIBase, "/v2/checkout/orders/", orderID), nil) + req, err := c.NewRequest(ctx, "GET", fmt.Sprintf("%s%s%s", c.APIBase, "/v2/checkout/orders/", orderID), nil) if err != nil { return order, err } @@ -21,7 +24,7 @@ func (c *Client) GetOrder(orderID string) (*Order, error) { // CreateOrder - Use this call to create an order // Endpoint: POST /v2/checkout/orders -func (c *Client) CreateOrder(intent string, purchaseUnits []PurchaseUnitRequest, payer *CreateOrderPayer, appContext *ApplicationContext) (*Order, error) { +func (c *Client) CreateOrder(ctx context.Context, intent string, purchaseUnits []PurchaseUnitRequest, payer *CreateOrderPayer, appContext *ApplicationContext) (*Order, error) { type createOrderRequest struct { Intent string `json:"intent"` Payer *CreateOrderPayer `json:"payer,omitempty"` @@ -31,7 +34,7 @@ func (c *Client) CreateOrder(intent string, purchaseUnits []PurchaseUnitRequest, order := &Order{} - req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/checkout/orders"), createOrderRequest{Intent: intent, PurchaseUnits: purchaseUnits, Payer: payer, ApplicationContext: appContext}) + req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/checkout/orders"), createOrderRequest{Intent: intent, PurchaseUnits: purchaseUnits, Payer: payer, ApplicationContext: appContext}) if err != nil { return order, err } @@ -45,10 +48,10 @@ func (c *Client) CreateOrder(intent string, purchaseUnits []PurchaseUnitRequest, // UpdateOrder updates the order by ID // Endpoint: PATCH /v2/checkout/orders/ID -func (c *Client) UpdateOrder(orderID string, purchaseUnits []PurchaseUnitRequest) (*Order, error) { +func (c *Client) UpdateOrder(ctx context.Context, orderID string, purchaseUnits []PurchaseUnitRequest) (*Order, error) { order := &Order{} - req, err := c.NewRequest("PATCH", fmt.Sprintf("%s%s%s", c.APIBase, "/v2/checkout/orders/", orderID), purchaseUnits) + req, err := c.NewRequest(ctx, "PATCH", fmt.Sprintf("%s%s%s", c.APIBase, "/v2/checkout/orders/", orderID), purchaseUnits) if err != nil { return order, err } @@ -62,10 +65,10 @@ func (c *Client) UpdateOrder(orderID string, purchaseUnits []PurchaseUnitRequest // AuthorizeOrder - https://developer.paypal.com/docs/api/orders/v2/#orders_authorize // Endpoint: POST /v2/checkout/orders/ID/authorize -func (c *Client) AuthorizeOrder(orderID string, authorizeOrderRequest AuthorizeOrderRequest) (*Authorization, error) { +func (c *Client) AuthorizeOrder(ctx context.Context, orderID string, authorizeOrderRequest AuthorizeOrderRequest) (*Authorization, error) { auth := &Authorization{} - req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/checkout/orders/"+orderID+"/authorize"), authorizeOrderRequest) + req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/checkout/orders/"+orderID+"/authorize"), authorizeOrderRequest) if err != nil { return auth, err } @@ -79,14 +82,14 @@ func (c *Client) AuthorizeOrder(orderID string, authorizeOrderRequest AuthorizeO // CaptureOrder - https://developer.paypal.com/docs/api/orders/v2/#orders_capture // Endpoint: POST /v2/checkout/orders/ID/capture -func (c *Client) CaptureOrder(orderID string, captureOrderRequest CaptureOrderRequest) (*CaptureOrderResponse, error) { - return c.CaptureOrderWithPaypalRequestId(orderID, captureOrderRequest, "") +func (c *Client) CaptureOrder(ctx context.Context, orderID string, captureOrderRequest CaptureOrderRequest) (*CaptureOrderResponse, error) { + return c.CaptureOrderWithPaypalRequestId(ctx, orderID, captureOrderRequest, "") } // CaptureOrder with idempotency - https://developer.paypal.com/docs/api/orders/v2/#orders_capture // Endpoint: POST /v2/checkout/orders/ID/capture // https://developer.paypal.com/docs/api/reference/api-requests/#http-request-headers -func (c *Client) CaptureOrderWithPaypalRequestId( +func (c *Client) CaptureOrderWithPaypalRequestId(ctx context.Context, orderID string, captureOrderRequest CaptureOrderRequest, requestID string, @@ -94,7 +97,7 @@ func (c *Client) CaptureOrderWithPaypalRequestId( capture := &CaptureOrderResponse{} c.SetReturnRepresentation() - req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/checkout/orders/"+orderID+"/capture"), captureOrderRequest) + req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/checkout/orders/"+orderID+"/capture"), captureOrderRequest) if err != nil { return capture, err } @@ -112,20 +115,20 @@ func (c *Client) CaptureOrderWithPaypalRequestId( // RefundCapture - https://developer.paypal.com/docs/api/payments/v2/#captures_refund // Endpoint: POST /v2/payments/captures/ID/refund -func (c *Client) RefundCapture(captureID string, refundCaptureRequest RefundCaptureRequest) (*RefundResponse, error) { - return c.RefundCaptureWithPaypalRequestId(captureID, refundCaptureRequest, "") +func (c *Client) RefundCapture(ctx context.Context, captureID string, refundCaptureRequest RefundCaptureRequest) (*RefundResponse, error) { + return c.RefundCaptureWithPaypalRequestId(ctx, captureID, refundCaptureRequest, "") } // RefundCapture with idempotency - https://developer.paypal.com/docs/api/payments/v2/#captures_refund // Endpoint: POST /v2/payments/captures/ID/refund -func (c *Client) RefundCaptureWithPaypalRequestId( +func (c *Client) RefundCaptureWithPaypalRequestId(ctx context.Context, captureID string, refundCaptureRequest RefundCaptureRequest, requestID string, ) (*RefundResponse, error) { refund := &RefundResponse{} - req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/captures/"+captureID+"/refund"), refundCaptureRequest) + req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/captures/"+captureID+"/refund"), refundCaptureRequest) if err != nil { return refund, err } diff --git a/payout.go b/payout.go index 512c630..e74c920 100644 --- a/payout.go +++ b/payout.go @@ -1,14 +1,15 @@ package paypal import ( + "context" "fmt" ) -// CreateSinglePayout submits a payout with an asynchronous API call, which immediately returns the results of a PayPal payment. +// CreatePayout 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 // Endpoint: POST /v1/payments/payouts -func (c *Client) CreateSinglePayout(p Payout) (*PayoutResponse, error) { - req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/payouts"), p) +func (c *Client) CreatePayout(ctx context.Context, p Payout) (*PayoutResponse, error) { + req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/payouts"), p) response := &PayoutResponse{} if err != nil { @@ -22,11 +23,16 @@ func (c *Client) CreateSinglePayout(p Payout) (*PayoutResponse, error) { return response, nil } +// CreateSinglePayout is deprecated, use CreatePayout instead. +func (c *Client) CreateSinglePayout(ctx context.Context, p Payout) (*PayoutResponse, error) { + return c.CreatePayout(ctx, p) +} + // 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) +func (c *Client) GetPayout(ctx context.Context, payoutBatchID string) (*PayoutResponse, error) { + req, err := c.NewRequest(ctx, "GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/payouts/"+payoutBatchID), nil) response := &PayoutResponse{} if err != nil { @@ -43,8 +49,8 @@ func (c *Client) GetPayout(payoutBatchID string) (*PayoutResponse, error) { // 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) +func (c *Client) GetPayoutItem(ctx context.Context, payoutItemID string) (*PayoutItemResponse, error) { + req, err := c.NewRequest(ctx, "GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/payouts-item/"+payoutItemID), nil) response := &PayoutItemResponse{} if err != nil { @@ -61,8 +67,8 @@ func (c *Client) GetPayoutItem(payoutItemID string) (*PayoutItemResponse, error) // 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) +func (c *Client) CancelPayoutItem(ctx context.Context, payoutItemID string) (*PayoutItemResponse, error) { + req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/payouts-item/"+payoutItemID+"/cancel"), nil) response := &PayoutItemResponse{} if err != nil { diff --git a/products.go b/products.go index fb41b99..1b2c2da 100644 --- a/products.go +++ b/products.go @@ -1,6 +1,7 @@ package paypal import ( + "context" "fmt" "net/http" ) @@ -60,8 +61,8 @@ func (self *Product) GetUpdatePatch() []Patch { // CreateProduct creates a product // Doc: https://developer.paypal.com/docs/api/catalog-products/v1/#products_create // Endpoint: POST /v1/catalogs/products -func (c *Client) CreateProduct(product Product) (*CreateProductResponse, error) { - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/catalogs/products"), product) +func (c *Client) CreateProduct(ctx context.Context, product Product) (*CreateProductResponse, error) { + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/catalogs/products"), product) response := &CreateProductResponse{} if err != nil { return response, err @@ -73,8 +74,8 @@ func (c *Client) CreateProduct(product Product) (*CreateProductResponse, error) // UpdateProduct. updates a product information // Doc: https://developer.paypal.com/docs/api/catalog-products/v1/#products_patch // Endpoint: PATCH /v1/catalogs/products/:product_id -func (c *Client) UpdateProduct(product Product) error { - req, err := c.NewRequest(http.MethodPatch, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/catalogs/products/", product.ID), product.GetUpdatePatch()) +func (c *Client) UpdateProduct(ctx context.Context, product Product) error { + req, err := c.NewRequest(ctx, http.MethodPatch, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/catalogs/products/", product.ID), product.GetUpdatePatch()) if err != nil { return err } @@ -85,8 +86,8 @@ func (c *Client) UpdateProduct(product Product) error { // Get product details // Doc: https://developer.paypal.com/docs/api/catalog-products/v1/#products_get // Endpoint: GET /v1/catalogs/products/:product_id -func (c *Client) GetProduct(productId string) (*Product, error) { - req, err := c.NewRequest(http.MethodGet, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/catalogs/products/", productId), nil) +func (c *Client) GetProduct(ctx context.Context, productId string) (*Product, error) { + req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/catalogs/products/", productId), nil) response := &Product{} if err != nil { return response, err @@ -98,8 +99,8 @@ func (c *Client) GetProduct(productId string) (*Product, error) { // List all products // Doc: https://developer.paypal.com/docs/api/catalog-products/v1/#products_list // Endpoint: GET /v1/catalogs/products -func (c *Client) ListProducts(params *ProductListParameters) (*ListProductsResponse, error) { - req, err := c.NewRequest(http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/catalogs/products"), nil) +func (c *Client) ListProducts(ctx context.Context, params *ProductListParameters) (*ListProductsResponse, error) { + req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/catalogs/products"), nil) response := &ListProductsResponse{} if err != nil { return response, err diff --git a/sale.go b/sale.go index f1e4d9c..0d81cb9 100644 --- a/sale.go +++ b/sale.go @@ -1,15 +1,18 @@ package paypal -import "fmt" +import ( + "context" + "fmt" +) // GetSale returns a sale by ID // Use this call to get details about a sale transaction. // Note: This call returns only the sales that were created via the REST API. // Endpoint: GET /v1/payments/sale/ID -func (c *Client) GetSale(saleID string) (*Sale, error) { +func (c *Client) GetSale(ctx context.Context, saleID string) (*Sale, error) { sale := &Sale{} - req, err := c.NewRequest("GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/sale/"+saleID), nil) + req, err := c.NewRequest(ctx, "GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/sale/"+saleID), nil) if err != nil { return sale, err } @@ -24,14 +27,14 @@ func (c *Client) GetSale(saleID string) (*Sale, error) { // RefundSale refunds a completed payment. // Use this call to refund a completed payment. Provide the sale_id in the URI and an empty JSON payload for a full refund. For partial refunds, you can include an amount. // Endpoint: POST /v1/payments/sale/ID/refund -func (c *Client) RefundSale(saleID string, a *Amount) (*Refund, error) { +func (c *Client) RefundSale(ctx context.Context, saleID string, a *Amount) (*Refund, error) { type refundRequest struct { Amount *Amount `json:"amount"` } refund := &Refund{} - req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/sale/"+saleID+"/refund"), &refundRequest{Amount: a}) + req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/sale/"+saleID+"/refund"), &refundRequest{Amount: a}) if err != nil { return refund, err } @@ -46,10 +49,10 @@ func (c *Client) RefundSale(saleID string, a *Amount) (*Refund, error) { // GetRefund by ID // Use it to look up details of a specific refund on direct and captured payments. // Endpoint: GET /v2/payments/refund/ID -func (c *Client) GetRefund(refundID string) (*Refund, error) { +func (c *Client) GetRefund(ctx context.Context, refundID string) (*Refund, error) { refund := &Refund{} - req, err := c.NewRequest("GET", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/refund/"+refundID), nil) + req, err := c.NewRequest(ctx, "GET", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/refund/"+refundID), nil) if err != nil { return refund, err } diff --git a/subscription.go b/subscription.go index 77b414d..efdb7e4 100644 --- a/subscription.go +++ b/subscription.go @@ -1,6 +1,7 @@ package paypal import ( + "context" "fmt" "net/http" "time" @@ -88,8 +89,8 @@ func (self *Subscription) GetUpdatePatch() []Patch { // CreateSubscriptionPlan creates a subscriptionPlan // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_create // Endpoint: POST /v1/billing/subscriptions -func (c *Client) CreateSubscription(newSubscription SubscriptionBase) (*SubscriptionDetailResp, error) { - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/billing/subscriptions"), newSubscription) +func (c *Client) CreateSubscription(ctx context.Context, newSubscription SubscriptionBase) (*SubscriptionDetailResp, error) { + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/billing/subscriptions"), newSubscription) req.Header.Add("Prefer", "return=representation") response := &SubscriptionDetailResp{} if err != nil { @@ -102,8 +103,8 @@ func (c *Client) CreateSubscription(newSubscription SubscriptionBase) (*Subscrip // UpdateSubscriptionPlan. updates a plan // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_patch // Endpoint: PATCH /v1/billing/subscriptions/:subscription_id -func (c *Client) UpdateSubscription(updatedSubscription Subscription) error { - req, err := c.NewRequest(http.MethodPatch, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/billing/subscriptions/", updatedSubscription.ID), updatedSubscription.GetUpdatePatch()) +func (c *Client) UpdateSubscription(ctx context.Context, updatedSubscription Subscription) error { + req, err := c.NewRequest(ctx, http.MethodPatch, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/billing/subscriptions/", updatedSubscription.ID), updatedSubscription.GetUpdatePatch()) if err != nil { return err } @@ -113,8 +114,8 @@ func (c *Client) UpdateSubscription(updatedSubscription Subscription) error { // GetSubscriptionDetails shows details for a subscription, by ID. // Endpoint: GET /v1/billing/subscriptions/ -func (c *Client) GetSubscriptionDetails(subscriptionID string) (*SubscriptionDetailResp, error) { - req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v1/billing/subscriptions/%s", c.APIBase, subscriptionID), nil) +func (c *Client) GetSubscriptionDetails(ctx context.Context, subscriptionID string) (*SubscriptionDetailResp, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/v1/billing/subscriptions/%s", c.APIBase, subscriptionID), nil) response := &SubscriptionDetailResp{} if err != nil { return response, err @@ -126,8 +127,8 @@ func (c *Client) GetSubscriptionDetails(subscriptionID string) (*SubscriptionDet // Activates the subscription. // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_activate // Endpoint: POST /v1/billing/subscriptions/{id}/activate -func (c *Client) ActivateSubscription(subscriptionId, activateReason string) error { - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/billing/subscriptions/%s/activate", c.APIBase, subscriptionId), map[string]string{"reason": activateReason}) +func (c *Client) ActivateSubscription(ctx context.Context, subscriptionId, activateReason string) error { + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s/v1/billing/subscriptions/%s/activate", c.APIBase, subscriptionId), map[string]string{"reason": activateReason}) if err != nil { return err } @@ -138,8 +139,8 @@ func (c *Client) ActivateSubscription(subscriptionId, activateReason string) err // Cancels the subscription. // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_cancel // Endpoint: POST /v1/billing/subscriptions/{id}/cancel -func (c *Client) CancelSubscription(subscriptionId, cancelReason string) error { - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/billing/subscriptions/%s/cancel", c.APIBase, subscriptionId), map[string]string{"reason": cancelReason}) +func (c *Client) CancelSubscription(ctx context.Context, subscriptionId, cancelReason string) error { + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s/v1/billing/subscriptions/%s/cancel", c.APIBase, subscriptionId), map[string]string{"reason": cancelReason}) if err != nil { return err } @@ -150,8 +151,8 @@ func (c *Client) CancelSubscription(subscriptionId, cancelReason string) error { // Captures an authorized payment from the subscriber on the subscription. // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_capture // Endpoint: POST /v1/billing/subscriptions/{id}/capture -func (c *Client) CaptureSubscription(subscriptionId string, request CaptureReqeust) (*SubscriptionCaptureResponse, error) { - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/billing/subscriptions/%s/capture", c.APIBase, subscriptionId), request) +func (c *Client) CaptureSubscription(ctx context.Context, subscriptionId string, request CaptureReqeust) (*SubscriptionCaptureResponse, error) { + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s/v1/billing/subscriptions/%s/capture", c.APIBase, subscriptionId), request) response := &SubscriptionCaptureResponse{} if err != nil { return response, err @@ -163,8 +164,8 @@ func (c *Client) CaptureSubscription(subscriptionId string, request CaptureReqeu // Suspends the subscription. // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_suspend // Endpoint: POST /v1/billing/subscriptions/{id}/suspend -func (c *Client) SuspendSubscription(subscriptionId, reason string) error { - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/billing/subscriptions/%s/suspend", c.APIBase, subscriptionId), map[string]string{"reason": reason}) +func (c *Client) SuspendSubscription(ctx context.Context, subscriptionId, reason string) error { + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s/v1/billing/subscriptions/%s/suspend", c.APIBase, subscriptionId), map[string]string{"reason": reason}) if err != nil { return err } @@ -175,10 +176,10 @@ func (c *Client) SuspendSubscription(subscriptionId, reason string) error { // Lists transactions for a subscription. // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_transactions // Endpoint: GET /v1/billing/subscriptions/{id}/transactions -func (c *Client) GetSubscriptionTransactions(requestParams SubscriptionTransactionsParams) (*SubscriptionTransactionsResponse, error) { +func (c *Client) GetSubscriptionTransactions(ctx context.Context, requestParams SubscriptionTransactionsParams) (*SubscriptionTransactionsResponse, error) { startTime := requestParams.StartTime.Format("2006-01-02T15:04:05Z") endTime := requestParams.EndTime.Format("2006-01-02T15:04:05Z") - req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v1/billing/subscriptions/%s/transactions?start_time=%s&end_time=%s", c.APIBase, requestParams.SubscriptionId, startTime, endTime), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/v1/billing/subscriptions/%s/transactions?start_time=%s&end_time=%s", c.APIBase, requestParams.SubscriptionId, startTime, endTime), nil) response := &SubscriptionTransactionsResponse{} if err != nil { return response, err @@ -191,8 +192,8 @@ func (c *Client) GetSubscriptionTransactions(requestParams SubscriptionTransacti // Revise plan or quantity of subscription // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_revise // Endpoint: POST /v1/billing/subscriptions/{id}/revise -func (c *Client) ReviseSubscription(subscriptionId string, reviseSubscription SubscriptionBase) (*SubscriptionDetailResp, error) { - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/billing/subscriptions/%s/revise", c.APIBase, subscriptionId), reviseSubscription) +func (c *Client) ReviseSubscription(ctx context.Context, subscriptionId string, reviseSubscription SubscriptionBase) (*SubscriptionDetailResp, error) { + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s/v1/billing/subscriptions/%s/revise", c.APIBase, subscriptionId), reviseSubscription) response := &SubscriptionDetailResp{} if err != nil { return response, err diff --git a/subscription_plan.go b/subscription_plan.go index 721c7a2..ffa461f 100644 --- a/subscription_plan.go +++ b/subscription_plan.go @@ -1,6 +1,7 @@ package paypal import ( + "context" "fmt" "net/http" "time" @@ -131,8 +132,8 @@ func (self *SubscriptionPlan) GetUpdatePatch() []Patch { // CreateSubscriptionPlan creates a subscriptionPlan // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#plans_create // Endpoint: POST /v1/billing/plans -func (c *Client) CreateSubscriptionPlan(newPlan SubscriptionPlan) (*CreateSubscriptionPlanResponse, error) { - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/billing/plans"), newPlan) +func (c *Client) CreateSubscriptionPlan(ctx context.Context, newPlan SubscriptionPlan) (*CreateSubscriptionPlanResponse, error) { + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/billing/plans"), newPlan) response := &CreateSubscriptionPlanResponse{} if err != nil { return response, err @@ -144,8 +145,8 @@ func (c *Client) CreateSubscriptionPlan(newPlan SubscriptionPlan) (*CreateSubscr // UpdateSubscriptionPlan. updates a plan // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#plans_patch // Endpoint: PATCH /v1/billing/plans/:plan_id -func (c *Client) UpdateSubscriptionPlan(updatedPlan SubscriptionPlan) error { - req, err := c.NewRequest(http.MethodPatch, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/billing/plans/", updatedPlan.ID), updatedPlan.GetUpdatePatch()) +func (c *Client) UpdateSubscriptionPlan(ctx context.Context, updatedPlan SubscriptionPlan) error { + req, err := c.NewRequest(ctx, http.MethodPatch, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/billing/plans/", updatedPlan.ID), updatedPlan.GetUpdatePatch()) if err != nil { return err } @@ -156,8 +157,8 @@ func (c *Client) UpdateSubscriptionPlan(updatedPlan SubscriptionPlan) error { // UpdateSubscriptionPlan. updates a plan // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#plans_get // Endpoint: GET /v1/billing/plans/:plan_id -func (c *Client) GetSubscriptionPlan(planId string) (*SubscriptionPlan, error) { - req, err := c.NewRequest(http.MethodGet, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/billing/plans/", planId), nil) +func (c *Client) GetSubscriptionPlan(ctx context.Context, planId string) (*SubscriptionPlan, error) { + req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/billing/plans/", planId), nil) response := &SubscriptionPlan{} if err != nil { return response, err @@ -169,8 +170,8 @@ func (c *Client) GetSubscriptionPlan(planId string) (*SubscriptionPlan, error) { // List all plans // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#plans_list // Endpoint: GET /v1/billing/plans -func (c *Client) ListSubscriptionPlans(params *SubscriptionPlanListParameters) (*ListSubscriptionPlansResponse, error) { - req, err := c.NewRequest(http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/billing/plans"), nil) +func (c *Client) ListSubscriptionPlans(ctx context.Context, params *SubscriptionPlanListParameters) (*ListSubscriptionPlansResponse, error) { + req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/billing/plans"), nil) response := &ListSubscriptionPlansResponse{} if err != nil { return response, err @@ -193,8 +194,8 @@ func (c *Client) ListSubscriptionPlans(params *SubscriptionPlanListParameters) ( // Activates a plan // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#plans_activate // Endpoint: POST /v1/billing/plans/{id}/activate -func (c *Client) ActivateSubscriptionPlan(planId string) error { - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/billing/plans/%s/activate", c.APIBase, planId), nil) +func (c *Client) ActivateSubscriptionPlan(ctx context.Context, planId string) error { + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s/v1/billing/plans/%s/activate", c.APIBase, planId), nil) if err != nil { return err } @@ -206,8 +207,8 @@ func (c *Client) ActivateSubscriptionPlan(planId string) error { // Deactivates a plan // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#plans_deactivate // Endpoint: POST /v1/billing/plans/{id}/deactivate -func (c *Client) DeactivateSubscriptionPlans(planId string) error { - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/billing/plans/%s/deactivate", c.APIBase, planId), nil) +func (c *Client) DeactivateSubscriptionPlans(ctx context.Context, planId string) error { + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s/v1/billing/plans/%s/deactivate", c.APIBase, planId), nil) if err != nil { return err } @@ -219,8 +220,8 @@ func (c *Client) DeactivateSubscriptionPlans(planId string) error { // Updates pricing for a plan. For example, you can update a regular billing cycle from $5 per month to $7 per month. // Doc: https://developer.paypal.com/docs/api/subscriptions/v1/#plans_update-pricing-schemes // Endpoint: POST /v1/billing/plans/{id}/update-pricing-schemes -func (c *Client) UpdateSubscriptionPlanPricing(planId string, pricingSchemes []PricingSchemeUpdate) error { - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/billing/plans/%s/update-pricing-schemes", c.APIBase, planId), PricingSchemeUpdateRequest{ +func (c *Client) UpdateSubscriptionPlanPricing(ctx context.Context, planId string, pricingSchemes []PricingSchemeUpdate) error { + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s/v1/billing/plans/%s/update-pricing-schemes", c.APIBase, planId), PricingSchemeUpdateRequest{ Schemes: pricingSchemes, }) if err != nil { diff --git a/transaction_search.go b/transaction_search.go index 9fdf773..a10a250 100644 --- a/transaction_search.go +++ b/transaction_search.go @@ -1,6 +1,7 @@ package paypal import ( + "context" "fmt" "strconv" "time" @@ -35,10 +36,10 @@ type TransactionSearchResponse struct { // ListTransactions - Use this to search PayPal transactions from the last 31 days. // Endpoint: GET /v1/reporting/transactions -func (c *Client) ListTransactions(req *TransactionSearchRequest) (*TransactionSearchResponse, error) { +func (c *Client) ListTransactions(ctx context.Context, req *TransactionSearchRequest) (*TransactionSearchResponse, error) { response := &TransactionSearchResponse{} - r, err := c.NewRequest("GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/reporting/transactions"), nil) + r, err := c.NewRequest(ctx, "GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/reporting/transactions"), nil) if err != nil { return nil, err } diff --git a/types.go b/types.go index c9b87a0..1279f2b 100644 --- a/types.go +++ b/types.go @@ -134,11 +134,11 @@ const ( // // https://developer.paypal.com/docs/api/payments.payouts-batch/v1/#definition-batch_status const ( - BatchStatusDenied string = "DENIED" - BatchStatusPending string = "PENDING" - BatchStatusProcessing string = "PROCESSING" + BatchStatusDenied string = "DENIED" + BatchStatusPending string = "PENDING" + BatchStatusProcessing string = "PROCESSING" BatchStatusSuccess string = "SUCCESS" - BatchStatusCanceled string = "CANCELED" + BatchStatusCanceled string = "CANCELED" ) const ( @@ -1027,6 +1027,10 @@ type ( VerificationStatus string `json:"verification_status,omitempty"` } + WebhookEventTypesResponse struct { + EventTypes []WebhookEventType `json:"event_types"` + } + // Webhook strunct Webhook struct { ID string `json:"id"` @@ -1052,6 +1056,7 @@ type ( WebhookEventType struct { Name string `json:"name"` Description string `json:"description"` + Status string `json:"status,omitempty"` } // CreateWebhookRequest struct diff --git a/unit_test.go b/unit_test.go index 967d516..b1623a4 100644 --- a/unit_test.go +++ b/unit_test.go @@ -1,6 +1,7 @@ package paypal import ( + "context" "encoding/json" "io/ioutil" "net/http" @@ -590,7 +591,7 @@ func TestCreateWebProfile_valid(t *testing.T) { }, } - res, err := c.CreateWebProfile(wp) + res, err := c.CreateWebProfile(context.Background(), wp) if err != nil { t.Fatal(err) @@ -609,7 +610,7 @@ func TestCreateWebProfile_invalid(t *testing.T) { wp := WebProfile{} - _, err := c.CreateWebProfile(wp) + _, err := c.CreateWebProfile(context.Background(), wp) if err == nil { t.Fatalf("expecting an error got nil") @@ -622,7 +623,7 @@ func TestGetWebProfile_valid(t *testing.T) { c, _ := NewClient("foo", "bar", ts.URL) - res, err := c.GetWebProfile("XP-CP6S-W9DY-96H8-MVN2") + res, err := c.GetWebProfile(context.Background(), "XP-CP6S-W9DY-96H8-MVN2") if err != nil { t.Fatal(err) @@ -643,7 +644,7 @@ func TestGetWebProfile_invalid(t *testing.T) { c, _ := NewClient("foo", "bar", ts.URL) - _, err := c.GetWebProfile("foobar") + _, err := c.GetWebProfile(context.Background(), "foobar") if err == nil { t.Fatalf("expecting an error got nil") @@ -656,7 +657,7 @@ func TestGetWebProfiles(t *testing.T) { c, _ := NewClient("foo", "bar", ts.URL) - res, err := c.GetWebProfiles() + res, err := c.GetWebProfiles(context.Background()) if err != nil { t.Fatal(err) @@ -678,7 +679,7 @@ func TestSetWebProfile_valid(t *testing.T) { Name: "Shop T-Shirt YeowZa!", } - err := c.SetWebProfile(wp) + err := c.SetWebProfile(context.Background(), wp) if err != nil { t.Fatal(err) @@ -696,7 +697,7 @@ func TestSetWebProfile_invalid(t *testing.T) { ID: "foobar", } - err := c.SetWebProfile(wp) + err := c.SetWebProfile(context.Background(), wp) if err == nil { t.Fatal(err) @@ -704,7 +705,7 @@ func TestSetWebProfile_invalid(t *testing.T) { wp = WebProfile{} - err = c.SetWebProfile(wp) + err = c.SetWebProfile(context.Background(), wp) if err == nil { t.Fatal(err) @@ -722,7 +723,7 @@ func TestDeleteWebProfile_valid(t *testing.T) { Name: "Shop T-Shirt YeowZa!", } - err := c.SetWebProfile(wp) + err := c.SetWebProfile(context.Background(), wp) if err != nil { t.Fatal(err) @@ -736,7 +737,7 @@ func TestDeleteWebProfile_invalid(t *testing.T) { c, _ := NewClient("foo", "bar", ts.URL) - err := c.DeleteWebProfile("foobar") + err := c.DeleteWebProfile(context.Background(), "foobar") if err == nil { t.Fatal(err) diff --git a/vault.go b/vault.go index 42195ad..7425662 100644 --- a/vault.go +++ b/vault.go @@ -1,13 +1,14 @@ package paypal import ( + "context" "fmt" ) // StoreCreditCard func // Endpoint: POST /v1/vault/credit-cards -func (c *Client) StoreCreditCard(cc CreditCard) (*CreditCard, error) { - req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/vault/credit-cards"), cc) +func (c *Client) StoreCreditCard(ctx context.Context, cc CreditCard) (*CreditCard, error) { + req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/vault/credit-cards"), cc) if err != nil { return nil, err } @@ -23,8 +24,8 @@ func (c *Client) StoreCreditCard(cc CreditCard) (*CreditCard, error) { // DeleteCreditCard func // Endpoint: DELETE /v1/vault/credit-cards/credit_card_id -func (c *Client) DeleteCreditCard(id string) error { - req, err := c.NewRequest("DELETE", fmt.Sprintf("%s/v1/vault/credit-cards/%s", c.APIBase, id), nil) +func (c *Client) DeleteCreditCard(ctx context.Context, id string) error { + req, err := c.NewRequest(ctx, "DELETE", fmt.Sprintf("%s/v1/vault/credit-cards/%s", c.APIBase, id), nil) if err != nil { return err } @@ -38,8 +39,8 @@ func (c *Client) DeleteCreditCard(id string) error { // GetCreditCard func // Endpoint: GET /v1/vault/credit-cards/credit_card_id -func (c *Client) GetCreditCard(id string) (*CreditCard, error) { - req, err := c.NewRequest("GET", fmt.Sprintf("%s/v1/vault/credit-cards/%s", c.APIBase, id), nil) +func (c *Client) GetCreditCard(ctx context.Context, id string) (*CreditCard, error) { + req, err := c.NewRequest(ctx, "GET", fmt.Sprintf("%s/v1/vault/credit-cards/%s", c.APIBase, id), nil) if err != nil { return nil, err } @@ -55,7 +56,7 @@ func (c *Client) GetCreditCard(id string) (*CreditCard, error) { // GetCreditCards func // Endpoint: GET /v1/vault/credit-cards -func (c *Client) GetCreditCards(ccf *CreditCardsFilter) (*CreditCards, error) { +func (c *Client) GetCreditCards(ctx context.Context, ccf *CreditCardsFilter) (*CreditCards, error) { page := 1 if ccf != nil && ccf.Page > 0 { page = ccf.Page @@ -65,7 +66,7 @@ func (c *Client) GetCreditCards(ccf *CreditCardsFilter) (*CreditCards, error) { pageSize = ccf.PageSize } - req, err := c.NewRequest("GET", fmt.Sprintf("%s/v1/vault/credit-cards?page=%d&page_size=%d", c.APIBase, page, pageSize), nil) + req, err := c.NewRequest(ctx, "GET", fmt.Sprintf("%s/v1/vault/credit-cards?page=%d&page_size=%d", c.APIBase, page, pageSize), nil) if err != nil { return nil, err } @@ -81,8 +82,8 @@ func (c *Client) GetCreditCards(ccf *CreditCardsFilter) (*CreditCards, error) { // PatchCreditCard func // Endpoint: PATCH /v1/vault/credit-cards/credit_card_id -func (c *Client) PatchCreditCard(id string, ccf []CreditCardField) (*CreditCard, error) { - req, err := c.NewRequest("PATCH", fmt.Sprintf("%s/v1/vault/credit-cards/%s", c.APIBase, id), ccf) +func (c *Client) PatchCreditCard(ctx context.Context, id string, ccf []CreditCardField) (*CreditCard, error) { + req, err := c.NewRequest(ctx, "PATCH", fmt.Sprintf("%s/v1/vault/credit-cards/%s", c.APIBase, id), ccf) if err != nil { return nil, err } diff --git a/webhooks.go b/webhooks.go index dd4d0eb..39d0dba 100644 --- a/webhooks.go +++ b/webhooks.go @@ -2,6 +2,7 @@ package paypal import ( "bytes" + "context" "encoding/json" "fmt" "io/ioutil" @@ -10,8 +11,8 @@ import ( // CreateWebhook - Subscribes your webhook listener to events. // Endpoint: POST /v1/notifications/webhooks -func (c *Client) CreateWebhook(createWebhookRequest *CreateWebhookRequest) (*Webhook, error) { - req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks"), createWebhookRequest) +func (c *Client) CreateWebhook(ctx context.Context, createWebhookRequest *CreateWebhookRequest) (*Webhook, error) { + req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks"), createWebhookRequest) webhook := &Webhook{} if err != nil { return webhook, err @@ -23,8 +24,8 @@ func (c *Client) CreateWebhook(createWebhookRequest *CreateWebhookRequest) (*Web // GetWebhook - Shows details for a webhook, by ID. // Endpoint: GET /v1/notifications/webhooks/ID -func (c *Client) GetWebhook(webhookID string) (*Webhook, error) { - req, err := c.NewRequest(http.MethodGet, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/notifications/webhooks/", webhookID), nil) +func (c *Client) GetWebhook(ctx context.Context, webhookID string) (*Webhook, error) { + req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/notifications/webhooks/", webhookID), nil) webhook := &Webhook{} if err != nil { return webhook, err @@ -36,8 +37,8 @@ func (c *Client) GetWebhook(webhookID string) (*Webhook, error) { // UpdateWebhook - Updates a webhook to replace webhook fields with new values. // Endpoint: PATCH /v1/notifications/webhooks/ID -func (c *Client) UpdateWebhook(webhookID string, fields []WebhookField) (*Webhook, error) { - req, err := c.NewRequest(http.MethodPatch, fmt.Sprintf("%s/v1/notifications/webhooks/%s", c.APIBase, webhookID), fields) +func (c *Client) UpdateWebhook(ctx context.Context, webhookID string, fields []WebhookField) (*Webhook, error) { + req, err := c.NewRequest(ctx, http.MethodPatch, fmt.Sprintf("%s/v1/notifications/webhooks/%s", c.APIBase, webhookID), fields) webhook := &Webhook{} if err != nil { return webhook, err @@ -49,11 +50,11 @@ func (c *Client) UpdateWebhook(webhookID string, fields []WebhookField) (*Webhoo // ListWebhooks - Lists webhooks for an app. // Endpoint: GET /v1/notifications/webhooks -func (c *Client) ListWebhooks(anchorType string) (*ListWebhookResponse, error) { +func (c *Client) ListWebhooks(ctx context.Context, anchorType string) (*ListWebhookResponse, error) { if len(anchorType) == 0 { anchorType = AncorTypeApplication } - req, err := c.NewRequest(http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks"), nil) + req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks"), nil) q := req.URL.Query() q.Add("anchor_type", anchorType) req.URL.RawQuery = q.Encode() @@ -68,8 +69,8 @@ func (c *Client) ListWebhooks(anchorType string) (*ListWebhookResponse, error) { // DeleteWebhook - Deletes a webhook, by ID. // Endpoint: DELETE /v1/notifications/webhooks/ID -func (c *Client) DeleteWebhook(webhookID string) error { - req, err := c.NewRequest(http.MethodDelete, fmt.Sprintf("%s/v1/notifications/webhooks/%s", c.APIBase, webhookID), nil) +func (c *Client) DeleteWebhook(ctx context.Context, webhookID string) error { + req, err := c.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/v1/notifications/webhooks/%s", c.APIBase, webhookID), nil) if err != nil { return err } @@ -80,7 +81,7 @@ func (c *Client) DeleteWebhook(webhookID string) error { // VerifyWebhookSignature - Use this to verify the signature of a webhook recieved from paypal. // Endpoint: POST /v1/notifications/verify-webhook-signature -func (c *Client) VerifyWebhookSignature(httpReq *http.Request, webhookID string) (*VerifyWebhookResponse, error) { +func (c *Client) VerifyWebhookSignature(ctx context.Context, httpReq *http.Request, webhookID string) (*VerifyWebhookResponse, error) { type verifyWebhookSignatureRequest struct { AuthAlgo string `json:"auth_algo,omitempty"` CertURL string `json:"cert_url,omitempty"` @@ -111,7 +112,7 @@ func (c *Client) VerifyWebhookSignature(httpReq *http.Request, webhookID string) response := &VerifyWebhookResponse{} - req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/verify-webhook-signature"), verifyRequest) + req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/verify-webhook-signature"), verifyRequest) if err != nil { return nil, err } @@ -122,3 +123,19 @@ func (c *Client) VerifyWebhookSignature(httpReq *http.Request, webhookID string) return response, nil } + +// GetWebhooksEventTypes - Lists all webhook event types. +// Endpoint: GET /v1/notifications/webhooks-event-types +func (c *Client) GetWebhookEventTypes(ctx context.Context) (*WebhookEventTypesResponse, error) { + req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks-event-types"), nil) + q := req.URL.Query() + + req.URL.RawQuery = q.Encode() + resp := &WebhookEventTypesResponse{} + if err != nil { + return nil, err + } + + err = c.SendWithAuth(req, resp) + return resp, err +} diff --git a/webprofile.go b/webprofile.go index 09b455c..66c3eec 100644 --- a/webprofile.go +++ b/webprofile.go @@ -1,6 +1,7 @@ package paypal import ( + "context" "fmt" "net/http" ) @@ -10,9 +11,9 @@ import ( // Allows for the customisation of the payment experience // // Endpoint: POST /v1/payment-experience/web-profiles -func (c *Client) CreateWebProfile(wp WebProfile) (*WebProfile, error) { +func (c *Client) CreateWebProfile(ctx context.Context, wp WebProfile) (*WebProfile, error) { url := fmt.Sprintf("%s%s", c.APIBase, "/v1/payment-experience/web-profiles") - req, err := c.NewRequest("POST", url, wp) + req, err := c.NewRequest(ctx, "POST", url, wp) response := &WebProfile{} if err != nil { @@ -29,11 +30,11 @@ func (c *Client) CreateWebProfile(wp WebProfile) (*WebProfile, error) { // GetWebProfile gets an exists payment experience from Paypal // // Endpoint: GET /v1/payment-experience/web-profiles/ -func (c *Client) GetWebProfile(profileID string) (*WebProfile, error) { +func (c *Client) GetWebProfile(ctx context.Context, profileID string) (*WebProfile, error) { var wp WebProfile url := fmt.Sprintf("%s%s%s", c.APIBase, "/v1/payment-experience/web-profiles/", profileID) - req, err := http.NewRequest("GET", url, nil) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { return &wp, err @@ -53,11 +54,11 @@ func (c *Client) GetWebProfile(profileID string) (*WebProfile, error) { // GetWebProfiles retreieves web experience profiles from Paypal // // Endpoint: GET /v1/payment-experience/web-profiles -func (c *Client) GetWebProfiles() ([]WebProfile, error) { +func (c *Client) GetWebProfiles(ctx context.Context) ([]WebProfile, error) { var wps []WebProfile url := fmt.Sprintf("%s%s", c.APIBase, "/v1/payment-experience/web-profiles") - req, err := http.NewRequest("GET", url, nil) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { return wps, err @@ -73,7 +74,7 @@ func (c *Client) GetWebProfiles() ([]WebProfile, error) { // SetWebProfile sets a web experience profile in Paypal with given id // // Endpoint: PUT /v1/payment-experience/web-profiles -func (c *Client) SetWebProfile(wp WebProfile) error { +func (c *Client) SetWebProfile(ctx context.Context, wp WebProfile) error { if wp.ID == "" { return fmt.Errorf("paypal: no ID specified for WebProfile") @@ -81,7 +82,7 @@ func (c *Client) SetWebProfile(wp WebProfile) error { url := fmt.Sprintf("%s%s%s", c.APIBase, "/v1/payment-experience/web-profiles/", wp.ID) - req, err := c.NewRequest("PUT", url, wp) + req, err := c.NewRequest(ctx, "PUT", url, wp) if err != nil { return err @@ -97,11 +98,11 @@ func (c *Client) SetWebProfile(wp WebProfile) error { // DeleteWebProfile deletes a web experience profile from Paypal with given id // // Endpoint: DELETE /v1/payment-experience/web-profiles -func (c *Client) DeleteWebProfile(profileID string) error { +func (c *Client) DeleteWebProfile(ctx context.Context, profileID string) error { url := fmt.Sprintf("%s%s%s", c.APIBase, "/v1/payment-experience/web-profiles/", profileID) - req, err := c.NewRequest("DELETE", url, nil) + req, err := c.NewRequest(ctx, "DELETE", url, nil) if err != nil { return err