activemerchant 1.42.9 → 1.43.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: baa3b2ef41f3fd7b7ee93ae111090938ffee872a
4
- data.tar.gz: 3104e5e77e0895fc86563e6ada9381b37d827f05
3
+ metadata.gz: bd0a074d4175458b2a017a44f74f0bc452e0f37e
4
+ data.tar.gz: 58c5170f7a74afe97dadca2da6c5cbe4466105eb
5
5
  SHA512:
6
- metadata.gz: 5eb2c499dad2b3d33e7c820ce3c2afa77ea7376e19a84a348e4577d7ec10f7b8bbc8c8c6facf881ed65ea32de8762b3a1638ad7e5e7d4019545455364c36e323
7
- data.tar.gz: 97f099bce96fa830eccc9be8d2b2a5934a01e58c4dcb94811827fff49321f48506f1e326f9d7797570af726298664d688241cfaf59e7627627727f1eff497455
6
+ metadata.gz: ee8290e0840f1b817d0f1c9de135bbee7ae677fe37509d246ddb99c85382fb108c044e76075be616db0608d7d14266b4916d4d4581ac0dc2ab8de61e7d07f8a1
7
+ data.tar.gz: cbaf9362768fa747a57b71b8aa26e271712d56611789f5ea57fb67d2d1087261e42144a6340acb74e1e55be70f566468b18eda05a1df2f85b5a4abaa5a9766b7
Binary file
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,9 +1,22 @@
1
1
  = ActiveMerchant CHANGELOG
2
2
 
3
+ == Version 1.43.0 (April 24, 2014)
4
+
5
+ * PagSeguro: New offsite integration [celsodantas]
6
+ * Sage Pay: Fix amount parsing in notifications [berkcaputcu]
7
+ * Sage Pay: Use API v3.00 [bslobodin]
8
+ * BridgePay: Switch method of success detection [markabe]
9
+ * BridgePay: Use Return as TransType for refunds [markabe]
10
+ * IATS: Complete rewrite using first class API [rwdaigle]
11
+ * IATS: Fix invalid country code UK -> GB [rwdaigle]
12
+ * DataCash: Fix refund processing using original authorization [bslobodin]
13
+ * Transnational gateway renamed to Network Merchants [bslobodin]
14
+ * PayMill: Handle non-JSON server responses [bslobodin]
15
+
3
16
  == Version 1.42.9 (April 15, 2014)
4
17
 
5
18
  * Spreedly: Add ip, description and gateway_specific_fields [faizalzakaria]
6
- * Sage (US): Support store/unstore of cards. [rwdaigle]
19
+ * Sage (US): Support store/unstore of cards [rwdaigle]
7
20
  * Pin: Add american express to supported cards [nagash]
8
21
  * Raven: Update handling of CVV/AVS [bslobodin]
9
22
  * Raven: Use UUID for RequestID [bslobodin]
@@ -468,3 +468,7 @@ WePay (March 2014)
468
468
  FirstGiving (March 2014)
469
469
 
470
470
  * Faizal Zakaria (faizalzakaria)
471
+
472
+ BridgePay (April 2014)
473
+
474
+ * Mark Bennett (markabe)
data/README.md CHANGED
@@ -94,6 +94,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
94
94
  * [Beanstream.com](http://www.beanstream.com/) - CA, US
95
95
  * [BluePay](http://www.bluepay.com/) - US
96
96
  * [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
97
+ * [BridgePay](http://www.bridgepaynetwork.com/) - CA, US
97
98
  * [CardSave](http://www.cardsave.net/) - GB
98
99
  * [CardStream](http://www.cardstream.com/) - GB
99
100
  * [Cecabank](http://www.ceca.es/es/) - ES
@@ -116,7 +117,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
116
117
  * [FirstGiving](http://www.firstgiving.com/) - US
117
118
  * [Garanti Sanal POS](https://sanalposweb.garanti.com.tr) - US, TR
118
119
  * [HDFC](http://www.hdfcbank.com/sme/sme-details/merchant-services/guzh6m0i) - IN
119
- * [IATSPayments](http://www.iatspayments.com/) - US, CA, GB
120
+ * [iATS Payments](http://home.iatspayments.com/) - AU, CA, CH, DE, DK, ES, FI, FR, GR, HK, IE, IT, JP, NL, NO, NZ, PT, SE, SG, TR, UK, US
120
121
  * [Inspire Commerce](http://www.inspiregateway.com) - US
121
122
  * [InstaPay](http://www.instapayllc.com) - US
122
123
  * [Iridium](http://www.iridiumcorp.co.uk/) - GB, ES
@@ -0,0 +1,182 @@
1
+ require "nokogiri"
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class BridgePayGateway < Gateway
6
+ self.display_name = "BridgePay"
7
+ self.homepage_url = "http://www.bridgepaynetwork.com/"
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"
11
+
12
+ self.supported_countries = ["CA", "US"]
13
+ self.default_currency = "USD"
14
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
15
+
16
+
17
+ def initialize(options={})
18
+ requires!(options, :user_name, :password)
19
+ super
20
+ end
21
+
22
+ def purchase(amount, creditcard, options={})
23
+ post = post_required_fields("Sale")
24
+
25
+ # Allow the same amount in multiple transactions.
26
+ post[:ExtData] = "<Force>T</Force>"
27
+ add_invoice(post, amount, options)
28
+ add_creditcard(post, creditcard)
29
+ add_customer_data(post, options)
30
+
31
+ commit(post)
32
+ end
33
+
34
+ def authorize(amount, creditcard, options={})
35
+ post = post_required_fields("Auth")
36
+
37
+ add_invoice(post, amount, options)
38
+ add_creditcard(post, creditcard)
39
+ add_customer_data(post, options)
40
+
41
+ commit(post)
42
+ end
43
+
44
+ def capture(amount, authorization, options={})
45
+ post = post_required_fields("Force")
46
+
47
+ add_invoice(post, amount, options)
48
+ add_reference(post, authorization)
49
+ add_customer_data(post, options)
50
+
51
+ commit(post)
52
+ end
53
+
54
+ def refund(amount, authorization, options={})
55
+ post = post_required_fields("Return")
56
+
57
+ add_invoice(post, amount, options)
58
+ add_reference(post, authorization)
59
+
60
+ commit(post)
61
+ end
62
+
63
+ def void(authorization, options={})
64
+ post = post_required_fields("Void")
65
+
66
+ add_reference(post, authorization)
67
+
68
+ commit(post)
69
+ end
70
+
71
+ private
72
+
73
+ def post_required_fields(transaction_type)
74
+ post = {}
75
+ post[:TransType] = transaction_type
76
+ post[:Amount] = ""
77
+ post[:PNRef] = ""
78
+ post[:InvNum] = ""
79
+ post[:CardNum] = ""
80
+ post[:ExpDate] = ""
81
+ post[:MagData] = ""
82
+ post[:NameOnCard] = ""
83
+ post[:Zip] = ""
84
+ post[:Street] = ""
85
+ post[:CVNum] = ""
86
+ post[:MagData] = ""
87
+ post[:ExtData] = ""
88
+ post
89
+ end
90
+
91
+ def add_customer_data(post, options)
92
+ if(billing_address = (options[:billing_address] || options[:address]))
93
+ post[:Street] = billing_address[:address1]
94
+ post[:Zip] = billing_address[:zip]
95
+ end
96
+ end
97
+
98
+ def add_invoice(post, amount, options)
99
+ post[:Amount] = amount(amount)
100
+ post[:InvNum] = options[:order_id]
101
+ end
102
+
103
+ def add_creditcard(post, creditcard)
104
+ post[:NameOnCard] = creditcard.name if creditcard.name
105
+ post[:ExpDate] = expdate(creditcard)
106
+ post[:CardNum] = creditcard.number
107
+ post[:CVNum] = creditcard.verification_value
108
+ end
109
+
110
+ def expdate(creditcard)
111
+ "#{format(creditcard.month, :two_digits)}#{format(creditcard.year, :two_digits)}"
112
+ end
113
+
114
+ def parse(xml)
115
+ response = {}
116
+
117
+ doc = Nokogiri::XML(xml)
118
+ doc.root.xpath("*").each do |node|
119
+ if (node.elements.size == 0)
120
+ response[node.name.downcase.to_sym] = node.text
121
+ else
122
+ node.elements.each do |childnode|
123
+ name = "#{node.name.downcase}_#{childnode.name.downcase}"
124
+ response[name.to_sym] = childnode.text
125
+ end
126
+ end
127
+ end unless doc.root.nil?
128
+
129
+ response
130
+ end
131
+
132
+ def commit(parameters)
133
+ url = (test? ? test_url : live_url)
134
+ data = post_data(parameters)
135
+ raw = parse(ssl_post(url, data))
136
+
137
+ Response.new(
138
+ success_from(raw[:respmsg]),
139
+ message_from(raw),
140
+ raw,
141
+ authorization: authorization_from(raw),
142
+ test: test?
143
+ )
144
+ end
145
+
146
+ def success_from(result)
147
+ case result
148
+ when "Approved"
149
+ true
150
+ else
151
+ false
152
+ end
153
+ end
154
+
155
+ def message_from(response)
156
+ response[:respmsg]
157
+ end
158
+
159
+ def authorization_from(response)
160
+ [response[:authcode], response[:pnref]].join("|")
161
+ end
162
+
163
+ def split_authorization(authorization)
164
+ authcode, pnref = authorization.split("|")
165
+ [authcode, pnref]
166
+ end
167
+
168
+ def add_reference(post, authorization)
169
+ authcode, pnref = split_authorization(authorization)
170
+ post[:AuthCode] = authcode
171
+ post[:PNRef] = pnref
172
+ end
173
+
174
+ def post_data(post)
175
+ {
176
+ :UserName => @options[:user_name],
177
+ :Password => @options[:password]
178
+ }.merge(post).collect{|k,v| "#{k}=#{CGI.escape(v.to_s)}"}.join("&")
179
+ end
180
+ end
181
+ end
182
+ end
@@ -182,8 +182,7 @@ module ActiveMerchant
182
182
  # -Builder xml document
183
183
  #
184
184
  def build_void_or_capture_request(type, money, authorization, options)
185
- reference, auth_code, ca_reference = authorization.to_s.split(';')
186
-
185
+ parsed_authorization = parse_authorization_string(authorization)
187
186
  xml = Builder::XmlMarkup.new :indent => 2
188
187
  xml.instruct!
189
188
  xml.tag! :Request do
@@ -191,8 +190,8 @@ module ActiveMerchant
191
190
 
192
191
  xml.tag! :Transaction do
193
192
  xml.tag! :HistoricTxn do
194
- xml.tag! :reference, reference
195
- xml.tag! :authcode, auth_code
193
+ xml.tag! :reference, parsed_authorization[:reference]
194
+ xml.tag! :authcode, parsed_authorization[:auth_code]
196
195
  xml.tag! :method, type
197
196
  end
198
197
 
@@ -328,8 +327,8 @@ module ActiveMerchant
328
327
  # -xml: Builder document containing the markup
329
328
  #
330
329
  def build_purchase_or_authorization_request_with_continuous_authority_reference_request(type, money, authorization, options)
331
- reference, auth_code, ca_reference = authorization.to_s.split(';')
332
- raise ArgumentError, "The continuous authority reference is required for continuous authority transactions" if ca_reference.blank?
330
+ parsed_authorization = parse_authorization_string(authorization)
331
+ raise ArgumentError, "The continuous authority reference is required for continuous authority transactions" if parsed_authorization[:ca_reference].blank?
333
332
 
334
333
  xml = Builder::XmlMarkup.new :indent => 2
335
334
  xml.instruct!
@@ -338,7 +337,7 @@ module ActiveMerchant
338
337
  xml.tag! :Transaction do
339
338
  xml.tag! :ContAuthTxn, :type => 'historic'
340
339
  xml.tag! :HistoricTxn do
341
- xml.tag! :reference, ca_reference
340
+ xml.tag! :reference, parsed_authorization[:ca_reference]
342
341
  xml.tag! :method, type
343
342
  end
344
343
  xml.tag! :TxnDetails do
@@ -371,14 +370,15 @@ module ActiveMerchant
371
370
  # </Transaction>
372
371
  # </Request>
373
372
  #
374
- def build_transaction_refund_request(money, reference)
373
+ def build_transaction_refund_request(money, authorization)
374
+ parsed_authorization = parse_authorization_string(authorization)
375
375
  xml = Builder::XmlMarkup.new :indent => 2
376
376
  xml.instruct!
377
377
  xml.tag! :Request do
378
378
  add_authentication(xml)
379
379
  xml.tag! :Transaction do
380
380
  xml.tag! :HistoricTxn do
381
- xml.tag! :reference, reference
381
+ xml.tag! :reference, parsed_authorization[:reference]
382
382
  xml.tag! :method, TRANSACTION_REFUND_TYPE
383
383
  end
384
384
  unless money.nil?
@@ -588,6 +588,11 @@ module ActiveMerchant
588
588
  def format_reference_number(number)
589
589
  number.to_s.gsub(/[^A-Za-z0-9]/, '').rjust(6, "0").first(30)
590
590
  end
591
+
592
+ def parse_authorization_string(authorization)
593
+ reference, auth_code, ca_reference = authorization.to_s.split(';')
594
+ {:reference => reference, :auth_code => auth_code, :ca_reference => ca_reference}
595
+ end
591
596
  end
592
597
  end
593
598
  end
@@ -1,34 +1,217 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
- class IatsPaymentsGateway < AuthorizeNetGateway
4
- self.live_url = self.test_url = 'https://www.iatspayments.com/netgate/AEGateway.aspx'
3
+ class IatsPaymentsGateway < Gateway
4
+ class_attribute :live_na_url, :live_uk_url
5
5
 
6
- self.homepage_url = 'http://www.iatspayments.com/'
7
- self.display_name = 'IATSPayments'
6
+ self.live_na_url = 'https://www.iatspayments.com/NetGate/ProcessLink.asmx'
7
+ self.live_uk_url = 'https://www.uk.iatspayments.com/NetGate/ProcessLink.asmx'
8
8
 
9
- def authorize(money, paysource, options = {})
10
- raise NotImplementedError
9
+ self.supported_countries = %w(AU CA CH DE DK ES FI FR GR HK IE IT JP NL NO NZ PT SE SG TR GB US)
10
+ self.default_currency = 'USD'
11
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
12
+
13
+ self.homepage_url = 'http://home.iatspayments.com/'
14
+ self.display_name = 'iATS Payments'
15
+
16
+ def initialize(options={})
17
+ if(options[:login])
18
+ deprecated("The 'login' option is deprecated in favor of 'agent_code' and will be removed in a future version.")
19
+ options[:agent_code] = options[:login]
20
+ end
21
+
22
+ options[:region] = 'na' unless options[:region]
23
+
24
+ requires!(options, :agent_code, :password, :region)
25
+ super
26
+ end
27
+
28
+ def purchase(money, payment, options={})
29
+ post = {}
30
+ add_invoice(post, money, options)
31
+ add_payment(post, payment)
32
+ add_address(post, options)
33
+ add_customer_data(post, options)
34
+
35
+ commit('ProcessCreditCardV1', post)
11
36
  end
12
37
 
13
- def capture(money, authorization, options = {})
14
- raise NotImplementedError
38
+ def authorize(money, payment, options={})
39
+ post = {}
40
+ add_invoice(post, money, options)
41
+ add_payment(post, payment)
42
+ add_address(post, options)
43
+ add_customer_data(post, options)
44
+
45
+ commit('authonly', post)
15
46
  end
16
47
 
17
- def void(authorization, options = {})
18
- raise NotImplementedError
48
+ def capture(money, authorization, options={})
49
+ commit('capture', post)
19
50
  end
20
51
 
21
- def refund(money, identification, options = {})
22
- raise NotImplementedError
52
+ def refund(money, authorization, options={})
53
+ post = {}
54
+ post[:transaction_id] = authorization
55
+ add_customer_data(post, options)
56
+ add_invoice(post, -money, options)
57
+
58
+ commit('ProcessCreditCardRefundWithTransactionIdV1', post)
23
59
  end
24
60
 
25
- def credit(money, identification, options = {})
26
- raise NotImplementedError
61
+ def void(authorization, options={})
62
+ commit('void', post)
27
63
  end
28
64
 
29
65
  private
30
- def split(response)
31
- response.split(',')
66
+
67
+ def add_customer_data(post, options)
68
+ post[:customer_ip_address] = options[:ip] if options.has_key?(:ip)
69
+ end
70
+
71
+ def add_address(post, options)
72
+ billing_address = options[:billing_address] || options[:address]
73
+ if(billing_address)
74
+ post[:address] = billing_address[:address1]
75
+ post[:city] = billing_address[:city]
76
+ post[:state] = billing_address[:state]
77
+ post[:zip_code] = billing_address[:zip]
78
+ end
79
+ end
80
+
81
+ def add_invoice(post, money, options)
82
+ post[:invoice_num] = options[:order_id] if options[:order_id]
83
+ post[:total] = amount(money)
84
+ post[:comment] = options[:description] if options[:description]
85
+ end
86
+
87
+ def add_payment(post, payment)
88
+ post[:first_name] = payment.first_name
89
+ post[:last_name] = payment.last_name
90
+ post[:credit_card_num] = payment.number
91
+ post[:credit_card_expiry] = expdate(payment)
92
+ post[:cvv2] = payment.verification_value if payment.verification_value?
93
+ post[:mop] = creditcard_brand(payment.brand)
94
+ end
95
+
96
+ def expdate(creditcard)
97
+ year = sprintf("%.4i", creditcard.year)
98
+ month = sprintf("%.2i", creditcard.month)
99
+
100
+ "#{month}/#{year[-2..-1]}"
101
+ end
102
+
103
+ def creditcard_brand(brand)
104
+ case brand
105
+ when "visa" then "VISA"
106
+ when "master" then "MC"
107
+ when "discover" then "DSC"
108
+ when "american_express" then "AMX"
109
+ when "maestro" then "MAESTR"
110
+ else
111
+ raise "Unhandled credit card brand #{brand}"
112
+ end
113
+ end
114
+
115
+ def commit(action, parameters)
116
+ response = parse(ssl_post(url(action), post_data(action, parameters),
117
+ { 'Content-Type' => 'application/soap+xml; charset=utf-8'}))
118
+
119
+ Response.new(
120
+ success_from(response),
121
+ message_from(response),
122
+ response,
123
+ authorization: authorization_from(response),
124
+ test: test?
125
+ )
126
+ end
127
+
128
+ def url(action)
129
+ base_url = @options[:region] == 'uk' ? live_uk_url : live_na_url
130
+ "#{base_url}?op=#{action}"
131
+ end
132
+
133
+ def parse(body)
134
+ response = {}
135
+ hashify_xml!(body, response)
136
+ response
137
+ end
138
+
139
+ def dexmlize_param_name(name)
140
+ names = {
141
+ 'AUTHORIZATIONRESULT' => :authorization_result,
142
+ 'SETTLEMENTBATCHDATE' => :settlement_batch_date,
143
+ 'SETTLEMENTDATE' => :settlement_date,
144
+ 'TRANSACTIONID' => :transaction_id
145
+ }
146
+ names[name] || name.to_s.downcase.intern
147
+ end
148
+
149
+ def hashify_xml!(xml, response)
150
+ xml = REXML::Document.new(xml)
151
+
152
+ # Purchase, refund
153
+ xml.elements.each("//IATSRESPONSE/*") do |node|
154
+ recursively_parse_element(node, response)
155
+ end
156
+ end
157
+
158
+ # Flatten nested XML structures
159
+ def recursively_parse_element(node, response)
160
+ if(node.has_elements?)
161
+ node.elements.each { |n| recursively_parse_element(n, response) }
162
+ else
163
+ response[dexmlize_param_name(node.name)] = (node.text ? node.text.strip : nil)
164
+ end
165
+ end
166
+
167
+ def successful_result_message?(response)
168
+ response[:authorization_result].start_with?('OK')
169
+ end
170
+
171
+ def success_from(response)
172
+ response[:status] == "Success" && successful_result_message?(response)
173
+ end
174
+
175
+ def message_from(response)
176
+ if(!successful_result_message?(response))
177
+ return response[:authorization_result].strip
178
+ elsif(response[:status] == 'Failure')
179
+ return response[:errors]
180
+ else
181
+ response[:status]
182
+ end
183
+ end
184
+
185
+ def authorization_from(response)
186
+ response[:transaction_id]
187
+ end
188
+
189
+ ENVELOPE_NAMESPACES = {
190
+ "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
191
+ "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
192
+ "xmlns:soap12" => "http://www.w3.org/2003/05/soap-envelope"
193
+ }
194
+
195
+ def post_data(action, parameters = {})
196
+ xml = Builder::XmlMarkup.new
197
+ xml.instruct!(:xml, :version => '1.0', :encoding => 'utf-8')
198
+ xml.tag! 'soap12:Envelope', ENVELOPE_NAMESPACES do
199
+ xml.tag! 'soap12:Body' do
200
+ xml.tag! action, { "xmlns" => "https://www.iatspayments.com/NetGate/" } do
201
+ xml.tag!('agentCode', @options[:agent_code])
202
+ xml.tag!('password', @options[:password])
203
+ parameters.each do |name, value|
204
+ xml.tag!(xmlize_param_name(name), value)
205
+ end
206
+ end
207
+ end
208
+ end
209
+ xml.target!
210
+ end
211
+
212
+ def xmlize_param_name(name)
213
+ names = { customer_ip_address: 'customerIPAddress' }
214
+ names[name] || name.to_s.camelcase(:lower)
32
215
  end
33
216
  end
34
217
  end