-
-
Save itskingori/51be3c543dcba43a3a77 to your computer and use it in GitHub Desktop.
module Account | |
module Payments | |
class PesapalController < ApplicationController | |
# GET /account/payments/pesapal/new | |
def new | |
# Configure transaction details | |
pesapal = Pesapal::Merchant.new | |
pesapal.order_details = { | |
amount: '<AMOUNT>', | |
description: '<DESCRIPTION>', | |
type: 'MERCHANT', | |
reference: '<REFERENCE>', | |
first_name:'<FIRST_NAME>', | |
last_name: '<LAST_NAME>', | |
email: '<EMAIL>', | |
phonenumber: '<PHONE_NUMBER>', | |
currency: 'KES_or_USD' | |
} | |
# Configure API settings while passing on the data that we need | |
pesapal.config = { | |
callback_url: pesapal_callback_account_payments_url, | |
consumer_key: Rails.application.secrets.pesapal_consumer_key, | |
consumer_secret: Rails.application.secrets.pesapal_consumer_secret | |
} | |
# Generate iframe | |
@order_url = pesapal.generate_order_url | |
end | |
# GET /account/payments/pesapal/callback | |
def callback | |
payment = Payment.new( | |
user: current_user, | |
reference_no: params.require(:pesapal_merchant_reference), | |
tracking_no: params.require(:pesapal_transaction_tracking_id), | |
amount: "amount", | |
currency_iso_code: "currency.iso_code", | |
status: 'pending' | |
) | |
if payment.save | |
redirect_to account_payments_url, notice: "Your payment of XXX has been completed but is still pending confirmation." | |
return | |
end | |
redirect_to new_account_payment_url, alert: "Your payment of XXX was not completed successfully." | |
end | |
# GET /account/payments/pesapal/ipn | |
def ipn | |
# Initialize Pesapal | |
pesapal = Pesapal::Merchant.new | |
pesapal.config = { | |
consumer_key: Rails.application.secrets.pesapal_consumer_key, | |
consumer_secret: Rails.application.secrets.pesapal_consumer_secret | |
} | |
# Get the pesapal transaction identifiers | |
reference_no = params.require(:pesapal_merchant_reference) | |
tracking_no = params.require(:pesapal_transaction_tracking_id) | |
# Make sure we respond to Pesapal and also, depending on the data from | |
# Pesapal ... apply our business logic appropriately. | |
respond_to do |format| | |
# Do nothing if we don't have what we need | |
if reference_no.blank? || tracking_no.blank? | |
format.html { render nothing: true } | |
# ... else apply business login ... | |
else | |
# Get hash with response from the `ipn_listener` helper | |
# method: | |
# | |
# { | |
# status: "<PAYMENT_STATUS>", | |
# response: "<IPN_RESPONSE>" | |
# } | |
ipn_response = pesapal.ipn_listener 'CHANGE', reference_no, tracking_no | |
# If payment exists in the DB so we proceed with updating it's | |
# status. INVALID indicates that the transaction with the reference | |
# you provided could not be found. | |
payment = ::Payment.find_by reference_no: reference_no, tracking_no: tracking_no | |
apply_ipn_update payment, ipn_response[:status] if payment | |
format.html { render text: ipn_response[:response] } | |
end | |
end | |
end | |
private | |
# Apply the update to the payment depending on the response | |
def apply_ipn_update(payment, ipn_status) | |
case ipn_status | |
when 'COMPLETED' | |
# do something | |
when 'FAILED' | |
# do something | |
when 'PENDING' | |
# do something | |
when 'INVALID' | |
# do somethimg | |
end | |
end | |
# Never trust parameters from the scary internet, only allow the white list through. | |
def payment_params | |
if params.key? :payment | |
params[:payment][:reference_no] = params[:pesapal_merchant_reference] unless params[:pesapal_merchant_reference].blank? | |
params[:payment][:tracking_no] = params[:pesapal_transaction_tracking_id] unless params[:pesapal_transaction_tracking_id].blank? | |
end | |
params.require(:payment).permit(:amount, :currency_iso_code, :payable_type, :reference_no, :tracking_no) | |
end | |
end | |
end | |
end |
So I finally managed to get my development whole environment working. The issue was this http://developer.pesapal.com/forum/6-announcements/1788-https-protocol-enabled-on-our-sandbox-application. Since the api's now should be handled via HTTPS, the current gem could not work as it is. What made it work was two things (1) changing the url endpoint for development to https and (2) making sure in the query functions to always check ssl.
i.e
http = Net::HTTP.new(uri.host, uri.port)
#if @env == 'production'
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
#end
response = http.request(Net::HTTP::Get.new(uri.request_uri))
@Alfred-W I see! I used the sandbox a long time ago so wouldn't have caught that change. All my stuff is in production. Do you mind filing this as an issue? I can update the gem when I get time.
I also think that setting http.verify_mode
to OpenSSL::SSL::VERIFY_NONE
is a bad idea because we pretty much disregard the SSL certificate! ๐ ... and I don't quite remember why I did this.
@Alfred-W Turns out the issue was already raised and someone had filed a PR! ๐
Pole sana.
@Alfred-W Your issue has been fixed in v1.7.0. There's also v1.8.0 which addresses an important security concern.
Thanks for this!!
I was lost for a moment after downloading the gem.
I have an issue though. Posting the transaction to pesapal works well but querying the status keeps returning nil.
@payment_status = pesapal.query_payment_status(@reference)
The variable
@payment_status
returns nil