Analysis: read a rarely-read meter as coarse, not absent; newest rows first
ci / build-test (push) Successful in 2m41s
ci / build-test (push) Successful in 2m41s
Three things a reported Heizoel page got wrong at once. Its tank is dipped a few times a year and its burner read every few months, which is exactly the shape the coverage rules had not been walked through. "No data" for data that exists. A tank books nothing until the next dipstick closes the interval, so the stretch after the last dipstick is covered by no run at all, and a bucket no run covers was reported missing. The burner, whose run reaches into the window, said "only coarser data" -- the honest answer -- so one card claimed there was nothing while the coverage panel beside it listed years of data. A bucket that no run covers, no gap overlaps and no opening balance explains now reports the meter's resolution when its preceding coverage is within one interval of its own class: it is not silent, it is read rarely. A meter that does book its own buckets and stops -- a dead hourly source, a sheet asked about a later month -- still reads missing. Auto answering twelve months with one bar. Coarse only means "longer than a month", so a dipstick taken each autumn straddles a New Year as surely as a month start: coarsening the chart to years bought nothing and cost every point. The planning resolution now caps coarse at month when a run crosses a local year edge, and a series that cannot resolve the natural size no longer coarsens the whole chart -- it is drawn at that size with its buckets marked, which the chart and table already explain. A page contradicting itself. The comparison line above the ranking was fed the leading measure's matched coverage but worded as if it spoke for the page, directly above a burner row that did compare. It now names the figure it is about. Alongside: the "largest changes" ranking no longer drops a meter whose change is not comparable. It ranks what can be ranked, then lists the rest with their values and the reason -- the tank had been vanishing from its own energy type. And every dated table now reads newest first, as lists are read; charts stay chronological left to right, and the CSV export stays ascending for spreadsheets. A-41 to A-43 in the note record the three rules.
This commit is contained in:
@@ -200,7 +200,8 @@ public sealed class MeterDetailService
|
||||
|
||||
/// <summary>
|
||||
/// The tariffs that can price the meter — its own, its energy type's and the global ones — by component, then
|
||||
/// start date. All of them, not only those of a period: a price history is short.
|
||||
/// scope, then start date with the newest first (A-42). All of them, not only those of a period: a price history
|
||||
/// is short.
|
||||
/// </summary>
|
||||
public async Task<IReadOnlyList<TariffRow>> GetTariffsAsync(int meterId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -213,14 +214,14 @@ public sealed class MeterDetailService
|
||||
}
|
||||
|
||||
return await TariffsOf(db, meterId, typeId)
|
||||
.OrderBy(t => t.Component).ThenBy(t => t.ScopeType).ThenBy(t => t.ValidFrom)
|
||||
.OrderBy(t => t.Component).ThenBy(t => t.ScopeType).ThenByDescending(t => t.ValidFrom)
|
||||
.Select(t => new TariffRow(t.Id, t.ScopeType, t.ScopeId, t.Component, t.Value, t.Unit, t.ValidFrom, t.ValidTo))
|
||||
.ToListAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The events and tariff changes inside <paramref name="range"/> (brief §7.2 contextual markers), at most
|
||||
/// <paramref name="maxEvents"/> events.
|
||||
/// <paramref name="maxEvents"/> events. Both lists are newest first (A-42), so the cap keeps the recent ones.
|
||||
/// </summary>
|
||||
/// <param name="meterId">The meter.</param>
|
||||
/// <param name="range">The analysis range.</param>
|
||||
@@ -248,7 +249,7 @@ public sealed class MeterDetailService
|
||||
.ToListAsync(cancellationToken).ConfigureAwait(false);
|
||||
var tariffs = await TariffsOf(db, meterId, typeId)
|
||||
.Where(t => t.ValidFrom >= firstDay && t.ValidFrom <= lastDay)
|
||||
.OrderBy(t => t.ValidFrom).ThenBy(t => t.Component)
|
||||
.OrderByDescending(t => t.ValidFrom).ThenBy(t => t.Component)
|
||||
.Take(maxEvents)
|
||||
.Select(t => new TariffRow(t.Id, t.ScopeType, t.ScopeId, t.Component, t.Value, t.Unit, t.ValidFrom, t.ValidTo))
|
||||
.ToListAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
Reference in New Issue
Block a user