schematichq 1.4.4 → 1.4.5

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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/.fern/metadata.json +2 -2
  3. data/.fern/replay.lock +501 -2
  4. data/lib/schematic/client.rb +1 -1
  5. data/lib/schematic/credits/client.rb +0 -104
  6. data/lib/schematic/plangroups/types/create_plan_group_request_body.rb +3 -0
  7. data/lib/schematic/plangroups/types/update_plan_group_request_body.rb +3 -0
  8. data/lib/schematic/plans/types/publish_plan_version_request_body.rb +0 -1
  9. data/lib/schematic/plans/types/retry_custom_plan_billing_request_body.rb +0 -1
  10. data/lib/schematic/types/billing_credit_grant_zeroed_out_reason.rb +1 -0
  11. data/lib/schematic/types/change_subscription_internal_request_body.rb +1 -0
  12. data/lib/schematic/types/change_subscription_request_body.rb +1 -0
  13. data/lib/schematic/types/checkout_settings_response_data.rb +3 -0
  14. data/lib/schematic/types/feature_entitlement.rb +2 -0
  15. data/lib/schematic/types/plan_change_response_data.rb +1 -0
  16. data/lib/schematic/types/preview_subscription_change_response_data.rb +3 -0
  17. data/lib/schematic/types/rulesengine_feature_entitlement.rb +2 -0
  18. data/lib/schematic/version.rb +1 -1
  19. data/lib/schematic.rb +3 -11
  20. data/reference.md +92 -252
  21. metadata +2 -10
  22. data/lib/schematic/credits/types/count_credit_ledger_params.rb +0 -19
  23. data/lib/schematic/credits/types/count_credit_ledger_request.rb +0 -18
  24. data/lib/schematic/credits/types/count_credit_ledger_response.rb +0 -12
  25. data/lib/schematic/credits/types/get_enriched_credit_ledger_params.rb +0 -19
  26. data/lib/schematic/credits/types/get_enriched_credit_ledger_request.rb +0 -18
  27. data/lib/schematic/credits/types/get_enriched_credit_ledger_response.rb +0 -12
  28. data/lib/schematic/types/credit_ledger_enriched_entry_response_data.rb +0 -30
  29. data/lib/schematic/types/credit_ledger_period.rb +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: beede11cf31a32d41acacecfcf43f24d415952cc1bfc02ae762593885d804030
4
- data.tar.gz: ca42025157214fcc6b06ce6313ce591ed78d7f9e49f033f6aad432dcef691097
3
+ metadata.gz: 85d9efb3046014492cb89dee9ca47427babf900a5738b4d2ebef375b014668c6
4
+ data.tar.gz: a3d972bc92e02315a9dba121231a4715e28704f1442f8f271177a0f1ce2f5779
5
5
  SHA512:
6
- metadata.gz: f36aa806e79e4dc3c547fd9580b021f616c1b187c659eb7f0784e28983cc5a1bf74f6c32b32edbca0234d0df3372b34aefb6974c0f2e21a059c6bfd56e91682d
7
- data.tar.gz: e8fb63d038eedf92d7fd992b18cd94931d599abe632640cb44b482eada7161392c8a373e18494b44c5acfbba3909ef1b4b61d3120763538630d68c0ceb9a7105
6
+ metadata.gz: df77700f492d8ed2fc5dc9ba25722864ab60d995761a3c142966560ca66cfb230e117a5f51f17b713cde545a487d419731a70c77761dc0d0a2d06dc099c6037d
7
+ data.tar.gz: e99075d5f93882c41af77da371fac5d3b28b225979f5acf78b3438f9a42d4b6694543e62c1892c1a05b93b8aec0d39b4bdbdcf12e63754f6add9533292bc066b
data/.fern/metadata.json CHANGED
@@ -13,6 +13,6 @@
13
13
  "webrick": ">= 1.0"
14
14
  }
15
15
  },
16
- "originGitCommit": "ad1cc528e658e3693935b819c9d22eed02d49017",
17
- "sdkVersion": "1.4.4"
16
+ "originGitCommit": "786b643cc0bf17aff1114597108246b5cf8af395",
17
+ "sdkVersion": "1.4.5"
18
18
  }
data/.fern/replay.lock CHANGED
@@ -6,5 +6,504 @@ generations:
6
6
  timestamp: 2026-05-19T19:48:36.665Z
7
7
  cli_version: unknown
8
8
  generator_versions: {}
9
- current_generation: 298b1d0ee88b6637d99742bff32b353cfbd5b32e
10
- patches: []
9
+ - commit_sha: 0dd219c7b903329d9db2fb5b9fb570f2fd6e1a39
10
+ tree_hash: 7a0aadd77d8091d4846b0968fc36d335be98a66d
11
+ timestamp: 2026-06-08T18:13:52.357Z
12
+ cli_version: unknown
13
+ generator_versions:
14
+ fernapi/fern-ruby-sdk: 1.1.13
15
+ current_generation: 0dd219c7b903329d9db2fb5b9fb570f2fd6e1a39
16
+ patches:
17
+ - id: patch-6a2db2b5
18
+ content_hash: sha256:630a8c3df9ae971e973e4dcb3d71d0d9f28b8da9877b0ff27ff3cca2a1eb924a
19
+ original_commit: 6a2db2b584601e13f90302155d37a22e45542fab
20
+ original_message: handle partial messages properly
21
+ original_author: Christopher Brady <chris@schematichq.com>
22
+ base_generation: e75de47f4e4f08f8e683366dd9b3936bc5c6452f
23
+ files:
24
+ - lib/schematic/datastream/merge.rb
25
+ patch_content: |
26
+ diff --git a/lib/schematic/datastream/merge.rb b/lib/schematic/datastream/merge.rb
27
+ index 0ab68fe..7f1084d 100644
28
+ --- a/lib/schematic/datastream/merge.rb
29
+ +++ b/lib/schematic/datastream/merge.rb
30
+ @@ -16,25 +16,42 @@ module Schematic
31
+ COMPANY_MAP_FIELDS = %i[credit_balances keys traits].freeze
32
+ COMPANY_ARRAY_FIELDS = %i[billing_product_ids entitlements plan_ids plan_version_ids rules].freeze
33
+
34
+ + # Partials don't carry refreshed entitlements, so when their derived
35
+ + # fields change in another part of the company we sync them here to match
36
+ + # server behavior (see schematic-python merge.partial_company):
37
+ + # - credit_remaining <- credit_balances[credit_id]
38
+ + # - usage <- metric value matching (event_name, metric_period, month_reset)
39
+ + # Both are skipped when the partial also sends entitlements wholesale.
40
+ def partial_company(existing, partial_data)
41
+ return existing unless partial_data.is_a?(Hash)
42
+
43
+ result = deep_copy(existing)
44
+ + entitlements_in_partial = partial_data.key?(:entitlements) || partial_data.key?("entitlements")
45
+ + updated_balances = nil
46
+ + metrics_updated = false
47
+
48
+ partial_data.each do |key, value|
49
+ sym_key = key.to_sym
50
+ if COMPANY_MAP_FIELDS.include?(sym_key)
51
+ result[sym_key] ||= {}
52
+ result[sym_key] = result[sym_key].merge(value) if value.is_a?(Hash)
53
+ + updated_balances = (value.is_a?(Hash) ? value : {}) if sym_key == :credit_balances
54
+ elsif COMPANY_ARRAY_FIELDS.include?(sym_key)
55
+ result[sym_key] = value if value.is_a?(Array)
56
+ elsif sym_key == :metrics
57
+ result[sym_key] = upsert_metrics(result[sym_key] || [], value || [])
58
+ + metrics_updated = true
59
+ else
60
+ result[sym_key] = value
61
+ end
62
+ end
63
+
64
+ + if (updated_balances || metrics_updated) && !entitlements_in_partial
65
+ + result[:entitlements] = sync_entitlements(
66
+ + result[:entitlements], result[:metrics], updated_balances, metrics_updated
67
+ + )
68
+ + end
69
+ +
70
+ result
71
+ end
72
+
73
+ @@ -90,6 +107,60 @@ module Schematic
74
+ def get_metric_field(metric, field)
75
+ metric[field] || metric[field.to_s]
76
+ end
77
+ +
78
+ + # Re-derive entitlement usage / credit_remaining from the merged metrics
79
+ + # and the just-updated credit balances. Mirrors schematic-python so that
80
+ + # entitlement usage reflects DataStream track events immediately.
81
+ + def sync_entitlements(entitlements, metrics, updated_balances, metrics_updated)
82
+ + return entitlements unless entitlements.is_a?(Array) && !entitlements.empty?
83
+ +
84
+ + metrics_lookup = {}
85
+ + if metrics_updated && metrics.is_a?(Array)
86
+ + metrics.each do |metric|
87
+ + next unless metric.is_a?(Hash)
88
+ +
89
+ + key = [
90
+ + get_metric_field(metric, :event_subtype) || "",
91
+ + get_metric_field(metric, :period) || "",
92
+ + get_metric_field(metric, :month_reset) || ""
93
+ + ]
94
+ + value = get_metric_field(metric, :value)
95
+ + metrics_lookup[key] = value.nil? ? 0 : value
96
+ + end
97
+ + end
98
+ +
99
+ + entitlements.map do |ent|
100
+ + next ent unless ent.is_a?(Hash)
101
+ +
102
+ + new_ent = deep_copy(ent)
103
+ +
104
+ + credit_id = get_metric_field(ent, :credit_id)
105
+ + if updated_balances && credit_id
106
+ + present, balance = fetch_balance(updated_balances, credit_id)
107
+ + new_ent[:credit_remaining] = balance if present
108
+ + end
109
+ +
110
+ + event_name = get_metric_field(ent, :event_name)
111
+ + unless metrics_lookup.empty? || event_name.nil?
112
+ + period = get_metric_field(ent, :metric_period) || "all_time"
113
+ + month_reset = get_metric_field(ent, :month_reset) || "first_of_month"
114
+ + matched = metrics_lookup[[event_name, period, month_reset]]
115
+ + new_ent[:usage] = matched unless matched.nil?
116
+ + end
117
+ +
118
+ + new_ent
119
+ + end
120
+ + end
121
+ +
122
+ + # credit_balances keys may be symbols (deep_copy symbolizes) while an
123
+ + # entitlement's credit_id is always a string, so check both forms.
124
+ + def fetch_balance(balances, credit_id)
125
+ + return [true, balances[credit_id]] if balances.key?(credit_id)
126
+ + return [true, balances[credit_id.to_sym]] if balances.key?(credit_id.to_sym)
127
+ + return [true, balances[credit_id.to_s]] if balances.key?(credit_id.to_s)
128
+ +
129
+ + [false, nil]
130
+ + end
131
+ end
132
+ end
133
+ end
134
+ theirs_snapshot:
135
+ lib/schematic/datastream/merge.rb: |
136
+ # frozen_string_literal: true
137
+
138
+ require "json"
139
+
140
+ module Schematic
141
+ module DataStream
142
+ module Merge
143
+ module_function
144
+
145
+ def deep_copy(obj)
146
+ JSON.parse(JSON.generate(obj), symbolize_names: true)
147
+ rescue StandardError
148
+ obj.dup
149
+ end
150
+
151
+ COMPANY_MAP_FIELDS = %i[credit_balances keys traits].freeze
152
+ COMPANY_ARRAY_FIELDS = %i[billing_product_ids entitlements plan_ids plan_version_ids rules].freeze
153
+
154
+ # Partials don't carry refreshed entitlements, so when their derived
155
+ # fields change in another part of the company we sync them here to match
156
+ # server behavior (see schematic-python merge.partial_company):
157
+ # - credit_remaining <- credit_balances[credit_id]
158
+ # - usage <- metric value matching (event_name, metric_period, month_reset)
159
+ # Both are skipped when the partial also sends entitlements wholesale.
160
+ def partial_company(existing, partial_data)
161
+ return existing unless partial_data.is_a?(Hash)
162
+
163
+ result = deep_copy(existing)
164
+ entitlements_in_partial = partial_data.key?(:entitlements) || partial_data.key?("entitlements")
165
+ updated_balances = nil
166
+ metrics_updated = false
167
+
168
+ partial_data.each do |key, value|
169
+ sym_key = key.to_sym
170
+ if COMPANY_MAP_FIELDS.include?(sym_key)
171
+ result[sym_key] ||= {}
172
+ result[sym_key] = result[sym_key].merge(value) if value.is_a?(Hash)
173
+ updated_balances = (value.is_a?(Hash) ? value : {}) if sym_key == :credit_balances
174
+ elsif COMPANY_ARRAY_FIELDS.include?(sym_key)
175
+ result[sym_key] = value if value.is_a?(Array)
176
+ elsif sym_key == :metrics
177
+ result[sym_key] = upsert_metrics(result[sym_key] || [], value || [])
178
+ metrics_updated = true
179
+ else
180
+ result[sym_key] = value
181
+ end
182
+ end
183
+
184
+ if (updated_balances || metrics_updated) && !entitlements_in_partial
185
+ result[:entitlements] = sync_entitlements(
186
+ result[:entitlements], result[:metrics], updated_balances, metrics_updated
187
+ )
188
+ end
189
+
190
+ result
191
+ end
192
+
193
+ USER_MAP_FIELDS = %i[keys traits].freeze
194
+
195
+ def partial_user(existing, partial_data)
196
+ return existing unless partial_data.is_a?(Hash)
197
+
198
+ result = deep_copy(existing)
199
+
200
+ partial_data.each do |key, value|
201
+ sym_key = key.to_sym
202
+ if USER_MAP_FIELDS.include?(sym_key)
203
+ result[sym_key] ||= {}
204
+ result[sym_key] = result[sym_key].merge(value) if value.is_a?(Hash)
205
+ elsif sym_key == :rules
206
+ result[sym_key] = value if value.is_a?(Array)
207
+ else
208
+ result[sym_key] = value
209
+ end
210
+ end
211
+
212
+ result
213
+ end
214
+
215
+ def upsert_metrics(existing, incoming)
216
+ return incoming if existing.nil? || existing.empty?
217
+ return existing if incoming.nil? || incoming.empty?
218
+
219
+ result = existing.map { |metric| deep_copy(metric) }
220
+
221
+ incoming.each do |inc_metric|
222
+ match_idx = result.index do |ex|
223
+ metrics_match?(ex, inc_metric)
224
+ end
225
+
226
+ if match_idx
227
+ result[match_idx] = inc_metric
228
+ else
229
+ result << inc_metric
230
+ end
231
+ end
232
+
233
+ result
234
+ end
235
+
236
+ def metrics_match?(left, right)
237
+ get_metric_field(left, :event_subtype) == get_metric_field(right, :event_subtype) &&
238
+ get_metric_field(left, :period) == get_metric_field(right, :period) &&
239
+ get_metric_field(left, :month_reset) == get_metric_field(right, :month_reset)
240
+ end
241
+
242
+ def get_metric_field(metric, field)
243
+ metric[field] || metric[field.to_s]
244
+ end
245
+
246
+ # Re-derive entitlement usage / credit_remaining from the merged metrics
247
+ # and the just-updated credit balances. Mirrors schematic-python so that
248
+ # entitlement usage reflects DataStream track events immediately.
249
+ def sync_entitlements(entitlements, metrics, updated_balances, metrics_updated)
250
+ return entitlements unless entitlements.is_a?(Array) && !entitlements.empty?
251
+
252
+ metrics_lookup = {}
253
+ if metrics_updated && metrics.is_a?(Array)
254
+ metrics.each do |metric|
255
+ next unless metric.is_a?(Hash)
256
+
257
+ key = [
258
+ get_metric_field(metric, :event_subtype) || "",
259
+ get_metric_field(metric, :period) || "",
260
+ get_metric_field(metric, :month_reset) || ""
261
+ ]
262
+ value = get_metric_field(metric, :value)
263
+ metrics_lookup[key] = value.nil? ? 0 : value
264
+ end
265
+ end
266
+
267
+ entitlements.map do |ent|
268
+ next ent unless ent.is_a?(Hash)
269
+
270
+ new_ent = deep_copy(ent)
271
+
272
+ credit_id = get_metric_field(ent, :credit_id)
273
+ if updated_balances && credit_id
274
+ present, balance = fetch_balance(updated_balances, credit_id)
275
+ new_ent[:credit_remaining] = balance if present
276
+ end
277
+
278
+ event_name = get_metric_field(ent, :event_name)
279
+ unless metrics_lookup.empty? || event_name.nil?
280
+ period = get_metric_field(ent, :metric_period) || "all_time"
281
+ month_reset = get_metric_field(ent, :month_reset) || "first_of_month"
282
+ matched = metrics_lookup[[event_name, period, month_reset]]
283
+ new_ent[:usage] = matched unless matched.nil?
284
+ end
285
+
286
+ new_ent
287
+ end
288
+ end
289
+
290
+ # credit_balances keys may be symbols (deep_copy symbolizes) while an
291
+ # entitlement's credit_id is always a string, so check both forms.
292
+ def fetch_balance(balances, credit_id)
293
+ return [true, balances[credit_id]] if balances.key?(credit_id)
294
+ return [true, balances[credit_id.to_sym]] if balances.key?(credit_id.to_sym)
295
+ return [true, balances[credit_id.to_s]] if balances.key?(credit_id.to_s)
296
+
297
+ [false, nil]
298
+ end
299
+ end
300
+ end
301
+ end
302
+ status: unresolved
303
+ - id: patch-46462128
304
+ content_hash: sha256:94f06e4e687a0908d3f305a4d605d9dc1271db6ed83014a10b86be900187dd83
305
+ original_commit: 46462128cacb25b73fac7770060cf427ff0d9e6d
306
+ original_message: add tests and address nits
307
+ original_author: Christopher Brady <chris@schematichq.com>
308
+ base_generation: e75de47f4e4f08f8e683366dd9b3936bc5c6452f
309
+ files:
310
+ - lib/schematic/datastream/merge.rb
311
+ patch_content: |
312
+ diff --git a/lib/schematic/datastream/merge.rb b/lib/schematic/datastream/merge.rb
313
+ index 7f1084d..f4dd4e5 100644
314
+ --- a/lib/schematic/datastream/merge.rb
315
+ +++ b/lib/schematic/datastream/merge.rb
316
+ @@ -46,7 +46,7 @@ module Schematic
317
+ end
318
+ end
319
+
320
+ - if (updated_balances || metrics_updated) && !entitlements_in_partial
321
+ + if (updated_balances&.any? || metrics_updated) && !entitlements_in_partial
322
+ result[:entitlements] = sync_entitlements(
323
+ result[:entitlements], result[:metrics], updated_balances, metrics_updated
324
+ )
325
+ @@ -152,12 +152,12 @@ module Schematic
326
+ end
327
+ end
328
+
329
+ - # credit_balances keys may be symbols (deep_copy symbolizes) while an
330
+ - # entitlement's credit_id is always a string, so check both forms.
331
+ + # The partial's credit_balances may be keyed by string or symbol depending
332
+ + # on how the message was parsed, while an entitlement's credit_id is a
333
+ + # string value, so check both key forms.
334
+ def fetch_balance(balances, credit_id)
335
+ return [true, balances[credit_id]] if balances.key?(credit_id)
336
+ return [true, balances[credit_id.to_sym]] if balances.key?(credit_id.to_sym)
337
+ - return [true, balances[credit_id.to_s]] if balances.key?(credit_id.to_s)
338
+
339
+ [false, nil]
340
+ end
341
+ theirs_snapshot:
342
+ lib/schematic/datastream/merge.rb: |
343
+ # frozen_string_literal: true
344
+
345
+ require "json"
346
+
347
+ module Schematic
348
+ module DataStream
349
+ module Merge
350
+ module_function
351
+
352
+ def deep_copy(obj)
353
+ JSON.parse(JSON.generate(obj), symbolize_names: true)
354
+ rescue StandardError
355
+ obj.dup
356
+ end
357
+
358
+ COMPANY_MAP_FIELDS = %i[credit_balances keys traits].freeze
359
+ COMPANY_ARRAY_FIELDS = %i[billing_product_ids entitlements plan_ids plan_version_ids rules].freeze
360
+
361
+ # Partials don't carry refreshed entitlements, so when their derived
362
+ # fields change in another part of the company we sync them here to match
363
+ # server behavior (see schematic-python merge.partial_company):
364
+ # - credit_remaining <- credit_balances[credit_id]
365
+ # - usage <- metric value matching (event_name, metric_period, month_reset)
366
+ # Both are skipped when the partial also sends entitlements wholesale.
367
+ def partial_company(existing, partial_data)
368
+ return existing unless partial_data.is_a?(Hash)
369
+
370
+ result = deep_copy(existing)
371
+ entitlements_in_partial = partial_data.key?(:entitlements) || partial_data.key?("entitlements")
372
+ updated_balances = nil
373
+ metrics_updated = false
374
+
375
+ partial_data.each do |key, value|
376
+ sym_key = key.to_sym
377
+ if COMPANY_MAP_FIELDS.include?(sym_key)
378
+ result[sym_key] ||= {}
379
+ result[sym_key] = result[sym_key].merge(value) if value.is_a?(Hash)
380
+ updated_balances = (value.is_a?(Hash) ? value : {}) if sym_key == :credit_balances
381
+ elsif COMPANY_ARRAY_FIELDS.include?(sym_key)
382
+ result[sym_key] = value if value.is_a?(Array)
383
+ elsif sym_key == :metrics
384
+ result[sym_key] = upsert_metrics(result[sym_key] || [], value || [])
385
+ metrics_updated = true
386
+ else
387
+ result[sym_key] = value
388
+ end
389
+ end
390
+
391
+ if (updated_balances&.any? || metrics_updated) && !entitlements_in_partial
392
+ result[:entitlements] = sync_entitlements(
393
+ result[:entitlements], result[:metrics], updated_balances, metrics_updated
394
+ )
395
+ end
396
+
397
+ result
398
+ end
399
+
400
+ USER_MAP_FIELDS = %i[keys traits].freeze
401
+
402
+ def partial_user(existing, partial_data)
403
+ return existing unless partial_data.is_a?(Hash)
404
+
405
+ result = deep_copy(existing)
406
+
407
+ partial_data.each do |key, value|
408
+ sym_key = key.to_sym
409
+ if USER_MAP_FIELDS.include?(sym_key)
410
+ result[sym_key] ||= {}
411
+ result[sym_key] = result[sym_key].merge(value) if value.is_a?(Hash)
412
+ elsif sym_key == :rules
413
+ result[sym_key] = value if value.is_a?(Array)
414
+ else
415
+ result[sym_key] = value
416
+ end
417
+ end
418
+
419
+ result
420
+ end
421
+
422
+ def upsert_metrics(existing, incoming)
423
+ return incoming if existing.nil? || existing.empty?
424
+ return existing if incoming.nil? || incoming.empty?
425
+
426
+ result = existing.map { |metric| deep_copy(metric) }
427
+
428
+ incoming.each do |inc_metric|
429
+ match_idx = result.index do |ex|
430
+ metrics_match?(ex, inc_metric)
431
+ end
432
+
433
+ if match_idx
434
+ result[match_idx] = inc_metric
435
+ else
436
+ result << inc_metric
437
+ end
438
+ end
439
+
440
+ result
441
+ end
442
+
443
+ def metrics_match?(left, right)
444
+ get_metric_field(left, :event_subtype) == get_metric_field(right, :event_subtype) &&
445
+ get_metric_field(left, :period) == get_metric_field(right, :period) &&
446
+ get_metric_field(left, :month_reset) == get_metric_field(right, :month_reset)
447
+ end
448
+
449
+ def get_metric_field(metric, field)
450
+ metric[field] || metric[field.to_s]
451
+ end
452
+
453
+ # Re-derive entitlement usage / credit_remaining from the merged metrics
454
+ # and the just-updated credit balances. Mirrors schematic-python so that
455
+ # entitlement usage reflects DataStream track events immediately.
456
+ def sync_entitlements(entitlements, metrics, updated_balances, metrics_updated)
457
+ return entitlements unless entitlements.is_a?(Array) && !entitlements.empty?
458
+
459
+ metrics_lookup = {}
460
+ if metrics_updated && metrics.is_a?(Array)
461
+ metrics.each do |metric|
462
+ next unless metric.is_a?(Hash)
463
+
464
+ key = [
465
+ get_metric_field(metric, :event_subtype) || "",
466
+ get_metric_field(metric, :period) || "",
467
+ get_metric_field(metric, :month_reset) || ""
468
+ ]
469
+ value = get_metric_field(metric, :value)
470
+ metrics_lookup[key] = value.nil? ? 0 : value
471
+ end
472
+ end
473
+
474
+ entitlements.map do |ent|
475
+ next ent unless ent.is_a?(Hash)
476
+
477
+ new_ent = deep_copy(ent)
478
+
479
+ credit_id = get_metric_field(ent, :credit_id)
480
+ if updated_balances && credit_id
481
+ present, balance = fetch_balance(updated_balances, credit_id)
482
+ new_ent[:credit_remaining] = balance if present
483
+ end
484
+
485
+ event_name = get_metric_field(ent, :event_name)
486
+ unless metrics_lookup.empty? || event_name.nil?
487
+ period = get_metric_field(ent, :metric_period) || "all_time"
488
+ month_reset = get_metric_field(ent, :month_reset) || "first_of_month"
489
+ matched = metrics_lookup[[event_name, period, month_reset]]
490
+ new_ent[:usage] = matched unless matched.nil?
491
+ end
492
+
493
+ new_ent
494
+ end
495
+ end
496
+
497
+ # The partial's credit_balances may be keyed by string or symbol depending
498
+ # on how the message was parsed, while an entitlement's credit_id is a
499
+ # string value, so check both key forms.
500
+ def fetch_balance(balances, credit_id)
501
+ return [true, balances[credit_id]] if balances.key?(credit_id)
502
+ return [true, balances[credit_id.to_sym]] if balances.key?(credit_id.to_sym)
503
+
504
+ [false, nil]
505
+ end
506
+ end
507
+ end
508
+ end
509
+ status: unresolved
@@ -10,7 +10,7 @@ module Schematic
10
10
  @raw_client = Schematic::Internal::Http::RawClient.new(
11
11
  base_url: base_url || Schematic::Environment::DEFAULT,
12
12
  headers: {
13
- "User-Agent" => "schematichq/1.4.4",
13
+ "User-Agent" => "schematichq/1.4.5",
14
14
  "X-Fern-Language" => "Ruby",
15
15
  "X-Schematic-Api-Key" => api_key.to_s
16
16
  }
@@ -849,110 +849,6 @@ module Schematic
849
849
  end
850
850
  end
851
851
 
852
- # @param request_options [Hash]
853
- # @param params [Hash]
854
- # @option request_options [String] :base_url
855
- # @option request_options [Hash{String => Object}] :additional_headers
856
- # @option request_options [Hash{String => Object}] :additional_query_parameters
857
- # @option request_options [Hash{String => Object}] :additional_body_parameters
858
- # @option request_options [Integer] :timeout_in_seconds
859
- # @option params [String] :company_id
860
- # @option params [String, nil] :billing_credit_id
861
- # @option params [String, nil] :feature_id
862
- # @option params [Schematic::Types::CreditLedgerPeriod] :period
863
- # @option params [String, nil] :start_time
864
- # @option params [String, nil] :end_time
865
- # @option params [Integer, nil] :limit
866
- # @option params [Integer, nil] :offset
867
- #
868
- # @return [Schematic::Credits::Types::GetEnrichedCreditLedgerResponse]
869
- def get_enriched_credit_ledger(request_options: {}, **params)
870
- params = Schematic::Internal::Types::Utils.normalize_keys(params)
871
- query_param_names = %i[company_id billing_credit_id feature_id period start_time end_time limit offset]
872
- query_params = {}
873
- query_params["company_id"] = params[:company_id] if params.key?(:company_id)
874
- query_params["billing_credit_id"] = params[:billing_credit_id] if params.key?(:billing_credit_id)
875
- query_params["feature_id"] = params[:feature_id] if params.key?(:feature_id)
876
- query_params["period"] = params[:period] if params.key?(:period)
877
- query_params["start_time"] = params[:start_time] if params.key?(:start_time)
878
- query_params["end_time"] = params[:end_time] if params.key?(:end_time)
879
- query_params["limit"] = params[:limit] if params.key?(:limit)
880
- query_params["offset"] = params[:offset] if params.key?(:offset)
881
- params.except(*query_param_names)
882
-
883
- request = Schematic::Internal::JSON::Request.new(
884
- base_url: request_options[:base_url],
885
- method: "GET",
886
- path: "billing/credits/ledger",
887
- query: query_params,
888
- request_options: request_options
889
- )
890
- begin
891
- response = @client.send(request)
892
- rescue Net::HTTPRequestTimeout
893
- raise Schematic::Errors::TimeoutError
894
- end
895
- code = response.code.to_i
896
- if code.between?(200, 299)
897
- Schematic::Credits::Types::GetEnrichedCreditLedgerResponse.load(response.body)
898
- else
899
- error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
900
- raise error_class.new(response.body, code: code)
901
- end
902
- end
903
-
904
- # @param request_options [Hash]
905
- # @param params [Hash]
906
- # @option request_options [String] :base_url
907
- # @option request_options [Hash{String => Object}] :additional_headers
908
- # @option request_options [Hash{String => Object}] :additional_query_parameters
909
- # @option request_options [Hash{String => Object}] :additional_body_parameters
910
- # @option request_options [Integer] :timeout_in_seconds
911
- # @option params [String] :company_id
912
- # @option params [String, nil] :billing_credit_id
913
- # @option params [String, nil] :feature_id
914
- # @option params [Schematic::Types::CreditLedgerPeriod] :period
915
- # @option params [String, nil] :start_time
916
- # @option params [String, nil] :end_time
917
- # @option params [Integer, nil] :limit
918
- # @option params [Integer, nil] :offset
919
- #
920
- # @return [Schematic::Credits::Types::CountCreditLedgerResponse]
921
- def count_credit_ledger(request_options: {}, **params)
922
- params = Schematic::Internal::Types::Utils.normalize_keys(params)
923
- query_param_names = %i[company_id billing_credit_id feature_id period start_time end_time limit offset]
924
- query_params = {}
925
- query_params["company_id"] = params[:company_id] if params.key?(:company_id)
926
- query_params["billing_credit_id"] = params[:billing_credit_id] if params.key?(:billing_credit_id)
927
- query_params["feature_id"] = params[:feature_id] if params.key?(:feature_id)
928
- query_params["period"] = params[:period] if params.key?(:period)
929
- query_params["start_time"] = params[:start_time] if params.key?(:start_time)
930
- query_params["end_time"] = params[:end_time] if params.key?(:end_time)
931
- query_params["limit"] = params[:limit] if params.key?(:limit)
932
- query_params["offset"] = params[:offset] if params.key?(:offset)
933
- params.except(*query_param_names)
934
-
935
- request = Schematic::Internal::JSON::Request.new(
936
- base_url: request_options[:base_url],
937
- method: "GET",
938
- path: "billing/credits/ledger/count",
939
- query: query_params,
940
- request_options: request_options
941
- )
942
- begin
943
- response = @client.send(request)
944
- rescue Net::HTTPRequestTimeout
945
- raise Schematic::Errors::TimeoutError
946
- end
947
- code = response.code.to_i
948
- if code.between?(200, 299)
949
- Schematic::Credits::Types::CountCreditLedgerResponse.load(response.body)
950
- else
951
- error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
952
- raise error_class.new(response.body, code: code)
953
- end
954
- end
955
-
956
852
  # @param request_options [Hash]
957
853
  # @param params [Hash]
958
854
  # @option request_options [String] :base_url
@@ -16,6 +16,9 @@ module Schematic
16
16
  field :fallback_plan_id, -> { String }, optional: true, nullable: false
17
17
  field :initial_plan_id, -> { String }, optional: true, nullable: false
18
18
  field :initial_plan_price_id, -> { String }, optional: true, nullable: false
19
+ field :opt_in_enabled, -> { Internal::Types::Boolean }, optional: false, nullable: false
20
+ field :opt_in_text, -> { String }, optional: true, nullable: false
21
+ field :opt_in_title, -> { String }, optional: true, nullable: false
19
22
  field :ordered_add_ons, -> { Internal::Types::Array[Schematic::Types::OrderedPlansInGroup] }, optional: false, nullable: false
20
23
  field :ordered_bundle_list, -> { Internal::Types::Array[Schematic::Types::PlanGroupBundleOrder] }, optional: false, nullable: false
21
24
  field :ordered_plans, -> { Internal::Types::Array[Schematic::Types::OrderedPlansInGroup] }, optional: false, nullable: false
@@ -17,6 +17,9 @@ module Schematic
17
17
  field :fallback_plan_id, -> { String }, optional: true, nullable: false
18
18
  field :initial_plan_id, -> { String }, optional: true, nullable: false
19
19
  field :initial_plan_price_id, -> { String }, optional: true, nullable: false
20
+ field :opt_in_enabled, -> { Internal::Types::Boolean }, optional: false, nullable: false
21
+ field :opt_in_text, -> { String }, optional: true, nullable: false
22
+ field :opt_in_title, -> { String }, optional: true, nullable: false
20
23
  field :ordered_add_ons, -> { Internal::Types::Array[Schematic::Types::OrderedPlansInGroup] }, optional: false, nullable: false
21
24
  field :ordered_bundle_list, -> { Internal::Types::Array[Schematic::Types::PlanGroupBundleOrder] }, optional: false, nullable: false
22
25
  field :ordered_plans, -> { Internal::Types::Array[Schematic::Types::OrderedPlansInGroup] }, optional: false, nullable: false
@@ -10,7 +10,6 @@ module Schematic
10
10
  field :days_until_due, -> { Integer }, optional: true, nullable: false
11
11
  field :excluded_company_ids, -> { Internal::Types::Array[String] }, optional: false, nullable: false
12
12
  field :migration_strategy, -> { Schematic::Types::PlanVersionMigrationStrategy }, optional: false, nullable: false
13
- field :pay_in_advance, -> { Internal::Types::Array[Schematic::Types::UpdatePayInAdvanceRequestBody] }, optional: false, nullable: false
14
13
  end
15
14
  end
16
15
  end