conexa 0.0.8 → 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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +64 -1
  3. data/Gemfile.lock +1 -1
  4. data/README.md +211 -56
  5. data/README_pt-BR.md +116 -12
  6. data/REFERENCE.md +138 -14
  7. data/lib/conexa/authenticator.rb +2 -0
  8. data/lib/conexa/configuration.rb +2 -0
  9. data/lib/conexa/core_ext.rb +11 -6
  10. data/lib/conexa/errors.rb +5 -3
  11. data/lib/conexa/model.rb +64 -28
  12. data/lib/conexa/object.rb +12 -17
  13. data/lib/conexa/{order_commom.rb → order_common.rb} +5 -5
  14. data/lib/conexa/request.rb +9 -8
  15. data/lib/conexa/resources/account.rb +33 -0
  16. data/lib/conexa/resources/bill.rb +3 -1
  17. data/lib/conexa/resources/bill_category.rb +33 -0
  18. data/lib/conexa/resources/bill_subcategory.rb +35 -0
  19. data/lib/conexa/resources/charge.rb +1 -1
  20. data/lib/conexa/resources/company.rb +2 -0
  21. data/lib/conexa/resources/cost_center.rb +33 -0
  22. data/lib/conexa/resources/credit_card.rb +2 -0
  23. data/lib/conexa/resources/customer.rb +3 -3
  24. data/lib/conexa/resources/invoicing_method.rb +2 -0
  25. data/lib/conexa/resources/legal_person.rb +2 -0
  26. data/lib/conexa/resources/pagination.rb +2 -0
  27. data/lib/conexa/resources/payment_method.rb +33 -0
  28. data/lib/conexa/resources/person.rb +2 -0
  29. data/lib/conexa/resources/plan.rb +2 -0
  30. data/lib/conexa/resources/product.rb +28 -4
  31. data/lib/conexa/resources/receiving_method.rb +55 -0
  32. data/lib/conexa/resources/recurring_sale.rb +2 -0
  33. data/lib/conexa/resources/result.rb +32 -5
  34. data/lib/conexa/resources/room_booking.rb +87 -0
  35. data/lib/conexa/resources/sale.rb +1 -1
  36. data/lib/conexa/resources/service_category.rb +33 -0
  37. data/lib/conexa/resources/supplier.rb +24 -1
  38. data/lib/conexa/token_manager.rb +3 -1
  39. data/lib/conexa/util.rb +37 -50
  40. data/lib/conexa/version.rb +1 -1
  41. data/lib/conexa.rb +1 -1
  42. metadata +10 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '050626980d9f896ca2c70ed30a27c1cfda7d0d30c89e25c90e86422d122fb1af'
4
- data.tar.gz: 43134221ca4dd8f38bc3f8a62bfffe2807d1565e949e2adf72d446fa14db01cf
3
+ metadata.gz: 76a95e870fc63f79b15b5227f1f0a10d94471efe573662dc626e42e57cf77b82
4
+ data.tar.gz: 92fce7222c5b9adad92e6524e6dbfb3466bc1282a81768c5872922af37d2085b
5
5
  SHA512:
6
- metadata.gz: 298ef626afb7783dff6d66161e20ff4b28b30b0d81761ce3f5debf187f1d60e0d01814004d3372ad6531b5e40e22e110af471522bbc577e3c0baac63dfb17014
7
- data.tar.gz: 768fbc470c103074ff5b768bf78ba6ed47385c4d06a7cadba7aed395947da92c73756c8f72c06e66be15520974c7f0c2e8438dfc567181cc83357416cad251d5
6
+ metadata.gz: 4071bc748f2855c39eb48e7360bf4d519f0502d898ca7e915c88c41115bb85422766a2e0274d9ab39ac032de69507dd2275b5fa976de26b8dc586846f3089814
7
+ data.tar.gz: 2962227ceb63eb324be8289502669995d4ac4d1136fd18570f972024b0774e0ff874c5c71d7fca8c296cd882850284415d8ce784312d1867d7471b3783ec79d3
data/CHANGELOG.md CHANGED
@@ -7,6 +7,67 @@ 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
+
45
+ ## [0.0.9] - 2026-03-30
46
+
47
+ ### Added
48
+ - **New pagination model**: `limit`/`offset`/`hasNext` — more efficient, avoids calculating total records
49
+ - Pass `limit:` to any `.all` or `.find_by` to use the new pagination
50
+ - Old `page`/`size` pagination emits deprecation warning (deadline: 2026-08-01)
51
+ - **New resources:**
52
+ - `Conexa::ReceivingMethod` — Meios de Recebimento (`/receivingMethods`, `/receivingMethod/:id`)
53
+ - `Conexa::PaymentMethod` — Meios de Pagamento (`/paymentMethods`, `/paymentMethod/:id`)
54
+ - `Conexa::BillCategory` — Categorias de Despesa (`/billCategories`, `/billCategory/:id`)
55
+ - `Conexa::BillSubcategory` — Subcategorias de Despesa (`/billSubcategories`, `/billSubcategory/:id`)
56
+ - `Conexa::CostCenter` — Centros de Custo (`/costCenters`, `/costCenter/:id`)
57
+ - `Conexa::Account` — Contas Bancárias (`/accounts`, `/account/:id`)
58
+ - `Conexa::ServiceCategory` — Categorias de Serviço (`/serviceCategories`, `/serviceCategory/:id`)
59
+ - `Conexa::RoomBooking` — Reservas de Sala (`/room/bookings`, `/room/booking`) with cancel, checkout, checkin
60
+ - `Product` now supports full CRUD (POST `/product`, DELETE `/product/:id`) per API v2 update
61
+
62
+ ### Changed
63
+ - `Model#extract_page_size_or_params` rewritten to support dual pagination modes
64
+ - `Customer.persons`, `Customer.contracts`, `Customer.charges` migrated to `limit: 100`
65
+
66
+ ### Fixed
67
+ - `Supplier` list URL corrected from `/supplier` to `/suppliers`
68
+ - `Supplier` now has `primary_key_attribute :supplier_id`
69
+ - `Product` now has `primary_key_attribute :product_id`
70
+
10
71
  ## [0.0.8] - 2026-02-19
11
72
 
12
73
  ### Fixed
@@ -61,7 +122,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
61
122
  - Charge with settle and PIX methods
62
123
  - Pagination support
63
124
 
64
- [Unreleased]: https://github.com/guilhermegazzinelli/conexa-ruby/compare/v0.0.8...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
127
+ [0.0.9]: https://github.com/guilhermegazzinelli/conexa-ruby/compare/v0.0.8...v0.0.9
65
128
  [0.0.8]: https://github.com/guilhermegazzinelli/conexa-ruby/compare/v0.0.7...v0.0.8
66
129
  [0.0.7]: https://github.com/guilhermegazzinelli/conexa-ruby/compare/v0.0.6...v0.0.7
67
130
  [0.0.6]: https://github.com/guilhermegazzinelli/conexa-ruby/compare/v0.0.5...v0.0.6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- conexa (0.0.8)
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,14 +118,16 @@ 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
- # List customers with filters
124
- customers = Conexa::Customer.list(
126
+ # List customers with filters (new pagination)
127
+ customers = Conexa::Customer.all(
125
128
  company_id: [3],
126
129
  is_active: true,
127
- page: 1,
128
- size: 20
130
+ limit: 20
129
131
  )
130
132
  ```
131
133
 
@@ -153,7 +155,7 @@ contract = Conexa::Contract.create_with_products(
153
155
  )
154
156
 
155
157
  # Retrieve contract
156
- contract = Conexa::Contract.retrieve(456)
158
+ contract = Conexa::Contract.find(456)
157
159
 
158
160
  # Cancel contract
159
161
  Conexa::Contract.cancel(456, cancel_date: '2024-12-31')
@@ -175,13 +177,13 @@ sale = Conexa::Sale.create(
175
177
  puts sale.id # => 188481
176
178
 
177
179
  # Retrieve sale
178
- sale = Conexa::Sale.retrieve(188510)
180
+ sale = Conexa::Sale.find(188510)
179
181
  sale.status # => "notBilled"
180
182
  sale.amount # => 80.99
181
183
  sale.discount_value # => 69.21
182
184
 
183
185
  # List sales
184
- sales = Conexa::Sale.list(
186
+ sales = Conexa::Sale.all(
185
187
  customer_id: [450, 216],
186
188
  status: 'notBilled',
187
189
  date_from: '2024-01-01',
@@ -191,10 +193,13 @@ sales = Conexa::Sale.list(
191
193
  )
192
194
 
193
195
  # Update sale
194
- 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
195
200
 
196
201
  # Delete sale (only if not billed)
197
- Conexa::Sale.delete(188510)
202
+ Conexa::Sale.destroy(188510)
198
203
  ```
199
204
 
200
205
  ### Recurring Sale
@@ -209,20 +214,20 @@ recurring = Conexa::RecurringSale.create(
209
214
  )
210
215
 
211
216
  # List recurring sales for a contract
212
- Conexa::RecurringSale.list(contract_id: 456)
217
+ Conexa::RecurringSale.all(contract_id: 456)
213
218
  ```
214
219
 
215
220
  ### Charge
216
221
 
217
222
  ```ruby
218
223
  # Retrieve charge
219
- charge = Conexa::Charge.retrieve(789)
224
+ charge = Conexa::Charge.find(789)
220
225
  charge.status # => "paid"
221
226
  charge.amount # => 299.90
222
227
  charge.due_date # => "2024-02-10"
223
228
 
224
229
  # List charges
225
- charges = Conexa::Charge.list(
230
+ charges = Conexa::Charge.all(
226
231
  customer_id: [127],
227
232
  status: 'pending',
228
233
  due_date_from: '2024-01-01',
@@ -240,10 +245,10 @@ Conexa::Charge.send_email(789)
240
245
 
241
246
  ```ruby
242
247
  # Retrieve bill
243
- bill = Conexa::Bill.retrieve(101)
248
+ bill = Conexa::Bill.find(101)
244
249
 
245
250
  # List bills
246
- bills = Conexa::Bill.list(
251
+ bills = Conexa::Bill.all(
247
252
  customer_id: [127],
248
253
  page: 1,
249
254
  size: 50
@@ -254,10 +259,10 @@ bills = Conexa::Bill.list(
254
259
 
255
260
  ```ruby
256
261
  # List plans
257
- plans = Conexa::Plan.list(company_id: [3])
262
+ plans = Conexa::Plan.all(company_id: [3])
258
263
 
259
264
  # Retrieve plan
260
- plan = Conexa::Plan.retrieve(5)
265
+ plan = Conexa::Plan.find(5)
261
266
  plan.name # => "Plano Básico"
262
267
  plan.price # => 99.90
263
268
  ```
@@ -266,10 +271,75 @@ plan.price # => 99.90
266
271
 
267
272
  ```ruby
268
273
  # List products
269
- products = Conexa::Product.list(company_id: [3])
274
+ products = Conexa::Product.all(company_id: [3], limit: 50)
270
275
 
271
276
  # Retrieve product
272
- product = Conexa::Product.retrieve(101)
277
+ product = Conexa::Product.find(101)
278
+
279
+ # Create product
280
+ product = Conexa::Product.create(name: 'Novo Produto', company_id: 3)
281
+
282
+ # Delete product
283
+ Conexa::Product.destroy(101)
284
+ ```
285
+
286
+ ### Receiving Method
287
+
288
+ ```ruby
289
+ methods = Conexa::ReceivingMethod.all(limit: 50)
290
+ method = Conexa::ReceivingMethod.find(11)
291
+ method.name # => "Cartão de Crédito"
292
+ ```
293
+
294
+ ### Payment Method
295
+
296
+ ```ruby
297
+ methods = Conexa::PaymentMethod.all(limit: 50)
298
+ method = Conexa::PaymentMethod.find(2)
299
+ ```
300
+
301
+ ### Bill Category / Subcategory
302
+
303
+ ```ruby
304
+ categories = Conexa::BillCategory.all(limit: 50)
305
+ subcategories = Conexa::BillSubcategory.all(limit: 50)
306
+ ```
307
+
308
+ ### Cost Center
309
+
310
+ ```ruby
311
+ centers = Conexa::CostCenter.all(limit: 50)
312
+ center = Conexa::CostCenter.find(11)
313
+ ```
314
+
315
+ ### Account
316
+
317
+ ```ruby
318
+ accounts = Conexa::Account.all(limit: 50)
319
+ account = Conexa::Account.find(23)
320
+ ```
321
+
322
+ ### Service Category
323
+
324
+ ```ruby
325
+ categories = Conexa::ServiceCategory.all(limit: 50)
326
+ category = Conexa::ServiceCategory.find(1)
327
+ ```
328
+
329
+ ### Room Booking
330
+
331
+ ```ruby
332
+ # List bookings
333
+ bookings = Conexa::RoomBooking.all(limit: 20)
334
+
335
+ # Create booking
336
+ booking = Conexa::RoomBooking.create(room_id: 5, customer_id: 127)
337
+
338
+ # Cancel booking
339
+ Conexa::RoomBooking.cancel(143063)
340
+
341
+ # Checkin
342
+ Conexa::RoomBooking.checkin(room_id: 5, customer_id: 127)
273
343
  ```
274
344
 
275
345
  ### Credit Card
@@ -286,45 +356,137 @@ card = Conexa::CreditCard.create(
286
356
  )
287
357
 
288
358
  # List customer's cards
289
- cards = Conexa::CreditCard.list(customer_id: 127)
359
+ cards = Conexa::CreditCard.all(customer_id: 127)
290
360
 
291
361
  # Delete card
292
- Conexa::CreditCard.delete(card_id)
362
+ Conexa::CreditCard.destroy(card_id)
293
363
  ```
294
364
 
295
365
  ### Company (Unit)
296
366
 
297
367
  ```ruby
298
368
  # List companies/units
299
- companies = Conexa::Company.list
369
+ companies = Conexa::Company.all
300
370
 
301
371
  # Retrieve company
302
- company = Conexa::Company.retrieve(3)
372
+ company = Conexa::Company.find(3)
303
373
  company.name # => "Matriz"
304
374
  company.document # => "12.345.678/0001-90"
305
375
  ```
306
376
 
307
377
  ## Pagination
308
378
 
309
- All list endpoints return paginated results:
379
+ ### New Pagination (recommended) `limit`/`offset`/`hasNext`
310
380
 
311
381
  ```ruby
312
- result = Conexa::Customer.list(page: 1, size: 20)
382
+ result = Conexa::Customer.all(limit: 50)
383
+
384
+ result.data # Array of customers
385
+ result.pagination.limit # => 50
386
+ result.pagination.offset # => 0
387
+ result.has_next? # => true/false
388
+
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
398
+ offset = 0
399
+ loop do
400
+ result = Conexa::Customer.all(limit: 50, offset: offset)
401
+ result.data.each { |customer| process(customer) }
402
+ break unless result.has_next?
403
+ offset += 50
404
+ end
405
+ ```
406
+
407
+ ### Legacy Pagination (deprecated — will be removed 2026-08-01)
313
408
 
314
- result.data # Array of customers
409
+ ```ruby
410
+ # Still works but emits a deprecation warning
411
+ result = Conexa::Customer.all(page: 1, size: 20)
315
412
  result.pagination.current_page # => 1
316
413
  result.pagination.total_pages # => 10
317
- result.pagination.total_items # => 195
318
- result.pagination.item_per_page # => 20
414
+ ```
415
+
416
+ ### Migration Guide: Legacy → New Pagination
319
417
 
320
- # Iterate through pages
418
+ The legacy `page`/`size` pagination is deprecated and will be removed on **2026-08-01**. Follow these steps to migrate:
419
+
420
+ #### 1. Replace `page`/`size` with `limit`/`offset`
421
+
422
+ ```ruby
423
+ # BEFORE (legacy — deprecated)
424
+ result = Conexa::Customer.all(page: 1, size: 50)
425
+ result = Conexa::Customer.all(page: 2, size: 50)
426
+
427
+ # AFTER (new)
428
+ result = Conexa::Customer.all(limit: 50) # offset defaults to 0
429
+ result = Conexa::Customer.all(limit: 50, offset: 50) # second page
430
+ ```
431
+
432
+ **Conversion formula:** `offset = (page - 1) * size`
433
+
434
+ #### 2. Update pagination metadata access
435
+
436
+ ```ruby
437
+ # BEFORE (legacy)
438
+ result.pagination # => { "page" => 1, "size" => 50, "total" => 150 }
439
+ total_pages = (result.pagination["total"].to_f / size).ceil
440
+
441
+ # AFTER (new)
442
+ result.pagination.limit # => 50
443
+ result.pagination.offset # => 0
444
+ result.pagination.has_next # => true/false
445
+ ```
446
+
447
+ #### 3. Update iteration loops
448
+
449
+ ```ruby
450
+ # BEFORE (legacy)
451
+ page = 1
321
452
  loop do
322
- result.data.each { |customer| process(customer) }
323
- break if result.pagination.current_page >= result.pagination.total_pages
324
- result = Conexa::Customer.list(page: result.pagination.current_page + 1)
453
+ result = Conexa::Customer.all(page: page, size: 100)
454
+ break if result.empty?
455
+ result.data.each { |c| process(c) }
456
+ page += 1
457
+ end
458
+
459
+ # AFTER (new — using next_page)
460
+ result = Conexa::Customer.all(limit: 100)
461
+ loop do
462
+ result.data.each { |c| process(c) }
463
+ break unless result.has_next?
464
+ result = result.next_page
325
465
  end
326
466
  ```
327
467
 
468
+ #### 4. Remove positional arguments
469
+
470
+ ```ruby
471
+ # BEFORE (legacy positional args)
472
+ Conexa::Customer.all(2, 50) # page 2, size 50
473
+ Conexa::Customer.find_by({}, 1, 20) # page 1, size 20
474
+
475
+ # AFTER (new keyword args)
476
+ Conexa::Customer.all(limit: 50, offset: 50)
477
+ Conexa::Customer.find_by(limit: 20)
478
+ ```
479
+
480
+ #### Quick reference
481
+
482
+ | Legacy | New |
483
+ |---|---|
484
+ | `page: 1, size: 50` | `limit: 50` (offset defaults to 0) |
485
+ | `page: N, size: S` | `limit: S, offset: (N-1)*S` |
486
+ | `pagination["total"]` | `pagination.has_next` |
487
+ | `pagination["page"]` | `pagination.offset` |
488
+ | Positional `(page, size)` | Keyword `limit:`, `offset:` |
489
+
328
490
  ## Error Handling
329
491
 
330
492
  ```ruby
@@ -332,35 +494,28 @@ begin
332
494
  customer = Conexa::Customer.create(name: '')
333
495
  rescue Conexa::ValidationError => e
334
496
  # Field validation errors (400)
335
- e.errors.each do |error|
336
- puts "#{error['field']}: #{error['messages'].join(', ')}"
337
- end
338
- rescue Conexa::AuthenticationError => e
339
- # Authentication required (401)
340
- puts e.message
341
- rescue Conexa::AuthorizationError => e
342
- # Not authorized (403)
343
497
  puts e.message
344
- rescue Conexa::NotFoundError => e
498
+ rescue Conexa::NotFound => e
345
499
  # Resource not found (404)
346
500
  puts e.message
347
- rescue Conexa::UnprocessableError => e
348
- # Business logic error (422)
349
- e.errors.each do |error|
350
- puts "#{error['code']}: #{error['message']}"
351
- end
352
- rescue Conexa::RateLimitError => e
353
- # Too many requests (429)
354
- puts "Rate limit exceeded. Retry after #{e.retry_after} seconds"
355
- rescue Conexa::ApiError => e
356
- # Generic API error
357
- 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
358
513
  end
359
514
  ```
360
515
 
361
516
  ## Rate Limiting
362
517
 
363
- The Conexa API has a limit of **100 requests per minute**. Response headers include:
518
+ The Conexa API has a limit of **100 requests per minute** (changing to **60 requests per minute** on 2026-04-27). Response headers include:
364
519
 
365
520
  - `X-Rate-Limit-Limit`: Maximum requests in 60s
366
521
  - `X-Rate-Limit-Remaining`: Remaining requests in 60s
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
@@ -281,7 +283,7 @@ paginacao = pagina1.pagination
281
283
  # paginacao contém total de registros, total de páginas, etc.
282
284
  ```
283
285
 
284
- #### Iterando Por Todas as Páginas
286
+ #### Iterando Por Todas as Páginas (legado — depreciado)
285
287
 
286
288
  ```ruby
287
289
  pagina = 1
@@ -301,6 +303,108 @@ loop do
301
303
  end
302
304
  ```
303
305
 
306
+ ### Nova Paginação (recomendada) — `limit`/`offset`/`hasNext`
307
+
308
+ ```ruby
309
+ resultado = Conexa::Customer.all(limit: 50)
310
+
311
+ resultado.data # Array de clientes
312
+ resultado.pagination.limit # => 50
313
+ resultado.pagination.offset # => 0
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
323
+
324
+ # Ou manualmente com offset
325
+ offset = 0
326
+ loop do
327
+ resultado = Conexa::Customer.all(limit: 50, offset: offset)
328
+ resultado.data.each { |cliente| processa(cliente) }
329
+ break unless resultado.has_next?
330
+ offset += 50
331
+ end
332
+ ```
333
+
334
+ ### Guia de Migração: Paginação Legada → Nova
335
+
336
+ A paginação legada `page`/`size` está depreciada e será removida em **01/08/2026**. Siga estes passos para migrar:
337
+
338
+ #### 1. Substitua `page`/`size` por `limit`/`offset`
339
+
340
+ ```ruby
341
+ # ANTES (legado — depreciado)
342
+ resultado = Conexa::Customer.all(page: 1, size: 50)
343
+ resultado = Conexa::Customer.all(page: 2, size: 50)
344
+
345
+ # DEPOIS (novo)
346
+ resultado = Conexa::Customer.all(limit: 50) # offset padrão 0
347
+ resultado = Conexa::Customer.all(limit: 50, offset: 50) # segunda página
348
+ ```
349
+
350
+ **Fórmula de conversão:** `offset = (page - 1) * size`
351
+
352
+ #### 2. Atualize o acesso aos metadados de paginação
353
+
354
+ ```ruby
355
+ # ANTES (legado)
356
+ resultado.pagination # => { "page" => 1, "size" => 50, "total" => 150 }
357
+ total_paginas = (resultado.pagination["total"].to_f / tamanho).ceil
358
+
359
+ # DEPOIS (novo)
360
+ resultado.pagination.limit # => 50
361
+ resultado.pagination.offset # => 0
362
+ resultado.pagination.has_next # => true/false
363
+ ```
364
+
365
+ #### 3. Atualize os loops de iteração
366
+
367
+ ```ruby
368
+ # ANTES (legado)
369
+ pagina = 1
370
+ loop do
371
+ resultado = Conexa::Customer.all(page: pagina, size: 100)
372
+ break if resultado.empty?
373
+ resultado.data.each { |c| processa(c) }
374
+ pagina += 1
375
+ end
376
+
377
+ # DEPOIS (novo — usando next_page)
378
+ resultado = Conexa::Customer.all(limit: 100)
379
+ loop do
380
+ resultado.data.each { |c| processa(c) }
381
+ break unless resultado.has_next?
382
+ resultado = resultado.next_page
383
+ end
384
+ ```
385
+
386
+ #### 4. Remova argumentos posicionais
387
+
388
+ ```ruby
389
+ # ANTES (argumentos posicionais legados)
390
+ Conexa::Customer.all(2, 50) # página 2, tamanho 50
391
+ Conexa::Customer.find_by({}, 1, 20) # página 1, tamanho 20
392
+
393
+ # DEPOIS (argumentos nomeados)
394
+ Conexa::Customer.all(limit: 50, offset: 50)
395
+ Conexa::Customer.find_by(limit: 20)
396
+ ```
397
+
398
+ #### Referência rápida
399
+
400
+ | Legado | Novo |
401
+ |---|---|
402
+ | `page: 1, size: 50` | `limit: 50` (offset padrão 0) |
403
+ | `page: N, size: S` | `limit: S, offset: (N-1)*S` |
404
+ | `pagination["total"]` | `pagination.has_next` |
405
+ | `pagination["page"]` | `pagination.offset` |
406
+ | Posicional `(page, size)` | Nomeado `limit:`, `offset:` |
407
+
304
408
  ### Exemplos
305
409
 
306
410
  #### Clientes (Customers)