chartmogul-ruby 4.7.0 → 4.8.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: 412ac47a1b6aa99718ae0d49b5637ca3440d002fc3df7b65a559de92ee9855cc
4
- data.tar.gz: be62073fffa5ab0fb374df1305fc9eeac218d489e6f664cd76bb452b95f85e94
3
+ metadata.gz: d8bfb17b4530e13675e2958de0bc1f11f371d34d1c306cecc1947094c49d7f26
4
+ data.tar.gz: 32e700778b8f366d4d45a2e52b0105c71d28b0d23546cb3fb99e2b6d8a89063b
5
5
  SHA512:
6
- metadata.gz: 1f48e0c1e88f9a0a33ffcc4d496c6127845f6e995967444e5dfaeedeab2f48a76480e063592eb90128f4adfc6b97846021dcacc1aea9932461d7fb759ccd76d6
7
- data.tar.gz: 5898d26b2120e9506451238a97d565aa1093664db3352b9374f802b406f5c0034cdf5e4fb66fbf98313a38a6d6cfd1f81e991654addcd120d8195ab446473b0f
6
+ metadata.gz: 54db5c88f38ac82440530cfdd137bfa7af53a85e66cd3d69efd6834909325cdcaafa186c53a6658fc0cef55c92d22398e78ecc59992e5e11883c29e0331ac4ce
7
+ data.tar.gz: da9b0d684ddd39e9d6adcaf98f4231452e1910828c91c24a153e1a97a6d604d0074b9e8b55a3f36957fa3ce83baecf59d5a12af43d067f31418a136540618b96
@@ -1,4 +1,4 @@
1
- name: Run specs and generate Code Climate report
1
+ name: Run specs
2
2
  on:
3
3
  push:
4
4
  branches: [ main ]
@@ -19,28 +19,5 @@ jobs:
19
19
  bundler-cache: true
20
20
  - name: Install dependencies
21
21
  run: bundle install
22
- - name: Set ENV for codeclimate (pull_request)
23
- run: |
24
- git fetch --no-tags --prune --depth=1 origin +refs/heads/$GITHUB_HEAD_REF:refs/remotes/origin/$GITHUB_HEAD_REF
25
- echo "GIT_BRANCH=$GITHUB_HEAD_REF" >> $GITHUB_ENV
26
- echo "GIT_COMMIT_SHA=$(git rev-parse origin/$GITHUB_HEAD_REF)" >> $GITHUB_ENV
27
- if: github.event_name == 'pull_request'
28
- - name: Set ENV for codeclimate (push)
29
- run: |
30
- echo "GIT_BRANCH=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV
31
- echo "GIT_COMMIT_SHA=$GITHUB_SHA" >> $GITHUB_ENV
32
- if: github.event_name == 'push'
33
- - name: Install Code Climate test report
34
- run: |
35
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
36
- chmod +x ./cc-test-reporter
37
- ./cc-test-reporter before-build
38
22
  - name: Run tests
39
- env:
40
- CC_TEST_REPORTER_ID: 'enable JSON output for SimpleCov'
41
23
  run: bundle exec rake
42
- - name: Send Report to Code Climate
43
- env:
44
- CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
45
- if: ${{ success() }}
46
- run: ./cc-test-reporter after-build
data/changelog.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # chartmogul-ruby Change Log
2
2
 
3
+ ## Version 4.7.1 - July 25, 2025
4
+ - Fix create! and update! methods for Task (customer_uuid was omitted from payload)
5
+
3
6
  ## Version 4.7.0 - April 25, 2025
4
7
  - Adds support for Tasks (https://dev.chartmogul.com/reference/tasks)
5
8
 
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
32
32
 
33
33
  # Higher versions break ruby 2.7 support.
34
34
  spec.add_development_dependency 'bundler', '~> 2'
35
+ spec.add_development_dependency 'cgi'
35
36
  spec.add_development_dependency 'pry'
36
37
  spec.add_development_dependency 'rake'
37
38
  spec.add_development_dependency 'rspec'
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
3
+ require "forwardable"
4
+ require "set"
4
5
 
5
6
  module ChartMogul
6
7
  class APIResource < ChartMogul::Object
@@ -8,17 +9,45 @@ module ChartMogul
8
9
 
9
10
  RETRY_STATUSES = [429, *500..599].freeze
10
11
  RETRY_EXCEPTIONS = [
11
- 'Faraday::ConnectionFailed',
12
- 'Faraday::RetriableResponse'
12
+ "Faraday::ConnectionFailed",
13
+ "Faraday::RetriableResponse"
13
14
  ].freeze
14
15
  BACKOFF_FACTOR = 2
15
16
  INTERVAL_RANDOMNESS = 0.5
16
17
  INTERVAL = 1
17
18
  MAX_INTERVAL = 60
18
- THREAD_CONNECTION_KEY = 'chartmogul_ruby.api_resource.connection'
19
+ THREAD_CONNECTION_KEY = "chartmogul_ruby.api_resource.connection"
19
20
 
20
21
  class << self; attr_reader :resource_path, :resource_name, :resource_root_key end
21
22
 
23
+ def self.query_params
24
+ @query_params ||= Set.new
25
+ end
26
+
27
+ def self.writeable_query_param(attribute, options = {})
28
+ query_params << attribute.to_sym
29
+ writeable_attr(attribute, options)
30
+ end
31
+
32
+ def self.extract_query_params(attrs, resource_key = nil)
33
+ remaining_attrs = attrs.dup
34
+ query_params = {}
35
+
36
+ self.query_params.each do |param|
37
+ # If resource_key is specified, look in nested structure
38
+ if resource_key && remaining_attrs[resource_key].is_a?(Hash) &&
39
+ remaining_attrs[resource_key]&.key?(param) &&
40
+ remaining_attrs[resource_key][param]
41
+ query_params[param] = remaining_attrs[resource_key].delete(param)
42
+ # Otherwise look at top level
43
+ elsif remaining_attrs.key?(param) && remaining_attrs[param]
44
+ query_params[param] = remaining_attrs.delete(param)
45
+ end
46
+ end
47
+
48
+ [remaining_attrs, query_params]
49
+ end
50
+
22
51
  def self.set_resource_path(path)
23
52
  @resource_path = ChartMogul::ResourcePath.new(path)
24
53
  end
@@ -60,10 +89,10 @@ module ChartMogul
60
89
  message = "JSON schema validation hasn't passed."
61
90
  raise ChartMogul::SchemaInvalidError.new(message, http_status: 400, response: response)
62
91
  when 401
63
- message = 'No valid API key provided'
92
+ message = "No valid API key provided"
64
93
  raise ChartMogul::UnauthorizedError.new(message, http_status: 401, response: response)
65
94
  when 403
66
- message = 'The requested action is forbidden.'
95
+ message = "The requested action is forbidden."
67
96
  raise ChartMogul::ForbiddenError.new(message, http_status: 403, response: response)
68
97
  when 404
69
98
  message = "The requested #{resource_name} could not be found."
@@ -72,7 +101,7 @@ module ChartMogul
72
101
  message = "The #{resource_name} could not be created or updated."
73
102
  raise ChartMogul::ResourceInvalidError.new(message, http_status: 422, response: response)
74
103
  when 500..504
75
- message = 'ChartMogul API server response error'
104
+ message = "ChartMogul API server response error"
76
105
  raise ChartMogul::ServerError.new(message, http_status: http_status, response: response)
77
106
  else
78
107
  message = "#{resource_name} request error has occurred."
@@ -84,17 +113,63 @@ module ChartMogul
84
113
  raise ChartMogul::ChartMogulError, exception.message
85
114
  end
86
115
 
87
- def_delegators 'self.class', :resource_path, :resource_name, :resource_root_key, :connection, :handling_errors
116
+ def_delegators "self.class", :resource_path, :resource_name, :resource_root_key, :connection, :handling_errors
117
+
118
+ def extract_query_params(attrs, resource_key = nil)
119
+ remaining_attrs = attrs.dup
120
+ query_params = {}
121
+
122
+ self.class.query_params.each do |param|
123
+ # If resource_key is specified, look in nested structure
124
+ if resource_key && remaining_attrs[resource_key].is_a?(Hash) &&
125
+ remaining_attrs[resource_key]&.key?(param) &&
126
+ remaining_attrs[resource_key][param]
127
+ query_params[param] = remaining_attrs[resource_key].delete(param)
128
+ # Otherwise look at top level
129
+ elsif remaining_attrs.key?(param) && remaining_attrs[param]
130
+ query_params[param] = remaining_attrs.delete(param)
131
+ end
132
+ end
133
+
134
+ [remaining_attrs, query_params]
135
+ end
136
+
137
+ # Generate path with query parameters applied
138
+ def path_with_query_params(attrs)
139
+ _, query_params = extract_query_params(attrs)
140
+ query_params.empty? ? resource_path.path : resource_path.apply_with_get_params(query_params)
141
+ end
142
+
143
+ # Enhanced custom! that automatically handles query parameters
144
+ def custom_with_query_params!(http_method, body_data = {}, resource_key = nil)
145
+ attrs, query_params = extract_query_params(body_data, resource_key)
146
+ # Only include path parameters from instance attributes, plus extracted query parameters
147
+ path_params = instance_attributes.select { |key, _| resource_path.named_params.values.include?(key) }
148
+ path_and_query_params = path_params.merge(query_params)
149
+ path = resource_path.apply_with_get_params(path_and_query_params)
88
150
 
89
- private
151
+ custom!(http_method, path, attrs)
152
+ end
153
+
154
+ # Class method version for enhanced custom! with query parameters
155
+ def self.custom_with_query_params!(http_method, body_data = {}, resource_key = nil)
156
+ attrs, query_params = extract_query_params(body_data, resource_key)
157
+ # Only include path parameters from body data, plus extracted query parameters
158
+ path_params = body_data.select { |key, _| resource_path.named_params.values.include?(key) }
159
+ path_and_query_params = path_params.merge(query_params)
160
+ path = resource_path.apply_with_get_params(path_and_query_params)
161
+
162
+ custom!(http_method, path, attrs)
163
+ end
90
164
 
91
165
  def self.build_connection
92
- Faraday.new(url: ChartMogul.api_base, headers: { 'User-Agent' => "chartmogul-ruby/#{ChartMogul::VERSION}" }) do |faraday|
166
+ Faraday.new(url: ChartMogul.api_base,
167
+ headers: { "User-Agent" => "chartmogul-ruby/#{ChartMogul::VERSION}" }) do |faraday|
93
168
  faraday.use Faraday::Response::RaiseError
94
- faraday.request :authorization, :basic, ChartMogul.api_key, ''
169
+ faraday.request :authorization, :basic, ChartMogul.api_key, ""
95
170
  faraday.request :retry, max: ChartMogul.max_retries, retry_statuses: RETRY_STATUSES,
96
- max_interval: MAX_INTERVAL, backoff_factor: BACKOFF_FACTOR,
97
- interval_randomness: INTERVAL_RANDOMNESS, interval: INTERVAL, exceptions: RETRY_EXCEPTIONS
171
+ max_interval: MAX_INTERVAL, backoff_factor: BACKOFF_FACTOR,
172
+ interval_randomness: INTERVAL_RANDOMNESS, interval: INTERVAL, exceptions: RETRY_EXCEPTIONS
98
173
  faraday.adapter Faraday::Adapter::NetHttp
99
174
  end
100
175
  end
@@ -1,21 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
3
+ require "forwardable"
4
4
 
5
5
  module ChartMogul
6
6
  class CustomerInvoices < APIResource
7
7
  extend Forwardable
8
8
  include Enumerable
9
9
 
10
- set_resource_name 'Invoices'
11
- set_resource_path '/v1/import/customers/:customer_uuid/invoices'
10
+ set_resource_name "Invoices"
11
+ set_resource_path "/v1/import/customers/:customer_uuid/invoices"
12
12
 
13
13
  writeable_attr :invoices, default: []
14
-
15
14
  writeable_attr :customer_uuid
15
+ writeable_query_param :handle_as_user_edit
16
16
 
17
17
  include API::Actions::All
18
- include API::Actions::Create
18
+ include API::Actions::Custom
19
19
  include Concerns::Pageable2
20
20
  include Concerns::PageableWithCursor
21
21
 
@@ -23,6 +23,29 @@ module ChartMogul
23
23
  map(&:serialize_for_write)
24
24
  end
25
25
 
26
+ def create!
27
+ # Only merge writeable_query_params to avoid overwriting serialized data
28
+ query_params_data = instance_attributes.select { |k, _| self.class.query_params.include?(k.to_sym) }
29
+ body_data = serialize_for_write.merge(query_params_data)
30
+ custom_with_query_params!(:post, body_data)
31
+ end
32
+
33
+ def self.create!(attributes = {})
34
+ resource = new(attributes)
35
+ # Only merge writeable_query_params to avoid overwriting serialized data
36
+ query_params_data = attributes.select { |k, _| query_params.include?(k.to_sym) }
37
+ body_data = resource.serialize_for_write.merge(query_params_data)
38
+ resource.custom_with_query_params!(:post, body_data)
39
+ end
40
+
41
+ def update!(attrs = {})
42
+ # Merge new attributes with existing, then only merge query params
43
+ updated_attrs = instance_attributes.merge(attrs)
44
+ query_params_data = updated_attrs.select { |k, _| self.class.query_params.include?(k.to_sym) }
45
+ body_data = serialize_for_write.merge(query_params_data)
46
+ custom_with_query_params!(:put, body_data)
47
+ end
48
+
26
49
  def self.all(customer_uuid, options = {})
27
50
  super(options.merge(customer_uuid: customer_uuid))
28
51
  end
@@ -32,7 +55,7 @@ module ChartMogul
32
55
  end
33
56
 
34
57
  def self.destroy_all!(data_source_uuid, customer_uuid)
35
- path = ChartMogul::ResourcePath.new('v1/data_sources/:data_source_uuid/customers/:customer_uuid/invoices')
58
+ path = ChartMogul::ResourcePath.new("v1/data_sources/:data_source_uuid/customers/:customer_uuid/invoices")
36
59
  handling_errors do
37
60
  connection.delete(path.apply(data_source_uuid: data_source_uuid, customer_uuid: customer_uuid))
38
61
  end
@@ -44,6 +67,7 @@ module ChartMogul
44
67
  private
45
68
 
46
69
  # TODO: replace with Entries concern?
70
+ # NOTE: called in the assign_all_attributes method
47
71
  def set_invoices(invoices_attributes)
48
72
  @invoices = invoices_attributes.map.with_index do |invoice_attributes, index|
49
73
  existing_invoice = invoices[index]
@@ -17,7 +17,6 @@ module ChartMogul
17
17
  writeable_attr :transaction_fees_currency
18
18
  writeable_attr :discount_description
19
19
  writeable_attr :event_order
20
-
21
20
  writeable_attr :plan_uuid
22
21
  writeable_attr :invoice_uuid
23
22
 
@@ -23,6 +23,7 @@ module ChartMogul
23
23
  writeable_attr :amount_in_cents
24
24
  writeable_attr :tax_amount_in_cents
25
25
  writeable_attr :retracted_event_id
26
+ writeable_query_param :handle_as_user_edit
26
27
 
27
28
  include API::Actions::Custom
28
29
  include API::Actions::DestroyWithParams
@@ -32,7 +33,7 @@ module ChartMogul
32
33
  end
33
34
 
34
35
  def create!
35
- custom!(:post, resource_path.path, subscription_event: instance_attributes)
36
+ custom_with_query_params!(:post, { subscription_event: instance_attributes }, :subscription_event)
36
37
  end
37
38
 
38
39
  # This endpoint requires we send the attributes as:
@@ -40,19 +41,12 @@ module ChartMogul
40
41
  # So we do not include the API::Actions::Create module here and rather use a
41
42
  # variation of the method there to accommodate this difference in behaviour.
42
43
  def self.create!(attributes)
43
- resp = handling_errors do
44
- connection.post(resource_path.path) do |req|
45
- req.headers['Content-Type'] = 'application/json'
46
- req.body = JSON.dump({ subscription_event: attributes })
47
- end
48
- end
49
- json = ChartMogul::Utils::JSONParser.parse(resp.body, immutable_keys: immutable_keys)
50
-
51
- new_from_json(json)
44
+ custom_with_query_params!(:post, { subscription_event: attributes }, :subscription_event)
52
45
  end
53
46
 
54
47
  def update!(attrs)
55
- custom!(:patch, resource_path.path, subscription_event: attrs.merge(id: instance_attributes[:id]))
48
+ custom_with_query_params!(:patch, { subscription_event: attrs.merge(id: instance_attributes[:id]) },
49
+ :subscription_event)
56
50
  end
57
51
 
58
52
  def destroy!
@@ -7,11 +7,11 @@ module ChartMogul
7
7
  set_resource_name 'Task'
8
8
  set_resource_path '/v1/tasks'
9
9
 
10
- readonly_attr :customer_uuid
11
10
  readonly_attr :task_uuid
12
11
  readonly_attr :created_at
13
12
  readonly_attr :updated_at
14
13
 
14
+ writeable_attr :customer_uuid
15
15
  writeable_attr :task_details
16
16
  writeable_attr :assignee
17
17
  writeable_attr :due_date
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ChartMogul
4
- VERSION = '4.7.0'
4
+ VERSION = '4.8.0'
5
5
  end
data/lib/chartmogul.rb CHANGED
@@ -87,6 +87,7 @@ require 'chartmogul/enrichment/customer'
87
87
 
88
88
  module ChartMogul
89
89
  API_BASE = 'https://api.chartmogul.com'
90
+
90
91
  MAX_RETRIES = 20
91
92
  CONFIG_THREAD_KEY = 'chartmogul_ruby.config'
92
93
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chartmogul-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.7.0
4
+ version: 4.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Petr Kopac
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-04-28 00:00:00.000000000 Z
11
+ date: 2025-11-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: cgi
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: pry
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -291,7 +305,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
291
305
  - !ruby/object:Gem::Version
292
306
  version: '0'
293
307
  requirements: []
294
- rubygems_version: 3.5.15
308
+ rubygems_version: 3.2.3
295
309
  signing_key:
296
310
  specification_version: 4
297
311
  summary: Chartmogul API Ruby Client