activemerchant 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +226 -0
- data/CONTRIBUTERS +52 -0
- data/README +34 -24
- data/Rakefile +152 -0
- data/gem-public_cert.pem +20 -0
- data/init.rb +3 -0
- data/lib/active_merchant.rb +3 -1
- data/lib/active_merchant/billing/credit_card.rb +21 -17
- data/lib/active_merchant/billing/credit_card_methods.rb +17 -19
- data/lib/active_merchant/billing/gateway.rb +160 -44
- data/lib/active_merchant/billing/gateways.rb +2 -15
- data/lib/active_merchant/billing/gateways/authorize_net.rb +21 -21
- data/lib/active_merchant/billing/gateways/bogus.rb +6 -6
- data/lib/active_merchant/billing/gateways/brain_tree.rb +191 -0
- data/lib/active_merchant/billing/gateways/card_stream.rb +207 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +402 -0
- data/lib/active_merchant/billing/gateways/data_cash.rb +41 -97
- data/lib/active_merchant/billing/gateways/efsnet.rb +256 -0
- data/lib/active_merchant/billing/gateways/eway.rb +77 -29
- data/lib/active_merchant/billing/gateways/exact.rb +230 -0
- data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -33
- data/lib/active_merchant/billing/gateways/moneris.rb +155 -125
- data/lib/active_merchant/billing/gateways/net_registry.rb +257 -0
- data/lib/active_merchant/billing/gateways/pay_junction.rb +407 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +163 -25
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +56 -38
- data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +10 -1
- data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +9 -0
- data/lib/active_merchant/billing/gateways/payflow_express.rb +36 -11
- data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +6 -0
- data/lib/active_merchant/billing/gateways/payflow_uk.rb +7 -3
- data/lib/active_merchant/billing/gateways/payment_express.rb +261 -0
- data/lib/active_merchant/billing/gateways/paypal.rb +18 -4
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +31 -15
- data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +8 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +33 -8
- data/lib/active_merchant/billing/gateways/plugnpay.rb +300 -0
- data/lib/active_merchant/billing/gateways/protx.rb +285 -0
- data/lib/active_merchant/billing/gateways/psigate.rb +13 -12
- data/lib/active_merchant/billing/gateways/psl_card.rb +297 -0
- data/lib/active_merchant/billing/gateways/quickpay.rb +197 -0
- data/lib/active_merchant/billing/gateways/realex.rb +212 -0
- data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
- data/lib/active_merchant/billing/gateways/trans_first.rb +136 -0
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +43 -20
- data/lib/active_merchant/billing/gateways/usa_epay.rb +6 -5
- data/lib/active_merchant/billing/gateways/verifi.rb +235 -0
- data/lib/active_merchant/billing/gateways/viaklix.rb +171 -0
- data/lib/active_merchant/billing/integrations/gestpay/helper.rb +0 -2
- data/lib/active_merchant/billing/integrations/helper.rb +8 -1
- data/lib/active_merchant/billing/integrations/nochex.rb +62 -1
- data/lib/active_merchant/billing/integrations/nochex/notification.rb +9 -16
- data/lib/active_merchant/billing/integrations/notification.rb +1 -1
- data/lib/active_merchant/billing/integrations/paypal/helper.rb +59 -46
- data/lib/active_merchant/billing/integrations/paypal/notification.rb +14 -47
- data/lib/active_merchant/lib/error.rb +4 -0
- data/lib/active_merchant/lib/post_data.rb +22 -0
- data/lib/active_merchant/lib/posts_data.rb +23 -5
- data/lib/active_merchant/lib/requires_parameters.rb +2 -2
- data/lib/active_merchant/lib/validateable.rb +1 -1
- data/lib/support/gateway_support.rb +45 -0
- data/lib/tasks/cia.rb +1 -1
- data/script/generate +14 -0
- data/script/generator/base.rb +45 -0
- data/script/generator/generator.rb +24 -0
- data/script/generator/generators/gateway/gateway_generator.rb +14 -0
- data/script/generator/generators/gateway/templates/gateway.rb +73 -0
- data/script/generator/generators/gateway/templates/gateway_test.rb +41 -0
- data/script/generator/generators/gateway/templates/remote_gateway_test.rb +56 -0
- data/script/generator/generators/integration/integration_generator.rb +25 -0
- data/script/generator/generators/integration/templates/helper.rb +34 -0
- data/script/generator/generators/integration/templates/helper_test.rb +54 -0
- data/script/generator/generators/integration/templates/integration.rb +18 -0
- data/script/generator/generators/integration/templates/module_test.rb +9 -0
- data/script/generator/generators/integration/templates/notification.rb +100 -0
- data/script/generator/generators/integration/templates/notification_test.rb +41 -0
- data/script/generator/manifest.rb +20 -0
- data/test/extra/binding_of_caller.rb +80 -0
- data/test/extra/breakpoint.rb +547 -0
- data/test/fixtures.yml +251 -0
- data/test/remote_tests/remote_authorize_net_test.rb +113 -0
- data/test/remote_tests/remote_brain_tree_test.rb +78 -0
- data/test/remote_tests/remote_card_stream_test.rb +160 -0
- data/test/remote_tests/remote_cyber_source_test.rb +130 -0
- data/test/remote_tests/remote_data_cash_test.rb +155 -0
- data/test/remote_tests/remote_efsnet_test.rb +93 -0
- data/test/remote_tests/remote_eway_test.rb +71 -0
- data/test/remote_tests/remote_exact_test.rb +59 -0
- data/test/remote_tests/remote_gestpay_integration_test.rb +37 -0
- data/test/remote_tests/remote_linkpoint_test.rb +144 -0
- data/test/remote_tests/remote_moneris_test.rb +110 -0
- data/test/remote_tests/remote_net_registry_test.rb +120 -0
- data/test/remote_tests/remote_pay_junction_test.rb +162 -0
- data/test/remote_tests/remote_payflow_express_test.rb +50 -0
- data/test/remote_tests/remote_payflow_test.rb +241 -0
- data/test/remote_tests/remote_payflow_uk_test.rb +172 -0
- data/test/remote_tests/remote_payment_express_test.rb +136 -0
- data/test/remote_tests/remote_paypal_express_test.rb +49 -0
- data/test/remote_tests/remote_paypal_integration_test.rb +14 -0
- data/test/remote_tests/remote_paypal_test.rb +163 -0
- data/test/remote_tests/remote_plugnpay_test.rb +70 -0
- data/test/remote_tests/remote_protx_test.rb +184 -0
- data/test/remote_tests/remote_psigate_test.rb +87 -0
- data/test/remote_tests/remote_psl_card_test.rb +105 -0
- data/test/remote_tests/remote_quickpay_test.rb +182 -0
- data/test/remote_tests/remote_realex_test.rb +227 -0
- data/test/remote_tests/remote_secure_pay_test.rb +36 -0
- data/test/remote_tests/remote_trans_first_test.rb +37 -0
- data/test/remote_tests/remote_trust_commerce_test.rb +136 -0
- data/test/remote_tests/remote_usa_epay_test.rb +57 -0
- data/test/remote_tests/remote_verifi_test.rb +107 -0
- data/test/remote_tests/remote_viaklix_test.rb +53 -0
- data/test/test_helper.rb +132 -0
- data/test/unit/base_test.rb +61 -0
- data/test/unit/country_code_test.rb +33 -0
- data/test/unit/country_test.rb +64 -0
- data/test/unit/credit_card_formatting_test.rb +24 -0
- data/test/unit/credit_card_methods_test.rb +37 -0
- data/test/unit/credit_card_test.rb +365 -0
- data/test/unit/gateways/authorize_net_test.rb +140 -0
- data/test/unit/gateways/bogus_test.rb +43 -0
- data/test/unit/gateways/brain_tree_test.rb +77 -0
- data/test/unit/gateways/card_stream_test.rb +37 -0
- data/test/unit/gateways/cyber_source_test.rb +151 -0
- data/test/unit/gateways/data_cash_test.rb +23 -0
- data/test/unit/gateways/efsnet_test.rb +70 -0
- data/test/unit/gateways/eway_test.rb +105 -0
- data/test/unit/gateways/exact_test.rb +118 -0
- data/test/unit/gateways/gateway_test.rb +24 -0
- data/test/unit/gateways/linkpoint_test.rb +165 -0
- data/test/unit/gateways/moneris_test.rb +167 -0
- data/test/unit/gateways/net_registry_test.rb +478 -0
- data/test/unit/gateways/pay_junction_test.rb +61 -0
- data/test/unit/gateways/payflow_express_test.rb +165 -0
- data/test/unit/gateways/payflow_express_uk_test.rb +14 -0
- data/test/unit/gateways/payflow_test.rb +230 -0
- data/test/unit/gateways/payflow_uk_test.rb +68 -0
- data/test/unit/gateways/payment_express_test.rb +215 -0
- data/test/unit/gateways/paypal_express_test.rb +222 -0
- data/test/unit/gateways/paypal_test.rb +241 -0
- data/test/unit/gateways/plugnpay_test.rb +79 -0
- data/test/unit/gateways/protx_test.rb +110 -0
- data/test/unit/gateways/psigate_test.rb +110 -0
- data/test/unit/gateways/psl_card_test.rb +51 -0
- data/test/unit/gateways/quickpay_test.rb +125 -0
- data/test/unit/gateways/realex_test.rb +150 -0
- data/test/unit/gateways/secure_pay_test.rb +78 -0
- data/test/unit/gateways/trans_first_test.rb +125 -0
- data/test/unit/gateways/trust_commerce_test.rb +57 -0
- data/test/unit/gateways/usa_epay_test.rb +117 -0
- data/test/unit/gateways/verifi_test.rb +91 -0
- data/test/unit/gateways/viaklix_test.rb +72 -0
- data/test/unit/integrations/action_view_helper_test.rb +54 -0
- data/test/unit/integrations/bogus_module_test.rb +16 -0
- data/test/unit/integrations/chronopay_module_test.rb +9 -0
- data/test/unit/integrations/gestpay_module_test.rb +10 -0
- data/test/unit/integrations/helpers/bogus_helper_test.rb +28 -0
- data/test/unit/integrations/helpers/chronopay_helper_test.rb +67 -0
- data/test/unit/integrations/helpers/gestpay_helper_test.rb +100 -0
- data/test/unit/integrations/helpers/nochex_helper_test.rb +53 -0
- data/test/unit/integrations/helpers/paypal_helper_test.rb +162 -0
- data/test/unit/integrations/helpers/two_checkout_helper_test.rb +92 -0
- data/test/unit/integrations/nochex_module_test.rb +9 -0
- data/test/unit/integrations/notifications/chronopay_notification_test.rb +66 -0
- data/test/unit/integrations/notifications/gestpay_notification_test.rb +60 -0
- data/test/unit/integrations/notifications/nochex_notification_test.rb +51 -0
- data/test/unit/integrations/notifications/notification_test.rb +41 -0
- data/test/unit/integrations/notifications/paypal_notification_test.rb +85 -0
- data/test/unit/integrations/notifications/two_checkout_notification_test.rb +55 -0
- data/test/unit/integrations/paypal_module_test.rb +24 -0
- data/test/unit/integrations/two_checkout_module_test.rb +9 -0
- data/test/unit/post_data_test.rb +55 -0
- data/test/unit/response_test.rb +14 -0
- data/test/unit/validateable_test.rb +56 -0
- metadata +160 -7
- metadata.gz.sig +0 -0
- data/lib/active_merchant/billing/gateways/payflow/f73e89fd.0 +0 -17
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
require 'digest/sha1'
|
|
2
|
-
|
|
3
1
|
module ActiveMerchant #:nodoc:
|
|
4
2
|
module Billing #:nodoc:
|
|
5
3
|
module PayflowCommonAPI
|
|
6
4
|
def self.included(base)
|
|
7
|
-
base.class_inheritable_accessor :default_currency
|
|
8
5
|
base.default_currency = 'USD'
|
|
9
6
|
|
|
10
7
|
# The certification_id is required by PayPal to make direct HTTPS posts to their servers.
|
|
11
|
-
#
|
|
8
|
+
# The certification_id has been deprecated by PayPal. It will soon be removed and you can simply
|
|
9
|
+
# use the certification_id that has been configured here, or generate your own
|
|
12
10
|
base.class_inheritable_accessor :certification_id
|
|
11
|
+
base.certification_id = '55d64dfec398cbbe66c1bf843cbad9'
|
|
12
|
+
|
|
13
13
|
base.class_inheritable_accessor :partner
|
|
14
14
|
|
|
15
15
|
# Set the default partner to PayPal
|
|
16
16
|
base.partner = 'PayPal'
|
|
17
|
+
|
|
18
|
+
base.supported_countries = ['US', 'CA', 'SG', 'AU']
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
XMLNS = 'http://www.paypal.com/XMLPay'
|
|
@@ -30,6 +32,14 @@ module ActiveMerchant #:nodoc:
|
|
|
30
32
|
:switch => 'Switch',
|
|
31
33
|
:solo => 'Solo'
|
|
32
34
|
}
|
|
35
|
+
|
|
36
|
+
TRANSACTIONS = {
|
|
37
|
+
:purchase => "Sale",
|
|
38
|
+
:authorization => "Authorization",
|
|
39
|
+
:capture => "Capture",
|
|
40
|
+
:void => "Void",
|
|
41
|
+
:credit => "Credit"
|
|
42
|
+
}
|
|
33
43
|
|
|
34
44
|
def initialize(options = {})
|
|
35
45
|
requires!(options, :login, :password)
|
|
@@ -46,33 +56,37 @@ module ActiveMerchant #:nodoc:
|
|
|
46
56
|
end
|
|
47
57
|
|
|
48
58
|
def capture(money, authorization, options = {})
|
|
49
|
-
request =
|
|
59
|
+
request = build_reference_request(:capture, money, authorization, options)
|
|
50
60
|
commit(request)
|
|
51
61
|
end
|
|
52
62
|
|
|
53
63
|
def void(authorization, options = {})
|
|
54
|
-
request =
|
|
64
|
+
request = build_reference_request(:void, nil, authorization, options)
|
|
55
65
|
commit(request)
|
|
56
66
|
end
|
|
57
|
-
|
|
67
|
+
|
|
58
68
|
private
|
|
59
|
-
def build_request(body)
|
|
69
|
+
def build_request(body, request_type = nil)
|
|
60
70
|
xml = Builder::XmlMarkup.new :indent => 2
|
|
61
71
|
xml.instruct!
|
|
62
72
|
xml.tag! 'XMLPayRequest', 'Timeout' => 30, 'version' => "2.1", "xmlns" => XMLNS do
|
|
63
73
|
xml.tag! 'RequestData' do
|
|
64
74
|
xml.tag! 'Vendor', @options[:login]
|
|
65
75
|
xml.tag! 'Partner', @options[:partner]
|
|
66
|
-
|
|
67
|
-
xml
|
|
68
|
-
|
|
69
|
-
|
|
76
|
+
if request_type == :recurring
|
|
77
|
+
xml << body
|
|
78
|
+
else
|
|
79
|
+
xml.tag! 'Transactions' do
|
|
80
|
+
xml.tag! 'Transaction' do
|
|
81
|
+
xml.tag! 'Verbosity', 'MEDIUM'
|
|
82
|
+
xml << body
|
|
83
|
+
end
|
|
70
84
|
end
|
|
71
85
|
end
|
|
72
86
|
end
|
|
73
87
|
xml.tag! 'RequestAuth' do
|
|
74
88
|
xml.tag! 'UserPass' do
|
|
75
|
-
xml.tag! 'User', @options[:login]
|
|
89
|
+
xml.tag! 'User', !@options[:user].blank? ? @options[:user] : @options[:login]
|
|
76
90
|
xml.tag! 'Password', @options[:password]
|
|
77
91
|
end
|
|
78
92
|
end
|
|
@@ -80,21 +94,20 @@ module ActiveMerchant #:nodoc:
|
|
|
80
94
|
xml.target!
|
|
81
95
|
end
|
|
82
96
|
|
|
83
|
-
def
|
|
97
|
+
def build_reference_request(action, money, authorization, options)
|
|
84
98
|
xml = Builder::XmlMarkup.new :indent => 2
|
|
85
|
-
xml.tag! action do
|
|
99
|
+
xml.tag! TRANSACTIONS[action] do
|
|
86
100
|
xml.tag! 'PNRef', authorization
|
|
101
|
+
|
|
102
|
+
unless money.nil?
|
|
103
|
+
xml.tag! 'Invoice' do
|
|
104
|
+
xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
87
107
|
end
|
|
108
|
+
|
|
88
109
|
xml.target!
|
|
89
110
|
end
|
|
90
|
-
|
|
91
|
-
def add_paypal_details(xml, options)
|
|
92
|
-
xml.tag! 'PayPal' do
|
|
93
|
-
xml.tag! 'EMail', options[:email]
|
|
94
|
-
xml.tag! 'ReturnURL', options[:return_url]
|
|
95
|
-
xml.tag! 'CancelURL', options[:cancel_return_url]
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
111
|
|
|
99
112
|
def add_address(xml, tag, address, options)
|
|
100
113
|
return if address.nil?
|
|
@@ -105,7 +118,7 @@ module ActiveMerchant #:nodoc:
|
|
|
105
118
|
xml.tag! 'Address' do
|
|
106
119
|
xml.tag! 'Street', address[:address1] unless address[:address1].blank?
|
|
107
120
|
xml.tag! 'City', address[:city] unless address[:city].blank?
|
|
108
|
-
xml.tag! 'State', address[:state]
|
|
121
|
+
xml.tag! 'State', address[:state].blank? ? "N/A" : address[:state]
|
|
109
122
|
xml.tag! 'Country', address[:country] unless address[:country].blank?
|
|
110
123
|
xml.tag! 'Zip', address[:zip] unless address[:zip].blank?
|
|
111
124
|
end
|
|
@@ -131,19 +144,13 @@ module ActiveMerchant #:nodoc:
|
|
|
131
144
|
def parse_element(response, node)
|
|
132
145
|
if node.has_elements?
|
|
133
146
|
node.elements.each{|e| parse_element(response, e) }
|
|
147
|
+
elsif node.name == 'ExtData'
|
|
148
|
+
response[node.attributes['Name'].underscore.to_sym] = node.attributes['Value']
|
|
134
149
|
else
|
|
135
150
|
response[node.name.underscore.to_sym] = node.text
|
|
136
151
|
end
|
|
137
152
|
end
|
|
138
153
|
|
|
139
|
-
def generate_request_token
|
|
140
|
-
Digest::SHA1.hexdigest(rand.to_s).slice(0,32)
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def currency(money)
|
|
144
|
-
money.respond_to?(:currency) ? money.currency : self.default_currency
|
|
145
|
-
end
|
|
146
|
-
|
|
147
154
|
def build_headers(content_length)
|
|
148
155
|
{
|
|
149
156
|
"Content-Type" => "text/xml",
|
|
@@ -152,16 +159,21 @@ module ActiveMerchant #:nodoc:
|
|
|
152
159
|
"X-VPS-VIT-Client-Certification-Id" => @options[:certification_id].to_s,
|
|
153
160
|
"X-VPS-VIT-Integration-Product" => "ActiveMerchant",
|
|
154
161
|
"X-VPS-VIT-Runtime-Version" => RUBY_VERSION,
|
|
155
|
-
"X-VPS-Request-ID" =>
|
|
162
|
+
"X-VPS-Request-ID" => generate_unique_id
|
|
156
163
|
}
|
|
157
164
|
end
|
|
158
165
|
|
|
159
|
-
def commit(request_body)
|
|
160
|
-
request = build_request(request_body)
|
|
161
|
-
headers = build_headers(
|
|
162
|
-
|
|
166
|
+
def commit(request_body, request_type = nil)
|
|
167
|
+
request = build_request(request_body, request_type)
|
|
168
|
+
headers = build_headers(request.size)
|
|
169
|
+
|
|
170
|
+
if result = test_result_from_cc_number(parse_credit_card_number(request))
|
|
171
|
+
return result
|
|
172
|
+
end
|
|
173
|
+
|
|
163
174
|
url = test? ? TEST_URL : LIVE_URL
|
|
164
175
|
data = ssl_post(url, request, headers)
|
|
176
|
+
|
|
165
177
|
@response = parse(data)
|
|
166
178
|
|
|
167
179
|
success = @response[:result] == "0"
|
|
@@ -169,9 +181,15 @@ module ActiveMerchant #:nodoc:
|
|
|
169
181
|
|
|
170
182
|
build_response(success, message, @response,
|
|
171
183
|
:test => test?,
|
|
172
|
-
:authorization => @response[:pn_ref]
|
|
184
|
+
:authorization => @response[:pn_ref] || @response[:rp_ref]
|
|
173
185
|
)
|
|
174
186
|
end
|
|
187
|
+
|
|
188
|
+
def parse_credit_card_number(request)
|
|
189
|
+
xml = REXML::Document.new(request)
|
|
190
|
+
card_number = REXML::XPath.first(xml, '//Tender/Card/CardNum')
|
|
191
|
+
card_number && card_number.text
|
|
192
|
+
end
|
|
175
193
|
end
|
|
176
194
|
end
|
|
177
195
|
end
|
|
@@ -5,6 +5,10 @@ module ActiveMerchant #:nodoc:
|
|
|
5
5
|
@params['e_mail']
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
+
def full_name
|
|
9
|
+
"#{@params['name']} #{@params['lastname']}"
|
|
10
|
+
end
|
|
11
|
+
|
|
8
12
|
def token
|
|
9
13
|
@params['token']
|
|
10
14
|
end
|
|
@@ -13,8 +17,13 @@ module ActiveMerchant #:nodoc:
|
|
|
13
17
|
@params['payer_id']
|
|
14
18
|
end
|
|
15
19
|
|
|
20
|
+
# Really the shipping country, but it is all the information provided
|
|
21
|
+
def payer_country
|
|
22
|
+
address['country']
|
|
23
|
+
end
|
|
24
|
+
|
|
16
25
|
def address
|
|
17
|
-
{ 'name' =>
|
|
26
|
+
{ 'name' => full_name,
|
|
18
27
|
'company' => nil,
|
|
19
28
|
'address1' => @params['street'],
|
|
20
29
|
'address2' => nil,
|
|
@@ -3,12 +3,15 @@ require File.dirname(__FILE__) + '/payflow/payflow_express_response'
|
|
|
3
3
|
|
|
4
4
|
module ActiveMerchant #:nodoc:
|
|
5
5
|
module Billing #:nodoc:
|
|
6
|
-
class PayflowExpressGateway < Gateway
|
|
6
|
+
class PayflowExpressGateway < Gateway
|
|
7
7
|
include PayflowCommonAPI
|
|
8
8
|
|
|
9
9
|
LIVE_REDIRECT_URL = 'https://www.paypal.com/cgibin/webscr?cmd=_express-checkout&token='
|
|
10
10
|
TEST_REDIRECT_URL = 'https://test-expresscheckout.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token='
|
|
11
11
|
|
|
12
|
+
self.homepage_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=xpt/merchant/ExpressCheckoutIntro-outside'
|
|
13
|
+
self.display_name = 'PayPal Express Checkout'
|
|
14
|
+
|
|
12
15
|
def redirect_url
|
|
13
16
|
test? ? TEST_REDIRECT_URL : LIVE_REDIRECT_URL
|
|
14
17
|
end
|
|
@@ -27,8 +30,13 @@ module ActiveMerchant #:nodoc:
|
|
|
27
30
|
requires!(options, :token, :payer_id)
|
|
28
31
|
request = build_sale_or_authorization_request('Sale', money, options)
|
|
29
32
|
commit(request)
|
|
30
|
-
end
|
|
31
|
-
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def credit(money, identification, options = {})
|
|
36
|
+
request = build_reference_request(:credit, money, identification, options)
|
|
37
|
+
commit(request)
|
|
38
|
+
end
|
|
39
|
+
|
|
32
40
|
def setup_authorization(money, options = {})
|
|
33
41
|
requires!(options, :return_url, :cancel_return_url)
|
|
34
42
|
|
|
@@ -46,7 +54,7 @@ module ActiveMerchant #:nodoc:
|
|
|
46
54
|
def details_for(token)
|
|
47
55
|
request = build_get_express_details_request(token)
|
|
48
56
|
commit(request)
|
|
49
|
-
end
|
|
57
|
+
end
|
|
50
58
|
|
|
51
59
|
private
|
|
52
60
|
def build_get_express_details_request(token)
|
|
@@ -81,7 +89,7 @@ module ActiveMerchant #:nodoc:
|
|
|
81
89
|
add_address(xml, 'BillTo', billing_address, options)
|
|
82
90
|
add_address(xml, 'ShipTo', shipping_address, options)
|
|
83
91
|
|
|
84
|
-
xml.tag! 'TotalAmt', amount(money), 'Currency' => currency(money)
|
|
92
|
+
xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
|
|
85
93
|
end
|
|
86
94
|
|
|
87
95
|
xml.tag! 'Tender' do
|
|
@@ -99,14 +107,10 @@ module ActiveMerchant #:nodoc:
|
|
|
99
107
|
xml.tag! action do
|
|
100
108
|
xml.tag! 'PayData' do
|
|
101
109
|
xml.tag! 'Invoice' do
|
|
102
|
-
xml.tag! 'TotalAmt', amount(money), 'Currency' => currency(money)
|
|
110
|
+
xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
|
|
103
111
|
end
|
|
104
112
|
xml.tag! 'Tender' do
|
|
105
|
-
xml
|
|
106
|
-
xml.tag! 'Token', options[:token]
|
|
107
|
-
xml.tag! 'PayerID', options[:payer_id]
|
|
108
|
-
xml.tag! 'NotifyURL', options[:notify_url]
|
|
109
|
-
end
|
|
113
|
+
add_paypal_details xml, options
|
|
110
114
|
end
|
|
111
115
|
end
|
|
112
116
|
end
|
|
@@ -114,6 +118,27 @@ module ActiveMerchant #:nodoc:
|
|
|
114
118
|
xml.target!
|
|
115
119
|
end
|
|
116
120
|
|
|
121
|
+
def add_paypal_details(xml, options)
|
|
122
|
+
xml.tag! 'PayPal' do
|
|
123
|
+
xml.tag! 'EMail', options[:email] unless options[:email].blank?
|
|
124
|
+
xml.tag! 'ReturnURL', options[:return_url] unless options[:return_url].blank?
|
|
125
|
+
xml.tag! 'CancelURL', options[:cancel_return_url] unless options[:cancel_return_url].blank?
|
|
126
|
+
xml.tag! 'NotifyURL', options[:notify_url] unless options[:notify_url].blank?
|
|
127
|
+
xml.tag! 'PayerID', options[:payer_id] unless options[:payer_id].blank?
|
|
128
|
+
xml.tag! 'Token', options[:token] unless options[:token].blank?
|
|
129
|
+
xml.tag! 'NoShipping', options[:no_shipping] ? '1' : '0'
|
|
130
|
+
xml.tag! 'AddressOverride', options[:address_override] ? '1' : '0'
|
|
131
|
+
xml.tag! 'ButtonSource', application_id.to_s.slice(0,32) unless application_id.blank?
|
|
132
|
+
|
|
133
|
+
# Customization of the payment page
|
|
134
|
+
xml.tag! 'PageStyle', options[:page_style] unless options[:page_style].blank?
|
|
135
|
+
xml.tag! 'HeaderImage', options[:header_image] unless options[:header_image].blank?
|
|
136
|
+
xml.tag! 'HeaderBackColor', options[:header_background_color] unless options[:header_background_color].blank?
|
|
137
|
+
xml.tag! 'HeaderBorderColor', options[:header_border_color] unless options[:header_border_color].blank?
|
|
138
|
+
xml.tag! 'PayflowColor', options[:background_color] unless options[:background_color].blank?
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
117
142
|
def build_response(success, message, response, options = {})
|
|
118
143
|
PayflowExpressResponse.new(success, message, response, options)
|
|
119
144
|
end
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/payflow_express'
|
|
2
|
+
|
|
1
3
|
module ActiveMerchant #:nodoc:
|
|
2
4
|
module Billing #:nodoc:
|
|
3
5
|
class PayflowExpressUkGateway < PayflowExpressGateway
|
|
4
6
|
self.default_currency = 'GBP'
|
|
5
7
|
self.partner = 'PayPalUk'
|
|
8
|
+
|
|
9
|
+
self.supported_countries = ['GB']
|
|
10
|
+
self.homepage_url = 'https://www.paypal.com/uk/cgi-bin/webscr?cmd=_additional-payment-overview-outside'
|
|
11
|
+
self.display_name = 'PayPal Express Checkout (UK)'
|
|
6
12
|
end
|
|
7
13
|
end
|
|
8
14
|
end
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/payflow'
|
|
2
|
+
require File.dirname(__FILE__) + '/payflow_express_uk'
|
|
3
|
+
|
|
1
4
|
module ActiveMerchant #:nodoc:
|
|
2
5
|
module Billing #:nodoc:
|
|
3
6
|
class PayflowUkGateway < PayflowGateway
|
|
@@ -8,9 +11,10 @@ module ActiveMerchant #:nodoc:
|
|
|
8
11
|
@express ||= PayflowExpressUkGateway.new(@options)
|
|
9
12
|
end
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :solo, :switch]
|
|
15
|
+
self.supported_countries = ['GB']
|
|
16
|
+
self.homepage_url = 'https://www.paypal.com/uk/cgi-bin/webscr?cmd=_wp-pro-overview-outside'
|
|
17
|
+
self.display_name = 'PayPal Website Payments Pro (UK)'
|
|
14
18
|
end
|
|
15
19
|
end
|
|
16
20
|
end
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
require 'rexml/document'
|
|
2
|
+
|
|
3
|
+
module ActiveMerchant
|
|
4
|
+
module Billing
|
|
5
|
+
|
|
6
|
+
# In NZ DPS supports ANZ, Westpac, National Bank, ASB and BNZ.
|
|
7
|
+
# In Australia DPS supports ANZ, NAB, Westpac, CBA, St George and Bank of South Australia.
|
|
8
|
+
# The Maybank in Malaysia is supported and the Citibank for Singapore.
|
|
9
|
+
class PaymentExpressGateway < Gateway
|
|
10
|
+
attr_reader :url
|
|
11
|
+
attr_reader :response
|
|
12
|
+
attr_reader :options
|
|
13
|
+
|
|
14
|
+
self.default_currency = 'NZD'
|
|
15
|
+
# PS supports all major credit cards; Visa, Mastercard, Amex, Diners, BankCard & JCB.
|
|
16
|
+
# Various white label cards can be accepted as well; Farmers, AirNZCard and Elders etc.
|
|
17
|
+
# Please note that not all acquirers and Eftpos networks can support some of these card types.
|
|
18
|
+
# VISA, Mastercard, Diners Club and Farmers cards are supported
|
|
19
|
+
#
|
|
20
|
+
# However, regular accounts with DPS only support VISA and Mastercard
|
|
21
|
+
self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :jcb ]
|
|
22
|
+
|
|
23
|
+
self.supported_countries = [ 'AU', 'MY', 'NZ', 'SG', 'ZA', 'GB', 'US' ]
|
|
24
|
+
|
|
25
|
+
self.homepage_url = 'http://www.paymentexpress.com/'
|
|
26
|
+
self.display_name = 'PaymentExpress'
|
|
27
|
+
|
|
28
|
+
PAYMENT_URL = 'https://www.paymentexpress.com/pxpost.aspx'
|
|
29
|
+
|
|
30
|
+
APPROVED = '1'
|
|
31
|
+
|
|
32
|
+
TRANSACTIONS = {
|
|
33
|
+
:purchase => 'Purchase',
|
|
34
|
+
:credit => 'Refund',
|
|
35
|
+
:authorization => 'Auth',
|
|
36
|
+
:capture => 'Complete',
|
|
37
|
+
:validate => 'Validate'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
POST_HEADERS = { "Content-Type" => "application/x-www-form-urlencoded" }
|
|
41
|
+
|
|
42
|
+
# We require the DPS gateway username and password when the object is created.
|
|
43
|
+
def initialize(options = {})
|
|
44
|
+
# A DPS username and password must exist
|
|
45
|
+
requires!(options, :login, :password)
|
|
46
|
+
# Make the options an instance variable
|
|
47
|
+
@options = options
|
|
48
|
+
super
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Funds are transferred immediately.
|
|
52
|
+
def purchase(money, credit_card_or_billing_token, options = {})
|
|
53
|
+
|
|
54
|
+
credit_card = credit_card_or_billing_token if credit_card_or_billing_token.respond_to?(:number)
|
|
55
|
+
|
|
56
|
+
if credit_card
|
|
57
|
+
if result = test_result_from_cc_number(credit_card.number)
|
|
58
|
+
return result
|
|
59
|
+
end
|
|
60
|
+
options[:credit_card] = credit_card
|
|
61
|
+
else
|
|
62
|
+
options[:token] = credit_card_or_billing_token
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
request = build_purchase_or_authorization_request(money, options)
|
|
66
|
+
commit(:purchase, request)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# NOTE: Perhaps in options we allow a transaction note to be inserted
|
|
70
|
+
# Verifies that funds are available for the requested card and amount and reserves the specified amount.
|
|
71
|
+
# See: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Authcomplete
|
|
72
|
+
def authorize(money, credit_card, options = {})
|
|
73
|
+
if result = test_result_from_cc_number(credit_card.number)
|
|
74
|
+
return result
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
options[:credit_card] = credit_card
|
|
78
|
+
|
|
79
|
+
request = build_purchase_or_authorization_request(money, options)
|
|
80
|
+
commit(:authorization, request)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Transfer pre-authorized funds immediately
|
|
84
|
+
# See: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Authcomplete
|
|
85
|
+
def capture(money, identification, options = {})
|
|
86
|
+
request = build_capture_or_credit_request(money, identification, options)
|
|
87
|
+
commit(:capture, request)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Refund funds to the card holder
|
|
91
|
+
def credit(money, identification, options = {})
|
|
92
|
+
requires!(options, :description)
|
|
93
|
+
|
|
94
|
+
request = build_capture_or_credit_request(money, identification, options)
|
|
95
|
+
commit(:credit, request)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# token based billing
|
|
99
|
+
|
|
100
|
+
# initiates a "Validate" transcation to store card data on payment express servers
|
|
101
|
+
# returns a "token" that can be used to rebill this card
|
|
102
|
+
# see: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Tokenbilling
|
|
103
|
+
# PaymentExpress does not support unstoring a stored card.
|
|
104
|
+
def store(credit_card, options = {})
|
|
105
|
+
request = build_token_request(credit_card, options)
|
|
106
|
+
commit(:validate, request)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
def build_purchase_or_authorization_request(money, options)
|
|
112
|
+
result = new_transaction
|
|
113
|
+
|
|
114
|
+
returning result do |r|
|
|
115
|
+
add_credit_card(r, options[:credit_card]) if options[:credit_card]
|
|
116
|
+
add_billing_token(r, options[:token]) if options[:token]
|
|
117
|
+
|
|
118
|
+
add_amount(r, money, options)
|
|
119
|
+
add_invoice(r, options)
|
|
120
|
+
add_address_verification_data(r, options)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def build_capture_or_credit_request(money, identification, options)
|
|
125
|
+
result = new_transaction
|
|
126
|
+
|
|
127
|
+
add_amount(result, money, options)
|
|
128
|
+
add_invoice(result, options)
|
|
129
|
+
add_reference(result, identification)
|
|
130
|
+
|
|
131
|
+
result
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def build_token_request(credit_card, options)
|
|
135
|
+
result = new_transaction
|
|
136
|
+
|
|
137
|
+
returning result do |r|
|
|
138
|
+
add_credit_card(r, credit_card)
|
|
139
|
+
add_amount(r, 100, options) #need to make an auth request for $1
|
|
140
|
+
add_token_request(r, options)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def add_credentials(xml)
|
|
145
|
+
xml.add_element("PostUsername").text = @options[:login]
|
|
146
|
+
xml.add_element("PostPassword").text = @options[:password]
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def add_reference(xml, identification)
|
|
150
|
+
xml.add_element("DpsTxnRef").text = identification
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def add_credit_card(xml, credit_card)
|
|
154
|
+
xml.add_element("CardHolderName").text = credit_card.name
|
|
155
|
+
xml.add_element("CardNumber").text = credit_card.number
|
|
156
|
+
xml.add_element("DateExpiry").text = format_date(credit_card.month, credit_card.year)
|
|
157
|
+
|
|
158
|
+
if credit_card.verification_value?
|
|
159
|
+
xml.add_element("Cvc2").text = credit_card.verification_value
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
if requires_start_date_or_issue_number?(credit_card)
|
|
163
|
+
xml.add_element("DateStart").text = format_date(credit_card.start_month, credit_card.start_year) unless credit_card.start_month.blank? || credit_card.start_year.blank?
|
|
164
|
+
xml.add_element("IssueNumber").text = credit_card.issue_number unless credit_card.issue_number.blank?
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def add_billing_token(xml, token)
|
|
169
|
+
xml.add_element("DpsBillingId").text = token
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def add_token_request(xml, options)
|
|
173
|
+
xml.add_element("BillingId").text = options[:billing_id] if options[:billing_id]
|
|
174
|
+
xml.add_element("EnableAddBillCard").text = 1
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def add_amount(xml, money, options)
|
|
178
|
+
xml.add_element("Amount").text = amount(money)
|
|
179
|
+
xml.add_element("InputCurrency").text = options[:currency] || currency(money)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def add_transaction_type(xml, action)
|
|
183
|
+
xml.add_element("TxnType").text = TRANSACTIONS[action]
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def add_invoice(xml, options)
|
|
187
|
+
xml.add_element("TxnId").text = options[:order_id] unless options[:order_id].blank?
|
|
188
|
+
xml.add_element("MerchantReference").text = options[:description] unless options[:description].blank?
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def add_address_verification_data(xml, options)
|
|
192
|
+
address = options[:billing_address] || options[:address]
|
|
193
|
+
return if address.nil?
|
|
194
|
+
|
|
195
|
+
xml.add_element("EnableAvsData").text = 0
|
|
196
|
+
xml.add_element("AvsAction").text = 0
|
|
197
|
+
|
|
198
|
+
xml.add_element("AvsStreetAddress").text = address[:address1]
|
|
199
|
+
xml.add_element("AvsPostCode").text = address[:zip]
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def new_transaction
|
|
203
|
+
REXML::Document.new.add_element("Txn")
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Take in the request and post it to DPS
|
|
207
|
+
def commit(action, request)
|
|
208
|
+
add_credentials(request)
|
|
209
|
+
add_transaction_type(request, action)
|
|
210
|
+
|
|
211
|
+
# Next, post it to the server
|
|
212
|
+
response = ssl_post(PAYMENT_URL, request.to_s, POST_HEADERS)
|
|
213
|
+
|
|
214
|
+
# Parse the XML response
|
|
215
|
+
@response = parse_response(response)
|
|
216
|
+
|
|
217
|
+
success = @response[:success] == APPROVED
|
|
218
|
+
test = @response[:test_mode] == '1'
|
|
219
|
+
|
|
220
|
+
# Return a response
|
|
221
|
+
PaymentExpressResponse.new(success, @response[:response_text], @response,
|
|
222
|
+
:test => test,
|
|
223
|
+
:authorization => @response[:dps_txn_ref]
|
|
224
|
+
)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Response XML documentation: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#XMLTxnOutput
|
|
228
|
+
def parse_response(xml_string)
|
|
229
|
+
response = {}
|
|
230
|
+
|
|
231
|
+
xml = REXML::Document.new(xml_string)
|
|
232
|
+
|
|
233
|
+
# Gather all root elements such as HelpText
|
|
234
|
+
xml.elements.each('Txn/*') do |element|
|
|
235
|
+
response[element.name.underscore.to_sym] = element.text unless element.name == 'Transaction'
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Gather all transaction elements and prefix with "account_"
|
|
239
|
+
# So we could access the MerchantResponseText by going
|
|
240
|
+
# response[account_merchant_response_text]
|
|
241
|
+
xml.elements.each('Txn/Transaction/*') do |element|
|
|
242
|
+
response[element.name.underscore.to_sym] = element.text
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
response
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def format_date(month, year)
|
|
249
|
+
"#{format(month, :two_digits)}#{format(year, :two_digits)}"
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
class PaymentExpressResponse < Response
|
|
254
|
+
# add a method to response so we can easily get the token
|
|
255
|
+
# for Validate transactions
|
|
256
|
+
def token
|
|
257
|
+
@params["billing_id"] || @params["dps_billing_id"]
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|