Skip to content

Commit

Permalink
Merge pull request #143 from VictorAvelar/feature/payments-api-link
Browse files Browse the repository at this point in the history
Payment Links API link
  • Loading branch information
VictorAvelar authored Jul 1, 2021
2 parents b7d3164 + 56c091d commit 2553194
Show file tree
Hide file tree
Showing 6 changed files with 346 additions and 3 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
2 changes: 2 additions & 0 deletions mollie/mollie.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type Client struct {
Mandates *MandatesService
Permissions *PermissionsService
Onboarding *OnboardingService
PaymentLinks *PaymentLinksService
}

type service struct {
Expand Down Expand Up @@ -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)
Expand Down
130 changes: 130 additions & 0 deletions mollie/payment_links.go
Original file line number Diff line number Diff line change
@@ -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
}
90 changes: 90 additions & 0 deletions mollie/payment_links_test.go
Original file line number Diff line number Diff line change
@@ -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()
}
}
121 changes: 121 additions & 0 deletions testdata/payment_links.go
Original file line number Diff line number Diff line change
@@ -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"
}
}
}`

0 comments on commit 2553194

Please sign in to comment.