mirror of
https://github.com/plutov/paypal.git
synced 2025-01-23 10:21:03 +01:00
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**
|
||||
* GET /v1/vault/credit-cards/**ID**
|
||||
* 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
|
||||
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 (
|
||||
// JsonTime overrides MarshalJson method to format in ISO8601
|
||||
JsonTime time.Time
|
||||
|
||||
// Address struct
|
||||
Address struct {
|
||||
Line1 string `json:"line1"`
|
||||
|
@ -55,6 +58,18 @@ type (
|
|||
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 {
|
||||
Currency string `json:"currency"`
|
||||
|
@ -93,6 +108,26 @@ 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"`
|
||||
}
|
||||
|
||||
// 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 {
|
||||
Amount *Amount `json:"amount,omitempty"`
|
||||
|
@ -105,6 +140,12 @@ type (
|
|||
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 struct {
|
||||
Client *http.Client
|
||||
|
@ -179,6 +220,19 @@ type (
|
|||
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 {
|
||||
ID string `json:"id"`
|
||||
|
@ -218,6 +272,16 @@ type (
|
|||
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 {
|
||||
ID string `json:"id,omitempty"`
|
||||
|
@ -263,6 +327,18 @@ type (
|
|||
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 struct {
|
||||
ID string `json:"id"`
|
||||
|
@ -449,3 +525,8 @@ type (
|
|||
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)
|
||||
}
|
||||
|
||||
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