Example #1
0
            /// <summary>
            /// Calculates distribution of manual loyalty discounts across the transaction.
            /// Should be called only after other discounts are calculated.
            /// </summary>
            /// <param name="transaction">Transaction to calculate manual loyalty discounts on.</param>
            public void CalculateLoyaltyManualDiscount(SalesTransaction transaction)
            {
                if (transaction == null)
                {
                    throw new ArgumentNullException("transaction");
                }

                Discount.ClearDiscountLinesOfType(transaction, DiscountLineType.LoyaltyDiscount);

                if (transaction.LoyaltyManualDiscountAmount.HasValue)
                {
                    this.AddLoyaltyDiscAmountLines(transaction, transaction.LoyaltyManualDiscountAmount.Value);
                }
            }
Example #2
0
            /// <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 when the redeem loyalty points button is applied.
            /// </summary>
            /// <param name="transaction">The transaction receiving loyalty discount lines.</param>
            /// <param name="amountToDiscount">The amount to discount the transaction.</param>
            private void AddLoyaltyDiscAmountLines(
                SalesTransaction transaction,
                decimal amountToDiscount)
            {
                decimal totalAmtAvailableForDiscount = decimal.Zero;

                // Build a list of the discountable items with the largest value item last
                var discountableSaleItems = (from s in transaction.SalesLines
                                             where ((s.IsEligibleForDiscount() && PriceContextHelper.IsDiscountAllowed(this.priceContext, s.ItemId)) ||
                                                    s.IsLoyaltyDiscountApplied)
                                             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
                foreach (SalesLine salesLine in transaction.SalesLines.Where(sl => !sl.IsVoided))
                {
                    Discount.ClearDiscountLinesOfType(salesLine, DiscountLineType.LoyaltyDiscount);
                    SalesLineTotaller.CalculateLine(transaction, salesLine, d => this.priceContext.CurrencyAndRoundingHelper.Round(d));

                    if (salesLine.IsEligibleForDiscount() || salesLine.IsLoyaltyDiscountApplied)
                    {
                        // Calculate the total amount that is available for discount
                        totalAmtAvailableForDiscount += Math.Abs(salesLine.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 (SalesLine salesLine in discountableSaleItems)
                {
                    decimal amountToDiscountForThisItem = decimal.Zero;

                    if (salesLine != 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 = salesLine.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 discountLine;
                    if (amountToDiscountForThisItem != decimal.Zero)
                    {
                        // Add a new loyalty points discount item
                        discountLine                  = new DiscountLine();
                        discountLine.Amount           = salesLine.Quantity != 0 ? amountToDiscountForThisItem / salesLine.Quantity : amountToDiscountForThisItem;
                        discountLine.DiscountLineType = DiscountLineType.LoyaltyDiscount;

                        salesLine.DiscountLines.Add(discountLine);
                        salesLine.IsLoyaltyDiscountApplied = true;
                    }

                    SalesLineTotaller.CalculateLine(transaction, salesLine, d => this.priceContext.CurrencyAndRoundingHelper.Round(d));
                }
            }