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,191 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class CashnetGateway < Gateway
4
+ self.live_url = "https://commerce.cashnet.com/"
5
+
6
+ self.supported_countries = ["US"]
7
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
8
+ self.homepage_url = "http://www.higherone.com/"
9
+ self.display_name = "Cashnet"
10
+ self.money_format = :dollars
11
+
12
+ # Creates a new CashnetGateway
13
+ #
14
+ # ==== Options
15
+ #
16
+ # * <tt>:merchant</tt> -- Gateway Merchant (REQUIRED)
17
+ # * <tt>:operator</tt> -- Operator (REQUIRED)
18
+ # * <tt>:password</tt> -- Password (REQUIRED)
19
+ # * <tt>:merchant_gateway_name</tt> -- Site name (REQUIRED)
20
+ # * <tt>:station</tt> -- Station (defaults to "WEB")
21
+ # * <tt>:custcode</tt> -- Customer code (defaults to
22
+ # "ActiveMerchant/#{ActiveMerchant::VERSION}")
23
+ # * <tt>:default_item_code</tt> -- Default item code (defaults to "FEE",
24
+ # can be overridden on a per-transaction basis with options[:item_code])
25
+ def initialize(options = {})
26
+ requires!(
27
+ options,
28
+ :merchant,
29
+ :operator,
30
+ :password,
31
+ :merchant_gateway_name
32
+ )
33
+ options[:default_item_code] ||= "FEE"
34
+ super
35
+ end
36
+
37
+ def purchase(money, payment_object, options = {})
38
+ post = {}
39
+ add_creditcard(post, payment_object)
40
+ add_invoice(post, options)
41
+ add_address(post, options)
42
+ add_customer_data(post, options)
43
+ commit('SALE', money, post)
44
+ end
45
+
46
+ def refund(money, identification, options = {})
47
+ post = {}
48
+ post[:origtx] = identification
49
+ add_invoice(post, options)
50
+ commit('REFUND', money, post)
51
+ end
52
+
53
+ private
54
+
55
+ def commit(action, money, fields)
56
+ fields[:amount] = amount(money)
57
+ url = live_url + @options[:merchant_gateway_name]
58
+ response = parse(ssl_post(url, post_data(action, fields)))
59
+
60
+ success = (response[:result] == '0')
61
+ Response.new(
62
+ success,
63
+ CASHNET_CODES[response[:result]],
64
+ response,
65
+ test: test?,
66
+ authorization: (success ? response[:tx] : '')
67
+ )
68
+ end
69
+
70
+ def post_data(action, parameters = {})
71
+ post = {}
72
+ post[:command] = action
73
+ post[:merchant] = @options[:merchant]
74
+ post[:operator] = @options[:operator]
75
+ post[:password] = @options[:password]
76
+ post[:station] = (@options[:station] || "WEB")
77
+ post[:custcode] = (@options[:custcode] || "ActiveMerchant/#{ActiveMerchant::VERSION}")
78
+ post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
79
+ end
80
+
81
+ def add_creditcard(post, creditcard)
82
+ post[:cardno] = creditcard.number
83
+ post[:cid] = creditcard.verification_value
84
+ post[:expdate] = expdate(creditcard)
85
+ post[:card_name_g] = creditcard.name
86
+ post[:fname] = creditcard.first_name
87
+ post[:lname] = creditcard.last_name
88
+ end
89
+
90
+ def add_invoice(post, options)
91
+ post[:order_number] = options[:order_id] if options[:order_id].present?
92
+ post[:itemcode] = (options[:item_code] || @options[:default_item_code])
93
+ end
94
+
95
+ def add_address(post, options)
96
+ if address = (options[:shipping_address] || options[:billing_address] || options[:address])
97
+ post[:addr_g] = String(address[:address1]) + ',' + String(address[:address2])
98
+ post[:city_g] = address[:city]
99
+ post[:state_g] = address[:state]
100
+ post[:zip_g] = address[:zip]
101
+ end
102
+ end
103
+
104
+ def add_customer_data(post, options)
105
+ post[:email_g] = options[:email]
106
+ end
107
+
108
+ def expdate(creditcard)
109
+ year = format(creditcard.year, :two_digits)
110
+ month = format(creditcard.month, :two_digits)
111
+
112
+ "#{month}#{year}"
113
+ end
114
+
115
+ def parse(body)
116
+ response_data = body.match(/<cngateway>(.*)<\/cngateway>/)[1]
117
+ Hash[CGI::parse(response_data).map{|k,v| [k.to_sym,v.first]}]
118
+ end
119
+
120
+ def handle_response(response)
121
+ if (200...300).include?(response.code.to_i)
122
+ return response.body
123
+ elsif 302 == response.code.to_i
124
+ return ssl_get(URI.parse(response['location']))
125
+ end
126
+ raise ResponseError.new(response)
127
+ end
128
+
129
+ CASHNET_CODES = {
130
+ '0' => 'Success',
131
+ '1' => 'Invalid customer code, no customer code specified',
132
+ '2' => 'Invalid operator code, no operator specified',
133
+ '3' => 'Invalid workstation code, no station specified',
134
+ '4' => 'Invalid item code, no code specified',
135
+ '5' => 'Negative amount is not allowed',
136
+ '6' => 'Invalid credit card number, no credit card number provided',
137
+ '7' => 'Invalid expiration date, no expiration date provided',
138
+ '8' => 'Please only provide either ACH or credit card information',
139
+ '9' => 'Invalid ACH account number, no account number provided',
140
+ '10' => 'Invalid routing/transit number, no routing/transit number provided',
141
+ '11' => 'Invalid account type, no account type provided',
142
+ '12' => 'Invalid check digit for routing/transit number',
143
+ '13' => 'No ACH merchant account set up for the location of the station being used',
144
+ '21' => 'Invalid merchant code, no merchant code provided',
145
+ '22' => 'Invalid client code, no client code provided',
146
+ '23' => 'Invalid password, no password provided',
147
+ '24' => 'Invalid transaction type, no transaction type provided',
148
+ '25' => 'Invalid amount, amount not provided',
149
+ '26' => 'Invalid payment code provided',
150
+ '27' => 'Invalid version number, version not found',
151
+ '31' => 'Application amount exceeds account balance',
152
+ '150' => 'Invalid payment information, no payment information provided',
153
+ '200' => 'Invalid command',
154
+ '201' => 'Customer not on file',
155
+ '205' => 'Invalid operator or password',
156
+ '206' => 'Operator is not authorized for this function',
157
+ '208' => 'Customer/PIN authentication unsuccessful',
158
+ '209' => 'Credit card error',
159
+ '211' => 'Credit card error',
160
+ '212' => 'Customer/PIN not on file',
161
+ '213' => 'Customer information not on file',
162
+ '215' => 'Old PIN does not validate ',
163
+ '221' => 'Invalid credit card processor type specified in location or payment code',
164
+ '222' => 'Credit card processor error',
165
+ '280' => 'SmartPay transaction not posted',
166
+ '301' => 'Original transaction not found for this customer',
167
+ '302' => 'Amount to refund exceeds original payment amount or is missing',
168
+ '304' => 'Original credit card payment not found or corrupted',
169
+ '305' => 'Refund amounts should be expressed as positive amounts',
170
+ '306' => 'Original ACH payment not found',
171
+ '307' => 'Original electronic payment not found',
172
+ '308' => 'Invalid original transaction number, original transaction number not found',
173
+ '310' => 'Refund amount exceeds amount still available for a refund',
174
+ '321' => 'Store has not been implemented',
175
+ '501' => 'Unable to roll over batch',
176
+ '502' => 'Batch not found',
177
+ '503' => 'Batch information not available',
178
+ '650' => 'Invalid quick code',
179
+ '651' => 'Transaction amount does not match amount specified in quick code',
180
+ '652' => 'Invalid item code in the detail of the quick code',
181
+ '701' => 'This website has been disabled. Please contact the system administrator.',
182
+ '702' => 'Improper merchant code. Please contact the system administrator.',
183
+ '703' => 'This site is temporarily down for maintenance. We regret the inconvenience. Please try again later.',
184
+ '704' => 'Duplicate item violation. Please contact the system administrator.',
185
+ '705' => 'An invalid reference type has been passed into the system. Please contact the system administrator',
186
+ '706' => 'Items violating unique selection have been passed in. Please contact the system administrator.',
187
+ '999' => 'An unexpected error has occurred. Please consult the event log.'
188
+ }
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,201 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ # CC5 API is used by many banks in Turkey. Extend this base class to provide
4
+ # concrete implementations.
5
+ class CC5Gateway < Gateway
6
+ self.default_currency = 'TRY'
7
+
8
+ CURRENCY_CODES = {
9
+ 'TRY' => 949,
10
+ 'YTL' => 949,
11
+ 'TRL' => 949,
12
+ 'TL' => 949,
13
+ 'USD' => 840,
14
+ 'EUR' => 978,
15
+ 'GBP' => 826,
16
+ 'JPY' => 392
17
+ }
18
+
19
+ def initialize(options = {})
20
+ requires!(options, :login, :password, :client_id)
21
+ super
22
+ end
23
+
24
+ def purchase(money, creditcard, options = {})
25
+ commit(build_sale_request('Auth', money, creditcard, options))
26
+ end
27
+
28
+ def authorize(money, creditcard, options = {})
29
+ commit(build_sale_request('PreAuth', money, creditcard, options))
30
+ end
31
+
32
+ def capture(money, authorization, options = {})
33
+ commit(build_capture_request(money, authorization, options))
34
+ end
35
+
36
+ def void(authorization, options = {})
37
+ commit(build_void_request(authorization, options))
38
+ end
39
+
40
+ def refund(money, authorization, options = {})
41
+ commit(build_authorization_credit_request(money, authorization, options))
42
+ end
43
+
44
+ def credit(money, creditcard, options = {})
45
+ commit(build_creditcard_credit_request(money, creditcard, options))
46
+ end
47
+
48
+ protected
49
+
50
+ def build_sale_request(type, money, creditcard, options = {})
51
+ requires!(options, :order_id)
52
+
53
+ xml = Builder::XmlMarkup.new :indent => 2
54
+
55
+ xml.tag! 'CC5Request' do
56
+ add_login_tags(xml)
57
+ xml.tag! 'OrderId', options[:order_id]
58
+ xml.tag! 'Type', type
59
+ xml.tag! 'Number', creditcard.number
60
+ xml.tag! 'Expires', [format(creditcard.month, :two_digits), format(creditcard.year, :two_digits)].join('/')
61
+ xml.tag! 'Cvv2Val', creditcard.verification_value
62
+ add_amount_tags(money, options, xml)
63
+ xml.tag! 'Email', options[:email] if options[:email]
64
+
65
+ if(address = (options[:billing_address] || options[:address]))
66
+ xml.tag! 'BillTo' do
67
+ add_address(xml, address)
68
+ end
69
+ xml.tag! 'ShipTo' do
70
+ add_address(xml, address)
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ xml.target!
77
+ end
78
+
79
+ def build_capture_request(money, authorization, options = {})
80
+ xml = Builder::XmlMarkup.new :indent => 2
81
+
82
+ xml.tag! 'CC5Request' do
83
+ add_login_tags(xml)
84
+ xml.tag! 'OrderId', authorization
85
+ xml.tag! 'Type', 'PostAuth'
86
+ add_amount_tags(money, options, xml)
87
+ end
88
+ end
89
+
90
+ def build_void_request(authorization, options = {})
91
+ xml = Builder::XmlMarkup.new :indent => 2
92
+
93
+ xml.tag! 'CC5Request' do
94
+ add_login_tags(xml)
95
+ xml.tag! 'OrderId', authorization
96
+ xml.tag! 'Type', 'Void'
97
+ end
98
+ end
99
+
100
+ def build_authorization_credit_request(money, authorization, options = {})
101
+ xml = Builder::XmlMarkup.new :indent => 2
102
+
103
+ xml.tag! 'CC5Request' do
104
+ add_login_tags(xml)
105
+ xml.tag! 'OrderId', authorization
106
+ xml.tag! 'Type', 'Credit'
107
+ add_amount_tags(money, options, xml)
108
+ end
109
+ end
110
+
111
+ def build_creditcard_credit_request(money, creditcard, options = {})
112
+ xml = Builder::XmlMarkup.new :indent => 2
113
+
114
+ xml.tag! 'CC5Request' do
115
+ add_login_tags(xml)
116
+ xml.tag! 'Type', 'Credit'
117
+ xml.tag! 'Number', creditcard.number
118
+
119
+ add_amount_tags(money, options, xml)
120
+ end
121
+ end
122
+
123
+ def add_address(xml, address)
124
+ xml.tag! 'Name', normalize(address[:name])
125
+ xml.tag! 'Street1', normalize(address[:address1])
126
+ xml.tag! 'Street2', normalize(address[:address2]) if address[:address2]
127
+ xml.tag! 'City', normalize(address[:city])
128
+ xml.tag! 'PostalCode', address[:zip]
129
+ xml.tag! 'Country', normalize(address[:country])
130
+ xml.tag! 'Company', normalize(address[:company])
131
+ xml.tag! 'TelVoice', address[:phone].to_s.gsub(/[^0-9]/, '') if address[:phone]
132
+ end
133
+
134
+ def add_login_tags(xml)
135
+ xml.tag! 'Name', @options[:login]
136
+ xml.tag! 'Password', @options[:password]
137
+ xml.tag! 'ClientId', @options[:client_id]
138
+ xml.tag! 'Mode', (test? ? 'T' : 'P')
139
+ end
140
+
141
+ def add_amount_tags(money, options, xml)
142
+ xml.tag! 'Total', amount(money)
143
+ xml.tag! 'Currency', currency_code(options[:currency] || currency(money))
144
+ end
145
+
146
+ def currency_code(currency)
147
+ (CURRENCY_CODES[currency] || CURRENCY_CODES[default_currency])
148
+ end
149
+
150
+ def commit(request)
151
+ raw_response = ssl_post((test? ? self.test_url : self.live_url), "DATA=" + request)
152
+
153
+ response = parse(raw_response)
154
+
155
+ success = success?(response)
156
+
157
+ Response.new(
158
+ success,
159
+ (success ? 'Approved' : "Declined (Reason: #{response[:proc_return_code]} - #{response[:err_msg]})"),
160
+ response,
161
+ :test => test?,
162
+ :authorization => response[:order_id]
163
+ )
164
+ end
165
+
166
+ def parse(body)
167
+ xml = REXML::Document.new(body)
168
+
169
+ response = {}
170
+ xml.root.elements.to_a.each do |node|
171
+ parse_element(response, node)
172
+ end
173
+ response
174
+ end
175
+
176
+ def parse_element(response, node)
177
+ if node.has_elements?
178
+ node.elements.each{|element| parse_element(response, element) }
179
+ else
180
+ response[node.name.underscore.to_sym] = node.text
181
+ end
182
+ end
183
+
184
+ def success?(response)
185
+ (response[:response] == "Approved")
186
+ end
187
+
188
+ def normalize(text)
189
+ return unless text
190
+
191
+ if ActiveSupport::Inflector.method(:transliterate).arity == -2
192
+ ActiveSupport::Inflector.transliterate(text,'')
193
+ elsif RUBY_VERSION >= '1.9'
194
+ text.gsub(/[^\x00-\x7F]+/, '')
195
+ else
196
+ ActiveSupport::Inflector.transliterate(text).to_s
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,229 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class CecabankGateway < Gateway
4
+ self.test_url = 'http://tpv.ceca.es:8000'
5
+ self.live_url = 'https://pgw.ceca.es'
6
+
7
+ self.supported_countries = ['ES']
8
+ self.supported_cardtypes = [:visa, :master, :american_express]
9
+ self.homepage_url = 'http://www.ceca.es/es/'
10
+ self.display_name = 'Cecabank'
11
+ self.default_currency = 'EUR'
12
+ self.money_format = :cents
13
+
14
+ #### CECA's MAGIC NUMBERS
15
+ CECA_NOTIFICATIONS_URL = 'NONE'
16
+ CECA_ENCRIPTION = 'SHA1'
17
+ CECA_DECIMALS = '2'
18
+ CECA_MODE = 'SSL'
19
+ CECA_UI_LESS_LANGUAGE = 'XML'
20
+ CECA_UI_LESS_LANGUAGE_REFUND = '1'
21
+ CECA_UI_LESS_REFUND_PAGE = 'anulacion_xml'
22
+ CECA_ACTION_REFUND = 'tpvanularparcialmente' #use partial refund's URL to avoid time frame limitations and decision logic on client side
23
+ CECA_ACTION_PURCHASE = 'tpv'
24
+ CECA_CURRENCIES_DICTIONARY = {'EUR' => 978, 'USD' => 840, 'GBP' => 826}
25
+
26
+ # Creates a new CecabankGateway
27
+ #
28
+ # The gateway requires four values for connection to be passed
29
+ # in the +options+ hash.
30
+ #
31
+ # ==== Options
32
+ #
33
+ # * <tt>:merchant_id</tt> -- Cecabank's merchant_id (REQUIRED)
34
+ # * <tt>:acquirer_bin</tt> -- Cecabank's acquirer_bin (REQUIRED)
35
+ # * <tt>:terminal_id</tt> -- Cecabank's terminal_id (REQUIRED)
36
+ # * <tt>:key</tt> -- Cecabank's cypher key (REQUIRED)
37
+ # * <tt>:test</tt> -- +true+ or +false+. If true, perform transactions against the test server.
38
+ # Otherwise, perform transactions against the production server.
39
+ def initialize(options = {})
40
+ requires!(options, :merchant_id, :acquirer_bin, :terminal_id, :key)
41
+ super
42
+ end
43
+
44
+ # Perform a purchase, which is essentially an authorization and capture in a single operation.
45
+ #
46
+ # ==== Parameters
47
+ #
48
+ # * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
49
+ # * <tt>creditcard</tt> -- The CreditCard details for the transaction.
50
+ # * <tt>options</tt> -- A hash of optional parameters.
51
+ #
52
+ # ==== Options
53
+ #
54
+ # * <tt>:order_id</tt> -- order_id passed used purchase. (REQUIRED)
55
+ # * <tt>:currency</tt> -- currency. Supported: EUR, USD, GBP.
56
+ # * <tt>:description</tt> -- description to be pased to the gateway.
57
+ def purchase(money, creditcard, options = {})
58
+ requires!(options, :order_id)
59
+
60
+ post = {'Descripcion' => options[:description],
61
+ 'Num_operacion' => options[:order_id],
62
+ 'Idioma' => CECA_UI_LESS_LANGUAGE,
63
+ 'Pago_soportado' => CECA_MODE,
64
+ 'URL_OK' => CECA_NOTIFICATIONS_URL,
65
+ 'URL_NOK' => CECA_NOTIFICATIONS_URL,
66
+ 'Importe' => amount(money),
67
+ 'TipoMoneda' => CECA_CURRENCIES_DICTIONARY[options[:currency] || currency(money)]}
68
+
69
+ add_creditcard(post, creditcard)
70
+
71
+ commit(CECA_ACTION_PURCHASE, post)
72
+ end
73
+
74
+ # Refund a transaction.
75
+ #
76
+ # This transaction indicates to the gateway that
77
+ # money should flow from the merchant to the customer.
78
+ #
79
+ # ==== Parameters
80
+ #
81
+ # * <tt>money</tt> -- The amount to be credited to the customer as an Integer value in cents.
82
+ # * <tt>identification</tt> -- The reference given from the gateway on purchase (reference, not operation).
83
+ # * <tt>options</tt> -- A hash of parameters.
84
+ def refund(money, identification, options = {})
85
+ reference, order_id = split_authorization(identification)
86
+
87
+ post = {'Referencia' => reference,
88
+ 'Num_operacion' => order_id,
89
+ 'Idioma' => CECA_UI_LESS_LANGUAGE_REFUND,
90
+ 'Pagina' => CECA_UI_LESS_REFUND_PAGE,
91
+ 'Importe' => amount(money),
92
+ 'TipoMoneda' => CECA_CURRENCIES_DICTIONARY[options[:currency] || currency(money)]}
93
+
94
+ commit(CECA_ACTION_REFUND, post)
95
+ end
96
+
97
+ private
98
+
99
+ def add_creditcard(post, creditcard)
100
+ post['PAN'] = creditcard.number
101
+ post['Caducidad'] = expdate(creditcard)
102
+ post['CVV2'] = creditcard.verification_value
103
+ post['Pago_elegido'] = CECA_MODE
104
+ end
105
+
106
+ def expdate(creditcard)
107
+ "#{format(creditcard.year, :four_digits)}#{format(creditcard.month, :two_digits)}"
108
+ end
109
+
110
+ def parse(body)
111
+ response = {}
112
+
113
+ root = REXML::Document.new(body).root
114
+
115
+ response[:success] = (root.attributes['valor'] == "OK")
116
+ response[:date] = root.attributes['fecha']
117
+ response[:operation_number] = root.attributes['numeroOperacion']
118
+ response[:message] = root.attributes['valor']
119
+
120
+ if root.elements['OPERACION']
121
+ response[:operation_type] = root.elements['OPERACION'].attributes['tipo']
122
+ response[:amount] = root.elements['OPERACION/importe'].text.strip
123
+ end
124
+
125
+ response[:description] = root.elements['OPERACION/descripcion'].text if root.elements['OPERACION/descripcion']
126
+ response[:authorization_number] = root.elements['OPERACION/numeroAutorizacion'].text if root.elements['OPERACION/numeroAutorizacion']
127
+ response[:reference] = root.elements['OPERACION/referencia'].text if root.elements['OPERACION/referencia']
128
+ response[:pan] = root.elements['OPERACION/pan'].text if root.elements['OPERACION/pan']
129
+
130
+ if root.elements['ERROR']
131
+ response[:error_code] = root.elements['ERROR/codigo'].text
132
+ response[:error_message] = root.elements['ERROR/descripcion'].text
133
+ else
134
+ if("000" == root.elements['OPERACION'].attributes['numeroOperacion'])
135
+ if(root.elements['OPERACION/numeroAutorizacion'])
136
+ response[:authorization] = root.elements['OPERACION/numeroAutorizacion'].text
137
+ end
138
+ else
139
+ response[:authorization] = root.attributes['numeroOperacion']
140
+ end
141
+ end
142
+
143
+ return response
144
+
145
+ rescue REXML::ParseException => e
146
+ response[:success] = false
147
+ response[:message] = "Unable to parse the response."
148
+ response[:error_message] = e.message
149
+ response
150
+ end
151
+
152
+ def commit(action, parameters)
153
+ parameters.merge!(
154
+ 'Cifrado' => CECA_ENCRIPTION,
155
+ 'Firma' => generate_signature(action, parameters),
156
+ 'Exponente' => CECA_DECIMALS,
157
+ 'MerchantID' => options[:merchant_id],
158
+ 'AcquirerBIN' => options[:acquirer_bin],
159
+ 'TerminalID' => options[:terminal_id]
160
+ )
161
+ url = (test? ? self.test_url : self.live_url) + "/cgi-bin/#{action}"
162
+ xml = ssl_post(url, post_data(parameters))
163
+ response = parse(xml)
164
+ Response.new(
165
+ response[:success],
166
+ response[:message],
167
+ response,
168
+ :test => test?,
169
+ :authorization => build_authorization(response)
170
+ )
171
+ end
172
+
173
+ def post_data(params)
174
+ return nil unless params
175
+
176
+ params.map do |key, value|
177
+ next if value.blank?
178
+ if value.is_a?(Hash)
179
+ h = {}
180
+ value.each do |k, v|
181
+ h["#{key}.#{k}"] = v unless v.blank?
182
+ end
183
+ post_data(h)
184
+ else
185
+ "#{key}=#{CGI.escape(value.to_s)}"
186
+ end
187
+ end.compact.join("&")
188
+ end
189
+
190
+ def build_authorization(response)
191
+ [response[:reference], response[:authorization]].join("|")
192
+ end
193
+
194
+ def split_authorization(authorization)
195
+ authorization.split("|")
196
+ end
197
+
198
+ def generate_signature(action, parameters)
199
+ signature_fields = case action
200
+ when CECA_ACTION_REFUND
201
+ options[:key].to_s +
202
+ options[:merchant_id].to_s +
203
+ options[:acquirer_bin].to_s +
204
+ options[:terminal_id].to_s +
205
+ parameters['Num_operacion'].to_s +
206
+ parameters['Importe'].to_s +
207
+ parameters['TipoMoneda'].to_s +
208
+ CECA_DECIMALS +
209
+ parameters['Referencia'].to_s +
210
+ CECA_ENCRIPTION
211
+ else
212
+ options[:key].to_s +
213
+ options[:merchant_id].to_s +
214
+ options[:acquirer_bin].to_s +
215
+ options[:terminal_id].to_s +
216
+ parameters['Num_operacion'].to_s +
217
+ parameters['Importe'].to_s +
218
+ parameters['TipoMoneda'].to_s +
219
+ CECA_DECIMALS +
220
+ CECA_ENCRIPTION +
221
+ CECA_NOTIFICATIONS_URL +
222
+ CECA_NOTIFICATIONS_URL
223
+ end
224
+ Digest::SHA1.hexdigest(signature_fields)
225
+ end
226
+ end
227
+ end
228
+ end
229
+