activemerchant 1.2.1 → 1.3.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.
Files changed (206) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +310 -294
  3. data/CONTRIBUTERS +13 -0
  4. data/README +55 -31
  5. data/Rakefile +21 -13
  6. data/lib/active_merchant.rb +7 -0
  7. data/lib/active_merchant/billing/avs_result.rb +95 -0
  8. data/lib/active_merchant/billing/base.rb +8 -3
  9. data/lib/active_merchant/billing/check.rb +61 -0
  10. data/lib/active_merchant/billing/credit_card.rb +104 -80
  11. data/lib/active_merchant/billing/credit_card_formatting.rb +11 -8
  12. data/lib/active_merchant/billing/credit_card_methods.rb +76 -32
  13. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  14. data/lib/active_merchant/billing/expiry_date.rb +28 -0
  15. data/lib/active_merchant/billing/gateway.rb +47 -111
  16. data/lib/active_merchant/billing/gateways/authorize_net.rb +508 -121
  17. data/lib/active_merchant/billing/gateways/bogus.rb +26 -32
  18. data/lib/active_merchant/billing/gateways/brain_tree.rb +82 -70
  19. data/lib/active_merchant/billing/gateways/card_stream.rb +43 -15
  20. data/lib/active_merchant/billing/gateways/cyber_source.rb +9 -29
  21. data/lib/active_merchant/billing/gateways/data_cash.rb +18 -38
  22. data/lib/active_merchant/billing/gateways/efsnet.rb +23 -50
  23. data/lib/active_merchant/billing/gateways/eway.rb +8 -19
  24. data/lib/active_merchant/billing/gateways/exact.rb +17 -25
  25. data/lib/active_merchant/billing/gateways/linkpoint.rb +18 -25
  26. data/lib/active_merchant/billing/gateways/moneris.rb +9 -39
  27. data/lib/active_merchant/billing/gateways/net_registry.rb +113 -182
  28. data/lib/active_merchant/billing/gateways/netbilling.rb +168 -0
  29. data/lib/active_merchant/billing/gateways/pay_junction.rb +52 -73
  30. data/lib/active_merchant/billing/gateways/pay_secure.rb +120 -0
  31. data/lib/active_merchant/billing/gateways/payflow.rb +13 -14
  32. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +55 -37
  33. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +4 -0
  34. data/lib/active_merchant/billing/gateways/payflow_express.rb +2 -4
  35. data/lib/active_merchant/billing/gateways/payment_express.rb +11 -30
  36. data/lib/active_merchant/billing/gateways/paypal.rb +3 -14
  37. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +36 -16
  38. data/lib/active_merchant/billing/gateways/paypal_express.rb +1 -2
  39. data/lib/active_merchant/billing/gateways/plugnpay.rb +7 -15
  40. data/lib/active_merchant/billing/gateways/protx.rb +24 -25
  41. data/lib/active_merchant/billing/gateways/psigate.rb +34 -71
  42. data/lib/active_merchant/billing/gateways/psl_card.rb +24 -19
  43. data/lib/active_merchant/billing/gateways/quickpay.rb +10 -24
  44. data/lib/active_merchant/billing/gateways/realex.rb +7 -19
  45. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +113 -0
  46. data/lib/active_merchant/billing/gateways/skip_jack.rb +437 -0
  47. data/lib/active_merchant/billing/gateways/trans_first.rb +5 -14
  48. data/lib/active_merchant/billing/gateways/trust_commerce.rb +100 -39
  49. data/lib/active_merchant/billing/gateways/usa_epay.rb +60 -55
  50. data/lib/active_merchant/billing/gateways/verifi.rb +32 -39
  51. data/lib/active_merchant/billing/gateways/viaklix.rb +31 -37
  52. data/lib/active_merchant/billing/integrations.rb +2 -0
  53. data/lib/active_merchant/billing/integrations/bogus.rb +5 -0
  54. data/lib/active_merchant/billing/integrations/bogus/return.rb +10 -0
  55. data/lib/active_merchant/billing/integrations/chronopay.rb +5 -0
  56. data/lib/active_merchant/billing/integrations/chronopay/return.rb +10 -0
  57. data/lib/active_merchant/billing/integrations/gestpay.rb +5 -0
  58. data/lib/active_merchant/billing/integrations/gestpay/return.rb +10 -0
  59. data/lib/active_merchant/billing/integrations/hi_trust.rb +26 -0
  60. data/lib/active_merchant/billing/integrations/hi_trust/helper.rb +58 -0
  61. data/lib/active_merchant/billing/integrations/hi_trust/notification.rb +57 -0
  62. data/lib/active_merchant/billing/integrations/hi_trust/return.rb +67 -0
  63. data/lib/active_merchant/billing/integrations/nochex.rb +5 -0
  64. data/lib/active_merchant/billing/integrations/nochex/return.rb +10 -0
  65. data/lib/active_merchant/billing/integrations/paypal.rb +5 -0
  66. data/lib/active_merchant/billing/integrations/paypal/return.rb +10 -0
  67. data/lib/active_merchant/billing/integrations/return.rb +35 -0
  68. data/lib/active_merchant/billing/integrations/two_checkout.rb +5 -0
  69. data/lib/active_merchant/billing/integrations/two_checkout/return.rb +17 -0
  70. data/lib/active_merchant/billing/response.rb +12 -8
  71. data/lib/active_merchant/lib/posts_data.rb +39 -7
  72. data/lib/active_merchant/lib/requires_parameters.rb +2 -3
  73. data/lib/active_merchant/lib/utils.rb +18 -0
  74. data/lib/active_merchant/lib/validateable.rb +3 -3
  75. data/lib/support/gateway_support.rb +22 -9
  76. data/script/destroy +14 -0
  77. data/script/generate +7 -7
  78. data/test/fixtures.yml +25 -3
  79. data/test/remote/gateways/remote_authorize_net_test.rb +145 -0
  80. data/test/remote/gateways/remote_brain_tree_test.rb +118 -0
  81. data/test/{remote_tests → remote/gateways}/remote_card_stream_test.rb +56 -68
  82. data/test/{remote_tests → remote/gateways}/remote_cyber_source_test.rb +21 -32
  83. data/test/{remote_tests → remote/gateways}/remote_data_cash_test.rb +2 -2
  84. data/test/{remote_tests → remote/gateways}/remote_efsnet_test.rb +22 -34
  85. data/test/{remote_tests → remote/gateways}/remote_eway_test.rb +18 -15
  86. data/test/{remote_tests → remote/gateways}/remote_exact_test.rb +20 -19
  87. data/test/{remote_tests → remote/gateways}/remote_linkpoint_test.rb +31 -63
  88. data/test/remote/gateways/remote_moneris_test.rb +82 -0
  89. data/test/{remote_tests → remote/gateways}/remote_net_registry_test.rb +19 -54
  90. data/test/remote/gateways/remote_netbilling_test.rb +70 -0
  91. data/test/{remote_tests → remote/gateways}/remote_pay_junction_test.rb +41 -60
  92. data/test/remote/gateways/remote_pay_secure_test.rb +39 -0
  93. data/test/{remote_tests → remote/gateways}/remote_payflow_express_test.rb +2 -2
  94. data/test/{remote_tests → remote/gateways}/remote_payflow_test.rb +34 -38
  95. data/test/{remote_tests → remote/gateways}/remote_payflow_uk_test.rb +13 -12
  96. data/test/{remote_tests → remote/gateways}/remote_payment_express_test.rb +26 -36
  97. data/test/{remote_tests → remote/gateways}/remote_paypal_express_test.rb +3 -3
  98. data/test/{remote_tests → remote/gateways}/remote_paypal_test.rb +25 -21
  99. data/test/{remote_tests → remote/gateways}/remote_plugnpay_test.rb +18 -16
  100. data/test/{remote_tests → remote/gateways}/remote_protx_test.rb +33 -33
  101. data/test/remote/gateways/remote_psigate_test.rb +50 -0
  102. data/test/{remote_tests → remote/gateways}/remote_psl_card_test.rb +27 -26
  103. data/test/{remote_tests → remote/gateways}/remote_quickpay_test.rb +48 -48
  104. data/test/{remote_tests → remote/gateways}/remote_realex_test.rb +30 -33
  105. data/test/remote/gateways/remote_secure_pay_tech_test.rb +37 -0
  106. data/test/remote/gateways/remote_secure_pay_test.rb +28 -0
  107. data/test/remote/gateways/remote_skipjack_test.rb +105 -0
  108. data/test/{remote_tests → remote/gateways}/remote_trans_first_test.rb +7 -10
  109. data/test/remote/gateways/remote_trust_commerce_test.rb +152 -0
  110. data/test/{remote_tests → remote/gateways}/remote_usa_epay_test.rb +11 -22
  111. data/test/{remote_tests → remote/gateways}/remote_verifi_test.rb +27 -27
  112. data/test/{remote_tests → remote/gateways}/remote_viaklix_test.rb +8 -18
  113. data/test/{remote_tests → remote/integrations}/remote_gestpay_integration_test.rb +1 -1
  114. data/test/{remote_tests → remote/integrations}/remote_paypal_integration_test.rb +1 -1
  115. data/test/test_helper.rb +102 -61
  116. data/test/unit/avs_result_test.rb +59 -0
  117. data/test/unit/base_test.rb +33 -39
  118. data/test/unit/check_test.rb +76 -0
  119. data/test/unit/credit_card_formatting_test.rb +10 -15
  120. data/test/unit/credit_card_methods_test.rb +132 -17
  121. data/test/unit/credit_card_test.rb +157 -228
  122. data/test/unit/cvv_result_test.rb +33 -0
  123. data/test/unit/expiry_date_test.rb +21 -0
  124. data/test/unit/gateways/authorize_net_test.rb +180 -40
  125. data/test/unit/gateways/bogus_test.rb +2 -3
  126. data/test/unit/gateways/brain_tree_test.rb +63 -29
  127. data/test/unit/gateways/card_stream_test.rb +59 -6
  128. data/test/unit/gateways/cyber_source_test.rb +59 -40
  129. data/test/unit/gateways/data_cash_test.rb +82 -1
  130. data/test/unit/gateways/efsnet_test.rb +97 -44
  131. data/test/unit/gateways/eway_test.rb +55 -42
  132. data/test/unit/gateways/exact_test.rb +93 -55
  133. data/test/unit/gateways/gateway_test.rb +7 -0
  134. data/test/unit/gateways/linkpoint_test.rb +60 -58
  135. data/test/unit/gateways/moneris_test.rb +67 -76
  136. data/test/unit/gateways/net_registry_test.rb +351 -419
  137. data/test/unit/gateways/netbilling_test.rb +54 -0
  138. data/test/unit/gateways/pay_junction_test.rb +108 -46
  139. data/test/unit/gateways/pay_secure_test.rb +71 -0
  140. data/test/unit/gateways/payflow_express_test.rb +0 -8
  141. data/test/unit/gateways/payflow_test.rb +136 -65
  142. data/test/unit/gateways/payflow_uk_test.rb +0 -38
  143. data/test/unit/gateways/payment_express_test.rb +31 -51
  144. data/test/unit/gateways/paypal_express_test.rb +8 -2
  145. data/test/unit/gateways/paypal_test.rb +213 -54
  146. data/test/unit/gateways/plugnpay_test.rb +39 -32
  147. data/test/unit/gateways/protx_test.rb +45 -33
  148. data/test/unit/gateways/psigate_test.rb +146 -87
  149. data/test/unit/gateways/psl_card_test.rb +37 -24
  150. data/test/unit/gateways/quickpay_test.rb +33 -46
  151. data/test/unit/gateways/realex_test.rb +32 -31
  152. data/test/unit/gateways/secure_pay_tech_test.rb +44 -0
  153. data/test/unit/gateways/secure_pay_test.rb +35 -26
  154. data/test/unit/gateways/skip_jack_test.rb +125 -0
  155. data/test/unit/gateways/trans_first_test.rb +24 -37
  156. data/test/unit/gateways/trust_commerce_test.rb +47 -26
  157. data/test/unit/gateways/usa_epay_test.rb +52 -41
  158. data/test/unit/gateways/verifi_test.rb +41 -35
  159. data/test/unit/gateways/viaklix_test.rb +38 -32
  160. data/test/unit/generators/test_gateway_generator.rb +46 -0
  161. data/test/unit/generators/test_generator_helper.rb +20 -0
  162. data/test/unit/generators/test_integration_generator.rb +53 -0
  163. data/test/unit/integrations/action_view_helper_test.rb +7 -14
  164. data/test/unit/integrations/bogus_module_test.rb +4 -0
  165. data/test/unit/integrations/chronopay_module_test.rb +4 -0
  166. data/test/unit/integrations/gestpay_module_test.rb +4 -0
  167. data/test/unit/integrations/helpers/hi_trust_helper_test.rb +16 -0
  168. data/test/unit/integrations/hi_trust_module_test.rb +13 -0
  169. data/test/unit/integrations/nochex_module_test.rb +4 -0
  170. data/test/unit/integrations/notifications/hi_trust_notification_test.rb +38 -0
  171. data/test/unit/integrations/paypal_module_test.rb +4 -0
  172. data/test/unit/integrations/returns/chronopay_return_test.rb +11 -0
  173. data/test/unit/integrations/returns/gestpay_return_test.rb +10 -0
  174. data/test/unit/integrations/returns/hi_trust_return_test.rb +24 -0
  175. data/test/unit/integrations/returns/nochex_return_test.rb +10 -0
  176. data/test/unit/integrations/returns/paypal_return_test.rb +10 -0
  177. data/test/unit/integrations/returns/return_test.rb +11 -0
  178. data/test/unit/integrations/returns/two_checkout_return_test.rb +24 -0
  179. data/test/unit/integrations/two_checkout_module_test.rb +4 -0
  180. data/test/unit/posts_data_test.rb +86 -0
  181. data/test/unit/response_test.rb +15 -1
  182. data/test/unit/utils_test.rb +7 -0
  183. data/test/unit/validateable_test.rb +10 -6
  184. metadata +180 -142
  185. metadata.gz.sig +0 -0
  186. data/lib/active_merchant/billing/gateways/paypal/api_cert_chain.crt +0 -35
  187. data/script/generator/base.rb +0 -45
  188. data/script/generator/generator.rb +0 -24
  189. data/script/generator/generators/gateway/gateway_generator.rb +0 -14
  190. data/script/generator/generators/gateway/templates/gateway.rb +0 -73
  191. data/script/generator/generators/gateway/templates/gateway_test.rb +0 -41
  192. data/script/generator/generators/gateway/templates/remote_gateway_test.rb +0 -56
  193. data/script/generator/generators/integration/integration_generator.rb +0 -25
  194. data/script/generator/generators/integration/templates/helper.rb +0 -34
  195. data/script/generator/generators/integration/templates/helper_test.rb +0 -54
  196. data/script/generator/generators/integration/templates/integration.rb +0 -18
  197. data/script/generator/generators/integration/templates/module_test.rb +0 -9
  198. data/script/generator/generators/integration/templates/notification.rb +0 -100
  199. data/script/generator/generators/integration/templates/notification_test.rb +0 -41
  200. data/script/generator/manifest.rb +0 -20
  201. data/test/remote_tests/remote_authorize_net_test.rb +0 -113
  202. data/test/remote_tests/remote_brain_tree_test.rb +0 -78
  203. data/test/remote_tests/remote_moneris_test.rb +0 -110
  204. data/test/remote_tests/remote_psigate_test.rb +0 -87
  205. data/test/remote_tests/remote_secure_pay_test.rb +0 -36
  206. data/test/remote_tests/remote_trust_commerce_test.rb +0 -136
@@ -62,8 +62,8 @@ module ActiveMerchant #:nodoc:
62
62
  commit(request, :recurring)
63
63
  end
64
64
 
65
- def recurring_inquiry(profile_id)
66
- request = build_recurring_request(:inquiry, nil, :profile_id => profile_id)
65
+ def recurring_inquiry(profile_id, options = {})
66
+ request = build_recurring_request(:inquiry, nil, options.update( :profile_id => profile_id ))
67
67
  commit(request, :recurring)
68
68
  end
69
69
 
@@ -81,7 +81,7 @@ module ActiveMerchant #:nodoc:
81
81
  end
82
82
 
83
83
  def build_reference_sale_or_authorization_request(action, money, reference, options)
84
- xml = Builder::XmlMarkup.new :indent => 2
84
+ xml = Builder::XmlMarkup.new
85
85
  xml.tag! TRANSACTIONS[action] do
86
86
  xml.tag! 'PayData' do
87
87
  xml.tag! 'Invoice' do
@@ -98,19 +98,17 @@ module ActiveMerchant #:nodoc:
98
98
  end
99
99
 
100
100
  def build_credit_card_request(action, money, credit_card, options)
101
- xml = Builder::XmlMarkup.new :indent => 2
101
+ xml = Builder::XmlMarkup.new
102
102
  xml.tag! TRANSACTIONS[action] do
103
103
  xml.tag! 'PayData' do
104
104
  xml.tag! 'Invoice' do
105
105
  xml.tag! 'CustIP', options[:ip] unless options[:ip].blank?
106
- xml.tag! 'InvNum', options[:order_id] unless options[:order_id].blank?
106
+ xml.tag! 'InvNum', options[:order_id].to_s.gsub(/[^\w.]/, '') unless options[:order_id].blank?
107
107
  xml.tag! 'Description', options[:description] unless options[:description].blank?
108
108
 
109
109
  billing_address = options[:billing_address] || options[:address]
110
- shipping_address = options[:shipping_address] || billing_address
111
-
112
- add_address(xml, 'BillTo', billing_address, options)
113
- add_address(xml, 'ShipTo', shipping_address, options)
110
+ add_address(xml, 'BillTo', billing_address, options) if billing_address
111
+ add_address(xml, 'ShipTo', options[:shipping_address], options) if options[:shipping_address]
114
112
 
115
113
  xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
116
114
  end
@@ -163,7 +161,7 @@ module ActiveMerchant #:nodoc:
163
161
  raise StandardError, "Invalid Recurring Profile Action: #{action}"
164
162
  end
165
163
 
166
- xml = Builder::XmlMarkup.new :indent => 2
164
+ xml = Builder::XmlMarkup.new
167
165
  xml.tag! 'RecurringProfiles' do
168
166
  xml.tag! 'RecurringProfile' do
169
167
  xml.tag! action.to_s.capitalize do
@@ -188,10 +186,8 @@ module ActiveMerchant #:nodoc:
188
186
  xml.tag! 'EMail', options[:email] unless options[:email].nil?
189
187
 
190
188
  billing_address = options[:billing_address] || options[:address]
191
- shipping_address = options[:shipping_address] || billing_address
192
-
193
- add_address(xml, 'BillTo', billing_address, options)
194
- add_address(xml, 'ShipTo', shipping_address, options)
189
+ add_address(xml, 'BillTo', billing_address, options) if billing_address
190
+ add_address(xml, 'ShipTo', options[:shipping_address], options) if options[:shipping_address]
195
191
  end
196
192
  xml.tag! 'Tender' do
197
193
  yield xml
@@ -200,6 +196,9 @@ module ActiveMerchant #:nodoc:
200
196
  if action != :add
201
197
  xml.tag! "ProfileID", options[:profile_id]
202
198
  end
199
+ if action == :inquiry
200
+ xml.tag! "PaymentHistory", ( options[:history] ? 'Y' : 'N' )
201
+ end
203
202
  end
204
203
  end
205
204
  end
@@ -4,23 +4,32 @@ module ActiveMerchant #:nodoc:
4
4
  def self.included(base)
5
5
  base.default_currency = 'USD'
6
6
 
7
- # The certification_id is required by PayPal to make direct HTTPS posts to their servers.
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
7
+ # The certification id requirement has been removed by Payflow
8
+ # This is no longer being sent in the requests to the gateway
10
9
  base.class_inheritable_accessor :certification_id
11
- base.certification_id = '55d64dfec398cbbe66c1bf843cbad9'
12
-
10
+
13
11
  base.class_inheritable_accessor :partner
14
12
 
15
13
  # Set the default partner to PayPal
16
14
  base.partner = 'PayPal'
17
15
 
18
16
  base.supported_countries = ['US', 'CA', 'SG', 'AU']
17
+
18
+ base.class_inheritable_accessor :timeout
19
+ base.timeout = 60
20
+
21
+ # Enable safe retry of failed connections
22
+ # Payflow is safe to retry because retried transactions use the same
23
+ # X-VPS-Request-ID header. If a transaction is detected as a duplicate
24
+ # only the original transaction data will be used by Payflow, and the
25
+ # subsequent Responses will have a :duplicate parameter set in the params
26
+ # hash.
27
+ base.retry_safe = true
19
28
  end
20
29
 
21
30
  XMLNS = 'http://www.paypal.com/XMLPay'
22
- TEST_URL = 'https://pilot-payflowpro.verisign.com/transaction'
23
- LIVE_URL = 'https://payflowpro.verisign.com/transaction'
31
+ TEST_URL = 'https://pilot-payflowpro.verisign.com'
32
+ LIVE_URL = 'https://payflowpro.verisign.com'
24
33
 
25
34
  CARD_MAPPING = {
26
35
  :visa => 'Visa',
@@ -40,6 +49,13 @@ module ActiveMerchant #:nodoc:
40
49
  :void => "Void",
41
50
  :credit => "Credit"
42
51
  }
52
+
53
+ CVV_CODE = {
54
+ 'Match' => 'M',
55
+ 'No Match' => 'N',
56
+ 'Service Not Available' => 'U',
57
+ 'Service not Requested' => 'P'
58
+ }
43
59
 
44
60
  def initialize(options = {})
45
61
  requires!(options, :login, :password)
@@ -52,7 +68,7 @@ module ActiveMerchant #:nodoc:
52
68
  end
53
69
 
54
70
  def test?
55
- @options[:test] || Base.gateway_mode == :test
71
+ @options[:test] || super
56
72
  end
57
73
 
58
74
  def capture(money, authorization, options = {})
@@ -67,7 +83,7 @@ module ActiveMerchant #:nodoc:
67
83
 
68
84
  private
69
85
  def build_request(body, request_type = nil)
70
- xml = Builder::XmlMarkup.new :indent => 2
86
+ xml = Builder::XmlMarkup.new
71
87
  xml.instruct!
72
88
  xml.tag! 'XMLPayRequest', 'Timeout' => 30, 'version' => "2.1", "xmlns" => XMLNS do
73
89
  xml.tag! 'RequestData' do
@@ -95,7 +111,7 @@ module ActiveMerchant #:nodoc:
95
111
  end
96
112
 
97
113
  def build_reference_request(action, money, authorization, options)
98
- xml = Builder::XmlMarkup.new :indent => 2
114
+ xml = Builder::XmlMarkup.new
99
115
  xml.tag! TRANSACTIONS[action] do
100
116
  xml.tag! 'PNRef', authorization
101
117
 
@@ -113,8 +129,10 @@ module ActiveMerchant #:nodoc:
113
129
  return if address.nil?
114
130
  xml.tag! tag do
115
131
  xml.tag! 'Name', address[:name] unless options[:name].blank?
116
- xml.tag! 'Email', options[:email] unless options[:email].blank?
132
+ xml.tag! 'EMail', options[:email] unless options[:email].blank?
117
133
  xml.tag! 'Phone', address[:phone] unless address[:phone].blank?
134
+ xml.tag! 'CustCode', options[:customer] if !options[:customer].blank? && tag == 'BillTo'
135
+
118
136
  xml.tag! 'Address' do
119
137
  xml.tag! 'Street', address[:address1] unless address[:address1].blank?
120
138
  xml.tag! 'City', address[:city] unless address[:city].blank?
@@ -130,7 +148,10 @@ module ActiveMerchant #:nodoc:
130
148
  xml = REXML::Document.new(data)
131
149
  root = REXML::XPath.first(xml, "//ResponseData")
132
150
 
133
- if REXML::XPath.first(root, "//TransactionResult/attribute::Duplicate")
151
+ # REXML::XPath in Ruby 1.8.6 is now unable to match nodes based on their attributes
152
+ tx_result = REXML::XPath.first(root, "//TransactionResult")
153
+
154
+ if tx_result && tx_result.attributes['Duplicate'] == "true"
134
155
  response[:duplicate] = true
135
156
  end
136
157
 
@@ -142,12 +163,24 @@ module ActiveMerchant #:nodoc:
142
163
  end
143
164
 
144
165
  def parse_element(response, node)
145
- if node.has_elements?
166
+ node_name = node.name.underscore.to_sym
167
+ case
168
+ when node_name == :rp_payment_result
169
+ # Since we'll have multiple history items, we can't just flatten everything
170
+ # down as we do everywhere else. RPPaymentResult elements are not contained
171
+ # in an RPPaymentResults element so we'll come here multiple times
172
+ response[node_name] ||= []
173
+ response[node_name] << ( payment_result_response = {} )
174
+ node.elements.each{ |e| parse_element(payment_result_response, e) }
175
+ when node.has_elements?
146
176
  node.elements.each{|e| parse_element(response, e) }
147
- elsif node.name == 'ExtData'
177
+ when node_name.to_s =~ /amt$/
178
+ # *Amt elements don't put the value in the #text - instead they use a Currency attribute
179
+ response[node_name] = node.attributes['Currency']
180
+ when node_name == :ext_data
148
181
  response[node.attributes['Name'].underscore.to_sym] = node.attributes['Value']
149
182
  else
150
- response[node.name.underscore.to_sym] = node.text
183
+ response[node_name] = node.text
151
184
  end
152
185
  end
153
186
 
@@ -155,11 +188,10 @@ module ActiveMerchant #:nodoc:
155
188
  {
156
189
  "Content-Type" => "text/xml",
157
190
  "Content-Length" => content_length.to_s,
158
- "X-VPS-Timeout" => "30",
159
- "X-VPS-VIT-Client-Certification-Id" => @options[:certification_id].to_s,
191
+ "X-VPS-Timeout" => timeout.to_s,
160
192
  "X-VPS-VIT-Integration-Product" => "ActiveMerchant",
161
193
  "X-VPS-VIT-Runtime-Version" => RUBY_VERSION,
162
- "X-VPS-Request-ID" => generate_unique_id
194
+ "X-VPS-Request-ID" => Utils.generate_unique_id
163
195
  }
164
196
  end
165
197
 
@@ -167,29 +199,15 @@ module ActiveMerchant #:nodoc:
167
199
  request = build_request(request_body, request_type)
168
200
  headers = build_headers(request.size)
169
201
 
170
- if result = test_result_from_cc_number(parse_credit_card_number(request))
171
- return result
172
- end
173
-
174
- url = test? ? TEST_URL : LIVE_URL
175
- data = ssl_post(url, request, headers)
176
-
177
- @response = parse(data)
202
+ response = parse(ssl_post(test? ? TEST_URL : LIVE_URL, request, headers))
178
203
 
179
- success = @response[:result] == "0"
180
- message = @response[:message]
181
-
182
- build_response(success, message, @response,
204
+ build_response(response[:result] == "0", response[:message], response,
183
205
  :test => test?,
184
- :authorization => @response[:pn_ref] || @response[:rp_ref]
206
+ :authorization => response[:pn_ref] || response[:rp_ref],
207
+ :cvv_result => CVV_CODE[response[:cv_result]],
208
+ :avs_result => { :code => response[:avs_result] }
185
209
  )
186
210
  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
193
211
  end
194
212
  end
195
213
  end
@@ -4,6 +4,10 @@ module ActiveMerchant #:nodoc:
4
4
  def profile_id
5
5
  @params['profile_id']
6
6
  end
7
+
8
+ def payment_history
9
+ @payment_history ||= @params['rp_payment_result'].collect{ |result| result.stringify_keys } rescue []
10
+ end
7
11
  end
8
12
  end
9
13
  end
@@ -84,10 +84,8 @@ module ActiveMerchant #:nodoc:
84
84
  xml.tag! 'Description', options[:description] unless options[:description].blank?
85
85
 
86
86
  billing_address = options[:billing_address] || options[:address]
87
- shipping_address = options[:shipping_address] || billing_address
88
-
89
- add_address(xml, 'BillTo', billing_address, options)
90
- add_address(xml, 'ShipTo', shipping_address, options)
87
+ add_address(xml, 'BillTo', billing_address, options) if billing_address
88
+ add_address(xml, 'ShipTo', options[:shipping_address], options) if options[:shipping_address]
91
89
 
92
90
  xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
93
91
  end
@@ -1,16 +1,12 @@
1
1
  require 'rexml/document'
2
2
 
3
- module ActiveMerchant
4
- module Billing
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
5
 
6
6
  # In NZ DPS supports ANZ, Westpac, National Bank, ASB and BNZ.
7
7
  # In Australia DPS supports ANZ, NAB, Westpac, CBA, St George and Bank of South Australia.
8
8
  # The Maybank in Malaysia is supported and the Citibank for Singapore.
9
9
  class PaymentExpressGateway < Gateway
10
- attr_reader :url
11
- attr_reader :response
12
- attr_reader :options
13
-
14
10
  self.default_currency = 'NZD'
15
11
  # PS supports all major credit cards; Visa, Mastercard, Amex, Diners, BankCard & JCB.
16
12
  # Various white label cards can be accepted as well; Farmers, AirNZCard and Elders etc.
@@ -37,8 +33,6 @@ module ActiveMerchant
37
33
  :validate => 'Validate'
38
34
  }
39
35
 
40
- POST_HEADERS = { "Content-Type" => "application/x-www-form-urlencoded" }
41
-
42
36
  # We require the DPS gateway username and password when the object is created.
43
37
  def initialize(options = {})
44
38
  # A DPS username and password must exist
@@ -49,17 +43,14 @@ module ActiveMerchant
49
43
  end
50
44
 
51
45
  # Funds are transferred immediately.
52
- def purchase(money, credit_card_or_billing_token, options = {})
46
+ def purchase(money, payment_source, options = {})
53
47
 
54
- credit_card = credit_card_or_billing_token if credit_card_or_billing_token.respond_to?(:number)
48
+ credit_card = payment_source if payment_source.respond_to?(:number)
55
49
 
56
50
  if credit_card
57
- if result = test_result_from_cc_number(credit_card.number)
58
- return result
59
- end
60
51
  options[:credit_card] = credit_card
61
52
  else
62
- options[:token] = credit_card_or_billing_token
53
+ options[:token] = payment_source
63
54
  end
64
55
 
65
56
  request = build_purchase_or_authorization_request(money, options)
@@ -70,10 +61,6 @@ module ActiveMerchant
70
61
  # Verifies that funds are available for the requested card and amount and reserves the specified amount.
71
62
  # See: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Authcomplete
72
63
  def authorize(money, credit_card, options = {})
73
- if result = test_result_from_cc_number(credit_card.number)
74
- return result
75
- end
76
-
77
64
  options[:credit_card] = credit_card
78
65
 
79
66
  request = build_purchase_or_authorization_request(money, options)
@@ -184,7 +171,7 @@ module ActiveMerchant
184
171
  end
185
172
 
186
173
  def add_invoice(xml, options)
187
- xml.add_element("TxnId").text = options[:order_id] unless options[:order_id].blank?
174
+ xml.add_element("TxnId").text = options[:order_id].to_s.slice(0, 16) unless options[:order_id].blank?
188
175
  xml.add_element("MerchantReference").text = options[:description] unless options[:description].blank?
189
176
  end
190
177
 
@@ -208,24 +195,18 @@ module ActiveMerchant
208
195
  add_credentials(request)
209
196
  add_transaction_type(request, action)
210
197
 
211
- # Next, post it to the server
212
- response = ssl_post(PAYMENT_URL, request.to_s, POST_HEADERS)
213
-
214
198
  # Parse the XML response
215
- @response = parse_response(response)
216
-
217
- success = @response[:success] == APPROVED
218
- test = @response[:test_mode] == '1'
199
+ response = parse( ssl_post(PAYMENT_URL, request.to_s) )
219
200
 
220
201
  # Return a response
221
- PaymentExpressResponse.new(success, @response[:response_text], @response,
222
- :test => test,
223
- :authorization => @response[:dps_txn_ref]
202
+ PaymentExpressResponse.new(response[:success] == APPROVED, response[:response_text], response,
203
+ :test => response[:test_mode] == '1',
204
+ :authorization => response[:dps_txn_ref]
224
205
  )
225
206
  end
226
207
 
227
208
  # Response XML documentation: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#XMLTxnOutput
228
- def parse_response(xml_string)
209
+ def parse(xml_string)
229
210
  response = {}
230
211
 
231
212
  xml = REXML::Document.new(xml_string)
@@ -8,27 +8,16 @@ module ActiveMerchant #:nodoc:
8
8
 
9
9
  self.supported_cardtypes = [:visa, :master, :american_express, :discover]
10
10
  self.supported_countries = ['US']
11
-
12
11
  self.homepage_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_wp-pro-overview-outside'
13
12
  self.display_name = 'PayPal Website Payments Pro (US)'
14
13
 
15
14
  def authorize(money, credit_card, options = {})
16
15
  requires!(options, :ip)
17
-
18
- if result = test_result_from_cc_number(credit_card.number)
19
- return result
20
- end
21
-
22
16
  commit 'DoDirectPayment', build_sale_or_authorization_request('Authorization', money, credit_card, options)
23
17
  end
24
18
 
25
19
  def purchase(money, credit_card, options = {})
26
20
  requires!(options, :ip)
27
-
28
- if result = test_result_from_cc_number(credit_card.number)
29
- return result
30
- end
31
-
32
21
  commit 'DoDirectPayment', build_sale_or_authorization_request('Sale', money, credit_card, options)
33
22
  end
34
23
 
@@ -38,7 +27,7 @@ module ActiveMerchant #:nodoc:
38
27
 
39
28
  private
40
29
  def build_sale_or_authorization_request(action, money, credit_card, options)
41
- shipping_address = options[:shipping_address] || options[:address]
30
+ billing_address = options[:billing_address] || options[:address]
42
31
  currency_code = options[:currency] || currency(money)
43
32
 
44
33
  xml = Builder::XmlMarkup.new :indent => 2
@@ -63,9 +52,9 @@ module ActiveMerchant #:nodoc:
63
52
  xml.tag! 'n2:InvoiceID', options[:order_id]
64
53
  xml.tag! 'n2:ButtonSource', application_id.to_s.slice(0,32) unless application_id.blank?
65
54
 
66
- add_address(xml, 'n2:ShipToAddress', shipping_address)
55
+ add_address(xml, 'n2:ShipToAddress', options[:shipping_address]) if options[:shipping_address]
67
56
  end
68
- add_credit_card(xml, credit_card, options[:billing_address] || shipping_address, options)
57
+ add_credit_card(xml, credit_card, billing_address, options)
69
58
  xml.tag! 'n2:IPAddress', options[:ip]
70
59
  end
71
60
  end
@@ -1,17 +1,21 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
- # This class is included in both PaypalGateway and PaypalExpressGateway
3
+ # This module is included in both PaypalGateway and PaypalExpressGateway
4
4
  module PaypalCommonAPI
5
5
  def self.included(base)
6
-
7
6
  base.default_currency = 'USD'
8
7
  base.cattr_accessor :pem_file
9
8
  base.cattr_accessor :signature
10
9
  end
11
10
 
12
11
  API_VERSION = '2.0'
13
- TEST_URL = 'https://api.sandbox.paypal.com/2.0/'
14
- LIVE_URL = 'https://api-aa.paypal.com/2.0/'
12
+
13
+ URLS = {
14
+ :test => { :certificate => 'https://api.sandbox.paypal.com/2.0/',
15
+ :signature => 'https://api-3t.sandbox.paypal.com/2.0/' },
16
+ :live => { :certificate => 'https://api-aa.paypal.com/2.0/',
17
+ :signature => 'https://api-3t.paypal.com/2.0/' }
18
+ }
15
19
 
16
20
  PAYPAL_NAMESPACE = 'urn:ebay:api:PayPalAPI'
17
21
  EBAY_NAMESPACE = 'urn:ebay:apis:eBLBaseComponents'
@@ -36,6 +40,8 @@ module ActiveMerchant #:nodoc:
36
40
  'WA' => 'Western Australia'
37
41
  }
38
42
 
43
+ SUCCESS_CODES = [ 'Success', 'SuccessWithWarning' ]
44
+
39
45
  # The gateway must be configured with either your PayPal PEM file
40
46
  # or your PayPal API Signature. Only one is required.
41
47
  #
@@ -60,6 +66,10 @@ module ActiveMerchant #:nodoc:
60
66
  :signature => signature
61
67
  }.update(options)
62
68
 
69
+ if @options[:pem].blank? && @options[:signature].blank?
70
+ raise ArgumentError, "An API Certificate or API Signature is required to make requests to PayPal"
71
+ end
72
+
63
73
  super
64
74
  end
65
75
 
@@ -273,27 +283,37 @@ module ActiveMerchant #:nodoc:
273
283
  case country.code(:alpha2).to_s
274
284
  when 'AU'
275
285
  AUSTRALIAN_STATES[address[:state]] || address[:state]
276
- when 'GB'
277
- address[:state].blank? ? 'N/A' : address[:state]
278
286
  else
279
- address[:state]
287
+ address[:state].blank? ? 'N/A' : address[:state]
280
288
  end
281
289
  end
290
+
291
+ def endpoint_url
292
+ URLS[test? ? :test : :live][@options[:signature].blank? ? :certificate : :signature]
293
+ end
282
294
 
283
295
  def commit(action, request)
284
- url = test? ? TEST_URL : LIVE_URL
285
-
286
- data = ssl_post(url, build_request(request))
287
- @response = parse(action, data)
296
+ response = parse(action, ssl_post(endpoint_url, build_request(request)))
288
297
 
289
- success = @response[:ack] == "Success"
290
- message = @response[:message] || @response[:ack]
291
-
292
- build_response(success, message, @response,
298
+ build_response(successful?(response), message_from(response), response,
293
299
  :test => test?,
294
- :authorization => @response[:transaction_id] || @response[:authorization_id] # latter one is from reauthorization
300
+ :authorization => authorization_from(response),
301
+ :avs_result => { :code => response[:avs_code] },
302
+ :cvv_result => response[:cvv2_code]
295
303
  )
296
304
  end
305
+
306
+ def authorization_from(response)
307
+ response[:transaction_id] || response[:authorization_id] # latter one is from reauthorization
308
+ end
309
+
310
+ def successful?(response)
311
+ SUCCESS_CODES.include?(response[:ack])
312
+ end
313
+
314
+ def message_from(response)
315
+ response[:message] || response[:ack]
316
+ end
297
317
  end
298
318
  end
299
319
  end