adyen 1.4.1 → 1.5.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.
@@ -98,15 +98,16 @@ module Adyen
98
98
 
99
99
  def authorise_one_click_payment_request_body
100
100
  validate_parameters!(:recurring_detail_reference,
101
- :shopper => [:email, :reference],
102
- :card => [:cvc])
103
- content = ONE_CLICK_PAYMENT_BODY_PARTIAL % [@params[:recurring_detail_reference], @params[:card][:cvc]]
101
+ :shopper => [:email, :reference])
102
+ content = one_click_card_partial
103
+ content << ONE_CLICK_PAYMENT_BODY_PARTIAL % [@params[:recurring_detail_reference]]
104
104
  payment_request_body(content)
105
105
  end
106
106
 
107
107
  def payment_request_body(content)
108
108
  validate_parameters!(:merchant_account, :reference, :amount => [:currency, :value])
109
109
  content << amount_partial
110
+ content << installments_partial if @params[:installments]
110
111
  content << shopper_partial if @params[:shopper]
111
112
  content << fraud_offset_partial if @params[:fraud_offset]
112
113
  LAYOUT % [@params[:merchant_account], @params[:reference], content]
@@ -139,8 +140,18 @@ module Adyen
139
140
  AMOUNT_PARTIAL % @params[:amount].values_at(:currency, :value)
140
141
  end
141
142
 
143
+ def one_click_card_partial
144
+ if @params[:card] && @params[:card][:encrypted] && @params[:card][:encrypted][:json]
145
+ ENCRYPTED_CARD_PARTIAL % [@params[:card][:encrypted][:json]]
146
+ else
147
+ validate_parameters!(:card => [:cvc])
148
+ card = @params[:card].values_at(:cvc)
149
+ ONE_CLICK_CARD_PARTIAL % card
150
+ end
151
+ end
152
+
142
153
  def card_partial
143
- if @params[:card] and @params[:card][:encrypted] and @params[:card][:encrypted][:json]
154
+ if @params[:card] && @params[:card][:encrypted] && @params[:card][:encrypted][:json]
144
155
  ENCRYPTED_CARD_PARTIAL % [@params[:card][:encrypted][:json]]
145
156
  else
146
157
  validate_parameters!(:card => [:holder_name, :number, :cvc, :expiry_year, :expiry_month])
@@ -150,15 +161,21 @@ module Adyen
150
161
  end
151
162
  end
152
163
 
164
+ def installments_partial
165
+ if @params[:installments] && @params[:installments][:value]
166
+ INSTALLMENTS_PARTIAL % @params[:installments].values_at(:value)
167
+ end
168
+ end
169
+
153
170
  def shopper_partial
154
171
  @params[:shopper].map { |k, v| SHOPPER_PARTIALS[k] % v }.join("\n")
155
172
  end
156
-
173
+
157
174
  def fraud_offset_partial
158
175
  validate_parameters!(:fraud_offset)
159
176
  FRAUD_OFFSET_PARTIAL % @params[:fraud_offset]
160
177
  end
161
-
178
+
162
179
  class AuthorisationResponse < Response
163
180
  ERRORS = {
164
181
  "validation 101 Invalid card number" => [:number, 'is not a valid creditcard number'],
@@ -171,7 +188,8 @@ module Adyen
171
188
  AUTHORISED = 'Authorised'
172
189
  REFUSED = 'Refused'
173
190
 
174
- response_attrs :result_code, :auth_code, :refusal_reason, :psp_reference
191
+ response_attrs :result_code, :auth_code, :refusal_reason, :psp_reference,
192
+ :additional_data
175
193
 
176
194
  def success?
177
195
  super && params[:result_code] == AUTHORISED
@@ -217,10 +235,28 @@ module Adyen
217
235
  :psp_reference => result.text('./payment:pspReference'),
218
236
  :result_code => result.text('./payment:resultCode'),
219
237
  :auth_code => result.text('./payment:authCode'),
238
+ :additional_data => parse_additional_data(result.xpath('.//payment:additionalData')),
220
239
  :refusal_reason => (invalid_request? ? fault_message : result.text('./payment:refusalReason'))
221
240
  }
222
241
  end
223
242
  end
243
+
244
+ private
245
+ def parse_additional_data(xpath)
246
+ if xpath.empty?
247
+ {}
248
+ else
249
+ results = {}
250
+
251
+ xpath.map do |node|
252
+ key = node.text('./payment:entry/payment:key')
253
+ value = node.text('./payment:entry/payment:value')
254
+ results[key] = value unless key.empty?
255
+ end
256
+
257
+ results
258
+ end
259
+ end
224
260
  end
225
261
 
226
262
  class ModificationResponse < Response
@@ -8,14 +8,14 @@ module Adyen
8
8
  # The base class of the API classes that map to Adyen SOAP services.
9
9
  class SimpleSOAPClient
10
10
  # @private
11
- ENVELOPE = <<EOS
12
- <?xml version="1.0"?>
13
- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
14
- <soap:Body>
15
- %s
16
- </soap:Body>
17
- </soap:Envelope>
18
- EOS
11
+ ENVELOPE = <<-EOXML.strip.freeze
12
+ <?xml version="1.0"?>
13
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
14
+ <soap:Body>
15
+ %s
16
+ </soap:Body>
17
+ </soap:Envelope>
18
+ EOXML
19
19
 
20
20
  # A CA file used to verify certificates when connecting to Adyen.
21
21
  #
@@ -5,24 +5,24 @@ module Adyen
5
5
  private
6
6
 
7
7
  def modification_request(method, body = nil)
8
- return <<EOS
9
- <payment:#{method} xmlns:payment="http://payment.services.adyen.com" xmlns:recurring="http://recurring.services.adyen.com" xmlns:common="http://common.services.adyen.com">
10
- <payment:modificationRequest>
11
- <payment:merchantAccount>%s</payment:merchantAccount>
12
- <payment:originalReference>%s</payment:originalReference>
13
- #{body}
14
- </payment:modificationRequest>
15
- </payment:#{method}>
16
- EOS
8
+ <<-EOXML
9
+ <payment:#{method} xmlns:payment="http://payment.services.adyen.com" xmlns:recurring="http://recurring.services.adyen.com" xmlns:common="http://common.services.adyen.com">
10
+ <payment:modificationRequest>
11
+ <payment:merchantAccount>%s</payment:merchantAccount>
12
+ <payment:originalReference>%s</payment:originalReference>
13
+ #{body}
14
+ </payment:modificationRequest>
15
+ </payment:#{method}>
16
+ EOXML
17
17
  end
18
18
 
19
19
  def modification_request_with_amount(method)
20
- modification_request(method, <<EOS)
21
- <payment:modificationAmount>
22
- <common:currency>%s</common:currency>
23
- <common:value>%s</common:value>
24
- </payment:modificationAmount>
25
- EOS
20
+ modification_request(method, <<-EOXML)
21
+ <payment:modificationAmount>
22
+ <common:currency>%s</common:currency>
23
+ <common:value>%s</common:value>
24
+ </payment:modificationAmount>
25
+ EOXML
26
26
  end
27
27
  end
28
28
 
@@ -36,26 +36,26 @@ EOS
36
36
  CANCEL_OR_REFUND_LAYOUT = modification_request(:cancelOrRefund)
37
37
 
38
38
  # @private
39
- LAYOUT = <<EOS
40
- <payment:authorise xmlns:payment="http://payment.services.adyen.com" xmlns:recurring="http://recurring.services.adyen.com" xmlns:common="http://common.services.adyen.com">
41
- <payment:paymentRequest>
42
- <payment:merchantAccount>%s</payment:merchantAccount>
43
- <payment:reference>%s</payment:reference>
44
- %s
45
- </payment:paymentRequest>
46
- </payment:authorise>
47
- EOS
39
+ LAYOUT = <<-EOXML
40
+ <payment:authorise xmlns:payment="http://payment.services.adyen.com" xmlns:recurring="http://recurring.services.adyen.com" xmlns:common="http://common.services.adyen.com">
41
+ <payment:paymentRequest>
42
+ <payment:merchantAccount>%s</payment:merchantAccount>
43
+ <payment:reference>%s</payment:reference>
44
+ %s
45
+ </payment:paymentRequest>
46
+ </payment:authorise>
47
+ EOXML
48
48
 
49
49
  # @private
50
- AMOUNT_PARTIAL = <<EOS
50
+ AMOUNT_PARTIAL = <<-EOXML
51
51
  <payment:amount>
52
52
  <common:currency>%s</common:currency>
53
53
  <common:value>%s</common:value>
54
54
  </payment:amount>
55
- EOS
55
+ EOXML
56
56
 
57
57
  # @private
58
- CARD_PARTIAL = <<EOS
58
+ CARD_PARTIAL = <<-EOXML
59
59
  <payment:card>
60
60
  <payment:holderName>%s</payment:holderName>
61
61
  <payment:number>%s</payment:number>
@@ -63,10 +63,24 @@ EOS
63
63
  <payment:expiryYear>%s</payment:expiryYear>
64
64
  <payment:expiryMonth>%02d</payment:expiryMonth>
65
65
  </payment:card>
66
- EOS
66
+ EOXML
67
+
68
+ # @private
69
+ ONE_CLICK_CARD_PARTIAL = <<-EOXML
70
+ <payment:card>
71
+ <payment:cvc>%s</payment:cvc>
72
+ </payment:card>
73
+ EOXML
67
74
 
68
75
  # @private
69
- ENCRYPTED_CARD_PARTIAL = <<EOS
76
+ INSTALLMENTS_PARTIAL = <<-EOXML
77
+ <payment:installments>
78
+ <common:value>%s</common:value>
79
+ </payment:installments>
80
+ EOXML
81
+
82
+ # @private
83
+ ENCRYPTED_CARD_PARTIAL = <<-EOXML
70
84
  <additionalAmount xmlns="http://payment.services.adyen.com" xsi:nil="true" />
71
85
  <additionalData xmlns="http://payment.services.adyen.com">
72
86
  <entry>
@@ -74,34 +88,31 @@ EOS
74
88
  <value xsi:type="xsd:string">%s</value>
75
89
  </entry>
76
90
  </additionalData>
77
- EOS
91
+ EOXML
78
92
 
79
93
  # @private
80
- ENABLE_RECURRING_CONTRACTS_PARTIAL = <<EOS
94
+ ENABLE_RECURRING_CONTRACTS_PARTIAL = <<-EOXML
81
95
  <payment:recurring>
82
96
  <payment:contract>RECURRING,ONECLICK</payment:contract>
83
97
  </payment:recurring>
84
- EOS
98
+ EOXML
85
99
 
86
100
  # @private
87
- RECURRING_PAYMENT_BODY_PARTIAL = <<EOS
101
+ RECURRING_PAYMENT_BODY_PARTIAL = <<-EOXML
88
102
  <payment:recurring>
89
103
  <payment:contract>RECURRING</payment:contract>
90
104
  </payment:recurring>
91
105
  <payment:selectedRecurringDetailReference>%s</payment:selectedRecurringDetailReference>
92
106
  <payment:shopperInteraction>ContAuth</payment:shopperInteraction>
93
- EOS
107
+ EOXML
94
108
 
95
109
  # @private
96
- ONE_CLICK_PAYMENT_BODY_PARTIAL = <<EOS
110
+ ONE_CLICK_PAYMENT_BODY_PARTIAL = <<-EOXML
97
111
  <payment:recurring>
98
112
  <payment:contract>ONECLICK</payment:contract>
99
113
  </payment:recurring>
100
114
  <payment:selectedRecurringDetailReference>%s</payment:selectedRecurringDetailReference>
101
- <payment:card>
102
- <payment:cvc>%s</payment:cvc>
103
- </payment:card>
104
- EOS
115
+ EOXML
105
116
 
106
117
  # @private
107
118
  SHOPPER_PARTIALS = {
@@ -110,7 +121,7 @@ EOS
110
121
  :ip => ' <payment:shopperIP>%s</payment:shopperIP>',
111
122
  :statement => ' <payment:shopperStatement>%s</payment:shopperStatement>',
112
123
  }
113
-
124
+
114
125
  # @private
115
126
  FRAUD_OFFSET_PARTIAL = '<payment:fraudOffset>%s</payment:fraudOffset>'
116
127
  end
@@ -8,48 +8,48 @@ module Adyen
8
8
  #
9
9
  # This module extends the {PaymentService} class and thus these methods are callable on it.
10
10
  module TestHelpers
11
- AUTHORISE_RESPONSE = SimpleSOAPClient::ENVELOPE % <<EOS
12
- <ns1:authoriseResponse xmlns:ns1="http://payment.services.adyen.com">
13
- <ns1:paymentResult>
14
- <additionalData xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
15
- <authCode xmlns="http://payment.services.adyen.com">1234</authCode>
16
- <dccAmount xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
17
- <dccSignature xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
18
- <fraudResult xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
19
- <issuerUrl xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
20
- <md xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
21
- <paRequest xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
22
- <pspReference xmlns="http://payment.services.adyen.com">9876543210987654</pspReference>
23
- <refusalReason xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
24
- <resultCode xmlns="http://payment.services.adyen.com">Authorised</resultCode>
25
- </ns1:paymentResult>
26
- </ns1:authoriseResponse>
27
- EOS
11
+ AUTHORISE_RESPONSE = SimpleSOAPClient::ENVELOPE % <<-EOXML
12
+ <ns1:authoriseResponse xmlns:ns1="http://payment.services.adyen.com">
13
+ <ns1:paymentResult>
14
+ <additionalData xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
15
+ <authCode xmlns="http://payment.services.adyen.com">1234</authCode>
16
+ <dccAmount xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
17
+ <dccSignature xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
18
+ <fraudResult xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
19
+ <issuerUrl xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
20
+ <md xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
21
+ <paRequest xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
22
+ <pspReference xmlns="http://payment.services.adyen.com">9876543210987654</pspReference>
23
+ <refusalReason xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
24
+ <resultCode xmlns="http://payment.services.adyen.com">Authorised</resultCode>
25
+ </ns1:paymentResult>
26
+ </ns1:authoriseResponse>
27
+ EOXML
28
28
 
29
- AUTHORISATION_REFUSED_RESPONSE = SimpleSOAPClient::ENVELOPE % <<EOS
30
- <ns1:authoriseResponse xmlns:ns1="http://payment.services.adyen.com">
31
- <ns1:paymentResult>
32
- <additionalData xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
33
- <authCode xmlns="http://payment.services.adyen.com">1234</authCode>
34
- <dccAmount xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
35
- <dccSignature xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
36
- <fraudResult xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
37
- <issuerUrl xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
38
- <md xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
39
- <paRequest xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
40
- <pspReference xmlns="http://payment.services.adyen.com">9876543210987654</pspReference>
41
- <refusalReason xmlns="http://payment.services.adyen.com">You need to actually own money.</refusalReason>
42
- <resultCode xmlns="http://payment.services.adyen.com">Refused</resultCode>
43
- </ns1:paymentResult>
44
- </ns1:authoriseResponse>
45
- EOS
29
+ AUTHORISATION_REFUSED_RESPONSE = SimpleSOAPClient::ENVELOPE % <<-EOXML
30
+ <ns1:authoriseResponse xmlns:ns1="http://payment.services.adyen.com">
31
+ <ns1:paymentResult>
32
+ <additionalData xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
33
+ <authCode xmlns="http://payment.services.adyen.com">1234</authCode>
34
+ <dccAmount xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
35
+ <dccSignature xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
36
+ <fraudResult xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
37
+ <issuerUrl xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
38
+ <md xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
39
+ <paRequest xmlns="http://payment.services.adyen.com" xsi:nil="true"/>
40
+ <pspReference xmlns="http://payment.services.adyen.com">9876543210987654</pspReference>
41
+ <refusalReason xmlns="http://payment.services.adyen.com">You need to actually own money.</refusalReason>
42
+ <resultCode xmlns="http://payment.services.adyen.com">Refused</resultCode>
43
+ </ns1:paymentResult>
44
+ </ns1:authoriseResponse>
45
+ EOXML
46
46
 
47
- AUTHORISATION_REQUEST_INVALID_RESPONSE = SimpleSOAPClient::ENVELOPE % <<EOS
48
- <soap:Fault>
49
- <faultcode>soap:Server</faultcode>
50
- <faultstring>validation 101 Invalid card number</faultstring>
51
- </soap:Fault>
52
- EOS
47
+ AUTHORISATION_REQUEST_INVALID_RESPONSE = SimpleSOAPClient::ENVELOPE % <<-EOXML
48
+ <soap:Fault>
49
+ <faultcode>soap:Server</faultcode>
50
+ <faultstring>validation 101 Invalid card number</faultstring>
51
+ </soap:Fault>
52
+ EOXML
53
53
 
54
54
  # @return [AuthorisationResponse] A authorisation succeeded response instance.
55
55
  def success_stub
@@ -104,15 +104,15 @@ EOS
104
104
  #
105
105
  # This module extends the {RecurringService} class and thus these methods are callable on it.
106
106
  module TestHelpers
107
- DISABLE_RESPONSE = SimpleSOAPClient::ENVELOPE % <<EOS
108
- <ns1:disableResponse xmlns:ns1="http://recurring.services.adyen.com">
109
- <ns1:result>
110
- <response xmlns="http://recurring.services.adyen.com">
111
- %s
112
- </response>
113
- </ns1:result>
114
- </ns1:disableResponse>
115
- EOS
107
+ DISABLE_RESPONSE = SimpleSOAPClient::ENVELOPE % <<-EOXML
108
+ <ns1:disableResponse xmlns:ns1="http://recurring.services.adyen.com">
109
+ <ns1:result>
110
+ <response xmlns="http://recurring.services.adyen.com">
111
+ %s
112
+ </response>
113
+ </ns1:result>
114
+ </ns1:disableResponse>
115
+ EOXML
116
116
 
117
117
  # @return [DisableResponse] A ‘disable succeeded’ response instance.
118
118
  def disabled_stub
@@ -31,6 +31,10 @@ module Adyen
31
31
  def perform_xpath(query, root_node)
32
32
  root_node.xpath(query, NS)
33
33
  end
34
+
35
+ def stringify_nodeset(nodeset)
36
+ nodeset.to_xml(encoding: 'UTF-8')
37
+ end
34
38
  end
35
39
 
36
40
  class REXMLBackend
@@ -48,7 +52,11 @@ module Adyen
48
52
 
49
53
  def perform_xpath(query, root_node)
50
54
  REXML::XPath.match(root_node, query, NS)
51
- end
55
+ end
56
+
57
+ def stringify_nodeset(nodeset)
58
+ nodeset.map { |n| n.to_s }.join("")
59
+ end
52
60
  end
53
61
 
54
62
  # @return A backend to handle XML parsing.
@@ -116,7 +124,7 @@ module Adyen
116
124
 
117
125
  # @return [String] A string representation of this node.
118
126
  def to_s
119
- Array === @node ? @node.join("") : @node.to_s
127
+ backend.stringify_nodeset(@node)
120
128
  end
121
129
 
122
130
  # @yield [XMLQuerier] A member of this node set, ready to be queried.
@@ -7,7 +7,7 @@ module Adyen
7
7
  module Encoding
8
8
  def self.hmac_base64(hmac_key, message)
9
9
  digest = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), hmac_key, message)
10
- Base64.encode64(digest).strip
10
+ Base64.strict_encode64(digest).strip
11
11
  end
12
12
 
13
13
  def self.gzip_base64(message)
@@ -15,7 +15,7 @@ module Adyen
15
15
  gz = Zlib::GzipWriter.new(sio)
16
16
  gz.write(message)
17
17
  gz.close
18
- Base64.encode64(sio.string).gsub("\n", "")
18
+ Base64.strict_encode64(sio.string)
19
19
  end
20
20
  end
21
21
  end
@@ -119,6 +119,10 @@ module Adyen
119
119
  parameters[:billing_address_sig] = calculate_billing_address_signature(parameters, shared_secret)
120
120
  end
121
121
 
122
+ if parameters[:shopper]
123
+ parameters[:shopper_sig] = calculate_shopper_signature(parameters, shared_secret)
124
+ end
125
+
122
126
  return parameters
123
127
  end
124
128
 
@@ -165,6 +169,20 @@ module Adyen
165
169
  }.join('&')
166
170
  end
167
171
 
172
+ # @see Adyen::Form.redirect_url
173
+ #
174
+ # Returns an absolute URL very similar to the one returned by Adyen::Form.redirect_url
175
+ # except that it uses the directory.shtml call which returns a list of all available
176
+ # payment methods
177
+ #
178
+ # @param [Hash] parameters The payment parameters to include in the payment request.
179
+ # @return [String] An absolute URL to redirect to the Adyen payment system.
180
+ def payment_methods_url(parameters = {})
181
+ url(nil, :directory) + '?' + flat_payment_parameters(parameters).map { |(k, v)|
182
+ "#{k}=#{CGI.escape(v)}"
183
+ }.join('&')
184
+ end
185
+
168
186
  # Returns a HTML snippet of hidden INPUT tags with the provided payment parameters.
169
187
  # The snippet can be included in a payment form that POSTs to the Adyen payment system.
170
188
  #
@@ -266,6 +284,20 @@ module Adyen
266
284
  Adyen::Encoding.hmac_base64(shared_secret, calculate_billing_address_signature_string(parameters[:billing_address]))
267
285
  end
268
286
 
287
+ # shopperSig: shopper.firstName + shopper.infix + shopper.lastName + shopper.gender + shopper.dateOfBirthDayOfMonth + shopper.dateOfBirthMonth + shopper.dateOfBirthYear + shopper.telephoneNumber
288
+ # (Note that you can send only shopper.firstName and shopper.lastName if you like. Do NOT include shopperSocialSecurityNumber in the shopperSig!)
289
+ def calculate_shopper_signature_string(parameters)
290
+ %w(first_name infix last_name gender date_of_birth_day_of_month date_of_birth_month date_of_birth_year telephone_number).map do |key|
291
+ parameters[key.to_sym]
292
+ end.join
293
+ end
294
+
295
+ def calculate_shopper_signature(parameters, shared_secret = nil)
296
+ shared_secret ||= parameters.delete(:shared_secret)
297
+ raise ArgumentError, "Cannot calculate shopper request signature with empty shared_secret" if shared_secret.to_s.empty?
298
+ Adyen::Encoding.hmac_base64(shared_secret, calculate_shopper_signature_string(parameters[:shopper]))
299
+ end
300
+
269
301
  ######################################################
270
302
  # REDIRECT SIGNATURE CHECKING
271
303
  ######################################################