chartmogul-ruby 4.7.1 → 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: 80466b596764090a0a5b98d57f27ac68434832c70669946bce93db4f8bb6c5e0
4
- data.tar.gz: b67f72518317c3e8ca975752ca5ce479697bb41a4a8741e443c4503d015295c6
3
+ metadata.gz: d8bfb17b4530e13675e2958de0bc1f11f371d34d1c306cecc1947094c49d7f26
4
+ data.tar.gz: 32e700778b8f366d4d45a2e52b0105c71d28b0d23546cb3fb99e2b6d8a89063b
5
5
  SHA512:
6
- metadata.gz: af3b79f2c5556630f406ca2ecfc386a5791f391925bbc7798c6a0c60e0f9e24bfafa73f39cba5ad028a8454c01732c6cd0240e68f82e0bf2b2a7952fca208797
7
- data.tar.gz: be695715d4eebdb77f5adc68669ee5e833a9e02f84e87ee324b1a51f52ff78b41014f941a87c2a71a36050cb3eb6c0db8a5df0c45c97d2b8480dfc1ec839e078
6
+ metadata.gz: 54db5c88f38ac82440530cfdd137bfa7af53a85e66cd3d69efd6834909325cdcaafa186c53a6658fc0cef55c92d22398e78ecc59992e5e11883c29e0331ac4ce
7
+ data.tar.gz: da9b0d684ddd39e9d6adcaf98f4231452e1910828c91c24a153e1a97a6d604d0074b9e8b55a3f36957fa3ce83baecf59d5a12af43d067f31418a136540618b96
@@ -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!
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ChartMogul
4
- VERSION = '4.7.1'
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,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chartmogul-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.7.1
4
+ version: 4.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Petr Kopac
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 2025-07-25 00:00:00.000000000 Z
11
+ date: 2025-11-07 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: faraday
@@ -304,7 +305,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
304
305
  - !ruby/object:Gem::Version
305
306
  version: '0'
306
307
  requirements: []
307
- rubygems_version: 3.6.2
308
+ rubygems_version: 3.2.3
309
+ signing_key:
308
310
  specification_version: 4
309
311
  summary: Chartmogul API Ruby Client
310
312
  test_files: []