conexa 0.1.0 → 0.2.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.
@@ -4,13 +4,23 @@ module Conexa
4
4
  class RecurringSale < Model
5
5
  primary_key_attribute :recurring_sale_id
6
6
 
7
- # End/terminate a recurring sale
8
- # @param params [Hash] optional parameters (e.g., endDate)
7
+ # Set this recurring sale's end date — closing it, or amending an existing
8
+ # closure.
9
+ #
10
+ # Like the contract endpoint, this one is documented as "encerra uma venda
11
+ # recorrente ativa **ou atualiza a data de encerramento**".
12
+ #
13
+ # @param params [Hash]
14
+ # @option params [String] :date required, yyyy-MM-dd — the closing date
15
+ # @option params [String] :end_date deprecated alias for +:date+; the API
16
+ # rejects the +endDate+ it camelizes to
9
17
  # @return [self]
10
18
  def end_recurring_sale(params = {})
11
- Conexa::Request.post(self.class.show_url("end", primary_key), params: params).call(class_name)
19
+ params = Util.normalize_end_date_param(params)
20
+ Conexa::Request.patch(self.class.show_url("end", primary_key), params: params).call(class_name)
12
21
  self
13
22
  end
23
+ alias_method :set_end_date, :end_recurring_sale
14
24
 
15
25
  class << self
16
26
  def url(*params)
@@ -21,13 +31,14 @@ module Conexa
21
31
  ["/recurringSale", *params].join '/'
22
32
  end
23
33
 
24
- # End a recurring sale by ID
34
+ # Set a recurring sale's end date by ID
35
+ # @see #end_recurring_sale
25
36
  # @param id [Integer, String] recurring sale ID
26
- # @param params [Hash] optional parameters (e.g., endDate)
27
37
  # @return [RecurringSale]
28
38
  def end_recurring_sale(id, params = {})
29
39
  find(id).end_recurring_sale(params)
30
40
  end
41
+ alias_method :set_end_date, :end_recurring_sale
31
42
  end
32
43
  end
33
44
  end
@@ -18,19 +18,37 @@ module Conexa
18
18
  @attributes["pagination"]
19
19
  end
20
20
 
21
+ # @return [Boolean] always a boolean — it used to yield nil when there was no
22
+ # pagination at all, which is falsy but not `false`, and leaks out of any
23
+ # caller that serialises or compares the result.
21
24
  def has_next?
22
- pagination && pagination.has_next == true
25
+ pagination.respond_to?(:has_next) && pagination.has_next == true
23
26
  end
24
27
 
25
28
  def next_page
26
29
  raise StopIteration, "No more pages" unless has_next?
27
- raise "No query context available for next_page" unless @query_context
30
+ raise Conexa::RequestError, "No query context available for next_page" unless @query_context
31
+
32
+ limit = pagination.limit
33
+ offset = pagination.offset
34
+ unless limit.is_a?(Integer) && offset.is_a?(Integer)
35
+ raise Conexa::ResponseError.new(@query_context[:params], nil,
36
+ "pagination is missing limit/offset " \
37
+ "(limit=#{limit.inspect}, offset=#{offset.inspect}), " \
38
+ "so the next page cannot be computed")
39
+ end
28
40
 
29
41
  resource_class = @query_context[:resource_class]
30
- next_params = Marshal.load(Marshal.dump(@query_context[:params]))
31
42
 
32
- next_params[:limit] = pagination.limit
33
- next_params[:offset] = pagination.offset + pagination.limit
43
+ begin
44
+ next_params = Marshal.load(Marshal.dump(@query_context[:params]))
45
+ rescue TypeError
46
+ # A non-marshallable filter (a Proc, an IO) in the original query.
47
+ next_params = @query_context[:params].dup
48
+ end
49
+
50
+ next_params[:limit] = limit
51
+ next_params[:offset] = offset + limit
34
52
  next_params.delete(:page)
35
53
  next_params.delete(:size)
36
54
 
data/lib/conexa/util.rb CHANGED
@@ -47,25 +47,62 @@ module Conexa
47
47
  string.to_s.strip.gsub(/[\s\-]+/, '_').to_sym
48
48
  end
49
49
 
50
+ # Both "end" endpoints — PATCH /contract/end/:id and
51
+ # PATCH /recurringSale/end/:id — document the closing date as `date`. The
52
+ # gem used to send `end_date`, which camelizes to `endDate` and is rejected:
53
+ # "endDate field does not exist or is not available in the company".
54
+ #
55
+ # Both key spellings are handled, and both are removed. Checking only the
56
+ # symbol `:date` would leave a caller's string `"date"` in place and add a
57
+ # second, colliding key — camelize_hash folds the two into one and the last
58
+ # one wins, so the deprecated value would silently replace the real one.
59
+ #
60
+ # @param params [Hash] caller params, possibly using the old name
61
+ # @return [Hash] a copy with end_date folded into date
62
+ def normalize_end_date_param(params)
63
+ params = params.dup
64
+
65
+ # Collapse both spellings of each key up front. Leaving one behind would
66
+ # let camelize_hash fold two `date` keys into one, last-write-wins — which
67
+ # is how the deprecated value once silently replaced the real one.
68
+ legacy = [params.delete(:end_date), params.delete("end_date")].compact.first
69
+ explicit = [params.delete(:date), params.delete("date")].compact.first
70
+
71
+ if legacy
72
+ warn "DEPRECATION WARNING: `end_date:` foi renomeado para `date:` em conexa 0.2.0 " \
73
+ "(a API v2 rejeita `endDate`). O alias será removido em 0.3.0."
74
+ end
75
+
76
+ # An explicit date wins; a key present with a nil value is not one.
77
+ date = explicit || legacy
78
+ params[:date] = date unless date.nil?
79
+ params
80
+ end
81
+
50
82
  def to_snake_case str
51
83
  str.gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, '')
52
84
  end
53
85
 
54
86
 
87
+ # Convert a payload's keys to the camelCase the API expects, all the way
88
+ # down. Arrays of objects matter as much as nested hashes: ten documented
89
+ # endpoints take them (complementaryServices, productQuotas, devices,
90
+ # extraFields, bookingModels, visitors, costCenters, ...), and a snake_case
91
+ # key inside one is rejected outright.
55
92
  def camelize_hash(hash)
56
93
  return {} if hash.nil?
57
94
 
58
- new_hash = {}
59
-
60
- hash.each do |key, value|
61
- if value.is_a?(Hash)
62
- new_hash[camel_case_lower(key).to_sym] = camelize_hash(value)
63
- else
64
- new_hash[camel_case_lower(key).to_sym] = value
65
- end
95
+ hash.each_with_object({}) do |(key, value), new_hash|
96
+ new_hash[camel_case_lower(key).to_sym] = camelize_value(value)
66
97
  end
98
+ end
67
99
 
68
- new_hash
100
+ def camelize_value(value)
101
+ case value
102
+ when Hash then camelize_hash(value)
103
+ when Array then value.map { |element| camelize_value(element) }
104
+ else value
105
+ end
69
106
  end
70
107
 
71
108
  def camelize_str(str)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Conexa
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/conexa.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "conexa/version"
4
- require_relative "conexa/authenticator"
5
4
  require_relative "conexa/request"
6
5
  require_relative "conexa/object"
7
6
  require_relative "conexa/model"
@@ -9,8 +8,6 @@ require_relative "conexa/core_ext"
9
8
  require_relative "conexa/errors"
10
9
  require_relative "conexa/util"
11
10
  require_relative "conexa/configuration"
12
- require_relative "conexa/order_common"
13
- require_relative "conexa/token_manager"
14
11
 
15
12
 
16
13
  Dir[File.expand_path('../conexa/resources/*.rb', __FILE__)].map do |path|
@@ -32,4 +29,42 @@ module Conexa
32
29
  def self.api_endpoint
33
30
  configuration.api_host + "/index.php/api/v2"
34
31
  end
32
+
33
+ # Key for the block-scoped read-only override. Thread-local so a guarded block
34
+ # in one thread cannot relax or tighten another.
35
+ READ_ONLY_KEY = :conexa_read_only
36
+
37
+ # Is writing currently forbidden?
38
+ #
39
+ # True inside a {read_only} block, or whenever `configuration.read_only` is set
40
+ # (which itself defaults from CONEXA_READ_ONLY).
41
+ #
42
+ # @return [Boolean]
43
+ def self.read_only?
44
+ scoped = Thread.current[READ_ONLY_KEY]
45
+ return scoped unless scoped.nil?
46
+
47
+ !!configuration&.read_only
48
+ end
49
+
50
+ # Run a block with writes forbidden, then restore the previous state.
51
+ #
52
+ # Useful for auditing or reporting code that should never mutate a tenant,
53
+ # without having to reconfigure the client globally.
54
+ #
55
+ # @example
56
+ # Conexa.read_only do
57
+ # Conexa::Charge.all(status: "pending") # fine
58
+ # Conexa::Charge.settle(555) # raises Conexa::ReadOnlyError
59
+ # end
60
+ #
61
+ # @param enabled [Boolean] pass false to explicitly allow writes in the block
62
+ # @return [Object] the block's return value
63
+ def self.read_only(enabled = true)
64
+ previous = Thread.current[READ_ONLY_KEY]
65
+ Thread.current[READ_ONLY_KEY] = enabled
66
+ yield
67
+ ensure
68
+ Thread.current[READ_ONLY_KEY] = previous
69
+ end
35
70
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: conexa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guilherme Gazzinelli
@@ -9,118 +9,90 @@ bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: jwt
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - ">="
17
- - !ruby/object:Gem::Version
18
- version: '0'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - ">="
24
- - !ruby/object:Gem::Version
25
- version: '0'
26
12
  - !ruby/object:Gem::Dependency
27
13
  name: rest-client
28
14
  requirement: !ruby/object:Gem::Requirement
29
15
  requirements:
30
- - - ">="
16
+ - - "~>"
31
17
  - !ruby/object:Gem::Version
32
- version: '0'
18
+ version: '2.1'
33
19
  type: :runtime
34
20
  prerelease: false
35
21
  version_requirements: !ruby/object:Gem::Requirement
36
22
  requirements:
37
- - - ">="
23
+ - - "~>"
38
24
  - !ruby/object:Gem::Version
39
- version: '0'
25
+ version: '2.1'
40
26
  - !ruby/object:Gem::Dependency
41
27
  name: multi_json
42
28
  requirement: !ruby/object:Gem::Requirement
43
29
  requirements:
44
- - - ">="
30
+ - - "~>"
45
31
  - !ruby/object:Gem::Version
46
- version: '0'
32
+ version: '1.15'
47
33
  type: :runtime
48
34
  prerelease: false
49
35
  version_requirements: !ruby/object:Gem::Requirement
50
36
  requirements:
51
- - - ">="
37
+ - - "~>"
52
38
  - !ruby/object:Gem::Version
53
- version: '0'
39
+ version: '1.15'
54
40
  - !ruby/object:Gem::Dependency
55
41
  name: vcr
56
42
  requirement: !ruby/object:Gem::Requirement
57
43
  requirements:
58
- - - ">="
44
+ - - "~>"
59
45
  - !ruby/object:Gem::Version
60
- version: '0'
46
+ version: '6.0'
61
47
  type: :development
62
48
  prerelease: false
63
49
  version_requirements: !ruby/object:Gem::Requirement
64
50
  requirements:
65
- - - ">="
51
+ - - "~>"
66
52
  - !ruby/object:Gem::Version
67
- version: '0'
53
+ version: '6.0'
68
54
  - !ruby/object:Gem::Dependency
69
55
  name: webmock
70
56
  requirement: !ruby/object:Gem::Requirement
71
57
  requirements:
72
- - - ">="
73
- - !ruby/object:Gem::Version
74
- version: '0'
75
- type: :development
76
- prerelease: false
77
- version_requirements: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - ">="
80
- - !ruby/object:Gem::Version
81
- version: '0'
82
- - !ruby/object:Gem::Dependency
83
- name: debug
84
- requirement: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - ">="
58
+ - - "~>"
87
59
  - !ruby/object:Gem::Version
88
- version: '0'
60
+ version: '3.0'
89
61
  type: :development
90
62
  prerelease: false
91
63
  version_requirements: !ruby/object:Gem::Requirement
92
64
  requirements:
93
- - - ">="
65
+ - - "~>"
94
66
  - !ruby/object:Gem::Version
95
- version: '0'
67
+ version: '3.0'
96
68
  - !ruby/object:Gem::Dependency
97
69
  name: faker
98
70
  requirement: !ruby/object:Gem::Requirement
99
71
  requirements:
100
- - - ">="
72
+ - - "~>"
101
73
  - !ruby/object:Gem::Version
102
- version: '0'
74
+ version: '3.0'
103
75
  type: :development
104
76
  prerelease: false
105
77
  version_requirements: !ruby/object:Gem::Requirement
106
78
  requirements:
107
- - - ">="
79
+ - - "~>"
108
80
  - !ruby/object:Gem::Version
109
- version: '0'
81
+ version: '3.0'
110
82
  - !ruby/object:Gem::Dependency
111
83
  name: factory_bot
112
84
  requirement: !ruby/object:Gem::Requirement
113
85
  requirements:
114
- - - ">="
86
+ - - "~>"
115
87
  - !ruby/object:Gem::Version
116
- version: '0'
88
+ version: '6.0'
117
89
  type: :development
118
90
  prerelease: false
119
91
  version_requirements: !ruby/object:Gem::Requirement
120
92
  requirements:
121
- - - ">="
93
+ - - "~>"
122
94
  - !ruby/object:Gem::Version
123
- version: '0'
95
+ version: '6.0'
124
96
  description: Gem para integração com a Conexa
125
97
  email:
126
98
  - guilherme.gazzinelli@gmail.com
@@ -128,32 +100,19 @@ executables: []
128
100
  extensions: []
129
101
  extra_rdoc_files: []
130
102
  files:
131
- - ".editorconfig"
132
- - ".rspec"
133
- - ".rubocop.yml"
134
- - ".solargraph.yml"
135
- - ".vscode/launch.json"
136
103
  - CHANGELOG.md
137
104
  - CODE_OF_CONDUCT.md
138
- - Gemfile
139
- - Gemfile.lock
140
105
  - LICENSE
141
106
  - README.md
142
107
  - README_pt-BR.md
143
108
  - REFERENCE.md
144
- - Rakefile
145
- - bin/console
146
- - bin/setup
147
- - docs/postman-collection.json
148
109
  - lib/conexa.rb
149
- - lib/conexa/authenticator.rb
150
110
  - lib/conexa/configuration.rb
151
111
  - lib/conexa/core_ext.rb
152
112
  - lib/conexa/errors.rb
153
113
  - lib/conexa/generators/install_generator.rb
154
114
  - lib/conexa/model.rb
155
115
  - lib/conexa/object.rb
156
- - lib/conexa/order_common.rb
157
116
  - lib/conexa/request.rb
158
117
  - lib/conexa/resources/account.rb
159
118
  - lib/conexa/resources/address.rb
@@ -181,10 +140,8 @@ files:
181
140
  - lib/conexa/resources/sale.rb
182
141
  - lib/conexa/resources/service_category.rb
183
142
  - lib/conexa/resources/supplier.rb
184
- - lib/conexa/token_manager.rb
185
143
  - lib/conexa/util.rb
186
144
  - lib/conexa/version.rb
187
- - scripts/extract_fixtures.rb
188
145
  homepage: https://github.com/guilhermegazzinelli/conexa-ruby
189
146
  licenses:
190
147
  - MIT
@@ -199,14 +156,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
199
156
  requirements:
200
157
  - - ">="
201
158
  - !ruby/object:Gem::Version
202
- version: 2.6.0
159
+ version: 3.1.0
203
160
  required_rubygems_version: !ruby/object:Gem::Requirement
204
161
  requirements:
205
162
  - - ">="
206
163
  - !ruby/object:Gem::Version
207
164
  version: '0'
208
165
  requirements: []
209
- rubygems_version: 3.6.9
166
+ rubygems_version: 4.0.16
210
167
  specification_version: 4
211
168
  summary: Gem para integração com a Api da Conexa
212
169
  test_files: []
data/.editorconfig DELETED
@@ -1,30 +0,0 @@
1
- root = true
2
-
3
- [*]
4
- end_of_line = lf
5
- indent_size = 2
6
- indent_style = space
7
- insert_final_newline = true
8
- tab_width = 4
9
- trim_trailing_whitespace = true
10
-
11
- [*.bat]
12
- end_of_line = crlf
13
-
14
- [*.gemspec]
15
- indent_size = 2
16
-
17
- [*.rb]
18
- indent_size = 2
19
-
20
- [*.yml]
21
- indent_size = 2
22
-
23
- [{*[Mm]akefile*,*.mak,*.mk,depend}]
24
- indent_style = tab
25
-
26
- [enc/*]
27
- indent_size = 2
28
-
29
- [reg*.[ch]]
30
- indent_size = 2
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rubocop.yml DELETED
@@ -1,13 +0,0 @@
1
- AllCops:
2
- TargetRubyVersion: 2.6
3
-
4
- Style/StringLiterals:
5
- Enabled: true
6
- EnforcedStyle: double_quotes
7
-
8
- Style/StringLiteralsInInterpolation:
9
- Enabled: true
10
- EnforcedStyle: double_quotes
11
-
12
- Layout/LineLength:
13
- Max: 120
data/.solargraph.yml DELETED
@@ -1,2 +0,0 @@
1
- include:
2
- - "lib/*.rb"
data/.vscode/launch.json DELETED
@@ -1,30 +0,0 @@
1
- {
2
- // Use IntelliSense to learn about possible attributes.
3
- // Hover to view descriptions of existing attributes.
4
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
- "version": "0.2.0",
6
- "configurations": [
7
-
8
- {
9
- "name": "Run console",
10
- "debugPort": "9999",
11
- "request": "launch",
12
- "script": "${workspaceRoot}/bin/console",
13
- "type": "rdbg",
14
- "useTerminal": true,
15
- "rdbgPath": "bundle exec rdbg",
16
-
17
- "args": []
18
- },
19
- {
20
- "name": "Run rspec",
21
- "request": "launch",
22
- "script": "respec",
23
- "type": "rdbg",
24
- "useTerminal": true,
25
- "rdbgPath": "bundle exec rdbg",
26
-
27
- "args": []
28
- }
29
- ]
30
- }
data/Gemfile DELETED
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source "https://rubygems.org"
4
-
5
- # Specify your gem's dependencies in conexa.gemspec
6
- gemspec
7
-
8
- gem "rake", "~> 13.0"
9
-
10
- gem "rspec", "~> 3.0"
11
-
12
- gem "rubocop", "~> 1.21"
13
-
14
- gem "standard"
15
-
16
- gem "debug"
17
- gem "byebug"
18
-