Guarav 是问题的核心,这也是我将其标记为答案的原因。基于此,我设计了以下代码来实现逻辑。它分为两部分:
- 从计量费率创建一个桶列表
- 使用存储桶列表处理数量以确定数量
以下函数创建一个桶列表(每个桶对象是一个简单的 POCO,具有 Min、Max 和 Rate 属性)。该列表附加到具有来自费率卡 api 的其他属性的仪表对象。
private Dictionary<int, RateBucket> ParseRateBuckets(string rates)
{
dynamic dRates = JsonConvert.DeserializeObject(rates);
var rateContainer = (JContainer)dRates;
var buckets = new Dictionary<int, RateBucket>();
var bucketNumber = 0;
foreach (var jToken in rateContainer.Children())
{
var jProperty = jToken as JProperty;
if (jProperty != null)
{
var bucket = new RateBucket
{
Min = Convert.ToDouble(jProperty.Name),
Rate = Convert.ToDouble(jProperty.Value.ToString())
};
if (bucketNumber > 0)
buckets[bucketNumber - 1].Max = bucket.Min;
buckets.Add(bucketNumber, bucket);
}
bucketNumber++;
}
return buckets;
}
第二个函数使用具有两个有用属性的仪表对象:桶列表和包含的数量。根据价目表文档(正如我所读),您在超过包含的数量之前不会开始计算可计费数量。我确信这里可以进行一些重构,但是桶的有序处理是关键。
我想我已经通过认识到它是双精度而不是整数来解决数量问题。因此,与任何单个桶相关联的数量是桶最大值和桶最小值之间的差异(除非我们只填充了部分桶)。
private double CalculateUsageCost(RateCardMeter meter, double quantity)
{
var amount = 0.0;
quantity -= meter.IncludedQuantity;
if (quantity > 0)
{
for (var i = 0; i < meter.RateBuckets.Count; i++)
{
var bucket = meter.RateBuckets[i];
if (quantity > bucket.Min)
{
if (bucket.Max.HasValue && quantity > bucket.Max)
amount += (bucket.Max.Value - bucket.Min)*bucket.Rate;
else
amount += (quantity - bucket.Min)*bucket.Rate;
}
}
}
return amount;
}
最后,文档并不清楚这些层的时间范围。如果我根据数量获得折扣价,我在什么时间范围内汇总数量?使用 api 允许我每天或每小时提取数据。我想每小时提取一次数据,这样我就可以按一天中的时间关联我的成本。但是什么时候适合实际计算账单呢?似乎每小时是错误的,每天可能有效,但它可能只适合整个月。