activemerchant 1.55.0 → 1.56.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7e8d9130eaadeedc543af0a5b2cf5b060a2f1399
4
- data.tar.gz: 868d04daf3f0dbd97f7f87adb0d96add9e868a57
3
+ metadata.gz: 8a7fa5a42dbb05e1c335a93e8cefc85781e7cbae
4
+ data.tar.gz: 928d0561eab8bc6a0fcac4245ccc2342d4e8fa6a
5
5
  SHA512:
6
- metadata.gz: c079b666da79f7f8e77f47ca08003f2712a5daefb801b927454234c9c25f7b1b7d311e63b9432f758dcbb1594d111a323a8606e8636d50cd45da33a87cc35434
7
- data.tar.gz: 0c77b4dbbf7f9f8b3bcbb5e1ae1bbc9af213cab749a0690b1337d46772813043dc65aefb2cc816b86c26dd8fe42cf53b0ce11cb93de53587bc2af3b55b6ecd49
6
+ metadata.gz: bf1511639e9a72d13e6be69a301e0f0553cd4b52e65205a0e9f777c951e355124c16440182716a622beb5cd56037d98aea1659e1bdf49541b20d0438d2bf3802
7
+ data.tar.gz: 83dd4208bb147e5dce68f4751ff27e7298f03fffa0ef8c32f0f335fbf8fa79b1c4177d4839b236510fc7d9f66bedf98a4237085fbb2dcc94a9509d57f3004feb
data/CHANGELOG CHANGED
@@ -1,5 +1,26 @@
1
1
  = ActiveMerchant CHANGELOG
2
2
 
3
+ == Version 1.56.0 (December 1, 2015)
4
+ * Add Cardknox gateway [dlehren]
5
+ * Mercury: Add support for card present track 2 [ryanbalsdon]
6
+ * Cardstream: Improve default currency handling [duff]
7
+ * Mercury: Strip start and end sentinels on track 2 [ryanbalsdon]
8
+ * Redsys: Support new SHA256 authentication method [davidsantoso]
9
+ * Cashnet: Allow custcode override [duff]
10
+ * Add Rails 5 support [rafaelfranca]
11
+ * Set required Ruby version for install to 2 or greater [rafaelfranca]
12
+ * JetPay: Pass ud_fields in capture too [duff]
13
+ * Stripe: Correctly detect test mode refunds [aprofeit]
14
+ * Fix variables in remote gateways test template [sdball]
15
+ * Micropayment: Update fieldnames for new API [duff]
16
+ * Fix CreditCard#valid_number? erroring on non-digit characters [PatrickTulskie]
17
+ * Stripe: Correctly detect test mode voids [methodmissing]
18
+ * Garanti: Add test mode URL and update remote test credentials [cbilgili]
19
+ * Cashnet: Allow custcode override on refund [duff]
20
+ * Omise: Add a new optional api_version config [zdk]
21
+ * Elavon: Include IP address in purchase and authorize requests [aprofeit]
22
+ * TransFirst: Add support for ACH and more operations [davidsantoso]
23
+ * FirstData_e4: Fix void for even dollar transactions [duff]
3
24
 
4
25
  == Version 1.55.0 (November 9, 2015)
5
26
  * CyberSource: send customer IP address when provided [fastjames]
@@ -51,6 +72,7 @@
51
72
  * PayBox Direct: Refunds and working test credentials [ivanfer]
52
73
  * Vanco: Handle case of no billing_address [duff]
53
74
  * BluePay: Add support for CUSTOM_ID2 field [ajporterfield]
75
+ * Creditcall: Handle no verification_value [duff]
54
76
 
55
77
  == Version 1.54.0 (October 2, 2015)
56
78
  * Beanstream: Add Network Tokenization support [girasquid]
data/CONTRIBUTORS CHANGED
@@ -562,3 +562,7 @@ Payeezy (October 2015)
562
562
  Clearhaus (October 2015)
563
563
 
564
564
  * Dinesh Yadav (dinesh)
565
+
566
+ Cardknox (November 2015)
567
+
568
+ * (dlehren)
data/README.md CHANGED
@@ -97,6 +97,7 @@ The [ActiveMerchant Wiki](http://github.com/activemerchant/active_merchant/wikis
97
97
  * [Borgun](https://www.borgun.is/) - IS
98
98
  * [Braintree](http://www.braintreepaymentsolutions.com) - US, CA, AU, AD, AT, BE, BG, CY, CZ, DK, EE, FI, FR, GI, DE, GR, HU, IS, IM, IE, IT, LV, LI, LT, LU, MT, MC, NL, NO, PL, PT, RO, SM, SK, SI, ES, SE, CH, TR, GB
99
99
  * [BridgePay](http://www.bridgepaynetwork.com/) - CA, US
100
+ * [Cardknox](https://www.cardknox.com/) - US, CA, GB
100
101
  * [CardSave](http://www.cardsave.net/) - GB
101
102
  * [CardStream](http://www.cardstream.com/) - GB
102
103
  * [Cashnet](http://www.higherone.com/) - US
@@ -33,7 +33,6 @@ if(!defined?(ActiveSupport::VERSION) || (ActiveSupport::VERSION::STRING < "4.1")
33
33
  require 'active_support/core_ext/class/attribute_accessors'
34
34
  end
35
35
 
36
- require 'active_support/core_ext/class/delegating_attributes'
37
36
  require 'active_support/core_ext/module/attribute_accessors'
38
37
 
39
38
  require 'base64'
@@ -68,6 +68,7 @@ module ActiveMerchant #:nodoc:
68
68
  def valid_number?(number)
69
69
  valid_test_mode_card_number?(number) ||
70
70
  valid_card_number_length?(number) &&
71
+ valid_card_number_characters?(number) &&
71
72
  valid_checksum?(number)
72
73
  end
73
74
 
@@ -138,6 +139,10 @@ module ActiveMerchant #:nodoc:
138
139
  number.to_s.length >= 12
139
140
  end
140
141
 
142
+ def valid_card_number_characters?(number) #:nodoc:
143
+ !number.to_s.match(/\D/)
144
+ end
145
+
141
146
  def valid_test_mode_card_number?(number) #:nodoc:
142
147
  ActiveMerchant::Billing::Base.test? &&
143
148
  %w[1 2 3 success failure error].include?(number.to_s)
@@ -6,8 +6,8 @@ module ActiveMerchant #:nodoc:
6
6
  self.display_name = "BridgePay"
7
7
  self.homepage_url = "http://www.bridgepaynetwork.com/"
8
8
 
9
- self.test_url = "https://gatewaystage.itstgate.com/SmartPayments/transact.asmx/ProcessCreditCard"
10
- self.live_url = "https://gateway.itstgate.com/SmartPayments/transact.asmx/ProcessCreditCard"
9
+ self.test_url = "https://gatewaystage.itstgate.com/SmartPayments/transact.asmx"
10
+ self.live_url = "https://gateway.itstgate.com/SmartPayments/transact.asmx"
11
11
 
12
12
  self.supported_countries = ["CA", "US"]
13
13
  self.default_currency = "USD"
@@ -19,30 +19,30 @@ module ActiveMerchant #:nodoc:
19
19
  super
20
20
  end
21
21
 
22
- def purchase(amount, creditcard, options={})
23
- post = post_required_fields("Sale")
22
+ def purchase(amount, payment_method, options={})
23
+ post = initialize_required_fields("Sale")
24
24
 
25
25
  # Allow the same amount in multiple transactions.
26
26
  post[:ExtData] = "<Force>T</Force>"
27
27
  add_invoice(post, amount, options)
28
- add_creditcard(post, creditcard)
28
+ add_payment_method(post, payment_method)
29
29
  add_customer_data(post, options)
30
30
 
31
31
  commit(post)
32
32
  end
33
33
 
34
- def authorize(amount, creditcard, options={})
35
- post = post_required_fields("Auth")
34
+ def authorize(amount, payment_method, options={})
35
+ post = initialize_required_fields("Auth")
36
36
 
37
37
  add_invoice(post, amount, options)
38
- add_creditcard(post, creditcard)
38
+ add_payment_method(post, payment_method)
39
39
  add_customer_data(post, options)
40
40
 
41
41
  commit(post)
42
42
  end
43
43
 
44
44
  def capture(amount, authorization, options={})
45
- post = post_required_fields("Force")
45
+ post = initialize_required_fields("Force")
46
46
 
47
47
  add_invoice(post, amount, options)
48
48
  add_reference(post, authorization)
@@ -52,7 +52,7 @@ module ActiveMerchant #:nodoc:
52
52
  end
53
53
 
54
54
  def refund(amount, authorization, options={})
55
- post = post_required_fields("Return")
55
+ post = initialize_required_fields("Return")
56
56
 
57
57
  add_invoice(post, amount, options)
58
58
  add_reference(post, authorization)
@@ -61,7 +61,7 @@ module ActiveMerchant #:nodoc:
61
61
  end
62
62
 
63
63
  def void(authorization, options={})
64
- post = post_required_fields("Void")
64
+ post = initialize_required_fields("Void")
65
65
 
66
66
  add_reference(post, authorization)
67
67
 
@@ -75,9 +75,37 @@ module ActiveMerchant #:nodoc:
75
75
  end
76
76
  end
77
77
 
78
+ def supports_scrubbing?
79
+ true
80
+ end
81
+
82
+ def scrub(transcript)
83
+ transcript.
84
+ gsub(%r((&?CardNum=)[^&]*)i, '\1[FILTERED]').
85
+ gsub(%r((&?CVNum=)[^&]*)i, '\1[FILTERED]').
86
+ gsub(%r((&?Password=)[^&]*)i, '\1[FILTERED]').
87
+ gsub(%r((&?TransitNum=)[^&]*)i, '\1[FILTERED]').
88
+ gsub(%r((&?AccountNum=)[^&]*)i, '\1[FILTERED]')
89
+ end
90
+
78
91
  private
79
92
 
80
- def post_required_fields(transaction_type)
93
+ def add_payment_method(post, payment_method)
94
+ if payment_method.respond_to? :brand
95
+ post[:NameOnCard] = payment_method.name if payment_method.name
96
+ post[:ExpDate] = expdate(payment_method)
97
+ post[:CardNum] = payment_method.number
98
+ post[:CVNum] = payment_method.verification_value
99
+ else
100
+ post[:CheckNum] = payment_method.number
101
+ post[:TransitNum] = payment_method.routing_number
102
+ post[:AccountNum] = payment_method.account_number
103
+ post[:NameOnCheck] = payment_method.name
104
+ post[:ExtData] = "<AccountType>#{payment_method.account_type.capitalize}</AccountType>"
105
+ end
106
+ end
107
+
108
+ def initialize_required_fields(transaction_type)
81
109
  post = {}
82
110
  post[:TransType] = transaction_type
83
111
  post[:Amount] = ""
@@ -92,6 +120,12 @@ module ActiveMerchant #:nodoc:
92
120
  post[:CVNum] = ""
93
121
  post[:MagData] = ""
94
122
  post[:ExtData] = ""
123
+ post[:MICR] = ""
124
+ post[:DL] = ""
125
+ post[:SS] = ""
126
+ post[:DOB] = ""
127
+ post[:StateCode] = ""
128
+ post[:CheckType] = ""
95
129
  post
96
130
  end
97
131
 
@@ -107,13 +141,6 @@ module ActiveMerchant #:nodoc:
107
141
  post[:InvNum] = options[:order_id]
108
142
  end
109
143
 
110
- def add_creditcard(post, creditcard)
111
- post[:NameOnCard] = creditcard.name if creditcard.name
112
- post[:ExpDate] = expdate(creditcard)
113
- post[:CardNum] = creditcard.number
114
- post[:CVNum] = creditcard.verification_value
115
- end
116
-
117
144
  def expdate(creditcard)
118
145
  "#{format(creditcard.month, :two_digits)}#{format(creditcard.year, :two_digits)}"
119
146
  end
@@ -137,12 +164,12 @@ module ActiveMerchant #:nodoc:
137
164
  end
138
165
 
139
166
  def commit(parameters)
140
- url = (test? ? test_url : live_url)
167
+ url = url(parameters[:TransitNum] ? 'ProcessCheck' : 'ProcessCreditCard')
141
168
  data = post_data(parameters)
142
169
  raw = parse(ssl_post(url, data))
143
170
 
144
171
  Response.new(
145
- success_from(raw[:respmsg]),
172
+ success_from(raw),
146
173
  message_from(raw),
147
174
  raw,
148
175
  authorization: authorization_from(raw),
@@ -150,17 +177,17 @@ module ActiveMerchant #:nodoc:
150
177
  )
151
178
  end
152
179
 
153
- def success_from(result)
154
- case result
155
- when "Approved"
156
- true
157
- else
158
- false
159
- end
180
+ def url(action)
181
+ base = test? ? test_url : live_url
182
+ "#{base}/#{action}"
183
+ end
184
+
185
+ def success_from(response)
186
+ response[:result] == "0"
160
187
  end
161
188
 
162
189
  def message_from(response)
163
- response[:respmsg]
190
+ response[:respmsg] || response[:message]
164
191
  end
165
192
 
166
193
  def authorization_from(response)
@@ -14,6 +14,7 @@ module ActiveMerchant #:nodoc:
14
14
 
15
15
  CURRENCY_CODES = {
16
16
  "AUD" => '036',
17
+ "BRL" => '986',
17
18
  "CAD" => '124',
18
19
  "CZK" => '203',
19
20
  "DKK" => '208',
@@ -132,7 +133,7 @@ module ActiveMerchant #:nodoc:
132
133
 
133
134
  def add_amount(post, money, options)
134
135
  add_pair(post, :amount, amount(money), :required => true)
135
- add_pair(post, :currencyCode, currency_code(options[:currency] || currency(money)) || currency_code(self.default_currency))
136
+ add_pair(post, :currencyCode, currency_code(options[:currency] || currency(money)))
136
137
  end
137
138
 
138
139
  def add_customer_data(post, options)
@@ -0,0 +1,328 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class CardknoxGateway < Gateway
4
+ self.live_url = 'https://x1.cardknox.com/gateway'
5
+
6
+ self.supported_countries = ['US','CA','GB']
7
+ self.default_currency = 'USD'
8
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
9
+
10
+ self.homepage_url = 'https://www.cardknox.com/'
11
+ self.display_name = 'Cardknox'
12
+
13
+ COMMANDS = {
14
+ credit_card: {
15
+ purchase: 'cc:sale',
16
+ authorization: 'cc:authonly',
17
+ capture: 'cc:capture',
18
+ refund: 'cc:refund',
19
+ void: 'cc:void',
20
+ save: 'cc:save'
21
+ },
22
+ check: {
23
+ purchase: 'check:sale',
24
+ refund: 'check:refund',
25
+ void: 'check:void',
26
+ save: 'check:save'
27
+ }
28
+ }
29
+
30
+ def initialize(options={})
31
+ requires!(options, :api_key)
32
+ super
33
+ end
34
+
35
+ # There are three sources for doing a purchase transation:
36
+ # - credit card
37
+ # - check
38
+ # - cardknox token, which is returned in the the authorization string "ref_num;token;command"
39
+
40
+ def purchase(amount, source, options={})
41
+ post = {}
42
+ add_amount(post, amount, options)
43
+ add_invoice(post, options)
44
+ add_source(post, source)
45
+ add_address(post, source, options)
46
+ add_customer_data(post, options)
47
+ add_custom_fields(post, options)
48
+ commit(:purchase, source_type(source), post)
49
+ end
50
+
51
+ def authorize(amount, source, options={})
52
+ post = {}
53
+ add_amount(post, amount)
54
+ add_invoice(post, options)
55
+ add_source(post, source)
56
+ add_address(post, source, options)
57
+ add_customer_data(post, options)
58
+ add_custom_fields(post, options)
59
+ commit(:authorization, source_type(source), post)
60
+ end
61
+
62
+ def capture(amount, authorization, options = {})
63
+ post = {}
64
+ add_reference(post, authorization)
65
+ add_amount(post, amount)
66
+ commit(:capture, source_type(authorization), post)
67
+ end
68
+
69
+ def refund(amount, authorization, options={})
70
+ post = {}
71
+ add_reference(post, authorization)
72
+ add_amount(post, amount)
73
+ commit(:refund, source_type(authorization), post)
74
+ end
75
+
76
+ def void(authorization, options = {})
77
+ post = {}
78
+ add_reference(post, authorization)
79
+ commit(:void, source_type(authorization), post)
80
+ end
81
+
82
+ def verify(credit_card, options={})
83
+ MultiResponse.run(:use_first_response) do |r|
84
+ r.process { authorize(100, credit_card, options) }
85
+ r.process(:ignore_result) { void(r.authorization, options) }
86
+ end
87
+ end
88
+
89
+ def store(source, options = {})
90
+ post = {}
91
+ add_source(post, source)
92
+ add_address(post, source, options)
93
+ add_invoice(post, options)
94
+ add_customer_data(post, options)
95
+ add_custom_fields(post, options)
96
+ commit(:save, source_type(source), post)
97
+ end
98
+
99
+ def supports_scrubbing?
100
+ true
101
+ end
102
+
103
+ def scrub(transcript)
104
+ transcript.
105
+ gsub(%r((xCardNum=)\d+), '\1[FILTERED]').
106
+ gsub(%r((xCVV=)\d+), '\1[FILTERED]').
107
+ gsub(%r((xAccount=)\d+), '\1[FILTERED]').
108
+ gsub(%r((xRouting=)\d+), '\1[FILTERED]').
109
+ gsub(%r((xKey=)\w+), '\1[FILTERED]')
110
+ end
111
+
112
+ private
113
+
114
+ def split_authorization(authorization)
115
+ authorization.split(";")
116
+ end
117
+
118
+ def add_reference(post, reference)
119
+ reference, _, _ = split_authorization(reference)
120
+ post[:Refnum] = reference
121
+ end
122
+
123
+ def source_type(source)
124
+ if source.respond_to?(:brand)
125
+ :credit_card
126
+ elsif source.respond_to?(:routing_number)
127
+ :check
128
+ elsif source.kind_of?(String)
129
+ source_type_from(source)
130
+ else
131
+ raise ArgumentError, "Unknown source #{source.inspect}"
132
+ end
133
+ end
134
+
135
+ def source_type_from(authorization)
136
+ _, _, source_type = split_authorization(authorization)
137
+ (source_type || "credit_card").to_sym
138
+ end
139
+
140
+ def add_source(post, source)
141
+ if source.respond_to?(:brand)
142
+ add_credit_card(post, source)
143
+ elsif source.respond_to?(:routing_number)
144
+ add_check(post, source)
145
+ elsif source.kind_of?(String)
146
+ add_cardknox_token(post, source)
147
+ else
148
+ raise ArgumentError, "Invalid payment source #{source.inspect}"
149
+ end
150
+ end
151
+
152
+ # Subtotal + Tax + Tip = Amount.
153
+
154
+ def add_amount(post, money, options = {})
155
+ post[:Tip] = amount(options[:tip])
156
+ post[:Amount] = amount(money)
157
+ end
158
+
159
+ def expdate(credit_card)
160
+ year = format(credit_card.year, :two_digits)
161
+ month = format(credit_card.month, :two_digits)
162
+ "#{month}#{year}"
163
+ end
164
+
165
+ def add_customer_data(post, options)
166
+ address = options[:billing_address] || {}
167
+ post[:Street] = address[:address1]
168
+ post[:Zip] = address[:zip]
169
+ post[:PONum] = options[:po_number]
170
+ post[:Fax] = options[:fax]
171
+ post[:Email] = options[:email]
172
+ post[:IP] = options[:ip]
173
+ end
174
+
175
+ def add_address(post, source, options)
176
+ add_address_for_type(:billing, post, source, options[:billing_address]) if options[:billing_address]
177
+ add_address_for_type(:shipping, post, source, options[:shipping_address]) if options[:shipping_address]
178
+ end
179
+
180
+ def add_address_for_type(type, post, source, address)
181
+ prefix = address_key_prefix(type)
182
+ if source.respond_to?(:first_name)
183
+ post[address_key(prefix, 'FirstName')] = source.first_name
184
+ post[address_key(prefix, 'LastName')] = source.last_name
185
+ else
186
+ post[address_key(prefix, 'FirstName')] = address[:first_name]
187
+ post[address_key(prefix, 'LastName')] = address[:last_name]
188
+ end
189
+ post[address_key(prefix, 'MiddleName')] = address[:middle_name]
190
+
191
+ post[address_key(prefix, 'Company')] = address[:company]
192
+ post[address_key(prefix, 'Street')] = address[:address1]
193
+ post[address_key(prefix, 'Street2')] = address[:address2]
194
+ post[address_key(prefix, 'City')] = address[:city]
195
+ post[address_key(prefix, 'State')] = address[:state]
196
+ post[address_key(prefix, 'Zip')] = address[:zip]
197
+ post[address_key(prefix, 'Country')] = address[:country]
198
+ post[address_key(prefix, 'Phone')] = address[:phone]
199
+ post[address_key(prefix, 'Mobile')] = address[:mobile]
200
+ end
201
+
202
+ def address_key_prefix(type)
203
+ case type
204
+ when :shipping then 'Ship'
205
+ when :billing then 'Bill'
206
+ else
207
+ raise ArgumentError, "Unknown address key prefix: #{type}"
208
+ end
209
+ end
210
+
211
+ def address_key(prefix, key)
212
+ "#{prefix}#{key}".to_sym
213
+ end
214
+
215
+ def add_invoice(post, options)
216
+ post[:Invoice] = options[:invoice]
217
+ post[:OrderID] = options[:order_id]
218
+ post[:Comments] = options[:comments]
219
+ post[:Description] = options[:description]
220
+ post[:Tax] = amount(options[:tax])
221
+ end
222
+
223
+ def add_custom_fields(post, options)
224
+ options.keys.grep(/^custom(?:[01]\d|20)$/) do |key|
225
+ post[key.to_s.capitalize] = options[key]
226
+ end
227
+ end
228
+
229
+ def add_credit_card(post, credit_card)
230
+ if credit_card.track_data.present?
231
+ post[:Magstripe] = credit_card.track_data
232
+ post[:Cardpresent] = true
233
+ else
234
+ post[:CardNum] = credit_card.number
235
+ post[:CVV] = credit_card.verification_value
236
+ post[:Exp] = expdate(credit_card)
237
+ post[:Name] = credit_card.name
238
+ post[:CardPresent] = true if credit_card.manual_entry
239
+ end
240
+ end
241
+
242
+ def add_check(post, check)
243
+ post[:Routing] = check.routing_number
244
+ post[:Account] = check.account_number
245
+ post[:Name] = check.name
246
+ post[:CheckNum] = check.number
247
+ end
248
+
249
+ def add_cardknox_token(post, authorization)
250
+ _, token, _ = split_authorization(authorization)
251
+
252
+ post[:Token] = token
253
+ end
254
+
255
+ def parse(body)
256
+ fields = {}
257
+ for line in body.split('&')
258
+ key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
259
+ fields[key] = CGI.unescape(value.to_s)
260
+ end
261
+
262
+ {
263
+ result: fields['xResult'],
264
+ status: fields['xStatus'],
265
+ error: fields['xError'],
266
+ auth_code: fields['xAuthCode'],
267
+ ref_num: fields['xRefNum'],
268
+ current_ref_num: fields['xRefNumCurrent'],
269
+ token: fields['xToken'],
270
+ batch: fields['xBatch'],
271
+ avs_result: fields['xAvsResult'],
272
+ avs_result_code: fields['xAvsResultCode'],
273
+ cvv_result: fields['xCvvResult'],
274
+ cvv_result_code: fields['xCvvResultCode'],
275
+ remaining_balance: fields['xRemainingBalance'],
276
+ amount: fields['xAuthAmount'],
277
+ masked_card_num: fields['xMaskedCardNumber'],
278
+ masked_account_number: fields['MaskedAccountNumber']
279
+ }.delete_if{|k, v| v.nil?}
280
+ end
281
+
282
+
283
+ def commit(action, source_type, parameters)
284
+ response = parse(ssl_post(live_url, post_data(COMMANDS[source_type][action], parameters)))
285
+
286
+ Response.new(
287
+ (response[:status] == 'Approved'),
288
+ message_from(response),
289
+ response,
290
+ authorization: authorization_from(response, source_type),
291
+ avs_result: { code: response[:avs_result_code] },
292
+ cvv_result: response[:cvv_result_code]
293
+ )
294
+ end
295
+
296
+ def message_from(response)
297
+ if response[:status] == "Approved"
298
+ "Success"
299
+ elsif response[:error].blank?
300
+ "Unspecified error"
301
+ else
302
+ response[:error]
303
+ end
304
+ end
305
+
306
+ def authorization_from(response, source_type)
307
+ "#{response[:ref_num]};#{response[:token]};#{source_type}"
308
+ end
309
+
310
+ def post_data(command, parameters = {})
311
+ initial_parameters = {
312
+ Key: @options[:api_key],
313
+ Version: "4.5.4",
314
+ SoftwareName: 'Active Merchant',
315
+ SoftwareVersion: "#{ActiveMerchant::VERSION}",
316
+ Command: command,
317
+ }
318
+
319
+ seed = SecureRandom.hex(32).upcase
320
+ hash = Digest::SHA1.hexdigest("#{initial_parameters[:command]}:#{@options[:pin]}:#{parameters[:amount]}:#{parameters[:invoice]}:#{seed}")
321
+ initial_parameters[:Hash] = "s/#{seed}/#{hash}/n" unless @options[:pin].blank?
322
+ parameters = initial_parameters.merge(parameters)
323
+
324
+ parameters.reject{|k, v| v.blank?}.collect{ |key, value| "x#{key}=#{CGI.escape(value.to_s)}" }.join("&")
325
+ end
326
+ end
327
+ end
328
+ end