/// <summary> /// Applies a discount to an order by reducing product prices. /// </summary> /// <param name="products">The order on which to apply a discount.</param> /// <param name="discount">The amount to deduct from the products.</param> /// <returns>Returns the amount of unused discount.</returns> public static decimal ApplyDiscount(this IList <ProcessOrderProduct> products, decimal discount) { products.CheckNotNull(nameof(products)); discount.CheckRange(nameof(discount), min: 0); var edited = false; while (discount > 0 && GetProductWithPrice(out var product)) { if (product.Quantity > 1) { // Split product so we edit the price of only 1 item. product.Quantity--; product = new ProcessOrderProduct(product.Name, product.Price); products.Add(product); } var reduce = Math.Min(discount, product.Price); product.Price -= reduce; discount -= reduce; edited = true; } if (edited) { GroupDuplicates(products); } return(discount); bool GetProductWithPrice(out ProcessOrderProduct product) { product = products.FirstOrDefault(x => x.Price > 0); return(product != null); } }
/// <summary> /// Returns the list of products to settle due payments. /// </summary> /// <param name="contact">The contact to create the bill for.</param> /// <param name="planList">The list of due payment plans.</param> /// <param name="currentDate">The current date, ensuring all calculations are done using the exact same date.</param> /// <param name="deduct">An amount to deduct from the order, such as account credits.</param> /// <returns>The list of products to pay.</returns> public IList <ProcessOrderProduct> GetBillProducts(ApiCustomContact contact, IEnumerable <ApiPaymentPlan> planList, DateTimeOffset currentDate) { contact.CheckNotNull(nameof(contact)); planList.CheckNotNull(nameof(planList)); var products = new List <ProcessOrderProduct>(); // Don't bill trials until something has been paid. foreach (var plan in planList.Where(x => contact.HasPaidHealingTechnologies == true || x.PeriodUnit != PaymentPeriodUnit.MonthPostpaidTrial)) { //var isTrialExpired = ((currentDate - (plan.StartDate ?? plan.DateAdded!.Value)).TotalDays > (plan.PeriodQty ?? _config.Value.DefaultTrialDays)) var qty = CalcPeriodQty(plan, currentDate); if (qty > 0) { // Apply TransactionsLeft. //var maxQty = plan.TransactionsLeft ?? (plan.PeriodUnit == PaymentPeriodUnit.MonthPostpaid || plan.PeriodUnit == PaymentPeriodUnit.MonthPostpaidTrial ? (int?)null : 1); //if (maxQty != null && qty > maxQty) //{ // qty = maxQty.Value; //} // Add product to cart. var product = new ProcessOrderProduct(plan.ProductName ?? string.Empty); if ((qty % 1) == 0) { product.Quantity = (int)qty; product.Price = plan.PricePerPeriod ?? 0; } else { product.Quantity = 1; product.Price = Math.Round((plan.PricePerPeriod ?? 0) * qty, 2); } products.Add(product); } } return(products.GroupDuplicates()); }