aktivemerchant 2.0.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 (193) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +1596 -0
  3. data/CONTRIBUTORS +511 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +18 -0
  6. data/lib/active_merchant.rb +108 -0
  7. data/lib/active_merchant/billing.rb +13 -0
  8. data/lib/active_merchant/billing/apple_pay_payment_token.rb +22 -0
  9. data/lib/active_merchant/billing/avs_result.rb +98 -0
  10. data/lib/active_merchant/billing/base.rb +72 -0
  11. data/lib/active_merchant/billing/check.rb +76 -0
  12. data/lib/active_merchant/billing/compatibility.rb +120 -0
  13. data/lib/active_merchant/billing/credit_card.rb +352 -0
  14. data/lib/active_merchant/billing/credit_card_formatting.rb +24 -0
  15. data/lib/active_merchant/billing/credit_card_methods.rb +160 -0
  16. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  17. data/lib/active_merchant/billing/gateway.rb +268 -0
  18. data/lib/active_merchant/billing/gateways.rb +17 -0
  19. data/lib/active_merchant/billing/gateways/adyen.rb +209 -0
  20. data/lib/active_merchant/billing/gateways/alfabank.rb +117 -0
  21. data/lib/active_merchant/billing/gateways/app55.rb +176 -0
  22. data/lib/active_merchant/billing/gateways/authorize_net.rb +419 -0
  23. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +417 -0
  24. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +976 -0
  25. data/lib/active_merchant/billing/gateways/balanced.rb +256 -0
  26. data/lib/active_merchant/billing/gateways/bank_frick.rb +225 -0
  27. data/lib/active_merchant/billing/gateways/banwire.rb +105 -0
  28. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +314 -0
  29. data/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb +15 -0
  30. data/lib/active_merchant/billing/gateways/be2bill.rb +131 -0
  31. data/lib/active_merchant/billing/gateways/beanstream.rb +188 -0
  32. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +393 -0
  33. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
  34. data/lib/active_merchant/billing/gateways/blue_pay.rb +506 -0
  35. data/lib/active_merchant/billing/gateways/bogus.rb +140 -0
  36. data/lib/active_merchant/billing/gateways/borgun.rb +210 -0
  37. data/lib/active_merchant/billing/gateways/braintree.rb +19 -0
  38. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  39. data/lib/active_merchant/billing/gateways/braintree_blue.rb +515 -0
  40. data/lib/active_merchant/billing/gateways/braintree_orange.rb +20 -0
  41. data/lib/active_merchant/billing/gateways/bridge_pay.rb +189 -0
  42. data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
  43. data/lib/active_merchant/billing/gateways/card_stream.rb +220 -0
  44. data/lib/active_merchant/billing/gateways/cashnet.rb +191 -0
  45. data/lib/active_merchant/billing/gateways/cc5.rb +201 -0
  46. data/lib/active_merchant/billing/gateways/cecabank.rb +229 -0
  47. data/lib/active_merchant/billing/gateways/certo_direct.rb +278 -0
  48. data/lib/active_merchant/billing/gateways/checkout.rb +213 -0
  49. data/lib/active_merchant/billing/gateways/commercegate.rb +143 -0
  50. data/lib/active_merchant/billing/gateways/conekta.rb +209 -0
  51. data/lib/active_merchant/billing/gateways/cyber_source.rb +709 -0
  52. data/lib/active_merchant/billing/gateways/data_cash.rb +600 -0
  53. data/lib/active_merchant/billing/gateways/efsnet.rb +219 -0
  54. data/lib/active_merchant/billing/gateways/elavon.rb +348 -0
  55. data/lib/active_merchant/billing/gateways/epay.rb +275 -0
  56. data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
  57. data/lib/active_merchant/billing/gateways/eway.rb +214 -0
  58. data/lib/active_merchant/billing/gateways/eway_managed.rb +291 -0
  59. data/lib/active_merchant/billing/gateways/eway_rapid.rb +524 -0
  60. data/lib/active_merchant/billing/gateways/exact.rb +218 -0
  61. data/lib/active_merchant/billing/gateways/fat_zebra.rb +173 -0
  62. data/lib/active_merchant/billing/gateways/federated_canada.rb +160 -0
  63. data/lib/active_merchant/billing/gateways/finansbank.rb +23 -0
  64. data/lib/active_merchant/billing/gateways/first_giving.rb +143 -0
  65. data/lib/active_merchant/billing/gateways/first_pay.rb +160 -0
  66. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +355 -0
  67. data/lib/active_merchant/billing/gateways/garanti.rb +257 -0
  68. data/lib/active_merchant/billing/gateways/global_transport.rb +183 -0
  69. data/lib/active_merchant/billing/gateways/hdfc.rb +207 -0
  70. data/lib/active_merchant/billing/gateways/hps.rb +288 -0
  71. data/lib/active_merchant/billing/gateways/iats_payments.rb +251 -0
  72. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +246 -0
  73. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  74. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  75. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +66 -0
  76. data/lib/active_merchant/billing/gateways/inspire.rb +213 -0
  77. data/lib/active_merchant/billing/gateways/instapay.rb +163 -0
  78. data/lib/active_merchant/billing/gateways/iridium.rb +457 -0
  79. data/lib/active_merchant/billing/gateways/itransact.rb +448 -0
  80. data/lib/active_merchant/billing/gateways/jetpay.rb +275 -0
  81. data/lib/active_merchant/billing/gateways/linkpoint.rb +438 -0
  82. data/lib/active_merchant/billing/gateways/litle.rb +346 -0
  83. data/lib/active_merchant/billing/gateways/maxipago.rb +197 -0
  84. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +170 -0
  85. data/lib/active_merchant/billing/gateways/merchant_one.rb +114 -0
  86. data/lib/active_merchant/billing/gateways/merchant_ware.rb +319 -0
  87. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +268 -0
  88. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +195 -0
  89. data/lib/active_merchant/billing/gateways/mercury.rb +333 -0
  90. data/lib/active_merchant/billing/gateways/metrics_global.rb +303 -0
  91. data/lib/active_merchant/billing/gateways/migs.rb +265 -0
  92. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
  93. data/lib/active_merchant/billing/gateways/modern_payments.rb +37 -0
  94. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +219 -0
  95. data/lib/active_merchant/billing/gateways/moneris.rb +309 -0
  96. data/lib/active_merchant/billing/gateways/moneris_us.rb +291 -0
  97. data/lib/active_merchant/billing/gateways/money_movers.rb +152 -0
  98. data/lib/active_merchant/billing/gateways/nab_transact.rb +280 -0
  99. data/lib/active_merchant/billing/gateways/net_registry.rb +198 -0
  100. data/lib/active_merchant/billing/gateways/netaxept.rb +181 -0
  101. data/lib/active_merchant/billing/gateways/netbilling.rb +190 -0
  102. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  103. data/lib/active_merchant/billing/gateways/network_merchants.rb +242 -0
  104. data/lib/active_merchant/billing/gateways/nmi.rb +256 -0
  105. data/lib/active_merchant/billing/gateways/ogone.rb +435 -0
  106. data/lib/active_merchant/billing/gateways/openpay.rb +194 -0
  107. data/lib/active_merchant/billing/gateways/optimal_payment.rb +313 -0
  108. data/lib/active_merchant/billing/gateways/orbital.rb +803 -0
  109. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +47 -0
  110. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +207 -0
  111. data/lib/active_merchant/billing/gateways/pago_facil.rb +122 -0
  112. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +261 -0
  113. data/lib/active_merchant/billing/gateways/pay_junction.rb +390 -0
  114. data/lib/active_merchant/billing/gateways/pay_secure.rb +112 -0
  115. data/lib/active_merchant/billing/gateways/pay_u_latam.rb +462 -0
  116. data/lib/active_merchant/billing/gateways/paybox_direct.rb +188 -0
  117. data/lib/active_merchant/billing/gateways/payex.rb +412 -0
  118. data/lib/active_merchant/billing/gateways/payflow.rb +304 -0
  119. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +209 -0
  120. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  121. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  122. data/lib/active_merchant/billing/gateways/payflow_express.rb +224 -0
  123. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  124. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  125. data/lib/active_merchant/billing/gateways/payment_express.rb +353 -0
  126. data/lib/active_merchant/billing/gateways/paymill.rb +281 -0
  127. data/lib/active_merchant/billing/gateways/paypal.rb +117 -0
  128. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +670 -0
  129. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +65 -0
  130. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +262 -0
  131. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  132. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +44 -0
  133. data/lib/active_merchant/billing/gateways/paypal_express.rb +264 -0
  134. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +30 -0
  135. data/lib/active_merchant/billing/gateways/payscout.rb +162 -0
  136. data/lib/active_merchant/billing/gateways/paystation.rb +199 -0
  137. data/lib/active_merchant/billing/gateways/payway.rb +207 -0
  138. data/lib/active_merchant/billing/gateways/pin.rb +197 -0
  139. data/lib/active_merchant/billing/gateways/plugnpay.rb +283 -0
  140. data/lib/active_merchant/billing/gateways/psigate.rb +216 -0
  141. data/lib/active_merchant/billing/gateways/psl_card.rb +303 -0
  142. data/lib/active_merchant/billing/gateways/qbms.rb +292 -0
  143. data/lib/active_merchant/billing/gateways/quantum.rb +276 -0
  144. data/lib/active_merchant/billing/gateways/quickpay.rb +367 -0
  145. data/lib/active_merchant/billing/gateways/realex.rb +298 -0
  146. data/lib/active_merchant/billing/gateways/redsys.rb +391 -0
  147. data/lib/active_merchant/billing/gateways/sage.rb +175 -0
  148. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +87 -0
  149. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +114 -0
  150. data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +149 -0
  151. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +102 -0
  152. data/lib/active_merchant/billing/gateways/sage_pay.rb +398 -0
  153. data/lib/active_merchant/billing/gateways/sallie_mae.rb +143 -0
  154. data/lib/active_merchant/billing/gateways/secure_net.rb +252 -0
  155. data/lib/active_merchant/billing/gateways/secure_pay.rb +201 -0
  156. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +281 -0
  157. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +105 -0
  158. data/lib/active_merchant/billing/gateways/skip_jack.rb +452 -0
  159. data/lib/active_merchant/billing/gateways/smart_ps.rb +283 -0
  160. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +194 -0
  161. data/lib/active_merchant/billing/gateways/spreedly_core.rb +247 -0
  162. data/lib/active_merchant/billing/gateways/stripe.rb +411 -0
  163. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +157 -0
  164. data/lib/active_merchant/billing/gateways/tns.rb +227 -0
  165. data/lib/active_merchant/billing/gateways/trans_first.rb +126 -0
  166. data/lib/active_merchant/billing/gateways/transax.rb +23 -0
  167. data/lib/active_merchant/billing/gateways/transnational.rb +10 -0
  168. data/lib/active_merchant/billing/gateways/trust_commerce.rb +416 -0
  169. data/lib/active_merchant/billing/gateways/usa_epay.rb +25 -0
  170. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1516 -0
  171. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +254 -0
  172. data/lib/active_merchant/billing/gateways/verifi.rb +225 -0
  173. data/lib/active_merchant/billing/gateways/viaklix.rb +183 -0
  174. data/lib/active_merchant/billing/gateways/vindicia.rb +385 -0
  175. data/lib/active_merchant/billing/gateways/webpay.rb +97 -0
  176. data/lib/active_merchant/billing/gateways/wepay.rb +189 -0
  177. data/lib/active_merchant/billing/gateways/wirecard.rb +421 -0
  178. data/lib/active_merchant/billing/gateways/worldpay.rb +331 -0
  179. data/lib/active_merchant/billing/gateways/worldpay_us.rb +181 -0
  180. data/lib/active_merchant/billing/model.rb +30 -0
  181. data/lib/active_merchant/billing/payment_token.rb +21 -0
  182. data/lib/active_merchant/billing/rails.rb +3 -0
  183. data/lib/active_merchant/billing/response.rb +91 -0
  184. data/lib/active_merchant/country.rb +332 -0
  185. data/lib/active_merchant/empty.rb +20 -0
  186. data/lib/active_merchant/errors.rb +29 -0
  187. data/lib/active_merchant/offsite_payments_shim.rb +19 -0
  188. data/lib/active_merchant/version.rb +3 -0
  189. data/lib/activemerchant.rb +1 -0
  190. data/lib/support/gateway_support.rb +71 -0
  191. data/lib/support/outbound_hosts.rb +25 -0
  192. data/lib/support/ssl_verify.rb +93 -0
  193. metadata +400 -0
@@ -0,0 +1,216 @@
1
+ require 'rexml/document'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ # This class implements the Psigate gateway for the ActiveMerchant module.
6
+ #
7
+ # Modifications by Sean O'Hara ( sohara at sohara dot com )
8
+ #
9
+ # Usage for a PreAuth (authorize) is as follows:
10
+ #
11
+ # gateway = PsigateGateway.new(
12
+ # :login => 'teststore',
13
+ # :password => 'psigate1234'
14
+ # )
15
+ #
16
+ # creditcard = CreditCard.new(
17
+ # :number => '4242424242424242',
18
+ # :month => 8,
19
+ # :year => 2006,
20
+ # :first_name => 'Longbob',
21
+ # :last_name => 'Longsen'
22
+ # )
23
+ #
24
+ # twenty = 2000
25
+ # response = @gateway.authorize(twenty, creditcard,
26
+ # :order_id => 1234,
27
+ # :billing_address => {
28
+ # :address1 => '123 fairweather Lane',
29
+ # :address2 => 'Apt B',
30
+ # :city => 'New York',
31
+ # :state => 'NY',
32
+ # :country => 'U.S.A.',
33
+ # :zip => '10010'
34
+ # },
35
+ # :email => 'jack@yahoo.com'
36
+ # )
37
+ class PsigateGateway < Gateway
38
+ self.test_url = 'https://dev.psigate.com:7989/Messenger/XMLMessenger'
39
+ self.live_url = 'https://secure.psigate.com:17934/Messenger/XMLMessenger'
40
+
41
+ self.supported_cardtypes = [:visa, :master, :american_express]
42
+ self.supported_countries = ['CA']
43
+ self.homepage_url = 'http://www.psigate.com/'
44
+ self.display_name = 'Psigate'
45
+
46
+ SUCCESS_MESSAGE = 'Success'
47
+ FAILURE_MESSAGE = 'The transaction was declined'
48
+
49
+ def initialize(options = {})
50
+ requires!(options, :login, :password)
51
+ super
52
+ end
53
+
54
+ def authorize(money, creditcard, options = {})
55
+ requires!(options, :order_id)
56
+ options[:CardAction] = "1"
57
+ commit(money, creditcard, options)
58
+ end
59
+
60
+ def purchase(money, creditcard, options = {})
61
+ requires!(options, :order_id)
62
+ options[:CardAction] = "0"
63
+ commit(money, creditcard, options)
64
+ end
65
+
66
+ def capture(money, authorization, options = {})
67
+ options[:CardAction] = "2"
68
+ options[:order_id], options[:trans_ref_number] = split_authorization(authorization)
69
+ commit(money, nil, options)
70
+ end
71
+
72
+ def credit(money, authorization, options = {})
73
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
74
+ refund(money, authorization, options)
75
+ end
76
+
77
+ def refund(money, authorization, options = {})
78
+ options[:CardAction] = "3"
79
+ options[:order_id], options[:trans_ref_number] = split_authorization(authorization)
80
+ commit(money, nil, options)
81
+ end
82
+
83
+ def void(authorization, options = {})
84
+ options[:CardAction] = "9"
85
+ options[:order_id], options[:trans_ref_number] = split_authorization(authorization)
86
+ commit(nil, nil, options)
87
+ end
88
+
89
+ private
90
+
91
+ def commit(money, creditcard, options = {})
92
+ response = parse(ssl_post(url, post_data(money, creditcard, options)))
93
+
94
+ Response.new(successful?(response), message_from(response), response,
95
+ :test => test?,
96
+ :authorization => build_authorization(response) ,
97
+ :avs_result => { :code => response[:avsresult] },
98
+ :cvv_result => response[:cardidresult]
99
+ )
100
+ end
101
+
102
+ def url
103
+ (test? ? self.test_url : self.live_url)
104
+ end
105
+
106
+ def successful?(response)
107
+ response[:approved] == "APPROVED"
108
+ end
109
+
110
+ def parse(xml)
111
+ response = {:message => "Global Error Receipt", :complete => false}
112
+
113
+ xml = REXML::Document.new(xml)
114
+ xml.elements.each('//Result/*') do |node|
115
+ response[node.name.downcase.to_sym] = normalize(node.text)
116
+ end unless xml.root.nil?
117
+
118
+ response
119
+ end
120
+
121
+ def post_data(money, creditcard, options)
122
+ xml = REXML::Document.new
123
+ xml << REXML::XMLDecl.new
124
+ root = xml.add_element("Order")
125
+
126
+ parameters(money, creditcard, options).each do |key, value|
127
+ root.add_element(key.to_s).text = value if value
128
+ end
129
+
130
+ xml.to_s
131
+ end
132
+
133
+ def parameters(money, creditcard, options = {})
134
+ params = {
135
+ # General order parameters
136
+ :StoreID => @options[:login],
137
+ :Passphrase => @options[:password],
138
+ :TestResult => options[:test_result],
139
+ :OrderID => options[:order_id],
140
+ :UserID => options[:user_id],
141
+ :Phone => options[:phone],
142
+ :Fax => options[:fax],
143
+ :Email => options[:email],
144
+ :TransRefNumber => options[:trans_ref_number],
145
+
146
+ # Credit Card parameters
147
+ :PaymentType => "CC",
148
+ :CardAction => options[:CardAction],
149
+
150
+ # Financial parameters
151
+ :CustomerIP => options[:ip],
152
+ :SubTotal => amount(money),
153
+ :Tax1 => options[:tax1],
154
+ :Tax2 => options[:tax2],
155
+ :ShippingTotal => options[:shipping_total],
156
+ }
157
+
158
+ if creditcard
159
+ exp_month = sprintf("%.2i", creditcard.month) unless creditcard.month.blank?
160
+ exp_year = creditcard.year.to_s[2,2] unless creditcard.year.blank?
161
+ card_id_code = (creditcard.verification_value.blank? ? nil : "1")
162
+
163
+ params.update(
164
+ :CardNumber => creditcard.number,
165
+ :CardExpMonth => exp_month,
166
+ :CardExpYear => exp_year,
167
+ :CardIDCode => card_id_code,
168
+ :CardIDNumber => creditcard.verification_value
169
+ )
170
+ end
171
+
172
+ if(address = (options[:billing_address] || options[:address]))
173
+ params[:Bname] = address[:name] || creditcard.name
174
+ params[:Baddress1] = address[:address1] unless address[:address1].blank?
175
+ params[:Baddress2] = address[:address2] unless address[:address2].blank?
176
+ params[:Bcity] = address[:city] unless address[:city].blank?
177
+ params[:Bprovince] = address[:state] unless address[:state].blank?
178
+ params[:Bpostalcode] = address[:zip] unless address[:zip].blank?
179
+ params[:Bcountry] = address[:country] unless address[:country].blank?
180
+ params[:Bcompany] = address[:company] unless address[:company].blank?
181
+ end
182
+
183
+ if address = options[:shipping_address]
184
+ params[:Sname] = address[:name] || creditcard.name
185
+ params[:Saddress1] = address[:address1] unless address[:address1].blank?
186
+ params[:Saddress2] = address[:address2] unless address[:address2].blank?
187
+ params[:Scity] = address[:city] unless address[:city].blank?
188
+ params[:Sprovince] = address[:state] unless address[:state].blank?
189
+ params[:Spostalcode] = address[:zip] unless address[:zip].blank?
190
+ params[:Scountry] = address[:country] unless address[:country].blank?
191
+ params[:Scompany] = address[:company] unless address[:company].blank?
192
+ end
193
+
194
+ params
195
+ end
196
+
197
+ def message_from(response)
198
+ if response[:approved] == "APPROVED"
199
+ return SUCCESS_MESSAGE
200
+ else
201
+ return FAILURE_MESSAGE if response[:errmsg].blank?
202
+ return response[:errmsg].gsub(/[^\w]/, ' ').split.join(" ").capitalize
203
+ end
204
+ end
205
+
206
+ def split_authorization(authorization)
207
+ order_id, trans_ref_number = authorization.split(';')
208
+ [order_id, trans_ref_number]
209
+ end
210
+
211
+ def build_authorization(response)
212
+ [response[:orderid], response[:transrefnumber]].join(";")
213
+ end
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,303 @@
1
+ module ActiveMerchant
2
+ module Billing
3
+ #
4
+ # ActiveMerchant PSL Card Gateway
5
+ #
6
+ # Notes:
7
+ # -To be able to use the capture function, the IP address of the machine must be
8
+ # registered with PSL
9
+ # -ESALE_KEYED should only be used in situations where the cardholder perceives the
10
+ # transaction to be Internet-based, such as purchasing from a web site/on-line store.
11
+ # If the Internet is used purely for the transport of information from the merchant
12
+ # directly to the gateway then the appropriate cardholder present or not present message
13
+ # type should be used rather than the ‘E’ equivalent.
14
+ # -The CV2 / AVS policies are set up with the account settings when signing up for an account
15
+ class PslCardGateway < Gateway
16
+ self.money_format = :cents
17
+ self.default_currency = 'GBP'
18
+
19
+ self.supported_countries = ['GB']
20
+ # Visa Credit, Visa Debit, Mastercard, Maestro, Solo, Electron,
21
+ # American Express, Diners Club, JCB, International Maestro,
22
+ # Style, Clydesdale Financial Services, Other
23
+
24
+ self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :jcb, :switch, :solo, :maestro ]
25
+ self.homepage_url = 'http://www.paymentsolutionsltd.com/'
26
+ self.display_name = 'PSL Payment Solutions'
27
+
28
+ # Default ISO 3166 country code (GB)
29
+ cattr_accessor :location
30
+ self.location = 826
31
+
32
+ # PslCard server self.live_url - The url is the same whether testing or live - use
33
+ # the test account when testing...
34
+ self.live_url = self.test_url = 'https://pslcard3.paymentsolutionsltd.com/secure/transact.asp?'
35
+
36
+ # eCommerce sale transaction, details keyed by merchant or cardholder
37
+ MESSAGE_TYPE = 'ESALE_KEYED'
38
+
39
+ # The type of response that we want to get from PSL, options are HTML, XML or REDIRECT
40
+ RESPONSE_ACTION = 'HTML'
41
+
42
+ # Currency Codes
43
+ CURRENCY_CODES = {
44
+ 'AUD' => 036,
45
+ 'GBP' => 826,
46
+ 'USD' => 840
47
+ }
48
+
49
+ #The terminal used - only for swipe transactions, so hard coded to 32 for online
50
+ EMV_TERMINAL_TYPE = 32
51
+
52
+ #Different Dispatch types
53
+ DISPATCH_LATER = 'LATER'
54
+ DISPATCH_NOW = 'NOW'
55
+
56
+ # Return codes
57
+ APPROVED = '00'
58
+
59
+ #Nominal amount to authorize for a 'dispatch later' type
60
+ #The nominal amount is held straight away, when the goods are ready
61
+ #to be dispatched, PSL is informed and the full amount is the
62
+ #taken.
63
+ NOMINAL_AMOUNT = 101
64
+
65
+ AVS_CODE = {
66
+ "ALL MATCH" => 'Y',
67
+ "SECURITY CODE MATCH ONLY" => 'N',
68
+ "ADDRESS MATCH ONLY" => 'Y',
69
+ "NO DATA MATCHES" => 'N',
70
+ "DATA NOT CHECKED" => 'R',
71
+ "SECURITY CHECKS NOT SUPPORTED" => 'X'
72
+ }
73
+
74
+ CVV_CODE = {
75
+ "ALL MATCH" => 'M',
76
+ "SECURITY CODE MATCH ONLY" => 'M',
77
+ "ADDRESS MATCH ONLY" => 'N',
78
+ "NO DATA MATCHES" => 'N',
79
+ "DATA NOT CHECKED" => 'P',
80
+ "SECURITY CHECKS NOT SUPPORTED" => 'X'
81
+ }
82
+
83
+ # Create a new PslCardGateway
84
+ #
85
+ # The gateway requires that a valid :login be passed in the options hash
86
+ #
87
+ # Paramaters:
88
+ # -options:
89
+ # :login - the PslCard account login (required)
90
+ def initialize(options = {})
91
+ requires!(options, :login)
92
+
93
+ super
94
+ end
95
+
96
+ # Purchase the item straight away
97
+ #
98
+ # Parameters:
99
+ # -money: Amount to be charged as an Integer value in cents
100
+ # -authorization: the PSL cross reference from the previous authorization
101
+ # -options:
102
+ #
103
+ # Returns:
104
+ # -ActiveRecord::Billing::Response object
105
+ #
106
+ def purchase(money, credit_card, options = {})
107
+ post = {}
108
+
109
+ add_amount(post, money, DISPATCH_NOW, options)
110
+ add_credit_card(post, credit_card)
111
+ add_address(post, options)
112
+ add_invoice(post, options)
113
+ add_purchase_details(post)
114
+
115
+ commit(post)
116
+ end
117
+
118
+ # Authorize the transaction
119
+ #
120
+ # Reserves the funds on the customer's credit card, but does not
121
+ # charge the card.
122
+ #
123
+ # This implementation does not authorize the full amount, rather it checks that the full amount
124
+ # is available and only 'reserves' the nominal amount (currently a pound and a penny)
125
+ #
126
+ # Parameters:
127
+ # -money: Amount to be charged as an Integer value in cents
128
+ # -authorization: the PSL cross reference from the previous authorization
129
+ # -options:
130
+ #
131
+ # Returns:
132
+ # -ActiveRecord::Billing::Response object
133
+ #
134
+ def authorize(money, credit_card, options = {})
135
+ post = {}
136
+
137
+ add_amount(post, money, DISPATCH_LATER, options)
138
+ add_credit_card(post, credit_card)
139
+ add_address(post, options)
140
+ add_invoice(post, options)
141
+ add_purchase_details(post)
142
+
143
+ commit(post)
144
+ end
145
+
146
+ # Post an authorization.
147
+ #
148
+ # Captures the funds from an authorized transaction.
149
+ #
150
+ # Parameters:
151
+ # -money: Amount to be charged as an Integer value in cents
152
+ # -authorization: The PSL Cross Reference
153
+ # -options:
154
+ #
155
+ # Returns:
156
+ # -ActiveRecord::Billing::Response object
157
+ #
158
+ def capture(money, authorization, options = {})
159
+ post = {}
160
+
161
+ add_amount(post, money, DISPATCH_NOW, options)
162
+ add_reference(post, authorization)
163
+ add_purchase_details(post)
164
+
165
+ commit(post)
166
+ end
167
+
168
+ private
169
+
170
+ def add_credit_card(post, credit_card)
171
+ post[:QAName] = credit_card.name
172
+ post[:CardNumber] = credit_card.number
173
+ post[:EMVTerminalType] = EMV_TERMINAL_TYPE
174
+ post[:ExpMonth] = credit_card.month
175
+ post[:ExpYear] = credit_card.year
176
+
177
+ if requires_start_date_or_issue_number?(credit_card)
178
+ post[:IssueNumber] = credit_card.issue_number unless credit_card.issue_number.blank?
179
+ post[:StartMonth] = credit_card.start_month unless credit_card.start_month.blank?
180
+ post[:StartYear] = credit_card.start_year unless credit_card.start_year.blank?
181
+ end
182
+
183
+ # CV2 check
184
+ post[:AVSCV2Check] = credit_card.verification_value? ? 'YES' : 'NO'
185
+ post[:CV2] = credit_card.verification_value if credit_card.verification_value?
186
+ end
187
+
188
+ def add_address(post, options)
189
+ address = options[:billing_address] || options[:address]
190
+ return if address.nil?
191
+
192
+ post[:QAAddress] = [:address1, :address2, :city, :state].collect{|a| address[a]}.reject{|a| a.blank?}.join(' ')
193
+ post[:QAPostcode] = address[:zip]
194
+ end
195
+
196
+ def add_invoice(post, options)
197
+ post[:MerchantName] = options[:merchant] || 'Merchant Name' # May use this as the order_id field
198
+ post[:OrderID] = options[:order_id] unless options[:order_id].blank?
199
+ end
200
+
201
+ def add_reference(post, authorization)
202
+ post[:CrossReference] = authorization
203
+ end
204
+
205
+ def add_amount(post, money, dispatch_type, options)
206
+ post[:CurrencyCode] = currency_code(options[:currency] || currency(money))
207
+
208
+ if dispatch_type == DISPATCH_LATER
209
+ post[:amount] = amount(NOMINAL_AMOUNT)
210
+ post[:DispatchLaterAmount] = amount(money)
211
+ else
212
+ post[:amount] = amount(money)
213
+ end
214
+
215
+ post[:Dispatch] = dispatch_type
216
+ end
217
+
218
+ def add_purchase_details(post)
219
+ post[:EchoAmount] = 'YES'
220
+ post[:SCBI] = 'YES' # Return information about the transaction
221
+ post[:MessageType] = MESSAGE_TYPE
222
+ end
223
+
224
+ # Get the currency code for the passed money object
225
+ #
226
+ # The money class stores the currency as an ISO 4217:2001 Alphanumeric,
227
+ # however PSL requires the ISO 4217:2001 Numeric code.
228
+ #
229
+ # Parameters:
230
+ # -money: Integer value in cents
231
+ #
232
+ # Returns:
233
+ # -the ISO 4217:2001 Numberic currency code
234
+ #
235
+ def currency_code(currency)
236
+ CURRENCY_CODES[currency]
237
+ end
238
+
239
+ # Parse the PSL response and create a Response object
240
+ #
241
+ # Parameters:
242
+ # -body: The response string returned from PSL, Formatted:
243
+ # Key=value&key=value...
244
+ #
245
+ # Returns:
246
+ # -a hash with all of the values returned in the PSL response
247
+ #
248
+ def parse(body)
249
+
250
+ fields = {}
251
+ for line in body.split('&')
252
+ key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
253
+ fields[key] = CGI.unescape(value)
254
+ end
255
+ fields.symbolize_keys
256
+ end
257
+
258
+ # Send the passed data to PSL for processing
259
+ #
260
+ # Parameters:
261
+ # -request: The data that is to be sent to PSL
262
+ #
263
+ # Returns:
264
+ # - ActiveMerchant::Billing::Response object
265
+ #
266
+ def commit(request)
267
+ response = parse( ssl_post(self.live_url, post_data(request)) )
268
+
269
+ Response.new(response[:ResponseCode] == APPROVED, response[:Message], response,
270
+ :test => test?,
271
+ :authorization => response[:CrossReference],
272
+ :cvv_result => CVV_CODE[response[:AVSCV2Check]],
273
+ :avs_result => { :code => AVS_CODE[response[:AVSCV2Check]] }
274
+ )
275
+ end
276
+
277
+ # Put the passed data into a format that can be submitted to PSL
278
+ # Key=Value&Key=Value...
279
+ #
280
+ # Any ampersands and equal signs are removed from the data being posted
281
+ # as PSL puts them back into the response string which then cannot be parsed.
282
+ # This is after escaping before sending the request to PSL - this is a work
283
+ # around for the time being
284
+ #
285
+ # Parameters:
286
+ # -post: Hash of all the data to be sent
287
+ #
288
+ # Returns:
289
+ # -String: the data to be sent
290
+ #
291
+ def post_data(post)
292
+ post[:CountryCode] = self.location
293
+ post[:MerchantID] = @options[:login]
294
+ post[:ValidityID] = @options[:password]
295
+ post[:ResponseAction] = RESPONSE_ACTION
296
+
297
+ post.collect { |key, value|
298
+ "#{key}=#{CGI.escape(value.to_s.tr('&=', ' '))}"
299
+ }.join("&")
300
+ end
301
+ end
302
+ end
303
+ end