This plugin provides convenient integration with Spgateway - an online payment service in Taiwan.
Add this line to your application's Gemfile:
gem 'spgateway-rails', github: '5xRuby/spgateway-rails'
And then execute:
$ bundle
Finally, run the install generator:
$ rails generate spgateway:install
then set your merchant_id
, hash_key
and hash_iv
in config/initializers/spgateway.rb
.
-
Place the pay button in a view, such as:
<%= spgateway_pay_button 'Go pay', payment_methods: [:credit_card], order_number: @order.serial, item_description: @order.description, amount: @order.amount, payer_email: current_user&.email, class: 'btn btn-success' %>
Note that we restrict the supported payment methods to only
credit_card
here. -
Configure how to process payment results in
config/initializers/spgateway.rb
, for example:config.mpg_callback do |mpg_response| if mpg_response.status == 'SUCCESS' Order.find_by(serial: mpg_response.result.merchant_order_no) .update_attributes!(paid: true) flash[:success] = mpg_response.message else flash[:error] = mpg_response.message end redirect_to orders_path end
With some payment methods, such as ATM 轉帳 (VACC), 超商代碼繳費 (CVS) or 超商條碼繳費 (BARCODE), users will not complete their transaction on the web browser but maybe in front of an ATM or in a convenient store or so. Spgateway will notify our application later if such transactions has been done, and we will need an additional setup to deal with these notifications.
Note that you will not be able to test this intergration with an local application server (i.e.
http://localhost:3000
) directly, because (in normal cases) Spgateway cannot connect to your local computer. Consider using services like ngrok to get a public URL tunneled to your local application server, and use that public URL in the browser to get things work.
-
You'll need to setup
mpg_callback
andnotify_callback
like this:# Callback after the user has been redirect back from Spgateway MPG gateway. config.mpg_callback do |spgateway_response| # Only shows the results to the user here, while notify_callback will do the # actual work. if spgateway_response.status == 'SUCCESS' flash[:success] = spgateway_response.message else flash[:error] = spgateway_response.message end redirect_to orders_path end # Callback triggered by Spgateway after an order has been paid. config.notify_callback do |spgateway_response| if spgateway_response.status == 'SUCCESS' # Find the order and mark it as paid. Order.find_by(serial: spgateway_response.result.merchant_order_no) .update_attributes!(paid: true) else # Or log the error. Rails.logger.info "Spgateway Payment Not Succeed: #{spgateway_response.status}: #{spgateway_response.message} (#{spgateway_response.result.to_json})" end end
The
notify_callback
will be called when Spgateway tries to notify us about payment status updates, nomatter which payment method does the user select. So in thempg_callback
block, we should only write code for user-facing logic, to prevent dulipaced work and unexpected results. -
Now you can add non-real-time payment methods to your pay button:
<%= spgateway_pay_button 'Go pay', payment_methods: [:credit_card, :vacc, :cvs, :barcode], order_number: @order.serial, item_description: @order.description, amount: @order.amount, payer_email: current_user&.email, class: 'btn btn-success' %>
Get the customer's ATM transfer account or payment code and show them on your website with payment_code_callback
By default, Spgateway will show the payment instruction of ATM 轉帳 (VACC), 超商代碼繳費 (CVS) or 超商條碼繳費 (BARCODE) to users on their site directly, this way you can not get the payment info and users will not be redirected back to your site.
You can add the payment_code_callback
config to let users be redirected back to your site, so then you can have the payment info and show it to your users by yourself. Do something like this:
config.payment_code_callback do |spgateway_response|
if spgateway_response.status == 'SUCCESS' &&
spgateway_response.result.payment_type == 'VACC'
bank_code = spgateway_response.result.bank_code
account_number = spgateway_response.result.code_no
expired_at =
DateTime.parse("#{spgateway_response.result.expire_date} #{spgateway_response.result.expire_time} UTC+8")
Order.find_by(serial: spgateway_response.result.merchant_order_no)
.update_attributes!(bank_code: bank_code, account_number: account_number, expired_at: expired_at)
flash[:info] =
"Please transfer the money to bank code #{bank_code}, account number #{account_number} before #{I18n.l(expired_at)}"
else
Rails.logger.error "Spgateway Payment Code Receive Not Succeed: #{spgateway_response.status}: #{spgateway_response.message} (#{spgateway_response.result.to_json})"
flash[:error] = "Our apologies, but an unexpected error occured, please try again"
end
redirect_to orders_path
end
- Support ClientBackURL.
- Build API wrapper for QueryTradeInfo.
- Add option to double check the payment results after callback.
- Build API wrapper for CreditCard/Cancel.
- Wtite docs.
- Test, test everything!
Just open an issue or send a PR :)
The gem is available as open source under the terms of the MIT License.