创建动态优惠券检查器

时间:2018-07-05 18:42:15

标签: c# algorithm while-loop

我正在尝试创建优惠券计数器,以检查可用于减少发票的可组合优惠券的可用性。

如果可用的优惠券等于所需的优惠券,则不需要发票。

示例:

XYZ公司需要为发票支付100美元(金额始终可以除以0,剩下的25除),但是他们可以使用优惠券付款。

一张优惠券价值25美元,所以我需要检查公司是否在动态选择的月份内保存了4张。

我的优惠券表如下:

总优惠券计数

  • ID
  • CompanyID
  • 总优惠券计数
  • 年份

示例续:

XYZ公司3月有0张优惠券,4月1日,5月0日,6月2日,7月1日有优惠券。

XYZ公司最多可以保存3个月的优惠券(因此优惠券可以是5月,6月,7月)

该示例的结果必须为:

已使用3张优惠券(6月2日,7月1日),客户仍需支付25美元。

我的程序需要做的是

  • 获取公司可以保存优惠券的月数(在这种情况下为3)

  • 减去优惠券,直到它们为0

  • 获取其余发票并将其显示给用户

这是我现在拥有的代码:

        //While the needed amount of coupons for the invoice is smaller than the total available coupons 
        while(neededCoupons < cv.combinableAmount)
        {
            //We start at the earliest month we can go back to (this month - the combinable months)
            for (int i = int.Parse(DateTime.Now.AddMonths(DateTime.Now.Month - cv.monthsCombinable).ToString()); i >= int.Parse(DateTime.Now.Month.ToString()) ; i++ )
            {
                int amountForMonth = GetCouponAmountByMonth(companyID, i);
                if (amountForMonth >= neededCoupons)
                {
                    //The amount is enough, we can stop
                    Result += "Coupons used from " + new DateTime(DateTime.Now.Year, i, 1).ToString("MMMM") + " amount: " + amountForMonth;
                    //To save the data, we subtract the neededCoupons from that month 
                    SubtractCoupons(companyID, i, amountForMonth);
                }
                else
                {
                    //The amount for that month is not enough (or zero), we need to subtract it, get the remaining and continue to the following month) 
                    if (amountForMonth != 0)
                    {
                        SubtractCoupons(companyID, i, amountForMonth);
                        Result += "Coupons used from " + new DateTime(DateTime.Now.Year, i, 1).ToString("MMMM") + " amount: " + amountForMonth;
                        neededCoupons = neededCoupons - amountForMonth;
                    }
                }
            }

我还没有测试我的代码,但是我知道我没有走正确的路,因为我没有考虑以下因素:

  • 如果所有优惠券均已使用且仍需要付款,则为最低价值
  • 我的代码将于明年一月开始工作吗?
  • 我的while循环,我应该继续循环直到我有足够的凭单(当然没有)

我认为我快到了。我只是想知道如何实现一个rest变量,以检查骑行结束时是否所有优惠券都已用完,仍然需要付款。

2 个答案:

答案 0 :(得分:3)

为了帮助生成和打印发票,我创建了以下两个模型:

public class Invoice
{
    public int TotalCouponsNeeded { get; set; }
    public int UsedCouponCount { get; set; }
    public List<UsedCouponsForMonth> UsedCoupons { get; set; }

    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();
        if (UsedCouponCount == 0)
        {
            sb.Append("0 coupons have been used");
        }
        else
        {
            sb.AppendFormat("{0} have been used ({1})",
                    UsedCouponCount,
                    String.Join(", ", UsedCoupons.Select(x => String.Format("{0} in {1:MMM yyyy}", x.Count, new DateTime(x.Year, x.Month, 1))))
                );
        }
        sb.AppendFormat(", {0} dollars still needs to be paid by client.", 25 * (TotalCouponsNeeded - UsedCouponCount));
        return sb.ToString();
    }       
}

public class UsedCouponsForMonth
{
    public int Month { get; set; }
    public int Year { get; set; }
    public int Count { get; set; }
}

Invoice包含需要多少张优惠券以及使用了多少张。它还知道如何以所需的格式打印自己。

生成发票的算法如下:

public Invoice GenerateInvoice(int companyId, int maxMonths, int couponsNeeded)
{
    Invoice invoice = new Invoice
    {
        TotalCouponsNeeded = couponsNeeded,
        UsedCouponCount = 0,
        UsedCoupons = new List<UsedCouponsForMonth>(),
    };

    for (int i = 0; i < maxMonths && invoice.UsedCouponCount < invoice.TotalCouponsNeeded; i++)
    {
        DateTime month = DateTime.Now.AddMonths(i - maxMonths + 1);
        int availableForMonth = GetCouponAmountByMonth(companyId, month.Year, month.Month);
        if (availableForMonth <= 0)
        {
            continue;
        }
        int usedThisMonth = (invoice.UsedCouponCount + availableForMonth < invoice.TotalCouponsNeeded)
            ? availableForMonth
            : (couponsNeeded - invoice.UsedCouponCount);
        invoice.UsedCouponCount += usedThisMonth;
        SubtractCoupons(companyId, month.Year, month.Month, usedThisMonth);
    }

    return invoice;
}

想法是从最早的月份开始,使用GetCouponAmountByMonth检查可用优惠券的数量,并根据需要使用SubtractCoupons减去它们。注意,我修改了这些函数以将yearmonth用作输入。同时,在invoice.UsedCouponCount变量中跟踪优惠券的总数。当使用的计数等于所需的数量时,循环会自动中断。

答案 1 :(得分:2)

我制作了一些与问题对应的类,然后是一个经理,该经理可以获取最旧的有效凭单,然后从未使用的有效凭单计算发票金额。您可以更改优惠券有效的月数,并且代码会根据需要做出反应。

public class Company
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public List<Coupon> Coupons { get; set; }
        public Company()
        {
            Coupons = new List<Coupon>();
        }
    }
    public class Coupon
    {
        public bool IsUsed { get; set; }
        public double Amount { get; set; }
        public DateTime Date { get; set; }
    }



public static class CouponManager
    {
        public const int MONTHS_BACK = 3;

        /// <summary>
        /// Returns all coupons within X months not used by the company
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        public static List<Coupon> GetValidCoupons(Company c)
        {
            return c.Coupons.Where(
                t => !t.IsUsed &&
            (Math.Abs((DateTime.Now.Month - t.Date.Month) + 12 * (DateTime.Now.Year - t.Date.Year))<   MONTHS_BACK))
            .OrderBy(t=>t.Date).ToList();
        }
        /// <summary>
        /// Find valid coupons, subtract from invoice each coupon amount until invoice is 0
        /// </summary>
        /// <param name="company"></param>
        /// <param name="invoice"></param>
        /// <returns></returns>
        public static double CalculateInvoice(Company company, double invoice)
        {
            double amountOwed = invoice;
            List<Coupon> coupons = GetValidCoupons(company);
            coupons.ForEach(c => {
                if(invoice <= 0) //we are done with coupons
                    { return; }
                if (c.Amount > invoice) //no credits to give
                { return; }
                invoice = invoice - c.Amount; //subtract amount from invoice
                c.IsUsed = true; //mark coupon as used then update in db later
            });
            return invoice;
        }
        public static Company GetMockedCompany()
        {
            //mock data
            Company myCompany = new Company();
            bool used = false;
            for (int i = 0; i < 215; i++)
            {
                Coupon c = new Coupon();
                c.Date = DateTime.Now.AddDays(-i);
                c.Amount = 5.00;
                c.IsUsed = used;
                used = !used;
                myCompany.Coupons.Add(c);
                Coupon d = new Coupon();
                d.Date = DateTime.Now.AddDays(-i * 4);
                d.Amount = 5.00;
                d.IsUsed = used;
                used = !used;
                myCompany.Coupons.Add(d);
            }
            return myCompany;
        }
    }

然后您可以通过模拟的公司测试例程,如下所示:

 double invoice = CouponManager.CalculateInvoice(CouponManager.GetMockedCompany(), 1400); //returns 1070