-
Notifications
You must be signed in to change notification settings - Fork 3
Subscription
subscription
is dedicated to monthly subscription function. it provides functions to record and update subscribe informations, and automates credit card transaction monthly with information users provided.
subscription
depends on Golang interface largely to realize its pluggable modularity. It relies on four domain: database layer, payments
, invoice
, and mail
package. They are basically replaceable.
Currently we uses MySQL as the data persistence layer. subscription
was designed to be agnostic about database, so we need to do dependency injection when initializing subscription
service. The injection happens in SetRoutes
.
There are three third-party dependencies:
- Tappay:
/pkg/payment/tappay
- ezPay:
/pkg/invoice/ezPay
- mail:
/pkg/mail
They will be injected in mysql
package.
subscription
├── http
│ ├── filter.go
│ ├── handler.go
│ ├── handler_test.go
│ ├── time_parser.go
│ └── time_parser_test.go
├── mysql
│ ├── mysql.go
│ └── mysql_test.go
├── test
│ └── mock
│ └── mock.go
└── subscription.go
subscription.go
contains the domain types, constants, and interfaces that subscription depends on.
The constants, like status of subscription, are declared with Golang's iota
functionality to achieve Enum-like constant groups instead of putting them in config.json
formerly.
const (
// StatusInit means subscriptions is init. It's different from zero-value of Go
StatusInit = iota + 1
// StatusOK means it is a functioning subscription
StatusOK
// StatusInactive indicates this is not an active subscription now
StatusInactive
// StatusInitPayFail denotes fail when pay for the first time
StatusInitPayFail
// StatusRoutinePayFail indicates failure when pays with token
StatusRoutinePayFail
)
The integration of all services happends here. The SubscriptionService
in mysql.go
holds the MySQL instances, service interface for Tappay, EzPay, and Gmail.
MySQL instance will be initalized in http
package.
payment
and invoice
service will be initialized explicitly in each service functions. They are decided based on the informations stored in Subscription
struct, PaymentService
and InvoiceService
to decide which service instances should be injected to this struct.
mail
will be injected with only Gmail service. It's the only mail service we support now. This also happens inside each functions.
http
package holds the http controller for endpoints Subscription
provides. Its main entrance is handler.go
. As always, SetRoutes
will be imported in routes/routes.go
to register handlers subscription
provides.
In the function SetRoutes
, The global sqlx.DB
instance rrsql.DB.DB
will be injected if there is no assigned database layer.
s := &mysql.SubscriptionService{DB: rrsql.DB.DB}
h.Service = s
pkg/subscription/test
└── mock
└── mock.go
mock
stores the interface generated by GoMock. It will be consumed by unit tests for handlers.
Supposedly integration tests for subscription should be put here, too.
This endpoint provides a handler to add information about a new subscriber. The payload for frontend to attach will looks like this:
{
"member_id": 648,
"payment_service": "tappay",
"invoice_service": "ezpay",
"amount": 100,
"email": "[email protected]",
"created_at": "2019-11-28T00:11:46Z",
"payment_infos": {
"prime": "test_3a2fb2b7e892b914a03c95dd4dd5dc7970c908df67a49527c0a648b2bc9",
"currency": "TWD",
"details": "show me the money",
"cardholder": {
"phone_number": "+886919123467",
"name": "wonderwomen",
"email": "[email protected]"
}
},
"invoice_infos":{
"item_name": ["訂閱"],
"item_unit": ["月"],
"carrier_type":"",
"carrier_num": "",
"buyer_name": "wonderwoman",
"item_price": [30],
"item_count": [1]
}
}
-
member_id
: (int) member's id in READr -
amount
(required): (int) how much we want to get from users? -
payment_service
: (string) which payment service to use in subscription. Default tappay -
invoice_service
: (string) which invoice service to use in subscription. Default ezpay
payment_infos
records necessary information to finish payment procedure. In the object above is the example for Tappay. the meaning of those fields are as follows:
-
prime
(required): (string) the prime token retrieved from Tappay by frontend -
currency
: (string) default TWD by Tappay -
details
(required): (string) description about this transaction
In cardholder
object, the information will be send to fraud detector. Those fields are required:
-
phone_number
(required): (string) phone number of the payer -
name
(required): (string) name of the payer -
email
(required): (string) email of the payer
invoice_infos
records the necessary information for our invoice service. The example above demonstrate how to do it with ezPay:
-
item_name
(required): (array[string]) indicates names for each purchased item -
item_unit
(required): (array[string]) indicates the corresponding unit for eachitem_count
-
carrier_type
: (string) applicable whencategory=B2C
,- "0"=手機條碼載具
- "1"=自然人憑證條碼載具
- "2"=ezPay 電子發票載具
-
carrier_num
: (string) required when carrier_type is filled, -
love_code
: (string) Donate code -
buyer_ubn
: (string) Set whencategory=B2B
-
buyer_address
: (string) buyer's address -
buyer_name
: (string) buyer's name -
item_price
(required): (array[int]) indicates the price for each item -
item_count
(required): (array[int]) indicates the amount for each purchase item
This endpoint provides the function to modify a single subscription information for a user.
id
: the subscription id