Skip to content

Commit

Permalink
Add functionality to stop, resume and pause a susbcription
Browse files Browse the repository at this point in the history
Signed-off-by: Imre Nagi <[email protected]>
  • Loading branch information
imrenagi committed Jun 7, 2020
1 parent 57d38f2 commit a9081ea
Show file tree
Hide file tree
Showing 12 changed files with 627 additions and 87 deletions.
3 changes: 3 additions & 0 deletions example/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,7 @@ func (s srv) routes() {
s.Router.HandleFunc("/payment/xendit/dana/callback", s.paymentSrv.XenditDanaCallbackHandler()).Methods("POST")
s.Router.HandleFunc("/payment/xendit/linkaja/callback", s.paymentSrv.XenditLinkAjaCallbackHandler()).Methods("POST")
s.Router.HandleFunc("/payment/subscriptions", s.paymentSrv.CreateSubscriptionHandler()).Methods("POST")
s.Router.HandleFunc("/payment/subscriptions/{subscription_number}/pause", s.paymentSrv.PauseSubscriptionHandler()).Methods("POST", "PUT")
s.Router.HandleFunc("/payment/subscriptions/{subscription_number}/stop", s.paymentSrv.StopSubscriptionHandler()).Methods("POST", "PUT")
s.Router.HandleFunc("/payment/subscriptions/{subscription_number}/resume", s.paymentSrv.ResumeSubscriptionHandler()).Methods("POST", "PUT")
}
7 changes: 0 additions & 7 deletions example/server/subscription.yaml

This file was deleted.

3 changes: 3 additions & 0 deletions gateway/xendit/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,7 @@ type xInvoice interface {

type xRecurring interface {
CreateWithContext(ctx context.Context, data *recurring.CreateParams) (*xgo.RecurringPayment, *xendit.Error)
PauseWithContext(ctx context.Context, data *recurring.PauseParams) (*xgo.RecurringPayment, *xendit.Error)
ResumeWithContext(ctx context.Context, data *recurring.ResumeParams) (*xgo.RecurringPayment, *xendit.Error)
StopWithContext(ctx context.Context, data *recurring.StopParams) (*xgo.RecurringPayment, *xendit.Error)
}
28 changes: 23 additions & 5 deletions manage/manage.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type FailInvoiceRequest struct {
Reason string `json:"reason"`
}

// CreateSubscriptionRequest contains data for creating subscription
type CreateSubscriptionRequest struct {
Name string `json:"name"`
Description string `json:"description"`
Expand Down Expand Up @@ -96,11 +97,12 @@ func (csr CreateSubscriptionRequest) ToSubscription() *subscription.Subscription
s.TotalReccurence = csr.TotalReccurence
s.CardToken = csr.CardToken
s.ChargeImmediately = csr.ChargeImmediately
s.Schedule = subscription.Schedule{
Interval: csr.Schedule.Interval,
IntervalUnit: subscription.NewIntervalUnit(csr.Schedule.IntervalUnit),
StartAt: csr.StartAt(),
}
schedule := subscription.NewSchedule(
csr.Schedule.Interval,
subscription.NewIntervalUnit(csr.Schedule.IntervalUnit),
csr.StartAt(),
)
s.Schedule = *schedule
return s
}

Expand All @@ -116,9 +118,14 @@ func (csr CreateSubscriptionRequest) StartAt() *time.Time {

// Interface payment management interface
type Interface interface {
invoiceI
subscriptionI

// return the payment methods available in payment service
GetPaymentMethods(ctx context.Context, opts ...payment.Option) (*PaymentMethodList, error)
}

type invoiceI interface {
// return invoice given its invoice number
GetInvoice(ctx context.Context, number string) (*invoice.Invoice, error)

Expand All @@ -133,9 +140,20 @@ type Interface interface {

// FailInvoice make the invoice failed
FailInvoice(ctx context.Context, fir *FailInvoiceRequest) (*invoice.Invoice, error)
}

type subscriptionI interface {
// CreateSubscription creates new subscription
CreateSubscription(ctx context.Context, csr *CreateSubscriptionRequest) (*subscription.Subscription, error)

// PauseSubscription pause active subscription
PauseSubscription(ctx context.Context, subsNumber string) (*subscription.Subscription, error)

// ResumeSubscription resume paused subscription
ResumeSubscription(ctx context.Context, subsNumber string) (*subscription.Subscription, error)

// StopSubscription stop subscription
StopSubscription(ctx context.Context, subsNumber string) (*subscription.Subscription, error)
}

// XenditProcessor callback handler for xendit
Expand Down
58 changes: 58 additions & 0 deletions manage/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,64 @@ func (m *Manager) CreateSubscription(ctx context.Context, csr *CreateSubscriptio
return s, nil
}

// PauseSubscription pause active subscription
func (m *Manager) PauseSubscription(ctx context.Context, subsNumber string) (*subscription.Subscription, error) {

sub, err := m.subscriptionRepository.FindByNumber(ctx, subsNumber)
if err != nil {
return nil, err
}

if err := sub.Pause(ctx, m.subscriptionController(payment.GatewayXendit)); err != nil {
return nil, err
}

if err := m.subscriptionRepository.Save(ctx, sub); err != nil {
return nil, err
}

return sub, nil

}

// ResumeSubscription resume paused subscription
func (m *Manager) ResumeSubscription(ctx context.Context, subsNumber string) (*subscription.Subscription, error) {

sub, err := m.subscriptionRepository.FindByNumber(ctx, subsNumber)
if err != nil {
return nil, err
}

if err := sub.Resume(ctx, m.subscriptionController(payment.GatewayXendit)); err != nil {
return nil, err
}

if err := m.subscriptionRepository.Save(ctx, sub); err != nil {
return nil, err
}

return sub, nil
}

// StopSubscription stop subscription
func (m *Manager) StopSubscription(ctx context.Context, subsNumber string) (*subscription.Subscription, error) {

sub, err := m.subscriptionRepository.FindByNumber(ctx, subsNumber)
if err != nil {
return nil, err
}

if err := sub.Stop(ctx, m.subscriptionController(payment.GatewayXendit)); err != nil {
return nil, err
}

if err := m.subscriptionRepository.Save(ctx, sub); err != nil {
return nil, err
}

return sub, nil
}

func (m Manager) subscriptionController(gateway payment.Gateway) subscription.Controller {
return &xenditSubscriptionController{
XenditGateway: m.xenditGateway,
Expand Down
34 changes: 34 additions & 0 deletions manage/subscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/imrenagi/go-payment/subscription"

goxendit "github.com/xendit/xendit-go"
xrecurring "github.com/xendit/xendit-go/recurringpayment"
)

type xenditSubscriptionController struct {
Expand Down Expand Up @@ -44,6 +45,39 @@ func (sc xenditSubscriptionController) Create(ctx context.Context, sub *subscrip
}, nil
}

func (sc xenditSubscriptionController) Resume(ctx context.Context, sub *subscription.Subscription) error {
_, err := sc.XenditGateway.Recurring.ResumeWithContext(ctx, &xrecurring.ResumeParams{
ID: sub.GatewayRecurringID,
})
var xError *goxendit.Error
if ok := errors.As(err, &xError); ok && xError != nil {
return xError
}
return nil
}

func (sc xenditSubscriptionController) Stop(ctx context.Context, sub *subscription.Subscription) error {
_, err := sc.XenditGateway.Recurring.StopWithContext(ctx, &xrecurring.StopParams{
ID: sub.GatewayRecurringID,
})
var xError *goxendit.Error
if ok := errors.As(err, &xError); ok && xError != nil {
return xError
}
return nil
}

func (sc xenditSubscriptionController) Pause(ctx context.Context, sub *subscription.Subscription) error {
_, err := sc.XenditGateway.Recurring.PauseWithContext(ctx, &xrecurring.PauseParams{
ID: sub.GatewayRecurringID,
})
var xError *goxendit.Error
if ok := errors.As(err, &xError); ok && xError != nil {
return xError
}
return nil
}

func (sc xenditSubscriptionController) Gateway() payment.Gateway {
return payment.GatewayXendit
}
2 changes: 1 addition & 1 deletion manage/xendit.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func (m Manager) processXenditRecurringTransactionCallback(ctx context.Context,
}
}

if err := subs.Record(inv); err != nil {
if err := subs.Save(inv); err != nil {
return err
}

Expand Down
42 changes: 42 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,48 @@ func (s Server) CreateSubscriptionHandler() http.HandlerFunc {
}
}

// PauseSubscriptionHandler returns handler for pausing subscription
func (s Server) PauseSubscriptionHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
subscriptionNumber := vars["subscription_number"]
subs, err := s.Manager.PauseSubscription(r.Context(), subscriptionNumber)
if err != nil {
WriteFailResponseFromError(w, err)
return
}
WriteSuccessResponse(w, http.StatusOK, subs, nil)
}
}

// StopSubscriptionHandler returns stop subscription handler
func (s Server) StopSubscriptionHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
subscriptionNumber := vars["subscription_number"]
subs, err := s.Manager.StopSubscription(r.Context(), subscriptionNumber)
if err != nil {
WriteFailResponseFromError(w, err)
return
}
WriteSuccessResponse(w, http.StatusOK, subs, nil)
}
}

// ResumeSubscriptionHandler returns resume susbcription handler
func (s Server) ResumeSubscriptionHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
subscriptionNumber := vars["subscription_number"]
subs, err := s.Manager.ResumeSubscription(r.Context(), subscriptionNumber)
if err != nil {
WriteFailResponseFromError(w, err)
return
}
WriteSuccessResponse(w, http.StatusOK, subs, nil)
}
}

// MidtransTransactionCallbackHandler handles incoming notification about payment status from midtrans.
func (s *Server) MidtransTransactionCallbackHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
Expand Down
17 changes: 17 additions & 0 deletions subscription/interface.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:generate mockery -dir . -name Controller -output ./mocks -filename controller.go

package subscription

import (
Expand All @@ -15,7 +17,22 @@ type creator interface {
Create(ctx context.Context, sub *Subscription) (*CreateResponse, error)
}

type pauser interface {
Pause(ctx context.Context, sub *Subscription) error
}

type stopper interface {
Stop(ctx context.Context, stop *Subscription) error
}

type resumer interface {
Resume(ctx context.Context, sub *Subscription) error
}

// Controller is payment gateway interface for subscription handling
type Controller interface {
creator
pauser
stopper
resumer
}
96 changes: 96 additions & 0 deletions subscription/mocks/controller.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit a9081ea

Please sign in to comment.