offsite_payments 2.7.20 → 2.7.27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -2
  3. data/lib/offsite_payments.rb +1 -1
  4. data/lib/offsite_payments/integrations/a1agregator.rb +0 -8
  5. data/lib/offsite_payments/integrations/bit_pay.rb +1 -1
  6. data/lib/offsite_payments/integrations/citrus.rb +2 -2
  7. data/lib/offsite_payments/integrations/direc_pay.rb +1 -1
  8. data/lib/offsite_payments/integrations/easy_pay.rb +1 -1
  9. data/lib/offsite_payments/integrations/epay.rb +2 -2
  10. data/lib/offsite_payments/integrations/gestpay.rb +2 -2
  11. data/lib/offsite_payments/integrations/liqpay.rb +2 -2
  12. data/lib/offsite_payments/integrations/mollie_ideal.rb +1 -1
  13. data/lib/offsite_payments/integrations/mollie_mistercash.rb +1 -1
  14. data/lib/offsite_payments/integrations/pag_seguro.rb +1 -1
  15. data/lib/offsite_payments/integrations/paxum.rb +2 -2
  16. data/lib/offsite_payments/integrations/pay_fast.rb +1 -1
  17. data/lib/offsite_payments/integrations/payflow_link.rb +0 -4
  18. data/lib/offsite_payments/integrations/paytm.rb +2 -2
  19. data/lib/offsite_payments/integrations/payu_in.rb +3 -3
  20. data/lib/offsite_payments/integrations/platron.rb +1 -1
  21. data/lib/offsite_payments/integrations/quickpay.rb +1 -1
  22. data/lib/offsite_payments/integrations/quickpay_v10.rb +173 -0
  23. data/lib/offsite_payments/integrations/realex_offsite.rb +549 -15
  24. data/lib/offsite_payments/integrations/sage_pay_form.rb +1 -0
  25. data/lib/offsite_payments/integrations/universal.rb +0 -1
  26. data/lib/offsite_payments/integrations/web_pay.rb +1 -1
  27. data/lib/offsite_payments/integrations/webmoney.rb +1 -1
  28. data/lib/offsite_payments/version.rb +1 -1
  29. metadata +5 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52bf59c63646b7d0fd207a51bb3e977e14234edd0d7b4d494967ebde13ead384
4
- data.tar.gz: 97d45379f6df925b274285ebec7f7b8380396dd3c46162734191b7a6ac03d83b
3
+ metadata.gz: 26c27fc431af5ea0650cb099bd36dc13ec371928e9f1ceabbe2aff0a09904a6e
4
+ data.tar.gz: 99edfdf3c683213d89fb05dc227c7323e2ded4e6725ea3d232a6a142cf38def5
5
5
  SHA512:
6
- metadata.gz: 85fc3bf1c22cdf71b0a4497b44eecb9406f5ff1538eb4d50ea9a26212a13002f8b8a59fc71e5ac2d7d037dda6a39ef7dbae4ec10d2faed2431d736c95565240e
7
- data.tar.gz: ba78f07a16f201b9607a98088c4c9173d855ef59ce34e7086334380ff5349d9a6772aea721f2be5bf1b99529061ad10347c9f97ff78e2a80145e0a78378cd051
6
+ metadata.gz: 3d15d1a95e2e6230b67176ceb7bdb8dc4831923611fe9dc93304d4a9a727acc97361117978161a8c31bf40c6df01f152bfe72e24f7af6626b7c0851a6e142a76
7
+ data.tar.gz: 83a2c6d68f7979cc7ba91ca7842aef2774f34e3e412f8c97da063e327c36ee0f78dab2c6a99a4c0d37f90ccc878da6ac69454ff47564f4bff69420051132808f
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Offsite Payments
2
- [![Build Status](https://travis-ci.org/activemerchant/offsite_payments.svg?branch=master)](https://travis-ci.org/activemerchant/offsite_payments)
2
+ [![Build Status](https://github.com/activemerchant/offsite_payments/workflows/CI/badge.svg?branch=master)](https://github.com/activemerchant/offsite_payments/actions?query=workflow%3ACI)
3
3
  [![Code Climate](https://codeclimate.com/github/activemerchant/offsite_payments/badges/gpa.svg)](https://codeclimate.com/github/activemerchant/offsite_payments)
4
4
 
5
5
  Offsite Payments is an extraction from the ecommerce system [Shopify](http://www.shopify.com). Shopify's requirements for a simple and unified API to handle dozens of different offsite payment pages (often called hosted payment pages) with very different exposed APIs was the chief principle in designing the library.
@@ -67,6 +67,7 @@ one.
67
67
  * [Dwolla](https://www.dwolla.com/default.aspx)
68
68
  * [ePay](http://www.epay.dk/epay-payment-solutions/)
69
69
  * [First Data](https://firstdata.zendesk.com/entries/407522-first-data-global-gateway-e4sm-payment-pages-integration-manual)
70
+ * [Realex](https://www.globalpaymentsinc.com)
70
71
  * [HiTRUST](http://www.hitrust.com.hk/)
71
72
  * [MOLPay](http://www.molpay.com/v2/) - MY, SG, ID, TH, VN, PH, CN, AU
72
73
  * [Moneybookers](http://www.moneybookers.com)
@@ -77,7 +78,7 @@ one.
77
78
  * [PayDollar](http://www.paydollar.com)
78
79
  * [Paysbuy](https://www.paysbuy.com/) - TH
79
80
  * [Platron](https://www.platron.ru/) - RU
80
- * [Realex](http://www.realexpayments.com)
81
+ * [QuickPay](http://quickpay.net/dk/) - AT, DE, DK, EE, LT, LV, FO, NL, NO, SE, UK
81
82
  * [RBK Money](https://rbkmoney.ru/) - RU
82
83
  * [Robokassa](http://robokassa.ru/) - RU
83
84
  * [SagePay Form](http://www.sagepay.com/products_services/sage_pay_go/integration/form)
@@ -40,5 +40,5 @@ module OffsitePayments
40
40
  self.mode == :test
41
41
  end
42
42
 
43
- CURRENCIES_WITHOUT_FRACTIONS = [ 'BIF', 'BYR', 'CLP', 'CVE', 'DJF', 'GNF', 'HUF', 'ISK', 'JPY', 'KMF', 'KRW', 'PYG', 'RWF', 'TWD', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF' ]
43
+ CURRENCIES_WITHOUT_FRACTIONS = [ 'BIF', 'BYR', 'CLP', 'CVE', 'DJF', 'GNF', 'ISK', 'JPY', 'KMF', 'KRW', 'PYG', 'RWF', 'TWD', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF' ]
44
44
  end
@@ -93,14 +93,6 @@ module OffsitePayments #:nodoc:
93
93
  params['type']
94
94
  end
95
95
 
96
- def partner_income
97
- params['partner_income']
98
- end
99
-
100
- def system_income
101
- params['system_income']
102
- end
103
-
104
96
  # Additional notification request params:
105
97
  # tid
106
98
  # name
@@ -41,7 +41,7 @@ module OffsitePayments #:nodoc:
41
41
  add_field('fullNotifications', true)
42
42
  add_field('transactionSpeed', 'high')
43
43
  add_field('token', account)
44
- end
44
+ end
45
45
 
46
46
  mapping :amount, 'price'
47
47
  mapping :order, 'orderID'
@@ -119,7 +119,7 @@ module OffsitePayments
119
119
  end
120
120
 
121
121
  def amount
122
- Money.from_amount(BigDecimal.new(gross), currency)
122
+ Money.from_amount(BigDecimal(gross), currency)
123
123
  end
124
124
 
125
125
  def transaction_id
@@ -202,7 +202,7 @@ module OffsitePayments
202
202
  end
203
203
 
204
204
  def status( order_id, order_amount )
205
- if @notification.invoice_ok?( order_id ) && @notification.amount_ok?( BigDecimal.new(order_amount) )
205
+ if @notification.invoice_ok?( order_id ) && @notification.amount_ok?(BigDecimal(order_amount))
206
206
  @notification.status
207
207
  else
208
208
  'Mismatch'
@@ -320,7 +320,7 @@ module OffsitePayments #:nodoc:
320
320
  data = ActiveUtils::PostData.new
321
321
  data[:requestparams] = parameters.join('|')
322
322
 
323
- response = ssl_get("#{url}?#{data.to_post_data}")
323
+ ssl_get("#{url}?#{data.to_post_data}")
324
324
  end
325
325
 
326
326
  def test?
@@ -101,7 +101,7 @@ module OffsitePayments #:nodoc:
101
101
  end
102
102
 
103
103
  def amount
104
- Money.from_amount(BigDecimal.new(gross), currency)
104
+ Money.from_amount(BigDecimal(gross), currency)
105
105
  end
106
106
 
107
107
  def item_id
@@ -125,7 +125,7 @@ module OffsitePayments #:nodoc:
125
125
  return false
126
126
  end
127
127
 
128
- %w(txnid orderid currency date time hash fraud payercountry issuercountry txnfee subscriptionid paymenttype cardno).each do |attr|
128
+ %w(txnid orderid date time hash fraud payercountry issuercountry txnfee subscriptionid paymenttype cardno).each do |attr|
129
129
  define_method(attr) do
130
130
  params[attr]
131
131
  end
@@ -138,7 +138,7 @@ module OffsitePayments #:nodoc:
138
138
  def generate_md5string
139
139
  md5string = String.new
140
140
  for line in @raw.split('&')
141
- key, value = *line.scan( %r{^([A-Za-z0-9_.]+)\=(.*)$} ).flatten
141
+ key, _ = *line.scan( %r{^([A-Za-z0-9_.]+)\=(.*)$} ).flatten
142
142
  md5string += params[key] if key != 'hash'
143
143
  end
144
144
  return md5string + @options[:credential3]
@@ -4,7 +4,7 @@ module OffsitePayments #:nodoc:
4
4
  module Integrations #:nodoc:
5
5
  module Gestpay
6
6
  mattr_accessor :service_url
7
- self.service_url = 'https://ecomm.sella.it/gestpay/pagam.asp'
7
+ self.service_url = 'https://ecomm.sella.it/pagam/pagam.aspx'
8
8
 
9
9
  def self.notification(post, options = {})
10
10
  Notification.new(post)
@@ -189,7 +189,7 @@ module OffsitePayments #:nodoc:
189
189
  response = ssl_get(Gestpay.service_url, decryption_query_string(shop_login, encrypted_string))
190
190
  encoded_response = parse_response(response)
191
191
  parse_delimited_string(encoded_response, DELIMITER, true)
192
- rescue GestpayEncryptionResponseError => e
192
+ rescue GestpayEncryptionResponseError
193
193
  { 'PAY1_TRANSACTIONRESULT' => 'Error' }
194
194
  end
195
195
 
@@ -80,7 +80,7 @@ module OffsitePayments #:nodoc:
80
80
  end
81
81
 
82
82
  def amount
83
- Money.from_amount(BigDecimal.new(gross), currency)
83
+ Money.from_amount(BigDecimal(gross), currency)
84
84
  end
85
85
 
86
86
  def item_id
@@ -156,7 +156,7 @@ module OffsitePayments #:nodoc:
156
156
  end
157
157
 
158
158
  def amount
159
- BigDecimal.new(gross)
159
+ BigDecimal(gross)
160
160
  end
161
161
 
162
162
  def item_id
@@ -133,7 +133,7 @@ module OffsitePayments #:nodoc:
133
133
  end
134
134
 
135
135
  def gross_cents
136
- (BigDecimal.new(@params['amount'], 2) * 100).to_i
136
+ (BigDecimal(@params['amount'], 2) * 100).to_i
137
137
  end
138
138
 
139
139
  def status
@@ -100,7 +100,7 @@ module OffsitePayments #:nodoc:
100
100
  end
101
101
 
102
102
  def gross_cents
103
- (BigDecimal.new(@params['amount'], 2) * 100).to_i
103
+ (BigDecimal(@params['amount'], 2) * 100).to_i
104
104
  end
105
105
 
106
106
  def status
@@ -111,7 +111,7 @@ module OffsitePayments #:nodoc:
111
111
  check_for_errors(response, xml)
112
112
 
113
113
  extract_token(xml)
114
- rescue Timeout::Error, Errno::ECONNRESET, Errno::ETIMEDOUT => e
114
+ rescue Timeout::Error, Errno::ECONNRESET, Errno::ETIMEDOUT
115
115
  raise ActionViewHelperError, "Erro ao conectar-se ao PagSeguro. Por favor, tente novamente."
116
116
  end
117
117
 
@@ -34,9 +34,9 @@ module OffsitePayments #:nodoc:
34
34
 
35
35
  module Common
36
36
  def generate_signature_string
37
- @raw_post.slice!(0) if @raw_post.starts_with?("&")
37
+ @raw_post.slice!(0) if @raw_post.start_with?("&")
38
38
  @raw_post = CGI.unescape(@raw_post)
39
- @raw_post = "&#{@raw_post}" unless @raw_post.starts_with?("&")
39
+ @raw_post = "&#{@raw_post}" unless @raw_post.start_with?("&")
40
40
  arr = @raw_post.split('&')
41
41
  arr.delete(arr.last)
42
42
  data = arr.join('&')
@@ -212,7 +212,7 @@ module OffsitePayments #:nodoc:
212
212
 
213
213
  # The net amount credited to the receiver's account.
214
214
  def amount
215
- Money.from_amount(BigDecimal.new(params['amount_net']), currency)
215
+ Money.from_amount(BigDecimal(params['amount_net']), currency)
216
216
  end
217
217
 
218
218
  # The name of the item being charged for.
@@ -138,10 +138,6 @@ module OffsitePayments #:nodoc:
138
138
  nil
139
139
  end
140
140
 
141
- def status
142
- params['RESPMSG']
143
- end
144
-
145
141
  # Id of this transaction (paypal number)
146
142
  def transaction_id
147
143
  params['PNREF']
@@ -136,7 +136,7 @@ module OffsitePayments #:nodoc:
136
136
 
137
137
  # Order amount should be equal to gross
138
138
  def amount_ok?(order_amount)
139
- BigDecimal.new(original_gross) == order_amount
139
+ BigDecimal(original_gross) == order_amount
140
140
  end
141
141
 
142
142
  # Status of transaction return from the Paytm. List of possible values:
@@ -245,7 +245,7 @@ module OffsitePayments #:nodoc:
245
245
  end
246
246
 
247
247
  def status(order_id, order_amount)
248
- if @notification.invoice_ok?(order_id) && @notification.amount_ok?(BigDecimal.new(order_amount))
248
+ if @notification.invoice_ok?(order_id) && @notification.amount_ok?(BigDecimal(order_amount))
249
249
  @notification.status
250
250
  else
251
251
  'Mismatch'
@@ -116,9 +116,9 @@ module OffsitePayments #:nodoc:
116
116
  end
117
117
 
118
118
  # Order amount should be equal to gross - discount
119
- def amount_ok?( order_amount, order_discount = BigDecimal.new( '0.0' ) )
119
+ def amount_ok?( order_amount, order_discount = BigDecimal( '0.0' ) )
120
120
  parsed_discount = discount.nil? ? 0.to_d : discount.to_d
121
- BigDecimal.new( original_gross ) == order_amount && parsed_discount == order_discount
121
+ BigDecimal( original_gross ) == order_amount && parsed_discount == order_discount
122
122
  end
123
123
 
124
124
  # Status of transaction return from the PayU. List of possible values:
@@ -258,7 +258,7 @@ module OffsitePayments #:nodoc:
258
258
  end
259
259
 
260
260
  def status( order_id, order_amount )
261
- if @notification.invoice_ok?( order_id ) && @notification.amount_ok?( BigDecimal.new(order_amount) )
261
+ if @notification.invoice_ok?( order_id ) && @notification.amount_ok?( BigDecimal(order_amount) )
262
262
  @notification.status
263
263
  else
264
264
  'Mismatch'
@@ -120,7 +120,7 @@ module OffsitePayments #:nodoc:
120
120
  end
121
121
 
122
122
  def amount
123
- Money.from_amount(BigDecimal.new(params['pg_amount']), currency)
123
+ Money.from_amount(BigDecimal(params['pg_amount']), currency)
124
124
  end
125
125
 
126
126
  def secret
@@ -2,7 +2,7 @@ module OffsitePayments #:nodoc:
2
2
  module Integrations #:nodoc:
3
3
  module Quickpay
4
4
  mattr_accessor :service_url
5
- self.service_url = 'https://secure.quickpay.dk/form/'
5
+ self.service_url = 'https://legacy-proxy.quickpay.net/form/'
6
6
 
7
7
  def self.notification(post, options = {})
8
8
  Notification.new(post, options)
@@ -0,0 +1,173 @@
1
+ require 'openssl'
2
+
3
+ module OffsitePayments #:nodoc:
4
+ module Integrations #:nodoc:
5
+ module QuickpayV10
6
+ mattr_accessor :service_url
7
+ self.service_url = 'https://payment.quickpay.net'
8
+
9
+ def self.notification(post, options = {})
10
+ Notification.new(post)
11
+ end
12
+
13
+ def self.return(post, options = {})
14
+ Return.new(post, options)
15
+ end
16
+
17
+ # credential2: Payment window API key
18
+ class Helper < OffsitePayments::Helper
19
+ def initialize(order, account, options = {})
20
+ payment_window_api_key options.delete(:credential2)
21
+ super
22
+ add_field('version', 'v10')
23
+ add_field('type', 'payment')
24
+ add_field('language', 'da')
25
+ add_field('autocapture', 0)
26
+ add_field('order_id', format_order_number(order))
27
+ end
28
+
29
+ def payment_window_api_key(value)
30
+ @payment_window_api_key = value
31
+ end
32
+
33
+ def form_fields
34
+ @fields.merge('checksum' => generate_checksum)
35
+ end
36
+
37
+ def flatten_params(obj, result = {}, path = [])
38
+ case obj
39
+ when Hash
40
+ obj.each do |k, v|
41
+ flatten_params(v, result, [*path, k])
42
+ end
43
+ when Array
44
+ obj.each_with_index do |v, i|
45
+ flatten_params(v, result, [*path, i])
46
+ end
47
+ else
48
+ result[path.map{|p| "[#{p}]"}.join.to_sym] = obj
49
+ end
50
+ result
51
+ end
52
+
53
+ def generate_checksum
54
+ flattened_params = flatten_params(@fields)
55
+ values = flattened_params.sort.map { |_, value| value }
56
+ base = values.join(' ')
57
+ OpenSSL::HMAC.hexdigest('sha256', @payment_window_api_key, base)
58
+ end
59
+
60
+ # Limited to 20 digits max
61
+ def format_order_number(number)
62
+ number.to_s.gsub(/[^\w]/, '').rjust(4, "0")[0...20]
63
+ end
64
+
65
+ mapping :version, 'version'
66
+ mapping :type, 'type'
67
+ mapping :account, 'merchant_id'
68
+ mapping :language, 'language'
69
+ mapping :amount, 'amount'
70
+ mapping :currency, 'currency'
71
+
72
+ mapping :return_url, 'continueurl'
73
+ mapping :cancel_return_url, 'cancelurl'
74
+ mapping :notify_url, 'callbackurl'
75
+
76
+ mapping :autocapture, 'autocapture'
77
+ mapping :autofee, 'autofee'
78
+
79
+ mapping :description, 'description'
80
+ mapping :payment_methods, 'payment_methods'
81
+ mapping :acquirer, 'acquirer'
82
+ mapping :branding_id, 'branding_id'
83
+ mapping :google_analytics_tracking_id, 'google_analytics_tracking_id'
84
+ mapping :google_analytics_client_id, 'google_analytics_client_id'
85
+ mapping :variables, 'variables'
86
+ mapping :text_on_statement, 'text_on_statement'
87
+ mapping :customer_email, 'customer_email'
88
+
89
+ mapping :splitpayment, 'splitpayment'
90
+ mapping :forcemobile, 'forcemobile'
91
+ mapping :deadline, 'deadline'
92
+ mapping :cardhash, 'cardhash'
93
+
94
+ mapping :invoice_address, {}
95
+ mapping :billing_address, {}
96
+ end
97
+
98
+ # credential3: private key
99
+ # checksum_header: QuickPay-Checksum-Sha256 request header value
100
+ class Notification < OffsitePayments::Notification
101
+ # http://tech.quickpay.net/appendixes/errors/
102
+ def complete?
103
+ status == '20000'
104
+ end
105
+
106
+ def item_id
107
+ params['order_id']
108
+ end
109
+
110
+ def transaction_id
111
+ params['id']
112
+ end
113
+
114
+ def received_at
115
+ Time.iso8601(params['created_at'])
116
+ end
117
+
118
+ def gross
119
+ "%.2f" % (gross_cents / 100.0)
120
+ end
121
+
122
+ def gross_cents
123
+ last_operation['amount']
124
+ end
125
+
126
+ def last_operation
127
+ params['operations'].last
128
+ end
129
+
130
+ def status
131
+ last_operation['qp_status_code'] if last_operation
132
+ end
133
+
134
+ # Provide access to raw fields from quickpay
135
+ %w(
136
+ accepted
137
+ test_mode
138
+ branding_id
139
+ variables
140
+ acquirer
141
+ operations
142
+ metadata
143
+ balance
144
+ currency
145
+ ).each do |attr|
146
+ define_method(attr) do
147
+ params[attr]
148
+ end
149
+ end
150
+
151
+ def generate_checksum
152
+ OpenSSL::HMAC.hexdigest('sha256', @options[:credential3], @raw)
153
+ end
154
+
155
+ def checksum_header
156
+ @options[:checksum_header]
157
+ end
158
+
159
+ # Quickpay doesn't do acknowledgements of callback notifications
160
+ # Instead it provides a SHA256 checksum header
161
+ def acknowledge(authcode = nil)
162
+ generate_checksum == checksum_header
163
+ end
164
+
165
+ # Take the posted data and move the relevant data into a hash
166
+ def parse(post)
167
+ @raw = post.to_s
168
+ @params = JSON.parse(post)
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
@@ -63,6 +63,335 @@ module OffsitePayments #:nodoc:
63
63
  'COU' => 4
64
64
  }
65
65
 
66
+ CANADIAN_STATES = {
67
+ 'AB' => 'Alberta',
68
+ 'BC' => 'British Columbia',
69
+ 'MB' => 'Manitoba',
70
+ 'NB' => 'New Brunswick',
71
+ 'NL' => 'Newfoundland',
72
+ 'NS' => 'Nova Scotia',
73
+ 'NU' => 'Nunavut',
74
+ 'NT' => 'Northwest Territories',
75
+ 'ON' => 'Ontario',
76
+ 'PE' => 'Prince Edward Island',
77
+ 'QC' => 'Quebec',
78
+ 'SK' => 'Saskatchewan',
79
+ 'YT' => 'Yukon'
80
+ }
81
+
82
+ US_STATES = {
83
+ 'AL' => 'Alabama',
84
+ 'AK' => 'Alaska',
85
+ 'AS' => 'American Samoa',
86
+ 'AZ' => 'Arizona',
87
+ 'AR' => 'Arkansas',
88
+ 'CA' => 'California',
89
+ 'CO' => 'Colorado',
90
+ 'CT' => 'Connecticut',
91
+ 'DE' => 'Delaware',
92
+ 'DC' => 'District Of Columbia',
93
+ 'FM' => 'Federated States Of Micronesia',
94
+ 'FL' => 'Florida',
95
+ 'GA' => 'Georgia',
96
+ 'GU' => 'Guam',
97
+ 'HI' => 'Hawaii',
98
+ 'ID' => 'Idaho',
99
+ 'IL' => 'Illinois',
100
+ 'IN' => 'Indiana',
101
+ 'IA' => 'Iowa',
102
+ 'KS' => 'Kansas',
103
+ 'KY' => 'Kentucky',
104
+ 'LA' => 'Louisiana',
105
+ 'ME' => 'Maine',
106
+ 'MH' => 'Marshall Islands',
107
+ 'MD' => 'Maryland',
108
+ 'MA' => 'Massachusetts',
109
+ 'MI' => 'Michigan',
110
+ 'MN' => 'Minnesota',
111
+ 'MS' => 'Mississippi',
112
+ 'MO' => 'Missouri',
113
+ 'MT' => 'Montana',
114
+ 'NE' => 'Nebraska',
115
+ 'NV' => 'Nevada',
116
+ 'NH' => 'New Hampshire',
117
+ 'NJ' => 'New Jersey',
118
+ 'NM' => 'New Mexico',
119
+ 'NY' => 'New York',
120
+ 'NC' => 'North Carolina',
121
+ 'ND' => 'North Dakota',
122
+ 'MP' => 'Northern Mariana Islands',
123
+ 'OH' => 'Ohio',
124
+ 'OK' => 'Oklahoma',
125
+ 'OR' => 'Oregon',
126
+ 'PW' => 'Palau',
127
+ 'PA' => 'Pennsylvania',
128
+ 'PR' => 'Puerto Rico',
129
+ 'RI' => 'Rhode Island',
130
+ 'SC' => 'South Carolina',
131
+ 'SD' => 'South Dakota',
132
+ 'TN' => 'Tennessee',
133
+ 'TX' => 'Texas',
134
+ 'UT' => 'Utah',
135
+ 'VT' => 'Vermont',
136
+ 'VI' => 'Virgin Islands',
137
+ 'VA' => 'Virginia',
138
+ 'WA' => 'Washington',
139
+ 'WV' => 'West Virginia',
140
+ 'WI' => 'Wisconsin',
141
+ 'WY' => 'Wyoming'
142
+ }
143
+
144
+ COUNTRY_PHONE_NUMBERS = {
145
+ 'AD' => { :code => '376', :length => [6, 7, 8, 9] },
146
+ 'AE' => { :code => '971', :length => [7, 8, 9] },
147
+ 'AF' => { :code => '93', :length => [8, 9] },
148
+ 'AG' => { :code => '1', :length => [10] },
149
+ 'AI' => { :code => '1', :length => [10] },
150
+ 'AL' => { :code => '355', :length => [7, 8, 9] },
151
+ 'AM' => { :code => '374', :length => [8] },
152
+ 'AO' => { :code => '244', :length => [9] },
153
+ 'AQ' => { :code => '672', :length => [] },
154
+ 'AR' => { :code => '54', :length => [8, 9] },
155
+ 'AS' => { :code => '1', :length => [10] },
156
+ 'AT' => { :code => '43', :length => [7, 8, 9, 10, 11, 12, 13] },
157
+ 'AU' => { :code => '61', :length => [9] },
158
+ 'AW' => { :code => '297', :length => [7] },
159
+ 'AX' => { :code => '358', :length => [] },
160
+ 'AZ' => { :code => '994', :length => [8, 9] },
161
+ 'BA' => { :code => '387', :length => [8] },
162
+ 'BB' => { :code => '1', :length => [10] },
163
+ 'BD' => { :code => '880', :length => [10] },
164
+ 'BE' => { :code => '32', :length => [8, 9] },
165
+ 'BF' => { :code => '226', :length => [8] },
166
+ 'BG' => { :code => '359', :length => [8, 9, 10] },
167
+ 'BH' => { :code => '973', :length => [8] },
168
+ 'BI' => { :code => '257', :length => [8] },
169
+ 'BJ' => { :code => '229', :length => [8] },
170
+ 'BL' => { :code => '590', :length => [] },
171
+ 'BM' => { :code => '1', :length => [10] },
172
+ 'BN' => { :code => '673', :length => [7] },
173
+ 'BO' => { :code => '591', :length => [8] },
174
+ 'BQ' => { :code => '599', :length => [7] },
175
+ 'BR' => { :code => '55', :length => [10, 11] },
176
+ 'BS' => { :code => '1', :length => [10] },
177
+ 'BT' => { :code => '975', :length => [7, 8] },
178
+ 'BV' => { :code => '47', :length => [] },
179
+ 'BW' => { :code => '267', :length => [7] },
180
+ 'BY' => { :code => '375', :length => [9] },
181
+ 'BZ' => { :code => '501', :length => [7] },
182
+ 'CA' => { :code => '1', :length => [10] },
183
+ 'CC' => { :code => '61', :length => [9] },
184
+ 'CD' => { :code => '243', :length => [8] },
185
+ 'CF' => { :code => '236', :length => [8] },
186
+ 'CG' => { :code => '242', :length => [7] },
187
+ 'CH' => { :code => '41', :length => [9, 10] },
188
+ 'CI' => { :code => '225', :length => [8] },
189
+ 'CK' => { :code => '682', :length => [5] },
190
+ 'CL' => { :code => '56', :length => [8, 9] },
191
+ 'CM' => { :code => '237', :length => [8] },
192
+ 'CN' => { :code => '86', :length => [7, 8, 9, 10, 11] },
193
+ 'CO' => { :code => '57', :length => [9, 10] },
194
+ 'CR' => { :code => '506', :length => [8] },
195
+ 'CU' => { :code => '53', :length => [8] },
196
+ 'CV' => { :code => '238', :length => [7] },
197
+ 'CW' => { :code => '599', :length => [7] },
198
+ 'CX' => { :code => '61', :length => [] },
199
+ 'CY' => { :code => '357', :length => [8] },
200
+ 'CZ' => { :code => '420', :length => [9] },
201
+ 'DE' => { :code => '49', :length => [6, 7, 8, 9, 10, 11] },
202
+ 'DJ' => { :code => '253', :length => [6] },
203
+ 'DK' => { :code => '45', :length => [8] },
204
+ 'DM' => { :code => '1', :length => [10] },
205
+ 'DO' => { :code => '1', :length => [10] },
206
+ 'DZ' => { :code => '213', :length => [8] },
207
+ 'EC' => { :code => '593', :length => [8, 9] },
208
+ 'EE' => { :code => '372', :length => [7, 8] },
209
+ 'EG' => { :code => '20', :length => [9] },
210
+ 'EH' => { :code => '212', :length => [] },
211
+ 'ER' => { :code => '291', :length => [7] },
212
+ 'ES' => { :code => '34', :length => [9] },
213
+ 'ET' => { :code => '251', :length => [9] },
214
+ 'FI' => { :code => '358', :length => [9] },
215
+ 'FJ' => { :code => '679', :length => [7] },
216
+ 'FK' => { :code => '500', :length => [5] },
217
+ 'FM' => { :code => '691', :length => [7] },
218
+ 'FO' => { :code => '298', :length => [6] },
219
+ 'FR' => { :code => '33', :length => [9, 10] },
220
+ 'GA' => { :code => '241', :length => [6, 7, 8] },
221
+ 'GB' => { :code => '44', :length => [10, 11] },
222
+ 'GD' => { :code => '1', :length => [10] },
223
+ 'GE' => { :code => '995', :length => [9] },
224
+ 'GF' => { :code => '594', :length => [10] },
225
+ 'GG' => { :code => '44', :length => [] },
226
+ 'GH' => { :code => '233', :length => [5, 6, 7, 8] },
227
+ 'GI' => { :code => '350', :length => [8] },
228
+ 'GL' => { :code => '299', :length => [6] },
229
+ 'GM' => { :code => '220', :length => [7] },
230
+ 'GN' => { :code => '224', :length => [8] },
231
+ 'GP' => { :code => '590', :length => [10] },
232
+ 'GQ' => { :code => '240', :length => [6] },
233
+ 'GR' => { :code => '30', :length => [10] },
234
+ 'GS' => { :code => '500', :length => [] },
235
+ 'GT' => { :code => '502', :length => [8] },
236
+ 'GU' => { :code => '1', :length => [10] },
237
+ 'GW' => { :code => '245', :length => [7] },
238
+ 'GY' => { :code => '592', :length => [6, 7] },
239
+ 'HK' => { :code => '852', :length => [8] },
240
+ 'HN' => { :code => '504', :length => [7, 8] },
241
+ 'HR' => { :code => '385', :length => [8] },
242
+ 'HT' => { :code => '509', :length => [8] },
243
+ 'HU' => { :code => '36', :length => [8, 9] },
244
+ 'ID' => { :code => '62', :length => [8, 9, 10, 11] },
245
+ 'IE' => { :code => '353', :length => [9] },
246
+ 'IL' => { :code => '972', :length => [7, 8, 9] },
247
+ 'IM' => { :code => '44', :length => [] },
248
+ 'IN' => { :code => '91', :length => [10] },
249
+ 'IO' => { :code => '246', :length => [] },
250
+ 'IQ' => { :code => '964', :length => [8, 9, 10] },
251
+ 'IR' => { :code => '98', :length => [10] },
252
+ 'IS' => { :code => '354', :length => [7, 8, 9] },
253
+ 'IT' => { :code => '39', :length => [9, 11] },
254
+ 'JE' => { :code => '44', :length => [] },
255
+ 'JM' => { :code => '1', :length => [10] },
256
+ 'JO' => { :code => '962', :length => [8, 9] },
257
+ 'JP' => { :code => '81', :length => [9, 10] },
258
+ 'KE' => { :code => '254', :length => [9] },
259
+ 'KG' => { :code => '996', :length => [9] },
260
+ 'KH' => { :code => '855', :length => [8] },
261
+ 'KI' => { :code => '686', :length => [5] },
262
+ 'KM' => { :code => '269', :length => [7] },
263
+ 'KN' => { :code => '1', :length => [10] },
264
+ 'KP' => { :code => '850', :length => [8, 9] },
265
+ 'KR' => { :code => '82', :length => [8, 9] },
266
+ 'KW' => { :code => '965', :length => [7] },
267
+ 'KY' => { :code => '1', :length => [10] },
268
+ 'KZ' => { :code => '7', :length => [10] },
269
+ 'LA' => { :code => '856', :length => [8] },
270
+ 'LB' => { :code => '961', :length => [8] },
271
+ 'LC' => { :code => '1', :length => [10] },
272
+ 'LI' => { :code => '423', :length => [7] },
273
+ 'LK' => { :code => '94', :length => [10] },
274
+ 'LR' => { :code => '231', :length => [6, 7, 8] },
275
+ 'LS' => { :code => '266', :length => [8] },
276
+ 'LT' => { :code => '370', :length => [8] },
277
+ 'LU' => { :code => '352', :length => [9] },
278
+ 'LV' => { :code => '371', :length => [8] },
279
+ 'LY' => { :code => '218', :length => [8, 9] },
280
+ 'MA' => { :code => '212', :length => [8] },
281
+ 'MC' => { :code => '377', :length => [8, 9] },
282
+ 'MD' => { :code => '373', :length => [8] },
283
+ 'ME' => { :code => '382', :length => [8] },
284
+ 'MF' => { :code => '590', :length => [] },
285
+ 'MG' => { :code => '261', :length => [9] },
286
+ 'MH' => { :code => '692', :length => [7] },
287
+ 'MK' => { :code => '389', :length => [7, 8] },
288
+ 'ML' => { :code => '223', :length => [8] },
289
+ 'MM' => { :code => '95', :length => [7, 8] },
290
+ 'MN' => { :code => '976', :length => [7, 8, 9, 10] },
291
+ 'MO' => { :code => '853', :length => [8] },
292
+ 'MP' => { :code => '1', :length => [10] },
293
+ 'MQ' => { :code => '596', :length => [10] },
294
+ 'MR' => { :code => '222', :length => [7] },
295
+ 'MS' => { :code => '1', :length => [10] },
296
+ 'MT' => { :code => '356', :length => [8] },
297
+ 'MU' => { :code => '230', :length => [7] },
298
+ 'MV' => { :code => '960', :length => [7] },
299
+ 'MW' => { :code => '265', :length => [8] },
300
+ 'MX' => { :code => '52', :length => [8, 9, 10] },
301
+ 'MY' => { :code => '60', :length => [9, 10] },
302
+ 'MZ' => { :code => '258', :length => [8, 9] },
303
+ 'NA' => { :code => '264', :length => [6, 7] },
304
+ 'NC' => { :code => '687', :length => [6] },
305
+ 'NE' => { :code => '227', :length => [8] },
306
+ 'NF' => { :code => '672', :length => [6] },
307
+ 'NG' => { :code => '234', :length => [7, 8] },
308
+ 'NI' => { :code => '505', :length => [8] },
309
+ 'NL' => { :code => '31', :length => [9] },
310
+ 'NO' => { :code => '47', :length => [8] },
311
+ 'NP' => { :code => '977', :length => [7, 8] },
312
+ 'NR' => { :code => '674', :length => [7] },
313
+ 'NU' => { :code => '683', :length => [4] },
314
+ 'NZ' => { :code => '64', :length => [8, 9] },
315
+ 'OM' => { :code => '968', :length => [8] },
316
+ 'PA' => { :code => '507', :length => [7] },
317
+ 'PE' => { :code => '51', :length => [8, 9] },
318
+ 'PF' => { :code => '689', :length => [6] },
319
+ 'PG' => { :code => '675', :length => [7] },
320
+ 'PH' => { :code => '63', :length => [8, 9, 10] },
321
+ 'PK' => { :code => '92', :length => [9, 10] },
322
+ 'PL' => { :code => '48', :length => [9] },
323
+ 'PM' => { :code => '508', :length => [6] },
324
+ 'PN' => { :code => '64', :length => [9] },
325
+ 'PR' => { :code => '1', :length => [10] },
326
+ 'PS' => { :code => '970', :length => [8] },
327
+ 'PT' => { :code => '351', :length => [9] },
328
+ 'PW' => { :code => '680', :length => [7] },
329
+ 'PY' => { :code => '595', :length => [9] },
330
+ 'QA' => { :code => '974', :length => [7] },
331
+ 'RE' => { :code => '262', :length => [10] },
332
+ 'RO' => { :code => '40', :length => [9] },
333
+ 'RS' => { :code => '381', :length => [9] },
334
+ 'RU' => { :code => '7', :length => [10] },
335
+ 'RW' => { :code => '250', :length => [8, 9] },
336
+ 'SA' => { :code => '966', :length => [8, 9] },
337
+ 'SB' => { :code => '677', :length => [5] },
338
+ 'SC' => { :code => '248', :length => [6] },
339
+ 'SD' => { :code => '249', :length => [9] },
340
+ 'SE' => { :code => '46', :length => [9] },
341
+ 'SG' => { :code => '65', :length => [8, 9] },
342
+ 'SH' => { :code => '290', :length => [4] },
343
+ 'SI' => { :code => '386', :length => [8] },
344
+ 'SJ' => { :code => '47', :length => [8] },
345
+ 'SK' => { :code => '421', :length => [9] },
346
+ 'SL' => { :code => '232', :length => [8] },
347
+ 'SM' => { :code => '378', :length => [9, 10, 11, 12] },
348
+ 'SN' => { :code => '221', :length => [7] },
349
+ 'SO' => { :code => '252', :length => [7, 8] },
350
+ 'SR' => { :code => '597', :length => [6] },
351
+ 'SS' => { :code => '211', :length => [9] },
352
+ 'ST' => { :code => '239', :length => [6, 7] },
353
+ 'SV' => { :code => '503', :length => [8] },
354
+ 'SX' => { :code => '1', :length => [10] },
355
+ 'SY' => { :code => '963', :length => [7, 8] },
356
+ 'SZ' => { :code => '268', :length => [7] },
357
+ 'TC' => { :code => '1', :length => [10] },
358
+ 'TD' => { :code => '235', :length => [7] },
359
+ 'TF' => { :code => '262', :length => [] },
360
+ 'TG' => { :code => '228', :length => [7] },
361
+ 'TH' => { :code => '66', :length => [9, 10] },
362
+ 'TJ' => { :code => '992', :length => [9] },
363
+ 'TK' => { :code => '690', :length => [4] },
364
+ 'TL' => { :code => '670', :length => [7] },
365
+ 'TM' => { :code => '993', :length => [8] },
366
+ 'TN' => { :code => '216', :length => [8] },
367
+ 'TO' => { :code => '676', :length => [5, 6, 7] },
368
+ 'TR' => { :code => '90', :length => [10] },
369
+ 'TT' => { :code => '1', :length => [10] },
370
+ 'TV' => { :code => '688', :length => [5] },
371
+ 'TW' => { :code => '886', :length => [7, 8] },
372
+ 'TZ' => { :code => '255', :length => [9] },
373
+ 'UA' => { :code => '380', :length => [8, 9] },
374
+ 'UG' => { :code => '256', :length => [9] },
375
+ 'UM' => { :code => '1', :length => [] },
376
+ 'US' => { :code => '1', :length => [10] },
377
+ 'UY' => { :code => '598', :length => [7, 8] },
378
+ 'UZ' => { :code => '998', :length => [9] },
379
+ 'VA' => { :code => '39', :length => [9] },
380
+ 'VC' => { :code => '1', :length => [10] },
381
+ 'VE' => { :code => '58', :length => [10] },
382
+ 'VG' => { :code => '1', :length => [10] },
383
+ 'VI' => { :code => '1', :length => [10] },
384
+ 'VN' => { :code => '84', :length => [7, 8, 9, 10] },
385
+ 'VU' => { :code => '678', :length => [5, 6, 7] },
386
+ 'WF' => { :code => '681', :length => [6] },
387
+ 'WS' => { :code => '685', :length => [6, 7] },
388
+ 'YE' => { :code => '967', :length => [7, 8, 9] },
389
+ 'YT' => { :code => '262', :length => [7] },
390
+ 'ZA' => { :code => '27', :length => [9] },
391
+ 'ZM' => { :code => '260', :length => [9] },
392
+ 'ZW' => { :code => '263', :length => [8, 9, 10, 11] }
393
+ }
394
+
66
395
  def create_signature(fields, secret)
67
396
  data = fields.join('.')
68
397
  digest = Digest::SHA1.hexdigest(data)
@@ -92,15 +421,135 @@ module OffsitePayments #:nodoc:
92
421
  value.scan(/\d+/).join('')
93
422
  end
94
423
 
424
+ # This method is used for generating the "BILLING_CODE" field,
425
+ # this field is generated by concatenating the zip field and
426
+ # the first line of address with a pipe(|) between them
427
+ # if the country is GB, we remove the non-numeric characters
95
428
  def extract_avs_code(params={})
96
- [extract_digits(params[:zip]), extract_digits(params[:address1])].join('|')
429
+ return unless params[:zip] && params[:address1]
430
+ code = [params[:zip], params[:address1]]
431
+ code = code.collect{|p| extract_digits(p) } if params[:country] == 'GB'
432
+ code.reject{|p| p.empty? }.join('|')
433
+ end
434
+
435
+ def extract_address_match_indicator(value)
436
+ value ? 'TRUE' : 'FALSE'
437
+ end
438
+
439
+ def adjust_phone_number_length(country_calling_code, phone_number)
440
+ country_calling_code[0...3] + '|' + phone_number[0...15]
441
+ end
442
+
443
+ # The home phone number provided by the Cardholder. Should be In format:
444
+ # of 'CountryCallingCode|Number' for example, '1|123456789'.
445
+ def format_phone_number(phone_number, country_code)
446
+ return nil if phone_number.nil?
447
+
448
+ country_number = COUNTRY_PHONE_NUMBERS[country_code] || { :code => '0', :length => [] }
449
+
450
+ # Remove non-digit characters
451
+ processed_number = phone_number.gsub(/\D/, '')
452
+ return '0|0' if [[], ['0']].include? processed_number.chars.uniq
453
+
454
+ # Allow Italy and Ivory Coast to have leading zero, as they use it as a part of some phone numbers
455
+ if ['IT', 'CI'].include?(country_code) && /\A0[1-9]\d*/.match(processed_number)
456
+ return adjust_phone_number_length(country_number[:code], processed_number)
457
+ end
458
+
459
+ return '0|0' if processed_number == country_number[:code]
460
+
461
+ # Remove leading zero(s)
462
+ processed_number = processed_number.gsub(/\A0*/, '')
463
+
464
+ # Check if the potential Singapore calling code is not the local prefix
465
+ if country_code == 'SG' &&
466
+ processed_number.start_with?(country_number[:code]) &&
467
+ country_number[:length].include?(processed_number.length)
468
+ then
469
+ return adjust_phone_number_length(country_number[:code], processed_number)
470
+ end
471
+
472
+ # Remove country calling code from the processed number and try to fix trivial mistakes
473
+ if processed_number.start_with?(country_number[:code]) ||
474
+ (!(country_number[:length].include?(processed_number.length)) &&
475
+ country_number[:length].include?(processed_number.length - country_number[:code].length) &&
476
+ (country_number[:code].chars.sort == processed_number[0...country_number[:code].length].chars.sort))
477
+ then
478
+ processed_number = processed_number[country_number[:code].length..-1]
479
+ end
480
+
481
+ # Limit returned string to 3 characters + | + 15 characters
482
+ adjust_phone_number_length(country_number[:code], processed_number)
483
+ end
484
+
485
+ def lookup_state_code(country_code, state)
486
+ case country_code
487
+ when 'CA'
488
+ state_code = CANADIAN_STATES.find { |code, state_name| state_name.downcase == state.downcase}
489
+ state_code ? state_code.first : state
490
+ when 'US'
491
+ state_code = US_STATES.find { |code, state_name| state_name.downcase == state.downcase}
492
+ state_code ? state_code.first : state
493
+ end
494
+ end
495
+
496
+ # if HPP_ADDRESS_MATCH_INDICATOR is set to TRUE
497
+ # HPP requires the shipping address to be sent from the billing address
498
+ def copy_billing_address
499
+ @fields.select { |k, _| k.start_with? 'HPP_BILLING_' }
500
+ .each do |k, v|
501
+ add_field("HPP_SHIPPING_#{k.split('HPP_BILLING_')[1]}", v)
502
+ end
503
+ end
504
+
505
+ # Validations
506
+ def get_pattern(key)
507
+ case key
508
+ when 'HPP_CUSTOMER_EMAIL' then /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,24})*$/
509
+ when 'HPP_CUSTOMER_PHONENUMBER_MOBILE' then /^([0-9 +]){1,3}(\|){0,1}([0-9 +]){1,15}$/
510
+ when 'HPP_BILLING_STREET1', 'HPP_SHIPPING_STREET1', 'HPP_BILLING_STREET2', 'HPP_SHIPPING_STREET2' then /^[\p{L}\p{M}\p{Blank}\p{N}\/\.\-\_\'\,]{1,50}$/
511
+ when 'HPP_BILLING_CITY', 'HPP_SHIPPING_CITY' then /^[\p{L}\p{M}\p{Blank}\p{N}\/\.\-\_\'\,]{1,40}$/
512
+ when 'HPP_BILLING_COUNTRY', 'HPP_SHIPPING_COUNTRY' then /^([0-9])*$/
513
+ when 'HPP_BILLING_POSTALCODE', 'HPP_SHIPPING_POSTALCODE' then /^[a-zA-Z0-9\-\s]{1,16}$/
514
+ when 'HPP_BILLING_STATE', 'HPP_SHIPPING_STATE' then /^([A-Z])*$/
515
+ end
516
+ end
517
+
518
+ def get_message(key)
519
+ case key
520
+ when 'HPP_CUSTOMER_EMAIL' then 'Invalid E-mail address.'
521
+ when 'HPP_CUSTOMER_PHONENUMBER_MOBILE' then 'Invalid Telephone. The selected payment method only allows numbers, spaces or punctuation (+, |), and no more than 19 characters.'
522
+ when 'HPP_BILLING_STREET1', 'HPP_SHIPPING_STREET1', 'HPP_BILLING_STREET2', 'HPP_SHIPPING_STREET2' then 'Invalid Street address. The selected payment method only allows letters, numbers, spaces or punctuation, and no more than 50 characters per line.'
523
+ when 'HPP_BILLING_CITY', 'HPP_SHIPPING_CITY' then 'Invalid City. The selected payment method only allows letters, numbers, spaces or punctuation, and no more than 40 characters.'
524
+ when 'HPP_BILLING_COUNTRY', 'HPP_SHIPPING_COUNTRY' then 'Invalid Country code.'
525
+ when 'HPP_BILLING_POSTALCODE', 'HPP_SHIPPING_POSTALCODE' then 'Invalid Zip/Postal Code. The selected payment method only allows letters, numbers, spaces or punctuation, and no more than 16 characters.'
526
+ when 'HPP_BILLING_STATE', 'HPP_SHIPPING_STATE' then 'Invalid State.'
527
+ end
528
+ end
529
+
530
+ def validate(key, value)
531
+ pattern = get_pattern(key)
532
+
533
+ return value unless pattern.present?
534
+
535
+ if value =~pattern
536
+ return value
537
+ else
538
+ raise ArgumentError, get_message(key)
539
+ end
97
540
  end
98
541
 
542
+ def add_field(name, value)
543
+ return if name.blank? || value.blank?
544
+ @fields[name.to_s] = validate(name.to_s, value.to_s)
545
+ end
99
546
  end
100
547
 
101
548
  class Helper < OffsitePayments::Helper
102
549
  include Common
103
550
 
551
+ self.country_format = :numeric
552
+
104
553
  def initialize(order, account, options = {})
105
554
  @timestamp = Time.now.strftime('%Y%m%d%H%M%S')
106
555
  @currency = options[:currency]
@@ -115,11 +564,13 @@ module OffsitePayments #:nodoc:
115
564
  add_field 'AUTO_SETTLE_FLAG', '1'
116
565
  add_field 'RETURN_TSS', '1'
117
566
  add_field 'TIMESTAMP', @timestamp
567
+ add_field 'HPP_VERSION', '2'
118
568
  # Realex does not send back CURRENCY param in response
119
569
  # however it does echo any other param so we send it twice.
120
570
  add_field 'X-CURRENCY', @currency
121
571
  add_field 'X-TEST', @test.to_s
122
572
  add_field 'ORDER_ID', "#{order}#{@timestamp.to_i}"
573
+ add_field 'COMMENT1', application_id
123
574
  end
124
575
 
125
576
  def form_fields
@@ -131,13 +582,82 @@ module OffsitePayments #:nodoc:
131
582
  end
132
583
 
133
584
  def billing_address(params={})
134
- add_field(mappings[:billing_address][:zip], extract_avs_code(params))
135
- add_field(mappings[:billing_address][:country], lookup_country_code(params[:country]))
585
+ country = params[:country]
586
+ country_code = lookup_country_code(country, :alpha2)
587
+ avs_code = extract_avs_code(params)
588
+ params[:state] = lookup_state_code(country_code, params[:state])
589
+
590
+ super
591
+
592
+ add_field(mappings[:billing_address][:country], lookup_country_code(country))
593
+ add_field(mappings[:billing_address][:code], avs_code)
594
+
595
+ unless ['US', 'CA'].include?(country_code)
596
+ # HPP_BILLING_STATE is required only for US and CA, otherwise is deleted
597
+ @fields.delete_if do |k, _|
598
+ k == 'HPP_BILLING_STATE'
599
+ end
600
+ end
601
+
602
+ if @fields[mappings[:customer][:phone]]
603
+ add_field(mappings[:customer][:phone], format_phone_number(@phone_number, country_code))
604
+ end
136
605
  end
137
606
 
138
607
  def shipping_address(params={})
139
- add_field(mappings[:shipping_address][:zip], extract_avs_code(params))
140
- add_field(mappings[:shipping_address][:country], lookup_country_code(params[:country]))
608
+ country = params[:country]
609
+ country_code = lookup_country_code(country, :alpha2)
610
+ params[:state] = lookup_state_code(country_code, params[:state])
611
+
612
+ super
613
+
614
+ add_field(mappings[:shipping_address][:country], lookup_country_code(country))
615
+ # the mapping for 'SHIPPING_CODE' field, which has the same value as the 'HPP_SHIPPING_POSTALCODE'
616
+ add_field(mappings[:shipping_address][:code], params[:zip])
617
+
618
+ unless ['US', 'CA'].include?(country_code)
619
+ # HPP_SHIPPING_STATE is required only for US and CA, otherwise is deleted
620
+ @fields.delete_if do |k, _|
621
+ k == 'HPP_SHIPPING_STATE'
622
+ end
623
+ end
624
+
625
+ if @fields[mappings[:customer][:phone]]&.[](0..1) == '0|'
626
+ add_field(mappings[:customer][:phone], format_phone_number(@phone_number, country_code))
627
+ end
628
+ end
629
+
630
+ def customer(params={})
631
+ country = @fields[mappings[:billing_address][:country]]
632
+ @phone_number = params[:phone]
633
+ params[:phone] = format_phone_number(@phone_number, lookup_country_code(country, :alpha2))
634
+
635
+ super
636
+ end
637
+
638
+ def addresses_match(address_match = nil)
639
+ return if address_match.nil?
640
+
641
+ add_field(
642
+ mappings[:addresses_match],
643
+ extract_address_match_indicator(address_match)
644
+ )
645
+
646
+ copy_billing_address if address_match
647
+ end
648
+
649
+ def comment(comment = nil)
650
+ add_field(mappings[:comment], comment)
651
+ end
652
+
653
+ # HPP does not want shipping address and HPP_ADDRESS_MATCH_INDICATOR to be sent
654
+ # if the product does not require shipping
655
+ def require_shipping(require_shipping = nil)
656
+ return unless require_shipping == false
657
+
658
+ @fields.delete_if do |k, _|
659
+ k.start_with?('HPP_SHIPPING_') || k == 'HPP_ADDRESS_MATCH_INDICATOR'
660
+ end
141
661
  end
142
662
 
143
663
  def sign_fields
@@ -161,13 +681,31 @@ module OffsitePayments #:nodoc:
161
681
  mapping :notify_url, 'MERCHANT_RESPONSE_URL'
162
682
  mapping :return_url, 'MERCHANT_RETURN_URL'
163
683
 
164
- # Realex Optional fields
165
- mapping :customer, :email => 'CUST_NUM'
166
684
 
167
- mapping :shipping_address, :zip => 'SHIPPING_CODE',
168
- :country => 'SHIPPING_CO'
169
- mapping :billing_address, :zip => 'BILLING_CODE',
170
- :country => 'BILLING_CO'
685
+ # Realex Optional fields
686
+ mapping :customer, :email => 'HPP_CUSTOMER_EMAIL',
687
+ :phone => 'HPP_CUSTOMER_PHONENUMBER_MOBILE'
688
+
689
+ mapping :shipping_address, :zip => 'HPP_SHIPPING_POSTALCODE',
690
+ :country => 'HPP_SHIPPING_COUNTRY',
691
+ :address1 => 'HPP_SHIPPING_STREET1',
692
+ :address2 => 'HPP_SHIPPING_STREET2',
693
+ :address3 => 'HPP_SHIPPING_STREET3',
694
+ :city => 'HPP_SHIPPING_CITY',
695
+ :state => 'HPP_SHIPPING_STATE',
696
+ :code => 'SHIPPING_CODE'
697
+
698
+ mapping :billing_address, :zip => 'HPP_BILLING_POSTALCODE',
699
+ :country => 'HPP_BILLING_COUNTRY',
700
+ :address1 => 'HPP_BILLING_STREET1',
701
+ :address2 => 'HPP_BILLING_STREET2',
702
+ :address3 => 'HPP_BILLING_STREET3',
703
+ :city => 'HPP_BILLING_CITY',
704
+ :state => 'HPP_BILLING_STATE',
705
+ :code => 'BILLING_CODE'
706
+
707
+ mapping :addresses_match, 'HPP_ADDRESS_MATCH_INDICATOR'
708
+ mapping :comment, 'COMMENT2'
171
709
  end
172
710
 
173
711
  class Notification < OffsitePayments::Notification
@@ -241,10 +779,6 @@ module OffsitePayments #:nodoc:
241
779
  params['MESSAGE']
242
780
  end
243
781
 
244
- def pasref
245
- params['PASREF']
246
- end
247
-
248
782
  def authcode
249
783
  params['AUTHCODE']
250
784
  end
@@ -72,6 +72,7 @@ module OffsitePayments #:nodoc:
72
72
  attr_reader :identifier
73
73
 
74
74
  def initialize(order, account, options={})
75
+ @shipping_address_set = nil
75
76
  super
76
77
  @identifier = rand(0..99999).to_s.rjust(5, '0')
77
78
  add_field 'VendorTxCode', "#{order}-#{@identifier}"
@@ -22,7 +22,6 @@ module OffsitePayments #:nodoc:
22
22
  'CVE' => 0,
23
23
  'DJF' => 0,
24
24
  'GNF' => 0,
25
- 'HUF' => 0,
26
25
  'ISK' => 0,
27
26
  'JPY' => 0,
28
27
  'KMF' => 0,
@@ -150,7 +150,7 @@ module OffsitePayments #:nodoc:
150
150
  end
151
151
 
152
152
  def amount
153
- Money.from_amount(BigDecimal.new(gross), currency)
153
+ Money.from_amount(BigDecimal(gross), currency)
154
154
  end
155
155
 
156
156
  def item_id
@@ -83,7 +83,7 @@ module OffsitePayments #:nodoc:
83
83
  end
84
84
 
85
85
  def amount
86
- Money.from_amount(BigDecimal.new(gross), currency)
86
+ Money.from_amount(BigDecimal(gross), currency)
87
87
  end
88
88
 
89
89
  def key_present?
@@ -1,3 +1,3 @@
1
1
  module OffsitePayments
2
- VERSION = "2.7.20"
2
+ VERSION = "2.7.27"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: offsite_payments
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.20
4
+ version: 2.7.27
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Luetke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-16 00:00:00.000000000 Z
11
+ date: 2021-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -257,6 +257,7 @@ files:
257
257
  - lib/offsite_payments/integrations/platron.rb
258
258
  - lib/offsite_payments/integrations/pxpay.rb
259
259
  - lib/offsite_payments/integrations/quickpay.rb
260
+ - lib/offsite_payments/integrations/quickpay_v10.rb
260
261
  - lib/offsite_payments/integrations/rbkmoney.rb
261
262
  - lib/offsite_payments/integrations/realex_offsite.rb
262
263
  - lib/offsite_payments/integrations/robokassa.rb
@@ -275,7 +276,8 @@ files:
275
276
  homepage: https://github.com/activemerchant/offsite_payments
276
277
  licenses:
277
278
  - MIT
278
- metadata: {}
279
+ metadata:
280
+ allowed_push_host: https://rubygems.org
279
281
  post_install_message: "\n In order to use `offsite_payments` gem, you need to either
280
282
  install or add to your Gemfile\n one of the two options for Money gem:\n -
281
283
  `gem 'money'`\n - `gem 'shopify-money', require: 'money'`\n\n Regardless