forked from go-packages/paypal
Merge pull request #32 from logpacker/feature_billing_plan
Feature billing plan
This commit is contained in:
commit
d30e9ced1e
|
@ -35,6 +35,10 @@
|
||||||
* PATCH /v1/vault/credit-cards/**ID**
|
* PATCH /v1/vault/credit-cards/**ID**
|
||||||
* GET /v1/vault/credit-cards/**ID**
|
* GET /v1/vault/credit-cards/**ID**
|
||||||
* GET /v1/vault/credit-cards
|
* GET /v1/vault/credit-cards
|
||||||
|
* POST /v1/payments/billing-plans
|
||||||
|
* PATCH /v1/payments/billing-plans/***ID***
|
||||||
|
* POST /v1/payments/billing-agreements
|
||||||
|
* POST /v1/payments/billing-agreements/***TOKEN***/agreement-execute
|
||||||
|
|
||||||
### Missing endpoints
|
### Missing endpoints
|
||||||
It is possible that some endpoints are missing in this SDK Client, but you can use built-in **paypalsdk** functions to perform a request: **NewClient -> NewRequest -> SendWithAuth**
|
It is possible that some endpoints are missing in this SDK Client, but you can use built-in **paypalsdk** functions to perform a request: **NewClient -> NewRequest -> SendWithAuth**
|
||||||
|
|
93
billing.go
Normal file
93
billing.go
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
package paypalsdk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// CreateBillingResp struct
|
||||||
|
CreateBillingResp 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAgreementResp struct
|
||||||
|
CreateAgreementResp 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"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-plans"), plan)
|
||||||
|
response := &CreateBillingResp{}
|
||||||
|
if err != nil {
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
err = c.SendWithAuth(req, response)
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
buf := bytes.NewBuffer([]byte("[{\"op\":\"replace\",\"path\":\"/\",\"value\":{\"state\":\"ACTIVE\"}}]"))
|
||||||
|
req, err := http.NewRequest("PATCH", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-plans/"+planID), buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.SetBasicAuth(c.ClientID, c.Secret)
|
||||||
|
req.Header.Set("Authorization", "Bearer "+c.Token.Token)
|
||||||
|
return c.SendWithAuth(req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an agreement for specified plan
|
||||||
|
// Endpoint: POST /v1/payments/billing-agreements
|
||||||
|
func (c *Client) CreateBillingAgreement(a BillingAgreement) (*CreateAgreementResp, error) {
|
||||||
|
req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-agreements"), a)
|
||||||
|
response := &CreateAgreementResp{}
|
||||||
|
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(token string) (*ExecuteAgreementResponse, error) {
|
||||||
|
req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-agreements/"+token+"/agreement-execute"), nil)
|
||||||
|
if err != nil {
|
||||||
|
return &ExecuteAgreementResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.SetBasicAuth(c.ClientID, c.Secret)
|
||||||
|
req.Header.Set("Authorization", "Bearer "+c.Token.Token)
|
||||||
|
|
||||||
|
e := ExecuteAgreementResponse{}
|
||||||
|
err = c.SendWithAuth(req, &e)
|
||||||
|
if err != nil {
|
||||||
|
return &e, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.ID == "" {
|
||||||
|
return &e, errors.New("Unable to execute agreement with token=" + token)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &e, err
|
||||||
|
}
|
107
billing_test.go
Normal file
107
billing_test.go
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
package paypalsdk_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
pp "github.com/logpacker/PayPal-Go-SDK"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BillingExample() {
|
||||||
|
plan := pp.BillingPlan{
|
||||||
|
Name: "Plan with Regular and Trial Payment Definitions",
|
||||||
|
Description: "Plan with regular and trial payment definitions.",
|
||||||
|
Type: "fixed",
|
||||||
|
PaymentDefinitions: []pp.PaymentDefinition{
|
||||||
|
pp.PaymentDefinition{
|
||||||
|
Name: "Regular payment definition",
|
||||||
|
Type: "REGULAR",
|
||||||
|
Frequency: "MONTH",
|
||||||
|
FrequencyInterval: "2",
|
||||||
|
Amount: pp.AmountPayout{
|
||||||
|
Value: "100",
|
||||||
|
Currency: "USD",
|
||||||
|
},
|
||||||
|
Cycles: "12",
|
||||||
|
ChargeModels: []pp.ChargeModel{
|
||||||
|
pp.ChargeModel{
|
||||||
|
Type: "SHIPPING",
|
||||||
|
Amount: pp.AmountPayout{
|
||||||
|
Value: "10",
|
||||||
|
Currency: "USD",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pp.ChargeModel{
|
||||||
|
Type: "TAX",
|
||||||
|
Amount: pp.AmountPayout{
|
||||||
|
Value: "12",
|
||||||
|
Currency: "USD",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pp.PaymentDefinition{
|
||||||
|
Name: "Trial payment definition",
|
||||||
|
Type: "trial",
|
||||||
|
Frequency: "week",
|
||||||
|
FrequencyInterval: "5",
|
||||||
|
Amount: pp.AmountPayout{
|
||||||
|
Value: "9.19",
|
||||||
|
Currency: "USD",
|
||||||
|
},
|
||||||
|
Cycles: "2",
|
||||||
|
ChargeModels: []pp.ChargeModel{
|
||||||
|
pp.ChargeModel{
|
||||||
|
Type: "SHIPPING",
|
||||||
|
Amount: pp.AmountPayout{
|
||||||
|
Value: "1",
|
||||||
|
Currency: "USD",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pp.ChargeModel{
|
||||||
|
Type: "TAX",
|
||||||
|
Amount: pp.AmountPayout{
|
||||||
|
Value: "2",
|
||||||
|
Currency: "USD",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MerchantPreferences: &pp.MerchantPreferences{
|
||||||
|
SetupFee: &pp.AmountPayout{
|
||||||
|
Value: "1",
|
||||||
|
Currency: "USD",
|
||||||
|
},
|
||||||
|
ReturnUrl: "http://www.paypal.com",
|
||||||
|
CancelUrl: "http://www.paypal.com/cancel",
|
||||||
|
AutoBillAmount: "YES",
|
||||||
|
InitialFailAmountAction: "CONTINUE",
|
||||||
|
MaxFailAttempts: "0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c, err := pp.NewClient("clientID", "secretID", pp.APIBaseSandBox)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_, err = c.GetAccessToken()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
planResp, err := c.CreateBillingPlan(plan)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = c.ActivatePlan(planResp.ID)
|
||||||
|
fmt.Println(err)
|
||||||
|
agreement := pp.BillingAgreement{
|
||||||
|
Name: "Fast Speed Agreement",
|
||||||
|
Description: "Agreement for Fast Speed Plan",
|
||||||
|
StartDate: pp.JsonTime(time.Now().Add(time.Hour * 24)),
|
||||||
|
Plan: pp.BillingPlan{ID: planResp.ID},
|
||||||
|
Payer: pp.Payer{
|
||||||
|
PaymentMethod: "paypal",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resp, err := c.CreateBillingAgreement(agreement)
|
||||||
|
fmt.Println(err, resp)
|
||||||
|
}
|
81
types.go
81
types.go
|
@ -44,6 +44,9 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
// JsonTime overrides MarshalJson method to format in ISO8601
|
||||||
|
JsonTime time.Time
|
||||||
|
|
||||||
// Address struct
|
// Address struct
|
||||||
Address struct {
|
Address struct {
|
||||||
Line1 string `json:"line1"`
|
Line1 string `json:"line1"`
|
||||||
|
@ -55,6 +58,18 @@ type (
|
||||||
Phone string `json:"phone,omitempty"`
|
Phone string `json:"phone,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AgreementDetails struct
|
||||||
|
AgreementDetails struct {
|
||||||
|
OutstandingBalance AmountPayout `json:"outstanding_balance"`
|
||||||
|
CyclesRemaining int `json:"cycles_remaining,string"`
|
||||||
|
CyclesCompleted int `json:"cycles_completed,string"`
|
||||||
|
NextBillingDate time.Time `json:"next_billing_date"`
|
||||||
|
LastPaymentDate time.Time `json:"last_payment_date"`
|
||||||
|
LastPaymentAmount AmountPayout `json:"last_payment_amount"`
|
||||||
|
FinalPaymentDate time.Time `json:"final_payment_date"`
|
||||||
|
FailedPaymentCount int `json:"failed_payment_count,string"`
|
||||||
|
}
|
||||||
|
|
||||||
// Amount struct
|
// Amount struct
|
||||||
Amount struct {
|
Amount struct {
|
||||||
Currency string `json:"currency"`
|
Currency string `json:"currency"`
|
||||||
|
@ -93,6 +108,26 @@ type (
|
||||||
SenderBatchHeader *SenderBatchHeader `json:"sender_batch_header,omitempty"`
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BillingPlan struct
|
||||||
|
BillingPlan struct {
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
PaymentDefinitions []PaymentDefinition `json:"payment_definitions,omitempty"`
|
||||||
|
MerchantPreferences *MerchantPreferences `json:"merchant_preferences,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Capture struct
|
// Capture struct
|
||||||
Capture struct {
|
Capture struct {
|
||||||
Amount *Amount `json:"amount,omitempty"`
|
Amount *Amount `json:"amount,omitempty"`
|
||||||
|
@ -105,6 +140,12 @@ type (
|
||||||
Links []Link `json:"links,omitempty"`
|
Links []Link `json:"links,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChargeModel struct
|
||||||
|
ChargeModel struct {
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Amount AmountPayout `json:"amount,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Client represents a Paypal REST API Client
|
// Client represents a Paypal REST API Client
|
||||||
Client struct {
|
Client struct {
|
||||||
Client *http.Client
|
Client *http.Client
|
||||||
|
@ -179,6 +220,19 @@ type (
|
||||||
Details string `json:"details"`
|
Details string `json:"details"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecuteAgreementResponse struct
|
||||||
|
ExecuteAgreementResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
State string `json:"state"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Payer Payer `json:"payer"`
|
||||||
|
Plan BillingPlan `json:"plan"`
|
||||||
|
StartDate time.Time `json:"start_date"`
|
||||||
|
ShippingAddress ShippingAddress `json:"shipping_address"`
|
||||||
|
AgreementDetails AgreementDetails `json:"agreement_details"`
|
||||||
|
Links []Link `json:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
// ExecuteResponse struct
|
// ExecuteResponse struct
|
||||||
ExecuteResponse struct {
|
ExecuteResponse struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
@ -218,6 +272,16 @@ type (
|
||||||
Enctype string `json:"enctype,omitempty"`
|
Enctype string `json:"enctype,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MerchantPreferences struct
|
||||||
|
MerchantPreferences struct {
|
||||||
|
SetupFee *AmountPayout `json:"setup_fee,omitempty"`
|
||||||
|
ReturnUrl string `json:"return_url,omitempty"`
|
||||||
|
CancelUrl string `json:"cancel_url,omitempty"`
|
||||||
|
AutoBillAmount string `json:"auto_bill_amount,omitempty"`
|
||||||
|
InitialFailAmountAction string `json:"initial_fail_amount_action,omitempty"`
|
||||||
|
MaxFailAttempts string `json:"max_fail_attempts,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Order struct
|
// Order struct
|
||||||
Order struct {
|
Order struct {
|
||||||
ID string `json:"id,omitempty"`
|
ID string `json:"id,omitempty"`
|
||||||
|
@ -263,6 +327,18 @@ type (
|
||||||
ExperienceProfileID string `json:"experience_profile_id,omitempty"`
|
ExperienceProfileID string `json:"experience_profile_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PaymentDefinition struct
|
||||||
|
PaymentDefinition struct {
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Frequency string `json:"frequency,omitempty"`
|
||||||
|
FrequencyInterval string `json:"frequency_interval,omitempty"`
|
||||||
|
Amount AmountPayout `json:"amount,omitempty"`
|
||||||
|
Cycles string `json:"cycles,omitempty"`
|
||||||
|
ChargeModels []ChargeModel `json:"charge_models,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// PaymentResponse structure
|
// PaymentResponse structure
|
||||||
PaymentResponse struct {
|
PaymentResponse struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
@ -449,3 +525,8 @@ type (
|
||||||
func (r *ErrorResponse) Error() string {
|
func (r *ErrorResponse) Error() string {
|
||||||
return fmt.Sprintf("%v %v: %d %s", r.Response.Request.Method, r.Response.Request.URL, r.Response.StatusCode, r.Message)
|
return fmt.Sprintf("%v %v: %d %s", r.Response.Request.Method, r.Response.Request.URL, r.Response.StatusCode, r.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t JsonTime) MarshalJSON() ([]byte, error) {
|
||||||
|
stamp := fmt.Sprintf(`"%s"`, time.Time(t).UTC().Format(time.RFC3339))
|
||||||
|
return []byte(stamp), nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user