activemerchant 1.47.0 → 1.48.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG +34 -0
  5. data/CONTRIBUTORS +16 -0
  6. data/README.md +8 -2
  7. data/lib/active_merchant/billing/credit_card.rb +16 -4
  8. data/lib/active_merchant/billing/gateway.rb +0 -1
  9. data/lib/active_merchant/billing/gateways/authorize_net.rb +48 -1
  10. data/lib/active_merchant/billing/gateways/axcessms.rb +181 -0
  11. data/lib/active_merchant/billing/gateways/braintree_blue.rb +16 -6
  12. data/lib/active_merchant/billing/gateways/cenpos.rb +272 -0
  13. data/lib/active_merchant/billing/gateways/epay.rb +8 -9
  14. data/lib/active_merchant/billing/gateways/exact.rb +9 -0
  15. data/lib/active_merchant/billing/gateways/fat_zebra.rb +33 -0
  16. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +49 -3
  17. data/lib/active_merchant/billing/gateways/inspire.rb +7 -1
  18. data/lib/active_merchant/billing/gateways/iridium.rb +1 -1
  19. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +2 -2
  20. data/lib/active_merchant/billing/gateways/monei.rb +307 -0
  21. data/lib/active_merchant/billing/gateways/nab_transact.rb +47 -37
  22. data/lib/active_merchant/billing/gateways/netbilling.rb +40 -7
  23. data/lib/active_merchant/billing/gateways/orbital.rb +45 -21
  24. data/lib/active_merchant/billing/gateways/pay_conex.rb +246 -0
  25. data/lib/active_merchant/billing/gateways/pay_hub.rb +213 -0
  26. data/lib/active_merchant/billing/gateways/paymill.rb +3 -2
  27. data/lib/active_merchant/billing/gateways/pin.rb +2 -2
  28. data/lib/active_merchant/billing/gateways/quickbooks.rb +6 -4
  29. data/lib/active_merchant/billing/gateways/qvalent.rb +179 -0
  30. data/lib/active_merchant/billing/gateways/redsys.rb +29 -15
  31. data/lib/active_merchant/billing/gateways/sage_pay.rb +1 -1
  32. data/lib/active_merchant/billing/gateways/stripe.rb +12 -3
  33. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +8 -3
  34. data/lib/active_merchant/billing/gateways/worldpay.rb +2 -2
  35. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +205 -0
  36. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +12 -4
  37. data/lib/active_merchant/billing/response.rb +1 -1
  38. data/lib/active_merchant/posts_data.rb +6 -0
  39. data/lib/active_merchant/version.rb +1 -1
  40. data/lib/support/outbound_hosts.rb +13 -10
  41. metadata +9 -2
  42. metadata.gz.sig +0 -0
@@ -40,6 +40,27 @@ module ActiveMerchant #:nodoc:
40
40
  self.homepage_url = "http://www.firstdata.com"
41
41
  self.display_name = "FirstData Global Gateway e4"
42
42
 
43
+ STANDARD_ERROR_CODE_MAPPING = {
44
+ # Bank error codes: https://firstdata.zendesk.com/entries/471297-First-Data-Global-Gateway-e4-Bank-Response-Codes
45
+ '201' => STANDARD_ERROR_CODE[:incorrect_number],
46
+ '531' => STANDARD_ERROR_CODE[:invalid_cvc],
47
+ '503' => STANDARD_ERROR_CODE[:invalid_cvc],
48
+ '811' => STANDARD_ERROR_CODE[:invalid_cvc],
49
+ '605' => STANDARD_ERROR_CODE[:invalid_expiry_date],
50
+ '522' => STANDARD_ERROR_CODE[:expired_card],
51
+ '303' => STANDARD_ERROR_CODE[:card_declined],
52
+ '530' => STANDARD_ERROR_CODE[:card_declined],
53
+ '401' => STANDARD_ERROR_CODE[:call_issuer],
54
+ '402' => STANDARD_ERROR_CODE[:call_issuer],
55
+ '501' => STANDARD_ERROR_CODE[:pickup_card],
56
+ # Ecommerce error codes -- https://firstdata.zendesk.com/entries/451980-ecommerce-response-codes-etg-codes
57
+ '22' => STANDARD_ERROR_CODE[:invalid_number],
58
+ '25' => STANDARD_ERROR_CODE[:invalid_expiry_date],
59
+ '31' => STANDARD_ERROR_CODE[:incorrect_cvc],
60
+ '44' => STANDARD_ERROR_CODE[:incorrect_zip],
61
+ '42' => STANDARD_ERROR_CODE[:processing_error]
62
+ }
63
+
43
64
  # Create a new FirstdataE4Gateway
44
65
  #
45
66
  # The gateway requires that a valid login and password be passed
@@ -213,12 +234,31 @@ module ActiveMerchant #:nodoc:
213
234
  xml.tag! "VerificationStr1", address_values.join("|")
214
235
  end
215
236
 
216
- if credit_card.verification_value?
237
+ if credit_card.is_a?(NetworkTokenizationCreditCard)
238
+ add_network_tokenization_credit_card(xml, credit_card)
239
+ elsif credit_card.verification_value?
217
240
  xml.tag! "CVD_Presence_Ind", "1"
218
241
  xml.tag! "VerificationStr2", credit_card.verification_value
219
242
  end
220
243
  end
221
244
 
245
+ def add_network_tokenization_credit_card(xml, credit_card)
246
+ xml.tag!("Ecommerce_Flag", credit_card.eci)
247
+
248
+ case card_brand(credit_card).to_sym
249
+ when :visa
250
+ xml.tag!("XID", credit_card.transaction_id) if credit_card.transaction_id
251
+ xml.tag!("CAVV", credit_card.payment_cryptogram)
252
+ when :mastercard
253
+ xml.tag!("XID", credit_card.transaction_id) if credit_card.transaction_id
254
+ xml.tag!("CAVV", credit_card.payment_cryptogram)
255
+ when :american_express
256
+ cryptogram = Base64.decode64(credit_card.payment_cryptogram)
257
+ xml.tag!("XID", Base64.encode64(cryptogram[20...40]))
258
+ xml.tag!("CAVV", Base64.encode64(cryptogram[0...20]))
259
+ end
260
+ end
261
+
222
262
  def add_card_authentication_data(xml, options)
223
263
  xml.tag! "CAVV", options[:cavv]
224
264
  xml.tag! "XID", options[:xid]
@@ -277,7 +317,8 @@ module ActiveMerchant #:nodoc:
277
317
  :test => test?,
278
318
  :authorization => successful?(response) ? response_authorization(action, response, credit_card) : '',
279
319
  :avs_result => {:code => response[:avs]},
280
- :cvv_result => response[:cvv2]
320
+ :cvv_result => response[:cvv2],
321
+ :error_code => standard_error_code(response)
281
322
  )
282
323
  end
283
324
 
@@ -341,10 +382,15 @@ module ActiveMerchant #:nodoc:
341
382
  {
342
383
  :transaction_approved => "false",
343
384
  :error_number => error.code,
344
- :error_description => error.body
385
+ :error_description => error.body,
386
+ :ecommerce_error_code => error.body.gsub(/[^\d]/, '')
345
387
  }
346
388
  end
347
389
 
390
+ def standard_error_code(response)
391
+ STANDARD_ERROR_CODE_MAPPING[response[:bank_resp_code] || response[:ecommerce_error_code]]
392
+ end
393
+
348
394
  def parse(xml)
349
395
  response = {}
350
396
  xml = REXML::Document.new(xml)
@@ -62,6 +62,12 @@ module ActiveMerchant #:nodoc:
62
62
  commit('void', nil, post)
63
63
  end
64
64
 
65
+ def refund(money, authorization, options = {})
66
+ post = {}
67
+ post[:transactionid] = authorization
68
+ commit('refund', money, post)
69
+ end
70
+
65
71
  # Update the values (such as CC expiration) stored at
66
72
  # InspireGateway. The CC number must be supplied in the
67
73
  # CreditCard object.
@@ -157,7 +163,7 @@ module ActiveMerchant #:nodoc:
157
163
  def parse(body)
158
164
  results = {}
159
165
  body.split(/&/).each do |pair|
160
- key,val = pair.split(/=/)
166
+ key,val = pair.split(%r{=})
161
167
  results[key] = val
162
168
  end
163
169
 
@@ -366,7 +366,7 @@ module ActiveMerchant #:nodoc:
366
366
  def commit(request, options)
367
367
  requires!(options, :action)
368
368
  response = parse(ssl_post(test? ? self.test_url : self.live_url, request,
369
- {"SOAPAction" => "https://www.thepaymentgateway.net/#{options[:action]}",
369
+ {"SOAPAction" => "https://www.thepaymentgateway.net/" + options[:action],
370
370
  "Content-Type" => "text/xml; charset=utf-8" }))
371
371
 
372
372
  success = response[:transaction_result][:status_code] == "0"
@@ -42,7 +42,7 @@ module ActiveMerchant #:nodoc:
42
42
  commit('processCard', post)
43
43
  end
44
44
 
45
- def capture(money, identification)
45
+ def capture(money, identification, options = {})
46
46
  post = {}
47
47
  add_amount(post, money, options)
48
48
  add_transaction(post, identification)
@@ -50,7 +50,7 @@ module ActiveMerchant #:nodoc:
50
50
  commit('processCapture', post)
51
51
  end
52
52
 
53
- def refund(money, identification)
53
+ def refund(money, identification, options = {})
54
54
  post = {}
55
55
  add_amount(post, money, options)
56
56
  add_transaction(post, identification)
@@ -0,0 +1,307 @@
1
+ require 'nokogiri'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ #
6
+ # == Monei gateway
7
+ # This class implements Monei gateway for Active Merchant. For more information about Monei
8
+ # gateway please go to http://www.monei.net
9
+ #
10
+ # === Setup
11
+ # In order to set-up the gateway you need four paramaters: sender_id, channel_id, login and pwd.
12
+ # Request that data to Monei.
13
+ class MoneiGateway < Gateway
14
+ self.test_url = 'https://test.monei-api.net/payment/ctpe'
15
+ self.live_url = 'https://monei-api.net/payment/ctpe'
16
+
17
+ self.supported_countries = ['ES']
18
+ self.default_currency = 'EUR'
19
+ self.supported_cardtypes = [:visa, :master, :maestro, :jcb, :american_express]
20
+
21
+ self.homepage_url = 'http://www.monei.net/'
22
+ self.display_name = 'Monei'
23
+
24
+ # Constructor
25
+ #
26
+ # options - Hash containing the gateway credentials, ALL MANDATORY
27
+ # :sender_id Sender ID
28
+ # :channel_id Channel ID
29
+ # :login User login
30
+ # :pwd User password
31
+ #
32
+ def initialize(options={})
33
+ requires!(options, :sender_id, :channel_id, :login, :pwd)
34
+ super
35
+ end
36
+
37
+ # Public: Performs purchase operation
38
+ #
39
+ # money - Amount of purchase
40
+ # credit_card - Credit card
41
+ # options - Hash containing purchase options
42
+ # :order_id Merchant created id for the purchase
43
+ # :billing_address Hash with billing address information
44
+ # :description Merchant created purchase description (optional)
45
+ # :currency Sale currency to override money object or default (optional)
46
+ #
47
+ # Returns Active Merchant response object
48
+ def purchase(money, credit_card, options)
49
+ execute_new_order(:purchase, money, credit_card, options)
50
+ end
51
+
52
+ # Public: Performs authorization operation
53
+ #
54
+ # money - Amount to authorize
55
+ # credit_card - Credit card
56
+ # options - Hash containing authorization options
57
+ # :order_id Merchant created id for the authorization
58
+ # :billing_address Hash with billing address information
59
+ # :description Merchant created authorization description (optional)
60
+ # :currency Sale currency to override money object or default (optional)
61
+ #
62
+ # Returns Active Merchant response object
63
+ def authorize(money, credit_card, options={})
64
+ execute_new_order(:authorize, money, credit_card, options)
65
+ end
66
+
67
+ # Public: Performs capture operation on previous authorization
68
+ #
69
+ # money - Amount to capture
70
+ # authorization - Reference to previous authorization, obtained from response object returned by authorize
71
+ # options - Hash containing capture options
72
+ # :order_id Merchant created id for the authorization (optional)
73
+ # :description Merchant created authorization description (optional)
74
+ # :currency Sale currency to override money object or default (optional)
75
+ #
76
+ # Note: you should pass either order_id or description
77
+ #
78
+ # Returns Active Merchant response object
79
+ def capture(money, authorization, options={})
80
+ execute_dependant(:capture, money, authorization, options)
81
+ end
82
+
83
+ # Public: Refunds from previous purchase
84
+ #
85
+ # money - Amount to refund
86
+ # authorization - Reference to previous purchase, obtained from response object returned by purchase
87
+ # options - Hash containing refund options
88
+ # :order_id Merchant created id for the authorization (optional)
89
+ # :description Merchant created authorization description (optional)
90
+ # :currency Sale currency to override money object or default (optional)
91
+ #
92
+ # Note: you should pass either order_id or description
93
+ #
94
+ # Returns Active Merchant response object
95
+ def refund(money, authorization, options={})
96
+ execute_dependant(:refund, money, authorization, options)
97
+ end
98
+
99
+ # Public: Voids previous authorization
100
+ #
101
+ # authorization - Reference to previous authorization, obtained from response object returned by authorize
102
+ # options - Hash containing capture options
103
+ # :order_id Merchant created id for the authorization (optional)
104
+ #
105
+ # Returns Active Merchant response object
106
+ def void(authorization, options={})
107
+ execute_dependant(:void, nil, authorization, options)
108
+ end
109
+
110
+ # Public: Verifies credit card. Does this by doing a authorization of 1.00 Euro and then voiding it.
111
+ #
112
+ # credit_card - Credit card
113
+ # options - Hash containing authorization options
114
+ # :order_id Merchant created id for the authorization
115
+ # :billing_address Hash with billing address information
116
+ # :description Merchant created authorization description (optional)
117
+ # :currency Sale currency to override money object or default (optional)
118
+ #
119
+ # Returns Active Merchant response object of Authorization operation
120
+ def verify(credit_card, options={})
121
+ MultiResponse.run(:use_first_response) do |r|
122
+ r.process { authorize(100, credit_card, options) }
123
+ r.process(:ignore_result) { void(r.authorization, options) }
124
+ end
125
+ end
126
+
127
+ private
128
+
129
+ # Private: Execute purchase or authorize operation
130
+ def execute_new_order(action, money, credit_card, options)
131
+ request = build_request do |xml|
132
+ add_identification_new_order(xml, options)
133
+ add_payment(xml, action, money, options)
134
+ add_account(xml, credit_card)
135
+ add_customer(xml, credit_card, options)
136
+ end
137
+
138
+ commit(request)
139
+ end
140
+
141
+ # Private: Execute operation that depends on athorization code from previous purchase or authorize operation
142
+ def execute_dependant(action, money, authorization, options)
143
+ request = build_request do |xml|
144
+ add_identification_authorization(xml, authorization, options)
145
+ add_payment(xml, action, money, options)
146
+ end
147
+
148
+ commit(request)
149
+ end
150
+
151
+ # Private: Build XML wrapping code yielding to code to fill the transaction information
152
+ def build_request
153
+ builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
154
+ xml.Request(:version => "1.0") do
155
+ xml.Header { xml.Security(:sender => @options[:sender_id]) }
156
+ xml.Transaction(:mode => test? ? 'CONNECTOR_TEST' : 'LIVE', :response => 'SYNC', :channel => @options[:channel_id]) do
157
+ xml.User(:login => @options[:login], :pwd => @options[:pwd])
158
+ yield xml
159
+ end
160
+ end
161
+ end
162
+ builder.to_xml
163
+ end
164
+
165
+ # Private: Add identification part to XML for new orders
166
+ def add_identification_new_order(xml, options)
167
+ requires!(options, :order_id)
168
+ xml.Identification do
169
+ xml.TransactionID options[:order_id]
170
+ end
171
+ end
172
+
173
+ # Private: Add identification part to XML for orders that depend on authorization from previous operation
174
+ def add_identification_authorization(xml, authorization, options)
175
+ xml.Identification do
176
+ xml.ReferenceID authorization
177
+ xml.TransactionID options[:order_id]
178
+ end
179
+ end
180
+
181
+ # Private: Add payment part to XML
182
+ def add_payment(xml, action, money, options)
183
+ code = tanslate_payment_code(action)
184
+
185
+ xml.Payment(:code => code) do
186
+ xml.Presentation do
187
+ xml.Amount amount(money)
188
+ xml.Currency options[:currency] || currency(money)
189
+ xml.Usage options[:description] || options[:order_id]
190
+ end unless money.nil?
191
+ end
192
+ end
193
+
194
+ # Private: Add account part to XML
195
+ def add_account(xml, credit_card)
196
+ xml.Account do
197
+ xml.Holder credit_card.name
198
+ xml.Number credit_card.number
199
+ xml.Brand credit_card.brand.upcase
200
+ xml.Expiry(:month => credit_card.month, :year => credit_card.year)
201
+ xml.Verification credit_card.verification_value
202
+ end
203
+ end
204
+
205
+ # Private: Add customer part to XML
206
+ def add_customer(xml, credit_card, options)
207
+ requires!(options, :billing_address)
208
+ address = options[:billing_address]
209
+ xml.Customer do
210
+ xml.Name do
211
+ xml.Given credit_card.first_name
212
+ xml.Family credit_card.last_name
213
+ end
214
+ xml.Address do
215
+ xml.Street address[:address1].to_s
216
+ xml.Zip address[:zip].to_s
217
+ xml.City address[:city].to_s
218
+ xml.State address[:state].to_s if address.has_key? :state
219
+ xml.Country address[:country].to_s
220
+ end
221
+ xml.Contact do
222
+ xml.Email options[:email] || 'noemail@monei.net'
223
+ xml.Ip options[:ip] || '0.0.0.0'
224
+ end
225
+ end
226
+ end
227
+
228
+ # Private: Parse XML response from Monei servers
229
+ def parse(body)
230
+ xml = Nokogiri::XML(body)
231
+ {
232
+ :unique_id => xml.xpath("//Response/Transaction/Identification/UniqueID").text,
233
+ :status => translate_status_code(xml.xpath("//Response/Transaction/Processing/Status/@code").text),
234
+ :reason => translate_status_code(xml.xpath("//Response/Transaction/Processing/Reason/@code").text),
235
+ :message => xml.xpath("//Response/Transaction/Processing/Return").text
236
+ }
237
+ end
238
+
239
+ # Private: Send XML transaction to Monei servers and create AM response
240
+ def commit(xml)
241
+ url = (test? ? test_url : live_url)
242
+
243
+ response = parse(ssl_post(url, post_data(xml), 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'))
244
+
245
+ Response.new(
246
+ success_from(response),
247
+ message_from(response),
248
+ response,
249
+ authorization: authorization_from(response),
250
+ test: test?,
251
+ error_code: error_code_from(response)
252
+ )
253
+ end
254
+
255
+ # Private: Decide success from servers response
256
+ def success_from(response)
257
+ response[:status] == :success || response[:status] == :new
258
+ end
259
+
260
+ # Private: Get message from servers response
261
+ def message_from(response)
262
+ response[:message]
263
+ end
264
+
265
+ # Private: Get error code from servers response
266
+ def error_code_from(response)
267
+ success_from(response) ? nil : STANDARD_ERROR_CODE[:card_declined]
268
+ end
269
+
270
+ # Private: Get authorization code from servers response
271
+ def authorization_from(response)
272
+ response[:unique_id]
273
+ end
274
+
275
+ # Private: Encode POST parameters
276
+ def post_data(xml)
277
+ "load=#{CGI.escape(xml)}"
278
+ end
279
+
280
+ # Private: Translate Monei status code to native ruby symbols
281
+ def translate_status_code(code)
282
+ {
283
+ '00' => :success,
284
+ '40' => :neutral,
285
+ '59' => :waiting_bank,
286
+ '60' => :rejected_bank,
287
+ '64' => :waiting_risk,
288
+ '65' => :rejected_risk,
289
+ '70' => :rejected_validation,
290
+ '80' => :waiting,
291
+ '90' => :new
292
+ }[code]
293
+ end
294
+
295
+ # Private: Translate AM operations to Monei operations codes
296
+ def tanslate_payment_code(action)
297
+ {
298
+ :purchase => 'CC.DB',
299
+ :authorize => 'CC.PA',
300
+ :capture => 'CC.CP',
301
+ :refund => 'CC.RF',
302
+ :void => 'CC.RV'
303
+ }[action]
304
+ end
305
+ end
306
+ end
307
+ end
@@ -35,7 +35,6 @@ module ActiveMerchant #:nodoc:
35
35
 
36
36
  PERIODIC_TYPES = {
37
37
  :addcrn => 5,
38
- :editcrn => 5,
39
38
  :deletecrn => 5,
40
39
  :trigger => 8
41
40
  }
@@ -50,12 +49,9 @@ module ActiveMerchant #:nodoc:
50
49
 
51
50
  def purchase(money, credit_card_or_stored_id, options = {})
52
51
  if credit_card_or_stored_id.respond_to?(:number)
53
- #Credit card for instant payment
54
52
  commit :purchase, build_purchase_request(money, credit_card_or_stored_id, options)
55
53
  else
56
- #Triggered payment for an existing stored credit card
57
- options[:billing_id] = credit_card_or_stored_id.to_s
58
- commit_periodic build_periodic_item(:trigger, money, nil, options)
54
+ commit_periodic(:trigger, build_purchase_using_stored_card_request(money, credit_card_or_stored_id, options))
59
55
  end
60
56
  end
61
57
 
@@ -75,14 +71,12 @@ module ActiveMerchant #:nodoc:
75
71
  commit :capture, build_reference_request(money, authorization, options)
76
72
  end
77
73
 
78
- def store(creditcard, options = {})
79
- requires!(options, :billing_id, :amount)
80
- commit_periodic(build_periodic_item(:addcrn, options[:amount], creditcard, options))
74
+ def store(credit_card, options = {})
75
+ commit_periodic(:addcrn, build_store_request(credit_card, options))
81
76
  end
82
77
 
83
78
  def unstore(identification, options = {})
84
- options[:billing_id] = identification
85
- commit_periodic(build_periodic_item(:deletecrn, options[:amount], nil, options))
79
+ commit_periodic(:deletecrn, build_unstore_request(identification, options))
86
80
  end
87
81
 
88
82
  private
@@ -163,27 +157,7 @@ module ActiveMerchant #:nodoc:
163
157
  xml.target!
164
158
  end
165
159
 
166
- def build_periodic_item(action, money, credit_card, options)
167
- xml = Builder::XmlMarkup.new
168
-
169
- xml.tag! 'actionType', action.to_s
170
- xml.tag! 'periodicType', PERIODIC_TYPES[action] if PERIODIC_TYPES[action]
171
- xml.tag! 'currency', options[:currency] || currency(money)
172
- xml.tag! 'crn', options[:billing_id]
173
-
174
- if credit_card
175
- xml.tag! 'CreditCardInfo' do
176
- xml.tag! 'cardNumber', credit_card.number
177
- xml.tag! 'expiryDate', expdate(credit_card)
178
- xml.tag! 'cvv', credit_card.verification_value if credit_card.verification_value?
179
- end
180
- end
181
- xml.tag! 'amount', amount(money)
182
-
183
- xml.target!
184
- end
185
-
186
- def build_periodic_request(body)
160
+ def build_periodic_request(action, body)
187
161
  xml = Builder::XmlMarkup.new
188
162
  xml.instruct!
189
163
  xml.tag! 'NABTransactMessage' do
@@ -203,6 +177,8 @@ module ActiveMerchant #:nodoc:
203
177
  xml.tag! 'Periodic' do
204
178
  xml.tag! 'PeriodicList', "count" => 1 do
205
179
  xml.tag! 'PeriodicItem', "ID" => 1 do
180
+ xml.tag! 'actionType', action.to_s
181
+ xml.tag! 'periodicType', PERIODIC_TYPES[action] if PERIODIC_TYPES[action]
206
182
  xml << body
207
183
  end
208
184
  end
@@ -212,20 +188,50 @@ module ActiveMerchant #:nodoc:
212
188
  xml.target!
213
189
  end
214
190
 
191
+ def build_purchase_using_stored_card_request(money, identification, options)
192
+ xml = Builder::XmlMarkup.new
193
+
194
+ xml.tag! 'crn', identification
195
+ xml.tag! 'currency', options[:currency] || currency(money)
196
+ xml.tag! 'amount', amount(money)
197
+
198
+ xml.target!
199
+ end
200
+
201
+ def build_store_request(credit_card, options)
202
+ xml = Builder::XmlMarkup.new
203
+
204
+ xml.tag! 'crn', options[:billing_id] || SecureRandom.hex(10)
205
+ xml.tag! 'CreditCardInfo' do
206
+ xml.tag! 'cardNumber', credit_card.number
207
+ xml.tag! 'expiryDate', expdate(credit_card)
208
+ xml.tag! 'cvv', credit_card.verification_value if credit_card.verification_value?
209
+ end
210
+
211
+ xml.target!
212
+ end
213
+
214
+ def build_unstore_request(identification, options)
215
+ xml = Builder::XmlMarkup.new
216
+
217
+ xml.tag! 'crn', identification
218
+ xml.target!
219
+ end
220
+
215
221
  def commit(action, request)
216
222
  response = parse(ssl_post(test? ? self.test_url : self.live_url, build_request(action, request)))
217
223
 
218
224
  Response.new(success?(response), message_from(response), response,
219
225
  :test => test?,
220
- :authorization => authorization_from(response)
226
+ :authorization => authorization_from(action, response)
221
227
  )
222
228
  end
223
229
 
224
- def commit_periodic(request)
225
- response = parse(ssl_post(test? ? self.test_periodic_url : self.live_periodic_url, build_periodic_request(request)))
230
+ def commit_periodic(action, request)
231
+ response = parse(ssl_post(test? ? self.test_periodic_url : self.live_periodic_url, build_periodic_request(action, request)))
226
232
  Response.new(success?(response), message_from(response), response,
227
233
  :test => test?,
228
- :authorization => authorization_from(response)
234
+ :authorization => authorization_from(action, response)
229
235
  )
230
236
  end
231
237
 
@@ -233,8 +239,12 @@ module ActiveMerchant #:nodoc:
233
239
  SUCCESS_CODES.include?(response[:response_code])
234
240
  end
235
241
 
236
- def authorization_from(response)
237
- [response[:txn_id], response[:purchase_order_no], response[:preauth_id], response[:amount]].join('*')
242
+ def authorization_from(action, response)
243
+ if action == :addcrn
244
+ response[:crn]
245
+ else
246
+ [response[:txn_id], response[:purchase_order_no], response[:preauth_id], response[:amount]].join('*')
247
+ end
238
248
  end
239
249
 
240
250
  def message_from(response)