/// <summary>
            /// Get struct PriceResult from active trade agreement.
            /// Struct PriceResult contains India MaxRetailPrice. Currently there is a field �Max. retail price� in the form price/discount agreement journal
            /// (Navigation path: Main Menu > Sales and marketing > Journal > price/discount agreement journal).
            /// The field will be visible only when the logged on company is an India company. And it is optional.
            /// User can use this field to specify different MRP values on different sites and warehouses for the same item. And when the trade agreement applies to a transaction,
            /// the MRP value should flow to the MRP field of the transaction as the default value.
            /// So current change is when fetching the superset of trade agreements which could apply to all of these items and customer for the given date,
            /// also takes field MAXIMUMRETAILPRICE_IN through the stored procedures GETALLDISCOUNTTRADEAGREEMENTS/ GETALLTRADEAGREEMENTS/ GETTRADEAGREEMENTS.
            /// Then return the whole struct PriceResult  rather than PriceResult.Price.
            /// </summary>
            /// <param name="tradeAgreementRules">The trade agreement rules.</param>
            /// <param name="priceParameters">The price parameters.</param>
            /// <param name="currencyCode">The currency code.</param>
            /// <param name="itemId">The item Id.</param>
            /// <param name="defaultSalesUnit">The default sales unit.</param>
            /// <param name="salesUnit">The sales unit.</param>
            /// <param name="variantLine">The variant line.</param>
            /// <param name="unitOfMeasureConversion">The UnitOfMeasure Conversion.</param>
            /// <param name="quantity">The quantity.</param>
            /// <param name="customerId">The customer Id.</param>
            /// <param name="customerPriceGroup">The customer price group.</param>
            /// <param name="channelPriceGroupIds">The channel price group Ids.</param>
            /// <param name="salesLines">Optional sales lines.</param>
            /// <param name="priceContext">Price context.</param>
            /// <param name="activeDate">The active date.</param>
            /// <returns>The PriceResult of active trade agreement.</returns>
            internal static PriceResult GetPriceResultOfActiveTradeAgreement(
                IDictionary <string, IList <TradeAgreement> > tradeAgreementRules,
                DiscountParameters priceParameters,
                string currencyCode,
                string itemId,
                string defaultSalesUnit,
                string salesUnit,
                ProductVariant variantLine,
                UnitOfMeasureConversion unitOfMeasureConversion,
                decimal quantity,
                string customerId,
                string customerPriceGroup,
                IEnumerable <string> channelPriceGroupIds,
                IEnumerable <SalesLine> salesLines,
                PriceContext priceContext,
                DateTimeOffset activeDate)
            {
                PriceResult result;

                variantLine = variantLine ?? new ProductVariant();

                // Get basic arguments for Price evaluation
                RetailPriceArgs args = new RetailPriceArgs()
                {
                    Barcode      = string.Empty,
                    CurrencyCode = currencyCode,
                    CustomerId   = customerId,
                    Dimensions   = variantLine,
                    DefaultSalesUnitOfMeasure = defaultSalesUnit,
                    ItemId                  = itemId,
                    PriceGroups             = channelPriceGroupIds.AsReadOnly(),
                    Quantity                = quantity,
                    SalesUOM                = salesUnit,
                    UnitOfMeasureConversion = unitOfMeasureConversion,
                };

                // Get the active retail price - checks following prices brackets in order: Customer TAs, Store price group TAs, 'All' TAs.
                // First bracket to return a price 'wins'. Each bracket returns the lowest price it can find.
                result = FindPriceAgreement(tradeAgreementRules, priceParameters, args, salesLines, priceContext, activeDate);

                // Direct customer TA price would have been caught above.
                // Compare against customer price group TAs now and override if lower than previously found price (or if previously found price was 0).
                if (!string.IsNullOrEmpty(customerId) &&
                    !string.IsNullOrEmpty(customerPriceGroup) &&
                    !channelPriceGroupIds.Contains(customerPriceGroup))
                {
                    // Customer price group
                    args.PriceGroups = new ReadOnlyCollection <string>(new[] { customerPriceGroup });
                    PriceResult customerResult = FindPriceAgreement(tradeAgreementRules, priceParameters, args, salesLines, priceContext, activeDate);

                    // Pick the Customer price if either the Retail price is ZERO, or the Customer Price is non-zero AND lower
                    if ((result.Price == decimal.Zero) ||
                        ((customerResult.Price > decimal.Zero) && (customerResult.Price <= result.Price)))
                    {
                        result = customerResult;
                    }
                }

                return(result);
            }
Esempio n. 2
0
        public void CheckZeroVolForward(AssetMarket assetMkt)
        {
            var zcCurve = assetMkt.RiskFreeDiscount;
            var market  = new Market(new[] { zcCurve }, new[] { assetMkt });

            var zeroVol           = new MapRawDatas <DateOrDuration, double>(new[] { new DateOrDuration(assetMkt.RefDate) }, new[] { 0.0 });
            var blackScholesDesc  = new BlackScholesModelDescription(assetMkt.Asset.Name, zeroVol, true);
            var mcConfig          = new MonteCarloConfig(1, RandomGenerators.GaussianSobol(SobolDirection.Kuo3));
            var blackScholesModel = ModelFactory.Instance.Build(blackScholesDesc, market);

            var fwdDates = new[] { Duration.Month, 6 * Duration.Month, Duration.Year, 2 * Duration.Year, 5 * Duration.Year }
            .Map(d => assetMkt.RefDate + d);

            IProduct    fwdLeg      = ForwardLeg(fwdDates);
            PriceResult priceResult = (PriceResult)McPricer.WithDetails(mcConfig).Price(fwdLeg, blackScholesModel, market);

            double[] fwds = priceResult.Details.Map(kv => kv.Item3.Value);

            var assetFwdCurve = assetMkt.Forward();

            double[] refFwds = fwdDates.Map(d => assetFwdCurve.Fwd(d) * zcCurve.Zc(d));

            foreach (var i  in Enumerable.Range(0, fwdDates.Length))
            {
                var err = Math.Abs(fwds[i] / refFwds[i] - 1.0);
                Assert.LessOrEqual(err, 20.0 * DoubleUtils.MachineEpsilon);
            }
        }
Esempio n. 3
0
            /// <summary>
            /// Gets maximum retail price from trade agreement.
            /// </summary>
            /// <param name="salesLine">The sales line.</param>
            /// <param name="context">The request context.</param>
            /// <returns>Maximum retail price from trade agreement.</returns>
            public decimal GetMaximumRetailPriceFromTradeAgreement(SalesLine salesLine, RequestContext context)
            {
                if (salesLine == null)
                {
                    throw new ArgumentNullException("salesLine");
                }

                decimal quantity = this.salesTransaction.ActiveSalesLines.Where(x => (x.ItemId == salesLine.ItemId) && (x.InventoryDimensionId == salesLine.InventoryDimensionId)).Sum(x => x.Quantity);

                if (quantity == decimal.Zero)
                {
                    quantity = 1;
                }

                if (!salesLine.BeginDateTime.IsValidAxDateTime())
                {
                    salesLine.BeginDateTime = context.GetNowInChannelTimeZone();
                }

                PriceResult priceResult = PricingEngine.GetActiveTradeAgreement(
                    this.pricingDataManager,
                    DiscountParameters.CreateAndInitialize(this.pricingDataManager),
                    this.channelConfiguration.Currency,
                    salesLine,
                    quantity,
                    this.customerId,
                    this.priceGroup,
                    salesLine.BeginDateTime);

                this.maxRetailPrice = priceResult.MaximumRetailPriceIndia;

                return(this.maxRetailPrice);
            }
            private static PriceResult FindPriceAgreement(
                IDictionary <string, IList <TradeAgreement> > tradeAgreementRules,
                DiscountParameters priceParameters,
                RetailPriceArgs args,
                IEnumerable <SalesLine> salesLines,
                PriceContext priceContext,
                DateTimeOffset activeDate)
            {
                // First we get the price according to the base UOM
                PriceAgreementArgs p      = args.AgreementArgsForDefaultSales();
                PriceResult        result = ApplyPriceTradeAgreements(tradeAgreementRules, p, priceParameters, salesLines, priceContext, activeDate);

                // Is the current UOM something different than the base UOM?
                if (args.SalesUOM != args.DefaultSalesUnitOfMeasure)
                {
                    // Then let's see if we find some price agreement for that UOM
                    p = args.ArgreementArgsForSale();
                    PriceResult salesUOMResult = ApplyPriceTradeAgreements(tradeAgreementRules, p, priceParameters, salesLines, priceContext, activeDate);

                    // If there is a price found then we return that as the price
                    if (salesUOMResult.Price > decimal.Zero)
                    {
                        return(salesUOMResult);
                    }
                    else
                    {
                        return(new PriceResult(result.Price * args.UnitOfMeasureConversion.GetFactorForQuantity(args.Quantity), result.IncludesTax, custPriceGroup: result.CustPriceGroup));
                    }
                }

                // else we return baseUOM price mulitplied with the unit qty factor.
                return(result);
            }
Esempio n. 5
0
        public void DescribeIsCorrect(decimal baseAmount, decimal taxRate, decimal afterTax, string expectedDescription)
        {
            string      filename    = "The Little Prince";
            int         upc         = 12345;
            PriceResult priceResult = new PriceResult(filename, upc, new MoneyCurrency(baseAmount), taxRate, new MoneyCurrency(afterTax));

            Assert.Equal(expectedDescription, priceResult.Describe());
        }
        public void DescribeIsCorrect(decimal taxRate)
        {
            PriceCalculator priceCalculator = new PriceCalculator(taxRate);

            PriceResult priceResult = priceCalculator.Calculate(product);

            Assert.Equal(product.Title, priceResult.Title);
            Assert.Equal(product.UPC, priceResult.Upc);
            Assert.Equal(product.Amount, priceResult.BaseAmount);
            Assert.Equal(taxRate, priceResult.TaxRate);
            Assert.Equal(product.Amount + product.Amount * taxRate, priceResult.AfterTax);
        }
Esempio n. 7
0
        public void SubTotal_IsCorrect()
        {
            // arrange
            var product = new Product("Widget", 12345, Money.USDollar(12.35));
            var pr      = new PriceResult();

            pr.Product = product;

            // act
            var result = pr.Subtotal();

            // assert
            Assert.True(result == Money.USDollar(12.35));
        }
Esempio n. 8
0
        public void Discount_IsCorrect()
        {
            // arrange
            var product = new Product("Widget", 12345, Money.USDollar(12.35));
            var pr      = new PriceResult();

            pr.Product             = product;
            pr.DiscountRatePercent = 0.15M;

            // act
            var result = pr.Discount();

            // assert
            Assert.True(result == Money.USDollar(1.85));
        }
Esempio n. 9
0
        public void Total_IsCorrect()
        {
            // arrange
            var product = new Product("Widget", 12345, Money.USDollar(12.35));
            var pr      = new PriceResult();

            pr.Product        = product;
            pr.TaxRatePercent = 0.07M;

            // act
            var result = pr.Total();

            // assert
            Assert.True(result == Money.USDollar(13.21));
        }
            /// <summary>
            /// This function takes arguments (customer, item, currency, etc.) related to price (trade) agreement
            /// as well as the set of currently enabled trade agreement types. It returns the best trade agreement
            /// price for the given constraints.
            /// As in AX, the method searches for a price on the given item which has been given to a
            /// customer, price group, or anyone (in given precedence order). If a price is found and marked as
            /// SearchAgain=False, the search will terminate. Otherwise, search for lowest price will continue.
            /// To recap, the logic is that three searches are done for customer, price group, and all, each bracket
            /// will return the lowest price it has for the constraints. If it has SearchAgain=True, then the search
            /// for lowest price continues to the next bracket.
            /// </summary>
            /// <param name="tradeAgreementRules">Trade agreements applicable to each item, keyed by item relation (i.e. item Id).</param>
            /// <param name="args">Arguments for price agreement search.</param>
            /// <param name="priceParameters">Set of enabled price agreement types.</param>
            /// <param name="salesLines">Sales lines.</param>
            /// <param name="priceContext">Price context.</param>
            /// <param name="activeDate">Date to use for querying trade agreement rules.</param>
            /// <returns>
            /// Most applicable price for the given price agreement constraints.
            /// </returns>
            private static PriceResult ApplyPriceTradeAgreements(
                IDictionary <string, IList <TradeAgreement> > tradeAgreementRules,
                PriceAgreementArgs args,
                DiscountParameters priceParameters,
                IEnumerable <SalesLine> salesLines,
                PriceContext priceContext,
                DateTimeOffset activeDate)
            {
                PriceResult priceResult = new PriceResult(0M, PriceGroupIncludesTax.NotSpecified);

                var itemCodes    = new PriceDiscountItemCode[] { PriceDiscountItemCode.Item, PriceDiscountItemCode.ItemGroup, PriceDiscountItemCode.AllItems };
                var accountCodes = new PriceDiscountAccountCode[] { PriceDiscountAccountCode.Customer, PriceDiscountAccountCode.CustomerGroup, PriceDiscountAccountCode.AllCustomers };

                // Search through combinations of item/account codes from most to least specific.
                // This needs to match the behavior of AX code PriceDisc.findPriceAgreement().
                foreach (var accountCode in accountCodes)
                {
                    foreach (var itemCode in itemCodes)
                    {
                        if (priceParameters.Activation(PriceDiscountType.PriceSales, accountCode, itemCode))
                        {
                            IList <string> accountRelations = args.GetAccountRelations(accountCode);
                            string         itemRelation     = args.GetItemRelation(itemCode);

                            if (accountRelations.All(a => ValidRelation(accountCode, a)) &&
                                ValidRelation(itemCode, itemRelation))
                            {
                                bool searchAgain;
                                IEnumerable <TradeAgreement> tradeAgreements = FindPriceAgreements(tradeAgreementRules, args, itemCode, accountCode, salesLines, priceContext, activeDate);
                                PriceResult currentPriceResult = GetBestPriceAgreement(tradeAgreements, out searchAgain);

                                if (priceResult.Price == 0M ||
                                    (currentPriceResult.Price > 0M && currentPriceResult.Price < priceResult.Price))
                                {
                                    priceResult = currentPriceResult;
                                }

                                if (!searchAgain)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }

                return(priceResult);
            }
Esempio n. 11
0
        public void TotalWithDiscountAndTax_IsCorrect()
        {
            // arrange
            var product = new Product("Widget", 12345, Money.USDollar(20.25));
            var pr      = new PriceResult();

            pr.Product             = product;
            pr.TaxRatePercent      = 0.20M;
            pr.DiscountRatePercent = 0.15M;

            // act

            // assert
            Assert.True(pr.Tax() == Money.USDollar(4.05));
            Assert.True(pr.Discount() == Money.USDollar(3.04));
            Assert.True(pr.Total() == Money.USDollar(21.26));
        }
Esempio n. 12
0
        public object[,] PublishPriceResult(PriceResult priceResult)
        {
            var price  = priceResult.Price;
            var result = PublisherServices.PublishScalar(string.Format("Price ({0})", price.Currency), price.Value);

            DateTime[] payDates;
            Currency[] payCurrencies;
            double[,] detailValues;
            PricingDetails(priceResult.Details, out payDates, out payCurrencies, out detailValues);

            var details = new object[payDates.Length + 1, payCurrencies.Length + 1];

            details[0, 0] = "PricingDetails";
            ArrayUtils.SetSubArray(ref details, 1, 1, detailValues.Map(v => (object)v));
            ArrayUtils.SetSubArray(ref details, 1, 0, payDates.Cast <object>().ToArray().AsColumn());
            ArrayUtils.SetSubArray(ref details, 0, 1, payCurrencies.Map(c => (object)c.ToString()).AsRow());

            result = result.AppendUnder(details, 1);
            return(result);
        }
Esempio n. 13
0
 public IActionResult GetPrices()
 {
     xServer.Stats.IncrementPublicRequest();
     if (xServer.Stats.TierLevel == ServerNode.Tier.TierLevel.Three)
     {
         var priceResults = new List <PriceResult>();
         foreach (var pair in priceFeature.FiatPairs)
         {
             PriceResult priceResult = new PriceResult()
             {
                 Price = pair.GetMytPrice(),
                 Pair  = (int)pair.Currency
             };
             priceResults.Add(priceResult);
         }
         return(Json(priceResults));
     }
     else
     {
         return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Tier 3 requirement not meet", "The node you requested is not a tier 3 node."));
     }
 }
Esempio n. 14
0
        public static void GetPriceList()
        {
            modelData = new List <ModelData>();
            priceList.Rows.Clear();

            string responseFromServer = GenerateRequest("Home", "GetPriceList", "GET", null);

            if (responseFromServer == null)
            {
                return;
            }

            PriceResult result = JsonConvert.DeserializeObject <PriceResult>(responseFromServer);

            List <ModelData> data = new List <ModelData>();

            foreach (var jsonData in result.JsonDatas)
            {
                try
                {
                    data.Add(JsonConvert.DeserializeObject <ModelData>(jsonData));
                }
                catch (Exception)
                {
                    throw;
                }
            }

            foreach (var item in result.Items)
            {
                ParseAndAddItem(item, data);
            }

            foreach (var d in modelData)
            {
                priceList.Rows.Add(AddRow(d));
            }
        }
Esempio n. 15
0
 public IActionResult GetPrice(int fiatPairId)
 {
     xServer.Stats.IncrementPublicRequest();
     if (xServer.Stats.TierLevel == ServerNode.Tier.TierLevel.Three)
     {
         var fiatPair = priceFeature.FiatPairs.Where(f => (int)f.Currency == fiatPairId).FirstOrDefault();
         if (fiatPair != null)
         {
             PriceResult priceResult = new PriceResult()
             {
                 Price = fiatPair.GetMytPrice()
             };
             return(Json(priceResult));
         }
         else
         {
             return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Invalid Pair", "The pair supplied does not exist."));
         }
     }
     else
     {
         return(ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Tier 3 requirement not meet", "The node you requested is not a tier 3 node."));
     }
 }
            private static Tuple <decimal, string> GetActiveTradeAgreementPriceAndGroup(
                IDictionary <string, IList <TradeAgreement> > tradeAgreementRules,
                DiscountParameters priceParameters,
                string currencyCode,
                string itemId,
                string defaultSalesUnit,
                string salesUnit,
                ProductVariant variantLine,
                UnitOfMeasureConversion unitOfMeasureConversion,
                decimal quantity,
                string customerId,
                string customerPriceGroup,
                IEnumerable <string> channelPriceGroupIds,
                IEnumerable <SalesLine> salesLines,
                PriceContext priceContext,
                DateTimeOffset activeDate)
            {
                PriceResult result = GetPriceResultOfActiveTradeAgreement(
                    tradeAgreementRules,
                    priceParameters,
                    currencyCode,
                    itemId,
                    defaultSalesUnit,
                    salesUnit,
                    variantLine,
                    unitOfMeasureConversion,
                    quantity,
                    customerId,
                    customerPriceGroup,
                    channelPriceGroupIds,
                    salesLines,
                    priceContext,
                    activeDate);

                return(new Tuple <decimal, string>(result.Price, result.CustPriceGroup));
            }
Esempio n. 17
0
 public static EnergyQuote ToEnergyQuote(this PriceResult priceResult)
 {
     return(new EnergyQuote
     {
         KeyFeatures = priceResult.KeyFeatures.Select(
             x =>
             new Models.PriceFeature
         {
             Category = x.Category.ToString(),
             ClassName = x.ClassName,
             Description = x.Description
         }).ToList(),
         Id = priceResult.Id,
         ResultId = priceResult.ResultId,
         SupplierId = priceResult.SupplierId,
         SupplierName = priceResult.SupplierName,
         SupplierRating = priceResult.SupplierRating,
         SupplierCss = priceResult.SupplierCss,
         TariffId = priceResult.TariffId,
         TariffName = priceResult.TariffName,
         TariffDetailsUrl = priceResult.TariffDetailsUrl,
         HasTariffCustomFeature = priceResult.HasTariffCustomFeature,
         CustomFeatureText = priceResult.CustomFeatureText,
         PaymentMethod = (int)priceResult.PaymentMethod,
         PaymentMethodId = priceResult.PaymentMethodId,
         CanApply = priceResult.CanApply,
         AnnualSavings = priceResult.AnnualSavings,
         AnnualSpend = priceResult.AnnualSpend,
         ElectricityAnnualSavings = priceResult.ElectricityAnnualSavings,
         ElectricityAnnualSpend = priceResult.ElectricityAnnualSpend,
         GasAnnualSavings = priceResult.GasAnnualSavings,
         GasAnnualSpend = priceResult.GasAnnualSpend,
         RenewableFuelPercentage = priceResult.RenewableFuelPercentage,
         PaperLessBilling = priceResult.PaperLessBilling,
         PaperBilling = priceResult.PaperBilling,
         NoStandingCharges = priceResult.NoStandingCharges,
         CappedOrFixed = priceResult.CappedOrFixed,
         Green = priceResult.Green,
         AccurateMonthlyBilling = priceResult.AccurateMonthlyBilling,
         StayWarm = priceResult.StayWarm,
         Economy10 = priceResult.Economy10,
         Cashback = priceResult.Cashback,
         Hide = priceResult.Hide,
         TotalExitFees = priceResult.TotalExitFees,
         ElectricityEstimatedMonthlyCost = priceResult.ElectricityEstimatedMonthlyCost,
         GasEstimatedMonthlyCost = priceResult.GasEstimatedMonthlyCost,
         IsMostPopularTariffForUser = priceResult.IsMostPopularTariffForUser,
         IsCollectiveTariff = priceResult.IsCollectiveTariff,
         IsExclusiveTariff = priceResult.IsExclusiveTariff,
         ShowInRelevancyBox = priceResult.ShowInRelevancyBox,
         ShowStrapline = priceResult.ShowStrapline,
         CheapestBigSupplier = priceResult.CheapestBigSupplier,
         CheapestLongFixed = priceResult.CheapestLongFixed,
         Cheapest = priceResult.Cheapest,
         CheapestMediumFixed = priceResult.CheapestMediumFixed,
         CheapestCanApply = priceResult.CheapestCanApply,
         CheapestGreen = priceResult.CheapestGreen,
         CheapestHighestRated = priceResult.CheapestHighestRated,
         CheapestShortFixed = priceResult.CheapestShortFixed
     });
 }
Esempio n. 18
0
        public static List <PriceResult> MapToPriceResults(this FutureSupplies ehlResults, GetPricesRequest request)
        {
            var mappedResults = new List <PriceResult>();

            var ehlResultsSet = ehlResults.Results.First(r => r.SupplyType.Id.Equals(request.CompareType.EhlSupplyType()));

            foreach (var supply in ehlResultsSet.EnergySupplies)
            {
                var paymentMethod = int.Parse(supply.SupplyDetails.PaymentMethod.Id);
                var priceResult   = new PriceResult
                {
                    AnnualSavings                   = decimal.Round(supply.ExpectedAnnualSavings, 0),
                    AnnualSpend                     = decimal.Round(supply.ExpectedAnnualSpend, 0),
                    ElectricityAnnualSavings        = supply.ExpectedElecAnnualSavings,
                    ElectricityAnnualSpend          = supply.ExpectedElecAnnualSpend,
                    ElectricityEstimatedMonthlyCost = supply.EstimatedElecMonthlyCost,
                    GasAnnualSavings                = supply.ExpectedGasAnnualSavings,
                    GasAnnualSpend                  = supply.ExpectedGasAnnualSpend,
                    GasEstimatedMonthlyCost         = supply.EstimatedGasMonthlyCost,
                    ResultId                = supply.Id,
                    SupplierId              = int.Parse(supply.Supplier.Id),
                    SupplierName            = supply.Supplier.Name,
                    SupplierRating          = supply.Supplier.ServiceStarRating,
                    TariffId                = int.Parse(supply.SupplyDetails.Id),
                    TariffName              = supply.SupplyDetails.Name,
                    TariffDetailsUrl        = supply.SupplyDetails.FurtherDetails.Uri,
                    PaymentMethod           = (PaymentMethodType)paymentMethod,
                    PaymentMethodId         = paymentMethod,
                    CanApply                = supply.CanApply,
                    CappedOrFixed           = supply.SupplyDetails.Attributes.Any(a => a.Equals("CappedOrFixed", StringComparison.InvariantCultureIgnoreCase)),
                    Green                   = supply.SupplyDetails.Attributes.Any(a => a.Equals("Green", StringComparison.InvariantCultureIgnoreCase)),
                    AccurateMonthlyBilling  = supply.SupplyDetails.Attributes.Any(a => a.Equals("AccurateMonthlyBilling", StringComparison.InvariantCultureIgnoreCase)),
                    StayWarm                = supply.SupplyDetails.Attributes.Any(a => a.Equals("StayWarm", StringComparison.InvariantCultureIgnoreCase)),
                    Economy10               = supply.SupplyDetails.Attributes.Any(a => a.Equals("Economy10", StringComparison.InvariantCultureIgnoreCase)),
                    PaperLessBilling        = supply.SupplyDetails.Attributes.Any(a => a.Equals("PaperlessBilling", StringComparison.InvariantCultureIgnoreCase)),
                    PaperBilling            = supply.SupplyDetails.Attributes.Any(a => a.Equals("PaperBilling", StringComparison.InvariantCultureIgnoreCase)),
                    NoStandingCharges       = supply.SupplyDetails.Attributes.Any(a => a.Equals("NoStandingCharges", StringComparison.InvariantCultureIgnoreCase)),
                    RenewableFuelPercentage = supply.SupplyDetails.RenewableFuelPercentage,
                    TotalExitFees           = CalculateTotalExitFees(request.CompareType, supply.SupplyDetails.ExitFeesGas, supply.SupplyDetails.ExitFeesElectricity),
                    CheapestBigSupplier     = PromotionsValidator(supply.Promotions, "CheapestBigSupplier"),
                    CheapestLongFixed       = PromotionsValidator(supply.Promotions, "CheapestLongFixed"),
                    CheapestShortFixed      = PromotionsValidator(supply.Promotions, "CheapestShortFixed"),
                    Cheapest                = PromotionsValidator(supply.Promotions, "Cheapest"),
                    CheapestMediumFixed     = PromotionsValidator(supply.Promotions, "CheapestMediumFixed"),
                    CheapestCanApply        = PromotionsValidator(supply.Promotions, "CheapestCanApply"),
                    CheapestGreen           = PromotionsValidator(supply.Promotions, "CheapestGreen"),
                    CheapestHighestRated    = PromotionsValidator(supply.Promotions, "CheapestHighestRated")
                };

                priceResult.SupplierRating = priceResult.SupplierRating > 5 ? 5 : priceResult.SupplierRating;

                // Key features
                priceResult.KeyFeatures = supply.SupplyDetails.KeyFeatures.ToPriceFeatures();

                // Set CTM custom feature text
                if (request.TariffCustomFeatureEnabled)
                {
                    priceResult.CustomFeatureText      = SetCustomFeatureText(string.Concat(priceResult.SupplierName, priceResult.TariffName).ToLowerInvariant(), request.CustomFeatures);
                    priceResult.HasTariffCustomFeature = !string.IsNullOrWhiteSpace(priceResult.CustomFeatureText);
                }

                mappedResults.Add(priceResult);
            }

            return(mappedResults);
        }