forked from activemerchant/active_merchant
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Tom Burns
committed
Aug 2, 2012
1 parent
75e432d
commit 01e807f
Showing
10 changed files
with
655 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
module ActiveMerchant #:nodoc: | ||
module Billing #:nodoc: | ||
module Integrations #:nodoc: | ||
module Pxpay | ||
autoload :Helper, 'active_merchant/billing/integrations/pxpay/helper.rb' | ||
autoload :Notification, 'active_merchant/billing/integrations/pxpay/notification.rb' | ||
autoload :Return, 'active_merchant/billing/integrations/pxpay/return.rb' | ||
|
||
TOKEN_URL = 'https://sec.paymentexpress.com/pxpay/pxaccess.aspx' | ||
|
||
LIVE_URL = 'https://sec.paymentexpress.com/pxpay/pxpay.aspx' | ||
|
||
def self.token_url | ||
TOKEN_URL | ||
end | ||
|
||
def self.service_url | ||
LIVE_URL | ||
end | ||
|
||
def self.notification(post, options={}) | ||
Notification.new(post, options) | ||
end | ||
|
||
def self.return(query_string, options={}) | ||
Return.new(query_string, options) | ||
end | ||
end | ||
end | ||
end | ||
end |
110 changes: 110 additions & 0 deletions
110
lib/active_merchant/billing/integrations/pxpay/helper.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
require 'active_support/core_ext/float/rounding.rb' # Float#round(precision) | ||
|
||
module ActiveMerchant #:nodoc: | ||
module Billing #:nodoc: | ||
module Integrations #:nodoc: | ||
module Pxpay | ||
# An example. Note the username as a parameter and transaction key you | ||
# will want to use later. The amount that you pass in will be *rounded*, | ||
# so preferably pass in X.2 decimal so that no rounding occurs. You need | ||
# to set :credential2 to your PxPay secret key. | ||
# | ||
# PxPay accounts have Failproof Notification enabled by default which means | ||
# in addition to the user being redirected to your return_url, the return_url will | ||
# be accessed by the PxPay servers directly, immediately after transaction success. | ||
# | ||
# payment_service_for('order_id', 'pxpay_user_ID', :service => :pxpay, | ||
# :amount => 157.0, :currency => 'USD', :credential2 => 'pxpay_key') do |service| | ||
# | ||
# service.customer :email => '[email protected]' | ||
# | ||
# service.description 'Order 123 for MyStore' | ||
# | ||
# # Must specify both a return_url or PxPay will show an error instead of | ||
# # capturing credit card details. | ||
# | ||
# service.return_url "http://t/pxpay/payment_received_notification_sub_step" | ||
# | ||
# # These fields will be copied verbatim to the Notification | ||
# service.custom1 'custom text 1' | ||
# service.custom2 '' | ||
# service.custom3 '' | ||
# # See the helper.rb file for various custom fields | ||
# end | ||
|
||
class Helper < ActiveMerchant::Billing::Integrations::Helper | ||
include PostsData | ||
mapping :account, 'PxPayUserId' | ||
mapping :credential2, 'PxPayKey' | ||
mapping :currency, 'CurrencyInput' | ||
mapping :description, 'MerchantReference' | ||
mapping :order, 'TxnId' | ||
mapping :customer, :email => 'EmailAddress' | ||
|
||
mapping :custom1, 'TxnData1' | ||
mapping :custom2, 'TxnData2' | ||
mapping :custom3, 'TxnData3' | ||
|
||
def initialize(order, account, options = {}) | ||
super | ||
add_field 'AmountInput', "%.2f" % options[:amount].to_f.round(2) | ||
add_field 'EnableAddBillCard', '0' | ||
add_field 'TxnType', 'Purchase' | ||
end | ||
|
||
def return_url(url) | ||
add_field 'UrlSuccess', url | ||
add_field 'UrlFail', url | ||
end | ||
|
||
def form_fields | ||
# if either return URLs are blank PxPay will generate a token but redirect user to error page. | ||
raise "error - must specify return_url" if @fields['UrlSuccess'].blank? | ||
raise "error - must specify cancel_return_url" if @fields['UrlFail'].blank? | ||
|
||
result = request_secure_redirect | ||
raise "error - failed to get token - message was #{result[:redirect]}" unless result[:valid] == "1" | ||
|
||
url = URI.parse(result[:redirect]) | ||
|
||
CGI.parse(url.query) | ||
end | ||
|
||
def form_method | ||
"GET" | ||
end | ||
|
||
private | ||
def generate_request | ||
xml = REXML::Document.new | ||
root = xml.add_element('GenerateRequest') | ||
|
||
@fields.each do | k, v | | ||
root.add_element(k).text = v | ||
end | ||
|
||
xml.to_s | ||
end | ||
|
||
def request_secure_redirect | ||
request = generate_request | ||
|
||
response = ssl_post(Pxpay.token_url, request) | ||
xml = REXML::Document.new(response) | ||
root = REXML::XPath.first(xml, "//Request") | ||
valid = root.attributes["valid"] | ||
redirect = root.elements["URI"].text | ||
|
||
# example positive response: | ||
# <Request valid="1"><URI>https://sec.paymentexpress.com/pxpay/pxpay.aspx?userid=PxpayUser&request=REQUEST_TOKEN</URI></Request> | ||
|
||
# example negative response: | ||
# <Request valid="0"><URI>Invalid TxnType</URI></Request> | ||
|
||
{:valid => valid, :redirect => redirect} | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
157 changes: 157 additions & 0 deletions
157
lib/active_merchant/billing/integrations/pxpay/notification.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
module ActiveMerchant #:nodoc: | ||
module Billing #:nodoc: | ||
module Integrations #:nodoc: | ||
|
||
module Pxpay | ||
class Notification < ActiveMerchant::Billing::Integrations::Notification | ||
include PostsData | ||
include RequiresParameters | ||
|
||
def initialize(query_string, options={}) | ||
# PxPay appends ?result=...&userid=... to whatever return_url was specified, even if that URL ended with a ?query. | ||
# So switch the first ? if present to a & | ||
query_string[/\?/] = '&' if query_string[/\?/] | ||
super | ||
|
||
@encrypted_params = @params | ||
@params = {} | ||
|
||
requires! @encrypted_params, "result" | ||
requires! @options, :credential1, :credential2 | ||
|
||
decrypt_transaction_result(@encrypted_params["result"]) | ||
end | ||
|
||
# was the notification a validly formed request? | ||
def acknowledge | ||
@valid == '1' | ||
end | ||
|
||
def status | ||
return 'Failed' unless success? | ||
return 'Completed' if complete? | ||
'Error' | ||
end | ||
|
||
def complete? | ||
@params['TxnType'] == 'Purchase' && success? | ||
end | ||
|
||
def cancelled? | ||
!success? | ||
end | ||
|
||
# for field definitions see | ||
# http://www.paymentexpress.com/Technical_Resources/Ecommerce_Hosted/PxPay | ||
|
||
def success? | ||
@params['Success'] == '1' | ||
end | ||
|
||
def gross | ||
@params['AmountSettlement'] | ||
end | ||
|
||
def currency | ||
@params['CurrencySettlement'] | ||
end | ||
|
||
def account | ||
@params['userid'] | ||
end | ||
|
||
def item_id | ||
@params['TxnId'] | ||
end | ||
|
||
def currency_input | ||
@params['CurrencyInput'] | ||
end | ||
|
||
def auth_code | ||
@params['AuthCode'] | ||
end | ||
|
||
def card_type | ||
@params['CardName'] | ||
end | ||
|
||
def card_holder_name | ||
@params['CardHolderName'] | ||
end | ||
|
||
def card_number | ||
@params['CardNumber'] | ||
end | ||
|
||
def expiry_date | ||
@params['DateExpiry'] | ||
end | ||
|
||
def client_ip | ||
@params['ClientInfo'] | ||
end | ||
|
||
def order_id | ||
item_id | ||
end | ||
|
||
def payer_email | ||
@params['EmailAddress'] | ||
end | ||
|
||
def transaction_id | ||
@params['DpsTxnRef'] | ||
end | ||
|
||
def settlement_date | ||
@params['DateSettlement'] | ||
end | ||
|
||
# Indication of the uniqueness of a card number | ||
def txn_mac | ||
@params['TxnMac'] | ||
end | ||
|
||
def message | ||
@params['ResponseText'] | ||
end | ||
|
||
def optional_data | ||
[@params['TxnData1'],@fields['TxnData2'],@fields['TxnData3']] | ||
end | ||
|
||
# When was this payment was received by the client. | ||
def received_at | ||
settlement_date | ||
end | ||
|
||
# Was this a test transaction? | ||
def test? | ||
nil | ||
end | ||
|
||
private | ||
|
||
def decrypt_transaction_result(encrypted_result) | ||
request_xml = REXML::Document.new | ||
root = request_xml.add_element('ProcessResponse') | ||
|
||
root.add_element('PxPayUserId').text = @options[:credential1] | ||
root.add_element('PxPayKey').text = @options[:credential2] | ||
root.add_element('Response').text = encrypted_result | ||
|
||
@raw = ssl_post(Pxpay.token_url, request_xml.to_s) | ||
|
||
response_xml = REXML::Document.new(@raw) | ||
root = REXML::XPath.first(response_xml) | ||
@valid = root.attributes["valid"] | ||
@params = {} | ||
root.elements.each { |e| @params[e.name] = e.text } | ||
end | ||
|
||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
module ActiveMerchant #:nodoc: | ||
module Billing #:nodoc: | ||
module Integrations #:nodoc: | ||
module Pxpay | ||
class Return < ActiveMerchant::Billing::Integrations::Return | ||
def initialize(query_string, options={}) | ||
@notification = Notification.new(query_string, options) | ||
end | ||
|
||
def success? | ||
@notification && @notification.complete? | ||
end | ||
|
||
def cancelled? | ||
@notification && @notification.cancelled? | ||
end | ||
|
||
def message | ||
@notification.message | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.