Skip to content

v4.13.0: New resources, external-id operations, and disable toggles#184

Open
jessicahearn wants to merge 12 commits intomainfrom
jessica/pip-309-ruby-sdk-feature-updates
Open

v4.13.0: New resources, external-id operations, and disable toggles#184
jessicahearn wants to merge 12 commits intomainfrom
jessica/pip-309-ruby-sdk-feature-updates

Conversation

@jessicahearn
Copy link
Contributor

@jessicahearn jessicahearn commented Feb 13, 2026

Summary

  • Add standalone Transaction and LineItem resources with CRUD, toggle_disabled!, and external-id operations
  • Add JsonImport resource for bulk JSON imports (create + retrieve)
  • Add Upload resource for CSV file uploads via multipart (requires faraday-multipart)
  • Add Invoice toggle_disabled!, update_status!, update_by_external_id!, destroy_by_external_id!, toggle_disabled_by_external_id!
  • Add SubscriptionEvent toggle_disabled!, update_by_external_id!, destroy_by_external_id!, toggle_disabled_by_external_id!
  • Add SubscriptionEvent class-level destroy! accepting both flat and envelope-wrapped params for backwards compatibility
  • Add Account include parameter support and id readonly attribute
  • Add DataSource empty! and soft_purge! methods
  • Add errors readonly attribute to LineItem and Transaction (PIP-304)
  • Add handle_as_user_edit query parameter to all write methods
  • URL-encode user-supplied query parameters in API request paths
  • Add missing middleware (RaiseError, retry, User-Agent) to Upload multipart connection
  • Remove outdated post-install gem message
  • Bump version to 4.13.0

Automated test plan

  • All 352 RSpec tests pass (97.9% line coverage)
  • Unit tests for all new resources and methods
  • Tests for handle_as_user_edit query parameter across all resources
  • Tests for SubscriptionEvent destroy backwards compatibility (flat + envelope params)

Manual testing instructions

Prerequisites for all tests:

require 'chartmogul'
ChartMogul::ChartMogul.token = 'YOUR_API_TOKEN'

You'll need a data source UUID and some existing resources. Create a test data source first:

ds = ChartMogul::DataSource.create!(name: 'SDK Test')
ds.uuid # => save this for later

PIP-304: LineItem and Transaction errors field

Verify that errors is exposed as a readonly attribute on LineItem and Transaction when validation errors are present.

# Retrieve a line item that has validation errors
li = ChartMogul::LineItem.retrieve('li_XXXXXXXX')
puts li.errors # => should be populated if the line item has errors, nil otherwise

# Same for Transaction
txn = ChartMogul::Transaction.retrieve('tr_XXXXXXXX')
puts txn.errors

Expected: errors attribute is accessible and returns the error hash (or nil if no errors).


PIP-76: Account include parameter

Verify that retrieve supports the include parameter for optional account settings.

# Without include — should NOT have optional fields
account = ChartMogul::Account.retrieve
puts account.id                   # => should be present (PIP-120)
puts account.churn_recognition    # => nil

# With include — should have the requested fields
account = ChartMogul::Account.retrieve(include: 'churn_recognition,refund_handling')
puts account.churn_recognition    # => e.g. "churn_at_time_of_cancelation"
puts account.refund_handling      # => e.g. a hash with settings

# Array form
account = ChartMogul::Account.retrieve(include: %w[churn_recognition auto_churn_subscription])
puts account.churn_recognition
puts account.auto_churn_subscription

Expected: Optional fields are populated only when requested via include.


PIP-120: Account ID in retrieve response

account = ChartMogul::Account.retrieve
puts account.id # => should return the account UUID string

Expected: id is present and returns a string UUID.


Invoice update_status!

Update the status of an invoice by data source UUID and invoice external ID.

ChartMogul::Invoice.update_status!(
  data_source_uuid: 'ds_XXXXXXXX',
  invoice_external_id: 'inv_ext_123',
  status: 'void'
)

Expected: Returns the updated invoice object with the new status.


Invoice toggle_disabled!

Disable/enable an invoice by UUID.

inv = ChartMogul::Invoice.retrieve('inv_XXXXXXXX')

# Disable
inv.toggle_disabled!(disabled: true)
puts inv.disabled # => true

# Re-enable
inv.toggle_disabled!(disabled: false)
puts inv.disabled # => false

Expected: Invoice disabled state toggles correctly.


Invoice by_external_id operations

# Retrieve
inv = ChartMogul::Invoice.retrieve_by_external_id(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'inv_ext_123'
)
puts inv.uuid

# Update
ChartMogul::Invoice.update_by_external_id!(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'inv_ext_123',
  due_date: '2026-12-31T00:00:00Z'
)

# Toggle disabled
ChartMogul::Invoice.toggle_disabled_by_external_id!(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'inv_ext_123',
  disabled: true
)

# Destroy
ChartMogul::Invoice.destroy_by_external_id!(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'inv_ext_123'
)

Expected: Each operation succeeds. Retrieve returns the invoice, update/toggle return updated objects, destroy returns true.


SubscriptionEvent toggle_disabled!

se = ChartMogul::SubscriptionEvent.all.subscription_events.first

# Disable by ID
se.toggle_disabled!(disabled: true)

# Re-enable
se.toggle_disabled!(disabled: false)

Expected: Returns updated subscription event with disabled toggled.


SubscriptionEvent by_external_id operations

# Update by external ID
ChartMogul::SubscriptionEvent.update_by_external_id!(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'se_ext_123',
  quantity: 5
)

# Toggle disabled by external ID
ChartMogul::SubscriptionEvent.toggle_disabled_by_external_id!(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'se_ext_123',
  disabled: true
)

# Destroy by external ID
ChartMogul::SubscriptionEvent.destroy_by_external_id!(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'se_ext_123'
)

Expected: Each operation succeeds without errors.


SubscriptionEvent destroy! backwards compatibility

Verify both flat params and envelope-wrapped params work.

# Flat params (new style)
ChartMogul::SubscriptionEvent.destroy!(id: 'se_XXXXXXXX')

# Envelope-wrapped params (old style, backwards compatible)
ChartMogul::SubscriptionEvent.destroy!(subscription_event: { id: 'se_XXXXXXXX' })

Expected: Both forms succeed and delete the subscription event.


Standalone LineItem resource

# Create a line item on an invoice
li = ChartMogul::LineItem.create!(
  invoice_uuid: 'inv_XXXXXXXX',
  type: 'one_time',
  amount_in_cents: 5000,
  description: 'SDK test line item',
  external_id: 'li_sdk_test_1'
)
puts li.uuid

# Retrieve
li = ChartMogul::LineItem.retrieve(li.uuid)

# Retrieve by external ID
li = ChartMogul::LineItem.retrieve_by_external_id(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'li_sdk_test_1'
)

# Toggle disabled
li.toggle_disabled!(disabled: true)

# Toggle disabled by external ID
ChartMogul::LineItem.toggle_disabled_by_external_id!(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'li_sdk_test_1',
  disabled: false
)

# Update by external ID
ChartMogul::LineItem.update_by_external_id!(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'li_sdk_test_1',
  description: 'Updated description'
)

# Destroy by external ID
ChartMogul::LineItem.destroy_by_external_id!(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'li_sdk_test_1'
)

Expected: Full CRUD lifecycle completes without errors.


Standalone Transaction resource

# Create a transaction on an invoice
txn = ChartMogul::Transaction.create!(
  invoice_uuid: 'inv_XXXXXXXX',
  type: 'payment',
  date: '2026-01-15T00:00:00Z',
  result: 'successful',
  external_id: 'txn_sdk_test_1'
)
puts txn.uuid

# Retrieve
txn = ChartMogul::Transaction.retrieve(txn.uuid)

# Retrieve by external ID
txn = ChartMogul::Transaction.retrieve_by_external_id(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'txn_sdk_test_1'
)

# Toggle disabled
txn.toggle_disabled!(disabled: true)

# Toggle disabled by external ID
ChartMogul::Transaction.toggle_disabled_by_external_id!(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'txn_sdk_test_1',
  disabled: false
)

# Update by external ID
ChartMogul::Transaction.update_by_external_id!(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'txn_sdk_test_1',
  result: 'failed'
)

# Destroy by external ID
ChartMogul::Transaction.destroy_by_external_id!(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'txn_sdk_test_1'
)

Expected: Full CRUD lifecycle completes without errors.


handle_as_user_edit parameter

Verify the handle_as_user_edit query param is appended to write requests across all resources.

# Example with Invoice toggle
inv = ChartMogul::Invoice.retrieve('inv_XXXXXXXX')
inv.toggle_disabled!(disabled: true, handle_as_user_edit: true)

# Example with LineItem create
ChartMogul::LineItem.create!(
  invoice_uuid: 'inv_XXXXXXXX',
  type: 'one_time',
  amount_in_cents: 1000,
  handle_as_user_edit: true
)

# Example with Transaction update by external ID
ChartMogul::Transaction.update_by_external_id!(
  data_source_uuid: 'ds_XXXXXXXX',
  external_id: 'txn_ext_1',
  result: 'failed',
  handle_as_user_edit: true
)

Expected: Requests succeed with ?handle_as_user_edit=true appended to the URL. The API should treat these as user-initiated edits.


JsonImport resource

# Create a JSON import batch
import = ChartMogul::JsonImport.create!(
  data_source_uuid: 'ds_XXXXXXXX',
  customers: [
    { external_id: 'cust_1', name: 'Test Customer', email: 'test@example.com' }
  ]
)
puts import.id
puts import.status # => e.g. "pending"

# Poll for status
status = ChartMogul::JsonImport.retrieve(
  data_source_uuid: 'ds_XXXXXXXX',
  id: import.id
)
puts status.status          # => "pending", "processing", "completed", or "failed"
puts status.processed_count
puts status.error_count

Expected: Import is created, returns an ID and status. Retrieve shows progress.


Upload resource (CSV)

# Upload a CSV file
upload = ChartMogul::Upload.create!(
  data_source_uuid: 'ds_XXXXXXXX',
  file: '/path/to/invoices.csv',
  type: 'invoices'
)
puts upload.id

# With batch name
upload = ChartMogul::Upload.create!(
  data_source_uuid: 'ds_XXXXXXXX',
  file: File.open('/path/to/invoices.csv'),
  type: 'invoices',
  batch_name: 'March 2026 import'
)

Expected: Upload succeeds, returns upload object with id. Both file path strings and File objects are accepted.


DataSource empty! and soft_purge!

ds = ChartMogul::DataSource.retrieve('ds_XXXXXXXX')

# Soft purge — clears data for reimport
ds.soft_purge!

# Soft purge with switch_system
ds.soft_purge!(switch_system: 'other_system')

# Empty — deletes all data from the data source
ds.empty!

Expected: Both methods return successfully. empty! deletes all data (data source remains). soft_purge! clears data for reimport.


🤖 Generated with Claude Code

@jessicahearn jessicahearn self-assigned this Feb 13, 2026
jessicahearn and others added 6 commits March 17, 2026 12:17
- Add Account `include` parameter for optional settings (churn_recognition,
  churn_when_zero_mrr, auto_churn_subscription, refund_handling,
  proximate_movement_reclassification)
- Add DataSource `empty!` and `soft_purge!` methods for data management
- Add Invoice `update!`, `toggle_disabled!`, `update_status!` methods
- Add SubscriptionEvent `toggle_disabled!` method
- Add standalone Transaction resource with CRUD and `toggle_disabled!`
- Add standalone LineItem resource with CRUD and `toggle_disabled!`
- Add external ID lookup methods (`*_by_external_id`) for Invoice,
  Transaction, LineItem, and SubscriptionEvent
- Add JsonImport resource for bulk JSON imports
- Add Upload resource for CSV file uploads (requires faraday-multipart)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added optional handle_as_user_edit parameter to:
- Invoice: toggle_disabled!, update_by_external_id!, destroy_by_external_id!, toggle_disabled_by_external_id!
- Transaction: toggle_disabled!, update_by_external_id!, destroy_by_external_id!, toggle_disabled_by_external_id!
- LineItem: create!, toggle_disabled!, update_by_external_id!, destroy_by_external_id!, toggle_disabled_by_external_id!
- SubscriptionEvent: toggle_disabled!, update_by_external_id!, destroy_by_external_id!, toggle_disabled_by_external_id!

This allows API consumers to indicate when changes should be treated as user edits for edit history tracking purposes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a class-level destroy! method that accepts both flat params and
envelope-wrapped params for full backwards compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@wscourge wscourge force-pushed the jessica/pip-309-ruby-sdk-feature-updates branch from 1414f52 to 1bb31e2 Compare March 17, 2026 11:19
wscourge and others added 6 commits March 17, 2026 17:04
Tests cover new_from_json (including errors/edit_history_summary fields),
CRUD operations, toggle_disabled, by_external_id methods, and
handle_as_user_edit query parameter support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…_id methods

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…thods

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@wscourge
Copy link
Contributor

@claude review

@wscourge wscourge marked this pull request as ready for review March 17, 2026 16:15
@wscourge
Copy link
Contributor

@claude review

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the ChartMogul Ruby SDK with new v4.13.0 resources and convenience endpoints (uploads/imports, external-id lookups, disable toggles), and bumps the gem version + changelog accordingly.

Changes:

  • Add new resources: Transaction, LineItem, JsonImport, and Upload (CSV multipart).
  • Add new operations to existing resources: Account include, DataSource empty! / soft_purge!, Invoice toggle/update-by-external-id/status, SubscriptionEvent disable toggle + external-id ops.
  • Add/extend specs for the newly added endpoints and behaviors, and update version/changelog.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
spec/chartmogul/upload_spec.rb Adds tests for CSV upload creation (multipart) and attribute parsing
spec/chartmogul/transaction_spec.rb Adds tests for Transaction external-id operations and disable toggling
spec/chartmogul/subscription_event_spec.rb Adds tests for SubscriptionEvent destroy variants, disable toggling, and external-id operations
spec/chartmogul/line_item_spec.rb Adds tests for LineItem CRUD-like endpoints + external-id ops + disable toggling
spec/chartmogul/json_import_spec.rb Adds tests for JsonImport create/retrieve endpoints
spec/chartmogul/invoice_spec.rb Adds tests for new Invoice disable toggling + external-id ops + status update
spec/chartmogul/data_source_spec.rb Adds tests for DataSource empty! and soft_purge!
spec/chartmogul/account_spec.rb Adds tests for Account .retrieve(include: ...) behavior
lib/chartmogul/version.rb Bumps gem version to 4.13.0
lib/chartmogul/upload.rb Implements Upload resource + multipart CSV upload
lib/chartmogul/transaction.rb Implements standalone Transaction resource + external-id ops + disable toggles
lib/chartmogul/subscription_event.rb Adds disabled fields, toggle APIs, and external-id update/destroy/toggle methods
lib/chartmogul/line_item.rb Implements standalone LineItem resource + external-id ops + disable toggles
lib/chartmogul/json_import.rb Implements JsonImport create/retrieve for bulk JSON import
lib/chartmogul/invoice.rb Adds Invoice update support + disable toggles + external-id ops + status update
lib/chartmogul/data_source.rb Adds DataSource empty! and soft_purge! methods
lib/chartmogul/account.rb Adds include parameter support and optional account settings attributes
lib/chartmogul.rb Requires the newly added resource files
chartmogul-ruby.gemspec Removes the post-install message
changelog.md Adds 4.13.0 changelog entry describing new SDK features

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@wscourge wscourge changed the title Add SDK features for v4.12.0 Ruby SDK v4.13.0: Add new resources, endpoints, and convenience methods Mar 18, 2026
@wscourge wscourge changed the title Ruby SDK v4.13.0: Add new resources, endpoints, and convenience methods Ruby SDK v4.13.0: New resources, external-id operations, and disable toggles Mar 18, 2026
@wscourge
Copy link
Contributor

I've opened a draft PR with fixes: #186
Please review and merge into your branch when you're happy with the changes.

@wscourge wscourge changed the title Ruby SDK v4.13.0: New resources, external-id operations, and disable toggles v4.13.0: New resources, external-id operations, and disable toggles Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants