/// <summary>
            /// Executes the workflow to fetch the promotions.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>The response.</returns>
            protected override GetPromotionsResponse Process(GetPromotionsRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.Null(request.CartId, "request.CartId");

                // Get the current instance of the transaction from the database.
                SalesTransaction transaction = CartWorkflowHelper.LoadSalesTransaction(this.Context, request.CartId);

                if (transaction == null)
                {
                    return(new GetPromotionsResponse(null));
                }

                ThrowIf.Null(transaction, "transaction");

                // Calculate totals on the current instance of transaction.
                CartWorkflowHelper.Calculate(this.Context, transaction, CalculationModes.All);

                // The discount lines on this transaction are the discount lines that have been applied.
                SalesTransaction currentSalesTransaction = transaction.Clone <SalesTransaction>();

                Cart cart = CartWorkflowHelper.ConvertToCart(this.Context, currentSalesTransaction);

                CartWorkflowHelper.RemoveHistoricalTenderLines(cart);

                // The discount lines on the transaction are all available discount lines for the items.
                CartWorkflowHelper.LoadAllPeriodicDiscounts(this.Context, currentSalesTransaction);
                SalesTransaction tempSalesTransaction = transaction.Clone <SalesTransaction>();

                transaction = currentSalesTransaction.Clone <SalesTransaction>();

                Collection <string>            cartPromotionLines = new Collection <string>();
                Collection <CartLinePromotion> cartLinePromotions = new Collection <CartLinePromotion>();

                for (int i = 0; i < currentSalesTransaction.SalesLines.Count; i++)
                {
                    // Removing the applied discount lines, except multiple buy because a different discount level of the already applied multi buy discount can be promoted.
                    foreach (DiscountLine discountLine in currentSalesTransaction.SalesLines[i].DiscountLines)
                    {
                        tempSalesTransaction.SalesLines[i].DiscountLines.Remove(tempSalesTransaction.SalesLines[i].DiscountLines.Where(j => j.OfferId == discountLine.OfferId).SingleOrDefault());
                    }

                    // Removing the discounts that require coupon code.
                    // Removing the discount offers those were not applied (because of concurrency rules).
                    // Removing mix and match discounts (mix and match discounts are not shown as promotions).
                    List <DiscountLine> offerDiscountLines = tempSalesTransaction.SalesLines[i].DiscountLines.Where(j => (j.PeriodicDiscountType == PeriodicDiscountOfferType.Offer) || j.IsDiscountCodeRequired || (j.PeriodicDiscountType == PeriodicDiscountOfferType.MixAndMatch)).ToList();
                    foreach (DiscountLine discountLine in offerDiscountLines)
                    {
                        tempSalesTransaction.SalesLines[i].DiscountLines.Remove(discountLine);
                    }

                    PricingDataManager pricingDataManager = new PricingDataManager(this.Context);

                    // Quantity discounts.
                    // Finding all the quantity discounts that will be applied to the cart.
                    List <DiscountLine> quantityDiscountLines = tempSalesTransaction.SalesLines[i].DiscountLines.Where(j => j.PeriodicDiscountType == PeriodicDiscountOfferType.MultipleBuy).ToList();

                    // Get the multibuy discount lines for this multi buy discounts.
                    IEnumerable <QuantityDiscountLevel> multiBuyDiscountLines = pricingDataManager.GetMultipleBuyDiscountLinesByOfferIds(quantityDiscountLines.Select(j => j.OfferId));

                    foreach (DiscountLine discountLine in quantityDiscountLines)
                    {
                        GetQuantityPromotions(transaction, tempSalesTransaction, this.Context, i, discountLine, multiBuyDiscountLines);
                    }

                    // Threshhold Discounts.
                    // Finding all the threshold discounts that will be applied to the cart.
                    List <DiscountLine> thresholdDiscountLines = tempSalesTransaction.SalesLines[i].DiscountLines.Where(j => j.PeriodicDiscountType == PeriodicDiscountOfferType.Threshold).ToList();

                    // Get the tiers for this threshold discounts
                    IEnumerable <ThresholdDiscountTier> tiers = pricingDataManager.GetThresholdTiersByOfferIds(thresholdDiscountLines.Select(j => j.OfferId));

                    foreach (DiscountLine thresholdDiscount in thresholdDiscountLines)
                    {
                        GetThresholdDiscounts(transaction, tempSalesTransaction, this.Context, i, cartPromotionLines, thresholdDiscount, tiers);
                    }

                    IEnumerable <string> promotionsForCurrentLine = tempSalesTransaction.SalesLines[i].DiscountLines.Select(j => j.OfferName);
                    cartLinePromotions.Add(new CartLinePromotion(cart.CartLines[i].LineId, promotionsForCurrentLine));
                }

                CartPromotions cartPromotions = new CartPromotions(cartPromotionLines, cartLinePromotions);

                return(new GetPromotionsResponse(cartPromotions));
            }
Ejemplo n.º 2
0
            /// <summary>
            /// The calculation of the total customer discount.
            /// </summary>
            /// <param name="tradeAgreements">Trade agreement collection to calculate on. If null, uses the pricing data manager to find agreements.</param>
            /// <param name="retailTransaction">The retail transaction which needs total discounts.</param>
            /// <returns>
            /// The retail transaction.
            /// </returns>
            public SalesTransaction CalcTotalCustomerDiscount(
                List <TradeAgreement> tradeAgreements,
                SalesTransaction retailTransaction)
            {
                if (tradeAgreements != null && tradeAgreements.Any())
                {
                    decimal totalAmount = 0;

                    // Find the total amount as a basis for the total discount
                    // Consider calculable lines only. Ignore voided or return-by-receipt lines.
                    var clonedTransaction = retailTransaction.Clone <SalesTransaction>();

                    foreach (var clonedSalesLine in clonedTransaction.PriceCalculableSalesLines)
                    {
                        if (this.IsTotalDiscountAllowed(clonedSalesLine.ItemId))
                        {
                            SalesLineTotaller.CalculateLine(clonedTransaction, clonedSalesLine, d => this.priceContext.CurrencyAndRoundingHelper.Round(d));
                            totalAmount += clonedSalesLine.NetAmountWithAllInclusiveTax;
                        }
                    }

                    decimal absTotalAmount = Math.Abs(totalAmount);

                    // Find the total discounts.
                    PriceDiscountType        relation    = PriceDiscountType.EndDiscountSales; // Total sales discount - 7
                    PriceDiscountItemCode    itemCode    = PriceDiscountItemCode.AllItems;     // All items - 2
                    PriceDiscountAccountCode accountCode = 0;
                    string         itemRelation          = string.Empty;
                    decimal        percent1       = 0m;
                    decimal        percent2       = 0m;
                    decimal        discountAmount = 0m;
                    ProductVariant dimension      = new ProductVariant();

                    int idx = 0;
                    while (idx < /* Max(PriceDiscAccountCode) */ 3)
                    {   // Check discounts for Store Currency
                        accountCode = (PriceDiscountAccountCode)idx;

                        string accountRelation = string.Empty;
                        if (accountCode == PriceDiscountAccountCode.Customer)
                        {
                            accountRelation = retailTransaction.CustomerId;
                        }
                        else if (accountCode == PriceDiscountAccountCode.CustomerGroup)
                        {
                            accountRelation = this.priceContext.CustomerTotalPriceGroup;
                        }

                        accountRelation = accountRelation ?? string.Empty;

                        // Only get Active discount combinations
                        if (this.discountParameters.Activation(relation, (PriceDiscountAccountCode)accountCode, (PriceDiscountItemCode)itemCode))
                        {
                            var priceDiscTable = Discount.GetPriceDiscData(tradeAgreements, relation, itemRelation, accountRelation, itemCode, accountCode, absTotalAmount, this.priceContext, dimension, false);

                            foreach (TradeAgreement row in priceDiscTable)
                            {
                                percent1       += row.PercentOne;
                                percent2       += row.PercentTwo;
                                discountAmount += row.Amount;

                                if (!row.ShouldSearchAgain)
                                {
                                    idx = 3;
                                }
                            }
                        }

                        idx++;
                    }

                    decimal totalPercentage = DiscountLine.GetCompoundedPercentage(percent1, percent2);

                    if (discountAmount != decimal.Zero)
                    {
                        this.AddTotalDiscAmountLines(retailTransaction, DiscountLineType.CustomerDiscount, discountAmount);
                    }

                    if (totalPercentage != 0)
                    {
                        // Update the sale items.
                        // Consider calculable lines only. Ignore voided or return-by-receipt lines.
                        foreach (var saleItem in retailTransaction.PriceCalculableSalesLines)
                        {
                            if (this.IsTotalDiscountAllowed(saleItem.ItemId))
                            {
                                DiscountLine discountItem = GetCustomerDiscountItem(saleItem, CustomerDiscountType.TotalDiscount, DiscountLineType.CustomerDiscount);
                                discountItem.Percentage = totalPercentage;
                            }
                        }
                    }
                }

                return(retailTransaction);
            }