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,218 @@
1
+ require 'rexml/document'
2
+ require 'digest/md5'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ class QuickpayGateway < Gateway
7
+ URL = 'https://secure.quickpay.dk/api'
8
+
9
+ self.default_currency = 'DKK'
10
+ self.money_format = :cents
11
+ self.supported_cardtypes = [ :dankort, :forbrugsforeningen, :visa, :master, :american_express, :diners_club, :jcb, :maestro ]
12
+ self.supported_countries = ['DK', 'SE']
13
+ self.homepage_url = 'http://quickpay.dk/'
14
+ self.display_name = 'Quickpay'
15
+
16
+ PROTOCOL = 3
17
+
18
+ MD5_CHECK_FIELDS = {
19
+ :authorize => [:protocol, :msgtype, :merchant, :ordernumber, :amount, :currency, :autocapture, :cardnumber, :expirationdate, :cvd, :cardtypelock],
20
+ :capture => [:protocol, :msgtype, :merchant, :amount, :transaction],
21
+ :cancel => [:protocol, :msgtype, :merchant, :transaction],
22
+ :refund => [:protocol, :msgtype, :merchant, :amount, :transaction],
23
+ :subscribe => [:protocol, :msgtype, :merchant, :ordernumber, :cardnumber, :expirationdate, :cvd, :cardtypelock, :description],
24
+ :recurring => [:protocol, :msgtype, :merchant, :ordernumber, :amount, :currency, :autocapture, :transaction],
25
+ :status => [:protocol, :msgtype, :merchant, :transaction],
26
+ :chstatus => [:protocol, :msgtype, :merchant],
27
+ }
28
+
29
+ APPROVED = '000'
30
+
31
+ # The login is the QuickpayId
32
+ # The password is the md5checkword from the Quickpay admin interface
33
+ def initialize(options = {})
34
+ requires!(options, :login, :password)
35
+ @options = options
36
+ super
37
+ end
38
+
39
+ def authorize(money, credit_card_or_reference, options = {})
40
+ post = {}
41
+
42
+ add_amount(post, money, options)
43
+ add_invoice(post, options)
44
+ add_creditcard_or_reference(post, credit_card_or_reference, options)
45
+ add_autocapture(post, false)
46
+
47
+ commit(recurring_or_authorize(credit_card_or_reference), post)
48
+ end
49
+
50
+ def purchase(money, credit_card_or_reference, options = {})
51
+ post = {}
52
+
53
+ add_amount(post, money, options)
54
+ add_creditcard_or_reference(post, credit_card_or_reference, options)
55
+ add_invoice(post, options)
56
+ add_autocapture(post, true)
57
+
58
+ commit(recurring_or_authorize(credit_card_or_reference), post)
59
+ end
60
+
61
+ def capture(money, authorization, options = {})
62
+ post = {}
63
+
64
+ add_reference(post, authorization)
65
+ add_amount_without_currency(post, money)
66
+
67
+ commit(:capture, post)
68
+ end
69
+
70
+ def void(identification, options = {})
71
+ post = {}
72
+
73
+ add_reference(post, identification)
74
+
75
+ commit(:cancel, post)
76
+ end
77
+
78
+ def refund(money, identification, options = {})
79
+ post = {}
80
+
81
+ add_amount_without_currency(post, money)
82
+ add_reference(post, identification)
83
+
84
+ commit(:refund, post)
85
+ end
86
+
87
+ def credit(money, identification, options = {})
88
+ deprecated CREDIT_DEPRECATION_MESSAGE
89
+ refund(money, identification, options)
90
+ end
91
+
92
+ def store(creditcard, options = {})
93
+ post = {}
94
+
95
+ add_creditcard(post, creditcard, options)
96
+ add_invoice(post, options)
97
+ add_description(post, options)
98
+
99
+ commit(:subscribe, post)
100
+ end
101
+
102
+ private
103
+
104
+ def add_amount(post, money, options = {})
105
+ post[:amount] = amount(money)
106
+ post[:currency] = options[:currency] || currency(money)
107
+ end
108
+
109
+ def add_amount_without_currency(post, money, options = {})
110
+ post[:amount] = amount(money)
111
+ end
112
+
113
+ def add_invoice(post, options)
114
+ post[:ordernumber] = format_order_number(options[:order_id])
115
+ end
116
+
117
+ def add_creditcard(post, credit_card, options)
118
+ post[:cardnumber] = credit_card.number
119
+ post[:cvd] = credit_card.verification_value
120
+ post[:expirationdate] = expdate(credit_card)
121
+ post[:cardtypelock] = options[:cardtypelock] unless options[:cardtypelock].blank?
122
+ end
123
+
124
+ def add_reference(post, identification)
125
+ post[:transaction] = identification
126
+ end
127
+
128
+ def add_creditcard_or_reference(post, credit_card_or_reference, options)
129
+ if credit_card_or_reference.is_a?(String)
130
+ add_reference(post, credit_card_or_reference)
131
+ else
132
+ add_creditcard(post, credit_card_or_reference, options)
133
+ end
134
+ end
135
+
136
+ def add_autocapture(post, autocapture)
137
+ post[:autocapture] = autocapture ? 1 : 0
138
+ end
139
+
140
+ def recurring_or_authorize(credit_card_or_reference)
141
+ credit_card_or_reference.is_a?(String) ? :recurring : :authorize
142
+ end
143
+
144
+ def add_description(post, options)
145
+ post[:description] = options[:description]
146
+ end
147
+
148
+ def commit(action, params)
149
+ response = parse(ssl_post(URL, post_data(action, params)))
150
+
151
+ Response.new(successful?(response), message_from(response), response,
152
+ :test => test?,
153
+ :authorization => response[:transaction]
154
+ )
155
+ end
156
+
157
+ def successful?(response)
158
+ response[:qpstat] == APPROVED
159
+ end
160
+
161
+ def parse(data)
162
+ response = {}
163
+
164
+ doc = REXML::Document.new(data)
165
+
166
+ doc.root.elements.each do |element|
167
+ response[element.name.to_sym] = element.text
168
+ end
169
+
170
+ response
171
+ end
172
+
173
+ def message_from(response)
174
+ case response[:qpstat]
175
+ when '008' # Error in request data
176
+ response[:qpstatmsg].to_s
177
+ #.scan(/[A-Z][a-z0-9 \/]+/).to_sentence
178
+ else
179
+ response[:qpstatmsg].to_s
180
+ end
181
+ end
182
+
183
+ def post_data(action, params = {})
184
+ params[:protocol] = PROTOCOL
185
+ params[:msgtype] = action.to_s
186
+ params[:merchant] = @options[:login]
187
+ #params[:testmode] = '1' if test?
188
+ params[:md5check] = generate_check_hash(action, params)
189
+
190
+ params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
191
+ end
192
+
193
+ def generate_check_hash(action, params)
194
+ string = MD5_CHECK_FIELDS[action].collect do |key|
195
+ params[key]
196
+ end.join('')
197
+
198
+ # Add the md5checkword
199
+ string << @options[:password].to_s
200
+
201
+ Digest::MD5.hexdigest(string)
202
+ end
203
+
204
+ def expdate(credit_card)
205
+ year = format(credit_card.year, :two_digits)
206
+ month = format(credit_card.month, :two_digits)
207
+
208
+ "#{year}#{month}"
209
+ end
210
+
211
+ # Limited to 20 digits max
212
+ def format_order_number(number)
213
+ number.to_s.gsub(/[^\w_]/, '').rjust(4, "0")[0...20]
214
+ end
215
+ end
216
+ end
217
+ end
218
+
@@ -0,0 +1,311 @@
1
+ require 'rexml/document'
2
+ require 'digest/sha1'
3
+
4
+ module ActiveMerchant
5
+ module Billing
6
+ # Realex is the leading CC gateway in Ireland
7
+ # see http://www.realexpayments.com
8
+ # Contributed by John Ward (john@ward.name)
9
+ # see http://thinedgeofthewedge.blogspot.com
10
+ #
11
+ # Realex works using the following
12
+ # login - The unique id of the merchant
13
+ # password - The secret is used to digitally sign the request
14
+ # account - This is an optional third part of the authentication process
15
+ # and is used if the merchant wishes do distuinguish cc traffic from the different sources
16
+ # by using a different account. This must be created in advance
17
+ #
18
+ # the Realex team decided to make the orderid unique per request,
19
+ # so if validation fails you can not correct and resend using the
20
+ # same order id
21
+ class RealexGateway < Gateway
22
+ URL = 'https://epage.payandshop.com/epage-remote.cgi'
23
+
24
+ CARD_MAPPING = {
25
+ 'master' => 'MC',
26
+ 'visa' => 'VISA',
27
+ 'american_express' => 'AMEX',
28
+ 'diners_club' => 'DINERS',
29
+ 'switch' => 'SWITCH',
30
+ 'solo' => 'SWITCH',
31
+ 'laser' => 'LASER'
32
+ }
33
+
34
+ self.money_format = :cents
35
+ self.default_currency = 'EUR'
36
+ self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :switch, :solo, :laser ]
37
+ self.supported_countries = [ 'IE', 'GB' ]
38
+ self.homepage_url = 'http://www.realexpayments.com/'
39
+ self.display_name = 'Realex'
40
+
41
+ SUCCESS, DECLINED = "Successful", "Declined"
42
+ BANK_ERROR = REALEX_ERROR = "Gateway is in maintenance. Please try again later."
43
+ ERROR = CLIENT_DEACTIVATED = "Gateway Error"
44
+
45
+ def initialize(options = {})
46
+ requires!(options, :login, :password)
47
+ options[:refund_hash] = Digest::SHA1.hexdigest(options[:rebate_secret]) if options.has_key?(:rebate_secret)
48
+ @options = options
49
+ super
50
+ end
51
+
52
+ def purchase(money, credit_card, options = {})
53
+ requires!(options, :order_id)
54
+
55
+ request = build_purchase_or_authorization_request(:purchase, money, credit_card, options)
56
+ commit(request)
57
+ end
58
+
59
+ def authorize(money, creditcard, options = {})
60
+ requires!(options, :order_id)
61
+
62
+ request = build_purchase_or_authorization_request(:authorization, money, creditcard, options)
63
+ commit(request)
64
+ end
65
+
66
+ def capture(money, authorization, options = {})
67
+ request = build_capture_request(authorization, options)
68
+ commit(request)
69
+ end
70
+
71
+ def refund(money, authorization, options = {})
72
+ request = build_refund_request(money, authorization, options)
73
+ commit(request)
74
+ end
75
+
76
+ def credit(money, authorization, options = {})
77
+ deprecated CREDIT_DEPRECATION_MESSAGE
78
+ refund(money, authorization, options)
79
+ end
80
+
81
+ def void(authorization, options = {})
82
+ request = build_void_request(authorization, options)
83
+ commit(request)
84
+ end
85
+
86
+ private
87
+ def commit(request)
88
+ response = parse(ssl_post(URL, request))
89
+
90
+ Response.new(response[:result] == "00", message_from(response), response,
91
+ :test => response[:message] =~ /\[ test system \]/,
92
+ :authorization => authorization_from(response),
93
+ :cvv_result => response[:cvnresult],
94
+ :avs_result => {
95
+ :street_match => response[:avspostcoderesponse],
96
+ :postal_match => response[:avspostcoderesponse]
97
+ }
98
+ )
99
+ end
100
+
101
+ def parse(xml)
102
+ response = {}
103
+
104
+ xml = REXML::Document.new(xml)
105
+ xml.elements.each('//response/*') do |node|
106
+
107
+ if (node.elements.size == 0)
108
+ response[node.name.downcase.to_sym] = normalize(node.text)
109
+ else
110
+ node.elements.each do |childnode|
111
+ name = "#{node.name.downcase}_#{childnode.name.downcase}"
112
+ response[name.to_sym] = normalize(childnode.text)
113
+ end
114
+ end
115
+
116
+ end unless xml.root.nil?
117
+
118
+ response
119
+ end
120
+
121
+ def authorization_from(parsed)
122
+ [parsed[:orderid], parsed[:pasref], parsed[:authcode]].join(';')
123
+ end
124
+
125
+ def build_purchase_or_authorization_request(action, money, credit_card, options)
126
+ timestamp = new_timestamp
127
+ xml = Builder::XmlMarkup.new :indent => 2
128
+ xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'auth' do
129
+ add_merchant_details(xml, options)
130
+ xml.tag! 'orderid', sanitize_order_id(options[:order_id])
131
+ add_amount(xml, money, options)
132
+ add_card(xml, credit_card)
133
+ xml.tag! 'autosettle', 'flag' => auto_settle_flag(action)
134
+ add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), amount(money), (options[:currency] || currency(money)), credit_card.number)
135
+ add_comments(xml, options)
136
+ add_address_and_customer_info(xml, options)
137
+ end
138
+ xml.target!
139
+ end
140
+
141
+ def build_capture_request(authorization, options)
142
+ timestamp = new_timestamp
143
+ xml = Builder::XmlMarkup.new :indent => 2
144
+ xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'settle' do
145
+ add_merchant_details(xml, options)
146
+ add_transaction_identifiers(xml, authorization, options)
147
+ add_comments(xml, options)
148
+ add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), nil, nil, nil)
149
+ end
150
+ xml.target!
151
+ end
152
+
153
+ def build_refund_request(money, authorization, options)
154
+ timestamp = new_timestamp
155
+ xml = Builder::XmlMarkup.new :indent => 2
156
+ xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'rebate' do
157
+ add_merchant_details(xml, options)
158
+ add_transaction_identifiers(xml, authorization, options)
159
+ xml.tag! 'amount', amount(money), 'currency' => options[:currency] || currency(money)
160
+ xml.tag! 'refundhash', @options[:refund_hash] if @options[:refund_hash]
161
+ xml.tag! 'autosettle', 'flag' => 1
162
+ add_comments(xml, options)
163
+ add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), amount(money), (options[:currency] || currency(money)), nil)
164
+ end
165
+ xml.target!
166
+ end
167
+
168
+ def build_void_request(authorization, options)
169
+ timestamp = new_timestamp
170
+ xml = Builder::XmlMarkup.new :indent => 2
171
+ xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'void' do
172
+ add_merchant_details(xml, options)
173
+ add_transaction_identifiers(xml, authorization, options)
174
+ add_comments(xml, options)
175
+ add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), nil, nil, nil)
176
+ end
177
+ xml.target!
178
+ end
179
+
180
+ def add_address_and_customer_info(xml, options)
181
+ billing_address = options[:billing_address] || options[:address]
182
+ shipping_address = options[:shipping_address]
183
+
184
+ return unless billing_address || shipping_address || options[:customer] || options[:invoice] || options[:ip]
185
+
186
+ xml.tag! 'tssinfo' do
187
+ xml.tag! 'custnum', options[:customer] if options[:customer]
188
+ xml.tag! 'prodid', options[:invoice] if options[:invoice]
189
+ xml.tag! 'custipaddress', options[:ip] if options[:ip]
190
+
191
+ if billing_address
192
+ xml.tag! 'address', 'type' => 'billing' do
193
+ xml.tag! 'code', avs_input_code( billing_address )
194
+ xml.tag! 'country', billing_address[:country]
195
+ end
196
+ end
197
+
198
+ if shipping_address
199
+ xml.tag! 'address', 'type' => 'shipping' do
200
+ xml.tag! 'code', shipping_address[:zip]
201
+ xml.tag! 'country', shipping_address[:country]
202
+ end
203
+ end
204
+ end
205
+ end
206
+
207
+ def add_merchant_details(xml, options)
208
+ xml.tag! 'merchantid', @options[:login]
209
+ if options[:account] || @options[:account]
210
+ xml.tag! 'account', (options[:account] || @options[:account])
211
+ end
212
+ end
213
+
214
+ def add_transaction_identifiers(xml, authorization, options)
215
+ options[:order_id], pasref, authcode = authorization.split(';')
216
+ xml.tag! 'orderid', sanitize_order_id(options[:order_id])
217
+ xml.tag! 'pasref', pasref
218
+ xml.tag! 'authcode', authcode
219
+ end
220
+
221
+ def add_comments(xml, options)
222
+ return unless options[:description]
223
+ xml.tag! 'comments' do
224
+ xml.tag! 'comment', options[:description], 'id' => 1
225
+ end
226
+ end
227
+
228
+ def add_amount(xml, money, options)
229
+ xml.tag! 'amount', amount(money), 'currency' => options[:currency] || currency(money)
230
+ end
231
+
232
+ def add_card(xml, credit_card)
233
+ xml.tag! 'card' do
234
+ xml.tag! 'number', credit_card.number
235
+ xml.tag! 'expdate', expiry_date(credit_card)
236
+ xml.tag! 'chname', credit_card.name
237
+ xml.tag! 'type', CARD_MAPPING[card_brand(credit_card).to_s]
238
+ xml.tag! 'issueno', credit_card.issue_number
239
+ xml.tag! 'cvn' do
240
+ xml.tag! 'number', credit_card.verification_value
241
+ xml.tag! 'presind', (options['presind'] || (credit_card.verification_value? ? 1 : nil))
242
+ end
243
+ end
244
+ end
245
+
246
+ def avs_input_code(address)
247
+ address.values_at(:zip, :address1).map{ |v| extract_digits(v) }.join('|')
248
+ end
249
+
250
+ def extract_digits(string)
251
+ return "" if string.nil?
252
+ string.gsub(/[\D]/,'')
253
+ end
254
+
255
+ def new_timestamp
256
+ Time.now.strftime('%Y%m%d%H%M%S')
257
+ end
258
+
259
+ def add_signed_digest(xml, *values)
260
+ string = Digest::SHA1.hexdigest(values.join("."))
261
+ xml.tag! 'sha1hash', Digest::SHA1.hexdigest([string, @options[:password]].join("."))
262
+ end
263
+
264
+ def auto_settle_flag(action)
265
+ action == :authorization ? '0' : '1'
266
+ end
267
+
268
+ def expiry_date(credit_card)
269
+ "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
270
+ end
271
+
272
+ def normalize(field)
273
+ case field
274
+ when "true" then true
275
+ when "false" then false
276
+ when "" then nil
277
+ when "null" then nil
278
+ else field
279
+ end
280
+ end
281
+
282
+ def message_from(response)
283
+ message = nil
284
+ case response[:result]
285
+ when "00"
286
+ message = SUCCESS
287
+ when "101"
288
+ message = response[:message]
289
+ when "102", "103"
290
+ message = DECLINED
291
+ when /^2[0-9][0-9]/
292
+ message = BANK_ERROR
293
+ when /^3[0-9][0-9]/
294
+ message = REALEX_ERROR
295
+ when /^5[0-9][0-9]/
296
+ message = response[:message]
297
+ when "600", "601", "603"
298
+ message = ERROR
299
+ when "666"
300
+ message = CLIENT_DEACTIVATED
301
+ else
302
+ message = DECLINED
303
+ end
304
+ end
305
+
306
+ def sanitize_order_id(order_id)
307
+ order_id.to_s.gsub(/[^a-zA-Z0-9\-_]/, '')
308
+ end
309
+ end
310
+ end
311
+ end