tlconnor-activemerchant 1.20.4 → 1.23.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 (58) hide show
  1. data/CHANGELOG +86 -6
  2. data/CONTRIBUTORS +33 -0
  3. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +2 -0
  4. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +4 -4
  5. data/lib/active_merchant/billing/gateways/blue_pay.rb +492 -11
  6. data/lib/active_merchant/billing/gateways/braintree_blue.rb +46 -19
  7. data/lib/active_merchant/billing/gateways/certo_direct.rb +1 -1
  8. data/lib/active_merchant/billing/gateways/elavon.rb +2 -0
  9. data/lib/active_merchant/billing/gateways/epay.rb +3 -1
  10. data/lib/active_merchant/billing/gateways/itransact.rb +450 -0
  11. data/lib/active_merchant/billing/gateways/litle.rb +275 -0
  12. data/lib/active_merchant/billing/gateways/migs.rb +259 -0
  13. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
  14. data/lib/active_merchant/billing/gateways/moneris.rb +4 -30
  15. data/lib/active_merchant/billing/gateways/moneris_us.rb +211 -0
  16. data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
  17. data/lib/active_merchant/billing/gateways/ogone.rb +104 -12
  18. data/lib/active_merchant/billing/gateways/orbital.rb +15 -6
  19. data/lib/active_merchant/billing/gateways/paybox_direct.rb +1 -4
  20. data/lib/active_merchant/billing/gateways/payflow.rb +8 -3
  21. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +4 -1
  22. data/lib/active_merchant/billing/gateways/payflow_express.rb +4 -2
  23. data/lib/active_merchant/billing/gateways/payment_express.rb +60 -13
  24. data/lib/active_merchant/billing/gateways/paypal.rb +3 -18
  25. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +333 -3
  26. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +245 -0
  27. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +43 -0
  28. data/lib/active_merchant/billing/gateways/paypal_express.rb +14 -65
  29. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +8 -3
  30. data/lib/active_merchant/billing/gateways/realex.rb +5 -7
  31. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +3 -2
  32. data/lib/active_merchant/billing/gateways/stripe.rb +1 -9
  33. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +2 -2
  34. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +1 -5
  35. data/lib/active_merchant/billing/gateways/viaklix.rb +7 -2
  36. data/lib/active_merchant/billing/gateways/vindicia.rb +359 -0
  37. data/lib/active_merchant/billing/integrations/dotpay.rb +22 -0
  38. data/lib/active_merchant/billing/integrations/dotpay/helper.rb +77 -0
  39. data/lib/active_merchant/billing/integrations/dotpay/notification.rb +86 -0
  40. data/lib/active_merchant/billing/integrations/dotpay/return.rb +11 -0
  41. data/lib/active_merchant/billing/integrations/epay.rb +21 -0
  42. data/lib/active_merchant/billing/integrations/epay/helper.rb +55 -0
  43. data/lib/active_merchant/billing/integrations/epay/notification.rb +110 -0
  44. data/lib/active_merchant/billing/integrations/paypal/notification.rb +2 -1
  45. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +2 -3
  46. data/lib/active_merchant/billing/integrations/robokassa.rb +49 -0
  47. data/lib/active_merchant/billing/integrations/robokassa/common.rb +19 -0
  48. data/lib/active_merchant/billing/integrations/robokassa/helper.rb +50 -0
  49. data/lib/active_merchant/billing/integrations/robokassa/notification.rb +55 -0
  50. data/lib/active_merchant/billing/integrations/robokassa/return.rb +17 -0
  51. data/lib/active_merchant/billing/integrations/two_checkout.rb +25 -3
  52. data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +58 -26
  53. data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +71 -46
  54. data/lib/active_merchant/billing/integrations/verkkomaksut.rb +20 -0
  55. data/lib/active_merchant/billing/integrations/verkkomaksut/helper.rb +87 -0
  56. data/lib/active_merchant/billing/integrations/verkkomaksut/notification.rb +59 -0
  57. data/lib/active_merchant/version.rb +1 -1
  58. metadata +28 -5
@@ -0,0 +1,275 @@
1
+ require 'rubygems'
2
+ require 'LitleOnline'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ class LitleGateway < Gateway
7
+ # Specific to Litle options:
8
+ # * <tt>:merchant_id</tt> - Merchant Id assigned by Litle
9
+ # * <tt>:user</tt> - Username assigned by Litle
10
+ # * <tt>:password</tt> - Password assigned by Litle
11
+ # * <tt>:version</tt> - The version of the api you are using (eg, '8.10')
12
+ # * <tt>:proxy_addr</tt> - Proxy address - nil if not needed
13
+ # * <tt>:proxy_port</tt> - Proxy port - nil if not needed
14
+ # * <tt>:url</tt> - URL assigned by Litle (for testing, use the sandbox)
15
+ #
16
+ # Standard Active Merchant options
17
+ # * <tt>:order_id</tt> - The order number
18
+ # * <tt>:ip</tt> - The IP address of the customer making the purchase
19
+ # * <tt>:customer</tt> - The name, customer number, or other information that identifies the customer
20
+ # * <tt>:invoice</tt> - The invoice number
21
+ # * <tt>:merchant</tt> - The name or description of the merchant offering the product
22
+ # * <tt>:description</tt> - A description of the transaction
23
+ # * <tt>:email</tt> - The email address of the customer
24
+ # * <tt>:currency</tt> - The currency of the transaction. Only important when you are using a currency that is not the default with a gateway that supports multiple currencies.
25
+ # * <tt>:billing_address</tt> - A hash containing the billing address of the customer.
26
+ # * <tt>:shipping_address</tt> - A hash containing the shipping address of the customer.
27
+ #
28
+ # The <tt>:billing_address</tt>, and <tt>:shipping_address</tt> hashes can have the following keys:
29
+ #
30
+ # * <tt>:name</tt> - The full name of the customer.
31
+ # * <tt>:company</tt> - The company name of the customer.
32
+ # * <tt>:address1</tt> - The primary street address of the customer.
33
+ # * <tt>:address2</tt> - Additional line of address information.
34
+ # * <tt>:city</tt> - The city of the customer.
35
+ # * <tt>:state</tt> - The state of the customer. The 2 digit code for US and Canadian addresses. The full name of the state or province for foreign addresses.
36
+ # * <tt>:country</tt> - The [ISO 3166-1-alpha-2 code](http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm) for the customer.
37
+ # * <tt>:zip</tt> - The zip or postal code of the customer.
38
+ # * <tt>:phone</tt> - The phone number of the customer.
39
+
40
+ TEST_URL = 'https://www.testlitle.com/sandbox/communicator/online'
41
+ LIVE_URL = 'https://payments.litle.com/vap/communicator/online'
42
+
43
+ # The countries the gateway supports merchants from as 2 digit ISO country codes
44
+ self.supported_countries = ['US']
45
+
46
+ # The card types supported by the payment gateway
47
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
48
+
49
+ # The homepage URL of the gateway
50
+ self.homepage_url = 'http://www.litle.com/'
51
+
52
+ # The name of the gateway
53
+ self.display_name = 'Litle & Co.'
54
+
55
+ self.default_currency = 'USD'
56
+
57
+ def initialize(options = {})
58
+ @litle = LitleOnline::LitleOnlineRequest.new
59
+ requires!(options, :merchant_id, :user, :password, :version, :url)
60
+ @options = options
61
+ end
62
+
63
+ def authorize(money, creditcard, options = {})
64
+ to_pass = create_credit_card_hash(money, creditcard, options)
65
+ build_response(:authorization, @litle.authorization(to_pass))
66
+ end
67
+
68
+ def purchase(money, creditcard, options = {})
69
+ to_pass = create_credit_card_hash(money, creditcard, options)
70
+ build_response(:sale, @litle.sale(to_pass))
71
+ end
72
+
73
+ def capture(money, authorization, options = {})
74
+ to_pass = create_capture_hash(money, authorization, options)
75
+ build_response(:capture, @litle.capture(to_pass))
76
+ end
77
+
78
+ def void(identification, options = {})
79
+ to_pass = create_void_hash(identification, options)
80
+ build_response(:void, @litle.void(to_pass))
81
+ end
82
+
83
+ def credit(money, identification, options = {})
84
+ to_pass = create_credit_hash(money, identification, options)
85
+ build_response(:credit, @litle.credit(to_pass))
86
+ end
87
+
88
+ def store(creditcard, options = {})
89
+ to_pass = create_token_hash(creditcard, options)
90
+ build_response(:registerToken, @litle.register_token_request(to_pass), %w(801 802))
91
+ end
92
+
93
+ private
94
+
95
+ CARD_TYPE = {
96
+ 'visa' => 'VI',
97
+ 'master' => 'MC',
98
+ 'american_express' => 'AX',
99
+ 'discover' => 'DI',
100
+ 'jcb' => 'DI',
101
+ 'diners_club' => 'DI'
102
+ }
103
+
104
+ AVS_RESPONSE_CODE = {
105
+ '00' => 'Y',
106
+ '01' => 'X',
107
+ '02' => 'D',
108
+ '10' => 'Z',
109
+ '11' => 'W',
110
+ '12' => 'A',
111
+ '13' => 'A',
112
+ '14' => 'P',
113
+ '20' => 'N',
114
+ '30' => 'S',
115
+ '31' => 'R',
116
+ '32' => 'U',
117
+ '33' => 'R',
118
+ '34' => 'I',
119
+ '40' => 'E'
120
+ }
121
+
122
+ def build_response(kind, litle_response, valid_responses=%w(000))
123
+ if litle_response.response == "0"
124
+ detail = litle_response.send("#{kind}Response")
125
+ Response.new(
126
+ (valid_responses.include?(detail.response)),
127
+ detail.message,
128
+ {:litleOnlineResponse => litle_response},
129
+ :authorization => detail.litleTxnId,
130
+ :avs_result => {:code => fraud_result(detail)['avs']},
131
+ :cvv_result => fraud_result(detail)['cvv']
132
+ )
133
+ else
134
+ Response.new(false, litle_response.message, :litleOnlineResponse => litle_response)
135
+ end
136
+ end
137
+
138
+ def create_credit_card_hash(money, creditcard, options)
139
+ cc_type = CARD_TYPE[creditcard.type]
140
+
141
+ exp_date_yr = creditcard.year.to_s()[2..3]
142
+
143
+ if( creditcard.month.to_s().length == 1 )
144
+ exp_date_mo = '0' + creditcard.month.to_s()
145
+ else
146
+ exp_date_mo = creditcard.month.to_s()
147
+ end
148
+
149
+ exp_date = exp_date_mo + exp_date_yr
150
+
151
+ card_info = {
152
+ 'type' => cc_type,
153
+ 'number' => creditcard.number,
154
+ 'expDate' => exp_date,
155
+ 'cardValidationNum' => creditcard.verification_value
156
+ }
157
+
158
+ hash = create_hash(money, options)
159
+ hash['card'] = card_info
160
+ hash
161
+ end
162
+
163
+ def create_capture_hash(money, authorization, options)
164
+ hash = create_hash(money, options)
165
+ hash['litleTxnId'] = authorization
166
+ hash
167
+ end
168
+
169
+ def create_credit_hash(money, identification, options)
170
+ hash = create_hash(money, options)
171
+ hash['litleTxnId'] = identification
172
+ hash['orderSource'] = nil
173
+ hash['orderId'] = nil
174
+ hash
175
+ end
176
+
177
+ def create_token_hash(creditcard, options)
178
+ hash = create_hash(0, options)
179
+ hash['accountNumber'] = creditcard.number
180
+ hash
181
+ end
182
+
183
+ def create_void_hash(identification, options)
184
+ hash = create_hash(nil, options)
185
+ hash['litleTxnId'] = identification
186
+ hash
187
+ end
188
+
189
+ def create_hash(money, options)
190
+ fraud_check_type = {}
191
+ if options[:ip]
192
+ fraud_check_type['customerIpAddress'] = options[:ip]
193
+ end
194
+
195
+ enhanced_data = {}
196
+ if options[:invoice]
197
+ enhanced_data['invoiceReferenceNumber'] = options[:invoice]
198
+ end
199
+
200
+ if options[:description]
201
+ enhanced_data['customerReference'] = options[:description]
202
+ end
203
+
204
+ if options[:billing_address]
205
+ bill_to_address = {
206
+ 'name' => options[:billing_address][:name],
207
+ 'companyName' => options[:billing_address][:company],
208
+ 'addressLine1' => options[:billing_address][:address1],
209
+ 'addressLine2' => options[:billing_address][:address2],
210
+ 'city' => options[:billing_address][:city],
211
+ 'state' => options[:billing_address][:state],
212
+ 'zip' => options[:billing_address][:zip],
213
+ 'country' => options[:billing_address][:country],
214
+ 'email' => options[:email],
215
+ 'phone' => options[:billing_address][:phone]
216
+ }
217
+ end
218
+ if options[:shipping_address]
219
+ ship_to_address = {
220
+ 'name' => options[:shipping_address][:name],
221
+ 'companyName' => options[:shipping_address][:company],
222
+ 'addressLine1' => options[:shipping_address][:address1],
223
+ 'addressLine2' => options[:shipping_address][:address2],
224
+ 'city' => options[:shipping_address][:city],
225
+ 'state' => options[:shipping_address][:state],
226
+ 'zip' => options[:shipping_address][:zip],
227
+ 'country' => options[:shipping_address][:country],
228
+ 'email' => options[:email],
229
+ 'phone' => options[:shipping_address][:phone]
230
+ }
231
+ end
232
+
233
+ hash = {
234
+ 'billToAddress' => bill_to_address,
235
+ 'shipToAddress' => ship_to_address,
236
+ 'orderId' => (options[:order_id] or @options[:order_id]),
237
+ 'customerId' => options[:customer],
238
+ 'reportGroup' => (options[:merchant] or @options[:merchant]),
239
+ 'merchantId' => (options[:merchant_id] or @options[:merchant_id]),
240
+ 'orderSource' => 'ecommerce',
241
+ 'enhancedData' => enhanced_data,
242
+ 'fraudCheckType' => fraud_check_type,
243
+ 'user' => (options[:user] or @options[:user]),
244
+ 'password' => (options[:password] or @options[:password]),
245
+ 'version' => (options[:version] or @options[:version]),
246
+ 'url' => (options[:url] or @options[:url]),
247
+ 'proxy_addr' => (options[:proxy_addr] or @options[:proxy_addr]),
248
+ 'proxy_port' => (options[:proxy_port] or @options[:proxy_port]),
249
+ 'id' => (options[:id] or options[:order_id] or @options[:order_id])
250
+ }
251
+
252
+ if( !money.nil? && money.to_s.length > 0 )
253
+ hash.merge!({'amount' => money})
254
+ end
255
+ hash
256
+ end
257
+
258
+ def fraud_result(authorization_response)
259
+ if authorization_response.respond_to?('fraudResult')
260
+ fraud_result = authorization_response.fraudResult
261
+ if fraud_result.respond_to?('cardValidationResult')
262
+ cvv_to_pass = fraud_result.cardValidationResult
263
+ if(cvv_to_pass == "")
264
+ cvv_to_pass = "P"
265
+ end
266
+ end
267
+ if fraud_result.respond_to?('avsResult')
268
+ avs_to_pass = AVS_RESPONSE_CODE[fraud_result.avsResult]
269
+ end
270
+ end
271
+ {'cvv'=>cvv_to_pass, 'avs'=>avs_to_pass}
272
+ end
273
+ end
274
+ end
275
+ end
@@ -0,0 +1,259 @@
1
+ require File.dirname(__FILE__) + '/migs/migs_codes'
2
+
3
+ require 'digest/md5' # Used in add_secure_hash
4
+
5
+ module ActiveMerchant #:nodoc:
6
+ module Billing #:nodoc:
7
+ class MigsGateway < Gateway
8
+ include MigsCodes
9
+
10
+ API_VERSION = 1
11
+
12
+ SERVER_HOSTED_URL = 'https://migs.mastercard.com.au/vpcpay'
13
+ MERCHANT_HOSTED_URL = 'https://migs.mastercard.com.au/vpcdps'
14
+
15
+ # MiGS is supported throughout Asia Pacific, Middle East and Africa
16
+ # MiGS is used in Australia (AU) by ANZ (eGate), CBA (CommWeb) and more
17
+ # Source of Country List: http://www.scribd.com/doc/17811923
18
+ self.supported_countries = %w(AU AE BD BN EG HK ID IN JO KW LB LK MU MV MY NZ OM PH QA SA SG TT VN)
19
+
20
+ # The card types supported by the payment gateway
21
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb]
22
+
23
+ self.money_format = :cents
24
+
25
+ # The homepage URL of the gateway
26
+ self.homepage_url = 'http://mastercard.com/mastercardsps'
27
+
28
+ # The name of the gateway
29
+ self.display_name = 'MasterCard Internet Gateway Service (MiGS)'
30
+
31
+ # Creates a new MigsGateway
32
+ # The advanced_login/advanced_password fields are needed for
33
+ # advanced methods such as the capture, refund and status methods
34
+ #
35
+ # ==== Options
36
+ #
37
+ # * <tt>:login</tt> -- The MiGS Merchant ID (REQUIRED)
38
+ # * <tt>:password</tt> -- The MiGS Access Code (REQUIRED)
39
+ # * <tt>:secure_hash</tt> -- The MiGS Secure Hash
40
+ # (Required for Server Hosted payments)
41
+ # * <tt>:advanced_login</tt> -- The MiGS AMA User
42
+ # * <tt>:advanced_password</tt> -- The MiGS AMA User's password
43
+ def initialize(options = {})
44
+ requires!(options, :login, :password)
45
+ @test = options[:login].start_with?('TEST')
46
+ @options = options
47
+ super
48
+ end
49
+
50
+ # ==== Options
51
+ #
52
+ # * <tt>:order_id</tt> -- A reference for tracking the order (REQUIRED)
53
+ # * <tt>:unique_id</tt> -- A unique id for this request (Max 40 chars).
54
+ # If not supplied one will be generated.
55
+ def purchase(money, creditcard, options = {})
56
+ requires!(options, :order_id)
57
+
58
+ post = {}
59
+ post[:Amount] = amount(money)
60
+ add_invoice(post, options)
61
+ add_creditcard(post, creditcard)
62
+ add_standard_parameters('pay', post, options[:unique_id])
63
+
64
+ commit(post)
65
+ end
66
+
67
+ # MiGS works by merchants being either purchase only or authorize/capture
68
+ # So authorize is the same as purchase when in authorize mode
69
+ alias_method :authorize, :purchase
70
+
71
+ # ==== Options
72
+ #
73
+ # * <tt>:unique_id</tt> -- A unique id for this request (Max 40 chars).
74
+ # If not supplied one will be generated.
75
+ def capture(money, authorization, options = {})
76
+ requires!(@options, :advanced_login, :advanced_password)
77
+
78
+ post = options.merge(:TransNo => authorization)
79
+ post[:Amount] = amount(money)
80
+ add_advanced_user(post)
81
+ add_standard_parameters('capture', post, options[:unique_id])
82
+
83
+ commit(post)
84
+ end
85
+
86
+ # ==== Options
87
+ #
88
+ # * <tt>:unique_id</tt> -- A unique id for this request (Max 40 chars).
89
+ # If not supplied one will be generated.
90
+ def refund(money, authorization, options = {})
91
+ requires!(@options, :advanced_login, :advanced_password)
92
+
93
+ post = options.merge(:TransNo => authorization)
94
+ post[:Amount] = amount(money)
95
+ add_advanced_user(post)
96
+ add_standard_parameters('refund', post, options[:unique_id])
97
+
98
+ commit(post)
99
+ end
100
+
101
+ def credit(money, authorization, options = {})
102
+ deprecated CREDIT_DEPRECATION_MESSAGE
103
+ refund(money, authorization, options)
104
+ end
105
+
106
+ # Checks the status of a previous transaction
107
+ # This can be useful when a response is not received due to network issues
108
+ #
109
+ # ==== Parameters
110
+ #
111
+ # * <tt>unique_id</tt> -- Unique id of transaction to find.
112
+ # This is the value of the option supplied in other methods or
113
+ # if not supplied is returned with key :MerchTxnRef
114
+ def status(unique_id)
115
+ requires!(@options, :advanced_login, :advanced_password)
116
+
117
+ post = {}
118
+ add_advanced_user(post)
119
+ add_standard_parameters('queryDR', post, unique_id)
120
+
121
+ commit(post)
122
+ end
123
+
124
+ # Generates a URL to redirect user to MiGS to process payment
125
+ # Once user is finished MiGS will redirect back to specified URL
126
+ # With a response hash which can be turned into a Response object
127
+ # with purchase_offsite_response
128
+ #
129
+ # ==== Options
130
+ #
131
+ # * <tt>:order_id</tt> -- A reference for tracking the order (REQUIRED)
132
+ # * <tt>:locale</tt> -- Change the language of the redirected page
133
+ # Values are 2 digit locale, e.g. en, es
134
+ # * <tt>:return_url</tt> -- the URL to return to once the payment is complete
135
+ # * <tt>:card_type</tt> -- Providing this skips the card type step.
136
+ # Values are ActiveMerchant formats: e.g. master, visa, american_express, diners_club
137
+ # * <tt>:unique_id</tt> -- Unique id of transaction to find.
138
+ # If not supplied one will be generated.
139
+ def purchase_offsite_url(money, options = {})
140
+ requires!(options, :order_id, :return_url)
141
+ requires!(@options, :secure_hash)
142
+
143
+ post = {}
144
+ post[:Amount] = amount(money)
145
+ add_invoice(post, options)
146
+ add_creditcard_type(post, options[:card_type]) if options[:card_type]
147
+
148
+ post.merge!(
149
+ :Locale => options[:locale] || 'en',
150
+ :ReturnURL => options[:return_url]
151
+ )
152
+
153
+ add_standard_parameters('pay', post, options[:unique_id])
154
+
155
+ add_secure_hash(post)
156
+
157
+ SERVER_HOSTED_URL + '?' + post_data(post)
158
+ end
159
+
160
+ # Parses a response from purchase_offsite_url once user is redirected back
161
+ #
162
+ # ==== Parameters
163
+ #
164
+ # * <tt>data</tt> -- All params when offsite payment returns
165
+ # e.g. returns to http://company.com/return?a=1&b=2, then input "a=1&b=2"
166
+ def purchase_offsite_response(data)
167
+ requires!(@options, :secure_hash)
168
+
169
+ response_hash = parse(data)
170
+
171
+ expected_secure_hash = calculate_secure_hash(response_hash.reject{|k, v| k == :SecureHash}, @options[:secure_hash])
172
+ unless response_hash[:SecureHash] == expected_secure_hash
173
+ raise SecurityError, "Secure Hash mismatch, response may be tampered with"
174
+ end
175
+
176
+ response_object(response_hash)
177
+ end
178
+
179
+ private
180
+
181
+ def add_advanced_user(post)
182
+ post[:User] = @options[:advanced_login]
183
+ post[:Password] = @options[:advanced_password]
184
+ end
185
+
186
+ def add_invoice(post, options)
187
+ post[:OrderInfo] = options[:order_id]
188
+ end
189
+
190
+ def add_creditcard(post, creditcard)
191
+ post[:CardNum] = creditcard.number
192
+ post[:CardSecurityCode] = creditcard.verification_value if creditcard.verification_value?
193
+ post[:CardExp] = format(creditcard.year, :two_digits) + format(creditcard.month, :two_digits)
194
+ end
195
+
196
+ def add_creditcard_type(post, card_type)
197
+ post[:Gateway] = 'ssl'
198
+ post[:card] = CARD_TYPES.detect{|ct| ct.am_code == card_type}.migs_long_code
199
+ end
200
+
201
+ def parse(body)
202
+ params = CGI::parse(body)
203
+ hash = {}
204
+ params.each do |key, value|
205
+ hash[key.gsub('vpc_', '').to_sym] = value[0]
206
+ end
207
+ hash
208
+ end
209
+
210
+ def commit(post)
211
+ data = ssl_post MERCHANT_HOSTED_URL, post_data(post)
212
+ response_hash = parse(data)
213
+ response_object(response_hash)
214
+ end
215
+
216
+ def response_object(response)
217
+ Response.new(success?(response), response[:Message], response,
218
+ :test => @test,
219
+ :authorization => response[:TransactionNo],
220
+ :fraud_review => fraud_review?(response),
221
+ :avs_result => { :code => response[:AVSResultCode] },
222
+ :cvv_result => response[:CSCResultCode]
223
+ )
224
+ end
225
+
226
+ def success?(response)
227
+ response[:TxnResponseCode] == '0'
228
+ end
229
+
230
+ def fraud_review?(response)
231
+ ISSUER_RESPONSE_CODES[response[:AcqResponseCode]] == 'Suspected Fraud'
232
+ end
233
+
234
+ def add_standard_parameters(action, post, unique_id = nil)
235
+ post.merge!(
236
+ :Version => API_VERSION,
237
+ :Merchant => @options[:login],
238
+ :AccessCode => @options[:password],
239
+ :Command => action,
240
+ :MerchTxnRef => unique_id || generate_unique_id.slice(0, 40)
241
+ )
242
+ end
243
+
244
+ def post_data(post)
245
+ post.collect { |key, value| "vpc_#{key}=#{CGI.escape(value.to_s)}" }.join("&")
246
+ end
247
+
248
+ def add_secure_hash(post)
249
+ post[:SecureHash] = calculate_secure_hash(post, @options[:secure_hash])
250
+ end
251
+
252
+ def calculate_secure_hash(post, secure_hash)
253
+ sorted_values = post.sort_by(&:to_s).map(&:last)
254
+ input = secure_hash + sorted_values.join
255
+ Digest::MD5.hexdigest(input).upcase
256
+ end
257
+ end
258
+ end
259
+ end