killbill-aviate 2.4.1.pre.1 → 2.4.1.pre.3

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: a03c9fbf0ae747d2accce4e819edb24433676609f46680b890223ce3cd89246f
4
- data.tar.gz: 37970b56d1c29958a87006f0e7b62a9d665bcca49f585dca71780ca0173728e7
3
+ metadata.gz: 668e8f43e5ab2c7c9c617b13e6e741b355613950f64e850682174001f93ac03c
4
+ data.tar.gz: b8eaa6d33bd8029125ca1ecb6e78d6c29902730c15a75ecf74498814b2f78ef3
5
5
  SHA512:
6
- metadata.gz: bdee42559069177e241a5617bfedb9ce15c9e2315d17c9e757a48b51da4649ed149e1cdcdd80a8b57600698097579a2f3bb3f63d4ffc3dbdc0852c986a97625f
7
- data.tar.gz: 032f003efb1423053ed5185ff5bc614cf6b391351d8aae9040cf43809aad2e1fceaf913805da184bae7d873e4dedc488f51ddae281567f7d221c7c646bd5a9eb
6
+ metadata.gz: 57a7d1d3458d82f0891c67a3a243bc9a45b679a67e53c17703059d3a2e49454f5dd77a12fc4211f63a6492d94f2080eb5fd92e79e229b2facf68fabb83f6b29a
7
+ data.tar.gz: d4ecb9bad5c487cab51f82912a6daaabd424ad996d2a4d6fdd52ed2857371523c32ffa7dd9247a7676902056826a1d6ad71c016afa33362d0840b50100531e49
@@ -47,15 +47,24 @@
47
47
  return result.concat(element.values);
48
48
  }, []);
49
49
 
50
- var x_domain = d3.extent(allValues, function (d) {
51
- return d.x;
52
- });
53
- self.x.domain(x_domain);
54
-
55
- var y_domain = d3.extent(allValues, function (d) {
56
- return d.y;
57
- });
58
- self.y.domain(y_domain);
50
+ // X domain: union of billing period bounds and actual data so that data
51
+ // points recorded just before the period start (e.g. on the charge date)
52
+ // remain visible.
53
+ var period_start = json.period_start ? helper.parseDate(json.period_start) : null;
54
+ var period_end = json.period_end ? helper.parseDate(json.period_end) : null;
55
+ var x_values = allValues.map(function (d) { return d.x; });
56
+ if (period_start) x_values.push(period_start);
57
+ if (period_end) x_values.push(period_end);
58
+ self.x.domain(d3.extent(x_values));
59
+
60
+ // Y domain: always start at 0 and use nice() for clean tick values.
61
+ var y_max = d3.max(allValues, function (d) { return d.y; }) || 1;
62
+ self.y.domain([0, y_max]).nice();
63
+
64
+ // Cap y-axis tick count to the domain max so integer formatting never
65
+ // produces duplicate labels (e.g. [0,3] with 10 ticks → "0,0,1,1,2,2,3").
66
+ var y_domain_max = self.y.domain()[1];
67
+ axes.y.ticks(Math.min(y_domain_max, 10));
59
68
 
60
69
  // Render axes
61
70
  axes.render(svg);
@@ -112,6 +121,17 @@
112
121
  yOffset += 22;
113
122
  });
114
123
 
124
+ // Extend each series to the right edge of the x domain so the cumulative
125
+ // step line is always visible — d3.curveStepAfter needs at least two points
126
+ // to produce a visible line segment; a single point produces only a move.
127
+ var x_domain_end = self.x.domain()[1];
128
+ datasets.forEach(function (dataset) {
129
+ var vals = dataset.values;
130
+ if (vals.length > 0 && vals[vals.length - 1].x < x_domain_end) {
131
+ vals.push({ x: x_domain_end, y: vals[vals.length - 1].y });
132
+ }
133
+ });
134
+
115
135
  // Render data lines (stepped)
116
136
  datasets.forEach(function (dataset) {
117
137
  var data = dataset.values,
@@ -49,7 +49,7 @@ module Aviate
49
49
  @wallet_balance = fetch_wallet_balance(@account_id, cached_options)
50
50
 
51
51
  # Build chart JSON for the view
52
- @chart_json = build_chart_json(@chart_data)
52
+ @chart_json = build_chart_json(@chart_data, start_date, end_date)
53
53
  end
54
54
 
55
55
  private
@@ -190,14 +190,17 @@ module Aviate
190
190
  chart_data
191
191
  end
192
192
 
193
- def build_chart_json(chart_data)
193
+ def build_chart_json(chart_data, period_start = nil, period_end = nil)
194
194
  return nil if chart_data.empty?
195
195
 
196
196
  series = chart_data.map do |unit_type, values|
197
197
  { 'name' => unit_type, 'values' => values }
198
198
  end
199
199
 
200
- { 'type' => 'TIMELINE', 'data' => series }.to_json
200
+ json = { 'type' => 'TIMELINE', 'data' => series }
201
+ json['period_start'] = period_start.to_s if period_start
202
+ json['period_end'] = period_end.to_s if period_end
203
+ json.to_json
201
204
  end
202
205
 
203
206
  def fetch_accrued_cost(account_id, cached_options)
data/lib/aviate/client.rb CHANGED
@@ -22,6 +22,9 @@ module Killbill
22
22
  # Returns true if the account/subscription is billed via an Aviate catalog (as opposed to a
23
23
  # standard XML one). Any error (plugin not installed, missing/invalid JWT, network issue, etc.)
24
24
  # is treated as "not Aviate" so callers can safely fall back to the standard catalog behavior.
25
+ #
26
+ # JWT authentication is handled by build_request_options, which sets the Authorization header
27
+ # from options[:jwt_token] when present (populated from the session cookie by EngineController).
25
28
  def aviate_catalog?(account_id, options = nil)
26
29
  path = "#{KILLBILL_AVIATE_PREFIX}/catalog/info"
27
30
  request_options = build_request_options(options)
@@ -36,6 +39,7 @@ module Killbill
36
39
  # Aviate catalogs record usage against a billing meter code rather than a standard
37
40
  # catalog unit type, so this must be used instead of the plain KillBillClient catalog/phase
38
41
  # lookup whenever `aviate_catalog?` is true.
42
+ # JWT authentication is handled by build_request_options (see aviate_catalog? above).
39
43
  def billing_meter_codes_for_plan(plan_name, account_id, options = nil)
40
44
  return [] if plan_name.blank?
41
45
 
@@ -167,15 +171,32 @@ module Killbill
167
171
  def parse_csv_response(body)
168
172
  return [] if body.nil? || body.strip.empty?
169
173
 
170
- require 'csv'
171
- rows = CSV.parse(body, headers: true)
172
- rows.map do |row|
173
- {
174
- date: row['timestamp']&.strip,
175
- value: row['value']&.strip&.to_f
176
- }
174
+ # The host_samples endpoint returns a JSON array. Each element has a
175
+ # "samples" field with usage data serialized as flat comma-separated
176
+ # timestamp/value pairs: "ts1,val1,ts2,val2,..." (observed format).
177
+ # Newlines, if ever present, are normalized to commas before parsing.
178
+ parsed = JSON.parse(body)
179
+ return [] unless parsed.is_a?(Array)
180
+
181
+ result = []
182
+ parsed.each do |entry|
183
+ samples_str = entry['samples']
184
+ next if samples_str.nil? || samples_str.strip.empty?
185
+
186
+ tokens = samples_str.tr("\n", ',').split(',').map(&:strip).reject(&:empty?)
187
+ tokens.each_slice(2) do |ts_str, val_str|
188
+ next if ts_str.nil? || val_str.nil?
189
+
190
+ ts = ts_str.to_i
191
+ next if ts.zero?
192
+
193
+ date = Time.at(ts).utc.strftime('%Y-%m-%dT%H:%M:%S')
194
+ result << { date: date, value: val_str.to_f }
195
+ end
177
196
  end
178
- rescue CSV::MalformedCSVError
197
+
198
+ result
199
+ rescue StandardError
179
200
  []
180
201
  end
181
202
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Aviate
4
- VERSION = '2.4.1.pre.1'
4
+ VERSION = '2.4.1.pre.3'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: killbill-aviate
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.1.pre.1
4
+ version: 2.4.1.pre.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kill Bill core team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-10 00:00:00.000000000 Z
11
+ date: 2026-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: killbill-assets-ui