activemerchant 1.1.0 → 1.2.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 (178) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +226 -0
  3. data/CONTRIBUTERS +52 -0
  4. data/README +34 -24
  5. data/Rakefile +152 -0
  6. data/gem-public_cert.pem +20 -0
  7. data/init.rb +3 -0
  8. data/lib/active_merchant.rb +3 -1
  9. data/lib/active_merchant/billing/credit_card.rb +21 -17
  10. data/lib/active_merchant/billing/credit_card_methods.rb +17 -19
  11. data/lib/active_merchant/billing/gateway.rb +160 -44
  12. data/lib/active_merchant/billing/gateways.rb +2 -15
  13. data/lib/active_merchant/billing/gateways/authorize_net.rb +21 -21
  14. data/lib/active_merchant/billing/gateways/bogus.rb +6 -6
  15. data/lib/active_merchant/billing/gateways/brain_tree.rb +191 -0
  16. data/lib/active_merchant/billing/gateways/card_stream.rb +207 -0
  17. data/lib/active_merchant/billing/gateways/cyber_source.rb +402 -0
  18. data/lib/active_merchant/billing/gateways/data_cash.rb +41 -97
  19. data/lib/active_merchant/billing/gateways/efsnet.rb +256 -0
  20. data/lib/active_merchant/billing/gateways/eway.rb +77 -29
  21. data/lib/active_merchant/billing/gateways/exact.rb +230 -0
  22. data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -33
  23. data/lib/active_merchant/billing/gateways/moneris.rb +155 -125
  24. data/lib/active_merchant/billing/gateways/net_registry.rb +257 -0
  25. data/lib/active_merchant/billing/gateways/pay_junction.rb +407 -0
  26. data/lib/active_merchant/billing/gateways/payflow.rb +163 -25
  27. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +56 -38
  28. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +10 -1
  29. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +9 -0
  30. data/lib/active_merchant/billing/gateways/payflow_express.rb +36 -11
  31. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +6 -0
  32. data/lib/active_merchant/billing/gateways/payflow_uk.rb +7 -3
  33. data/lib/active_merchant/billing/gateways/payment_express.rb +261 -0
  34. data/lib/active_merchant/billing/gateways/paypal.rb +18 -4
  35. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +31 -15
  36. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +8 -0
  37. data/lib/active_merchant/billing/gateways/paypal_express.rb +33 -8
  38. data/lib/active_merchant/billing/gateways/plugnpay.rb +300 -0
  39. data/lib/active_merchant/billing/gateways/protx.rb +285 -0
  40. data/lib/active_merchant/billing/gateways/psigate.rb +13 -12
  41. data/lib/active_merchant/billing/gateways/psl_card.rb +297 -0
  42. data/lib/active_merchant/billing/gateways/quickpay.rb +197 -0
  43. data/lib/active_merchant/billing/gateways/realex.rb +212 -0
  44. data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
  45. data/lib/active_merchant/billing/gateways/trans_first.rb +136 -0
  46. data/lib/active_merchant/billing/gateways/trust_commerce.rb +43 -20
  47. data/lib/active_merchant/billing/gateways/usa_epay.rb +6 -5
  48. data/lib/active_merchant/billing/gateways/verifi.rb +235 -0
  49. data/lib/active_merchant/billing/gateways/viaklix.rb +171 -0
  50. data/lib/active_merchant/billing/integrations/gestpay/helper.rb +0 -2
  51. data/lib/active_merchant/billing/integrations/helper.rb +8 -1
  52. data/lib/active_merchant/billing/integrations/nochex.rb +62 -1
  53. data/lib/active_merchant/billing/integrations/nochex/notification.rb +9 -16
  54. data/lib/active_merchant/billing/integrations/notification.rb +1 -1
  55. data/lib/active_merchant/billing/integrations/paypal/helper.rb +59 -46
  56. data/lib/active_merchant/billing/integrations/paypal/notification.rb +14 -47
  57. data/lib/active_merchant/lib/error.rb +4 -0
  58. data/lib/active_merchant/lib/post_data.rb +22 -0
  59. data/lib/active_merchant/lib/posts_data.rb +23 -5
  60. data/lib/active_merchant/lib/requires_parameters.rb +2 -2
  61. data/lib/active_merchant/lib/validateable.rb +1 -1
  62. data/lib/support/gateway_support.rb +45 -0
  63. data/lib/tasks/cia.rb +1 -1
  64. data/script/generate +14 -0
  65. data/script/generator/base.rb +45 -0
  66. data/script/generator/generator.rb +24 -0
  67. data/script/generator/generators/gateway/gateway_generator.rb +14 -0
  68. data/script/generator/generators/gateway/templates/gateway.rb +73 -0
  69. data/script/generator/generators/gateway/templates/gateway_test.rb +41 -0
  70. data/script/generator/generators/gateway/templates/remote_gateway_test.rb +56 -0
  71. data/script/generator/generators/integration/integration_generator.rb +25 -0
  72. data/script/generator/generators/integration/templates/helper.rb +34 -0
  73. data/script/generator/generators/integration/templates/helper_test.rb +54 -0
  74. data/script/generator/generators/integration/templates/integration.rb +18 -0
  75. data/script/generator/generators/integration/templates/module_test.rb +9 -0
  76. data/script/generator/generators/integration/templates/notification.rb +100 -0
  77. data/script/generator/generators/integration/templates/notification_test.rb +41 -0
  78. data/script/generator/manifest.rb +20 -0
  79. data/test/extra/binding_of_caller.rb +80 -0
  80. data/test/extra/breakpoint.rb +547 -0
  81. data/test/fixtures.yml +251 -0
  82. data/test/remote_tests/remote_authorize_net_test.rb +113 -0
  83. data/test/remote_tests/remote_brain_tree_test.rb +78 -0
  84. data/test/remote_tests/remote_card_stream_test.rb +160 -0
  85. data/test/remote_tests/remote_cyber_source_test.rb +130 -0
  86. data/test/remote_tests/remote_data_cash_test.rb +155 -0
  87. data/test/remote_tests/remote_efsnet_test.rb +93 -0
  88. data/test/remote_tests/remote_eway_test.rb +71 -0
  89. data/test/remote_tests/remote_exact_test.rb +59 -0
  90. data/test/remote_tests/remote_gestpay_integration_test.rb +37 -0
  91. data/test/remote_tests/remote_linkpoint_test.rb +144 -0
  92. data/test/remote_tests/remote_moneris_test.rb +110 -0
  93. data/test/remote_tests/remote_net_registry_test.rb +120 -0
  94. data/test/remote_tests/remote_pay_junction_test.rb +162 -0
  95. data/test/remote_tests/remote_payflow_express_test.rb +50 -0
  96. data/test/remote_tests/remote_payflow_test.rb +241 -0
  97. data/test/remote_tests/remote_payflow_uk_test.rb +172 -0
  98. data/test/remote_tests/remote_payment_express_test.rb +136 -0
  99. data/test/remote_tests/remote_paypal_express_test.rb +49 -0
  100. data/test/remote_tests/remote_paypal_integration_test.rb +14 -0
  101. data/test/remote_tests/remote_paypal_test.rb +163 -0
  102. data/test/remote_tests/remote_plugnpay_test.rb +70 -0
  103. data/test/remote_tests/remote_protx_test.rb +184 -0
  104. data/test/remote_tests/remote_psigate_test.rb +87 -0
  105. data/test/remote_tests/remote_psl_card_test.rb +105 -0
  106. data/test/remote_tests/remote_quickpay_test.rb +182 -0
  107. data/test/remote_tests/remote_realex_test.rb +227 -0
  108. data/test/remote_tests/remote_secure_pay_test.rb +36 -0
  109. data/test/remote_tests/remote_trans_first_test.rb +37 -0
  110. data/test/remote_tests/remote_trust_commerce_test.rb +136 -0
  111. data/test/remote_tests/remote_usa_epay_test.rb +57 -0
  112. data/test/remote_tests/remote_verifi_test.rb +107 -0
  113. data/test/remote_tests/remote_viaklix_test.rb +53 -0
  114. data/test/test_helper.rb +132 -0
  115. data/test/unit/base_test.rb +61 -0
  116. data/test/unit/country_code_test.rb +33 -0
  117. data/test/unit/country_test.rb +64 -0
  118. data/test/unit/credit_card_formatting_test.rb +24 -0
  119. data/test/unit/credit_card_methods_test.rb +37 -0
  120. data/test/unit/credit_card_test.rb +365 -0
  121. data/test/unit/gateways/authorize_net_test.rb +140 -0
  122. data/test/unit/gateways/bogus_test.rb +43 -0
  123. data/test/unit/gateways/brain_tree_test.rb +77 -0
  124. data/test/unit/gateways/card_stream_test.rb +37 -0
  125. data/test/unit/gateways/cyber_source_test.rb +151 -0
  126. data/test/unit/gateways/data_cash_test.rb +23 -0
  127. data/test/unit/gateways/efsnet_test.rb +70 -0
  128. data/test/unit/gateways/eway_test.rb +105 -0
  129. data/test/unit/gateways/exact_test.rb +118 -0
  130. data/test/unit/gateways/gateway_test.rb +24 -0
  131. data/test/unit/gateways/linkpoint_test.rb +165 -0
  132. data/test/unit/gateways/moneris_test.rb +167 -0
  133. data/test/unit/gateways/net_registry_test.rb +478 -0
  134. data/test/unit/gateways/pay_junction_test.rb +61 -0
  135. data/test/unit/gateways/payflow_express_test.rb +165 -0
  136. data/test/unit/gateways/payflow_express_uk_test.rb +14 -0
  137. data/test/unit/gateways/payflow_test.rb +230 -0
  138. data/test/unit/gateways/payflow_uk_test.rb +68 -0
  139. data/test/unit/gateways/payment_express_test.rb +215 -0
  140. data/test/unit/gateways/paypal_express_test.rb +222 -0
  141. data/test/unit/gateways/paypal_test.rb +241 -0
  142. data/test/unit/gateways/plugnpay_test.rb +79 -0
  143. data/test/unit/gateways/protx_test.rb +110 -0
  144. data/test/unit/gateways/psigate_test.rb +110 -0
  145. data/test/unit/gateways/psl_card_test.rb +51 -0
  146. data/test/unit/gateways/quickpay_test.rb +125 -0
  147. data/test/unit/gateways/realex_test.rb +150 -0
  148. data/test/unit/gateways/secure_pay_test.rb +78 -0
  149. data/test/unit/gateways/trans_first_test.rb +125 -0
  150. data/test/unit/gateways/trust_commerce_test.rb +57 -0
  151. data/test/unit/gateways/usa_epay_test.rb +117 -0
  152. data/test/unit/gateways/verifi_test.rb +91 -0
  153. data/test/unit/gateways/viaklix_test.rb +72 -0
  154. data/test/unit/integrations/action_view_helper_test.rb +54 -0
  155. data/test/unit/integrations/bogus_module_test.rb +16 -0
  156. data/test/unit/integrations/chronopay_module_test.rb +9 -0
  157. data/test/unit/integrations/gestpay_module_test.rb +10 -0
  158. data/test/unit/integrations/helpers/bogus_helper_test.rb +28 -0
  159. data/test/unit/integrations/helpers/chronopay_helper_test.rb +67 -0
  160. data/test/unit/integrations/helpers/gestpay_helper_test.rb +100 -0
  161. data/test/unit/integrations/helpers/nochex_helper_test.rb +53 -0
  162. data/test/unit/integrations/helpers/paypal_helper_test.rb +162 -0
  163. data/test/unit/integrations/helpers/two_checkout_helper_test.rb +92 -0
  164. data/test/unit/integrations/nochex_module_test.rb +9 -0
  165. data/test/unit/integrations/notifications/chronopay_notification_test.rb +66 -0
  166. data/test/unit/integrations/notifications/gestpay_notification_test.rb +60 -0
  167. data/test/unit/integrations/notifications/nochex_notification_test.rb +51 -0
  168. data/test/unit/integrations/notifications/notification_test.rb +41 -0
  169. data/test/unit/integrations/notifications/paypal_notification_test.rb +85 -0
  170. data/test/unit/integrations/notifications/two_checkout_notification_test.rb +55 -0
  171. data/test/unit/integrations/paypal_module_test.rb +24 -0
  172. data/test/unit/integrations/two_checkout_module_test.rb +9 -0
  173. data/test/unit/post_data_test.rb +55 -0
  174. data/test/unit/response_test.rb +14 -0
  175. data/test/unit/validateable_test.rb +56 -0
  176. metadata +160 -7
  177. metadata.gz.sig +0 -0
  178. data/lib/active_merchant/billing/gateways/payflow/f73e89fd.0 +0 -17
@@ -0,0 +1,197 @@
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/transaction.php'
8
+
9
+ attr_reader :url
10
+ attr_reader :response
11
+ attr_reader :options
12
+
13
+ self.default_currency = 'DKK'
14
+ self.money_format = :cents
15
+ self.supported_cardtypes = [ :dankort, :forbrugsforeningen, :visa, :master, :american_express, :diners_club, :jcb, :maestro ]
16
+ self.supported_countries = ['DK']
17
+ self.homepage_url = 'http://quickpay.dk/'
18
+ self.display_name = 'Quickpay'
19
+
20
+ TRANSACTIONS = {
21
+ :authorization => '1100',
22
+ :capture => '1220',
23
+ :void => '1420',
24
+ :credit => 'credit'
25
+ }
26
+
27
+ POS_CODES = {
28
+ :mail => '100020100110',
29
+ :phone => '100030100110',
30
+ :internet => 'L00500L00130',
31
+ :internet_secure => 'K00500K00130',
32
+ :internet_edankort => 'KM0500R00130',
33
+ :internet_recurring => 'K00540K00130'
34
+ }
35
+
36
+ MD5_CHECK_FIELDS = {
37
+ :authorization => [:msgtype, :cardnumber, :amount, :expirationdate, :posc, :ordernum, :currency, :cvd, :merchant, :authtype, :reference, :transaction],
38
+ :capture => [:msgtype, :amount, :merchant, :transaction],
39
+ :void => [:msgtype, :merchant, :transaction],
40
+ :credit => [:msgtype, :amount, :merchant, :transaction]
41
+ }
42
+
43
+ CURRENCIES = [ 'DKK', 'EUR', 'NOK', 'GBP', 'USD' ]
44
+
45
+ APPROVED = '000'
46
+
47
+ # The login is the QuickpayId
48
+ # The password is the md5checkword from the Quickpay admin interface
49
+ def initialize(options = {})
50
+ requires!(options, :login, :password)
51
+ @options = options
52
+ super
53
+ end
54
+
55
+ def authorize(money, creditcard, options = {})
56
+ post = {}
57
+
58
+ add_amount(post, money, options)
59
+ add_creditcard(post, creditcard)
60
+ add_invoice(post, options)
61
+
62
+ commit(:authorization, post)
63
+ end
64
+
65
+ def purchase(money, creditcard, options = {})
66
+ if result = test_result_from_cc_number(creditcard.number)
67
+ return result
68
+ end
69
+
70
+ auth = authorize(money, creditcard, options)
71
+ auth.success? ? capture(money, auth.authorization) : auth
72
+ end
73
+
74
+ def capture(money, authorization, options = {})
75
+ post = {}
76
+
77
+ add_reference(post, authorization)
78
+ add_amount(post, money)
79
+
80
+ commit(:capture, post)
81
+ end
82
+
83
+ def void(identification, options = {})
84
+ post = {}
85
+
86
+ add_reference(post, identification)
87
+
88
+ commit(:void, post)
89
+ end
90
+
91
+ def credit(money, identification, options = {})
92
+ post = {}
93
+
94
+ add_amount(post, money)
95
+ add_reference(post, identification)
96
+
97
+ commit(:credit, post)
98
+ end
99
+
100
+ private
101
+
102
+ def add_amount(post, money, options = {})
103
+ post[:amount] = amount(money)
104
+ post[:currency] = options[:currency] || currency(money)
105
+ end
106
+
107
+ def add_invoice(post, options)
108
+ post[:ordernum] = format_order_number(options[:order_id])
109
+ post[:posc] = POS_CODES[:internet_secure]
110
+ end
111
+
112
+ def add_creditcard(post, credit_card)
113
+ post[:cardnumber] = credit_card.number
114
+ post[:cvd] = credit_card.verification_value
115
+ post[:expirationdate] = expdate(credit_card)
116
+ end
117
+
118
+ def add_reference(post, identification)
119
+ post[:transaction] = identification
120
+ end
121
+
122
+ def commit(action, params)
123
+
124
+ if result = test_result_from_cc_number(params[:cardnumber])
125
+ return result
126
+ end
127
+
128
+ data = ssl_post URL, post_data(action, params)
129
+
130
+ @response = parse(data)
131
+
132
+ success = @response[:qpstat] == APPROVED
133
+ message = message_from(@response)
134
+
135
+ Response.new(success, message, @response,
136
+ :test => test?,
137
+ :authorization => @response[:transaction]
138
+ )
139
+ end
140
+
141
+ def parse(data)
142
+ response = {}
143
+
144
+ doc = REXML::Document.new(data)
145
+
146
+ doc.root.attributes.each do |name, value|
147
+ response[name.to_sym] = value
148
+ end
149
+
150
+ response
151
+ end
152
+
153
+ def message_from(response)
154
+ case response[:qpstat]
155
+ when '008'
156
+ response[:qpstatmsg].to_s.scan(/[A-Z][a-z0-9 \/]+/).to_sentence
157
+ else
158
+ response[:qpstatmsg].to_s
159
+ end
160
+ end
161
+
162
+ def post_data(action, params = {})
163
+ params[:merchant] = @options[:login]
164
+ params[:msgtype] = TRANSACTIONS[action]
165
+
166
+ check_field = (action == :authorization) ? :md5checkV2 : :md5check
167
+ params[check_field] = generate_check_hash(action, params)
168
+
169
+ request = params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
170
+ request
171
+ end
172
+
173
+ def generate_check_hash(action, params)
174
+ string = MD5_CHECK_FIELDS[action].collect do |key|
175
+ params[key]
176
+ end.join('')
177
+
178
+ # Add the md5checkword
179
+ string << @options[:password].to_s
180
+
181
+ Digest::MD5.hexdigest(string)
182
+ end
183
+
184
+ def expdate(credit_card)
185
+ year = format(credit_card.year, :two_digits)
186
+ month = format(credit_card.month, :two_digits)
187
+
188
+ "#{year}#{month}"
189
+ end
190
+
191
+ def format_order_number(number)
192
+ number.to_s.gsub(/[^0-9]/, '').rjust(4, "0")
193
+ end
194
+ end
195
+ end
196
+ end
197
+
@@ -0,0 +1,212 @@
1
+ require 'rexml/document'
2
+ require 'digest/sha1'
3
+
4
+ module ActiveMerchant
5
+ module Billing
6
+ # Realex us 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
+ attr_reader :url
46
+ attr_reader :response
47
+ attr_reader :options
48
+
49
+ def initialize(options = {})
50
+ requires!(options, :login, :password)
51
+ @options = options
52
+ super
53
+ end
54
+
55
+ def purchase(money, credit_card, options = {})
56
+ requires!(options, :order_id)
57
+
58
+ request = build_purchase_or_authorization_request(:purchase, money, credit_card, options)
59
+ commit(request)
60
+ end
61
+
62
+ private
63
+ def commit(request)
64
+ if result = test_result_from_cc_number(parse_credit_card_number(request))
65
+ return result
66
+ end
67
+
68
+ data = ssl_post(URL, request)
69
+
70
+ @response = parse(data)
71
+
72
+ success = @response[:result] == "00"
73
+ test = response[:message] =~ /\[ test system \]/
74
+
75
+ Response.new(success, message_from(@response), @response,
76
+ :test => test,
77
+ :authorization => @response[:authcode]
78
+ )
79
+ end
80
+
81
+ def parse(xml)
82
+ response = {}
83
+
84
+ xml = REXML::Document.new(xml)
85
+ xml.elements.each('//response/*') do |node|
86
+
87
+ if (node.elements.size == 0)
88
+ response[node.name.downcase.to_sym] = normalize(node.text)
89
+ else
90
+ node.elements.each do |childnode|
91
+ name = "#{node.name.downcase}_#{childnode.name.downcase}"
92
+ response[name.to_sym] = normalize(childnode.text)
93
+ end
94
+ end
95
+
96
+ end unless xml.root.nil?
97
+
98
+ response
99
+ end
100
+
101
+ def parse_credit_card_number(request)
102
+ xml = REXML::Document.new(request)
103
+ card_number = REXML::XPath.first(xml, '/request/card/number')
104
+ card_number && card_number.text
105
+ end
106
+
107
+ def build_purchase_or_authorization_request(action, money, credit_card, options)
108
+ timestamp = Time.now.strftime('%Y%m%d%H%M%S')
109
+
110
+ xml = Builder::XmlMarkup.new :indent => 2
111
+ xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'auth' do
112
+
113
+ xml.tag! 'merchantid', @options[:login]
114
+ xml.tag! 'account', @options[:account]
115
+
116
+ xml.tag! 'orderid', sanitize_order_id(options[:order_id])
117
+ xml.tag! 'amount', amount(money), 'currency' => options[:currency] || currency(money)
118
+
119
+ xml.tag! 'card' do
120
+ xml.tag! 'number', credit_card.number
121
+ xml.tag! 'expdate', expiry_date(credit_card)
122
+ xml.tag! 'type', CARD_MAPPING[credit_card.type.to_s]
123
+ xml.tag! 'chname', credit_card.name
124
+ xml.tag! 'issueno', credit_card.issue_number
125
+
126
+ xml.tag! 'cvn' do
127
+ xml.tag! 'number', credit_card.verification_value
128
+ xml.tag! 'presind', credit_card.verification_value? ? 1 : nil
129
+ end
130
+ end
131
+
132
+ xml.tag! 'autosettle', 'flag' => auto_settle_flag(action)
133
+ xml.tag! 'sha1hash', sha1from("#{timestamp}.#{@options[:login]}.#{sanitize_order_id(options[:order_id])}.#{amount(money)}.#{options[:currency] || currency(money)}.#{credit_card.number}")
134
+ xml.tag! 'comments' do
135
+ xml.tag! 'comment', options[:description], 'id' => 1
136
+ xml.tag! 'comment', 'id' => 2
137
+ end
138
+
139
+ billing_address = options[:billing_address] || options[:address] || {}
140
+ shipping_address = options[:shipping_address] || billing_address
141
+
142
+ xml.tag! 'tssinfo' do
143
+ xml.tag! 'address', 'type' => 'billing' do
144
+ xml.tag! 'code', billing_address[:zip]
145
+ xml.tag! 'country', billing_address[:country]
146
+ end
147
+
148
+ xml.tag! 'address', 'type' => 'shipping' do
149
+ xml.tag! 'code', shipping_address[:zip]
150
+ xml.tag! 'country', shipping_address[:country]
151
+ end
152
+
153
+ xml.tag! 'custnum', options[:customer]
154
+
155
+ xml.tag! 'prodid', options[:invoice]
156
+ xml.tag! 'varref'
157
+ end
158
+ end
159
+
160
+ xml.target!
161
+ end
162
+
163
+ def auto_settle_flag(action)
164
+ action == :authorization ? '0' : '1'
165
+ end
166
+
167
+ def expiry_date(credit_card)
168
+ "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
169
+ end
170
+
171
+ def sha1from(string)
172
+ Digest::SHA1.hexdigest("#{Digest::SHA1.hexdigest(string)}.#{@options[:password]}")
173
+ end
174
+
175
+ def normalize(field)
176
+ case field
177
+ when "true" then true
178
+ when "false" then false
179
+ when "" then nil
180
+ when "null" then nil
181
+ else field
182
+ end
183
+ end
184
+
185
+ def message_from(response)
186
+ message = nil
187
+ case response[:result]
188
+ when "00"
189
+ message = SUCCESS
190
+ when "101"
191
+ message = response[:message]
192
+ when "102", "103"
193
+ message = DECLINED
194
+ when /^2[0-9][0-9]/
195
+ message = BANK_ERROR
196
+ when /^3[0-9][0-9]/
197
+ message = REALEX_ERROR
198
+ when /^5[0-9][0-9]/
199
+ message = ERROR
200
+ when "666"
201
+ message = CLIENT_DEACTIVATED
202
+ else
203
+ message = DECLINED
204
+ end
205
+ end
206
+
207
+ def sanitize_order_id(order_id)
208
+ order_id.to_s.gsub(/[^a-zA-Z0-9\-_]/, '')
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/authorize_net'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class SecurePayGateway < AuthorizeNetGateway
6
+ self.live_url = self.test_url = 'https://www.securepay.com/AuthSpayAdapter/process.aspx'
7
+
8
+ self.homepage_url = 'http://www.securepay.com/'
9
+ self.display_name = 'SecurePay'
10
+
11
+ # Limit support to purchase() for the time being
12
+ # JRuby chokes here
13
+ # undef_method :authorize, :capture, :void, :credit
14
+
15
+ undef_method :authorize
16
+ undef_method :capture
17
+ undef_method :void
18
+ undef_method :credit
19
+
20
+ def test?
21
+ Base.gateway_mode == :test
22
+ end
23
+
24
+ private
25
+ def split(response)
26
+ response.split('%')
27
+ end
28
+ end
29
+ end
30
+ end
31
+
@@ -0,0 +1,136 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class TransFirstGateway < Gateway
4
+ URL = 'https://webservices.primerchants.com/creditcard.asmx/CCSale'
5
+
6
+ attr_reader :url
7
+ attr_reader :response
8
+ attr_reader :options
9
+
10
+ self.supported_countries = ['US']
11
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
12
+ self.homepage_url = 'http://www.transfirst.com/'
13
+ self.display_name = 'TransFirst'
14
+
15
+ UNUSED_FIELDS = %w(ECIValue UserId CAVVData TrackData POSInd EComInd MerchZIP MerchCustPNum MCC InstallmentNum InstallmentOf POSEntryMode POSConditionCode AuthCharInd CardCertData)
16
+
17
+ DECLINED = 'The transaction was declined'
18
+
19
+ def initialize(options = {})
20
+ requires!(options, :login, :password)
21
+ @options = options
22
+ super
23
+ end
24
+
25
+ def purchase(money, credit_card, options = {})
26
+ post = {}
27
+
28
+ add_amount(post, money)
29
+ add_invoice(post, options)
30
+ add_credit_card(post, credit_card)
31
+ add_address(post, options)
32
+
33
+ commit(post)
34
+ end
35
+
36
+ private
37
+ def add_amount(post, money)
38
+ add_pair(post, :Amount, amount(money), :required => true)
39
+ end
40
+
41
+ def add_address(post, options)
42
+ address = options[:billing_address] || options[:address]
43
+
44
+ if address
45
+ add_pair(post, :Address, address[:address1])
46
+ add_pair(post, :ZipCode, address[:zip])
47
+ end
48
+ end
49
+
50
+ def add_invoice(post, options)
51
+ add_pair(post, :RefID, options[:order_id], :required => true)
52
+ add_pair(post, :PONumber, options[:invoice], :required => true)
53
+ add_pair(post, :SaleTaxAmount, amount(options[:tax] || 0))
54
+ add_pair(post, :PaymentDesc, options[:description], :required => true)
55
+ add_pair(post, :TaxIndicator, 0)
56
+ end
57
+
58
+ def add_credit_card(post, credit_card)
59
+ add_pair(post, :CardHolderName, credit_card.name, :required => true)
60
+ add_pair(post, :CardNumber, credit_card.number, :required => true)
61
+
62
+ add_pair(post, :Expiration, expdate(credit_card), :required => true)
63
+ add_pair(post, :CVV2, credit_card.verification_value)
64
+ end
65
+
66
+ def add_unused_fields(post)
67
+ UNUSED_FIELDS.each do |f|
68
+ post[f] = ""
69
+ end
70
+ end
71
+
72
+ def expdate(credit_card)
73
+ year = format(credit_card.year, :two_digits)
74
+ month = format(credit_card.month, :two_digits)
75
+
76
+ "#{month}#{year}"
77
+ end
78
+
79
+ def parse(data)
80
+ response = {}
81
+
82
+ xml = REXML::Document.new(data)
83
+ root = REXML::XPath.first(xml, "//CCSaleDebitResponse")
84
+
85
+ if root.nil?
86
+ response[:message] = data.to_s.strip
87
+ else
88
+ root.elements.to_a.each do |node|
89
+ response[node.name.underscore.to_sym] = node.text
90
+ end
91
+ end
92
+
93
+ response
94
+ end
95
+
96
+ def commit(params)
97
+ if result = test_result_from_cc_number(params[:CardNumber])
98
+ return result
99
+ end
100
+
101
+ data = ssl_post URL, post_data(params)
102
+
103
+ @response = parse(data)
104
+ success = @response[:status] == "Authorized"
105
+
106
+ Response.new(success, message_from(@response), @response,
107
+ :test => test?,
108
+ :authorization => @response[:trans_id]
109
+ )
110
+ end
111
+
112
+ def message_from(response)
113
+ case response[:message]
114
+ when 'Call Voice Center'
115
+ DECLINED
116
+ else
117
+ response[:message]
118
+ end
119
+ end
120
+
121
+ def post_data(params = {})
122
+ add_unused_fields(params)
123
+ params[:MerchantID] = @options[:login]
124
+ params[:RegKey] = @options[:password]
125
+
126
+ request = params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
127
+ request
128
+ end
129
+
130
+ def add_pair(post, key, value, options = {})
131
+ post[key] = value if !value.blank? || options[:required]
132
+ end
133
+ end
134
+ end
135
+ end
136
+