Guarav は問題の核心に到達し、それが私がそれを回答としてマークした理由です。それに基づいて、ロジックを実装するために次のコードを考案しました。次の 2 つの部分に分かれます。
- 従量料金からのバケット リストの作成
- バケット リストを使用して数量を処理し、金額を決定する
次の関数は、バケットのリストを作成します (各バケット オブジェクトは、Min、Max、および Rate プロパティを持つ単純な POCO です)。このリストは、料金表 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;
}
2 番目の関数は、バケット リストと含まれる数量という 2 つの便利なプロパティを持つ meter オブジェクトを使用します。レートカードのドキュメント(私が読んだとき)によると、含まれている数量を超えるまで、請求可能な数量のカウントを開始しません。ここで実行できるリファクタリングがあると確信していますが、バケットの順序付けされた処理が重要なポイントです。
整数ではなく倍精度であることを認識することで、数量に関する問題に対処したと思います。したがって、1 つのバケットに関連付けられた数量は、バケットの最大値とバケットの最小値の差です (部分的なバケットしか満たしていない場合を除く)。
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 を使用すると、毎日または毎時間データを取得できます。1 時間ごとにコストを関連付けるために、1 時間ごとにデータを取得したいと考えています。しかし、請求額を実際に計算するのはいつが適切なのでしょうか? 毎時は間違っているようです。