Skip to content

Commit a9081ea

Browse files
committed
Add functionality to stop, resume and pause a susbcription
Signed-off-by: Imre Nagi <[email protected]>
1 parent 57d38f2 commit a9081ea

File tree

12 files changed

+627
-87
lines changed

12 files changed

+627
-87
lines changed

example/server/server.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,7 @@ func (s srv) routes() {
9090
s.Router.HandleFunc("/payment/xendit/dana/callback", s.paymentSrv.XenditDanaCallbackHandler()).Methods("POST")
9191
s.Router.HandleFunc("/payment/xendit/linkaja/callback", s.paymentSrv.XenditLinkAjaCallbackHandler()).Methods("POST")
9292
s.Router.HandleFunc("/payment/subscriptions", s.paymentSrv.CreateSubscriptionHandler()).Methods("POST")
93+
s.Router.HandleFunc("/payment/subscriptions/{subscription_number}/pause", s.paymentSrv.PauseSubscriptionHandler()).Methods("POST", "PUT")
94+
s.Router.HandleFunc("/payment/subscriptions/{subscription_number}/stop", s.paymentSrv.StopSubscriptionHandler()).Methods("POST", "PUT")
95+
s.Router.HandleFunc("/payment/subscriptions/{subscription_number}/resume", s.paymentSrv.ResumeSubscriptionHandler()).Methods("POST", "PUT")
9396
}

example/server/subscription.yaml

Lines changed: 0 additions & 7 deletions
This file was deleted.

gateway/xendit/gateway.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,7 @@ type xInvoice interface {
5252

5353
type xRecurring interface {
5454
CreateWithContext(ctx context.Context, data *recurring.CreateParams) (*xgo.RecurringPayment, *xendit.Error)
55+
PauseWithContext(ctx context.Context, data *recurring.PauseParams) (*xgo.RecurringPayment, *xendit.Error)
56+
ResumeWithContext(ctx context.Context, data *recurring.ResumeParams) (*xgo.RecurringPayment, *xendit.Error)
57+
StopWithContext(ctx context.Context, data *recurring.StopParams) (*xgo.RecurringPayment, *xendit.Error)
5558
}

manage/manage.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ type FailInvoiceRequest struct {
5050
Reason string `json:"reason"`
5151
}
5252

53+
// CreateSubscriptionRequest contains data for creating subscription
5354
type CreateSubscriptionRequest struct {
5455
Name string `json:"name"`
5556
Description string `json:"description"`
@@ -96,11 +97,12 @@ func (csr CreateSubscriptionRequest) ToSubscription() *subscription.Subscription
9697
s.TotalReccurence = csr.TotalReccurence
9798
s.CardToken = csr.CardToken
9899
s.ChargeImmediately = csr.ChargeImmediately
99-
s.Schedule = subscription.Schedule{
100-
Interval: csr.Schedule.Interval,
101-
IntervalUnit: subscription.NewIntervalUnit(csr.Schedule.IntervalUnit),
102-
StartAt: csr.StartAt(),
103-
}
100+
schedule := subscription.NewSchedule(
101+
csr.Schedule.Interval,
102+
subscription.NewIntervalUnit(csr.Schedule.IntervalUnit),
103+
csr.StartAt(),
104+
)
105+
s.Schedule = *schedule
104106
return s
105107
}
106108

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

117119
// Interface payment management interface
118120
type Interface interface {
121+
invoiceI
122+
subscriptionI
123+
119124
// return the payment methods available in payment service
120125
GetPaymentMethods(ctx context.Context, opts ...payment.Option) (*PaymentMethodList, error)
126+
}
121127

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

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

134141
// FailInvoice make the invoice failed
135142
FailInvoice(ctx context.Context, fir *FailInvoiceRequest) (*invoice.Invoice, error)
143+
}
136144

145+
type subscriptionI interface {
137146
// CreateSubscription creates new subscription
138147
CreateSubscription(ctx context.Context, csr *CreateSubscriptionRequest) (*subscription.Subscription, error)
148+
149+
// PauseSubscription pause active subscription
150+
PauseSubscription(ctx context.Context, subsNumber string) (*subscription.Subscription, error)
151+
152+
// ResumeSubscription resume paused subscription
153+
ResumeSubscription(ctx context.Context, subsNumber string) (*subscription.Subscription, error)
154+
155+
// StopSubscription stop subscription
156+
StopSubscription(ctx context.Context, subsNumber string) (*subscription.Subscription, error)
139157
}
140158

141159
// XenditProcessor callback handler for xendit

manage/manager.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,64 @@ func (m *Manager) CreateSubscription(ctx context.Context, csr *CreateSubscriptio
261261
return s, nil
262262
}
263263

264+
// PauseSubscription pause active subscription
265+
func (m *Manager) PauseSubscription(ctx context.Context, subsNumber string) (*subscription.Subscription, error) {
266+
267+
sub, err := m.subscriptionRepository.FindByNumber(ctx, subsNumber)
268+
if err != nil {
269+
return nil, err
270+
}
271+
272+
if err := sub.Pause(ctx, m.subscriptionController(payment.GatewayXendit)); err != nil {
273+
return nil, err
274+
}
275+
276+
if err := m.subscriptionRepository.Save(ctx, sub); err != nil {
277+
return nil, err
278+
}
279+
280+
return sub, nil
281+
282+
}
283+
284+
// ResumeSubscription resume paused subscription
285+
func (m *Manager) ResumeSubscription(ctx context.Context, subsNumber string) (*subscription.Subscription, error) {
286+
287+
sub, err := m.subscriptionRepository.FindByNumber(ctx, subsNumber)
288+
if err != nil {
289+
return nil, err
290+
}
291+
292+
if err := sub.Resume(ctx, m.subscriptionController(payment.GatewayXendit)); err != nil {
293+
return nil, err
294+
}
295+
296+
if err := m.subscriptionRepository.Save(ctx, sub); err != nil {
297+
return nil, err
298+
}
299+
300+
return sub, nil
301+
}
302+
303+
// StopSubscription stop subscription
304+
func (m *Manager) StopSubscription(ctx context.Context, subsNumber string) (*subscription.Subscription, error) {
305+
306+
sub, err := m.subscriptionRepository.FindByNumber(ctx, subsNumber)
307+
if err != nil {
308+
return nil, err
309+
}
310+
311+
if err := sub.Stop(ctx, m.subscriptionController(payment.GatewayXendit)); err != nil {
312+
return nil, err
313+
}
314+
315+
if err := m.subscriptionRepository.Save(ctx, sub); err != nil {
316+
return nil, err
317+
}
318+
319+
return sub, nil
320+
}
321+
264322
func (m Manager) subscriptionController(gateway payment.Gateway) subscription.Controller {
265323
return &xenditSubscriptionController{
266324
XenditGateway: m.xenditGateway,

manage/subscription.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/imrenagi/go-payment/subscription"
1414

1515
goxendit "github.com/xendit/xendit-go"
16+
xrecurring "github.com/xendit/xendit-go/recurringpayment"
1617
)
1718

1819
type xenditSubscriptionController struct {
@@ -44,6 +45,39 @@ func (sc xenditSubscriptionController) Create(ctx context.Context, sub *subscrip
4445
}, nil
4546
}
4647

48+
func (sc xenditSubscriptionController) Resume(ctx context.Context, sub *subscription.Subscription) error {
49+
_, err := sc.XenditGateway.Recurring.ResumeWithContext(ctx, &xrecurring.ResumeParams{
50+
ID: sub.GatewayRecurringID,
51+
})
52+
var xError *goxendit.Error
53+
if ok := errors.As(err, &xError); ok && xError != nil {
54+
return xError
55+
}
56+
return nil
57+
}
58+
59+
func (sc xenditSubscriptionController) Stop(ctx context.Context, sub *subscription.Subscription) error {
60+
_, err := sc.XenditGateway.Recurring.StopWithContext(ctx, &xrecurring.StopParams{
61+
ID: sub.GatewayRecurringID,
62+
})
63+
var xError *goxendit.Error
64+
if ok := errors.As(err, &xError); ok && xError != nil {
65+
return xError
66+
}
67+
return nil
68+
}
69+
70+
func (sc xenditSubscriptionController) Pause(ctx context.Context, sub *subscription.Subscription) error {
71+
_, err := sc.XenditGateway.Recurring.PauseWithContext(ctx, &xrecurring.PauseParams{
72+
ID: sub.GatewayRecurringID,
73+
})
74+
var xError *goxendit.Error
75+
if ok := errors.As(err, &xError); ok && xError != nil {
76+
return xError
77+
}
78+
return nil
79+
}
80+
4781
func (sc xenditSubscriptionController) Gateway() payment.Gateway {
4882
return payment.GatewayXendit
4983
}

manage/xendit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ func (m Manager) processXenditRecurringTransactionCallback(ctx context.Context,
227227
}
228228
}
229229

230-
if err := subs.Record(inv); err != nil {
230+
if err := subs.Save(inv); err != nil {
231231
return err
232232
}
233233

server/server.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,48 @@ func (s Server) CreateSubscriptionHandler() http.HandlerFunc {
110110
}
111111
}
112112

113+
// PauseSubscriptionHandler returns handler for pausing subscription
114+
func (s Server) PauseSubscriptionHandler() http.HandlerFunc {
115+
return func(w http.ResponseWriter, r *http.Request) {
116+
vars := mux.Vars(r)
117+
subscriptionNumber := vars["subscription_number"]
118+
subs, err := s.Manager.PauseSubscription(r.Context(), subscriptionNumber)
119+
if err != nil {
120+
WriteFailResponseFromError(w, err)
121+
return
122+
}
123+
WriteSuccessResponse(w, http.StatusOK, subs, nil)
124+
}
125+
}
126+
127+
// StopSubscriptionHandler returns stop subscription handler
128+
func (s Server) StopSubscriptionHandler() http.HandlerFunc {
129+
return func(w http.ResponseWriter, r *http.Request) {
130+
vars := mux.Vars(r)
131+
subscriptionNumber := vars["subscription_number"]
132+
subs, err := s.Manager.StopSubscription(r.Context(), subscriptionNumber)
133+
if err != nil {
134+
WriteFailResponseFromError(w, err)
135+
return
136+
}
137+
WriteSuccessResponse(w, http.StatusOK, subs, nil)
138+
}
139+
}
140+
141+
// ResumeSubscriptionHandler returns resume susbcription handler
142+
func (s Server) ResumeSubscriptionHandler() http.HandlerFunc {
143+
return func(w http.ResponseWriter, r *http.Request) {
144+
vars := mux.Vars(r)
145+
subscriptionNumber := vars["subscription_number"]
146+
subs, err := s.Manager.ResumeSubscription(r.Context(), subscriptionNumber)
147+
if err != nil {
148+
WriteFailResponseFromError(w, err)
149+
return
150+
}
151+
WriteSuccessResponse(w, http.StatusOK, subs, nil)
152+
}
153+
}
154+
113155
// MidtransTransactionCallbackHandler handles incoming notification about payment status from midtrans.
114156
func (s *Server) MidtransTransactionCallbackHandler() http.HandlerFunc {
115157
return func(w http.ResponseWriter, r *http.Request) {

subscription/interface.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//go:generate mockery -dir . -name Controller -output ./mocks -filename controller.go
2+
13
package subscription
24

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

20+
type pauser interface {
21+
Pause(ctx context.Context, sub *Subscription) error
22+
}
23+
24+
type stopper interface {
25+
Stop(ctx context.Context, stop *Subscription) error
26+
}
27+
28+
type resumer interface {
29+
Resume(ctx context.Context, sub *Subscription) error
30+
}
31+
1832
// Controller is payment gateway interface for subscription handling
1933
type Controller interface {
2034
creator
35+
pauser
36+
stopper
37+
resumer
2138
}

subscription/mocks/controller.go

Lines changed: 96 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)