activemerchant 1.32.0 → 1.33.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 (52) hide show
  1. data/CHANGELOG +50 -0
  2. data/CONTRIBUTORS +8 -0
  3. data/README.md +6 -4
  4. data/lib/active_merchant/billing/check.rb +4 -3
  5. data/lib/active_merchant/billing/credit_card.rb +7 -3
  6. data/lib/active_merchant/billing/gateways/authorize_net.rb +27 -7
  7. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +8 -1
  8. data/lib/active_merchant/billing/gateways/blue_pay.rb +201 -185
  9. data/lib/active_merchant/billing/gateways/bogus.rb +1 -1
  10. data/lib/active_merchant/billing/gateways/card_stream_modern.rb +155 -0
  11. data/lib/active_merchant/billing/gateways/cc5.rb +0 -4
  12. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +94 -12
  13. data/lib/active_merchant/billing/gateways/garanti.rb +0 -4
  14. data/lib/active_merchant/billing/gateways/litle.rb +41 -11
  15. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +27 -6
  16. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +2 -2
  17. data/lib/active_merchant/billing/gateways/net_registry.rb +8 -3
  18. data/lib/active_merchant/billing/gateways/netaxept.rb +65 -117
  19. data/lib/active_merchant/billing/gateways/orbital.rb +181 -48
  20. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +12 -10
  21. data/lib/active_merchant/billing/gateways/paymill.rb +27 -13
  22. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +11 -6
  23. data/lib/active_merchant/billing/gateways/paypal_express.rb +25 -7
  24. data/lib/active_merchant/billing/gateways/pin.rb +5 -5
  25. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +16 -11
  26. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +1 -1
  27. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +21 -16
  28. data/lib/active_merchant/billing/gateways/sage.rb +10 -5
  29. data/lib/active_merchant/billing/gateways/sage_pay.rb +1 -0
  30. data/lib/active_merchant/billing/gateways/transnational.rb +239 -0
  31. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +9 -4
  32. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +1 -1
  33. data/lib/active_merchant/billing/integrations/direc_pay.rb +1 -1
  34. data/lib/active_merchant/billing/integrations/dwolla/common.rb +21 -0
  35. data/lib/active_merchant/billing/integrations/dwolla/helper.rb +15 -6
  36. data/lib/active_merchant/billing/integrations/dwolla/notification.rb +11 -6
  37. data/lib/active_merchant/billing/integrations/dwolla/return.rb +12 -4
  38. data/lib/active_merchant/billing/integrations/dwolla.rb +5 -12
  39. data/lib/active_merchant/billing/integrations/notification.rb +13 -8
  40. data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +13 -1
  41. data/lib/active_merchant/billing/integrations/payu_in/helper.rb +74 -0
  42. data/lib/active_merchant/billing/integrations/payu_in/notification.rb +167 -0
  43. data/lib/active_merchant/billing/integrations/payu_in/return.rb +53 -0
  44. data/lib/active_merchant/billing/integrations/payu_in.rb +43 -0
  45. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +68 -5
  46. data/lib/active_merchant/billing/integrations/rbkmoney/helper.rb +23 -0
  47. data/lib/active_merchant/billing/integrations/rbkmoney/notification.rb +91 -0
  48. data/lib/active_merchant/billing/integrations/rbkmoney.rb +17 -0
  49. data/lib/active_merchant/version.rb +1 -1
  50. data.tar.gz.sig +0 -0
  51. metadata +72 -62
  52. metadata.gz.sig +0 -0
@@ -30,56 +30,73 @@ module ActiveMerchant #:nodoc:
30
30
  def purchase(money, creditcard, options = {})
31
31
  requires!(options, :order_id)
32
32
 
33
- post = {}
34
- add_credentials(post, options)
35
- add_transaction(post, options)
36
- add_order(post, money, options)
37
- add_creditcard(post, creditcard)
38
- commit('Sale', post)
33
+ MultiResponse.run do |r|
34
+ r.process{authorize(money, creditcard, options)}
35
+ r.process{capture(money, r.authorization, options)}
36
+ end
39
37
  end
40
38
 
41
39
  def authorize(money, creditcard, options = {})
42
40
  requires!(options, :order_id)
43
41
 
44
- post = {}
45
- add_credentials(post, options)
46
- add_transaction(post, options)
47
- add_order(post, money, options)
48
- add_creditcard(post, creditcard)
49
- commit('Auth', post)
42
+ MultiResponse.run do |r|
43
+ r.process{setup_transaction(money, options)}
44
+ r.process{add_and_auth_credit_card(r.authorization, creditcard, options)}
45
+ r.process{query_transaction(r.authorization, options)}
46
+ end
50
47
  end
51
48
 
52
49
  def capture(money, authorization, options = {})
53
50
  post = {}
54
51
  add_credentials(post, options)
55
52
  add_authorization(post, authorization, money)
56
- commit('Capture', post, false)
53
+ post[:operation] = "Capture"
54
+ commit("Netaxept/process.aspx", post)
57
55
  end
58
56
 
59
57
  def refund(money, authorization, options = {})
60
58
  post = {}
61
59
  add_credentials(post, options)
62
60
  add_authorization(post, authorization, money)
63
- commit('Credit', post, false)
64
- end
65
-
66
- def credit(money, authorization, options = {})
67
- deprecated CREDIT_DEPRECATION_MESSAGE
68
- refund(money, authorization, options)
61
+ post[:operation] = "Credit"
62
+ commit("Netaxept/process.aspx", post)
69
63
  end
70
64
 
71
65
  def void(authorization, options = {})
72
66
  post = {}
73
67
  add_credentials(post, options)
74
68
  add_authorization(post, authorization)
75
- commit('Annul', post, false)
69
+ post[:operation] = "Annul"
70
+ commit("Netaxept/process.aspx", post)
76
71
  end
77
72
 
78
73
  private
79
74
 
80
- def add_credentials(post, options)
75
+ def setup_transaction(money, options)
76
+ post = {}
77
+ add_credentials(post, options)
78
+ add_order(post, money, options)
79
+ commit("Netaxept/Register.aspx", post)
80
+ end
81
+
82
+ def add_and_auth_credit_card(authorization, creditcard, options)
83
+ post = {}
84
+ add_credentials(post, options, false)
85
+ add_authorization(post, authorization)
86
+ add_creditcard(post, creditcard)
87
+ commit("terminal/default.aspx", post, false)
88
+ end
89
+
90
+ def query_transaction(authorization, options)
91
+ post = {}
92
+ add_credentials(post, options)
93
+ add_authorization(post, authorization)
94
+ commit("Netaxept/query.aspx", post)
95
+ end
96
+
97
+ def add_credentials(post, options, secure=true)
81
98
  post[:merchantId] = @options[:login]
82
- post[:token] = @options[:password]
99
+ post[:token] = @options[:password] if secure
83
100
  end
84
101
 
85
102
  def add_authorization(post, authorization, money=nil)
@@ -87,92 +104,45 @@ module ActiveMerchant #:nodoc:
87
104
  post[:transactionAmount] = amount(money) if money
88
105
  end
89
106
 
90
- def add_transaction(post, options)
91
- post[:transactionId] = generate_transaction_id(options)
92
- post[:serviceType] = 'M'
93
- post[:redirectUrl] = 'http://example.com'
94
- end
95
-
96
107
  def add_order(post, money, options)
108
+ post[:serviceType] = 'M'
97
109
  post[:orderNumber] = options[:order_id]
98
110
  post[:amount] = amount(money)
99
111
  post[:currencyCode] = (options[:currency] || currency(money))
112
+ post[:autoAuth] = "true"
100
113
  end
101
114
 
102
- CARD_TYPE_PREFIXES = {
103
- 'visa' => 'v',
104
- 'master' => 'm',
105
- 'american_express' => 'a',
106
- }
107
- def add_creditcard(post, creditcard)
108
- brand = Gateway.card_brand(creditcard)
109
- prefix = CARD_TYPE_PREFIXES[brand]
110
- unless prefix
111
- raise ArgumentError.new("Card type #{brand} not supported.")
112
- end
113
-
114
- post[:creditcard] = {}
115
- post[:creditcard][:"#{prefix}a"] = creditcard.number
116
- post[:creditcard][:"#{prefix}m"] = format(creditcard.month, :two_digits)
117
- post[:creditcard][:"#{prefix}y"] = format(creditcard.year, :two_digits)
118
- post[:creditcard][:"#{prefix}c"] = creditcard.verification_value
115
+ def add_creditcard(post, options)
116
+ post[:pan] = options.number
117
+ post[:expiryDate] = format(options.month, :two_digits) + format(options.year, :two_digits)
118
+ post[:securityCode] = options.verification_value
119
119
  end
120
120
 
121
- def commit(action, parameters, setup=true)
122
- parameters[:action] = action
123
-
124
- response = {:success => false}
125
-
126
- catch(:exception) do
127
- if setup
128
- commit_transaction_setup(response, parameters)
129
- commit_payment_details(response, parameters)
130
- commit_process_setup(response, parameters)
131
- end
132
- commit_transaction(response, parameters)
133
- response[:success] = true
134
- end
135
-
136
- Response.new(response[:success], response[:message], response, :test => test?, :authorization => response[:authorization])
137
- end
138
-
139
- def commit_transaction_setup(response, parameters)
140
- response[:setup] = parse(ssl_get(build_url("REST/Setup.aspx", pick(parameters, :merchantId, :token, :serviceType, :amount, :currencyCode, :redirectUrl, :orderNumber, :transactionId))))
141
- process(response, :setup)
142
- end
143
-
144
- def commit_payment_details(response, parameters)
145
- data = encode(parameters[:creditcard].merge(:BBSePay_transaction => response[:setup]['SetupString']))
146
- response[:paymentDetails] = parse(ssl_post(build_url("terminal/default.aspx"), data), false)
147
- process(response, :paymentDetails)
148
- end
149
-
150
- def commit_process_setup(response, parameters)
151
- result = ssl_get(build_url("REST/ProcessSetup.aspx", pick(parameters, :merchantId, :token, :transactionId).merge(:transactionString => response[:paymentDetails][:result])))
152
- response[:processSetup] = parse(result)
153
- process(response, :processSetup)
154
- end
121
+ def commit(path, parameters, xml=true)
122
+ raw = parse(ssl_get(build_url(path, parameters)), xml)
155
123
 
156
- def commit_transaction(response, parameters)
157
- result = ssl_get(build_url("REST/#{parameters[:action]}.aspx", pick(parameters, :merchantId, :token, :transactionId, :transactionAmount)))
158
- response[:action] = parse(result)
159
- process(response, :action)
160
- end
161
-
162
- def process(response, step)
163
- if response[step][:container] =~ /Exception|Error/
164
- response[:message] = response[step]['Message']
165
- throw :exception
124
+ success = false
125
+ authorization = (raw["TransactionId"] || parameters[:transactionId])
126
+ if raw[:container] =~ /Exception|Error/
127
+ message = (raw["Message"] || raw["Error"]["Message"])
128
+ elsif raw["Error"] && !raw["Error"].empty?
129
+ message = (raw["Error"]["ResponseText"] || raw["Error"]["ResponseCode"])
166
130
  else
167
- message = (response[step]['ResponseText'] || response[step]['ResponseCode'])
168
- response[:message] = (message || response[:message])
169
-
170
- response[:authorization] = response[step]['TransactionId']
131
+ message = (raw["ResponseText"] || raw["ResponseCode"] || "OK")
132
+ success = true
171
133
  end
134
+
135
+ Response.new(
136
+ success,
137
+ message,
138
+ raw,
139
+ :test => test?,
140
+ :authorization => authorization
141
+ )
172
142
  end
173
143
 
174
144
  def parse(result, expects_xml=true)
175
- if expects_xml || /^</ =~ result
145
+ if expects_xml
176
146
  doc = REXML::Document.new(result)
177
147
  extract_xml(doc.root).merge(:container => doc.root.name)
178
148
  else
@@ -192,20 +162,8 @@ module ActiveMerchant #:nodoc:
192
162
  end
193
163
  end
194
164
 
195
- def url
196
- (test? ? self.test_url : self.live_url)
197
- end
198
-
199
- def generate_transaction_id(options)
200
- Digest::MD5.hexdigest("#{options.inspect}+#{Time.now}+#{rand}")
201
- end
202
-
203
- def pick(hash, *keys)
204
- keys.inject({}){|h,key| h[key] = hash[key] if hash[key]; h}
205
- end
206
-
207
165
  def build_url(base, parameters=nil)
208
- url = "#{test? ? self.test_url : self.live_url}"
166
+ url = (test? ? self.test_url : self.live_url).dup
209
167
  url << base
210
168
  if parameters
211
169
  url << '?'
@@ -217,16 +175,6 @@ module ActiveMerchant #:nodoc:
217
175
  def encode(hash)
218
176
  hash.collect{|(k,v)| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"}.join('&')
219
177
  end
220
-
221
- class Response < Billing::Response
222
- attr_reader :error_detail
223
- def initialize(success, message, raw, options)
224
- super
225
- unless success
226
- @error_detail = raw[:processSetup]['Result']['ResponseText'] if raw[:processSetup] && raw[:processSetup]['Result']
227
- end
228
- end
229
- end
230
178
  end
231
179
  end
232
180
  end
@@ -32,8 +32,8 @@ module ActiveMerchant #:nodoc:
32
32
  API_VERSION = "5.6"
33
33
 
34
34
  POST_HEADERS = {
35
- "MIME-Version" => "1.0",
36
- "Content-Type" => "Application/PTI46",
35
+ "MIME-Version" => "1.1",
36
+ "Content-Type" => "application/PTI56",
37
37
  "Content-transfer-encoding" => "text",
38
38
  "Request-number" => '1',
39
39
  "Document-type" => "Request",
@@ -80,6 +80,63 @@ module ActiveMerchant #:nodoc:
80
80
  "EUR" => '978'
81
81
  }
82
82
 
83
+ # INDUSTRY TYPES
84
+ ECOMMERCE_TRANSACTION = 'EC'
85
+ RECURRING_PAYMENT_TRANSACTION = 'RC'
86
+ MAIL_ORDER_TELEPHONE_ORDER_TRANSACTION = 'MO'
87
+ INTERACTIVE_VOICE_RESPONSE = 'IV'
88
+ # INTERACTIVE_VOICE_RESPONSE = 'IN'
89
+
90
+ # Auth Only No Capture
91
+ AUTH_ONLY = 'A'
92
+ # AC - Auth and Capture = 'AC'
93
+ AUTH_AND_CAPTURE = 'AC'
94
+ # F - Force Auth No Capture and no online authorization = 'F'
95
+ FORCE_AUTH_ONLY = 'F'
96
+ # FR - Force Auth No Capture and no online authorization = 'FR'
97
+ # FC - Force Auth and Capture no online authorization = 'FC'
98
+ FORCE_AUTH_AND_CAPTURE = 'FC'
99
+ # Refund and Capture no online authorization
100
+ REFUND = 'R'
101
+
102
+ # Tax Inds
103
+ TAX_NOT_PROVIDED = 0
104
+ TAX_INCLUDED = 1
105
+ NON_TAXABLE_TRANSACTION = 2
106
+
107
+ # Customer Profile Actions
108
+ CREATE = 'C'
109
+ RETRIEVE = 'R'
110
+ UPDATE = 'U'
111
+ DELETE = 'D'
112
+
113
+ RECURRING = 'R'
114
+ DEFERRED = 'D'
115
+
116
+ # Status
117
+ # Profile Status Flag
118
+ # This field is used to set the status of a Customer Profile.
119
+ ACTIVE = 'A'
120
+ INACTIVE = 'I'
121
+ MANUAL_SUSPEND = 'MS'
122
+
123
+ # CustomerProfileOrderOverrideInd
124
+ # Defines if any Order Data can be pre-populated from
125
+ # the Customer Reference Number (CustomerRefNum)
126
+ NO_MAPPING_TO_ORDER_DATA = 'NO'
127
+ USE_CRN_FOR_ORDER_ID = 'OI'
128
+ USE_CRN_FOR_COMMENTS = 'OD'
129
+ USE_CRN_FOR_ORDER_ID_AND_COMMENTS = 'OA'
130
+
131
+ # CustomerProfileFromOrderInd
132
+ # Method to use to Generate the Customer Profile Number
133
+ # When Customer Profile Action Type = Create, defines
134
+ # what the Customer Profile Number will be:
135
+ AUTO_GENERATE = 'A' # Auto-Generate the CustomerRefNum
136
+ USE_CUSTOMER_REF_NUM = 'S' # Use CustomerRefNum field
137
+ USE_ORDER_ID = 'O' # Use OrderID field
138
+ USE_COMMENTS = 'D' # Use Comments field
139
+
83
140
  def initialize(options = {})
84
141
  requires!(options, :merchant_id)
85
142
  requires!(options, :login, :password) unless options[:ip_authentication]
@@ -88,22 +145,28 @@ module ActiveMerchant #:nodoc:
88
145
 
89
146
  # A – Authorization request
90
147
  def authorize(money, creditcard, options = {})
91
- order = build_new_order_xml('A', money, options) do |xml|
148
+ order = build_new_order_xml(AUTH_ONLY, money, options) do |xml|
92
149
  add_creditcard(xml, creditcard, options[:currency]) unless creditcard.nil? && options[:profile_txn]
93
150
  add_address(xml, creditcard, options)
94
- add_customer_data(xml, options) if @options[:customer_profiles]
151
+ if @options[:customer_profiles]
152
+ add_customer_data(xml, options)
153
+ add_managed_billing(xml, options)
154
+ end
95
155
  end
96
- commit(order, :authorize)
156
+ commit(order, :authorize, options[:trace_number])
97
157
  end
98
158
 
99
159
  # AC – Authorization and Capture
100
160
  def purchase(money, creditcard, options = {})
101
- order = build_new_order_xml('AC', money, options) do |xml|
161
+ order = build_new_order_xml(AUTH_AND_CAPTURE, money, options) do |xml|
102
162
  add_creditcard(xml, creditcard, options[:currency]) unless creditcard.nil? && options[:profile_txn]
103
163
  add_address(xml, creditcard, options)
104
- add_customer_data(xml, options) if @options[:customer_profiles]
164
+ if @options[:customer_profiles]
165
+ add_customer_data(xml, options)
166
+ add_managed_billing(xml, options)
167
+ end
105
168
  end
106
- commit(order, :purchase)
169
+ commit(order, :purchase, options[:trace_number])
107
170
  end
108
171
 
109
172
  # MFC - Mark For Capture
@@ -113,11 +176,11 @@ module ActiveMerchant #:nodoc:
113
176
 
114
177
  # R – Refund request
115
178
  def refund(money, authorization, options = {})
116
- order = build_new_order_xml('R', money, options.merge(:authorization => authorization)) do |xml|
179
+ order = build_new_order_xml(REFUND, money, options.merge(:authorization => authorization)) do |xml|
117
180
  add_refund(xml, options[:currency])
118
181
  xml.tag! :CustomerRefNum, options[:customer_ref_num] if @options[:customer_profiles] && options[:profile_txn]
119
182
  end
120
- commit(order, :refund)
183
+ commit(order, :refund, options[:trace_number])
121
184
  end
122
185
 
123
186
  def credit(money, authorization, options= {})
@@ -132,7 +195,7 @@ module ActiveMerchant #:nodoc:
132
195
  end
133
196
 
134
197
  order = build_void_request_xml(authorization, options)
135
- commit(order, :void)
198
+ commit(order, :void, options[:trace_number])
136
199
  end
137
200
 
138
201
 
@@ -158,25 +221,25 @@ module ActiveMerchant #:nodoc:
158
221
  # 'MS' - Manual Suspend
159
222
 
160
223
  def add_customer_profile(creditcard, options = {})
161
- options.merge!(:customer_profile_action => 'C')
224
+ options.merge!(:customer_profile_action => CREATE)
162
225
  order = build_customer_request_xml(creditcard, options)
163
226
  commit(order, :add_customer_profile)
164
227
  end
165
228
 
166
229
  def update_customer_profile(creditcard, options = {})
167
- options.merge!(:customer_profile_action => 'U')
230
+ options.merge!(:customer_profile_action => UPDATE)
168
231
  order = build_customer_request_xml(creditcard, options)
169
232
  commit(order, :update_customer_profile)
170
233
  end
171
234
 
172
235
  def retrieve_customer_profile(customer_ref_num)
173
- options = {:customer_profile_action => 'R', :customer_ref_num => customer_ref_num}
236
+ options = {:customer_profile_action => RETRIEVE, :customer_ref_num => customer_ref_num}
174
237
  order = build_customer_request_xml(nil, options)
175
238
  commit(order, :retrieve_customer_profile)
176
239
  end
177
240
 
178
241
  def delete_customer_profile(customer_ref_num)
179
- options = {:customer_profile_action => 'D', :customer_ref_num => customer_ref_num}
242
+ options = {:customer_profile_action => DELETE, :customer_ref_num => customer_ref_num}
180
243
  order = build_customer_request_xml(nil, options)
181
244
  commit(order, :delete_customer_profile)
182
245
  end
@@ -196,12 +259,12 @@ module ActiveMerchant #:nodoc:
196
259
  xml.tag! :CustomerRefNum, options[:customer_ref_num]
197
260
  else
198
261
  if options[:customer_ref_num]
199
- xml.tag! :CustomerProfileFromOrderInd, 'S'
262
+ xml.tag! :CustomerProfileFromOrderInd, USE_CUSTOMER_REF_NUM
200
263
  xml.tag! :CustomerRefNum, options[:customer_ref_num]
201
264
  else
202
- xml.tag! :CustomerProfileFromOrderInd, 'A'
265
+ xml.tag! :CustomerProfileFromOrderInd, AUTO_GENERATE
203
266
  end
204
- xml.tag! :CustomerProfileOrderOverrideInd, options[:customer_profile_order_override_ind] || 'NO'
267
+ xml.tag! :CustomerProfileOrderOverrideInd, options[:customer_profile_order_override_ind] || NO_MAPPING_TO_ORDER_DATA
205
268
  end
206
269
  end
207
270
 
@@ -215,32 +278,51 @@ module ActiveMerchant #:nodoc:
215
278
  end
216
279
 
217
280
  def add_address(xml, creditcard, options)
218
- if address = options[:billing_address] || options[:address]
281
+ if(address = (options[:billing_address] || options[:address]))
219
282
  avs_supported = AVS_SUPPORTED_COUNTRIES.include?(address[:country].to_s)
220
283
 
221
284
  if avs_supported
222
- xml.tag! :AVSzip, address[:zip].to_s[0..9]
223
- xml.tag! :AVSaddress1, address[:address1][0..29]
224
- xml.tag! :AVSaddress2, address[:address2][0..29]
225
- xml.tag! :AVScity, address[:city][0..19]
226
- xml.tag! :AVSstate, address[:state]
227
- xml.tag! :AVSphoneNum, address[:phone] ? address[:phone].scan(/\d/).join.to_s[0..13] : nil
285
+ xml.tag! :AVSzip, (address[:zip] ? address[:zip].to_s[0..9] : nil)
286
+ xml.tag! :AVSaddress1, (address[:address1] ? address[:address1][0..29] : nil)
287
+ xml.tag! :AVSaddress2, (address[:address2] ? address[:address2][0..29] : nil)
288
+ xml.tag! :AVScity, (address[:city] ? address[:city][0..19] : nil)
289
+ xml.tag! :AVSstate, address[:state]
290
+ xml.tag! :AVSphoneNum, (address[:phone] ? address[:phone].scan(/\d/).join.to_s[0..13] : nil)
228
291
  end
229
- xml.tag! :AVSname, creditcard.name[0..29]
230
- xml.tag! :AVScountryCode, avs_supported ? address[:country] : ''
292
+ # can't look in billing address?
293
+ xml.tag! :AVSname, ((creditcard && creditcard.name) ? creditcard.name[0..29] : nil)
294
+ xml.tag! :AVScountryCode, (avs_supported ? address[:country] : '')
295
+
296
+ # Needs to come after AVScountryCode
297
+ add_destination_address(xml, address) if avs_supported
298
+ end
299
+ end
300
+
301
+ def add_destination_address(xml, address)
302
+ if address[:dest_zip]
303
+ xml.tag! :AVSDestzip, (address[:dest_zip] ? address[:dest_zip].to_s[0..9] : nil)
304
+ xml.tag! :AVSDestaddress1, (address[:dest_address1] ? address[:dest_address1][0..29] : nil)
305
+ xml.tag! :AVSDestaddress2, (address[:dest_address2] ? address[:dest_address2][0..29] : nil)
306
+ xml.tag! :AVSDestcity, (address[:dest_city] ? address[:dest_city][0..19] : nil)
307
+ xml.tag! :AVSDeststate, address[:dest_state]
308
+ xml.tag! :AVSDestphoneNum, (address[:dest_phone] ? address[:dest_phone].scan(/\d/).join.to_s[0..13] : nil)
309
+
310
+ xml.tag! :AVSDestname, (address[:dest_name] ? address[:dest_name][0..29] : nil)
311
+ xml.tag! :AVSDestcountryCode, address[:dest_country]
231
312
  end
232
313
  end
233
314
 
234
315
  # For Profile requests
235
316
  def add_customer_address(xml, options)
236
- if address = options[:billing_address] || options[:address]
237
- xml.tag! :CustomerAddress1, address[:address1]
238
- xml.tag! :CustomerAddress2, address[:address2]
239
- xml.tag! :CustomerCity, address[:city]
317
+ if(address = (options[:billing_address] || options[:address]))
318
+ xml.tag! :CustomerAddress1, (address[:address1] ? address[:address1][0..29] : nil)
319
+ xml.tag! :CustomerAddress2, (address[:address2] ? address[:address2][0..29] : nil)
320
+ xml.tag! :CustomerCity, (address[:city] ? address[:city][0..19] : nil)
240
321
  xml.tag! :CustomerState, address[:state]
241
- xml.tag! :CustomerZIP, address[:zip]
242
- xml.tag! :CustomerPhone, address[:phone] ? address[:phone].scan(/\d/).to_s : nil
243
- xml.tag! :CustomerCountryCode, address[:country]
322
+ xml.tag! :CustomerZIP, (address[:zip] ? address[:zip].to_s[0..9] : nil)
323
+ xml.tag! :CustomerEmail, address[:email].to_s[0..49] if address[:email]
324
+ xml.tag! :CustomerPhone, (address[:phone] ? address[:phone].scan(/\d/).join.to_s : nil)
325
+ xml.tag! :CustomerCountryCode, (address[:country] ? address[:country][0..1] : nil)
244
326
  end
245
327
  end
246
328
 
@@ -261,7 +343,7 @@ module ActiveMerchant #:nodoc:
261
343
  # Do not submit the attribute at all.
262
344
  # - http://download.chasepaymentech.com/docs/orbital/orbital_gateway_xml_specification.pdf
263
345
  if %w( visa discover ).include?(creditcard.brand)
264
- xml.tag! :CardSecValInd, creditcard.verification_value? ? '1' : '9'
346
+ xml.tag! :CardSecValInd, (creditcard.verification_value? ? '1' : '9')
265
347
  end
266
348
  xml.tag! :CardSecVal, creditcard.verification_value if creditcard.verification_value?
267
349
  end
@@ -273,6 +355,27 @@ module ActiveMerchant #:nodoc:
273
355
  xml.tag! :CurrencyExponent, '2' # Will need updating to support currencies such as the Yen.
274
356
  end
275
357
 
358
+ def add_managed_billing(xml, options)
359
+ if mb = options[:managed_billing]
360
+ # default to recurring (R). Other option is deferred (D).
361
+ xml.tag! :MBType, mb[:type] || RECURRING
362
+ # default to Customer Reference Number
363
+ xml.tag! :MBOrderIdGenerationMethod, mb[:order_id_generation_method] || 'IO'
364
+ # By default use MBRecurringEndDate, set to N.
365
+ # MMDDYYYY
366
+ xml.tag! :MBRecurringStartDate, mb[:start_date].scan(/\d/).join.to_s if mb[:start_date]
367
+ # MMDDYYYY
368
+ xml.tag! :MBRecurringEndDate, mb[:end_date].scan(/\d/).join.to_s if mb[:end_date]
369
+ # By default listen to any value set in MBRecurringEndDate.
370
+ xml.tag! :MBRecurringNoEndDateFlag, mb[:no_end_date_flag] || 'N' # 'Y' || 'N' (Yes or No).
371
+ xml.tag! :MBRecurringMaxBillings, mb[:max_billings] if mb[:max_billings]
372
+ xml.tag! :MBRecurringFrequency, mb[:frequency] if mb[:frequency]
373
+ xml.tag! :MBDeferredBillDate, mb[:deferred_bill_date] if mb[:deferred_bill_date]
374
+ xml.tag! :MBMicroPaymentMaxDollarValue, mb[:max_dollar_value] if mb[:max_dollar_value]
375
+ xml.tag! :MBMicroPaymentMaxBillingDays, mb[:max_billing_days] if mb[:max_billing_days]
376
+ xml.tag! :MBMicroPaymentMaxTransactions, mb[:max_transactions] if mb[:max_transactions]
377
+ end
378
+ end
276
379
 
277
380
  def parse(body)
278
381
  response = {}
@@ -295,8 +398,10 @@ module ActiveMerchant #:nodoc:
295
398
  end
296
399
  end
297
400
 
298
- def commit(order, message_type)
401
+ def commit(order, message_type, trace_number=nil)
299
402
  headers = POST_HEADERS.merge("Content-length" => order.size.to_s)
403
+ headers.merge!( "Trace-number" => trace_number.to_s,
404
+ "Merchant-Id" => @options[:merchant_id] ) if @options[:retry_logic] && trace_number
300
405
  request = lambda{|url| parse(ssl_post(url, order, headers))}
301
406
 
302
407
  # Failover URL will be attempted in the event of a connection error
@@ -318,9 +423,9 @@ module ActiveMerchant #:nodoc:
318
423
 
319
424
  def remote_url(url=:primary)
320
425
  if url == :primary
321
- self.test? ? self.test_url : self.live_url
426
+ (self.test? ? self.test_url : self.live_url)
322
427
  else
323
- self.test? ? self.secondary_test_url : self.secondary_live_url
428
+ (self.test? ? self.secondary_test_url : self.secondary_live_url)
324
429
  end
325
430
  end
326
431
 
@@ -349,7 +454,18 @@ module ActiveMerchant #:nodoc:
349
454
  xml.tag! :Request do
350
455
  xml.tag! :NewOrder do
351
456
  add_xml_credentials(xml)
352
- xml.tag! :IndustryType, parameters[:industry_type] || "EC"
457
+ # EC - Ecommerce transaction
458
+ # RC - Recurring Payment transaction
459
+ # MO - Mail Order Telephone Order transaction
460
+ # IV - Interactive Voice Response
461
+ # IN - Interactive Voice Response
462
+ xml.tag! :IndustryType, parameters[:industry_type] || ECOMMERCE_TRANSACTION
463
+ # A - Auth Only No Capture
464
+ # AC - Auth and Capture
465
+ # F - Force Auth No Capture and no online authorization
466
+ # FR - Force Auth No Capture and no online authorization
467
+ # FC - Force Auth and Capture no online authorization
468
+ # R - Refund and Capture no online authorization
353
469
  xml.tag! :MessageType, action
354
470
  add_bin_merchant_and_terminal(xml, parameters)
355
471
 
@@ -359,6 +475,8 @@ module ActiveMerchant #:nodoc:
359
475
  xml.tag! :Amount, amount(money)
360
476
  xml.tag! :Comments, parameters[:comments] if parameters[:comments]
361
477
 
478
+ # CustomerAni, AVSPhoneType and AVSDestPhoneType could be added here.
479
+
362
480
  if parameters[:soft_descriptors].is_a?(OrbitalSoftDescriptors)
363
481
  add_soft_descriptors(xml, parameters[:soft_descriptors])
364
482
  end
@@ -366,7 +484,7 @@ module ActiveMerchant #:nodoc:
366
484
  set_recurring_ind(xml, parameters)
367
485
 
368
486
  # Append Transaction Reference Number at the end for Refund transactions
369
- if action == "R"
487
+ if action == REFUND
370
488
  tx_ref_num, _ = split_authorization(parameters[:authorization])
371
489
  xml.tag! :TxRefNum, tx_ref_num
372
490
  end
@@ -411,6 +529,8 @@ module ActiveMerchant #:nodoc:
411
529
  xml.tag! :AdjustedAmt, parameters[:amount] # setting adjusted amount to nil will void entire amount
412
530
  xml.tag! :OrderID, format_order_id(order_id || parameters[:order_id])
413
531
  add_bin_merchant_and_terminal(xml, parameters)
532
+ xml.tag! :ReversalRetryNumber, parameters[:reversal_retry_number] if parameters[:reversal_retry_number]
533
+ xml.tag! :OnlineReversalInd, parameters[:online_reversal_ind] if parameters[:online_reversal_ind]
414
534
  end
415
535
  end
416
536
  xml.target!
@@ -435,8 +555,10 @@ module ActiveMerchant #:nodoc:
435
555
  end
436
556
 
437
557
  def add_xml_credentials(xml)
438
- xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
439
- xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
558
+ unless ip_authentication?
559
+ xml.tag! :OrbitalConnectionUsername, @options[:login]
560
+ xml.tag! :OrbitalConnectionPassword, @options[:password]
561
+ end
440
562
  end
441
563
 
442
564
  def add_bin_merchant_and_terminal(xml, parameters)
@@ -475,22 +597,33 @@ module ActiveMerchant #:nodoc:
475
597
  add_customer_address(xml, options)
476
598
 
477
599
  xml.tag! :CustomerProfileAction, options[:customer_profile_action] # C, R, U, D
478
- xml.tag! :CustomerProfileOrderOverrideInd, options[:customer_profile_order_override_ind] || 'NO'
479
-
480
- if options[:customer_profile_action] == 'C'
481
- xml.tag! :CustomerProfileFromOrderInd, options[:customer_ref_num] ? 'S' : 'A'
600
+ # NO No mapping to order data
601
+ # OI Use <CustomerRefNum> for <OrderID>
602
+ # OD Use <CustomerReferNum> for <Comments>
603
+ # OA Use <CustomerRefNum> for <OrderID> and <Comments>
604
+ xml.tag! :CustomerProfileOrderOverrideInd, options[:customer_profile_order_override_ind] || NO_MAPPING_TO_ORDER_DATA
605
+
606
+ if options[:customer_profile_action] == CREATE
607
+ # A Auto-Generate the CustomerRefNum
608
+ # S Use CustomerRefNum field
609
+ # O Use OrderID field
610
+ # D Use Comments field
611
+ xml.tag! :CustomerProfileFromOrderInd, (options[:customer_ref_num] ? USE_CUSTOMER_REF_NUM : AUTO_GENERATE)
482
612
  end
483
613
 
484
614
  xml.tag! :OrderDefaultDescription, options[:order_default_description][0..63] if options[:order_default_description]
485
615
  xml.tag! :OrderDefaultAmount, options[:order_default_amount] if options[:order_default_amount]
486
616
 
487
- if ['C', 'U'].include? options[:customer_profile_action]
617
+ if [CREATE, UPDATE].include? options[:customer_profile_action]
488
618
  xml.tag! :CustomerAccountType, 'CC' # Only credit card supported
489
- xml.tag! :Status, options[:status] || 'A' # Active
619
+ xml.tag! :Status, options[:status] || ACTIVE # Active
490
620
  end
491
621
 
492
622
  xml.tag! :CCAccountNum, creditcard.number if creditcard
493
623
  xml.tag! :CCExpireDate, creditcard.expiry_date.expiration.strftime("%m%y") if creditcard
624
+
625
+ # This has to come after CCExpireDate.
626
+ add_managed_billing(xml, options)
494
627
  end
495
628
  end
496
629
  xml.target!