public void DifferentMarginTest()
        {
            var request = new Request();
            request.ProductHierarchy = new List<Relation>(this.hierarchy);
            request.GeographyHierarchy = new List<Relation>(this.hierarchy);
            request.SalesComponentHierarchy = new List<Relation>(this.hierarchy);
            request.PeriodHierarchy = new List<Relation>();

            request.Sales = new List<ConcreteFact>();
            request.Sales.AddRange(makeDuetos(4, 7, 4, 7, 4, 7, 1, 10, 100));

            //including facts for each period
            request.Margins = Enumerable.Range(1, 10).SelectMany(r =>
                {
                    var facts = new List<NullableFact>();
                    facts.Add(new NullableFact() { TimeId = (short)r, ProductId = 2, Value = 0.15f });
                    facts.Add(new NullableFact() { TimeId = (short)r, ProductId = 3, Value = 0.25f });
                    return facts;
                }).ToList();

            request.Spend = new List<NullableFact>() { new NullableFact() { ProductId = 1, GeographyId = 1, Value = 100 } };

            // no adjustments
            request.Adjustments = null;

            var calculator = new CalculatorService();
            var result = calculator.CalculateRoi(request);

            Assert.AreEqual(1, result.Count);
            Assert.AreEqual(128f, result.Single().Value, 0.0001);
        }
        public List<NullableFact> CalculateRoi(Request request)
        {
            var products = new Hierarchy(request.ProductHierarchy);
            var geographies = new Hierarchy(request.GeographyHierarchy);
            var causals = new Hierarchy(request.SalesComponentHierarchy);
            var periods = new Hierarchy(request.PeriodHierarchy);

            var adjuster = new Adjuster(products, geographies, causals, periods);
            var sales = adjuster.AdjustSales(request);
            var aggregatedDuetos = adjuster.AggregateSales(request.Spend, sales);

            var rois = request.Spend.Join(aggregatedDuetos,
                s => new { s.ProductId, s.GeographyId, CausalId = s.SalesComponentId, s.TimeId },
                adt => new { adt.ProductId, adt.GeographyId, CausalId = adt.SalesComponentId, adt.TimeId },
                (s, adt) =>
                    new NullableFact()
                    {
                        ProductId = s.ProductId,
                        GeographyId = s.GeographyId,
                        SalesComponentId = s.SalesComponentId,
                        TimeId = s.TimeId,
                        Value = adt.Value / s.Value
                    });

            return rois.ToList();
        }
Example #3
0
        public List<ConcreteFact> AdjustSales(Request roiRequest)
        {
            var marginLookup = new FactLookup(roiRequest.Margins, products, geographies, causals, periods);
            var spendPeriods = roiRequest.Spend.Select(s => s.TimeId).ToList();

            if (!spendPeriods.Any())
                return new List<ConcreteFact>();

            // we can genericize this when more adjustments come online
            List<NullableFact> adjustment = null;

            var adjustmentLookup = new FactLookup(adjustment, products, geographies, causals, periods);

            var timeIsNull = spendPeriods.All(s => s == null);
            var dueTos = roiRequest.Sales.Where(d => timeIsNull || spendPeriods.Contains(d.TimeId));

            dueTos.AsParallel().ForAll(item =>
                {
                    var margin = marginLookup.GetParent(item, false);
                    var adjustmentFactor = adjustmentLookup.GetParent(item, false, 1.0f, false);

                    item.Value *= margin;
                    item.Value *= adjustmentFactor;
                });

            return roiRequest.Sales;
        }
        public void IntegratedCalculateRoi_ComplexTest()
        {
            var request = new Request();
            request.ProductHierarchy = new List<Relation>(this.hierarchy);
            request.GeographyHierarchy = new List<Relation>(this.hierarchy);
            request.SalesComponentHierarchy = new List<Relation>();
            request.PeriodHierarchy = new List<Relation>();

            request.Sales = new List<ConcreteFact>();
            request.Sales.AddRange(makeDuetos(2, 2, 2, 2, 1, 1, 1, 10, 50));
            request.Sales.AddRange(makeDuetos(2, 2, 2, 2, 2, 2, 1, 10, 120));
            request.Sales.AddRange(makeDuetos(2, 2, 2, 2, 3, 3, 6, 10, 95));

            request.Margins = Enumerable.Range(1, 10).Select(r => new NullableFact() { TimeId = (short)r, Value = 0.15f }).ToList();
            request.Spend = new List<NullableFact>() { new NullableFact() { ProductId = 1, GeographyId = 1, Value = 100 } };

            // no adjustments
            request.Adjustments = null;

            var calculator = new CalculatorService();
            var result = calculator.CalculateRoi(request);

            Assert.AreEqual(1, result.Count);
            Assert.AreEqual(3.2625f, result.Single().Value, 0.01);
        }
        public void DifferentMarginTest_WithDiscreteGaps()
        {
            var request = new Request();
            request.ProductHierarchy = new List<Relation>(this.hierarchy);
            request.GeographyHierarchy = new List<Relation>(this.hierarchy);
            request.SalesComponentHierarchy = new List<Relation>(this.hierarchy);
            request.PeriodHierarchy = new List<Relation>();

            request.Sales = new List<ConcreteFact>();
            request.Sales.AddRange(makeDuetos(4, 7, 4, 7, 4, 7, 1, 10, 1));

            // no product 7 in geog 7
            // will exclude for all 4 sales components x 10 weeks (40 leaf)
            request.Sales.RemoveAll(d => d.ProductId == 7 && d.GeographyId == 7);

            // causal 6 not run in geogs 4,5
            // will exclude for all 4 products x 10 weeks in both geogs (80 leaf)
            request.Sales.RemoveAll(d => d.SalesComponentId == 6 && (d.GeographyId == 4 || d.GeographyId == 5));

            //including facts for each period
            request.Margins = Enumerable.Range(1, 10).SelectMany(r =>
            {
                var facts = new List<NullableFact>();
                facts.Add(new NullableFact() { TimeId = (short)r, ProductId = 2, Value = 0.15f });
                facts.Add(new NullableFact() { TimeId = (short)r, ProductId = 3, Value = 0.25f });
                return facts;
            }).ToList();

            request.Spend = new List<NullableFact>() { new NullableFact() { ProductId = 1, GeographyId = 1, Value = 100 } };

            // no adjustments
            request.Adjustments = null;

            var calculator = new CalculatorService();
            var result = calculator.CalculateRoi(request);

            Assert.AreEqual(1, result.Count);
            Assert.AreEqual(1.02f, result.Single().Value, 0.0001);
        }
        public void IntegratedTest()
        {
            var request = new Request();
            request.ProductHierarchy = new List<Relation>(this.hierarchy);
            request.GeographyHierarchy = new List<Relation>(this.hierarchy);
            request.SalesComponentHierarchy = new List<Relation>();
            request.PeriodHierarchy = new List<Relation>();

            request.Sales = new List<ConcreteFact>();
            request.Sales.AddRange(makeDuetos(4, 7, 4, 7, 4, 7, 1, 10, 100));

            request.Margins = new List<NullableFact>() { new NullableFact() { Value = 0.15f } };
            request.Spend = new List<NullableFact>() { new NullableFact() { ProductId = 1, GeographyId = 1, Value = 100 } };

            var calculator = new CalculatorService();

            var adjustments = new List<NullableFact>();

            for (short g = 4; g <= 7; g++)
            for (short s = 4; s <= 7; s++)
            {
                adjustments.Add(new NullableFact() { GeographyId = g, SalesComponentId = s, Value = 1.5f });
            }

            request.Adjustments = new List<Adjustment>() { new Adjustment() { AdjustmentType = AdjustmentType.Adjustment, Facts = adjustments } };
            var result = calculator.CalculateRoi(request);

            // Missing assert
            Assert.Fail();
        }