lib/paynow_sdk.rb in paynow_sdk-0.1.8 vs lib/paynow_sdk.rb in paynow_sdk-0.1.9

- old
+ new

@@ -1,9 +1,11 @@ require "paynow_sdk/version" -require "httparty" require "cgi" require "digest" +require "httparty" +require "uri" +require "rest-client" #throws error when hash from Paynow does not match locally generated hash class HashMismatchException < Exception def initialize(message) @@ -11,22 +13,22 @@ end end class StatusResponse @@paid = true - @@status = String + @@status = "" @@amount = Float - @@reference = String - @@paynow_reference = String - @@hash = String + @@reference = "" + @@paynow_reference = "" + @@hash = "" def __status_update(data) return "Not implemented" end def initialize(data, update) - if is_bool(update) + if update __status_update(data) else @status = data["status"].downcase @paid = @status == "paid" if data.include?("amount") @@ -81,30 +83,29 @@ def hash=(val); @hash = val; end end class InitResponse @@success = true - @@instructions = String + @@instructions = "" @@has_redirect = true - @@hash = String - @@redirect_url = String - @@error = String - @@poll_url = String + @@hash = "" + @@redirect_url = "" + @@error = "" + @@poll_url = "" def initialize(data) @status = data["status"] @success = data["status"].downcase != "error" @has_redirect = data.include?("browserurl") @hash = data.include?("hash") - if is_bool(!@success) - return + if !@success + @poll_url = data["pollurl"] end - @poll_url = data["pollurl"] - if is_bool(!@success) + if !@success @error = data["error"] end - if is_bool(@has_redirect) + if @has_redirect @redirect_url = data["browserurl"] end if data.include?("instructions") @instruction = data["instructions"] end @@ -152,39 +153,39 @@ def poll_url; @poll_url = @@poll_url if @poll_url.nil?; @poll_url; end def poll_url=(val); @poll_url = val; end end class Payment - @@reference = String + @@reference = "" @@items = [] - @@auth_email = String + @@auth_email = "" def initialize(reference, auth_email) @reference = reference @auth_email = auth_email end def add(title, amount) @items = [] @items.push([title, amount]) - return self + self end - def total() + def total total = 0.0 for item in @items total += item[1].to_f end - return total + total end - def info() + def info out = "" for item in @items out += item[0] + ", " end - return out + out end def self.reference; @@reference; end def self.reference=(val); @@reference = val; end @@ -203,14 +204,14 @@ def auth_email; @auth_email = @@auth_email if @auth_email.nil?; @auth_email; end def auth_email=(val); @auth_email = val; end end class Paynow - @@url_initiate_transaction = URI("https://www.paynow.co.zw/interface/initiatetransaction") - @@url_initiate_mobile_transaction = "https://www.paynow.co.zw/interface/remotetransaction" - @@integration_id = String - @@integration_key = String + @@url_initiate_transaction = "https://www.paynow.co.zw/interface/initiatetransaction/" + @@url_initiate_mobile_transaction = "https://www.paynow.co.zw/interface/remotetransaction/" + @@integration_id = "" + @@integration_key = "" @@return_url = "" @@result_url = "" def initialize(integration_id, integration_key, return_url, result_url) @integration_id = integration_id @@ -226,127 +227,117 @@ def set_return_url(url) @return_url = url end def create_payment(reference, auth_email) - return Payment.new(reference, auth_email) + Payment.new(reference, auth_email) end def send(payment) - return __init(payment) + init(payment) end def send_mobile(payment, phone, method) - return __init_mobile(payment, phone, method) + init_mobile(payment, phone, method) end def process_status_update(data) - return StatusResponse.new(data, true) + StatusResponse.new(data, true) end - def qs_to_hash(querystring) - keyvals = querystring.split("&").inject({}) do |result, q| - k, v = q.split("=") - if !v.nil? - result.merge({ k => v }) - elsif !result.key?(k) - result.merge({ k => true }) - else - result - end - end - keyvals - end + # def qs_to_hash(querystring) + # keyvals = querystring.split("&").inject({}) do |result, q| + # k, v = q.split("=") + # if !v.nil? + # result.merge({ k => v }) + # elsif !result.key?(k) + # result.merge({ k => true }) + # else + # result + # end + # end + # keyvals + # end - def __init(payment) - if payment.total() <= 0 + def init(payment) + if payment.total <= 0 raise TypeError, "Transaction total cannot be less than 1" end - data = __build(payment) - response = HTTParty.post(@url_initiate_transaction, data) - response_object = __rebuild_response(CGI.parse(response)) - if response_object["status"].to_s.downcase == "error" - return InitResponse.new(response_object) - end - if is_bool(!__verify_hash(response_object, @integration_key)) - raise HashMismatchException, "Hashes do not match" - end - return InitResponse.new(response_object) - end + data = build(payment) - def __init_mobile(payment, phone, method) - if payment.total() <= 0 - raise TypeError, "Transaction total cannot be less than 1" - end - if is_bool(!payment.auth_email || payment.auth_email.size <= 0) - raise TypeError, "Auth email is required for mobile transactions. You can pass the auth email as the second parameter in the create_payment method call" - end - data = __build_mobile(payment, phone, method) - response = HTTParty.post(@url_initiate_mobile_transaction, data) - response_object = __rebuild_response(CGI.parse(response)) + response = RestClient.post("https://www.paynow.co.zw/interface/initiatetransaction/", data) + response_object = rebuild_response(response) + if response_object["status"].to_s.downcase == "error" - return InitResponse.new(response_object) + InitResponse.new(response_object) end - if is_bool(!__verify_hash(response_object, @integration_key)) - raise HashMismatchException, "Hashes do not match" - end - return InitResponse.new(response_object) + # if !verify_hash(response_object, @integration_key) + # raise HashMismatchException, "Hashes do not match" + # end + InitResponse.new(response_object) end + # def init_mobile(payment, phone, method) + # if payment.total <= 0 + # raise TypeError, "Transaction total cannot be less than 1" + # end + # if is_bool(!payment.auth_email || payment.auth_email.size <= 0) + # raise TypeError, "Auth email is required for mobile transactions. You can pass the auth email as the second parameter in the create_payment method call" + # end + # data = build_mobile(payment, phone, method) + # response = HTTParty.post(@url_initiate_mobile_transaction, data) + # response_object = rebuild_response(response) + # if response_object["status"].to_s.downcase == "error" + # InitResponse.new(response_object) + # end + # if is_bool(!verify_hash(response_object, @integration_key)) + # raise HashMismatchException, "Hashes do not match" + # end + # InitResponse.new(response_object) + # end + def check_transaction_status(poll_url) response = HTTParty.post(poll_url, data: {}) - response_object = __rebuild_response(CGI.parse(response)) - return StatusResponse.new(response_object, false) + response_object = rebuild_response(response) + StatusResponse.new(response_object, false) end - def __build(payment) - body = { "resulturl" => @result_url, "returnurl" => @return_url, "reference" => payment.reference, "amount" => payment.total(), "id" => @integration_id, "additionalinfo" => payment.info(), "authemail" => payment.auth_email || "", "status" => "Message" } - for (key, value) in body - body[key] = CGI::escape(value.to_s) - end - body["hash"] = __hash(body, @integration_key) + def build(payment) + body = { "resulturl": @result_url, "returnurl": @return_url, "reference": payment.reference, "amount": payment.total, "id": @integration_id, "additionalinfo": payment.info, "authemail": payment.auth_email || "", "status": "Message" } + joined = body.values.join.to_s + add_key = joined += @integration_key + body["hash"] = createdhash(add_key) + body = URI.encode_www_form(body) body end - def __build_mobile(payment, phone, method) - body = { "resulturl" => @result_url, "returnurl" => @return_url, "reference" => payment.reference, "amount" => payment.total(), "id" => @integration_id, "additionalinfo" => payment.info(), "authemail" => payment.auth_email, "phone" => phone, "method" => method, "status" => "Message" } - for (key, value) in body - if key == "authemail" - next - end - body[key] = CGI::escape(value.to_s) - end - body["hash"] = __hash(body, @integration_key) + def build_mobile(payment, phone, method) + body = { "resulturl": @result_url, "returnurl": @return_url, "reference": payment.reference, "amount": payment.total, "id": @integration_id, "additionalinfo": payment.info, "authemail": payment.auth_email, "phone": phone, "method": method, "status": "Message" } + joined = body.values.join.to_s + add_key = joined += @integration_key + body["hash"] = createdhash(add_key) + body = URI.encode_www_form(body) body end - def __hash(items, integration_key) - out = "" - for (key, value) in items - if key.to_s.downcase == "hash" - next - end - out += value.to_s - end - out += integration_key.downcase + def createdhash(out) Digest::SHA2.new(512).hexdigest(out).upcase end - def __verify_hash(response, integration_key) - if !response.include?("hash") - raise TypeError, "Response from Paynow does not contain a hash" - end - old_hash = response["hash"] - new_hash = __hash(response, integration_key) - return old_hash == new_hash - end + #verify the hash send to paynow is equal to the hash from paynow + # def verify_hash(response) + # # if !response.include?("hash") + # # raise TypeError, "Response from Paynow does not contain a hash" + # # end + # old_hash = response["hash"] + # new_hash = createdhash(response) + # old_hash == new_hash + # end - def __rebuild_response(response) - res = {} - for (key, value) in response.to_a - res[key] = value[0].to_s - end - return res + # rebuild a response from paynow into hash like the we send + + def rebuild_response(response) + URI.decode_www_form(response).to_h end def self.url_initiate_transaction; @@url_initiate_transaction; end def self.url_initiate_transaction=(val); @@url_initiate_transaction = val; end