internal static void ClearDiscountLinesOfType(SalesLine salesLine, DiscountLineType lineType) { var remainingDiscounts = salesLine.DiscountLines.Where(l => l.DiscountLineType != lineType).ToList(); salesLine.DiscountLines.Clear(); foreach (var discount in remainingDiscounts) { salesLine.DiscountLines.Add(discount); } if (lineType == DiscountLineType.PeriodicDiscount) { salesLine.PeriodicDiscountPossibilities.Clear(); salesLine.QuantityDiscounted = 0; } }
private static void ClearDiscountLinesOfType(SalesLine salesLine, DiscountLineType lineType) { var remainingDiscounts = salesLine.DiscountLines.Where(l => l.DiscountLineType != lineType).ToList(); salesLine.DiscountLines.Clear(); foreach (var discount in remainingDiscounts) { salesLine.DiscountLines.Add(discount); } if (lineType == DiscountLineType.PeriodicDiscount) { salesLine.PeriodicDiscountPossibilities.Clear(); salesLine.QuantityDiscounted = 0; } if (lineType == DiscountLineType.CustomerDiscount) { salesLine.LineMultilineDiscOnItem = LineMultilineDiscountOnItem.None; } }
/// <summary> /// This method will distribute the amountToDiscount across all the sale items in the transaction /// proportionally except for the line item with the largest amount. The remainder will be distributed /// to the line item with the largest amount to ensure the amount to discount is exactly applied. /// This method currently works for either the customer discount or when the total discount button is applied. /// </summary> /// <param name="transaction">The transaction receiving total discount lines.</param> /// <param name="discountType">Whether this discount is for a customer or for the total discount item.</param> /// <param name="amountToDiscount">The amount to discount the transaction.</param> private void AddTotalDiscAmountLines( SalesTransaction transaction, DiscountLineType discountType, decimal amountToDiscount) { decimal totalAmtAvailableForDiscount = decimal.Zero; // Build a list of the discountable items with the largest value item last. // Consider calculable lines only. Ignore voided or return-by-receipt lines. var discountableSaleItems = (from s in transaction.PriceCalculableSalesLines where s.IsEligibleForDiscount() && s.Quantity > 0 && PriceContextHelper.IsDiscountAllowed(this.priceContext, s.ItemId) orderby Math.Abs(s.NetAmount), s.LineId select s).ToList(); // Iterate through all non voided items whether we are going to discount or not so that they get added // back to the totals // Consider calculable lines only. Ignore voided or return-by-receipt lines. foreach (var saleItem in transaction.PriceCalculableSalesLines) { // We can clear the discount line for total discount because a total manual amount discount // will override a total manual percent discount, whereas customer discount can have both // amount and percentage applied simultaneously. if (discountType == DiscountLineType.ManualDiscount) { Discount.ClearManualDiscountLinesOfType(saleItem, ManualDiscountType.TotalDiscountAmount); Discount.ClearManualDiscountLinesOfType(saleItem, ManualDiscountType.TotalDiscountPercent); } SalesLineTotaller.CalculateLine(transaction, saleItem, d => this.priceContext.CurrencyAndRoundingHelper.Round(d)); if (saleItem.IsEligibleForDiscount() && saleItem.Quantity > 0) { // Calculate the total amount that is available for discount totalAmtAvailableForDiscount += Math.Abs(saleItem.NetAmountWithAllInclusiveTax); } } // Calculate the percentage (as a fraction) that we should attempt to discount each discountable item // to reach the total. decimal discountFactor = totalAmtAvailableForDiscount != decimal.Zero ? (amountToDiscount / totalAmtAvailableForDiscount) : decimal.Zero; decimal totalAmtDistributed = decimal.Zero; // Iterate through all discountable items. foreach (var saleItem in discountableSaleItems) { decimal amountToDiscountForThisItem = decimal.Zero; if (saleItem != discountableSaleItems.Last()) { // for every item except for the last in the list (which will have the largest value) // discount by the rounded amount that is closest to the percentage desired for the transaction decimal itemPrice = saleItem.NetAmount; amountToDiscountForThisItem = this.priceContext.CurrencyAndRoundingHelper.Round(discountFactor * Math.Abs(itemPrice)); totalAmtDistributed += amountToDiscountForThisItem; } else { // Discount the last item by the remainder to ensure that the exact desired discount is applied amountToDiscountForThisItem = amountToDiscount - totalAmtDistributed; } DiscountLine discountItem; if (amountToDiscountForThisItem != decimal.Zero) { if (discountType == DiscountLineType.ManualDiscount) { // Add a new total discount item discountItem = new DiscountLine(); discountItem.DiscountLineType = DiscountLineType.ManualDiscount; discountItem.ManualDiscountType = ManualDiscountType.TotalDiscountAmount; saleItem.DiscountLines.Add(discountItem); } else { // for customer discounts we need to either update the existing one, or add a new one. discountItem = GetCustomerDiscountItem(saleItem, CustomerDiscountType.TotalDiscount, DiscountLineType.CustomerDiscount); } discountItem.Amount = saleItem.Quantity != 0 ? amountToDiscountForThisItem / saleItem.Quantity : amountToDiscountForThisItem; } SalesLineTotaller.CalculateLine(transaction, saleItem, d => this.priceContext.CurrencyAndRoundingHelper.Round(d)); } }
/// <summary> /// Retrieves a customer discount item of the indicated type if it exists and creates one if not. /// </summary> /// <param name="salesLine">The sales line from which to find customer discount lines.</param> /// <param name="customerDiscountType">The customer discount type.</param> /// <param name="lineDiscountType">The line discount type.</param> /// <returns> /// The discount line. /// </returns> private static DiscountLine GetCustomerDiscountItem(SalesLine salesLine, CustomerDiscountType customerDiscountType, DiscountLineType lineDiscountType) { DiscountLine discount; var discounts = from d in salesLine.DiscountLines where d.DiscountLineType == lineDiscountType && d.CustomerDiscountType == customerDiscountType select d; // If the discount doesn't exist create a new one if (discounts.Count() == 0) { discount = new DiscountLine { DiscountLineType = lineDiscountType, CustomerDiscountType = customerDiscountType, }; salesLine.DiscountLines.Add(discount); } else { // otherwise select it. discount = discounts.First(); } return(discount); }
public DiscountLine(DiscountLineType type) { Type = type.ToString().ToLower(); }