费率的计费计算

Billing calculation of rates

Azure 费率卡 API returns 一个 MeterRates 字段(请参阅 documentation)。 Azure UsageAggregate 给出了一个数量(参见documentation)。

根据天蓝色的支持page。这是提问的论坛。

那么,如何应用电表费率?

电表费率示例:

{"0":20, "100":15, "200":10}

如果我有175的数量是100*20 + 75*15还是175*15

为什么要指定包含数量?

示例:rates:{"0":23} 包含数量 10 可以表示为费率:

{"0":0, "10":23}

example meter rates: {"0":20, "100":15, "200":10}

if I have a quantity of 175 is the amount 100*20 + 75*15 or 175*15 ?

定价为分级定价。因此,当您获得费率时,它实际上会告诉您:

  • 来自0 - 99个单元,单元率是20
  • 来自100 - 199个单元,单元率是15
  • 200个单元及以上,单元率是10

根据这个逻辑,你的计算应该是:

99 * 20 + 75 * 15 = 3105

让我困惑的一件事是上限。以上计算基于我从 Azure 计费团队收到的信息。让我感到困惑的是,如果消耗量是 99.5 个单位,会发生什么情况?对于第一个 99 个单位,它很好,但我不确定如何计算额外的 0.5 个单位。

Guarav 触及了问题的核心,这也是我将其标记为答案的原因。基于此,我设计了以下代码来实现逻辑。它分为两部分:

  1. 根据计量费率创建遗愿清单
  2. 使用存储桶列表处理数量以确定金额

以下函数创建一个桶列表(每个桶对象都是一个简单的 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;
    }

第二个函数使用具有两个有用属性的 meter 对象:存储桶列表和包含的数量。根据价目表文件(正如我所读的),在超过包含的数量之前,您不会开始计算可计费数量。我敢肯定这里可以进行一些重构,但是桶的有序处理是关键。

我认为我已经通过识别它是双精度而不是整数来解决数量问题。因此,与任何单个桶关联的数量是桶最大值和桶最小值之间的差值(除非我们只填充了部分桶)。

        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 允许我每天或每小时提取数据。我想每小时提取一次数据,这样我就可以按一天中的时间关联我的成本。但是什么时候才真正算帐合适呢?好像hourly是错误的,daily可能行,但可能只适用于整个月。

最近我刚做了这个类似的任务。以下是我的示例(我认为您可以使用正则表达式来删除这些字符,而不是像我一样使用替换)。第一个函数解析费率信息字符串生成键值对集合,第二个函数用于计算总价。

private Dictionary<float, double> GetRatesDetail(string r)
{
    Dictionary<float, double> pairs = null;
    if(string.IsNullOrEmpty(r) || r.Length <=2)
    {
        pairs = new Dictionary<float, double>();
        pairs.Add(0, 0);
    }
    else
    {
        pairs = r.Replace("{", "").Replace("}", "").Split(',')
        .Select(value => value.Split(':'))
        .ToDictionary(pair => float.Parse(pair[0].Replace("\"", "")), pair => double.Parse(pair[1]));
    }

    return pairs;
}

public decimal Process(Dictionary<float, double> rates, decimal quantity)
{
    double ret = 0;

    foreach (int key in rates.Keys.OrderByDescending(k => k))
    {
        if (quantity >= key)
        {
            ret += ((double)quantity - key) * rates[key];
            quantity = key;
        }
    }

    return (decimal)ret;
}