gonow-activemerchant 1.15.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 (189) hide show
  1. data/CHANGELOG +690 -0
  2. data/CONTRIBUTORS +237 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +165 -0
  5. data/gem-public_cert.pem +20 -0
  6. data/lib/active_merchant.rb +47 -0
  7. data/lib/active_merchant/billing.rb +9 -0
  8. data/lib/active_merchant/billing/avs_result.rb +98 -0
  9. data/lib/active_merchant/billing/base.rb +57 -0
  10. data/lib/active_merchant/billing/check.rb +68 -0
  11. data/lib/active_merchant/billing/credit_card.rb +178 -0
  12. data/lib/active_merchant/billing/credit_card_formatting.rb +21 -0
  13. data/lib/active_merchant/billing/credit_card_methods.rb +125 -0
  14. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  15. data/lib/active_merchant/billing/expiry_date.rb +34 -0
  16. data/lib/active_merchant/billing/gateway.rb +170 -0
  17. data/lib/active_merchant/billing/gateways.rb +18 -0
  18. data/lib/active_merchant/billing/gateways/authorize_net.rb +664 -0
  19. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +858 -0
  20. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +308 -0
  21. data/lib/active_merchant/billing/gateways/beanstream.rb +139 -0
  22. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +282 -0
  23. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
  24. data/lib/active_merchant/billing/gateways/blue_pay.rb +11 -0
  25. data/lib/active_merchant/billing/gateways/bogus.rb +132 -0
  26. data/lib/active_merchant/billing/gateways/braintree.rb +17 -0
  27. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  28. data/lib/active_merchant/billing/gateways/braintree_blue.rb +293 -0
  29. data/lib/active_merchant/billing/gateways/braintree_orange.rb +17 -0
  30. data/lib/active_merchant/billing/gateways/braspag.rb +188 -0
  31. data/lib/active_merchant/billing/gateways/card_stream.rb +230 -0
  32. data/lib/active_merchant/billing/gateways/cyber_source.rb +430 -0
  33. data/lib/active_merchant/billing/gateways/data_cash.rb +597 -0
  34. data/lib/active_merchant/billing/gateways/efsnet.rb +235 -0
  35. data/lib/active_merchant/billing/gateways/elavon.rb +134 -0
  36. data/lib/active_merchant/billing/gateways/epay.rb +268 -0
  37. data/lib/active_merchant/billing/gateways/eway.rb +277 -0
  38. data/lib/active_merchant/billing/gateways/eway_managed.rb +231 -0
  39. data/lib/active_merchant/billing/gateways/exact.rb +222 -0
  40. data/lib/active_merchant/billing/gateways/federated_canada.rb +168 -0
  41. data/lib/active_merchant/billing/gateways/first_pay.rb +177 -0
  42. data/lib/active_merchant/billing/gateways/garanti.rb +262 -0
  43. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +250 -0
  44. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  45. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  46. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +55 -0
  47. data/lib/active_merchant/billing/gateways/inspire.rb +221 -0
  48. data/lib/active_merchant/billing/gateways/instapay.rb +164 -0
  49. data/lib/active_merchant/billing/gateways/iridium.rb +258 -0
  50. data/lib/active_merchant/billing/gateways/jetpay.rb +276 -0
  51. data/lib/active_merchant/billing/gateways/linkpoint.rb +454 -0
  52. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +156 -0
  53. data/lib/active_merchant/billing/gateways/merchant_ware.rb +289 -0
  54. data/lib/active_merchant/billing/gateways/modern_payments.rb +36 -0
  55. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +220 -0
  56. data/lib/active_merchant/billing/gateways/moneris.rb +209 -0
  57. data/lib/active_merchant/billing/gateways/net_registry.rb +189 -0
  58. data/lib/active_merchant/billing/gateways/netaxept.rb +239 -0
  59. data/lib/active_merchant/billing/gateways/netbilling.rb +168 -0
  60. data/lib/active_merchant/billing/gateways/nmi.rb +13 -0
  61. data/lib/active_merchant/billing/gateways/ogone.rb +292 -0
  62. data/lib/active_merchant/billing/gateways/orbital.rb +321 -0
  63. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +46 -0
  64. data/lib/active_merchant/billing/gateways/pay_junction.rb +392 -0
  65. data/lib/active_merchant/billing/gateways/pay_secure.rb +120 -0
  66. data/lib/active_merchant/billing/gateways/paybox_direct.rb +207 -0
  67. data/lib/active_merchant/billing/gateways/payflow.rb +253 -0
  68. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +207 -0
  69. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  70. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  71. data/lib/active_merchant/billing/gateways/payflow_express.rb +222 -0
  72. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  73. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  74. data/lib/active_merchant/billing/gateways/payment_express.rb +235 -0
  75. data/lib/active_merchant/billing/gateways/paypal.rb +121 -0
  76. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +351 -0
  77. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +49 -0
  78. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  79. data/lib/active_merchant/billing/gateways/paypal_express.rb +177 -0
  80. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +25 -0
  81. data/lib/active_merchant/billing/gateways/plugnpay.rb +298 -0
  82. data/lib/active_merchant/billing/gateways/psigate.rb +219 -0
  83. data/lib/active_merchant/billing/gateways/psl_card.rb +304 -0
  84. data/lib/active_merchant/billing/gateways/qbms.rb +295 -0
  85. data/lib/active_merchant/billing/gateways/quantum.rb +282 -0
  86. data/lib/active_merchant/billing/gateways/quickpay.rb +218 -0
  87. data/lib/active_merchant/billing/gateways/realex.rb +311 -0
  88. data/lib/active_merchant/billing/gateways/sage.rb +146 -0
  89. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +88 -0
  90. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +116 -0
  91. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
  92. data/lib/active_merchant/billing/gateways/sage_pay.rb +320 -0
  93. data/lib/active_merchant/billing/gateways/sallie_mae.rb +144 -0
  94. data/lib/active_merchant/billing/gateways/secure_net.rb +330 -0
  95. data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
  96. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +193 -0
  97. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +113 -0
  98. data/lib/active_merchant/billing/gateways/skip_jack.rb +453 -0
  99. data/lib/active_merchant/billing/gateways/smart_ps.rb +271 -0
  100. data/lib/active_merchant/billing/gateways/stripe.rb +212 -0
  101. data/lib/active_merchant/billing/gateways/trans_first.rb +127 -0
  102. data/lib/active_merchant/billing/gateways/transax.rb +25 -0
  103. data/lib/active_merchant/billing/gateways/trust_commerce.rb +423 -0
  104. data/lib/active_merchant/billing/gateways/usa_epay.rb +194 -0
  105. data/lib/active_merchant/billing/gateways/verifi.rb +233 -0
  106. data/lib/active_merchant/billing/gateways/viaklix.rb +189 -0
  107. data/lib/active_merchant/billing/gateways/wirecard.rb +318 -0
  108. data/lib/active_merchant/billing/gateways/worldpay.rb +280 -0
  109. data/lib/active_merchant/billing/integrations.rb +17 -0
  110. data/lib/active_merchant/billing/integrations/action_view_helper.rb +68 -0
  111. data/lib/active_merchant/billing/integrations/bogus.rb +23 -0
  112. data/lib/active_merchant/billing/integrations/bogus/helper.rb +17 -0
  113. data/lib/active_merchant/billing/integrations/bogus/notification.rb +11 -0
  114. data/lib/active_merchant/billing/integrations/bogus/return.rb +10 -0
  115. data/lib/active_merchant/billing/integrations/chronopay.rb +23 -0
  116. data/lib/active_merchant/billing/integrations/chronopay/helper.rb +120 -0
  117. data/lib/active_merchant/billing/integrations/chronopay/notification.rb +158 -0
  118. data/lib/active_merchant/billing/integrations/chronopay/return.rb +10 -0
  119. data/lib/active_merchant/billing/integrations/direc_pay.rb +41 -0
  120. data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +200 -0
  121. data/lib/active_merchant/billing/integrations/direc_pay/notification.rb +76 -0
  122. data/lib/active_merchant/billing/integrations/direc_pay/return.rb +32 -0
  123. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +37 -0
  124. data/lib/active_merchant/billing/integrations/directebanking.rb +47 -0
  125. data/lib/active_merchant/billing/integrations/directebanking/helper.rb +90 -0
  126. data/lib/active_merchant/billing/integrations/directebanking/notification.rb +120 -0
  127. data/lib/active_merchant/billing/integrations/directebanking/return.rb +11 -0
  128. data/lib/active_merchant/billing/integrations/e_payment_plans.rb +48 -0
  129. data/lib/active_merchant/billing/integrations/e_payment_plans/helper.rb +34 -0
  130. data/lib/active_merchant/billing/integrations/e_payment_plans/notification.rb +84 -0
  131. data/lib/active_merchant/billing/integrations/gestpay.rb +25 -0
  132. data/lib/active_merchant/billing/integrations/gestpay/common.rb +42 -0
  133. data/lib/active_merchant/billing/integrations/gestpay/helper.rb +70 -0
  134. data/lib/active_merchant/billing/integrations/gestpay/notification.rb +85 -0
  135. data/lib/active_merchant/billing/integrations/gestpay/return.rb +10 -0
  136. data/lib/active_merchant/billing/integrations/helper.rb +96 -0
  137. data/lib/active_merchant/billing/integrations/hi_trust.rb +27 -0
  138. data/lib/active_merchant/billing/integrations/hi_trust/helper.rb +58 -0
  139. data/lib/active_merchant/billing/integrations/hi_trust/notification.rb +59 -0
  140. data/lib/active_merchant/billing/integrations/hi_trust/return.rb +67 -0
  141. data/lib/active_merchant/billing/integrations/moneybookers.rb +26 -0
  142. data/lib/active_merchant/billing/integrations/moneybookers/helper.rb +59 -0
  143. data/lib/active_merchant/billing/integrations/moneybookers/notification.rb +129 -0
  144. data/lib/active_merchant/billing/integrations/nochex.rb +88 -0
  145. data/lib/active_merchant/billing/integrations/nochex/helper.rb +68 -0
  146. data/lib/active_merchant/billing/integrations/nochex/notification.rb +94 -0
  147. data/lib/active_merchant/billing/integrations/nochex/return.rb +10 -0
  148. data/lib/active_merchant/billing/integrations/notification.rb +62 -0
  149. data/lib/active_merchant/billing/integrations/paypal.rb +39 -0
  150. data/lib/active_merchant/billing/integrations/paypal/helper.rb +119 -0
  151. data/lib/active_merchant/billing/integrations/paypal/notification.rb +154 -0
  152. data/lib/active_merchant/billing/integrations/paypal/return.rb +10 -0
  153. data/lib/active_merchant/billing/integrations/quickpay.rb +21 -0
  154. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +72 -0
  155. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +74 -0
  156. data/lib/active_merchant/billing/integrations/return.rb +42 -0
  157. data/lib/active_merchant/billing/integrations/sage_pay_form.rb +37 -0
  158. data/lib/active_merchant/billing/integrations/sage_pay_form/encryption.rb +33 -0
  159. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +111 -0
  160. data/lib/active_merchant/billing/integrations/sage_pay_form/notification.rb +210 -0
  161. data/lib/active_merchant/billing/integrations/sage_pay_form/return.rb +31 -0
  162. data/lib/active_merchant/billing/integrations/two_checkout.rb +23 -0
  163. data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +59 -0
  164. data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +114 -0
  165. data/lib/active_merchant/billing/integrations/two_checkout/return.rb +17 -0
  166. data/lib/active_merchant/billing/integrations/valitor.rb +33 -0
  167. data/lib/active_merchant/billing/integrations/valitor/helper.rb +86 -0
  168. data/lib/active_merchant/billing/integrations/valitor/notification.rb +13 -0
  169. data/lib/active_merchant/billing/integrations/valitor/response_fields.rb +97 -0
  170. data/lib/active_merchant/billing/integrations/valitor/return.rb +13 -0
  171. data/lib/active_merchant/billing/integrations/world_pay.rb +27 -0
  172. data/lib/active_merchant/billing/integrations/world_pay/helper.rb +100 -0
  173. data/lib/active_merchant/billing/integrations/world_pay/notification.rb +160 -0
  174. data/lib/active_merchant/billing/response.rb +32 -0
  175. data/lib/active_merchant/common.rb +14 -0
  176. data/lib/active_merchant/common/connection.rb +177 -0
  177. data/lib/active_merchant/common/country.rb +328 -0
  178. data/lib/active_merchant/common/error.rb +26 -0
  179. data/lib/active_merchant/common/post_data.rb +24 -0
  180. data/lib/active_merchant/common/posts_data.rb +63 -0
  181. data/lib/active_merchant/common/requires_parameters.rb +16 -0
  182. data/lib/active_merchant/common/utils.rb +22 -0
  183. data/lib/active_merchant/common/validateable.rb +81 -0
  184. data/lib/active_merchant/version.rb +3 -0
  185. data/lib/activemerchant.rb +1 -0
  186. data/lib/certs/cacert.pem +7815 -0
  187. data/lib/support/gateway_support.rb +58 -0
  188. data/lib/support/outbound_hosts.rb +25 -0
  189. metadata +276 -0
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/payflow_express'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class PayflowExpressUkGateway < PayflowExpressGateway
6
+ self.default_currency = 'GBP'
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)'
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/payflow'
2
+ require File.dirname(__FILE__) + '/payflow_express_uk'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ class PayflowUkGateway < PayflowGateway
7
+ self.default_currency = 'GBP'
8
+ self.partner = 'PayPalUk'
9
+
10
+ def express
11
+ @express ||= PayflowExpressUkGateway.new(@options)
12
+ end
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)'
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,235 @@
1
+ require 'rexml/document'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
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
+ self.default_currency = 'NZD'
11
+ # PS supports all major credit cards; Visa, Mastercard, Amex, Diners, BankCard & JCB.
12
+ # Various white label cards can be accepted as well; Farmers, AirNZCard and Elders etc.
13
+ # Please note that not all acquirers and Eftpos networks can support some of these card types.
14
+ # VISA, Mastercard, Diners Club and Farmers cards are supported
15
+ #
16
+ # However, regular accounts with DPS only support VISA and Mastercard
17
+ self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :jcb ]
18
+
19
+ self.supported_countries = [ 'AU', 'MY', 'NZ', 'SG', 'ZA', 'GB', 'US' ]
20
+
21
+ self.homepage_url = 'http://www.paymentexpress.com/'
22
+ self.display_name = 'PaymentExpress'
23
+
24
+ URL = 'https://sec.paymentexpress.com/pxpost.aspx'
25
+
26
+ APPROVED = '1'
27
+
28
+ TRANSACTIONS = {
29
+ :purchase => 'Purchase',
30
+ :credit => 'Refund',
31
+ :authorization => 'Auth',
32
+ :capture => 'Complete',
33
+ :validate => 'Validate'
34
+ }
35
+
36
+ # We require the DPS gateway username and password when the object is created.
37
+ def initialize(options = {})
38
+ # A DPS username and password must exist
39
+ requires!(options, :login, :password)
40
+ # Make the options an instance variable
41
+ @options = options
42
+ super
43
+ end
44
+
45
+ # Funds are transferred immediately.
46
+ def purchase(money, payment_source, options = {})
47
+ request = build_purchase_or_authorization_request(money, payment_source, options)
48
+ commit(:purchase, request)
49
+ end
50
+
51
+ # NOTE: Perhaps in options we allow a transaction note to be inserted
52
+ # Verifies that funds are available for the requested card and amount and reserves the specified amount.
53
+ # See: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Authcomplete
54
+ def authorize(money, payment_source, options = {})
55
+ request = build_purchase_or_authorization_request(money, payment_source, options)
56
+ commit(:authorization, request)
57
+ end
58
+
59
+ # Transfer pre-authorized funds immediately
60
+ # See: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Authcomplete
61
+ def capture(money, identification, options = {})
62
+ request = build_capture_or_credit_request(money, identification, options)
63
+ commit(:capture, request)
64
+ end
65
+
66
+ # Refund funds to the card holder
67
+ def refund(money, identification, options = {})
68
+ requires!(options, :description)
69
+
70
+ request = build_capture_or_credit_request(money, identification, options)
71
+ commit(:credit, request)
72
+ end
73
+
74
+ def credit(money, identification, options = {})
75
+ deprecated CREDIT_DEPRECATION_MESSAGE
76
+ refund(money, identification, options)
77
+ end
78
+
79
+ # token based billing
80
+
81
+ # initiates a "Validate" transcation to store card data on payment express servers
82
+ # returns a "token" that can be used to rebill this card
83
+ # see: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Tokenbilling
84
+ # PaymentExpress does not support unstoring a stored card.
85
+ def store(credit_card, options = {})
86
+ request = build_token_request(credit_card, options)
87
+ commit(:validate, request)
88
+ end
89
+
90
+ private
91
+
92
+ def build_purchase_or_authorization_request(money, payment_source, options)
93
+ result = new_transaction
94
+
95
+ if payment_source.is_a?(String)
96
+ add_billing_token(result, payment_source)
97
+ else
98
+ add_credit_card(result, payment_source)
99
+ end
100
+
101
+ add_amount(result, money, options)
102
+ add_invoice(result, options)
103
+ add_address_verification_data(result, options)
104
+ result
105
+ end
106
+
107
+ def build_capture_or_credit_request(money, identification, options)
108
+ result = new_transaction
109
+
110
+ add_amount(result, money, options)
111
+ add_invoice(result, options)
112
+ add_reference(result, identification)
113
+ result
114
+ end
115
+
116
+ def build_token_request(credit_card, options)
117
+ result = new_transaction
118
+ add_credit_card(result, credit_card)
119
+ add_amount(result, 100, options) #need to make an auth request for $1
120
+ add_token_request(result, options)
121
+ result
122
+ end
123
+
124
+ def add_credentials(xml)
125
+ xml.add_element("PostUsername").text = @options[:login]
126
+ xml.add_element("PostPassword").text = @options[:password]
127
+ end
128
+
129
+ def add_reference(xml, identification)
130
+ xml.add_element("DpsTxnRef").text = identification
131
+ end
132
+
133
+ def add_credit_card(xml, credit_card)
134
+ xml.add_element("CardHolderName").text = credit_card.name
135
+ xml.add_element("CardNumber").text = credit_card.number
136
+ xml.add_element("DateExpiry").text = format_date(credit_card.month, credit_card.year)
137
+
138
+ if credit_card.verification_value?
139
+ xml.add_element("Cvc2").text = credit_card.verification_value
140
+ end
141
+
142
+ if requires_start_date_or_issue_number?(credit_card)
143
+ 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?
144
+ xml.add_element("IssueNumber").text = credit_card.issue_number unless credit_card.issue_number.blank?
145
+ end
146
+ end
147
+
148
+ def add_billing_token(xml, token)
149
+ xml.add_element("DpsBillingId").text = token
150
+ end
151
+
152
+ def add_token_request(xml, options)
153
+ xml.add_element("BillingId").text = options[:billing_id] if options[:billing_id]
154
+ xml.add_element("EnableAddBillCard").text = 1
155
+ end
156
+
157
+ def add_amount(xml, money, options)
158
+ xml.add_element("Amount").text = amount(money)
159
+ xml.add_element("InputCurrency").text = options[:currency] || currency(money)
160
+ end
161
+
162
+ def add_transaction_type(xml, action)
163
+ xml.add_element("TxnType").text = TRANSACTIONS[action]
164
+ end
165
+
166
+ def add_invoice(xml, options)
167
+ xml.add_element("TxnId").text = options[:order_id].to_s.slice(0, 16) unless options[:order_id].blank?
168
+ xml.add_element("MerchantReference").text = options[:description] unless options[:description].blank?
169
+ end
170
+
171
+ def add_address_verification_data(xml, options)
172
+ address = options[:billing_address] || options[:address]
173
+ return if address.nil?
174
+
175
+ xml.add_element("EnableAvsData").text = 1
176
+ xml.add_element("AvsAction").text = 1
177
+
178
+ xml.add_element("AvsStreetAddress").text = address[:address1]
179
+ xml.add_element("AvsPostCode").text = address[:zip]
180
+ end
181
+
182
+ def new_transaction
183
+ REXML::Document.new.add_element("Txn")
184
+ end
185
+
186
+ # Take in the request and post it to DPS
187
+ def commit(action, request)
188
+ add_credentials(request)
189
+ add_transaction_type(request, action)
190
+
191
+ # Parse the XML response
192
+ response = parse( ssl_post(URL, request.to_s) )
193
+
194
+ # Return a response
195
+ PaymentExpressResponse.new(response[:success] == APPROVED, response[:card_holder_help_text], response,
196
+ :test => response[:test_mode] == '1',
197
+ :authorization => response[:dps_txn_ref]
198
+ )
199
+ end
200
+
201
+ # Response XML documentation: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#XMLTxnOutput
202
+ def parse(xml_string)
203
+ response = {}
204
+
205
+ xml = REXML::Document.new(xml_string)
206
+
207
+ # Gather all root elements such as HelpText
208
+ xml.elements.each('Txn/*') do |element|
209
+ response[element.name.underscore.to_sym] = element.text unless element.name == 'Transaction'
210
+ end
211
+
212
+ # Gather all transaction elements and prefix with "account_"
213
+ # So we could access the MerchantResponseText by going
214
+ # response[account_merchant_response_text]
215
+ xml.elements.each('Txn/Transaction/*') do |element|
216
+ response[element.name.underscore.to_sym] = element.text
217
+ end
218
+
219
+ response
220
+ end
221
+
222
+ def format_date(month, year)
223
+ "#{format(month, :two_digits)}#{format(year, :two_digits)}"
224
+ end
225
+ end
226
+
227
+ class PaymentExpressResponse < Response
228
+ # add a method to response so we can easily get the token
229
+ # for Validate transactions
230
+ def token
231
+ @params["billing_id"] || @params["dps_billing_id"]
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,121 @@
1
+ require File.dirname(__FILE__) + '/paypal/paypal_common_api'
2
+ require File.dirname(__FILE__) + '/paypal_express'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ class PaypalGateway < Gateway
7
+ include PaypalCommonAPI
8
+
9
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
10
+ self.supported_countries = ['US']
11
+ self.homepage_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_wp-pro-overview-outside'
12
+ self.display_name = 'PayPal Website Payments Pro (US)'
13
+
14
+ def authorize(money, credit_card_or_referenced_id, options = {})
15
+ requires!(options, :ip)
16
+ commit define_transaction_type(credit_card_or_referenced_id), build_sale_or_authorization_request('Authorization', money, credit_card_or_referenced_id, options)
17
+ end
18
+
19
+ def purchase(money, credit_card_or_referenced_id, options = {})
20
+ requires!(options, :ip)
21
+ commit define_transaction_type(credit_card_or_referenced_id), build_sale_or_authorization_request('Sale', money, credit_card_or_referenced_id, options)
22
+ end
23
+
24
+ def express
25
+ @express ||= PaypalExpressGateway.new(@options)
26
+ end
27
+
28
+ private
29
+
30
+ def define_transaction_type(transaction_arg)
31
+ if transaction_arg.is_a?(String)
32
+ return 'DoReferenceTransaction'
33
+ else
34
+ return 'DoDirectPayment'
35
+ end
36
+ end
37
+
38
+ def build_sale_or_authorization_request(action, money, credit_card_or_referenced_id, options)
39
+ transaction_type = define_transaction_type(credit_card_or_referenced_id)
40
+ reference_id = credit_card_or_referenced_id if transaction_type == "DoReferenceTransaction"
41
+
42
+ billing_address = options[:billing_address] || options[:address]
43
+ currency_code = options[:currency] || currency(money)
44
+
45
+ xml = Builder::XmlMarkup.new :indent => 2
46
+ xml.tag! transaction_type + 'Req', 'xmlns' => PAYPAL_NAMESPACE do
47
+ xml.tag! transaction_type + 'Request', 'xmlns:n2' => EBAY_NAMESPACE do
48
+ xml.tag! 'n2:Version', API_VERSION
49
+ xml.tag! 'n2:' + transaction_type + 'RequestDetails' do
50
+ xml.tag! 'n2:ReferenceID', reference_id if transaction_type == 'DoReferenceTransaction'
51
+ xml.tag! 'n2:PaymentAction', action
52
+ xml.tag! 'n2:PaymentDetails' do
53
+ xml.tag! 'n2:OrderTotal', localized_amount(money, currency_code), 'currencyID' => currency_code
54
+
55
+ # All of the values must be included together and add up to the order total
56
+ if [:subtotal, :shipping, :handling, :tax].all?{ |o| options.has_key?(o) }
57
+ xml.tag! 'n2:ItemTotal', localized_amount(options[:subtotal], currency_code), 'currencyID' => currency_code
58
+ xml.tag! 'n2:ShippingTotal', localized_amount(options[:shipping], currency_code),'currencyID' => currency_code
59
+ xml.tag! 'n2:HandlingTotal', localized_amount(options[:handling], currency_code),'currencyID' => currency_code
60
+ xml.tag! 'n2:TaxTotal', localized_amount(options[:tax], currency_code), 'currencyID' => currency_code
61
+ end
62
+
63
+ xml.tag! 'n2:NotifyURL', options[:notify_url]
64
+ xml.tag! 'n2:OrderDescription', options[:description]
65
+ xml.tag! 'n2:InvoiceID', options[:order_id]
66
+ xml.tag! 'n2:ButtonSource', application_id.to_s.slice(0,32) unless application_id.blank?
67
+
68
+ add_address(xml, 'n2:ShipToAddress', options[:shipping_address]) if options[:shipping_address]
69
+ end
70
+ add_credit_card(xml, credit_card_or_referenced_id, billing_address, options) unless transaction_type == 'DoReferenceTransaction'
71
+ xml.tag! 'n2:IPAddress', options[:ip]
72
+ end
73
+ end
74
+ end
75
+
76
+ xml.target!
77
+ end
78
+
79
+ def add_credit_card(xml, credit_card, address, options)
80
+ xml.tag! 'n2:CreditCard' do
81
+ xml.tag! 'n2:CreditCardType', credit_card_type(card_brand(credit_card))
82
+ xml.tag! 'n2:CreditCardNumber', credit_card.number
83
+ xml.tag! 'n2:ExpMonth', format(credit_card.month, :two_digits)
84
+ xml.tag! 'n2:ExpYear', format(credit_card.year, :four_digits)
85
+ xml.tag! 'n2:CVV2', credit_card.verification_value
86
+
87
+ if [ 'switch', 'solo' ].include?(card_brand(credit_card).to_s)
88
+ xml.tag! 'n2:StartMonth', format(credit_card.start_month, :two_digits) unless credit_card.start_month.blank?
89
+ xml.tag! 'n2:StartYear', format(credit_card.start_year, :four_digits) unless credit_card.start_year.blank?
90
+ xml.tag! 'n2:IssueNumber', format(credit_card.issue_number, :two_digits) unless credit_card.issue_number.blank?
91
+ end
92
+
93
+ xml.tag! 'n2:CardOwner' do
94
+ xml.tag! 'n2:PayerName' do
95
+ xml.tag! 'n2:FirstName', credit_card.first_name
96
+ xml.tag! 'n2:LastName', credit_card.last_name
97
+ end
98
+
99
+ xml.tag! 'n2:Payer', options[:email]
100
+ add_address(xml, 'n2:Address', address)
101
+ end
102
+ end
103
+ end
104
+
105
+ def credit_card_type(type)
106
+ case type
107
+ when 'visa' then 'Visa'
108
+ when 'master' then 'MasterCard'
109
+ when 'discover' then 'Discover'
110
+ when 'american_express' then 'Amex'
111
+ when 'switch' then 'Switch'
112
+ when 'solo' then 'Solo'
113
+ end
114
+ end
115
+
116
+ def build_response(success, message, response, options = {})
117
+ Response.new(success, message, response, options)
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,351 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ # This module is included in both PaypalGateway and PaypalExpressGateway
4
+ module PaypalCommonAPI
5
+ def self.included(base)
6
+ base.default_currency = 'USD'
7
+ base.cattr_accessor :pem_file
8
+ base.cattr_accessor :signature
9
+ end
10
+
11
+ API_VERSION = '62.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
+ }
19
+
20
+ PAYPAL_NAMESPACE = 'urn:ebay:api:PayPalAPI'
21
+ EBAY_NAMESPACE = 'urn:ebay:apis:eBLBaseComponents'
22
+
23
+ ENVELOPE_NAMESPACES = { 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
24
+ 'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/',
25
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
26
+ }
27
+ CREDENTIALS_NAMESPACES = { 'xmlns' => PAYPAL_NAMESPACE,
28
+ 'xmlns:n1' => EBAY_NAMESPACE,
29
+ 'env:mustUnderstand' => '0'
30
+ }
31
+
32
+ AUSTRALIAN_STATES = {
33
+ 'ACT' => 'Australian Capital Territory',
34
+ 'NSW' => 'New South Wales',
35
+ 'NT' => 'Northern Territory',
36
+ 'QLD' => 'Queensland',
37
+ 'SA' => 'South Australia',
38
+ 'TAS' => 'Tasmania',
39
+ 'VIC' => 'Victoria',
40
+ 'WA' => 'Western Australia'
41
+ }
42
+
43
+ SUCCESS_CODES = [ 'Success', 'SuccessWithWarning' ]
44
+
45
+ FRAUD_REVIEW_CODE = "11610"
46
+
47
+ # The gateway must be configured with either your PayPal PEM file
48
+ # or your PayPal API Signature. Only one is required.
49
+ #
50
+ # <tt>:pem</tt> The text of your PayPal PEM file. Note
51
+ # this is not the path to file, but its
52
+ # contents. If you are only using one PEM
53
+ # file on your site you can declare it
54
+ # globally and then you won't need to
55
+ # include this option
56
+ #
57
+ # <tt>:signature</tt> The text of your PayPal signature.
58
+ # If you are only using one API Signature
59
+ # on your site you can declare it
60
+ # globally and then you won't need to
61
+ # include this option
62
+
63
+ def initialize(options = {})
64
+ requires!(options, :login, :password)
65
+
66
+ @options = {
67
+ :pem => pem_file,
68
+ :signature => signature
69
+ }.update(options)
70
+
71
+ if @options[:pem].blank? && @options[:signature].blank?
72
+ raise ArgumentError, "An API Certificate or API Signature is required to make requests to PayPal"
73
+ end
74
+
75
+ super
76
+ end
77
+
78
+ def test?
79
+ @options[:test] || Base.gateway_mode == :test
80
+ end
81
+
82
+ def reauthorize(money, authorization, options = {})
83
+ commit 'DoReauthorization', build_reauthorize_request(money, authorization, options)
84
+ end
85
+
86
+ def capture(money, authorization, options = {})
87
+ commit 'DoCapture', build_capture_request(money, authorization, options)
88
+ end
89
+
90
+ # Transfer money to one or more recipients.
91
+ #
92
+ # gateway.transfer 1000, 'bob@example.com',
93
+ # :subject => "The money I owe you", :note => "Sorry it's so late"
94
+ #
95
+ # gateway.transfer [1000, 'fred@example.com'],
96
+ # [2450, 'wilma@example.com', :note => 'You will receive another payment on 3/24'],
97
+ # [2000, 'barney@example.com'],
98
+ # :subject => "Your Earnings", :note => "Thanks for your business."
99
+ #
100
+ def transfer(*args)
101
+ commit 'MassPay', build_mass_pay_request(*args)
102
+ end
103
+
104
+ def void(authorization, options = {})
105
+ commit 'DoVoid', build_void_request(authorization, options)
106
+ end
107
+
108
+ def refund(money, identification, options = {})
109
+ commit 'RefundTransaction', build_refund_request(money, identification, options)
110
+ end
111
+
112
+ def credit(money, identification, options = {})
113
+ deprecated Gateway::CREDIT_DEPRECATION_MESSAGE
114
+ refund(money, identification, options)
115
+ end
116
+
117
+ private
118
+ def build_reauthorize_request(money, authorization, options)
119
+ xml = Builder::XmlMarkup.new
120
+
121
+ xml.tag! 'DoReauthorizationReq', 'xmlns' => PAYPAL_NAMESPACE do
122
+ xml.tag! 'DoReauthorizationRequest', 'xmlns:n2' => EBAY_NAMESPACE do
123
+ xml.tag! 'n2:Version', API_VERSION
124
+ xml.tag! 'AuthorizationID', authorization
125
+ xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
126
+ end
127
+ end
128
+
129
+ xml.target!
130
+ end
131
+
132
+ def build_capture_request(money, authorization, options)
133
+ xml = Builder::XmlMarkup.new
134
+
135
+ xml.tag! 'DoCaptureReq', 'xmlns' => PAYPAL_NAMESPACE do
136
+ xml.tag! 'DoCaptureRequest', 'xmlns:n2' => EBAY_NAMESPACE do
137
+ xml.tag! 'n2:Version', API_VERSION
138
+ xml.tag! 'AuthorizationID', authorization
139
+ xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
140
+ xml.tag! 'CompleteType', 'Complete'
141
+ xml.tag! 'InvoiceID', options[:order_id] unless options[:order_id].blank?
142
+ xml.tag! 'Note', options[:description]
143
+ end
144
+ end
145
+
146
+ xml.target!
147
+ end
148
+
149
+ def build_refund_request(money, identification, options)
150
+ xml = Builder::XmlMarkup.new
151
+
152
+ xml.tag! 'RefundTransactionReq', 'xmlns' => PAYPAL_NAMESPACE do
153
+ xml.tag! 'RefundTransactionRequest', 'xmlns:n2' => EBAY_NAMESPACE do
154
+ xml.tag! 'n2:Version', API_VERSION
155
+ xml.tag! 'TransactionID', identification
156
+ xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
157
+ xml.tag! 'RefundType', 'Partial'
158
+ xml.tag! 'Memo', options[:note] unless options[:note].blank?
159
+ end
160
+ end
161
+
162
+ xml.target!
163
+ end
164
+
165
+ def build_void_request(authorization, options)
166
+ xml = Builder::XmlMarkup.new
167
+
168
+ xml.tag! 'DoVoidReq', 'xmlns' => PAYPAL_NAMESPACE do
169
+ xml.tag! 'DoVoidRequest', 'xmlns:n2' => EBAY_NAMESPACE do
170
+ xml.tag! 'n2:Version', API_VERSION
171
+ xml.tag! 'AuthorizationID', authorization
172
+ xml.tag! 'Note', options[:description]
173
+ end
174
+ end
175
+
176
+ xml.target!
177
+ end
178
+
179
+ def build_mass_pay_request(*args)
180
+ default_options = args.last.is_a?(Hash) ? args.pop : {}
181
+ recipients = args.first.is_a?(Array) ? args : [args]
182
+
183
+ xml = Builder::XmlMarkup.new
184
+
185
+ xml.tag! 'MassPayReq', 'xmlns' => PAYPAL_NAMESPACE do
186
+ xml.tag! 'MassPayRequest', 'xmlns:n2' => EBAY_NAMESPACE do
187
+ xml.tag! 'n2:Version', API_VERSION
188
+ xml.tag! 'EmailSubject', default_options[:subject] if default_options[:subject]
189
+ recipients.each do |money, recipient, options|
190
+ options ||= default_options
191
+ xml.tag! 'MassPayItem' do
192
+ xml.tag! 'ReceiverEmail', recipient
193
+ xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
194
+ xml.tag! 'Note', options[:note] if options[:note]
195
+ xml.tag! 'UniqueId', options[:unique_id] if options[:unique_id]
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ xml.target!
202
+ end
203
+
204
+ def parse(action, xml)
205
+ legacy_hash = legacy_parse(action, xml)
206
+ xml = strip_attributes(xml)
207
+ hash = Hash.from_xml(xml)
208
+ hash = hash.fetch('Envelope').fetch('Body').fetch("#{action}Response")
209
+ hash = hash["#{action}ResponseDetails"] if hash["#{action}ResponseDetails"]
210
+
211
+ legacy_hash.merge(hash)
212
+ rescue IndexError
213
+ legacy_hash.merge(hash['Envelope']['Body'])
214
+ end
215
+
216
+ def strip_attributes(xml)
217
+ xml = REXML::Document.new(xml)
218
+ REXML::XPath.each(xml, '//SOAP-ENV:Envelope//*[@*]') do |el|
219
+ el.attributes.each_attribute { |a| a.remove }
220
+ end
221
+ xml.to_s
222
+ end
223
+
224
+ def legacy_parse(action, xml)
225
+ response = {}
226
+
227
+ error_messages = []
228
+ error_codes = []
229
+
230
+ xml = REXML::Document.new(xml)
231
+ if root = REXML::XPath.first(xml, "//#{action}Response")
232
+ root.elements.each do |node|
233
+ case node.name
234
+ when 'Errors'
235
+ short_message = nil
236
+ long_message = nil
237
+
238
+ node.elements.each do |child|
239
+ case child.name
240
+ when "LongMessage"
241
+ long_message = child.text unless child.text.blank?
242
+ when "ShortMessage"
243
+ short_message = child.text unless child.text.blank?
244
+ when "ErrorCode"
245
+ error_codes << child.text unless child.text.blank?
246
+ end
247
+ end
248
+
249
+ if message = long_message || short_message
250
+ error_messages << message
251
+ end
252
+ else
253
+ legacy_parse_element(response, node)
254
+ end
255
+ end
256
+ response[:message] = error_messages.uniq.join(". ") unless error_messages.empty?
257
+ response[:error_codes] = error_codes.uniq.join(",") unless error_codes.empty?
258
+ elsif root = REXML::XPath.first(xml, "//SOAP-ENV:Fault")
259
+ legacy_parse_element(response, root)
260
+ response[:message] = "#{response[:faultcode]}: #{response[:faultstring]} - #{response[:detail]}"
261
+ end
262
+
263
+ response
264
+ end
265
+
266
+ def legacy_parse_element(response, node)
267
+ if node.has_elements?
268
+ node.elements.each{|e| legacy_parse_element(response, e) }
269
+ else
270
+ response[node.name.underscore.to_sym] = node.text
271
+ node.attributes.each do |k, v|
272
+ response["#{node.name.underscore}_#{k.underscore}".to_sym] = v if k == 'currencyID'
273
+ end
274
+ end
275
+ end
276
+
277
+ def build_request(body)
278
+ xml = Builder::XmlMarkup.new
279
+
280
+ xml.instruct!
281
+ xml.tag! 'env:Envelope', ENVELOPE_NAMESPACES do
282
+ xml.tag! 'env:Header' do
283
+ add_credentials(xml)
284
+ end
285
+
286
+ xml.tag! 'env:Body' do
287
+ xml << body
288
+ end
289
+ end
290
+ xml.target!
291
+ end
292
+
293
+ def add_credentials(xml)
294
+ xml.tag! 'RequesterCredentials', CREDENTIALS_NAMESPACES do
295
+ xml.tag! 'n1:Credentials' do
296
+ xml.tag! 'Username', @options[:login]
297
+ xml.tag! 'Password', @options[:password]
298
+ xml.tag! 'Subject', @options[:subject]
299
+ xml.tag! 'Signature', @options[:signature] unless @options[:signature].blank?
300
+ end
301
+ end
302
+ end
303
+
304
+ def add_address(xml, element, address)
305
+ return if address.nil?
306
+ xml.tag! element do
307
+ xml.tag! 'n2:Name', address[:name]
308
+ xml.tag! 'n2:Street1', address[:address1]
309
+ xml.tag! 'n2:Street2', address[:address2]
310
+ xml.tag! 'n2:CityName', address[:city]
311
+ xml.tag! 'n2:StateOrProvince', address[:state].blank? ? 'N/A' : address[:state]
312
+ xml.tag! 'n2:Country', address[:country]
313
+ xml.tag! 'n2:PostalCode', address[:zip]
314
+ xml.tag! 'n2:Phone', address[:phone]
315
+ end
316
+ end
317
+
318
+ def endpoint_url
319
+ URLS[test? ? :test : :live][@options[:signature].blank? ? :certificate : :signature]
320
+ end
321
+
322
+ def commit(action, request)
323
+ response = parse(action, ssl_post(endpoint_url, build_request(request)))
324
+
325
+ build_response(successful?(response), message_from(response), response,
326
+ :test => test?,
327
+ :authorization => authorization_from(response),
328
+ :fraud_review => fraud_review?(response),
329
+ :avs_result => { :code => response[:avs_code] },
330
+ :cvv_result => response[:cvv2_code]
331
+ )
332
+ end
333
+
334
+ def fraud_review?(response)
335
+ response[:error_codes] == FRAUD_REVIEW_CODE
336
+ end
337
+
338
+ def authorization_from(response)
339
+ response[:transaction_id] || response[:authorization_id] || response[:refund_transaction_id] # middle one is from reauthorization
340
+ end
341
+
342
+ def successful?(response)
343
+ SUCCESS_CODES.include?(response[:ack])
344
+ end
345
+
346
+ def message_from(response)
347
+ response[:message] || response[:ack]
348
+ end
349
+ end
350
+ end
351
+ end