activemerchant 1.41.0 → 1.42.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 (36) hide show
  1. checksums.yaml +15 -0
  2. data/CHANGELOG +23 -1
  3. data/CONTRIBUTORS +12 -0
  4. data/README.md +3 -0
  5. data/lib/active_merchant/billing/gateway.rb +8 -1
  6. data/lib/active_merchant/billing/gateways/app55.rb +185 -0
  7. data/lib/active_merchant/billing/gateways/authorize_net.rb +12 -2
  8. data/lib/active_merchant/billing/gateways/balanced.rb +9 -3
  9. data/lib/active_merchant/billing/gateways/card_stream_modern.rb +2 -1
  10. data/lib/active_merchant/billing/gateways/elavon.rb +1 -1
  11. data/lib/active_merchant/billing/gateways/eway_rapid.rb +2 -2
  12. data/lib/active_merchant/billing/gateways/litle.rb +5 -5
  13. data/lib/active_merchant/billing/gateways/mercury.rb +22 -0
  14. data/lib/active_merchant/billing/gateways/orbital.rb +25 -2
  15. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +187 -0
  16. data/lib/active_merchant/billing/gateways/paymill.rb +60 -28
  17. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +1 -1
  18. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +4 -2
  19. data/lib/active_merchant/billing/gateways/spreedly_core.rb +4 -2
  20. data/lib/active_merchant/billing/gateways/stripe.rb +35 -15
  21. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +158 -0
  22. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +62 -46
  23. data/lib/active_merchant/billing/gateways/webpay.rb +1 -2
  24. data/lib/active_merchant/billing/integrations/bit_pay.rb +2 -2
  25. data/lib/active_merchant/billing/integrations/bit_pay/helper.rb +15 -19
  26. data/lib/active_merchant/billing/integrations/bit_pay/notification.rb +38 -20
  27. data/lib/active_merchant/billing/integrations/notification.rb +2 -2
  28. data/lib/active_merchant/billing/integrations/wirecard_checkout_page.rb +39 -0
  29. data/lib/active_merchant/billing/integrations/wirecard_checkout_page/common.rb +104 -0
  30. data/lib/active_merchant/billing/integrations/wirecard_checkout_page/helper.rb +145 -0
  31. data/lib/active_merchant/billing/integrations/wirecard_checkout_page/notification.rb +101 -0
  32. data/lib/active_merchant/billing/integrations/wirecard_checkout_page/return.rb +35 -0
  33. data/lib/active_merchant/version.rb +1 -1
  34. metadata +16 -59
  35. data.tar.gz.sig +0 -0
  36. metadata.gz.sig +0 -0
@@ -0,0 +1,158 @@
1
+ require 'json'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class SwipeCheckoutGateway < Gateway
6
+ TRANSACTION_APPROVED_MSG = 'Transaction approved'
7
+ TRANSACTION_DECLINED_MSG = 'Transaction declined'
8
+
9
+ LIVE_URLS = {
10
+ 'NZ' => 'https://api.swipehq.com',
11
+ 'CA' => 'https://api.swipehq.ca'
12
+ }
13
+ self.test_url = 'https://api.swipehq.com'
14
+
15
+ TRANSACTION_API = '/createShopifyTransaction.php'
16
+
17
+ self.supported_countries = %w[ NZ CA ]
18
+ self.default_currency = 'NZD'
19
+ self.supported_cardtypes = [:visa, :master]
20
+ self.homepage_url = 'https://www.swipehq.com/checkout'
21
+ self.display_name = 'Swipe Checkout'
22
+ self.money_format = :dollars
23
+
24
+ # Swipe Checkout requires the merchant's email and API key for authorization.
25
+ # This can be found under Settings > API Credentials after logging in to your
26
+ # Swipe Checkout merchant console at https://merchant.swipehq.[com|ca]
27
+ #
28
+ # :region determines which Swipe URL is used, this can be one of "NZ" or "CA".
29
+ # Currently Swipe Checkout has New Zealand and Canadian domains (swipehq.com
30
+ # and swipehq.ca respectively). Merchants must use the region that they
31
+ # signed up in for authentication with their merchant ID and API key to succeed.
32
+ def initialize(options = {})
33
+ requires!(options, :login, :api_key, :region)
34
+ super
35
+ end
36
+
37
+ # Transfers funds immediately.
38
+ # Note that Swipe Checkout only supports purchase at this stage
39
+ def purchase(money, creditcard, options = {})
40
+ post = {}
41
+ add_invoice(post, options)
42
+ add_creditcard(post, creditcard)
43
+ add_customer_data(post, creditcard, options)
44
+ add_amount(post, money, options)
45
+
46
+ commit('sale', money, post)
47
+ end
48
+
49
+ private
50
+
51
+ def add_customer_data(post, creditcard, options)
52
+ post[:email] = options[:email]
53
+ post[:ip_address] = options[:ip]
54
+
55
+ address = options[:billing_address] || options[:address]
56
+ return if address.nil?
57
+
58
+ post[:company] = address[:company]
59
+
60
+ # groups all names after the first into the last name param
61
+ post[:first_name], post[:last_name] = address[:name].split(' ', 2)
62
+ post[:address] = "#{address[:address1]}, #{address[:address2]}"
63
+ post[:city] = address[:city]
64
+ post[:country] = address[:country]
65
+ post[:mobile] = address[:phone] # API only has a "mobile" field, no "phone"
66
+ end
67
+
68
+ def add_invoice(post, options)
69
+ # store shopping-cart order ID in Swipe for merchant's records
70
+ post[:td_user_data] = options[:order_id] if options[:order_id]
71
+ post[:td_item] = options[:description] if options[:description]
72
+ post[:td_description] = options[:description] if options[:description]
73
+ post[:item_quantity] = "1"
74
+ end
75
+
76
+ def add_creditcard(post, creditcard)
77
+ post[:card_number] = creditcard.number
78
+ post[:card_type] = creditcard.brand
79
+ post[:name_on_card] = "#{creditcard.first_name} #{creditcard.last_name}"
80
+ post[:card_expiry] = expdate(creditcard)
81
+ post[:secure_number] = creditcard.verification_value
82
+ end
83
+
84
+ def expdate(creditcard)
85
+ year = format(creditcard.year, :two_digits)
86
+ month = format(creditcard.month, :two_digits)
87
+
88
+ "#{month}#{year}"
89
+ end
90
+
91
+ def add_amount(post, money, options)
92
+ post[:amount] = money.to_s
93
+
94
+ post[:currency] = (options[:currency] || currency(money))
95
+ end
96
+
97
+ def commit(action, money, parameters)
98
+ case action
99
+ when "sale"
100
+ begin
101
+ response = call_api(TRANSACTION_API, parameters)
102
+
103
+ # response code and message params should always be present
104
+ code = response["response_code"]
105
+ message = response["message"]
106
+
107
+ if code == 200
108
+ result = response["data"]["result"]
109
+ success = (result == 'accepted' || (test? && result == 'test-accepted'))
110
+
111
+ Response.new(success,
112
+ success ?
113
+ TRANSACTION_APPROVED_MSG :
114
+ TRANSACTION_DECLINED_MSG,
115
+ response,
116
+ :test => test?
117
+ )
118
+ else
119
+ build_error_response(message, response)
120
+ end
121
+ rescue ResponseError => e
122
+ raw_response = e.response.body
123
+ build_error_response("ssl_post() with url #{url} raised ResponseError: #{e}")
124
+ rescue JSON::ParserError => e
125
+ msg = 'Invalid response received from the Swipe Checkout API. ' +
126
+ 'Please contact support@optimizerhq.com if you continue to receive this message.' +
127
+ " (Full error message: #{e})"
128
+ build_error_response(msg)
129
+ end
130
+ end
131
+ end
132
+
133
+ def call_api(api, params=nil)
134
+ params ||= {}
135
+ params[:merchant_id] = @options[:login]
136
+ params[:api_key] = @options[:api_key]
137
+
138
+ # ssl_post() returns the response body as a string on success,
139
+ # or raises a ResponseError exception on failure
140
+ JSON.parse(ssl_post(url(@options[:region], api), params.to_query))
141
+ end
142
+
143
+ def url(region, api)
144
+ ((test? ? self.test_url : LIVE_URLS[region]) + api)
145
+ end
146
+
147
+ def build_error_response(message, params={})
148
+ Response.new(
149
+ false,
150
+ message,
151
+ params,
152
+ :test => test?
153
+ )
154
+ end
155
+ end
156
+ end
157
+ end
158
+
@@ -2,20 +2,20 @@ module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
 
4
4
  class UsaEpayTransactionGateway < Gateway
5
- self.test_url = 'https://sandbox.usaepay.com/gate.php'
6
- self.live_url = 'https://www.usaepay.com/gate.php'
5
+ self.live_url = 'https://www.usaepay.com/gate'
6
+ self.test_url = 'https://sandbox.usaepay.com/gate'
7
7
 
8
- self.supported_cardtypes = [:visa, :master, :american_express]
9
- self.supported_countries = ['US']
10
- self.homepage_url = 'http://www.usaepay.com/'
11
- self.display_name = 'USA ePay'
8
+ self.supported_cardtypes = [:visa, :master, :american_express]
9
+ self.supported_countries = ['US']
10
+ self.homepage_url = 'http://www.usaepay.com/'
11
+ self.display_name = 'USA ePay'
12
12
 
13
13
  TRANSACTIONS = {
14
- :authorization => 'authonly',
15
- :purchase => 'sale',
16
- :capture => 'capture',
17
- :refund => 'refund',
18
- :void => 'void'
14
+ :authorization => 'cc:authonly',
15
+ :purchase => 'cc:sale',
16
+ :capture => 'cc:capture',
17
+ :refund => 'cc:refund',
18
+ :void => 'cc:void'
19
19
  }
20
20
 
21
21
  def initialize(options = {})
@@ -31,6 +31,7 @@ module ActiveMerchant #:nodoc:
31
31
  add_credit_card(post, credit_card)
32
32
  add_address(post, credit_card, options)
33
33
  add_customer_data(post, options)
34
+ add_split_payments(post, options)
34
35
 
35
36
  commit(:authorization, post)
36
37
  end
@@ -43,6 +44,7 @@ module ActiveMerchant #:nodoc:
43
44
  add_credit_card(post, credit_card)
44
45
  add_address(post, credit_card, options)
45
46
  add_customer_data(post, options)
47
+ add_split_payments(post, options)
46
48
 
47
49
  commit(:purchase, post)
48
50
  end
@@ -66,7 +68,7 @@ module ActiveMerchant #:nodoc:
66
68
  commit(:void, post)
67
69
  end
68
70
 
69
- private
71
+ private
70
72
 
71
73
  def add_amount(post, money)
72
74
  post[:amount] = amount(money)
@@ -108,16 +110,16 @@ module ActiveMerchant #:nodoc:
108
110
  def add_address_for_type(type, post, credit_card, address)
109
111
  prefix = address_key_prefix(type)
110
112
 
111
- post[address_key(prefix, 'fname')] = credit_card.first_name
112
- post[address_key(prefix, 'lname')] = credit_card.last_name
113
- post[address_key(prefix, 'company')] = address[:company] unless address[:company].blank?
114
- post[address_key(prefix, 'street')] = address[:address1] unless address[:address1].blank?
115
- post[address_key(prefix, 'street2')] = address[:address2] unless address[:address2].blank?
116
- post[address_key(prefix, 'city')] = address[:city] unless address[:city].blank?
117
- post[address_key(prefix, 'state')] = address[:state] unless address[:state].blank?
118
- post[address_key(prefix, 'zip')] = address[:zip] unless address[:zip].blank?
119
- post[address_key(prefix, 'country')] = address[:country] unless address[:country].blank?
120
- post[address_key(prefix, 'phone')] = address[:phone] unless address[:phone].blank?
113
+ post[address_key(prefix, 'fname')] = credit_card.first_name
114
+ post[address_key(prefix, 'lname')] = credit_card.last_name
115
+ post[address_key(prefix, 'company')] = address[:company] unless address[:company].blank?
116
+ post[address_key(prefix, 'street')] = address[:address1] unless address[:address1].blank?
117
+ post[address_key(prefix, 'street2')] = address[:address2] unless address[:address2].blank?
118
+ post[address_key(prefix, 'city')] = address[:city] unless address[:city].blank?
119
+ post[address_key(prefix, 'state')] = address[:state] unless address[:state].blank?
120
+ post[address_key(prefix, 'zip')] = address[:zip] unless address[:zip].blank?
121
+ post[address_key(prefix, 'country')] = address[:country] unless address[:country].blank?
122
+ post[address_key(prefix, 'phone')] = address[:phone] unless address[:phone].blank?
121
123
  end
122
124
 
123
125
  def address_key_prefix(type)
@@ -132,15 +134,29 @@ module ActiveMerchant #:nodoc:
132
134
  end
133
135
 
134
136
  def add_invoice(post, options)
135
- post[:invoice] = options[:order_id]
136
- post[:description] = options[:description]
137
+ post[:invoice] = options[:order_id]
138
+ post[:description] = options[:description]
137
139
  end
138
140
 
139
141
  def add_credit_card(post, credit_card)
140
- post[:card] = credit_card.number
141
- post[:cvv2] = credit_card.verification_value if credit_card.verification_value?
142
+ post[:card] = credit_card.number
143
+ post[:cvv2] = credit_card.verification_value if credit_card.verification_value?
142
144
  post[:expir] = expdate(credit_card)
143
- post[:name] = credit_card.name
145
+ post[:name] = credit_card.name
146
+ end
147
+
148
+ # see: http://wiki.usaepay.com/developer/transactionapi#split_payments
149
+ def add_split_payments(post, options)
150
+ return unless options[:split_payments].is_a?(Array)
151
+ options[:split_payments].each_with_index do |payment, index|
152
+ prefix = '%02d' % (index + 2)
153
+ post["#{prefix}key"] = payment[:key]
154
+ post["#{prefix}amount"] = amount(payment[:amount])
155
+ post["#{prefix}description"] = payment[:description]
156
+ end
157
+
158
+ # When blank it's 'Stop'. 'Continue' is another one
159
+ post['onError'] = options[:on_error] || 'Void'
144
160
  end
145
161
 
146
162
  def parse(body)
@@ -151,32 +167,32 @@ module ActiveMerchant #:nodoc:
151
167
  end
152
168
 
153
169
  {
154
- :status => fields['UMstatus'],
155
- :auth_code => fields['UMauthCode'],
156
- :ref_num => fields['UMrefNum'],
157
- :batch => fields['UMbatch'],
158
- :avs_result => fields['UMavsResult'],
159
- :avs_result_code => fields['UMavsResultCode'],
160
- :cvv2_result => fields['UMcvv2Result'],
170
+ :status => fields['UMstatus'],
171
+ :auth_code => fields['UMauthCode'],
172
+ :ref_num => fields['UMrefNum'],
173
+ :batch => fields['UMbatch'],
174
+ :avs_result => fields['UMavsResult'],
175
+ :avs_result_code => fields['UMavsResultCode'],
176
+ :cvv2_result => fields['UMcvv2Result'],
161
177
  :cvv2_result_code => fields['UMcvv2ResultCode'],
162
178
  :vpas_result_code => fields['UMvpasResultCode'],
163
- :result => fields['UMresult'],
164
- :error => fields['UMerror'],
165
- :error_code => fields['UMerrorcode'],
166
- :acs_url => fields['UMacsurl'],
167
- :payload => fields['UMpayload']
179
+ :result => fields['UMresult'],
180
+ :error => fields['UMerror'],
181
+ :error_code => fields['UMerrorcode'],
182
+ :acs_url => fields['UMacsurl'],
183
+ :payload => fields['UMpayload']
168
184
  }.delete_if{|k, v| v.nil?}
169
185
  end
170
186
 
171
187
  def commit(action, parameters)
172
- url = (self.test? ? self.test_url : self.live_url)
173
- response = parse( ssl_post(url, post_data(action, parameters)) )
188
+ url = (test? ? self.test_url : self.live_url)
189
+ response = parse(ssl_post(url, post_data(action, parameters)))
174
190
 
175
191
  Response.new(response[:status] == 'Approved', message_from(response), response,
176
- :test => test?,
177
- :authorization => response[:ref_num],
178
- :cvv_result => response[:cvv2_result_code],
179
- :avs_result => { :code => response[:avs_result_code] }
192
+ :test => test?,
193
+ :authorization => response[:ref_num],
194
+ :cvv_result => response[:cvv2_result_code],
195
+ :avs_result => { :code => response[:avs_result_code] }
180
196
  )
181
197
  end
182
198
 
@@ -191,7 +207,7 @@ module ActiveMerchant #:nodoc:
191
207
 
192
208
  def post_data(action, parameters = {})
193
209
  parameters[:command] = TRANSACTIONS[action]
194
- parameters[:key] = @options[:login]
210
+ parameters[:key] = @options[:login]
195
211
  parameters[:software] = 'Active Merchant'
196
212
  parameters[:testmode] = (@options[:test] ? 1 : 0)
197
213
 
@@ -68,8 +68,7 @@ module ActiveMerchant #:nodoc:
68
68
  :lang => 'ruby',
69
69
  :lang_version => "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})",
70
70
  :platform => RUBY_PLATFORM,
71
- :publisher => 'active_merchant',
72
- :uname => (RUBY_PLATFORM =~ /linux|darwin/i ? `uname -a 2>/dev/null`.strip : nil)
71
+ :publisher => 'active_merchant'
73
72
  })
74
73
 
75
74
  {
@@ -13,8 +13,8 @@ module ActiveMerchant #:nodoc:
13
13
  mattr_accessor :invoicing_url
14
14
  self.invoicing_url = 'https://bitpay.com/api/invoice'
15
15
 
16
- def self.notification(post)
17
- Notification.new(post)
16
+ def self.notification(post, options = {})
17
+ Notification.new(post, options)
18
18
  end
19
19
 
20
20
  def self.helper(order, account, options = {})
@@ -6,20 +6,14 @@ module ActiveMerchant #:nodoc:
6
6
  def initialize(order_id, account, options)
7
7
  super
8
8
  @account = account
9
- add_field('orderID', order_id)
10
- add_field('posData', options[:authcode])
11
- add_field('currency', options[:currency])
12
- add_field('fullNotifications', 'true')
13
- add_field('transactionSpeed', options[:transactionSpeed] || "high")
14
- add_field('address1', options[:address1])
15
9
 
16
- generate_invoice_id
10
+ add_field('posData', {'orderId' => order_id}.to_json)
11
+ add_field('fullNotifications', true)
12
+ add_field('transactionSpeed', 'high')
17
13
  end
18
14
 
19
- # Replace with the real mapping
20
15
  mapping :amount, 'price'
21
-
22
- mapping :order, 'orderID'
16
+ mapping :order, 'orderID'
23
17
  mapping :currency, 'currency'
24
18
 
25
19
  mapping :customer, :first_name => 'buyerName',
@@ -37,20 +31,20 @@ module ActiveMerchant #:nodoc:
37
31
  mapping :return_url, 'redirectURL'
38
32
  mapping :id, 'id'
39
33
 
40
- def generate_invoice_id
41
- invoice_data = ssl_post(BitPay.invoicing_url)
42
-
43
- add_field('id', JSON.parse(invoice_data.body)['id'])
44
- end
45
-
46
34
  def form_method
47
35
  "GET"
48
36
  end
49
37
 
38
+ def form_fields
39
+ invoice = create_invoice
40
+
41
+ {"id" => invoice['id']}
42
+ end
43
+
50
44
  private
51
45
 
52
- def ssl_post(url, options = {})
53
- uri = URI.parse(url)
46
+ def create_invoice
47
+ uri = URI.parse(BitPay.invoicing_url)
54
48
  http = Net::HTTP.new(uri.host, uri.port)
55
49
  http.use_ssl = true
56
50
 
@@ -59,7 +53,9 @@ module ActiveMerchant #:nodoc:
59
53
  request.body = @fields.to_json
60
54
  request.basic_auth @account, ''
61
55
 
62
- http.request(request)
56
+ response = http.request(request)
57
+ JSON.parse(response.body)
58
+ rescue JSON::ParseError
63
59
  end
64
60
  end
65
61
  end
@@ -6,13 +6,29 @@ module ActiveMerchant #:nodoc:
6
6
  module BitPay
7
7
  class Notification < ActiveMerchant::Billing::Integrations::Notification
8
8
  def complete?
9
- status == "complete"
9
+ status == "Completed"
10
10
  end
11
11
 
12
12
  def transaction_id
13
13
  params['id']
14
14
  end
15
15
 
16
+ def item_id
17
+ JSON.parse(params['posData'])['orderId']
18
+ rescue JSON::ParserError
19
+ end
20
+
21
+ def status
22
+ case params['status']
23
+ when 'complete'
24
+ 'Completed'
25
+ when 'confirmed'
26
+ 'Pending'
27
+ when 'invalid'
28
+ 'Failed'
29
+ end
30
+ end
31
+
16
32
  # When was this payment received by the client.
17
33
  def received_at
18
34
  params['invoiceTime'].to_i
@@ -22,32 +38,34 @@ module ActiveMerchant #:nodoc:
22
38
  params['currency']
23
39
  end
24
40
 
25
- def amount
26
- params['price']
41
+ def gross
42
+ params['price'].to_f
27
43
  end
28
44
 
29
- # the money amount we received in X.2 decimal.
30
- def btcPrice
31
- params['btcPrice'].to_f
32
- end
45
+ def acknowledge(authcode = nil)
46
+ uri = URI.parse("#{ActiveMerchant::Billing::Integrations::BitPay.invoicing_url}/#{transaction_id}")
33
47
 
34
- def status
35
- params['status'].downcase
36
- end
48
+ http = Net::HTTP.new(uri.host, uri.port)
49
+ http.use_ssl = true
37
50
 
38
- def acknowledge(authcode = nil)
39
- authcode == params['posData']
51
+ request = Net::HTTP::Get.new(uri.path)
52
+ request.basic_auth @options[:credential1], ''
53
+
54
+ response = http.request(request)
55
+
56
+ posted_json = JSON.parse(@raw).tap { |j| j.delete('currentTime') }
57
+ parse(response.body)
58
+ retrieved_json = JSON.parse(@raw).tap { |j| j.delete('currentTime') }
59
+
60
+ posted_json == retrieved_json
61
+ rescue JSON::ParserError
40
62
  end
41
63
 
42
64
  private
43
-
44
- # Take the posted data and move the relevant data into a hash
45
- def parse(post)
46
- @raw = post.to_s
47
- for line in @raw.split('&')
48
- key, value = *line.scan( %r{^([A-Za-z0-9_.]+)\=(.*)$} ).flatten
49
- params[key] = CGI.unescape(value)
50
- end
65
+ def parse(body)
66
+ @raw = body
67
+ @params = JSON.parse(@raw)
68
+ rescue JSON::ParserError
51
69
  end
52
70
  end
53
71
  end