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,262 @@
1
+ if RUBY_VERSION < '1.9' && $KCODE == "NONE"
2
+ $KCODE = 'u'
3
+ end
4
+
5
+ module ActiveMerchant #:nodoc:
6
+ module Billing #:nodoc:
7
+ class GarantiGateway < Gateway
8
+ URL = 'https://sanalposprov.garanti.com.tr/VPServlet'
9
+
10
+ # The countries the gateway supports merchants from as 2 digit ISO country codes
11
+ self.supported_countries = ['US','TR']
12
+
13
+ # The card types supported by the payment gateway
14
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
15
+
16
+ # The homepage URL of the gateway
17
+ self.homepage_url = 'https://sanalposweb.garanti.com.tr'
18
+
19
+ # The name of the gateway
20
+ self.display_name = 'Garanti Sanal POS'
21
+
22
+ self.default_currency = 'TRL'
23
+
24
+ self.money_format = :cents
25
+
26
+ CURRENCY_CODES = {
27
+ 'YTL' => 949,
28
+ 'TRL' => 949,
29
+ 'TL' => 949,
30
+ 'USD' => 840,
31
+ 'EUR' => 978,
32
+ 'GBP' => 826,
33
+ 'JPY' => 392
34
+ }
35
+
36
+
37
+ def initialize(options = {})
38
+ requires!(options, :login, :password, :terminal_id, :merchant_id)
39
+ @options = options
40
+ super
41
+ end
42
+
43
+ def purchase(money, credit_card, options = {})
44
+ options = options.merge(:gvp_order_type => "sales")
45
+ commit(money, build_sale_request(money, credit_card, options))
46
+ end
47
+
48
+ def authorize(money, credit_card, options = {})
49
+ options = options.merge(:gvp_order_type => "preauth")
50
+ commit(money, build_authorize_request(money, credit_card, options))
51
+ end
52
+
53
+ def capture(money, ref_id, options = {})
54
+ options = options.merge(:gvp_order_type => "postauth")
55
+ commit(money, build_capture_request(money, ref_id, options))
56
+ end
57
+
58
+ private
59
+
60
+ def security_data
61
+ rjusted_terminal_id = @options[:terminal_id].to_s.rjust(9, "0")
62
+ Digest::SHA1.hexdigest(@options[:password].to_s + rjusted_terminal_id).upcase
63
+ end
64
+
65
+ def generate_hash_data(order_id, terminal_id, credit_card_number, amount, security_data)
66
+ data = [order_id, terminal_id, credit_card_number, amount, security_data].join
67
+ Digest::SHA1.hexdigest(data).upcase
68
+ end
69
+
70
+ def build_xml_request(money, credit_card, options, &block)
71
+ card_number = credit_card.respond_to?(:number) ? credit_card.number : ''
72
+ hash_data = generate_hash_data(format_order_id(options[:order_id]), @options[:terminal_id], card_number, amount(money), security_data)
73
+
74
+ xml = Builder::XmlMarkup.new(:indent => 2)
75
+ xml.instruct! :xml, :version => "1.0", :encoding => "UTF-8"
76
+
77
+ xml.tag! 'GVPSRequest' do
78
+ xml.tag! 'Mode', test? ? 'TEST' : 'PROD'
79
+ xml.tag! 'Version', 'V0.01'
80
+ xml.tag! 'Terminal' do
81
+ xml.tag! 'ProvUserID', 'PROVAUT'
82
+ xml.tag! 'HashData', hash_data
83
+ xml.tag! 'UserID', @options[:login]
84
+ xml.tag! 'ID', @options[:terminal_id]
85
+ xml.tag! 'MerchantID', @options[:merchant_id]
86
+ end
87
+
88
+ if block_given?
89
+ yield xml
90
+ else
91
+ xml.target!
92
+ end
93
+ end
94
+ end
95
+
96
+ def build_sale_request(money, credit_card, options)
97
+ build_xml_request(money, credit_card, options) do |xml|
98
+ add_customer_data(xml, options)
99
+ add_order_data(xml, options) do |xml|
100
+ add_addresses(xml, options)
101
+ end
102
+ add_credit_card(xml, credit_card)
103
+ add_transaction_data(xml, money, options)
104
+
105
+ xml.target!
106
+ end
107
+ end
108
+
109
+ def build_authorize_request(money, credit_card, options)
110
+ build_xml_request(money, credit_card, options) do |xml|
111
+ add_customer_data(xml, options)
112
+ add_order_data(xml, options) do |xml|
113
+ add_addresses(xml, options)
114
+ end
115
+ add_credit_card(xml, credit_card)
116
+ add_transaction_data(xml, money, options)
117
+
118
+ xml.target!
119
+ end
120
+ end
121
+
122
+ def build_capture_request(money, ref_id, options)
123
+ options = options.merge(:order_id => ref_id)
124
+ build_xml_request(money, ref_id, options) do |xml|
125
+ add_customer_data(xml, options)
126
+ add_order_data(xml, options)
127
+ add_transaction_data(xml, money, options)
128
+
129
+ xml.target!
130
+ end
131
+ end
132
+
133
+ def add_customer_data(xml, options)
134
+ xml.tag! 'Customer' do
135
+ xml.tag! 'IPAddress', options[:ip] || '1.1.1.1'
136
+ xml.tag! 'EmailAddress', options[:email]
137
+ end
138
+ end
139
+
140
+ def add_order_data(xml, options, &block)
141
+ xml.tag! 'Order' do
142
+ xml.tag! 'OrderID', format_order_id(options[:order_id])
143
+ xml.tag! 'GroupID'
144
+
145
+ if block_given?
146
+ yield xml
147
+ end
148
+ end
149
+ end
150
+
151
+ def add_credit_card(xml, credit_card)
152
+ xml.tag! 'Card' do
153
+ xml.tag! 'Number', credit_card.number
154
+ xml.tag! 'ExpireDate', [format_exp(credit_card.month), format_exp(credit_card.year)].join
155
+ xml.tag! 'CVV2', credit_card.verification_value
156
+ end
157
+ end
158
+
159
+ def format_exp(value)
160
+ format(value, :two_digits)
161
+ end
162
+
163
+ # OrderId field must be A-Za-z0-9_ format and max 36 char
164
+ def format_order_id(order_id)
165
+ order_id.to_s.gsub(/[^A-Za-z0-9_]/, '')[0...36]
166
+ end
167
+
168
+ def add_addresses(xml, options)
169
+ xml.tag! 'AddressList' do
170
+ if billing_address = options[:billing_address] || options[:address]
171
+ xml.tag! 'Address' do
172
+ xml.tag! 'Type', 'B'
173
+ add_address(xml, billing_address)
174
+ end
175
+ end
176
+
177
+ if options[:shipping_address]
178
+ xml.tag! 'Address' do
179
+ xml.tag! 'Type', 'S'
180
+ add_address(xml, options[:shipping_address])
181
+ end
182
+ end
183
+ end
184
+ end
185
+
186
+ def add_address(xml, address)
187
+ xml.tag! 'Name', normalize(address[:name])
188
+ address_text = address[:address1]
189
+ address_text << " #{ address[:address2]}" if address[:address2]
190
+ xml.tag! 'Text', normalize(address_text)
191
+ xml.tag! 'City', normalize(address[:city])
192
+ xml.tag! 'District', normalize(address[:state])
193
+ xml.tag! 'PostalCode', address[:zip]
194
+ xml.tag! 'Country', normalize(address[:country])
195
+ xml.tag! 'Company', normalize(address[:company])
196
+ xml.tag! 'PhoneNumber', address[:phone].to_s.gsub(/[^0-9]/, '') if address[:phone]
197
+ end
198
+
199
+ def normalize(text)
200
+ return unless text
201
+
202
+ if ActiveSupport::Inflector.method(:transliterate).arity == -2
203
+ ActiveSupport::Inflector.transliterate(text,'')
204
+ elsif RUBY_VERSION >= '1.9'
205
+ text.gsub(/[^\x00-\x7F]+/, '')
206
+ else
207
+ ActiveSupport::Inflector.transliterate(text).to_s
208
+ end
209
+ end
210
+
211
+ def add_transaction_data(xml, money, options)
212
+ xml.tag! 'Transaction' do
213
+ xml.tag! 'Type', options[:gvp_order_type]
214
+ xml.tag! 'Amount', amount(money)
215
+ xml.tag! 'CurrencyCode', currency_code(options[:currency] || currency(money))
216
+ xml.tag! 'CardholderPresentCode', 0
217
+ end
218
+ end
219
+
220
+ def currency_code(currency)
221
+ CURRENCY_CODES[currency] || CURRENCY_CODES[default_currency]
222
+ end
223
+
224
+ def commit(money,request)
225
+ raw_response = ssl_post(URL, "data=" + request)
226
+ response = parse(raw_response)
227
+
228
+ success = success?(response)
229
+
230
+ Response.new(success,
231
+ success ? 'Approved' : "Declined (Reason: #{response[:reason_code]} - #{response[:error_msg]} - #{response[:sys_err_msg]})",
232
+ response,
233
+ :test => test?,
234
+ :authorization => response[:order_id])
235
+ end
236
+
237
+ def parse(body)
238
+ xml = REXML::Document.new(body)
239
+
240
+ response = {}
241
+ xml.root.elements.to_a.each do |node|
242
+ parse_element(response, node)
243
+ end
244
+ response
245
+ end
246
+
247
+ def parse_element(response, node)
248
+ if node.has_elements?
249
+ node.elements.each{|element| parse_element(response, element) }
250
+ else
251
+ response[node.name.underscore.to_sym] = node.text
252
+ end
253
+ end
254
+
255
+ def success?(response)
256
+ response[:message] == "Approved"
257
+ end
258
+
259
+ end
260
+ end
261
+ end
262
+
@@ -0,0 +1,250 @@
1
+ require File.dirname(__FILE__) + '/ideal_response'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ # Implementation contains some simplifications
6
+ # - does not support multiple subID per merchant
7
+ # - language is fixed to 'nl'
8
+ class IdealBaseGateway < Gateway
9
+ class_attribute :test_url, :live_url, :server_pem, :pem_password, :default_expiration_period
10
+ self.default_expiration_period = 'PT10M'
11
+ self.default_currency = 'EUR'
12
+ self.pem_password = true
13
+
14
+ # These constants will never change for most users
15
+ AUTHENTICATION_TYPE = 'SHA1_RSA'
16
+ LANGUAGE = 'nl'
17
+ SUB_ID = '0'
18
+ API_VERSION = '1.1.0'
19
+
20
+ attr_reader :url
21
+
22
+ def initialize(options = {})
23
+ requires!(options, :login, :password, :pem)
24
+ @options = options
25
+
26
+ @options[:pem_password] = options[:password]
27
+ @url = test? ? test_url : live_url
28
+ super
29
+ end
30
+
31
+ # Setup transaction. Get redirect_url from response.service_url
32
+ def setup_purchase(money, options = {})
33
+ requires!(options, :issuer_id, :return_url, :order_id, :currency, :description, :entrance_code)
34
+
35
+ commit(build_transaction_request(money, options))
36
+ end
37
+
38
+ # Check status of transaction and confirm payment
39
+ # transaction_id must be a valid transaction_id from a prior setup.
40
+ def capture(transaction, options = {})
41
+ options[:transaction_id] = transaction
42
+ commit(build_status_request(options))
43
+ end
44
+
45
+ # Get list of issuers from response.issuer_list
46
+ def issuers
47
+ commit(build_directory_request)
48
+ end
49
+
50
+ def test?
51
+ @options[:test] || Base.gateway_mode == :test
52
+ end
53
+
54
+ private
55
+ def token
56
+ if @token.nil?
57
+ @token = create_fingerprint(@options[:pem])
58
+ end
59
+ @token
60
+ end
61
+
62
+ # <?xml version="1.0" encoding="UTF-8"?>
63
+ # <AcquirerTrxReq xmlns="http://www.idealdesk.com/Message" version="1.1.0">
64
+ # <createDateTimeStamp>2001-12-17T09:30:47.0Z</createDateTimeStamp>
65
+ # <Issuer>
66
+ # <issuerID>1003</issuerID>
67
+ # </Issuer>
68
+ # <Merchant>
69
+ # <merchantID>000123456</merchantID>
70
+ # <subID>0</subID>
71
+ # <authentication>passkey</authentication>
72
+ # <token>1</token>
73
+ # <tokenCode>3823ad872eff23</tokenCode>
74
+ # <merchantReturnURL>https://www.mijnwinkel.nl/betaalafhandeling
75
+ # </merchantReturnURL>
76
+ # </Merchant>
77
+ # <Transaction>
78
+ # <purchaseID>iDEAL-aankoop 21</purchaseID>
79
+ # <amount>5999</amount>
80
+ # <currency>EUR</currency>
81
+ # <expirationPeriod>PT3M30S</expirationPeriod>
82
+ # <language>nl</language>
83
+ # <description>Documentensuite</description>
84
+ # <entranceCode>D67tyx6rw9IhY71</entranceCode>
85
+ # </Transaction>
86
+ # </AcquirerTrxReq>
87
+ def build_transaction_request(money, options)
88
+ date_time_stamp = create_time_stamp
89
+ message = date_time_stamp +
90
+ options[:issuer_id] +
91
+ @options[:login] +
92
+ SUB_ID +
93
+ options[:return_url] +
94
+ options[:order_id] +
95
+ money.to_s +
96
+ (options[:currency] || currency(money)) +
97
+ LANGUAGE +
98
+ options[:description] +
99
+ options[:entrance_code]
100
+ token_code = sign_message(@options[:pem], @options[:password], message)
101
+
102
+ xml = Builder::XmlMarkup.new(:indent => 2)
103
+ xml.instruct!
104
+ xml.tag! 'AcquirerTrxReq', 'xmlns' => 'http://www.idealdesk.com/Message', 'version' => API_VERSION do
105
+ xml.tag! 'createDateTimeStamp', date_time_stamp
106
+ xml.tag! 'Issuer' do
107
+ xml.tag! 'issuerID', options[:issuer_id]
108
+ end
109
+ xml.tag! 'Merchant' do
110
+ xml.tag! 'merchantID', @options[:login]
111
+ xml.tag! 'subID', SUB_ID
112
+ xml.tag! 'authentication', AUTHENTICATION_TYPE
113
+ xml.tag! 'token', token
114
+ xml.tag! 'tokenCode', token_code
115
+ xml.tag! 'merchantReturnURL', options[:return_url]
116
+ end
117
+ xml.tag! 'Transaction' do
118
+ xml.tag! 'purchaseID', options[:order_id]
119
+ xml.tag! 'amount', money
120
+ xml.tag! 'currency', options[:currency]
121
+ xml.tag! 'expirationPeriod', options[:expiration_period] || default_expiration_period
122
+ xml.tag! 'language', LANGUAGE
123
+ xml.tag! 'description', options[:description]
124
+ xml.tag! 'entranceCode', options[:entrance_code]
125
+ end
126
+ xml.target!
127
+ end
128
+ end
129
+
130
+ # <?xml version="1.0" encoding="UTF-8"?>
131
+ # <AcquirerStatusReq xmlns="http://www.idealdesk.com/Message" version="1.1.0">
132
+ # <createDateTimeStamp>2001-12-17T09:30:47.0Z</createDateTimeStamp>
133
+ # <Merchant>
134
+ # <merchantID>000123456</merchantID>
135
+ # <subID>0</subID>
136
+ # <authentication>keyed hash</authentication>
137
+ # <token>1</token>
138
+ # <tokenCode>3823ad872eff23</tokenCode>
139
+ # </Merchant>
140
+ # <Transaction>
141
+ # <transactionID>0001023456789112</transactionID>
142
+ # </Transaction>
143
+ # </AcquirerStatusReq>
144
+ def build_status_request(options)
145
+ datetimestamp = create_time_stamp
146
+ message = datetimestamp + @options[:login] + SUB_ID + options[:transaction_id]
147
+ tokenCode = sign_message(@options[:pem], @options[:password], message)
148
+
149
+ xml = Builder::XmlMarkup.new(:indent => 2)
150
+ xml.instruct!
151
+ xml.tag! 'AcquirerStatusReq', 'xmlns' => 'http://www.idealdesk.com/Message', 'version' => API_VERSION do
152
+ xml.tag! 'createDateTimeStamp', datetimestamp
153
+ xml.tag! 'Merchant' do
154
+ xml.tag! 'merchantID', @options[:login]
155
+ xml.tag! 'subID', SUB_ID
156
+ xml.tag! 'authentication' , AUTHENTICATION_TYPE
157
+ xml.tag! 'token', token
158
+ xml.tag! 'tokenCode', tokenCode
159
+ end
160
+ xml.tag! 'Transaction' do
161
+ xml.tag! 'transactionID', options[:transaction_id]
162
+ end
163
+ end
164
+ xml.target!
165
+ end
166
+
167
+ # <?xml version="1.0" encoding="UTF-8"?>
168
+ # <DirectoryReq xmlns="http://www.idealdesk.com/Message" version="1.1.0">
169
+ # <createDateTimeStamp>2001-12-17T09:30:47.0Z</createDateTimeStamp>
170
+ # <Merchant>
171
+ # <merchantID>000000001</merchantID>
172
+ # <subID>0</subID>
173
+ # <authentication>1</authentication>
174
+ # <token>hashkey</token>
175
+ # <tokenCode>WajqV1a3nDen0be2r196g9FGFF=</tokenCode>
176
+ # </Merchant>
177
+ # </DirectoryReq>
178
+ def build_directory_request
179
+ datetimestamp = create_time_stamp
180
+ message = datetimestamp + @options[:login] + SUB_ID
181
+ tokenCode = sign_message(@options[:pem], @options[:password], message)
182
+
183
+ xml = Builder::XmlMarkup.new(:indent => 2)
184
+ xml.instruct!
185
+ xml.tag! 'DirectoryReq', 'xmlns' => 'http://www.idealdesk.com/Message', 'version' => API_VERSION do
186
+ xml.tag! 'createDateTimeStamp', datetimestamp
187
+ xml.tag! 'Merchant' do
188
+ xml.tag! 'merchantID', @options[:login]
189
+ xml.tag! 'subID', SUB_ID
190
+ xml.tag! 'authentication', AUTHENTICATION_TYPE
191
+ xml.tag! 'token', token
192
+ xml.tag! 'tokenCode', tokenCode
193
+ end
194
+ end
195
+ xml.target!
196
+ end
197
+
198
+ def commit(request)
199
+ raw_response = ssl_post(url, request)
200
+ response = Hash.from_xml(raw_response.to_s)
201
+ response_type = response.keys[0]
202
+
203
+ case response_type
204
+ when 'AcquirerTrxRes', 'DirectoryRes'
205
+ success = true
206
+ when 'ErrorRes'
207
+ success = false
208
+ when 'AcquirerStatusRes'
209
+ raise SecurityError, "Message verification failed.", caller unless status_response_verified?(response)
210
+ success = (response['AcquirerStatusRes']['Transaction']['status'] == 'Success')
211
+ else
212
+ raise ArgumentError, "Unknown response type.", caller
213
+ end
214
+
215
+ return IdealResponse.new(success, response.keys[0], response, :test => test?)
216
+ end
217
+
218
+ def create_fingerprint(cert_file)
219
+ cert_data = OpenSSL::X509::Certificate.new(cert_file).to_s
220
+ cert_data = cert_data.sub(/-----BEGIN CERTIFICATE-----/, '')
221
+ cert_data = cert_data.sub(/-----END CERTIFICATE-----/, '')
222
+ fingerprint = ActiveSupport::Base64.decode64(cert_data)
223
+ fingerprint = Digest::SHA1.hexdigest(fingerprint)
224
+ return fingerprint.upcase
225
+ end
226
+
227
+ def sign_message(private_key_data, password, data)
228
+ private_key = OpenSSL::PKey::RSA.new(private_key_data, password)
229
+ signature = private_key.sign(OpenSSL::Digest::SHA1.new, data.gsub('\s', ''))
230
+ return ActiveSupport::Base64.encode64(signature).gsub(/\n/, '')
231
+ end
232
+
233
+ def verify_message(cert_file, data, signature)
234
+ public_key = OpenSSL::X509::Certificate.new(cert_file).public_key
235
+ return public_key.verify(OpenSSL::Digest::SHA1.new, ActiveSupport::Base64.decode64(signature), data)
236
+ end
237
+
238
+ def status_response_verified?(response)
239
+ transaction = response['AcquirerStatusRes']['Transaction']
240
+ message = response['AcquirerStatusRes']['createDateTimeStamp'] + transaction['transactionID' ] + transaction['status']
241
+ message << transaction['consumerAccountNumber'].to_s
242
+ verify_message(server_pem, message, response['AcquirerStatusRes']['Signature']['signatureValue'])
243
+ end
244
+
245
+ def create_time_stamp
246
+ Time.now.gmtime.strftime('%Y-%m-%dT%H:%M:%S.000Z')
247
+ end
248
+ end
249
+ end
250
+ end