fintecture 0.1.7 → 0.3.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +17 -16
  3. data/.rspec +3 -3
  4. data/.travis.yml +7 -7
  5. data/CODE_OF_CONDUCT.md +74 -74
  6. data/Gemfile +8 -6
  7. data/Gemfile.lock +59 -40
  8. data/LICENSE.txt +674 -674
  9. data/README.md +404 -121
  10. data/Rakefile +8 -6
  11. data/bin/console +15 -14
  12. data/bin/setup +8 -8
  13. data/exemples/ais.rb +53 -0
  14. data/exemples/config_ais.json +8 -0
  15. data/exemples/config_pis.json +6 -0
  16. data/exemples/pis.rb +148 -0
  17. data/exemples/ressources.rb +23 -0
  18. data/fintecture.gemspec +44 -43
  19. data/lib/fintecture/ais_client.rb +94 -0
  20. data/lib/fintecture/api/ais/account_holders.rb +61 -0
  21. data/lib/fintecture/api/ais/accounts.rb +63 -0
  22. data/lib/fintecture/api/ais/authorize.rb +72 -0
  23. data/lib/fintecture/api/ais/authorize_decoupled.rb +68 -0
  24. data/lib/fintecture/api/ais/connect.rb +65 -0
  25. data/lib/fintecture/api/ais/delete_customer.rb +53 -0
  26. data/lib/fintecture/api/ais/transactions.rb +64 -0
  27. data/lib/fintecture/{authentication.rb → api/auth/authentication.rb} +78 -76
  28. data/lib/fintecture/api/pis/connect.rb +77 -0
  29. data/lib/fintecture/api/pis/initiate.rb +52 -0
  30. data/lib/fintecture/api/pis/payments.rb +48 -0
  31. data/lib/fintecture/api/pis/refund.rb +67 -0
  32. data/lib/fintecture/api/pis/request_to_pay.rb +63 -0
  33. data/lib/fintecture/api/pis/settlements.rb +48 -0
  34. data/lib/fintecture/api/ressources/applications.rb +57 -0
  35. data/lib/fintecture/api/ressources/providers.rb +61 -0
  36. data/lib/fintecture/api/ressources/test_accounts.rb +60 -0
  37. data/lib/fintecture/base_url.rb +26 -0
  38. data/lib/fintecture/endpoints/ais.rb +17 -0
  39. data/lib/fintecture/{api/endpoints → endpoints}/authentication.rb +13 -13
  40. data/lib/fintecture/endpoints/pis.rb +16 -0
  41. data/lib/fintecture/endpoints/ressources.rb +13 -0
  42. data/lib/fintecture/exceptions.rb +72 -4
  43. data/lib/fintecture/faraday/authentication/connection.rb +140 -74
  44. data/lib/fintecture/pis_client.rb +100 -0
  45. data/lib/fintecture/utils/constants.rb +11 -14
  46. data/lib/fintecture/utils/crypto.rb +75 -76
  47. data/lib/fintecture/utils/date.rb +15 -15
  48. data/lib/fintecture/utils/validation.rb +32 -17
  49. data/lib/fintecture/version.rb +5 -3
  50. data/lib/fintecture.rb +65 -82
  51. metadata +35 -13
  52. data/lib/fintecture/api/base_url.rb +0 -28
  53. data/lib/fintecture/api/endpoints/pis.rb +0 -13
  54. data/lib/fintecture/connect.rb +0 -172
  55. data/lib/fintecture/pis.rb +0 -61
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'faraday'
5
+ require 'fintecture/endpoints/pis'
6
+ require 'fintecture/base_url'
7
+
8
+ module Fintecture
9
+ module Pis
10
+ class Settlements
11
+ class << self
12
+ # ------------ PUBLIC METHOD ------------
13
+ def get(client, settlement_id)
14
+ @client = client
15
+
16
+ # Do the get_payments request
17
+ _request settlement_id
18
+ end
19
+
20
+ private
21
+
22
+ # ------------ REQUEST ------------
23
+ def _request(settlement_id)
24
+ url = _endpoint
25
+
26
+ Fintecture::Faraday::Authentication::Connection.get(
27
+ url: "#{url}/#{settlement_id}",
28
+ client: @client,
29
+ custom_content_type: 'application/json',
30
+ bearer: "Bearer #{@client.token}",
31
+ secure_headers: true
32
+ )
33
+ end
34
+
35
+ # ------------ API ENDPOINT ------------
36
+ def _endpoint
37
+ "#{_api_base_url}/#{Fintecture::Api::Endpoints::Pis::SETTLEMENTS}"
38
+ end
39
+
40
+ # ------------ BASE URL ------------
41
+ def _api_base_url
42
+ Fintecture::Api::BaseUrl::FINTECTURE_API_URL[@client.environment.to_sym]
43
+ end
44
+
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'json'
5
+ require 'faraday'
6
+ require 'fintecture/utils/validation'
7
+ require 'fintecture/exceptions'
8
+ require 'fintecture/utils/date'
9
+ require 'fintecture/utils/constants'
10
+
11
+ module Fintecture
12
+ module Ressources
13
+ class Applications
14
+ class << self
15
+ # ------------ PUBLIC METHOD ------------
16
+ def get(client)
17
+ @client = client
18
+
19
+ # Do the request
20
+ _request
21
+ end
22
+
23
+ private
24
+
25
+ # ------------ REQUEST ------------
26
+ def _request
27
+ # Get the url request
28
+ url = _endpoint
29
+
30
+ # Build additional headers
31
+ additional_headers = {}
32
+ additional_headers['app_id'] = @client.app_id
33
+
34
+ # Do connect request
35
+ Fintecture::Faraday::Authentication::Connection.get(
36
+ url: url,
37
+ client: @client,
38
+ custom_content_type: 'application/json',
39
+ secure_headers: true,
40
+ additional_headers: additional_headers
41
+ )
42
+ end
43
+
44
+ # ------------ API ENDPOINT ------------
45
+ def _endpoint
46
+ "#{_api_base_url}/#{Fintecture::Api::Endpoints::Ressources::APPLICATION}"
47
+ end
48
+
49
+ # ------------ BASE URL ------------
50
+ def _api_base_url
51
+ Fintecture::Api::BaseUrl::FINTECTURE_API_URL[@client.environment.to_sym]
52
+ end
53
+
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'json'
5
+ require 'faraday'
6
+ require 'fintecture/utils/validation'
7
+ require 'fintecture/exceptions'
8
+ require 'fintecture/utils/date'
9
+ require 'fintecture/utils/constants'
10
+
11
+ module Fintecture
12
+ module Ressources
13
+ class Providers
14
+ class << self
15
+ # ------------ PUBLIC METHOD ------------
16
+ def get(client, provider_id, paramsProviders)
17
+ @client = client
18
+
19
+ # Do the request
20
+ _request provider_id, paramsProviders
21
+ end
22
+
23
+ private
24
+
25
+ # ------------ REQUEST ------------
26
+ def _request(provider_id, paramsProviders)
27
+ # Get the url request
28
+ url = _endpoint provider_id
29
+
30
+ # Build additional headers
31
+ additional_headers = {}
32
+ additional_headers['app_id'] = @client.app_id
33
+
34
+ # Build uri params
35
+ query_string = ''
36
+ query_string = "?#{paramsProviders.map { |key, value| "#{key}=#{value}" }.join('&')}" if paramsProviders
37
+
38
+ # Do connect request
39
+ Fintecture::Faraday::Authentication::Connection.get(
40
+ url: url + query_string,
41
+ client: @client,
42
+ custom_content_type: 'application/json',
43
+ secure_headers: true,
44
+ additional_headers: additional_headers
45
+ )
46
+ end
47
+
48
+ # ------------ API ENDPOINT ------------
49
+ def _endpoint(provider_id)
50
+ "#{_api_base_url}/#{Fintecture::Api::Endpoints::Ressources::PROVIDERS}/#{provider_id || ''}"
51
+ end
52
+
53
+ # ------------ BASE URL ------------
54
+ def _api_base_url
55
+ Fintecture::Api::BaseUrl::FINTECTURE_API_URL[@client.environment.to_sym]
56
+ end
57
+
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'json'
5
+ require 'faraday'
6
+ require 'fintecture/utils/validation'
7
+ require 'fintecture/exceptions'
8
+ require 'fintecture/utils/date'
9
+ require 'fintecture/utils/constants'
10
+
11
+ module Fintecture
12
+ module Ressources
13
+ class TestAccounts
14
+ class << self
15
+ # ------------ PUBLIC METHOD ------------
16
+ def get(client, provider_id)
17
+ @client = client
18
+
19
+ # Do the request
20
+ _request provider_id
21
+ end
22
+
23
+ private
24
+
25
+ # ------------ REQUEST ------------
26
+ def _request(provider_id)
27
+ # Get the url request
28
+ url = _endpoint
29
+
30
+ # Build additional headers
31
+ additional_headers = {}
32
+ additional_headers['app_id'] = @client.app_id
33
+
34
+ # Build uri params
35
+ query_string = ''
36
+ query_string = "?filter[provider_id]=#{provider_id}" if provider_id
37
+ # Do connect request
38
+ Fintecture::Faraday::Authentication::Connection.get(
39
+ url: url + query_string,
40
+ client: @client,
41
+ custom_content_type: 'application/json',
42
+ secure_headers: true,
43
+ additional_headers: additional_headers
44
+ )
45
+ end
46
+
47
+ # ------------ API ENDPOINT ------------
48
+ def _endpoint
49
+ "#{_api_base_url}/#{Fintecture::Api::Endpoints::Ressources::TESTACCOUNTS}"
50
+ end
51
+
52
+ # ------------ BASE URL ------------
53
+ def _api_base_url
54
+ Fintecture::Api::BaseUrl::FINTECTURE_API_URL[@client.environment.to_sym]
55
+ end
56
+
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,26 @@
1
+ module Fintecture
2
+ module Api
3
+ module BaseUrl
4
+ FINTECTURE_OAUTH_URL = {
5
+ local: 'http://localhost:3030/oauth',
6
+ test: 'https://oauth-sandbox-test.fintecture.com/oauth',
7
+ sandbox: 'https://api-sandbox.fintecture.com/oauth',
8
+ production: 'https://api.fintecture.com/oauth'
9
+ }
10
+
11
+ FINTECTURE_API_URL = {
12
+ local: 'http://localhost:3030',
13
+ test: 'https://api-sandbox-test.fintecture.com',
14
+ sandbox: 'https://api-sandbox-test.fintecture.com',
15
+ production: 'https://api.fintecture.com'
16
+ }
17
+
18
+ FINTECTURE_CONNECT_URL = {
19
+ local: 'http://localhost:4201',
20
+ test: 'https://connect-test.fintecture.com',
21
+ sandbox: 'https://connect-sandbox.fintecture.com',
22
+ production: 'https://connect.fintecture.com'
23
+ }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fintecture
4
+ module Api
5
+ module Endpoints
6
+ module Ais
7
+ # TODO: faire plus complet, avec un mot clef a remplacer
8
+ CONNECT = 'ais/v2/connect'
9
+ ACCOUNTS = 'ais/v1/customer'
10
+ TRANSACTIONS = 'ais/v1/customer'
11
+ ACCOUNTHOLDERS = 'ais/v1/customer'
12
+ CUSTOMER = 'ais/v1/customer'
13
+ AUTHORIZE = 'ais/v1/provider'
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,13 +1,13 @@
1
- module Fintecture
2
- module Api
3
- module Endpoints
4
- module Authentication
5
-
6
- OAUTH_TOKEN_AUTHORIZE = '/token/authorize'
7
- OAUTH_ACCESS_TOKEN = '/accesstoken'
8
- OAUTH_REFRESH_TOKEN = '/refreshtoken'
9
-
10
- end
11
- end
12
- end
13
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Fintecture
4
+ module Api
5
+ module Endpoints
6
+ module Authentication
7
+ OAUTH_TOKEN_AUTHORIZE = '/token/authorize'
8
+ OAUTH_ACCESS_TOKEN = '/accesstoken'
9
+ OAUTH_REFRESH_TOKEN = '/refreshtoken'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fintecture
4
+ module Api
5
+ module Endpoints
6
+ module Pis
7
+ INITIATE = 'pis/v2/provider'
8
+ REFUND = 'pis/v2/refund'
9
+ REQUEST_TO_PAY = 'pis/v2/request-to-pay'
10
+ PAYMENTS = 'pis/v2/payments'
11
+ CONNECT = 'pis/v2/connect'
12
+ SETTLEMENTS = 'pis/v2/settlements'
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fintecture
4
+ module Api
5
+ module Endpoints
6
+ module Ressources
7
+ APPLICATION = 'res/v1/applications'
8
+ PROVIDERS = 'res/v1/providers'
9
+ TESTACCOUNTS = 'res/v1/testaccounts'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,4 +1,72 @@
1
- module Fintecture
2
- class ValidationException < Exception; end
3
- class CryptoException < Exception; end
4
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Fintecture
6
+ class ValidationException < RuntimeError; end
7
+
8
+ class CryptoException < RuntimeError; end
9
+
10
+ class ApiException
11
+ class << self
12
+ def error(res)
13
+ body = JSON.parse res.body
14
+
15
+ # Errors array
16
+ if body['code'] && body['log_id'] && body['errors']
17
+ raise _construct_message_errors(res, body)
18
+ # Single error
19
+ else
20
+ raise _construct_message_error(res, body)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def _construct_message_errors(res, body)
27
+ status = res.status
28
+ code = body['code']
29
+ log_id = body['log_id']
30
+ errors_array = body['errors']
31
+
32
+ error_string = "\nFintecture server errors : "
33
+ error_string += "\n status: #{status} "
34
+ error_string += "\n code: #{code}"
35
+ error_string += "\n id : #{log_id}"
36
+
37
+ errors_array.each do |error|
38
+ formated_error = error.map { |key, value| " #{key}: #{value}" }.join("\n")
39
+ error_string += "\n\n#{formated_error}"
40
+ end
41
+ error_string += "\n\n"
42
+
43
+ {
44
+ type: 'Fintecture api',
45
+ status: status,
46
+ errors: errors_array,
47
+ error_string: error_string
48
+ }.to_json
49
+ end
50
+
51
+ def _construct_message_error(res, body)
52
+ status = res.status
53
+ error = body['meta']
54
+
55
+ error_string = "\nFintecture server errors : "
56
+ error_string += "\n status: #{status} "
57
+
58
+ formated_error = error.map { |key, value| " #{key}: #{value}" }.join("\n")
59
+ error_string += "\n\n#{formated_error}"
60
+
61
+ error_string += "\n\n"
62
+
63
+ {
64
+ type: 'Fintecture api',
65
+ status: status,
66
+ errors: [error],
67
+ error_string: error_string
68
+ }.to_json
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,74 +1,140 @@
1
- require 'base64'
2
- require 'faraday'
3
- require 'uri'
4
- require 'fintecture/utils/crypto'
5
- require 'fintecture/utils/date'
6
-
7
- module Fintecture
8
- module Faraday
9
- module Authentication
10
- class Connection
11
- class << self
12
-
13
- def connection(url)
14
- ::Faraday.new(url: url) do |faraday|
15
- faraday.request :url_encoded
16
- faraday.adapter ::Faraday.default_adapter
17
- end
18
- end
19
-
20
- def post(url:, req_body: nil, custom_content_type: nil, bearer: nil, secure_headers: false)
21
- conn = connection(url)
22
-
23
- conn.post do |req|
24
- req.headers = req_headers(custom_content_type, bearer, secure_headers, method: 'post', body: req_body, url: url)
25
- req.body = req_body
26
- end
27
- end
28
-
29
- def get(url:, req_body: nil, custom_content_type: nil, bearer: nil, secure_headers: false)
30
- conn = connection(url)
31
-
32
- conn.get do |req|
33
- req.headers = req_headers(custom_content_type, bearer, secure_headers, method: 'get', url: url)
34
- req.body = req_body
35
- end
36
- end
37
-
38
- def req_headers(custom_content_type, bearer, secure_headers, method: '', body: {}, url:)
39
- client_token = Base64.strict_encode64("#{Fintecture.app_id}:#{Fintecture.app_secret}")
40
-
41
- {
42
- 'Accept' => 'application/json',
43
- 'User-Agent' => "Fintecture Ruby SDK v #{Fintecture::VERSION}",
44
- 'Authorization' => bearer ? bearer : "Basic #{client_token}",
45
- 'Content-Type' => custom_content_type ? custom_content_type : 'application/x-www-form-urlencoded',
46
- }.merge(secure_headers ? req_secure_headers(body: body, url: url, method: method) : {})
47
-
48
- end
49
-
50
- def req_secure_headers(body: {}, url: '', method: '')
51
- payload = ( body.class.name == 'String' ? body : body.to_s )
52
- path_name = URI(url).path
53
- search_params = URI(url).query
54
-
55
- headers = {
56
- 'Date' => Fintecture::Utils::Date.header_time.to_s,
57
- 'X-Request-ID' => Fintecture::Utils::Crypto.generate_uuid
58
- }.merge(payload ? load_digest(payload) : {})
59
-
60
- request_target = search_params ? "#{method.downcase} #{path_name}?#{search_params}" : "#{method.downcase} #{path_name}"
61
-
62
- headers['Signature'] = Fintecture::Utils::Crypto.create_signature_header({'(request-target)' => request_target}.merge(headers))
63
- headers
64
- end
65
-
66
- def load_digest(payload)
67
- {'Digest' => "SHA-256=#{Fintecture::Utils::Crypto.hash_base64(payload)}"}
68
- end
69
-
70
- end
71
- end
72
- end
73
- end
74
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'faraday'
5
+ require 'uri'
6
+ require 'fintecture/utils/crypto'
7
+ require 'fintecture/utils/date'
8
+
9
+ module Fintecture
10
+ module Faraday
11
+ module Authentication
12
+ class Connection
13
+ class << self
14
+ def connection(url)
15
+ ::Faraday.new(url: url) do |faraday|
16
+ faraday.request :url_encoded
17
+ faraday.adapter ::Faraday.default_adapter
18
+ end
19
+ end
20
+
21
+ def post(url:, req_body: nil, client: nil, custom_content_type: nil, bearer: nil, secure_headers: false, additional_headers: nil, disableAuthorization: nil)
22
+ @client = client
23
+ conn = connection(url)
24
+ res = conn.post do |req|
25
+ req.options.params_encoder = Faraday::DisabledEncoder
26
+ req.headers = req_headers(custom_content_type, bearer, secure_headers, additional_headers, disableAuthorization,
27
+ method: 'post', body: req_body, url: url)
28
+ req.body = req_body
29
+ end
30
+
31
+ !res.success? ? Fintecture::ApiException.error(res) : res
32
+ end
33
+
34
+ def get(url:, req_body: nil, client: nil, custom_content_type: nil, bearer: nil, secure_headers: false, additional_headers: nil, disableAuthorization: nil)
35
+ @client = client
36
+ conn = connection(url)
37
+
38
+ res = conn.get do |req|
39
+ req.options.params_encoder = Faraday::DisabledEncoder
40
+ req.headers = req_headers(custom_content_type, bearer, secure_headers, additional_headers, disableAuthorization,
41
+ method: 'get', url: url)
42
+ req.body = req_body
43
+ end
44
+
45
+ !res.success? ? Fintecture::ApiException.error(res) : res
46
+ end
47
+
48
+ def delete(url:, req_body: nil, client: nil, custom_content_type: nil, bearer: nil, secure_headers: false, additional_headers: nil, disableAuthorization: nil)
49
+ @client = client
50
+ conn = connection(url)
51
+
52
+ res = conn.delete do |req|
53
+ req.options.params_encoder = Faraday::DisabledEncoder
54
+ req.headers = req_headers(custom_content_type, bearer, secure_headers, additional_headers, disableAuthorization,
55
+ method: 'delete', body: req_body, url: url)
56
+ req.body = req_body
57
+ end
58
+
59
+ !res.success? ? Fintecture::ApiException.error(res) : res
60
+ end
61
+
62
+ def req_headers(custom_content_type, bearer, secure_headers, additional_headers, disableAuthorization, url:, method: '', body: {})
63
+ if !additional_headers.nil? && !additional_headers.is_a?(Hash)
64
+ raise Fintecture::ValidationException, 'additional_headers must be an object'
65
+ end
66
+
67
+ client_token = Base64.strict_encode64("#{@client.app_id}:#{@client.app_secret}")
68
+
69
+ headers = {
70
+ 'Accept' => 'application/json',
71
+ 'User-Agent' => "Fintecture Ruby SDK v #{Fintecture::VERSION}",
72
+ 'Content-Type' => custom_content_type || 'application/x-www-form-urlencoded'
73
+ }
74
+ headers['Authorization'] = bearer || "Basic #{client_token}" unless disableAuthorization
75
+ headers = headers.merge(additional_headers) unless additional_headers.nil?
76
+ headers.merge(secure_headers ? req_secure_headers(body: body, url: url, method: method) : {})
77
+ end
78
+
79
+ def req_secure_headers(body: {}, url: '', method: '')
80
+ payload = (body.instance_of?(String) ? body : body.to_s)
81
+ path_name = URI(url).path
82
+ search_params = URI(url).query
83
+
84
+ request_target = search_params ? "#{method.downcase} #{path_name}?#{search_params}" : "#{method.downcase} #{path_name}"
85
+ date = Fintecture::Utils::Date.header_time.to_s
86
+ digest = load_digest(payload)
87
+ x_request_id = Fintecture::Utils::Crypto.generate_uuid
88
+
89
+ headers = {
90
+ 'Date' => date,
91
+ 'X-Request-ID' => x_request_id
92
+ }.merge(payload ? digest : {})
93
+
94
+ headers['Signature'] =
95
+ Fintecture::Utils::Crypto.create_signature_header(
96
+ { '(request-target)' => request_target }.merge(headers), @client
97
+ )
98
+ headers
99
+ end
100
+
101
+ def load_digest(payload)
102
+ { 'Digest' => "SHA-256=#{Fintecture::Utils::Crypto.hash_base64(payload)}" }
103
+ end
104
+
105
+ end
106
+ end
107
+ end
108
+
109
+ module DisabledEncoder
110
+ class << self
111
+ extend Forwardable
112
+ def_delegators :'Faraday::Utils', :escape, :unescape
113
+ end
114
+
115
+ def self.encode(params)
116
+ return nil if params.nil?
117
+
118
+ newParams = {}
119
+ params.each do |key, value|
120
+ if value.instance_of?(Hash)
121
+ value.each do |subkey, subvalue|
122
+ newParams["#{key}[#{subkey}]"] = subvalue
123
+ end
124
+ else
125
+ newParams[key] = value
126
+ end
127
+ end
128
+
129
+ newParams.map { |key, value| "#{key}=#{value}" }.join('&').to_s
130
+ end
131
+
132
+ class << self
133
+ attr_accessor :sort_params
134
+ end
135
+
136
+ # Useful default for OAuth and caching.
137
+ @sort_params = true
138
+ end
139
+ end
140
+ end