chartmogul-ruby 4.12.0 → 4.15.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.
@@ -7,6 +7,7 @@ module ChartMogul
7
7
  set_immutable_keys([:custom])
8
8
 
9
9
  readonly_attr :uuid
10
+ readonly_attr :historical_values
10
11
 
11
12
  writeable_attr :customer_uuid
12
13
  writeable_attr :data_source_uuid
@@ -20,8 +21,10 @@ module ChartMogul
20
21
  writeable_attr :linked_in
21
22
  writeable_attr :twitter
22
23
  writeable_attr :notes
24
+ writeable_attr :last_seen
23
25
  writeable_attr :external_id
24
26
  writeable_attr :custom
27
+ writeable_attr :overrides
25
28
 
26
29
  include API::Actions::Create
27
30
  include API::Actions::Custom
@@ -38,6 +41,22 @@ module ChartMogul
38
41
  true
39
42
  end
40
43
 
44
+ def tasks(options = {})
45
+ Tasks.all(options.merge(contact_uuid: uuid))
46
+ end
47
+
48
+ def create_task(options = {})
49
+ Task.create!(with_associated_object_identifier(options))
50
+ end
51
+
52
+ def entity_notes(options = {})
53
+ EntityNotes.all(options.merge(contact_uuid: uuid))
54
+ end
55
+
56
+ def create_entity_note(options = {})
57
+ EntityNote.create!(with_associated_object_identifier(options))
58
+ end
59
+
41
60
  def serialize_for_write
42
61
  super.tap do |attributes|
43
62
  attributes.clone.each do |attribute_name, attribute_value|
@@ -55,6 +74,42 @@ module ChartMogul
55
74
  attributes[:external_id] = nil if instance_variable_defined?(:@external_id) && external_id.nil?
56
75
  end
57
76
  end
77
+
78
+ # Responses echo the current override state, so only overrides assigned by
79
+ # the caller are serialized: replaying an echoed `true` flag on a later
80
+ # update! would re-protect stale in-memory values on the server. The echoed
81
+ # hash is deep-frozen and `dup` copies only the top level — request changes
82
+ # by assigning a freshly built hash, not by editing or duplicating the
83
+ # reader's result. Assigned intent is cleared by the response
84
+ # of the successful write (every write endpoint echoes `overrides`); an
85
+ # endpoint that stopped echoing would leave it set and resend it on the
86
+ # next update!.
87
+ def overrides=(value)
88
+ @overrides_requested = true
89
+ @overrides = value
90
+ end
91
+
92
+ def serialize_overrides
93
+ overrides if @overrides_requested
94
+ end
95
+
96
+ private
97
+
98
+ def set_overrides(value)
99
+ @overrides_requested = false
100
+ @overrides = freeze_nested(value)
101
+ end
102
+
103
+ def freeze_nested(value)
104
+ value.each_value { |nested| freeze_nested(nested) } if value.is_a?(Hash)
105
+ value.freeze
106
+ end
107
+
108
+ def with_associated_object_identifier(options)
109
+ return options if options[:customer_uuid] || options[:associated_object_identifier]
110
+
111
+ options.merge(associated_object_identifier: { associated_object: 'contact', method: 'uuid', value: uuid })
112
+ end
58
113
  end
59
114
 
60
115
  class Contacts < APIResource
@@ -5,7 +5,7 @@ module ChartMogul
5
5
  class Customer < APIResource
6
6
  set_resource_name 'Customer'
7
7
  set_resource_path '/v1/customers'
8
- set_immutable_keys(%i[attributes custom])
8
+ set_immutable_keys(%i[attributes custom overrides historical_values])
9
9
 
10
10
  readonly_attr :uuid
11
11
  readonly_attr :id
@@ -22,6 +22,7 @@ module ChartMogul
22
22
  readonly_attr :currency_sign
23
23
  readonly_attr :data_source_uuids
24
24
  readonly_attr :external_ids
25
+ readonly_attr :historical_values
25
26
 
26
27
  writeable_attr :attributes
27
28
  writeable_attr :external_id
@@ -38,6 +39,7 @@ module ChartMogul
38
39
  writeable_attr :owner
39
40
  writeable_attr :primary_contact
40
41
  writeable_attr :website_url
42
+ writeable_attr :overrides
41
43
 
42
44
  include API::Actions::Create
43
45
  include API::Actions::Custom
@@ -57,6 +59,22 @@ module ChartMogul
57
59
  all(external_id: external_id).first
58
60
  end
59
61
 
62
+ def self.retrieve_attributes(customer_uuid, options = {})
63
+ path = ChartMogul::ResourcePath.new("/v1/customers/#{customer_uuid}/attributes")
64
+ custom_without_assign!(:get, path.apply_with_get_params(options))
65
+ end
66
+
67
+ def self.add_tags_by_email!(email, *tags)
68
+ custom_without_assign!(:post, '/v1/customers/attributes/tags', email: email, tags: tags)
69
+ end
70
+
71
+ def self.add_custom_attributes_by_email!(email, *custom_attrs, overrides: nil, **brace_less_attr)
72
+ custom_attrs << brace_less_attr unless brace_less_attr.empty?
73
+ body = { email: email, custom: custom_attrs }
74
+ body[:overrides] = overrides if overrides
75
+ custom_without_assign!(:post, '/v1/customers/attributes/custom', body)
76
+ end
77
+
60
78
  def self.merge!(into_uuid:, from_uuid:)
61
79
  options = {
62
80
  from: { customer_uuid: from_uuid },
@@ -97,14 +115,26 @@ module ChartMogul
97
115
  Contact.create!(options.merge(customer_uuid: uuid))
98
116
  end
99
117
 
118
+ # @deprecated Use {#entity_notes} instead.
100
119
  def notes(options = {})
120
+ warn 'DEPRECATION WARNING: the method ChartMogul::Customer#notes is deprecated. Use ChartMogul::Customer#entity_notes instead.'
101
121
  Notes.all(options.merge(customer_uuid: uuid))
102
122
  end
103
123
 
124
+ # @deprecated Use {#create_entity_note} instead.
104
125
  def create_note(options = {})
126
+ warn 'DEPRECATION WARNING: the method ChartMogul::Customer#create_note is deprecated. Use ChartMogul::Customer#create_entity_note instead.'
105
127
  Note.create!(options.merge(customer_uuid: uuid))
106
128
  end
107
129
 
130
+ def entity_notes(options = {})
131
+ EntityNotes.all(options.merge(customer_uuid: uuid))
132
+ end
133
+
134
+ def create_entity_note(options = {})
135
+ EntityNote.create!(options.merge(customer_uuid: uuid))
136
+ end
137
+
108
138
  def opportunities(options = {})
109
139
  Opportnities.all(options.merge(customer_uuid: uuid))
110
140
  end
@@ -142,22 +172,49 @@ module ChartMogul
142
172
  tags: tags)[:tags]
143
173
  end
144
174
 
145
- def add_custom_attributes!(*custom_attrs)
146
- self.custom_attributes = custom_without_assign!(:post,
147
- "/v1/customers/#{uuid}/attributes/custom",
148
- custom: custom_attrs)[:custom]
175
+ # The custom attribute helpers (including .add_custom_attributes_by_email!)
176
+ # take override flags via the overrides: keyword, shaped
177
+ # { custom: { Name: true } } — unlike create!/update!, where the same flags
178
+ # nest under { attributes: { custom: { Name: true } } }. In
179
+ # update_custom_attributes!, an attribute literally named `overrides` must
180
+ # be passed in a braced hash, since the bare keyword is taken:
181
+ # update_custom_attributes!({ overrides: 'value' }) updates the attribute
182
+ # update_custom_attributes!(overrides: { ... }) sends override flags
183
+ def add_custom_attributes!(*custom_attrs, overrides: nil, **brace_less_attr)
184
+ custom_attrs << brace_less_attr unless brace_less_attr.empty?
185
+ body = { custom: custom_attrs }
186
+ body[:overrides] = overrides if overrides
187
+ response = custom_without_assign!(:post,
188
+ "/v1/customers/#{uuid}/attributes/custom",
189
+ body)
190
+ sync_custom_attribute_overrides(response)
191
+ self.custom_attributes = response[:custom]
149
192
  end
150
193
 
151
- def update_custom_attributes!(custom_attrs = {})
152
- self.custom_attributes = custom_without_assign!(:put,
153
- "/v1/customers/#{uuid}/attributes/custom",
154
- custom: custom_attrs)[:custom]
194
+ def update_custom_attributes!(custom_attrs = {}, overrides: nil, **brace_less_attrs)
195
+ body = { custom: custom_attrs.merge(brace_less_attrs) }
196
+ body[:overrides] = overrides if overrides
197
+ response = custom_without_assign!(:put,
198
+ "/v1/customers/#{uuid}/attributes/custom",
199
+ body)
200
+ sync_custom_attribute_overrides(response)
201
+ self.custom_attributes = response[:custom]
155
202
  end
156
203
 
157
- def remove_custom_attributes!(*custom_attrs)
158
- self.custom_attributes = custom_without_assign!(:delete,
159
- "/v1/customers/#{uuid}/attributes/custom",
160
- custom: custom_attrs)
204
+ def remove_custom_attributes!(*custom_attrs, overrides: nil, **brace_less_attr)
205
+ custom_attrs << brace_less_attr unless brace_less_attr.empty?
206
+ body = { custom: custom_attrs }
207
+ body[:overrides] = overrides if overrides
208
+ response = custom_without_assign!(:delete,
209
+ "/v1/customers/#{uuid}/attributes/custom",
210
+ body)
211
+ sync_custom_attribute_overrides(response)
212
+ self.custom_attributes = response[:custom]
213
+ response
214
+ end
215
+
216
+ def retrieve_attributes(options = {})
217
+ self.class.retrieve_attributes(uuid, options)
161
218
  end
162
219
 
163
220
  def merge_into!(other_customer)
@@ -178,8 +235,49 @@ module ChartMogul
178
235
  )
179
236
  end
180
237
 
238
+ # Responses echo the current override state, so only overrides assigned by
239
+ # the caller are serialized: replaying an echoed `true` flag on a later
240
+ # update! would re-protect stale in-memory values on the server. The echoed
241
+ # hash is deep-frozen and `dup` copies only the top level — request changes
242
+ # by assigning a freshly built hash, not by editing or duplicating the
243
+ # reader's result. Assigned intent is cleared by the response
244
+ # of the successful write (every write endpoint echoes `overrides`); an
245
+ # endpoint that stopped echoing would leave it set and resend it on the
246
+ # next update!.
247
+ def overrides=(value)
248
+ @overrides_requested = true
249
+ @overrides = value
250
+ end
251
+
252
+ def serialize_overrides
253
+ overrides if @overrides_requested
254
+ end
255
+
181
256
  private
182
257
 
258
+ def set_overrides(value)
259
+ @overrides_requested = false
260
+ @overrides = freeze_nested(value)
261
+ end
262
+
263
+ def freeze_nested(value)
264
+ value.each_value { |nested| freeze_nested(nested) } if value.is_a?(Hash)
265
+ value.freeze
266
+ end
267
+
268
+ # The custom attribute endpoints echo the customer's current custom
269
+ # attribute overrides, in the shape overrides[:attributes] uses. Synced
270
+ # through the read-only path so the flags are never marked for
271
+ # serialization; a pending explicitly assigned hash is not clobbered,
272
+ # keeping the serialize-exactly-once contract.
273
+ def sync_custom_attribute_overrides(response)
274
+ return if @overrides_requested || !response.key?(:overrides)
275
+
276
+ updated = (overrides || {}).reject { |key, _| key == :attributes }
277
+ updated[:attributes] = response[:overrides] unless response[:overrides].empty?
278
+ set_overrides(updated)
279
+ end
280
+
183
281
  def tags=(tags)
184
282
  @attributes[:tags] = tags
185
283
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChartMogul
4
+ class EntityNote < APIResource
5
+ set_resource_name 'EntityNote'
6
+ set_resource_path '/v1/notes'
7
+
8
+ readonly_attr :uuid
9
+ readonly_attr :associated_object
10
+ readonly_attr :associated_object_uuid
11
+ readonly_attr :author
12
+
13
+ writeable_attr :customer_uuid
14
+ writeable_attr :associated_object_identifier
15
+ writeable_attr :type
16
+ writeable_attr :text
17
+ writeable_attr :author_email
18
+ writeable_attr :call_duration
19
+ writeable_attr :created_at
20
+ writeable_attr :updated_at
21
+
22
+ include API::Actions::Create
23
+ include API::Actions::Destroy
24
+ include API::Actions::Retrieve
25
+ include API::Actions::Update
26
+
27
+ def self.all(options = {})
28
+ EntityNotes.all(options)
29
+ end
30
+ end
31
+
32
+ class EntityNotes < APIResource
33
+ set_resource_name 'EntityNotes'
34
+ set_resource_path '/v1/notes'
35
+
36
+ include Concerns::Entries
37
+ include Concerns::PageableWithCursor
38
+
39
+ set_entry_class EntityNote
40
+ end
41
+ end
@@ -23,7 +23,17 @@ module ChartMogul
23
23
  writeable_attr :due_date, type: :time
24
24
 
25
25
  include API::Actions::Retrieve
26
+ include API::Actions::Update
26
27
  include API::Actions::Destroy
28
+ include Concerns::ToggleDisabled
29
+ include Concerns::ExternalIdOperations
30
+
31
+ # Update the status of an invoice by external_id
32
+ def self.update_status!(data_source_uuid:, invoice_external_id:, status:)
33
+ path = "/v1/data_sources/#{CGI.escape(data_source_uuid)}/invoices/#{CGI.escape(invoice_external_id)}/status"
34
+ handling_errors { json_put(path, { status: status }) }
35
+ true
36
+ end
27
37
 
28
38
  def serialize_line_items
29
39
  line_items.map(&:serialize_for_write)
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChartMogul
4
+ # JsonImport resource for bulk importing data via JSON.
5
+ # Use this to efficiently upload large datasets to a data source.
6
+ class JsonImport < APIResource
7
+ set_resource_name 'JsonImport'
8
+ set_resource_path '/v1/data_sources/:data_source_uuid/json_imports'
9
+
10
+ readonly_attr :id
11
+ readonly_attr :external_id
12
+ readonly_attr :status
13
+ readonly_attr :created_at
14
+ readonly_attr :updated_at
15
+ readonly_attr :error_count
16
+ readonly_attr :processed_count
17
+
18
+ # Create a new JSON import batch for a data source
19
+ # @param data_source_uuid [String] The UUID of the data source
20
+ # @param data [Hash] The import data (customers, plans, invoices, etc.)
21
+ def self.create!(data_source_uuid:, **data)
22
+ path = "/v1/data_sources/#{data_source_uuid}/json_imports"
23
+ resp = handling_errors do
24
+ connection.post(path) do |req|
25
+ req.headers['Content-Type'] = 'application/json'
26
+ req.body = JSON.dump(data)
27
+ end
28
+ end
29
+ json = ChartMogul::Utils::JSONParser.parse(resp.body, immutable_keys:)
30
+ new_from_json(json)
31
+ end
32
+
33
+ # Retrieve the status of a JSON import
34
+ # @param data_source_uuid [String] The UUID of the data source
35
+ # @param id [String, Integer] The ID of the import
36
+ def self.retrieve(data_source_uuid:, id:)
37
+ path = "/v1/data_sources/#{data_source_uuid}/json_imports/#{id}"
38
+ resp = handling_errors do
39
+ connection.get(path)
40
+ end
41
+ json = ChartMogul::Utils::JSONParser.parse(resp.body, immutable_keys:)
42
+ new_from_json(json)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChartMogul
4
+ # Standalone LineItem resource for CRUD operations on existing line items.
5
+ # Note: For creating line items on invoices, use LineItems::Subscription or LineItems::OneTime.
6
+ class LineItem < APIResource
7
+ set_resource_name 'LineItem'
8
+ set_resource_path '/v1/line_items'
9
+
10
+ readonly_attr :uuid
11
+ readonly_attr :disabled
12
+ readonly_attr :disabled_at
13
+ readonly_attr :disabled_by
14
+ readonly_attr :invoice_uuid
15
+ readonly_attr :subscription_uuid
16
+ readonly_attr :edit_history_summary
17
+ readonly_attr :errors
18
+
19
+ writeable_attr :type
20
+ writeable_attr :subscription_external_id
21
+ writeable_attr :subscription_set_external_id
22
+ writeable_attr :plan_uuid
23
+ writeable_attr :service_period_start, type: :time
24
+ writeable_attr :service_period_end, type: :time
25
+ writeable_attr :amount_in_cents
26
+ writeable_attr :quantity
27
+ writeable_attr :discount_amount_in_cents
28
+ writeable_attr :discount_code
29
+ writeable_attr :discount_description
30
+ writeable_attr :tax_amount_in_cents
31
+ writeable_attr :transaction_fees_in_cents
32
+ writeable_attr :transaction_fees_currency
33
+ writeable_attr :external_id
34
+ writeable_attr :data_source_uuid
35
+ writeable_attr :prorated
36
+ writeable_attr :proration_type
37
+ writeable_attr :cancelled_at, type: :time
38
+ writeable_attr :description
39
+ writeable_attr :account_code
40
+ writeable_attr :event_order
41
+
42
+ include API::Actions::Retrieve
43
+ include API::Actions::Update
44
+ include API::Actions::Destroy
45
+ include Concerns::ToggleDisabled
46
+ include Concerns::ExternalIdOperations
47
+
48
+ # Create a line item for an invoice
49
+ # @param handle_as_user_edit [Boolean] If true, the change is treated as a user edit
50
+ def self.create!(invoice_uuid:, handle_as_user_edit: nil, **attributes)
51
+ path = build_query_path(
52
+ "/v1/import/invoices/#{invoice_uuid}/line_items",
53
+ handle_as_user_edit: handle_as_user_edit
54
+ )
55
+ resp = handling_errors { json_post(path, attributes) }
56
+ json = ChartMogul::Utils::JSONParser.parse(resp.body, immutable_keys:)
57
+ new_from_json(json)
58
+ end
59
+ end
60
+ end
@@ -3,6 +3,7 @@
3
3
  require 'forwardable'
4
4
 
5
5
  module ChartMogul
6
+ # @deprecated Use {ChartMogul::EntityNote} instead. /v1/customer_notes is superseded by /v1/notes.
6
7
  class Note < APIResource
7
8
  set_resource_name 'CustomerNote'
8
9
  set_resource_path '/v1/customer_notes'
@@ -23,11 +24,55 @@ module ChartMogul
23
24
  include API::Actions::Retrieve
24
25
  include API::Actions::Update
25
26
 
27
+ # @deprecated Use {ChartMogul::EntityNote.all} instead.
26
28
  def self.all(options = {})
27
29
  Notes.all(options)
28
30
  end
31
+
32
+ # @deprecated Use {ChartMogul::EntityNote.create!} instead.
33
+ def self.create!(attributes = {})
34
+ warn 'DEPRECATION WARNING: the method ChartMogul::Note.create! is deprecated. Use ChartMogul::EntityNote.create! instead.'
35
+ super
36
+ end
37
+
38
+ # @deprecated Use {ChartMogul::EntityNote.retrieve} instead.
39
+ def self.retrieve(uuid, options = {})
40
+ warn 'DEPRECATION WARNING: the method ChartMogul::Note.retrieve is deprecated. Use ChartMogul::EntityNote.retrieve instead.'
41
+ super
42
+ end
43
+
44
+ # @deprecated Use {ChartMogul::EntityNote.update!} instead.
45
+ def self.update!(uuid, attributes = {})
46
+ warn 'DEPRECATION WARNING: the method ChartMogul::Note.update! is deprecated. Use ChartMogul::EntityNote.update! instead.'
47
+ super
48
+ end
49
+
50
+ # @deprecated Use {ChartMogul::EntityNote.destroy!} instead.
51
+ def self.destroy!(options = {})
52
+ warn 'DEPRECATION WARNING: the method ChartMogul::Note.destroy! is deprecated. Use ChartMogul::EntityNote.destroy! instead.'
53
+ super
54
+ end
55
+
56
+ # @deprecated Use {ChartMogul::EntityNote#create!} instead.
57
+ def create!
58
+ warn 'DEPRECATION WARNING: the method ChartMogul::Note#create! is deprecated. Use ChartMogul::EntityNote#create! instead.'
59
+ super
60
+ end
61
+
62
+ # @deprecated Use {ChartMogul::EntityNote#update!} instead.
63
+ def update!
64
+ warn 'DEPRECATION WARNING: the method ChartMogul::Note#update! is deprecated. Use ChartMogul::EntityNote#update! instead.'
65
+ super
66
+ end
67
+
68
+ # @deprecated Use {ChartMogul::EntityNote#destroy!} instead.
69
+ def destroy!
70
+ warn 'DEPRECATION WARNING: the method ChartMogul::Note#destroy! is deprecated. Use ChartMogul::EntityNote#destroy! instead.'
71
+ super
72
+ end
29
73
  end
30
74
 
75
+ # @deprecated Use {ChartMogul::EntityNotes} instead.
31
76
  class Notes < APIResource
32
77
  set_resource_name 'CustomerNotes'
33
78
  set_resource_path '/v1/customer_notes'
@@ -36,5 +81,11 @@ module ChartMogul
36
81
  include Concerns::PageableWithCursor
37
82
 
38
83
  set_entry_class Note
84
+
85
+ # @deprecated Use {ChartMogul::EntityNotes.all} instead.
86
+ def self.all(options = {})
87
+ warn 'DEPRECATION WARNING: the method ChartMogul::Notes.all is deprecated. Use ChartMogul::EntityNotes.all instead.'
88
+ super
89
+ end
39
90
  end
40
91
  end
@@ -42,6 +42,7 @@ module ChartMogul
42
42
  end
43
43
 
44
44
  def self.all(customer_uuid, options = {})
45
+ warn 'DEPRECATION WARNING: the method ChartMogul::Subscription.all is deprecated. Use ChartMogul::Metrics::Customers::Subscriptions.all instead.'
45
46
  Subscriptions.all(customer_uuid, options)
46
47
  end
47
48
 
@@ -71,6 +72,7 @@ module ChartMogul
71
72
  set_entry_class Subscription
72
73
 
73
74
  def self.all(customer_uuid, options = {})
75
+ warn 'DEPRECATION WARNING: the method ChartMogul::Subscriptions.all is deprecated. Use ChartMogul::Metrics::Customers::Subscriptions.all instead.'
74
76
  super(options.merge(customer_uuid: customer_uuid))
75
77
  end
76
78
 
@@ -6,6 +6,8 @@ module ChartMogul
6
6
  set_resource_path '/v1/subscription_events'
7
7
 
8
8
  readonly_attr :id
9
+ readonly_attr :disabled
10
+ readonly_attr :disabled_at
9
11
  writeable_attr :data_source_uuid
10
12
  writeable_attr :customer_external_id
11
13
  writeable_attr :subscription_set_external_id
@@ -49,11 +51,71 @@ module ChartMogul
49
51
  :subscription_event)
50
52
  end
51
53
 
54
+ # Instance method: destroys this subscription event
52
55
  def destroy!
53
56
  handling_errors do
54
57
  connection.delete(resource_path.path, subscription_event: { id: instance_attributes[:id] })
55
58
  end
56
59
  end
60
+
61
+ # Class method: accepts both flat and envelope-wrapped params for backwards compatibility
62
+ # flat params. : SubscriptionEvent.destroy!(id: 123)
63
+ # envelope-wrapped params: SubscriptionEvent.destroy!(subscription_event: { id: 123 })
64
+ def self.destroy!(params = {})
65
+ body = params.key?(:subscription_event) ? params : { subscription_event: params }
66
+ handling_errors do
67
+ connection.delete(resource_path.path, body)
68
+ end
69
+ true
70
+ end
71
+
72
+ # Toggle the disabled state of a subscription event.
73
+ # Note: SubscriptionEvent uses envelope-wrapped requests/responses ({ subscription_event: ... })
74
+ # unlike other resources, because the API requires this format for this endpoint.
75
+ def toggle_disabled!(disabled:, handle_as_user_edit: nil)
76
+ path = self.class.build_query_path(
77
+ "#{resource_path.path}/#{instance_attributes[:id]}/disabled_state",
78
+ handle_as_user_edit: handle_as_user_edit
79
+ )
80
+ resp = handling_errors { self.class.json_patch(path, { disabled: disabled }) }
81
+ json = ChartMogul::Utils::JSONParser.parse(resp.body, immutable_keys: self.class.immutable_keys)
82
+ assign_all_attributes(json[:subscription_event] || json)
83
+ self
84
+ end
85
+
86
+ # Update a subscription event by data_source_uuid and external_id.
87
+ # Uses envelope-wrapped body ({ subscription_event: ... }) as required by this API endpoint.
88
+ def self.update_by_external_id!(data_source_uuid:, external_id:, handle_as_user_edit: nil, **attributes)
89
+ path = build_query_path(resource_path.path, handle_as_user_edit: handle_as_user_edit)
90
+ resp = handling_errors do
91
+ json_patch(path, { subscription_event: attributes.merge(data_source_uuid: data_source_uuid, external_id: external_id) })
92
+ end
93
+ json = ChartMogul::Utils::JSONParser.parse(resp.body, immutable_keys:)
94
+ new_from_json(json[:subscription_event] || json)
95
+ end
96
+
97
+ # Delete a subscription event by data_source_uuid and external_id
98
+ def self.destroy_by_external_id!(data_source_uuid:, external_id:, handle_as_user_edit: nil)
99
+ path = build_query_path(resource_path.path, handle_as_user_edit: handle_as_user_edit)
100
+ handling_errors do
101
+ connection.delete(path, subscription_event: { data_source_uuid: data_source_uuid, external_id: external_id })
102
+ end
103
+ true
104
+ end
105
+
106
+ # Toggle disabled state of a subscription event by data_source_uuid and external_id.
107
+ # Uses envelope-wrapped body ({ subscription_event: ... }) as required by this API endpoint.
108
+ def self.toggle_disabled_by_external_id!(data_source_uuid:, external_id:, disabled:, handle_as_user_edit: nil)
109
+ path = build_query_path("#{resource_path.path}/disabled_state", handle_as_user_edit: handle_as_user_edit)
110
+ resp = handling_errors do
111
+ json_patch(path, {
112
+ subscription_event: { data_source_uuid: data_source_uuid, external_id: external_id },
113
+ disabled: disabled
114
+ })
115
+ end
116
+ json = ChartMogul::Utils::JSONParser.parse(resp.body, immutable_keys:)
117
+ new_from_json(json[:subscription_event] || json)
118
+ end
57
119
  end
58
120
 
59
121
  class SubscriptionEvents < APIResource
@@ -8,10 +8,13 @@ module ChartMogul
8
8
  set_resource_path '/v1/tasks'
9
9
 
10
10
  readonly_attr :task_uuid
11
+ readonly_attr :associated_object
12
+ readonly_attr :associated_object_uuid
11
13
  readonly_attr :created_at
12
14
  readonly_attr :updated_at
13
15
 
14
16
  writeable_attr :customer_uuid
17
+ writeable_attr :associated_object_identifier
15
18
  writeable_attr :task_details
16
19
  writeable_attr :assignee
17
20
  writeable_attr :due_date
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChartMogul
4
+ # Standalone Transaction resource for CRUD operations on existing transactions.
5
+ # Note: For creating transactions on invoices, use Transactions::Payment or Transactions::Refund.
6
+ class Transaction < APIResource
7
+ set_resource_name 'Transaction'
8
+ set_resource_path '/v1/transactions'
9
+
10
+ readonly_attr :uuid
11
+ readonly_attr :disabled
12
+ readonly_attr :disabled_at
13
+ readonly_attr :disabled_by
14
+ readonly_attr :invoice_uuid
15
+ readonly_attr :edit_history_summary
16
+ readonly_attr :errors
17
+
18
+ writeable_attr :type
19
+ writeable_attr :date, type: :time
20
+ writeable_attr :result
21
+ writeable_attr :external_id
22
+ writeable_attr :data_source_uuid
23
+ writeable_attr :amount_in_cents
24
+ writeable_attr :transaction_fees_in_cents
25
+ writeable_attr :transaction_fees_currency
26
+
27
+ include API::Actions::Retrieve
28
+ include API::Actions::Update
29
+ include API::Actions::Destroy
30
+ include Concerns::ToggleDisabled
31
+ include Concerns::ExternalIdOperations
32
+ end
33
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ChartMogul
4
- VERSION = '4.12.0'
4
+ VERSION = '4.15.0'
5
5
  end