conexa 0.0.9 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1dba13ee9b0dc841e758d5cb0b9c468a480ca564129666814c0e25892ea4cff
4
- data.tar.gz: 732eebd11f3ec3b5ee727f030ac51493fbce0e6212fb510dfcf5ba476d6424c4
3
+ metadata.gz: 76a95e870fc63f79b15b5227f1f0a10d94471efe573662dc626e42e57cf77b82
4
+ data.tar.gz: 92fce7222c5b9adad92e6524e6dbfb3466bc1282a81768c5872922af37d2085b
5
5
  SHA512:
6
- metadata.gz: c45016bd74d1e830ae18915be67be0f5a5e5dfc87581a9fe6685775b83c0aa08a4b8a10389d1ae9c92bfbffbf1b1b076b244c736c74002688f6be84e4115f02e
7
- data.tar.gz: ff7831e660833da76d85325532889590d27f60451747980427ce7e2d8f7f5e48ec02960d5fdad5bfb5ea7abadab9fdec19e6e30c5bb2adbc0be2e9527680ec3b
6
+ metadata.gz: 4071bc748f2855c39eb48e7360bf4d519f0502d898ca7e915c88c41115bb85422766a2e0274d9ab39ac032de69507dd2275b5fa976de26b8dc586846f3089814
7
+ data.tar.gz: 2962227ceb63eb324be8289502669995d4ac4d1136fd18570f972024b0774e0ff874c5c71d7fca8c296cd882850284415d8ce784312d1867d7471b3783ec79d3
data/CHANGELOG.md CHANGED
@@ -7,6 +7,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.0] - 2026-03-31
11
+
12
+ ### Added
13
+ - `Result#next_page` — automatically fetches the next page preserving original filter params
14
+ - `Result#has_next?` — convenience method to check if more pages are available
15
+ - Pagination migration guide added to README (EN/PT-BR) and REFERENCE.md
16
+ - Validation for `limit` (must be positive integer) and `offset` (must be non-negative integer) parameters
17
+ - `frozen_string_literal: true` pragma added to all Ruby source files
18
+ - ActiveSupport compatibility guard for `blank?`/`present?` monkey-patches
19
+ - `respond_to_missing?` implemented in `ConexaObject` and `Result` (Ruby best practice)
20
+ - Integration tests for all new API v2 resources (24 specs)
21
+ - Unit tests for pagination validation and `class_name` camelCase preservation (6 specs)
22
+ - Total: 502 specs
23
+
24
+ ### Changed
25
+ - **Breaking**: Default pagination is now `limit: 100, offset: 0` (was `page: 1, size: 100`)
26
+ - Calling `.all` or `.find_by` without pagination params now uses the new model
27
+ - Legacy `page`/`size` is only used when explicitly passed (emits deprecation warning)
28
+ - `Model.all` simplified — delegates directly to `find_by` without double param extraction
29
+ - `Model.class_name` now returns proper lowerCamelCase (e.g. `recurringSale` instead of `recurringsale`)
30
+ - `OrderCommom` renamed to `OrderCommon` (backwards-compatible alias kept)
31
+ - `Bill#save` now raises `NoMethodError` with descriptive message
32
+ - README updated: all examples now use correct method names (`.all`, `.find`, `.destroy`)
33
+ - README error handling section rewritten with actual exception classes
34
+
35
+ ### Fixed
36
+ - **Concurrency bug**: `DEFAULT_HEADERS` constant was mutated on every request; now uses `.dup`
37
+ - **Boolean false bug**: `Result#method_missing` skipped `false` attribute values due to `||` operator
38
+ - **ValidationError crash**: undefined variable `error` in block scope — fixed to use `msg`
39
+ - **TokenManager typo**: `ShiConexa` → `Conexa` in credentials handling
40
+ - **Singularize**: `SINGULARS` patterns were stored as strings, never used as regex — rewritten with proper `Regexp` objects
41
+ - **Deep copy**: `Result#next_page` now uses `Marshal.load(Marshal.dump(...))` to prevent param mutation between pages
42
+ - Stray `-` character removed from `util.rb`
43
+ - Removed dead code: `Hash#except_nested` monkey-patch, commented-out `to_s` method
44
+
10
45
  ## [0.0.9] - 2026-03-30
11
46
 
12
47
  ### Added
@@ -87,7 +122,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
87
122
  - Charge with settle and PIX methods
88
123
  - Pagination support
89
124
 
90
- [Unreleased]: https://github.com/guilhermegazzinelli/conexa-ruby/compare/v0.0.9...HEAD
125
+ [Unreleased]: https://github.com/guilhermegazzinelli/conexa-ruby/compare/v0.1.0...HEAD
126
+ [0.1.0]: https://github.com/guilhermegazzinelli/conexa-ruby/compare/v0.0.9...v0.1.0
91
127
  [0.0.9]: https://github.com/guilhermegazzinelli/conexa-ruby/compare/v0.0.8...v0.0.9
92
128
  [0.0.8]: https://github.com/guilhermegazzinelli/conexa-ruby/compare/v0.0.7...v0.0.8
93
129
  [0.0.7]: https://github.com/guilhermegazzinelli/conexa-ruby/compare/v0.0.6...v0.0.7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- conexa (0.0.9)
4
+ conexa (0.1.0)
5
5
  jwt
6
6
  multi_json
7
7
  rest-client
data/README.md CHANGED
@@ -46,13 +46,13 @@ Conexa.configure do |config|
46
46
  end
47
47
 
48
48
  # List customers
49
- customers = Conexa::Customer.list
49
+ customers = Conexa::Customer.all
50
50
  customers.data.each do |customer|
51
51
  puts "#{customer.customer_id}: #{customer.name}"
52
52
  end
53
53
 
54
54
  # Get a specific customer
55
- customer = Conexa::Customer.retrieve(127)
55
+ customer = Conexa::Customer.find(127)
56
56
  puts customer.name
57
57
  puts customer.address.city
58
58
  ```
@@ -110,7 +110,7 @@ customer = Conexa::Customer.create(
110
110
  )
111
111
 
112
112
  # Retrieve customer
113
- customer = Conexa::Customer.retrieve(127)
113
+ customer = Conexa::Customer.find(127)
114
114
  customer.name # => "Empresa ABC Ltda"
115
115
  customer.company_id # => 3
116
116
  customer.is_active # => true
@@ -118,10 +118,13 @@ customer.address.city # => "Campinas"
118
118
  customer.legal_person['cnpj'] # => "99.557.155/0001-90"
119
119
 
120
120
  # Update customer
121
- Conexa::Customer.update(127, name: 'New Name', cell_number: '11888887777')
121
+ customer = Conexa::Customer.find(127)
122
+ customer.name = 'New Name'
123
+ customer.cell_number = '11888887777'
124
+ customer.save
122
125
 
123
126
  # List customers with filters (new pagination)
124
- customers = Conexa::Customer.list(
127
+ customers = Conexa::Customer.all(
125
128
  company_id: [3],
126
129
  is_active: true,
127
130
  limit: 20
@@ -152,7 +155,7 @@ contract = Conexa::Contract.create_with_products(
152
155
  )
153
156
 
154
157
  # Retrieve contract
155
- contract = Conexa::Contract.retrieve(456)
158
+ contract = Conexa::Contract.find(456)
156
159
 
157
160
  # Cancel contract
158
161
  Conexa::Contract.cancel(456, cancel_date: '2024-12-31')
@@ -174,13 +177,13 @@ sale = Conexa::Sale.create(
174
177
  puts sale.id # => 188481
175
178
 
176
179
  # Retrieve sale
177
- sale = Conexa::Sale.retrieve(188510)
180
+ sale = Conexa::Sale.find(188510)
178
181
  sale.status # => "notBilled"
179
182
  sale.amount # => 80.99
180
183
  sale.discount_value # => 69.21
181
184
 
182
185
  # List sales
183
- sales = Conexa::Sale.list(
186
+ sales = Conexa::Sale.all(
184
187
  customer_id: [450, 216],
185
188
  status: 'notBilled',
186
189
  date_from: '2024-01-01',
@@ -190,10 +193,13 @@ sales = Conexa::Sale.list(
190
193
  )
191
194
 
192
195
  # Update sale
193
- Conexa::Sale.update(188510, quantity: 2, amount: 150.00)
196
+ sale = Conexa::Sale.find(188510)
197
+ sale.quantity = 2
198
+ sale.amount = 150.00
199
+ sale.save
194
200
 
195
201
  # Delete sale (only if not billed)
196
- Conexa::Sale.delete(188510)
202
+ Conexa::Sale.destroy(188510)
197
203
  ```
198
204
 
199
205
  ### Recurring Sale
@@ -208,20 +214,20 @@ recurring = Conexa::RecurringSale.create(
208
214
  )
209
215
 
210
216
  # List recurring sales for a contract
211
- Conexa::RecurringSale.list(contract_id: 456)
217
+ Conexa::RecurringSale.all(contract_id: 456)
212
218
  ```
213
219
 
214
220
  ### Charge
215
221
 
216
222
  ```ruby
217
223
  # Retrieve charge
218
- charge = Conexa::Charge.retrieve(789)
224
+ charge = Conexa::Charge.find(789)
219
225
  charge.status # => "paid"
220
226
  charge.amount # => 299.90
221
227
  charge.due_date # => "2024-02-10"
222
228
 
223
229
  # List charges
224
- charges = Conexa::Charge.list(
230
+ charges = Conexa::Charge.all(
225
231
  customer_id: [127],
226
232
  status: 'pending',
227
233
  due_date_from: '2024-01-01',
@@ -239,10 +245,10 @@ Conexa::Charge.send_email(789)
239
245
 
240
246
  ```ruby
241
247
  # Retrieve bill
242
- bill = Conexa::Bill.retrieve(101)
248
+ bill = Conexa::Bill.find(101)
243
249
 
244
250
  # List bills
245
- bills = Conexa::Bill.list(
251
+ bills = Conexa::Bill.all(
246
252
  customer_id: [127],
247
253
  page: 1,
248
254
  size: 50
@@ -253,10 +259,10 @@ bills = Conexa::Bill.list(
253
259
 
254
260
  ```ruby
255
261
  # List plans
256
- plans = Conexa::Plan.list(company_id: [3])
262
+ plans = Conexa::Plan.all(company_id: [3])
257
263
 
258
264
  # Retrieve plan
259
- plan = Conexa::Plan.retrieve(5)
265
+ plan = Conexa::Plan.find(5)
260
266
  plan.name # => "Plano Básico"
261
267
  plan.price # => 99.90
262
268
  ```
@@ -265,66 +271,66 @@ plan.price # => 99.90
265
271
 
266
272
  ```ruby
267
273
  # List products
268
- products = Conexa::Product.list(company_id: [3], limit: 50)
274
+ products = Conexa::Product.all(company_id: [3], limit: 50)
269
275
 
270
276
  # Retrieve product
271
- product = Conexa::Product.retrieve(101)
277
+ product = Conexa::Product.find(101)
272
278
 
273
279
  # Create product
274
280
  product = Conexa::Product.create(name: 'Novo Produto', company_id: 3)
275
281
 
276
282
  # Delete product
277
- Conexa::Product.delete(101)
283
+ Conexa::Product.destroy(101)
278
284
  ```
279
285
 
280
286
  ### Receiving Method
281
287
 
282
288
  ```ruby
283
- methods = Conexa::ReceivingMethod.list(limit: 50)
284
- method = Conexa::ReceivingMethod.retrieve(11)
289
+ methods = Conexa::ReceivingMethod.all(limit: 50)
290
+ method = Conexa::ReceivingMethod.find(11)
285
291
  method.name # => "Cartão de Crédito"
286
292
  ```
287
293
 
288
294
  ### Payment Method
289
295
 
290
296
  ```ruby
291
- methods = Conexa::PaymentMethod.list(limit: 50)
292
- method = Conexa::PaymentMethod.retrieve(2)
297
+ methods = Conexa::PaymentMethod.all(limit: 50)
298
+ method = Conexa::PaymentMethod.find(2)
293
299
  ```
294
300
 
295
301
  ### Bill Category / Subcategory
296
302
 
297
303
  ```ruby
298
- categories = Conexa::BillCategory.list(limit: 50)
299
- subcategories = Conexa::BillSubcategory.list(limit: 50)
304
+ categories = Conexa::BillCategory.all(limit: 50)
305
+ subcategories = Conexa::BillSubcategory.all(limit: 50)
300
306
  ```
301
307
 
302
308
  ### Cost Center
303
309
 
304
310
  ```ruby
305
- centers = Conexa::CostCenter.list(limit: 50)
306
- center = Conexa::CostCenter.retrieve(11)
311
+ centers = Conexa::CostCenter.all(limit: 50)
312
+ center = Conexa::CostCenter.find(11)
307
313
  ```
308
314
 
309
315
  ### Account
310
316
 
311
317
  ```ruby
312
- accounts = Conexa::Account.list(limit: 50)
313
- account = Conexa::Account.retrieve(23)
318
+ accounts = Conexa::Account.all(limit: 50)
319
+ account = Conexa::Account.find(23)
314
320
  ```
315
321
 
316
322
  ### Service Category
317
323
 
318
324
  ```ruby
319
- categories = Conexa::ServiceCategory.list(limit: 50)
320
- category = Conexa::ServiceCategory.retrieve(1)
325
+ categories = Conexa::ServiceCategory.all(limit: 50)
326
+ category = Conexa::ServiceCategory.find(1)
321
327
  ```
322
328
 
323
329
  ### Room Booking
324
330
 
325
331
  ```ruby
326
332
  # List bookings
327
- bookings = Conexa::RoomBooking.list(limit: 20)
333
+ bookings = Conexa::RoomBooking.all(limit: 20)
328
334
 
329
335
  # Create booking
330
336
  booking = Conexa::RoomBooking.create(room_id: 5, customer_id: 127)
@@ -350,20 +356,20 @@ card = Conexa::CreditCard.create(
350
356
  )
351
357
 
352
358
  # List customer's cards
353
- cards = Conexa::CreditCard.list(customer_id: 127)
359
+ cards = Conexa::CreditCard.all(customer_id: 127)
354
360
 
355
361
  # Delete card
356
- Conexa::CreditCard.delete(card_id)
362
+ Conexa::CreditCard.destroy(card_id)
357
363
  ```
358
364
 
359
365
  ### Company (Unit)
360
366
 
361
367
  ```ruby
362
368
  # List companies/units
363
- companies = Conexa::Company.list
369
+ companies = Conexa::Company.all
364
370
 
365
371
  # Retrieve company
366
- company = Conexa::Company.retrieve(3)
372
+ company = Conexa::Company.find(3)
367
373
  company.name # => "Matriz"
368
374
  company.document # => "12.345.678/0001-90"
369
375
  ```
@@ -373,19 +379,27 @@ company.document # => "12.345.678/0001-90"
373
379
  ### New Pagination (recommended) — `limit`/`offset`/`hasNext`
374
380
 
375
381
  ```ruby
376
- result = Conexa::Customer.list(limit: 50)
382
+ result = Conexa::Customer.all(limit: 50)
377
383
 
378
384
  result.data # Array of customers
379
385
  result.pagination.limit # => 50
380
386
  result.pagination.offset # => 0
381
- result.pagination.has_next # => true/false
387
+ result.has_next? # => true/false
382
388
 
383
- # Iterate through all pages
389
+ # Iterate through all pages using next_page
390
+ result = Conexa::Customer.all(limit: 50)
391
+ loop do
392
+ result.data.each { |customer| process(customer) }
393
+ break unless result.has_next?
394
+ result = result.next_page
395
+ end
396
+
397
+ # Or manually with offset
384
398
  offset = 0
385
399
  loop do
386
- result = Conexa::Customer.list(limit: 50, offset: offset)
400
+ result = Conexa::Customer.all(limit: 50, offset: offset)
387
401
  result.data.each { |customer| process(customer) }
388
- break unless result.pagination.has_next
402
+ break unless result.has_next?
389
403
  offset += 50
390
404
  end
391
405
  ```
@@ -394,7 +408,7 @@ end
394
408
 
395
409
  ```ruby
396
410
  # Still works but emits a deprecation warning
397
- result = Conexa::Customer.list(page: 1, size: 20)
411
+ result = Conexa::Customer.all(page: 1, size: 20)
398
412
  result.pagination.current_page # => 1
399
413
  result.pagination.total_pages # => 10
400
414
  ```
@@ -407,12 +421,12 @@ The legacy `page`/`size` pagination is deprecated and will be removed on **2026-
407
421
 
408
422
  ```ruby
409
423
  # BEFORE (legacy — deprecated)
410
- result = Conexa::Customer.list(page: 1, size: 50)
411
- result = Conexa::Customer.list(page: 2, size: 50)
424
+ result = Conexa::Customer.all(page: 1, size: 50)
425
+ result = Conexa::Customer.all(page: 2, size: 50)
412
426
 
413
427
  # AFTER (new)
414
- result = Conexa::Customer.list(limit: 50) # offset defaults to 0
415
- result = Conexa::Customer.list(limit: 50, offset: 50) # second page
428
+ result = Conexa::Customer.all(limit: 50) # offset defaults to 0
429
+ result = Conexa::Customer.all(limit: 50, offset: 50) # second page
416
430
  ```
417
431
 
418
432
  **Conversion formula:** `offset = (page - 1) * size`
@@ -436,19 +450,18 @@ result.pagination.has_next # => true/false
436
450
  # BEFORE (legacy)
437
451
  page = 1
438
452
  loop do
439
- result = Conexa::Customer.list(page: page, size: 100)
453
+ result = Conexa::Customer.all(page: page, size: 100)
440
454
  break if result.empty?
441
455
  result.data.each { |c| process(c) }
442
456
  page += 1
443
457
  end
444
458
 
445
- # AFTER (new)
446
- offset = 0
459
+ # AFTER (new — using next_page)
460
+ result = Conexa::Customer.all(limit: 100)
447
461
  loop do
448
- result = Conexa::Customer.list(limit: 100, offset: offset)
449
462
  result.data.each { |c| process(c) }
450
- break unless result.pagination.has_next
451
- offset += 100
463
+ break unless result.has_next?
464
+ result = result.next_page
452
465
  end
453
466
  ```
454
467
 
@@ -481,29 +494,22 @@ begin
481
494
  customer = Conexa::Customer.create(name: '')
482
495
  rescue Conexa::ValidationError => e
483
496
  # Field validation errors (400)
484
- e.errors.each do |error|
485
- puts "#{error['field']}: #{error['messages'].join(', ')}"
486
- end
487
- rescue Conexa::AuthenticationError => e
488
- # Authentication required (401)
489
497
  puts e.message
490
- rescue Conexa::AuthorizationError => e
491
- # Not authorized (403)
492
- puts e.message
493
- rescue Conexa::NotFoundError => e
498
+ rescue Conexa::NotFound => e
494
499
  # Resource not found (404)
495
500
  puts e.message
496
- rescue Conexa::UnprocessableError => e
497
- # Business logic error (422)
498
- e.errors.each do |error|
499
- puts "#{error['code']}: #{error['message']}"
500
- end
501
- rescue Conexa::RateLimitError => e
502
- # Too many requests (429)
503
- puts "Rate limit exceeded. Retry after #{e.retry_after} seconds"
504
- rescue Conexa::ApiError => e
505
- # Generic API error
506
- puts "Error #{e.status}: #{e.message}"
501
+ rescue Conexa::ResponseError => e
502
+ # API response error (4xx/5xx)
503
+ puts e.message
504
+ rescue Conexa::RequestError => e
505
+ # Request-level error (invalid params, etc.)
506
+ puts e.message
507
+ rescue Conexa::ConnectionError => e
508
+ # Network/connection error
509
+ puts e.message
510
+ rescue Conexa::ConexaError => e
511
+ # Generic Conexa error (catch-all)
512
+ puts e.message
507
513
  end
508
514
  ```
509
515
 
data/README_pt-BR.md CHANGED
@@ -73,25 +73,27 @@ Cada recurso segue um conjunto consistente de padrões de métodos:
73
73
 
74
74
  ### Paginação
75
75
 
76
- A API utiliza os parâmetros `page` e `size` para paginação com os seguintes valores padrão:
77
-
78
- - **page**: Número da página atual (padrão: `1`)
79
- - **size**: Quantidade de itens por página (padrão: `100`)
76
+ A gem utiliza por padrão `limit: 100, offset: 0` (nova paginação). O modelo legado `page`/`size` ainda funciona mas emite um aviso de depreciação.
80
77
 
81
78
  #### Chamando com Paginação
82
79
 
83
80
  ```ruby
84
- # Paginação padrão (página 1, 100 itens)
81
+ # Paginação padrão (limit: 100, offset: 0)
85
82
  Conexa::Customer.all
86
83
 
87
- # Argumentos posicionais (página, tamanho)
88
- Conexa::Customer.all(2, 50) # página 2, 50 itens por página
84
+ # Com limite customizado
85
+ Conexa::Customer.all(limit: 50)
89
86
 
90
- # Parâmetros nomeados
91
- Conexa::Customer.all(page: 3, size: 25)
87
+ # Com offset
88
+ Conexa::Customer.all(limit: 50, offset: 100)
92
89
 
93
- # Usando o alias `where`
94
- Conexa::Customer.where(page: 2, size: 10)
90
+ # Iteração automática com next_page
91
+ resultado = Conexa::Customer.all(limit: 50)
92
+ loop do
93
+ resultado.data.each { |cliente| processa(cliente) }
94
+ break unless resultado.has_next?
95
+ resultado = resultado.next_page
96
+ end
95
97
  ```
96
98
 
97
99
  ### Objeto Result
@@ -309,14 +311,22 @@ resultado = Conexa::Customer.all(limit: 50)
309
311
  resultado.data # Array de clientes
310
312
  resultado.pagination.limit # => 50
311
313
  resultado.pagination.offset # => 0
312
- resultado.pagination.has_next # => true/false
314
+ resultado.has_next? # => true/false
315
+
316
+ # Iterar por todas as páginas usando next_page
317
+ resultado = Conexa::Customer.all(limit: 50)
318
+ loop do
319
+ resultado.data.each { |cliente| processa(cliente) }
320
+ break unless resultado.has_next?
321
+ resultado = resultado.next_page
322
+ end
313
323
 
314
- # Iterar por todas as páginas
324
+ # Ou manualmente com offset
315
325
  offset = 0
316
326
  loop do
317
327
  resultado = Conexa::Customer.all(limit: 50, offset: offset)
318
328
  resultado.data.each { |cliente| processa(cliente) }
319
- break unless resultado.pagination.has_next
329
+ break unless resultado.has_next?
320
330
  offset += 50
321
331
  end
322
332
  ```
@@ -364,13 +374,12 @@ loop do
364
374
  pagina += 1
365
375
  end
366
376
 
367
- # DEPOIS (novo)
368
- offset = 0
377
+ # DEPOIS (novo — usando next_page)
378
+ resultado = Conexa::Customer.all(limit: 100)
369
379
  loop do
370
- resultado = Conexa::Customer.all(limit: 100, offset: offset)
371
380
  resultado.data.each { |c| processa(c) }
372
- break unless resultado.pagination.has_next
373
- offset += 100
381
+ break unless resultado.has_next?
382
+ resultado = resultado.next_page
374
383
  end
375
384
  ```
376
385
 
data/REFERENCE.md CHANGED
@@ -32,7 +32,7 @@ Conexa is a Brazilian SaaS platform for **recurring billing**, **subscription ma
32
32
 
33
33
  ```ruby
34
34
  # Gemfile
35
- gem 'conexa', '~> 0.0.9'
35
+ gem 'conexa', '~> 0.1.0'
36
36
 
37
37
  # Or install directly
38
38
  gem install conexa
@@ -1034,7 +1034,7 @@ person.destroy
1034
1034
 
1035
1035
  #### New Pagination (recommended) — `limit`/`offset`/`hasNext`
1036
1036
 
1037
- All `#all` and `#find_by` methods support the new pagination when `limit:` is passed:
1037
+ All `#all` and `#find_by` methods use `limit`/`offset` by default. When no pagination params are passed, the gem defaults to `limit: 100, offset: 0`.
1038
1038
 
1039
1039
  ```ruby
1040
1040
  # Page 1, 50 items
@@ -1043,24 +1043,35 @@ result = Conexa::Customer.all(limit: 50)
1043
1043
  result.data # => Array of customers
1044
1044
  result.pagination.limit # => 50
1045
1045
  result.pagination.offset # => 0
1046
- result.pagination.has_next # => true/false
1046
+ result.has_next? # => true/false
1047
1047
  result.empty? # => false
1048
1048
 
1049
- # Iterate all pages
1049
+ # Iterate all pages using next_page
1050
+ result = Conexa::Customer.all(limit: 100)
1051
+ loop do
1052
+ result.each { |customer| process(customer) }
1053
+ break unless result.has_next?
1054
+ result = result.next_page
1055
+ end
1056
+
1057
+ # Or manually with offset
1050
1058
  offset = 0
1051
1059
  loop do
1052
1060
  result = Conexa::Customer.all(limit: 100, offset: offset)
1053
1061
  break if result.empty?
1054
-
1055
1062
  result.each { |customer| process(customer) }
1056
- break unless result.pagination.has_next
1063
+ break unless result.has_next?
1057
1064
  offset += 100
1058
1065
  end
1059
1066
  ```
1060
1067
 
1068
+ **`next_page`** — Fetches the next page automatically, preserving all original filter params. Raises `StopIteration` when there are no more pages.
1069
+
1070
+ **`has_next?`** — Returns `true` if more pages are available.
1071
+
1061
1072
  #### Legacy Pagination (deprecated — removed 2026-08-01)
1062
1073
 
1063
- If `limit:` is NOT passed, the gem falls back to the old `page`/`size` model
1074
+ If `page:` or `size:` is explicitly passed, the gem uses the old pagination model
1064
1075
  (emitting a deprecation warning):
1065
1076
 
1066
1077
  ```ruby
@@ -1115,13 +1126,12 @@ loop do
1115
1126
  page += 1
1116
1127
  end
1117
1128
 
1118
- # AFTER
1119
- offset = 0
1129
+ # AFTER (using next_page)
1130
+ result = Conexa::Customer.all(limit: 100)
1120
1131
  loop do
1121
- result = Conexa::Customer.all(limit: 100, offset: offset)
1122
1132
  result.each { |c| process(c) }
1123
- break unless result.pagination.has_next
1124
- offset += 100
1133
+ break unless result.has_next?
1134
+ result = result.next_page
1125
1135
  end
1126
1136
  ```
1127
1137
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'jwt'
2
4
 
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  class Configuration
3
5
  attr_accessor :api_token, :api_host
@@ -1,9 +1,14 @@
1
- class Object
2
- def blank?
3
- respond_to?(:empty?) ? !!empty? : !self
4
- end
1
+ # frozen_string_literal: true
2
+
3
+ # Only define blank?/present? if not already provided (e.g., by ActiveSupport)
4
+ unless Object.method_defined?(:blank?)
5
+ class Object
6
+ def blank?
7
+ respond_to?(:empty?) ? !!empty? : !self
8
+ end
5
9
 
6
- def present?
7
- !blank?
10
+ def present?
11
+ !blank?
12
+ end
8
13
  end
9
14
  end
data/lib/conexa/errors.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  class ConexaError < StandardError
3
5
  end
@@ -38,11 +40,11 @@ module Conexa
38
40
 
39
41
  def initialize(response)
40
42
  @response = response
41
- @errors = response['message']&.map do |message|
42
- params = error.values_at('message', 'parameter_name', 'type', 'url')
43
+ @errors = response['message']&.map do |msg|
44
+ params = msg.values_at('message', 'parameter_name', 'type', 'url')
43
45
  ParamError.new(*params)
44
46
  end
45
- super @errors&.map(&:message).join(', ')
47
+ super @errors&.map(&:message)&.join(', ')
46
48
  end
47
49
 
48
50
  def to_h
data/lib/conexa/model.rb CHANGED
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  # Base class for all API resources (Customer, Charge, Contract, etc.)
3
5
  #
4
6
  # == Attribute Access
5
- #
7
+ #
6
8
  # Attributes are automatically accessible via method_missing:
7
9
  # customer.name # => "Empresa ABC"
8
10
  # customer.company_id # => 3
@@ -31,29 +33,11 @@ module Conexa
31
33
  # instead of "recurring_sale_id". Explicit declaration ensures correctness.
32
34
  #
33
35
  class Model < ConexaObject
34
- class << self
35
- # DSL for primary key attribute with :id alias
36
- # @example
37
- # primary_key_attribute :charge_id
38
- # # Generates: charge_id method + chargeId alias + id alias
39
- def primary_key_attribute(snake_name)
40
- camel_name = Util.camelize_str(snake_name.to_s)
41
-
42
- define_method(snake_name) do
43
- @attributes[snake_name.to_s]
44
- end
45
-
46
- alias_method camel_name.to_sym, snake_name
47
- alias_method :id, snake_name
48
- end
49
- end
50
-
51
36
  def create
52
37
  set_primary_key Conexa::Request.post(self.class.show_url, params: to_hash).call(class_name).attributes['id']
53
38
  fetch
54
39
  end
55
40
 
56
-
57
41
  def save
58
42
  update Conexa::Request.patch(self.class.show_url(primary_key), params: unsaved_attributes).call(class_name)
59
43
  self
@@ -86,11 +70,26 @@ module Conexa
86
70
 
87
71
  def destroy
88
72
  raise RequestError.new('Invalid ID') unless id.present?
89
- update Conexa::Request.delete( self.class.show_url(primary_key) ).call(class_name)
73
+ update Conexa::Request.delete(self.class.show_url(primary_key)).call(class_name)
90
74
  self
91
75
  end
92
76
 
93
77
  class << self
78
+ # DSL for primary key attribute with :id alias
79
+ # @example
80
+ # primary_key_attribute :charge_id
81
+ # # Generates: charge_id method + chargeId alias + id alias
82
+ def primary_key_attribute(snake_name)
83
+ camel_name = Util.camelize_str(snake_name.to_s)
84
+
85
+ define_method(snake_name) do
86
+ @attributes[snake_name.to_s]
87
+ end
88
+
89
+ alias_method camel_name.to_sym, snake_name
90
+ alias_method :id, snake_name
91
+ end
92
+
94
93
  def create(*args)
95
94
  self.new(*args).create
96
95
  end
@@ -101,18 +100,19 @@ module Conexa
101
100
  end
102
101
  alias :find :find_by_id
103
102
 
104
-
105
103
  def find_by(params = Hash.new, page = nil, size = nil)
106
104
  params = extract_page_size_or_params(page, size, **params)
107
105
  raise RequestError.new('Invalid page size') if (!params.key?(:limit)) && (params[:page] < 1 or params[:size] < 1)
108
106
 
109
- Conexa::Request.get(url, params: params).call underscored_class_name
107
+ Conexa::Request.get(url, params: params).call(
108
+ underscored_class_name,
109
+ query_context: { resource_class: self, params: params }
110
+ )
110
111
  end
111
112
  alias :find_by_hash :find_by
112
113
 
113
114
  def all(*args, **params)
114
- params = extract_page_size_or_params(*args, **params)
115
- find_by params
115
+ find_by(params, *args)
116
116
  end
117
117
  alias :where :all
118
118
 
@@ -131,7 +131,8 @@ module Conexa
131
131
  end
132
132
 
133
133
  def class_name
134
- self.name.split('::').last.downcase
134
+ name = self.name.split('::').last
135
+ name[0].downcase + name[1..]
135
136
  end
136
137
 
137
138
  def underscored_class_name
@@ -147,20 +148,35 @@ module Conexa
147
148
  end
148
149
  size_val = args[1]
149
150
 
151
+ # Explicit new pagination (limit/offset)
150
152
  if params.key?(:limit)
153
+ unless params[:limit].is_a?(Integer) && params[:limit].positive?
154
+ raise RequestError, "limit must be a positive integer"
155
+ end
156
+
151
157
  params[:offset] ||= size_val if size_val.is_a?(Integer)
152
158
  params[:offset] ||= 0
153
- params.delete(:page) # Fix to ensure the api doesn't get confused
159
+
160
+ unless params[:offset].is_a?(Integer) && params[:offset] >= 0
161
+ raise RequestError, "offset must be a non-negative integer"
162
+ end
163
+
164
+ params.delete(:page)
154
165
  params.delete(:size)
155
166
  return params
156
167
  end
157
168
 
169
+ # Explicit legacy pagination (page/size) — deprecated
158
170
  if params.key?(:page) || params.key?(:size) || page_val.is_a?(Integer)
159
171
  warn "DEPRECATION WARNING: O modelo antigo de paginação (page/size) será removido em 01 de agosto de 2026. Utilize limit e offset."
172
+ params[:page] ||= page_val || 1
173
+ params[:size] ||= size_val || 100
174
+ return params
160
175
  end
161
176
 
162
- params[:page] ||= page_val || 1
163
- params[:size] ||= size_val || 100
177
+ # Default: new pagination
178
+ params[:limit] = 100
179
+ params[:offset] = 0
164
180
  params
165
181
  end
166
182
  end
data/lib/conexa/object.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  # Base class for all Conexa objects with dynamic attribute access
3
5
  #
@@ -24,8 +26,6 @@ module Conexa
24
26
  end
25
27
 
26
28
  def initialize(response = {})
27
- # raise MissingCredentialsError.new("Missing :client_key for extra options #{options}") if options && !options[:client_key]
28
-
29
29
  @attributes = Hash.new
30
30
  @unsaved_attributes = Set.new
31
31
 
@@ -57,21 +57,13 @@ module Conexa
57
57
  end]
58
58
  end
59
59
 
60
- def respond_to?(name, include_all = false)
61
- return true if name.to_s.end_with? '='
60
+ def respond_to_missing?(name, include_private = false)
61
+ name_str = Util.to_snake_case(name.to_s)
62
+ return true if name_str.end_with?('=')
62
63
 
63
- @attributes.has_key?(name.to_s) || super
64
+ @attributes.key?(name_str) || @attributes.key?(name_str.to_sym) || super
64
65
  end
65
66
 
66
- # def to_s
67
- # attributes_str = ''
68
- # (attributes.keys - ['id', 'object']).sort.each do |key|
69
- # attributes_str += " \033[1;33m#{key}:\033[0m#{self[key].inspect}" unless self[key].nil?
70
- # end
71
- # "\033[1;31m#<#{self.class.name}:\033[0;32m#{id}#{attributes_str}\033[0m\033[0m\033[1;31m>\033[0;32m"
72
- # end
73
- # # alias :inspect :to_s
74
-
75
67
  protected
76
68
  def update(attributes)
77
69
  removed_attributes = @attributes.keys - attributes.to_hash.keys
@@ -127,7 +119,6 @@ module Conexa
127
119
  super name, *args, &block
128
120
  end
129
121
 
130
-
131
122
  class << self
132
123
  def convert(response, resource_name = nil, client_key=nil)
133
124
  case response
@@ -154,7 +145,6 @@ module Conexa
154
145
 
155
146
  def capitalize_name(name)
156
147
  name.split('_').collect(&:capitalize).join
157
- # name.gsub(/(\A\w|\_\w)/){ |str| str.gsub('_', '').upcase }
158
148
  end
159
149
  end
160
150
  end
@@ -1,9 +1,9 @@
1
- module Conexa
2
- class OrderCommom < Model
1
+ # frozen_string_literal: true
3
2
 
4
- # def self.url(*params)
5
- # ["/#{ CGI.escape underscored_class_name }", *params].join '/'
6
- # end
3
+ module Conexa
4
+ class OrderCommon < Model
5
+ # Keep old name as alias for backwards compatibility
6
+ OrderCommom = self
7
7
 
8
8
  #
9
9
  # Request refund to Conexa api for this order
@@ -1,9 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
  require 'rest_client'
3
5
  require 'multi_json'
4
6
 
5
-
6
-
7
7
  module Conexa
8
8
  class Request
9
9
  DEFAULT_HEADERS = {
@@ -29,7 +29,6 @@ module Conexa
29
29
  response = MultiJson.decode response.body
30
30
  return {data: response.dig("data") || response, pagination: response.dig("pagination")}
31
31
 
32
-
33
32
  rescue RestClient::Exception => error
34
33
  begin
35
34
  parsed_error = MultiJson.decode error.http_body
@@ -60,16 +59,18 @@ module Conexa
60
59
  raise Conexa::ConnectionError.new $!
61
60
  end
62
61
 
63
- def call(ressource_name)
62
+ def call(resource_name, query_context: nil)
64
63
  dt = run
65
64
 
66
65
  if dt[:pagination]
67
- return ConexaObject.convert({
68
- data: ConexaObject.convert(dt[:data], ressource_name),
66
+ result = ConexaObject.convert({
67
+ data: ConexaObject.convert(dt[:data], resource_name),
69
68
  pagination: ConexaObject.convert(dt[:pagination], "pagination")}, "result")
69
+ result.instance_variable_set(:@query_context, query_context) if query_context
70
+ return result
70
71
  end
71
72
 
72
- ConexaObject.convert(dt[:data], ressource_name)
73
+ ConexaObject.convert(dt[:data], resource_name)
73
74
  end
74
75
 
75
76
  def self.get(url, options={})
@@ -105,7 +106,7 @@ module Conexa
105
106
  @parameters = Util.camelize_hash(@parameters)
106
107
  aux.merge!({ payload: MultiJson.encode(@parameters)}) unless %w(GET DELETE).include? method
107
108
 
108
- extra_headers = DEFAULT_HEADERS
109
+ extra_headers = DEFAULT_HEADERS.dup
109
110
  extra_headers[:authorization] = "Bearer #{Conexa.configuration.api_token}" unless @auth
110
111
  extra_headers[:params] = @parameters if method == "GET"
111
112
  aux.merge!({ headers: extra_headers })
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  class Bill < Model
3
5
  def save
4
- raise NoMethodError
6
+ raise NoMethodError, "Bill does not support save"
5
7
  end
6
8
  end
7
9
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  class Company < Model
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  class CreditCard < Model
3
5
  primary_key_attribute :credit_card_id
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  class InvoicingMethod < Model
3
5
  primary_key_attribute :invoicing_method_id
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  class LegalPerson < ConexaObject
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  class Pagination < ConexaObject
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  class Person < Model
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  class Plan < Model
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  # Product resource (read-only for listing/retrieving)
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  class RecurringSale < Model
3
5
  primary_key_attribute :recurring_sale_id
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  class Result < ConexaObject
3
5
 
@@ -16,10 +18,31 @@ module Conexa
16
18
  @attributes["pagination"]
17
19
  end
18
20
 
19
- def respond_to?(name, include_all = false)
20
- return true if name.to_s.end_with? '='
21
+ def has_next?
22
+ pagination && pagination.has_next == true
23
+ end
24
+
25
+ def next_page
26
+ raise StopIteration, "No more pages" unless has_next?
27
+ raise "No query context available for next_page" unless @query_context
28
+
29
+ resource_class = @query_context[:resource_class]
30
+ next_params = Marshal.load(Marshal.dump(@query_context[:params]))
31
+
32
+ next_params[:limit] = pagination.limit
33
+ next_params[:offset] = pagination.offset + pagination.limit
34
+ next_params.delete(:page)
35
+ next_params.delete(:size)
21
36
 
22
- @attributes.has_key?(name.to_s) || super
37
+ resource_class.find_by(next_params)
38
+ end
39
+
40
+ def respond_to_missing?(name, include_private = false)
41
+ name_str = Util.to_snake_case(name.to_s)
42
+ return true if name_str.end_with?('=')
43
+ return true if @attributes["data"]&.respond_to?(name_str)
44
+
45
+ @attributes.key?(name_str) || @attributes.key?(name_str.to_sym) || super
23
46
  end
24
47
 
25
48
  def method_missing(name, *args, &block)
@@ -30,14 +53,18 @@ module Conexa
30
53
  end
31
54
 
32
55
  unless block_given?
33
-
34
56
  if name.end_with?('=') && args.size == 1
35
57
  attribute_name = name[0...-1]
36
58
  return self[attribute_name] = args[0]
37
59
  end
38
60
 
39
61
  if args.size == 0
40
- return self[name] || self[name.to_sym]
62
+ if @attributes.key?(name)
63
+ return @attributes[name]
64
+ elsif @attributes.key?(name.to_sym)
65
+ return @attributes[name.to_sym]
66
+ end
67
+ return nil
41
68
  end
42
69
  end
43
70
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
 
3
5
  #
@@ -19,7 +21,7 @@ module Conexa
19
21
  when Array
20
22
  tokens = Conexa.credentials
21
23
  when Hash
22
- tokens = [ShiConexa.credentials]
24
+ tokens = [Conexa.credentials]
23
25
  end
24
26
  else
25
27
  tokens = [{
data/lib/conexa/util.rb CHANGED
@@ -1,44 +1,46 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Conexa
2
4
  class Util
3
5
  class << self
4
6
 
5
- SINGULARS = {
6
- '/s$/i' => "",
7
- '/(ss)$/i' => '\1',
8
- '/(n)ews$/i' => '\1ews',
9
- '/([ti])a$/i' => '\1um',
10
- '/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i' => '\1sis',
11
- '/(^analy)(sis|ses)$/i' => '\1sis',
12
- '/([^f])ves$/i' => '\1fe',
13
- '/(hive)s$/i' => '\1',
14
- '/(tive)s$/i' => '\1',
15
- '/([lr])ves$/i' => '\1f',
16
- '/([^aeiouy]|qu)ies$/i' => '\1y',
17
- '/(s)eries$/i' => '\1eries',
18
- '/(m)ovies$/i' => '\1ovie',
19
- '/(x|ch|ss|sh)es$/i' => '\1',
20
- '/^(m|l)ice$/i' => '\1ouse',-
21
- '/(bus)(es)?$/i' => '\1',
22
- '/(o)es$/i' => '\1',
23
- '/(shoe)s$/i' => '\1',
24
- '/(cris|test)(is|es)$/i' => '\1is',
25
- '/^(a)x[ie]s$/i' => '\1xis',
26
- '/(octop|vir)(us|i)$/i' => '\1us',
27
- '/(alias|status)(es)?$/i' => '\1',
28
- '/^(ox)en/i' => '\1',
29
- '/(vert|ind)ices$/i' => '\1ex',
30
- '/(matr)ices$/i' => '\1ix',
31
- '/(quiz)zes$/i' => '\1',
32
- '/(database)s$/i' => '\1'}
7
+ SINGULARS = [
8
+ [/(ss)$/i, '\1'],
9
+ [/(n)ews$/i, '\1ews'],
10
+ [/([ti])a$/i, '\1um'],
11
+ [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis'],
12
+ [/(^analy)(sis|ses)$/i, '\1sis'],
13
+ [/([^f])ves$/i, '\1fe'],
14
+ [/(hive)s$/i, '\1'],
15
+ [/(tive)s$/i, '\1'],
16
+ [/([lr])ves$/i, '\1f'],
17
+ [/([^aeiouy]|qu)ies$/i, '\1y'],
18
+ [/(s)eries$/i, '\1eries'],
19
+ [/(m)ovies$/i, '\1ovie'],
20
+ [/(x|ch|ss|sh)es$/i, '\1'],
21
+ [/^(m|l)ice$/i, '\1ouse'],
22
+ [/(bus)(es)?$/i, '\1'],
23
+ [/(o)es$/i, '\1'],
24
+ [/(shoe)s$/i, '\1'],
25
+ [/(cris|test)(is|es)$/i, '\1is'],
26
+ [/^(a)x[ie]s$/i, '\1xis'],
27
+ [/(octop|vir)(us|i)$/i, '\1us'],
28
+ [/(alias|status)(es)?$/i, '\1'],
29
+ [/^(ox)en/i, '\1'],
30
+ [/(vert|ind)ices$/i, '\1ex'],
31
+ [/(matr)ices$/i, '\1ix'],
32
+ [/(quiz)zes$/i, '\1'],
33
+ [/(database)s$/i, '\1'],
34
+ [/s$/i, '']
35
+ ].freeze
33
36
 
34
- def singularize resource
35
- out = ''
36
- SINGULARS.keys.each do |key|
37
- out = resource.to_s.gsub(/s$/,SINGULARS[key])
38
- break out if out != resource
37
+ def singularize(resource)
38
+ str = resource.to_s
39
+ SINGULARS.each do |pattern, replacement|
40
+ result = str.sub(pattern, replacement)
41
+ return resource.is_a?(Symbol) ? result.to_sym : result if result != str
39
42
  end
40
-
41
- resource.is_a?(Symbol) ? out.to_sym : out
43
+ resource
42
44
  end
43
45
 
44
46
  def to_sym string
@@ -77,18 +79,3 @@ module Conexa
77
79
  end
78
80
  end
79
81
  end
80
-
81
- class Hash
82
- def except_nested(key)
83
- r = Marshal.load(Marshal.dump(self))
84
- r.except_nested!(key)
85
- end
86
-
87
- def except_nested!(key)
88
- self.reject!{|k, _| k == key || k.to_s == key }
89
- self.each do |_, v|
90
- v.except_nested!(key) if v.is_a?(Hash)
91
- v.map!{|obj| obj.except_nested!(key) if obj.is_a?(Hash)} if v.is_a?(Array)
92
- end
93
- end
94
- end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Conexa
4
- VERSION = "0.0.9"
4
+ VERSION = "0.1.0"
5
5
  end
data/lib/conexa.rb CHANGED
@@ -9,7 +9,7 @@ require_relative "conexa/core_ext"
9
9
  require_relative "conexa/errors"
10
10
  require_relative "conexa/util"
11
11
  require_relative "conexa/configuration"
12
- require_relative "conexa/order_commom"
12
+ require_relative "conexa/order_common"
13
13
  require_relative "conexa/token_manager"
14
14
 
15
15
 
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.0.9
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guilherme Gazzinelli
@@ -153,7 +153,7 @@ files:
153
153
  - lib/conexa/generators/install_generator.rb
154
154
  - lib/conexa/model.rb
155
155
  - lib/conexa/object.rb
156
- - lib/conexa/order_commom.rb
156
+ - lib/conexa/order_common.rb
157
157
  - lib/conexa/request.rb
158
158
  - lib/conexa/resources/account.rb
159
159
  - lib/conexa/resources/address.rb