From b6d36be128258e20748f1903214ba164de334925 Mon Sep 17 00:00:00 2001 From: VictorAvelar Date: Tue, 29 Jun 2021 21:59:50 +0200 Subject: [PATCH 1/2] Update dependencies --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b4ec7b84..7eb3208a 100644 --- a/go.mod +++ b/go.mod @@ -4,5 +4,5 @@ go 1.15 require ( github.com/google/go-querystring v1.1.0 - golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c + golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 ) diff --git a/go.sum b/go.sum index 5519de91..71816d34 100644 --- a/go.sum +++ b/go.sum @@ -186,8 +186,8 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 56c091ddaa6b13dcda2a61b70ce6bc4a0f4f49df Mon Sep 17 00:00:00 2001 From: VictorAvelar Date: Thu, 1 Jul 2021 12:20:31 +0200 Subject: [PATCH 2/2] Add payment links API --- mollie/mollie.go | 2 + mollie/payment_links.go | 130 +++++++++++++++++++++++++++++++++++ mollie/payment_links_test.go | 90 ++++++++++++++++++++++++ testdata/payment_links.go | 121 ++++++++++++++++++++++++++++++++ 4 files changed, 343 insertions(+) create mode 100644 mollie/payment_links.go create mode 100644 mollie/payment_links_test.go create mode 100644 testdata/payment_links.go diff --git a/mollie/mollie.go b/mollie/mollie.go index d5a3e053..5d6d4d16 100644 --- a/mollie/mollie.go +++ b/mollie/mollie.go @@ -57,6 +57,7 @@ type Client struct { Mandates *MandatesService Permissions *PermissionsService Onboarding *OnboardingService + PaymentLinks *PaymentLinksService } type service struct { @@ -189,6 +190,7 @@ func NewClient(baseClient *http.Client, c *Config) (mollie *Client, err error) { mollie.Mandates = (*MandatesService)(&mollie.common) mollie.Permissions = (*PermissionsService)(&mollie.common) mollie.Onboarding = (*OnboardingService)(&mollie.common) + mollie.PaymentLinks = (*PaymentLinksService)(&mollie.common) // Parse authorization from specified environment variable tkn, ok := os.LookupEnv(c.auth) diff --git a/mollie/payment_links.go b/mollie/payment_links.go new file mode 100644 index 00000000..3738b71d --- /dev/null +++ b/mollie/payment_links.go @@ -0,0 +1,130 @@ +package mollie + +import ( + "encoding/json" + "fmt" + "net/http" + "time" + + "github.com/google/go-querystring/query" +) + +// PaymentLink is a resource that can be shared with your customers +// and will redirect them to them the payment page where they can +// complete the payment. +// +// See: https://docs.mollie.com/reference/v2/payment-links-api/get-payment-link +type PaymentLink struct { + ID string `json:"id,omitempty"` + Resource string `json:"resource,omitempty"` + Description string `json:"description,omitempty"` + ProfileID string `json:"profileId,omitempty"` + RedirectURL string `json:"redirectUrl,omitempty"` + WebhookURL string `json:"webhookUrl,omitempty"` + Mode Mode `json:"mode,omitempty"` + Amount Amount `json:"amount,omitempty"` + CreatedAt *time.Time `json:"createdAt,omitempty"` + PaidAt *time.Time `json:"paidAt,omitempty"` + UpdatedAt *time.Time `json:"updatedAt,omitempty"` + ExpiresAt *time.Time `json:"expiresAt,omitempty"` + Links PaymentLinkLinks `json:"_links,omitempty"` +} + +// PaymentLinkLinks describes all the possible links returned with +// a payment link struct. +// +// See: https://docs.mollie.com/reference/v2/payment-links-api/get-payment-link +type PaymentLinkLinks struct { + Self *URL `json:"self,omitempty` + Documentation *URL `json:"documentation,omitempty"` + PaymentLink *URL `json:"paymentLink,omitempty"` + Next *URL `json:"next,omitempty"` + Previous *URL `json:"previous,omitempty"` +} + +// PaymentLinkOptions represents query string parameters to modify +// the payment links requests. +type PaymentLinkOptions struct { + ProfileID string `url:"profileId,omitempty"` + From string `url:"from,omitemtpy"` + Limit int `url:"limit,omitempty"` +} + +type PaymentLinksList struct { + Count int `json:"count,omitempty"` + Links PaymentLinkLinks `json:"_links,omitempty"` + Embedded struct { + PaymentLinks []*PaymentLink `json:"payment_links,omitempty"` + } `json:"_embedded,omitempty"` +} + +// PaymentLinksService operates over the payment link resource. +type PaymentLinksService service + +// Get retrieves a single payment link object by its id/token. +// +// See: https://docs.mollie.com/reference/v2/payment-links-api/get-payment-link +func (pls *PaymentLinksService) Get(id string) (pl *PaymentLink, err error) { + req, err := pls.client.NewAPIRequest(http.MethodGet, fmt.Sprintf("v2/payment-links/%s", id), nil) + if err != nil { + return + } + + res, err := pls.client.Do(req) + if err != nil { + return + } + if err = json.Unmarshal(res.content, &pl); err != nil { + return + } + return +} + +// Create generates payment links that by default, unlike regular payments, do not expire. +// +// See: https://docs.mollie.com/reference/v2/payment-links-api/create-payment-link +func (pls *PaymentLinksService) Create(p PaymentLink, opts *PaymentLinkOptions) (np *PaymentLink, err error) { + u := "v2/payment-links" + if opts != nil { + v, _ := query.Values(opts) + u = fmt.Sprintf("%s?%s", u, v.Encode()) + } + req, err := pls.client.NewAPIRequest(http.MethodPost, u, p) + if err != nil { + return + } + + res, err := pls.client.Do(req) + if err != nil { + return + } + if err = json.Unmarshal(res.content, &np); err != nil { + return + } + return +} + +// List retrieves all payments links created with the current website profile, +// ordered from newest to oldest. +// +// See: https://docs.mollie.com/reference/v2/payment-links-api/list-payment-links +func (pls *PaymentLinksService) List(opts *PaymentLinkOptions) (pl *PaymentLinksList, err error) { + u := "v2/payment-links" + if opts != nil { + v, _ := query.Values(opts) + u = fmt.Sprintf("%s?%s", u, v.Encode()) + } + req, err := pls.client.NewAPIRequest(http.MethodGet, u, nil) + if err != nil { + return + } + + res, err := pls.client.Do(req) + if err != nil { + return + } + if err = json.Unmarshal(res.content, &pl); err != nil { + return + } + return +} diff --git a/mollie/payment_links_test.go b/mollie/payment_links_test.go new file mode 100644 index 00000000..07a4a244 --- /dev/null +++ b/mollie/payment_links_test.go @@ -0,0 +1,90 @@ +package mollie + +import ( + "net/http" + "testing" + + "github.com/VictorAvelar/mollie-api-go/v2/testdata" +) + +func TestPaymentLinkService_Get(t *testing.T) { + setup() + defer teardown() + _ = tClient.WithAuthenticationValue("test_token") + tMux.HandleFunc("/v2/payment-links/test_id", func(w http.ResponseWriter, r *http.Request) { + testHeader(t, r, AuthHeader, "Bearer test_token") + testMethod(t, r, "GET") + if _, ok := r.Header[AuthHeader]; !ok { + w.WriteHeader(http.StatusUnauthorized) + } + + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(testdata.GetPaymentLinkResponse)) + }) + + v, err := tClient.PaymentLinks.Get("test_id") + if err != nil { + t.Fatal(err) + } + + if v.Amount.Value != "24.95" { + t.Error("unexpected response") + } +} + +func TestPaymentLinkService_Create(t *testing.T) { + setup() + defer teardown() + _ = tClient.WithAuthenticationValue("test_token") + tMux.HandleFunc("/v2/payment-links", func(w http.ResponseWriter, r *http.Request) { + testHeader(t, r, AuthHeader, "Bearer test_token") + testMethod(t, r, "POST") + if _, ok := r.Header[AuthHeader]; !ok { + w.WriteHeader(http.StatusUnauthorized) + } + + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(testdata.CreatePaymentLinkResponse)) + }) + + v, err := tClient.PaymentLinks.Create( + PaymentLink{ + Description: "payment_test_desc", + }, + nil, + ) + if err != nil { + t.Fatal(err) + } + + if v.ID != "pl_4Y0eZitmBnQ6IDoMqZQKh" { + t.Fail() + } +} + +func TestPaymentLinkService_List(t *testing.T) { + setup() + defer teardown() + _ = tClient.WithAuthenticationValue("test_token") + tMux.HandleFunc("/v2/payment-links", func(w http.ResponseWriter, r *http.Request) { + testHeader(t, r, AuthHeader, "Bearer test_token") + testMethod(t, r, "GET") + if _, ok := r.Header[AuthHeader]; !ok { + w.WriteHeader(http.StatusUnauthorized) + } + + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(testdata.ListPaymentLinksResponse)) + }) + + v, err := tClient.PaymentLinks.List( + nil, + ) + if err != nil { + t.Fatal(err) + } + + if v.Count != 1 { + t.Fail() + } +} diff --git a/testdata/payment_links.go b/testdata/payment_links.go new file mode 100644 index 00000000..c80c4474 --- /dev/null +++ b/testdata/payment_links.go @@ -0,0 +1,121 @@ +package testdata + +// GetPaymentLink response sample. +const GetPaymentLinkResponse = `{ + "resource": "payment-link", + "id": "pl_4Y0eZitmBnQ6IDoMqZQKh", + "mode": "test", + "profileId": "pfl_QkEhN94Ba", + "createdAt": "2021-03-20T09:13:37+00:00", + "paidAt": "2021-03-21T09:13:37+00:00", + "updatedAt": "2021-03-21T09:13:37+00:00", + "expiresAt": null, + "amount": { + "value": "24.95", + "currency": "EUR" + }, + "description": "Bicycle tires", + "redirectUrl": "https://webshop.example.org/thanks", + "webhookUrl": "https://webshop.example.org/payment-links/webhook/", + "_links": { + "self": { + "href": "https://api.mollie.com/v2/payment-links/pl_4Y0eZitmBnQ6IDoMqZQKh", + "type": "application/json" + }, + "paymentLink": { + "href": "https://paymentlink.mollie.com/payment/4Y0eZitmBnQ6IDoMqZQKh/", + "type": "text/html" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/payment-links-api/get-payment-link", + "type": "text/html" + } + } +} +` + +const CreatePaymentLinkResponse = `{ + "resource": "payment-link", + "id": "pl_4Y0eZitmBnQ6IDoMqZQKh", + "mode": "test", + "profileId": "pfl_QkEhN94Ba", + "createdAt": "2021-03-20T09:13:37+00:00", + "paidAt": null, + "updatedAt": null, + "expiresAt": "2021-06-06T11:00:00+00:00", + "amount": { + "value": "24.95", + "currency": "EUR" + }, + "description": "Bicycle tires", + "redirectUrl": "https://webshop.example.org/thanks", + "webhookUrl": "https://webshop.example.org/payment-links/webhook/", + "_links": { + "self": { + "href": "https://api.mollie.com/v2/payment-links/pl_4Y0eZitmBnQ6IDoMqZQKh", + "type": "application/json" + }, + "paymentLink": { + "href": "https://paymentlink.mollie.com/payment/4Y0eZitmBnQ6IDoMqZQKh/", + "type": "text/html" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/payment-links-api/create-payment-link", + "type": "text/html" + } + } +}` + +const ListPaymentLinksResponse = `{ + "count": 1, + "_embedded": { + "payment_links": [ + { + "resource": "payment-link", + "id": "pl_4Y0eZitmBnQ6IDoMqZQKh", + "mode": "test", + "profileId": "pfl_QkEhN94Ba", + "createdAt": "2021-03-20T09:13:37+00:00", + "paidAt": "2021-03-21T09:13:37+00:00", + "updatedAt": "2021-03-21T09:13:37+00:00", + "expiresAt": null, + "amount": { + "value": "24.95", + "currency": "EUR" + }, + "description": "Bicycle tires", + "redirectUrl": "https://webshop.example.org/thanks", + "webhookUrl": "https://webshop.example.org/payment-links/webhook/", + "_links": { + "self": { + "href": "https://api.mollie.com/v2/payment-links/pl_4Y0eZitmBnQ6IDoMqZQKh", + "type": "application/json" + }, + "paymentLink": { + "href": "https://paymentlink.mollie.com/payment/4Y0eZitmBnQ6IDoMqZQKh/", + "type": "text/html" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/payment-links-api/get-payment-link", + "type": "text/html" + } + } + } + ] + }, + "_links": { + "self": { + "href": "https://api.mollie.com/v2/payment-links?limit=5", + "type": "application/hal+json" + }, + "previous": null, + "next": { + "href": "https://api.mollie.com/v2/payment-links?from=pl_ER6aqfpXg6nZrJvcsxNsm&limit=5", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/payment-links-api/list-payment-links", + "type": "text/html" + } + } +}`