activemerchant 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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