From 6ebb0352bc5f7327134be66bff57bb66b9156313 Mon Sep 17 00:00:00 2001 From: Alex Pliutau Date: Mon, 3 Jun 2024 09:53:55 +0200 Subject: [PATCH] Remove deprecated endpoints --- LICENSE.md | 2 +- README.md | 113 +----------- billing.go | 161 ---------------- billing_agreements.go | 115 ------------ capture.go | 23 --- client_test.go | 3 + go.mod | 10 +- go.sum | 13 +- integration_test.go | 417 ------------------------------------------ order_test.go | 66 ------- patch.go | 7 - payout.go | 5 - sale.go | 41 ----- types.go | 70 +------ 14 files changed, 36 insertions(+), 1010 deletions(-) delete mode 100644 billing.go delete mode 100644 billing_agreements.go delete mode 100644 capture.go delete mode 100644 integration_test.go delete mode 100644 order_test.go delete mode 100644 patch.go diff --git a/LICENSE.md b/LICENSE.md index 989adc5..14bd593 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2021 Aliaksandr Pliutau +Copyright (c) 2024 Aliaksandr Pliutau Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index f17f7a5..fd630c3 100644 --- a/README.md +++ b/README.md @@ -2,112 +2,13 @@ # Go client for PayPal REST API -## Coverage +## Paypal REST API Docs -### Auth +[Get started with PayPal REST APIs](https://developer.paypal.com/api/rest/) -* POST /v1/oauth2/token - -### /v1/payments - -* POST /v1/payments/payouts -* GET /v1/payments/payouts/:id -* GET /v1/payments/payouts-item/:id -* POST /v1/payments/payouts-item/:id/cancel -* GET /v1/payments/sale/:id -* POST /v1/payments/sale/:id/refund -* GET /v1/payments/billing-plans -* POST /v1/payments/billing-plans -* PATCH /v1/payments/billing-plans/:id -* POST /v1/payments/billing-agreements -* POST /v1/payments/billing-agreements/:token/agreement-execute - -### /v2/payments - -* GET /v2/payments/authorizations/:id -* GET /v2/payments/captures/:id -* POST /v2/payments/authorizations/:id/capture -* POST /v2/payments/authorizations/:id/void -* POST /v2/payments/authorizations/:id/reauthorize -* GET /v2/payments/refund/:id - -### Identity -* POST /v1/identity/openidconnect/tokenservice -* GET /v1/identity/openidconnect/userinfo/?schema=:schema - -### /v1/payment-experience - -* GET /v1/payment-experience/web-profiles -* POST /v1/payment-experience/web-profiles -* GET /v1/payment-experience/web-profiles/:id -* PUT /v1/payment-experience/web-profiles/:id -* DELETE /v1/payment-experience/web-profiles/:id - -### /v1/reporting - -* POST /v1/reporting/transactions - -### Vault - -* POST /v1/vault/credit-cards -* DELETE /v1/vault/credit-cards/:id -* PATCH /v1/vault/credit-cards/:id -* GET /v1/vault/credit-cards/:id -* GET /v1/vault/credit-cards - -### Checkout - -* POST /v2/checkout/orders -* GET /v2/checkout/orders/:id -* PATCH /v2/checkout/orders/:id -* POST /v2/checkout/orders/:id/authorize -* POST /v2/checkout/orders/:id/capture - -### Notifications -* POST /v1/notifications/webhooks -* GET /v1/notifications/webhooks -* GET /v1/notifications/webhooks/:id -* PATCH /v1/notifications/webhooks/:id -* DELETE /v1/notifications/webhooks/:id -* POST /v1/notifications/verify-webhook-signature - -### Products (Catalog) - -* POST /v1/catalogs/products -* PATCH /v1/catalogs/products/:id -* GET /v1/catalogs/products/:id -* GET /v1/catalogs/products - -### Billing Plans (Subscriptions) - -* POST /v1/billing/plans -* PATCH /v1/billing/plans/:id -* GET /v1/billing/plans/:id -* GET /v1/billing/plans -* POST /v1/billing/plans/:id/activate -* POST /v1/billing/plans/:id/deactivate -* POST /v1/billing/plans/:id/update-pricing-schemes - -### Subscriptions - -* POST /v1/billing/subscriptions -* PATCH /v1/billing/subscriptions/:id -* GET /v1/billing/subscriptions/:id -* POST /v1/billing/subscriptions/:id/activate -* POST /v1/billing/subscriptions/:id/cancel -* POST /v1/billing/subscriptions/:id/revise -* POST /v1/billing/subscriptions/:id/capture -* POST /v1/billing/subscriptions/:id/suspend -* GET /v1/billing/subscriptions/:id/transactions - -### Invoicing - -* POST /v2/invoicing/generate-next-invoice-number -* GET /v2/invoicing/invoices/:id - ## Missing endpoints -It is possible that some endpoints are missing in this Client, but you can use built-in `paypal` functions to perform a request: `NewClient -> NewRequest -> SendWithAuth` +It is possible that some endpoints are missing in this client, but you can use built-in `paypal` functions to perform a request: `NewClient -> NewRequest -> SendWithAuth` ## Usage @@ -373,16 +274,19 @@ c.ListWebhooks(paypal.AncorTypeApplication) ``` ### Generate Next Invoice Number + ```go // GenerateInvoiceNumber: generates the next invoice number that is available to the merchant. c.GenerateInvoiceNumber(ctx) // might return something like "0001" or "0010". ``` ### Get Invoice Details by ID + ```go // the second argument is an ID, it should be valid invoice, err := c.GetInvoiceDetails(ctx, "INV2-XFXV-YW42-ZANU-4F33") ``` + * for now, we are yet to implement the ShowAllInvoices endpoint, so use the following cURL request for the same(this gives you the list of invoice-IDs for this customer) ```bash curl -v -X GET https://api-m.sandbox.paypal.com/v2/invoicing/invoices?total_required=true \ @@ -407,5 +311,6 @@ Current contributors: ## Tests -* Unit tests: `go test -v ./...` -* Integration tests: `go test -tags=integration` +``` +go test -v ./... +``` diff --git a/billing.go b/billing.go deleted file mode 100644 index 9b9d25e..0000000 --- a/billing.go +++ /dev/null @@ -1,161 +0,0 @@ -package paypal - -import ( - "context" - "errors" - "fmt" - "net/http" - "time" -) - -type ( - // CreateBillingResponse struct - CreateBillingResponse struct { - ID string `json:"id,omitempty"` - State string `json:"state,omitempty"` - PaymentDefinitions []PaymentDefinition `json:"payment_definitions,omitempty"` - MerchantPreferences MerchantPreferences `json:"merchant_preferences,omitempty"` - CreateTime time.Time `json:"create_time,omitempty"` - UpdateTime time.Time `json:"update_time,omitempty"` - Links []Link `json:"links,omitempty"` - } - - // 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"` - Links []Link `json:"links,omitempty"` - StartTime time.Time `json:"start_time,omitempty"` - } - - // CreateAgreementResp. - // - // Deprecated: use CreateAgreementResponse instead. - CreateAgreementResp = CreateAgreementResponse - - // BillingPlanListParams - BillingPlanListParams struct { - ListParams - Status string `json:"status,omitempty"` //Allowed values: CREATED, ACTIVE, INACTIVE, ALL. - } - - // BillingPlanListResponse - BillingPlanListResponse struct { - SharedListResponse - Plans []BillingPlan `json:"plans,omitempty"` - } - - // BillingPlanListResp. - // - // Deprecated: use BillingPlanListResponse instead. - BillingPlanListResp = BillingPlanListResponse -) - -// CreateBillingPlan creates a billing plan in Paypal -// Endpoint: POST /v1/payments/billing-plans -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 - } - err = c.SendWithAuth(req, response) - return response, err -} - -// UpdateBillingPlan updates values inside a billing plan -// Endpoint: PATCH /v1/payments/billing-plans -func (c *Client) UpdateBillingPlan(ctx context.Context, planId string, pathValues map[string]map[string]interface{}) error { - var patchData []Patch - for path, data := range pathValues { - patchData = append(patchData, Patch{ - Operation: "replace", - Path: path, - Value: data, - }) - } - - 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 - } - err = c.SendWithAuth(req, nil) - return err -} - -// ActivatePlan activates a billing plan -// By default, a new plan is not activated -// Endpoint: PATCH /v1/payments/billing-plans/ -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 -// Deprecated: Use POST /v1/billing-agreements/agreements -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(ctx, http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-agreements"), a) - response := &CreateAgreementResponse{} - if err != nil { - return response, err - } - err = c.SendWithAuth(req, response) - return response, err -} - -// 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(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 { - return response, err - } - - req.SetBasicAuth(c.ClientID, c.Secret) - req.Header.Set("Authorization", "Bearer "+c.Token.Token) - - if err = c.SendWithAuth(req, response); err != nil { - return response, err - } - - if response.ID == "" { - return response, errors.New("Unable to execute agreement with token=" + token) - } - - return response, err -} - -// ListBillingPlans lists billing-plans -// Endpoint: GET /v1/payments/billing-plans -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 - } - - q := req.URL.Query() - q.Add("page", bplp.Page) - q.Add("page_size", bplp.PageSize) - q.Add("status", bplp.Status) - q.Add("total_required", bplp.TotalRequired) - req.URL.RawQuery = q.Encode() - - err = c.SendWithAuth(req, response) - return response, err -} diff --git a/billing_agreements.go b/billing_agreements.go deleted file mode 100644 index a2afc55..0000000 --- a/billing_agreements.go +++ /dev/null @@ -1,115 +0,0 @@ -package paypal - -import ( - "context" - "fmt" -) - -// CreatePaypalBillingAgreementToken - Use this call to create a billing agreement token -// Endpoint: POST /v1/billing-agreements/agreement-tokens -// Deprecated: use CreateBillingAgreementToken instead -func (c *Client) CreatePaypalBillingAgreementToken( - ctx context.Context, - description *string, - shippingAddress *ShippingAddress, - payer *Payer, - plan *BillingPlan, -) (*BillingAgreementToken, error) { - return c.CreateBillingAgreementToken(ctx, description, shippingAddress, payer, plan) -} - -// CreateBillingAgreementToken - Use this call to create a billing agreement token -// Endpoint: POST /v1/billing-agreements/agreement-tokens -func (c *Client) CreateBillingAgreementToken( - ctx context.Context, - description *string, - shippingAddress *ShippingAddress, - payer *Payer, - plan *BillingPlan, -) (*BillingAgreementToken, error) { - type createBARequest struct { - Description *string `json:"description,omitempty"` - ShippingAddress *ShippingAddress `json:"shipping_address,omitempty"` - Payer *Payer `json:"payer"` - Plan *BillingPlan `json:"plan"` - } - - billingAgreementToken := &BillingAgreementToken{} - - req, err := c.NewRequest( - ctx, - "POST", - fmt.Sprintf("%s%s", c.APIBase, "/v1/billing-agreements/agreement-tokens"), - createBARequest{Description: description, ShippingAddress: shippingAddress, Payer: payer, Plan: plan}) - if err != nil { - return nil, err - } - - if err = c.SendWithAuth(req, billingAgreementToken); err != nil { - return billingAgreementToken, err - } - - return billingAgreementToken, nil -} - -// CreatePaypalBillingAgreementFromToken - Use this call to create a billing agreement -// Endpoint: POST /v1/billing-agreements/agreements -// Deprecated: use CreateBillingAgreementFromToken instead -func (c *Client) CreatePaypalBillingAgreementFromToken( - ctx context.Context, - tokenID string, -) (*BillingAgreementFromToken, error) { - return c.CreateBillingAgreementFromToken(ctx, tokenID) -} - -// CreateBillingAgreementFromToken - Use this call to create a billing agreement -// Endpoint: POST /v1/billing-agreements/agreements -func (c *Client) CreateBillingAgreementFromToken( - ctx context.Context, - tokenID string, -) (*BillingAgreementFromToken, error) { - type createBARequest struct { - TokenID string `json:"token_id"` - } - - billingAgreement := &BillingAgreementFromToken{} - - req, err := c.NewRequest( - ctx, - "POST", - fmt.Sprintf("%s%s", c.APIBase, "/v1/billing-agreements/agreements"), - createBARequest{TokenID: tokenID}) - if err != nil { - return nil, err - } - - if err = c.SendWithAuth(req, billingAgreement); err != nil { - return billingAgreement, err - } - - return billingAgreement, nil -} - -// CancelBillingAgreement - Use this call to cancel a billing agreement -// Endpoint: POST /v1/billing-agreements/agreements/{agreement_id}/cancel -func (c *Client) CancelBillingAgreement( - ctx context.Context, - billingAgreementID string, -) error { - type cancelBARequest struct{} - - req, err := c.NewRequest( - ctx, - "POST", - fmt.Sprintf("%s%s%s%s", c.APIBase, "/v1/billing-agreements/agreements/", billingAgreementID, "/cancel"), - cancelBARequest{}) - if err != nil { - return err - } - - if err = c.SendWithAuth(req, nil); err != nil { - return err - } - - return nil -} diff --git a/capture.go b/capture.go deleted file mode 100644 index cec5cea..0000000 --- a/capture.go +++ /dev/null @@ -1,23 +0,0 @@ -package paypal - -import ( - "context" - "fmt" -) - -// GetCapturedPaymentDetails. -// Endpoint: GET /v1/payments/capture/:id -func (c *Client) GetCapturedPaymentDetails(ctx context.Context, id string) (*Capture, error) { - res := &Capture{} - - req, err := c.NewRequest(ctx, "GET", fmt.Sprintf("%s%s%s", c.APIBase, "/v1/payments/capture/", id), nil) - if err != nil { - return res, err - } - - if err = c.SendWithAuth(req, res); err != nil { - return res, err - } - - return res, nil -} diff --git a/client_test.go b/client_test.go index d18fa4f..bfcd6b1 100644 --- a/client_test.go +++ b/client_test.go @@ -15,6 +15,9 @@ import ( const alphabet = "abcedfghijklmnopqrstuvwxyz" +var testClientID = "AXy9orp-CDaHhBZ9C78QHW2BKZpACgroqo85_NIOa9mIfJ9QnSVKzY-X_rivR_fTUUr6aLjcJsj6sDur" +var testSecret = "EBoIiUSkCKeSk49hHSgTem1qnjzzJgRQHDEHvGpzlLEf_nIoJd91xu8rPOBDCdR_UYNKVxJE-UgS2iCw" + func RandomString(n int) string { var sb strings.Builder k := len(alphabet) diff --git a/go.mod b/go.mod index e025f4e..ec346a0 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,11 @@ module github.com/plutov/paypal/v4 -go 1.13 +go 1.22 -require github.com/stretchr/testify v1.6.0 +require github.com/stretchr/testify v1.9.0 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index e357f9b..60ce688 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,10 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho= -github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integration_test.go b/integration_test.go deleted file mode 100644 index afd1960..0000000 --- a/integration_test.go +++ /dev/null @@ -1,417 +0,0 @@ -// +build integration - -package paypal - -import ( - "context" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -// All test values are defined here -var testClientID = "AXy9orp-CDaHhBZ9C78QHW2BKZpACgroqo85_NIOa9mIfJ9QnSVKzY-X_rivR_fTUUr6aLjcJsj6sDur" -var testSecret = "EBoIiUSkCKeSk49hHSgTem1qnjzzJgRQHDEHvGpzlLEf_nIoJd91xu8rPOBDCdR_UYNKVxJE-UgS2iCw" -var testUserID = "https://www.paypal.com/webapps/auth/identity/user/VBqgHcgZwb1PBs69ybjjXfIW86_Hr93aBvF_Rgbh2II" -var testCardID = "CARD-54E6956910402550WKGRL6EA" - -var testProductId = "" // will be fetched in func TestProduct(t *testing.T) -var testBillingPlan = "" // will be fetched in func TestSubscriptionPlans(t *testing.T) - -func TestGetAccessToken(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - token, err := c.GetAccessToken(context.Background()) - if err != nil { - t.Errorf("Not expected error for GetAccessToken(), got %s", err.Error()) - } - if token.Token == "" { - t.Errorf("Expected non-empty token for GetAccessToken()") - } -} - -func TestGetUserInfo(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken(context.Background()) - - 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) - } -} - -func TestCreateVenmoPayout(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken(context.Background()) - - payout := Payout{ - SenderBatchHeader: &SenderBatchHeader{ - SenderBatchID: "Payouts_2018_100007", - EmailSubject: "You have a payout!", - EmailMessage: "You have received a payout! Thanks for using our service!", - }, - Items: []PayoutItem{ - { - RecipientType: "EMAIL", - RecipientWallet: VenmoRecipientWallet, - Receiver: "receiver@example.com", - Amount: &AmountPayout{ - Value: "9.87", - Currency: "USD", - }, - Note: "Thanks for your patronage!", - SenderItemID: "201403140001", - }, - }, - } - - res, err := c.CreatePayout(context.Background(), payout) - assert.NoError(t, err, "should accept venmo wallet") - assert.Greater(t, len(res.Items), 0) -} - -func TestCreatePayout(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken(context.Background()) - - payout := Payout{ - SenderBatchHeader: &SenderBatchHeader{ - SenderBatchID: "Payouts_2018_100007", - EmailSubject: "You have a payout!", - EmailMessage: "You have received a payout! Thanks for using our service!", - }, - Items: []PayoutItem{ - { - RecipientType: "EMAIL", - Receiver: "receiver@example.com", - Amount: &AmountPayout{ - Value: "9.87", - Currency: "USD", - }, - Note: "Thanks for your patronage!", - SenderItemID: "201403140001", - }, - }, - } - - c.CreatePayout(context.Background(), payout) -} - -func TestStoreCreditCard(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken(context.Background()) - - r1, e1 := c.StoreCreditCard(context.Background(), CreditCard{}) - if e1 == nil || r1 != nil { - t.Errorf("Error is expected for invalid CC") - } - - r2, e2 := c.StoreCreditCard(context.Background(), CreditCard{ - Number: "4417119669820331", - Type: "visa", - ExpireMonth: "11", - ExpireYear: "2020", - CVV2: "874", - FirstName: "Foo", - LastName: "Bar", - }) - if e2 != nil || r2 == nil { - t.Errorf("200 code expected for valid CC card. Error: %v", e2) - } -} - -func TestDeleteCreditCard(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken(context.Background()) - - e1 := c.DeleteCreditCard(context.Background(), "") - if e1 == nil { - t.Errorf("Error is expected for invalid CC ID") - } -} - -func TestGetCreditCard(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken(context.Background()) - - r1, e1 := c.GetCreditCard(context.Background(), "BBGGG") - if e1 == nil || r1 != nil { - t.Errorf("Error is expected for invalid CC, got CC %v", r1) - } -} - -func TestGetCreditCards(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken(context.Background()) - - r1, e1 := c.GetCreditCards(context.Background(), nil) - if e1 != nil || r1 == nil { - t.Errorf("200 code expected. Error: %v", e1) - } - - r2, e2 := c.GetCreditCards(context.Background(), &CreditCardsFilter{ - Page: 2, - PageSize: 7, - }) - if e2 != nil || r2 == nil { - t.Errorf("200 code expected. Error: %v", e2) - } -} - -func TestPatchCreditCard(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken(context.Background()) - - r1, e1 := c.PatchCreditCard(context.Background(), testCardID, nil) - if e1 == nil || r1 != nil { - t.Errorf("Error is expected for empty update info") - } -} - -// Creates, gets, and deletes single webhook -func TestCreateAndGetWebhook(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken(context.Background()) - - payload := &CreateWebhookRequest{ - URL: "https://example.com/paypal_webhooks", - EventTypes: []WebhookEventType{ - WebhookEventType{ - Name: "PAYMENT.AUTHORIZATION.CREATED", - }, - }, - } - - createdWebhook, err := c.CreateWebhook(context.Background(), payload) - if err != nil { - t.Errorf("Webhook couldn't be created, error %v", err) - } - - _, err = c.GetWebhook(context.Background(), createdWebhook.ID) - if err != nil { - t.Errorf("An error occurred while getting webhook, error %v", err) - } - - err = c.DeleteWebhook(context.Background(), createdWebhook.ID) - if err != nil { - t.Errorf("An error occurred while webhooks deletion, error %v", err) - } -} - -// Creates, updates, and deletes single webhook -func TestCreateAndUpdateWebhook(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken(context.Background()) - - creationPayload := &CreateWebhookRequest{ - URL: "https://example.com/paypal_webhooks", - EventTypes: []WebhookEventType{ - WebhookEventType{ - Name: "PAYMENT.AUTHORIZATION.CREATED", - }, - }, - } - - createdWebhook, err := c.CreateWebhook(context.Background(), creationPayload) - if err != nil { - t.Errorf("Webhook couldn't be created, error %v", err) - } - - updatePayload := []WebhookField{ - WebhookField{ - Operation: "replace", - Path: "/event_types", - Value: []interface{}{ - map[string]interface{}{ - "name": "PAYMENT.SALE.REFUNDED", - }, - }, - }, - } - - _, err = c.UpdateWebhook(context.Background(), createdWebhook.ID, updatePayload) - if err != nil { - t.Errorf("Couldn't update webhook, error %v", err) - } - - err = c.DeleteWebhook(context.Background(), createdWebhook.ID) - if err != nil { - t.Errorf("An error occurred while webhooks deletion, error %v", err) - } -} - -func TestListWebhooks(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken(context.Background()) - - _, err := c.ListWebhooks(context.Background(), AncorTypeApplication) - if err != nil { - t.Errorf("Cannot registered list webhooks, error %v", err) - } -} - -func TestProduct(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken(context.Background()) - - //create a product - productData := Product{ - Name: "Test Product", - Description: "A Test Product", - Category: ProductCategorySoftware, - Type: ProductTypeService, - ImageUrl: "https://example.com/image.png", - HomeUrl: "https://example.com", - } - - productCreateResponse, err := c.CreateProduct(context.Background(), productData) - assert.Equal(t, nil, err) - - testProductId = productCreateResponse.ID - - //update the product - productData.ID = productCreateResponse.ID - productData.Description = "Updated product" - - err = c.UpdateProduct(context.Background(), productData) - assert.Equal(t, nil, err) - - //get product data - 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(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(context.Background()) - - //create a product - newSubscriptionPlan := SubscriptionPlan{ - ProductId: testProductId, - Name: "Test subscription plan", - Status: SubscriptionPlanStatusCreated, - Description: "Integration test subscription plan", - BillingCycles: []BillingCycle{ - { - PricingScheme: PricingScheme{ - Version: 1, - FixedPrice: Money{ - Currency: "EUR", - Value: "5", - }, - CreateTime: time.Now(), - UpdateTime: time.Now(), - }, - Frequency: Frequency{ - IntervalUnit: IntervalUnitYear, - IntervalCount: 1, - }, - TenureType: TenureTypeRegular, - Sequence: 1, - TotalCycles: 0, - }, - }, - PaymentPreferences: &PaymentPreferences{ - AutoBillOutstanding: false, - SetupFee: nil, - SetupFeeFailureAction: SetupFeeFailureActionCancel, - PaymentFailureThreshold: 0, - }, - Taxes: &Taxes{ - Percentage: "19", - Inclusive: false, - }, - QuantitySupported: false, - } - - //test create new plan - 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(context.Background(), newSubscriptionPlan) - assert.Equal(t, nil, err) - - //test get plan information - 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(context.Background(), newSubscriptionPlan.ID) - assert.Equal(t, nil, err) - - //test deactivate plan - err = c.DeactivateSubscriptionPlans(context.Background(), newSubscriptionPlan.ID) - assert.Equal(t, nil, err) - - //reactivate this plan for next next (subscription) - err = c.ActivateSubscriptionPlan(context.Background(), newSubscriptionPlan.ID) - assert.Equal(t, nil, err) - - //test upadte plan pricing - err = c.UpdateSubscriptionPlanPricing(context.Background(), newSubscriptionPlan.ID, []PricingSchemeUpdate{ - { - BillingCycleSequence: 1, - PricingScheme: PricingScheme{ - Version: 1, - FixedPrice: Money{ - Currency: "EUR", - Value: "6", - }, - CreateTime: time.Now(), - UpdateTime: time.Now(), - }, - }, - }) - assert.Equal(t, nil, err) - - //test update pricing scheme - updatedPricingPlan, err := c.GetSubscriptionPlan(context.Background(), newSubscriptionPlan.ID) - assert.Equal(t, nil, err) - assert.Equal(t, "6.0", updatedPricingPlan.BillingCycles[0].PricingScheme.FixedPrice.Value) - -} - -func TestSubscription(t *testing.T) { - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - c.GetAccessToken(context.Background()) - - newSubscription := SubscriptionBase{ - PlanID: testBillingPlan, - } - - //create new subscription - newSubResponse, err := c.CreateSubscription(context.Background(), newSubscription) - assert.Equal(t, nil, err) - assert.NotEqual(t, "", newSubResponse.ID) - - //get subscription details - 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_test.go b/order_test.go deleted file mode 100644 index 88ed9f8..0000000 --- a/order_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package paypal - -import ( - "context" - "testing" -) - -var testClientID = "AXy9orp-CDaHhBZ9C78QHW2BKZpACgroqo85_NIOa9mIfJ9QnSVKzY-X_rivR_fTUUr6aLjcJsj6sDur" -var testSecret = "EBoIiUSkCKeSk49hHSgTem1qnjzzJgRQHDEHvGpzlLEf_nIoJd91xu8rPOBDCdR_UYNKVxJE-UgS2iCw" - -func TestUpdateOrder(t *testing.T) { - ctx := context.Background() - - c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) - _, _ = c.GetAccessToken(ctx) - - orderResponse, err := c.CreateOrder( - ctx, - OrderIntentCapture, - []PurchaseUnitRequest{ - { - Amount: &PurchaseUnitAmount{ - Value: "7.00", - Currency: "USD", - }, - }, - }, - &CreateOrderPayer{}, - &ApplicationContext{}, - ) - if err != nil { - t.Errorf("Not expected error for CreateOrder(), got %s", err.Error()) - } - - order, err := c.GetOrder(ctx, orderResponse.ID) - if err != nil { - t.Errorf("Not expected error for GetOrder(), got %s", err.Error()) - } - - if order.PurchaseUnits[0].Amount.Value != "7.00" { - t.Errorf("CreateOrder amount incorrect") - } - - err = c.UpdateOrder( - ctx, - orderResponse.ID, - "replace", - "/purchase_units/@reference_id=='default'/amount", - map[string]string{ - "currency_code": "USD", - "value": "2.00", - }, - ) - if err != nil { - t.Errorf("Not expected error for UpdateOrder(), got %s", err.Error()) - } - - order, err = c.GetOrder(ctx, orderResponse.ID) - if err != nil { - t.Errorf("Not expected error for GetOrder(), got %s", err.Error()) - } - - if order.PurchaseUnits[0].Amount.Value != "2.00" { - t.Errorf("CreateOrder after update amount incorrect") - } -} diff --git a/patch.go b/patch.go deleted file mode 100644 index 6739bd9..0000000 --- a/patch.go +++ /dev/null @@ -1,7 +0,0 @@ -package paypal - -type Patch struct { - Operation string `json:"op"` - Path string `json:"path"` - Value interface{} `json:"value"` -} diff --git a/payout.go b/payout.go index e74c920..b749d17 100644 --- a/payout.go +++ b/payout.go @@ -23,11 +23,6 @@ func (c *Client) CreatePayout(ctx context.Context, p Payout) (*PayoutResponse, e 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 diff --git a/sale.go b/sale.go index 0d81cb9..843ccec 100644 --- a/sale.go +++ b/sale.go @@ -5,47 +5,6 @@ import ( "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(ctx context.Context, saleID string) (*Sale, error) { - sale := &Sale{} - - req, err := c.NewRequest(ctx, "GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/sale/"+saleID), nil) - if err != nil { - return sale, err - } - - if err = c.SendWithAuth(req, sale); err != nil { - return sale, err - } - - return sale, nil -} - -// 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(ctx context.Context, saleID string, a *Amount) (*Refund, error) { - type refundRequest struct { - Amount *Amount `json:"amount"` - } - - refund := &Refund{} - - 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 - } - - if err = c.SendWithAuth(req, refund); err != nil { - return refund, err - } - - return refund, nil -} - // GetRefund by ID // Use it to look up details of a specific refund on direct and captured payments. // Endpoint: GET /v2/payments/refund/ID diff --git a/types.go b/types.go index d695dd1..6d07587 100644 --- a/types.go +++ b/types.go @@ -587,32 +587,6 @@ type ( SenderBatchHeader *SenderBatchHeader `json:"sender_batch_header,omitempty"` } - // BillingAgreement struct - BillingAgreement struct { - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - StartDate JSONTime `json:"start_date,omitempty"` - Plan BillingPlan `json:"plan,omitempty"` - Payer Payer `json:"payer,omitempty"` - ShippingAddress *ShippingAddress `json:"shipping_address,omitempty"` - OverrideMerchantPreferences *MerchantPreferences `json:"override_merchant_preferences,omitempty"` - } - - // BillingAgreementFromToken struct - BillingAgreementFromToken struct { - ID string `json:"id,omitempty"` - Description string `json:"description,omitempty"` - Payer *Payer `json:"payer,omitempty"` - Plan BillingPlan `json:"plan,omitempty"` - Links []Link `json:"links,omitempty"` - } - - // BillingAgreementToken response struct - BillingAgreementToken struct { - Links []Link `json:"links,omitempty"` - TokenID string `json:"token_id,omitempty"` - } - // Plan struct Plan struct { ID string `json:"id"` @@ -1415,38 +1389,6 @@ type ( Value interface{} `json:"value"` } - // Resource is a mix of fields from several webhook resource types. - // - // Deprecated: Add implementation of specific resource types in your own - // code and don't use this catch all struct, you show know which resource - // type you are expecting and handle that type only. - // - // Every resource struct type should be unique for every combination of - // "resource_type"/"resource_version" combination of the Event type / - // webhook message. - Resource struct { - ID string `json:"id,omitempty"` - Status string `json:"status,omitempty"` - StatusDetails *CaptureStatusDetails `json:"status_details,omitempty"` - Amount *PurchaseUnitAmount `json:"amount,omitempty"` - UpdateTime string `json:"update_time,omitempty"` - CreateTime string `json:"create_time,omitempty"` - ExpirationTime string `json:"expiration_time,omitempty"` - SellerProtection *SellerProtection `json:"seller_protection,omitempty"` - FinalCapture bool `json:"final_capture,omitempty"` - SellerPayableBreakdown *CaptureSellerBreakdown `json:"seller_payable_breakdown,omitempty"` - SellerReceivableBreakdown *SellerReceivableBreakdown `json:"seller_receivable_breakdown,omitempty"` - NoteToPayer string `json:"note_to_payer,omitempty"` - CustomID string `json:"custom_id,omitempty"` - PartnerClientID string `json:"partner_client_id,omitempty"` - MerchantID string `json:"merchant_id,omitempty"` - Intent string `json:"intent,omitempty"` - BillingAgreementID *string `json:"billing_agreement_id,omitempty"` - PurchaseUnits []*PurchaseUnitRequest `json:"purchase_units,omitempty"` - Payer *PayerWithNameAndPhone `json:"payer,omitempty"` - Links []Link `json:"links,omitempty"` - } - CaptureSellerBreakdown struct { GrossAmount PurchaseUnitAmount `json:"gross_amount"` PayPalFee PurchaseUnitAmount `json:"paypal_fee"` @@ -1615,6 +1557,12 @@ type ( TotalPages int `json:"total_pages,omitempty"` Links []Link `json:"links,omitempty"` } + + Patch struct { + Operation string `json:"op"` + Path string `json:"path"` + Value interface{} `json:"value"` + } ) // Error method implementation for ErrorResponse struct @@ -1652,6 +1600,6 @@ func (e *expirationTime) UnmarshalJSON(b []byte) error { // Convert ExpirationTime to time.Duration func (e *expirationTime) ToDuration() time.Duration { - seconds := int64(*e) - return time.Duration(seconds) * time.Second -} \ No newline at end of file + seconds := int64(*e) + return time.Duration(seconds) * time.Second +}