public static double CalculateTotalPrice(Orders order,
            ITermPositionsManager termPositionsManager,
            IPositionsManager positionsManager,
            ITermCostsManager termCostsManager,
            ITaxesManager taxesManager,
            DateTime? fromDate,
            DateTime? toDate,
            ref double profit)
        {
            double result = 0;

            //TODO discuss with customer - take positions where proccessed amount not null (but take with 0)
            var termPositions = termPositionsManager.GetEntities(o => !o.DeleteDate.HasValue && o.Terms.OrderId == order.Id && o.ProccessedAmount.HasValue);

            if(fromDate.HasValue && toDate.HasValue)
            {
                termPositions = termPositions.Where(o => o.Terms.Date >= fromDate.Value && o.Terms.Date <= toDate.Value);
            }

            foreach (var termPosition in termPositions.ToList())
            {
                //positions
                if (termPosition.ProccessedAmount.Value > 0)
                {
                    var positionProfit = CalculatePositionPrice(termPosition.Positions.Price, termPosition.ProccessedAmount.Value,
                        termPosition.Positions.Payment);

                    result += positionProfit;

                    //todo calculate profit
                    profit += positionProfit;
                }

                //materials
                foreach (var material in termPosition.TermPositionMaterialRsps.Where(o => !o.DeleteDate.HasValue && o.Amount.HasValue))
                {
                    var amount = material.Amount.Value;
                    if (material.Materials.MaterialAmountTypes == MaterialAmountTypes.Meter)
                    {
                        if (material.Materials.Length != 0)
                        {
                            amount = amount / (double)material.Materials.Length.Value;
                        }
                        else
                        {
                            //todo
                        }
                    }

                    result += CalculatePositionPrice(material.Materials.Price, amount, PaymentTypes.Standard);

                    var materialProfit = material.Materials.Price * amount - material.Materials.BoughtPrice * amount;
                    profit += materialProfit;
                }
            }

            //material positions without terms
            var materialPositionsWithoutTerms = positionsManager.GetEntities(o => o.OrderId == order.Id && !o.DeleteDate.HasValue &&
                !o.TermId.HasValue && o.MaterialId.HasValue && o.IsMaterialPosition);

            if (fromDate.HasValue && toDate.HasValue)
            {
                materialPositionsWithoutTerms = materialPositionsWithoutTerms.Where(o => o.ChangeDate >= fromDate.Value && o.ChangeDate <= toDate.Value);
            }

            foreach (var position in materialPositionsWithoutTerms.ToList())
            {
                var price = CalculatePositionPrice(position.Price, position.Amount, position.Payment);

                result += price;

                profit += price - position.Materials.BoughtPrice * position.Amount;
            }

            //extra costs
            var termCosts = termCostsManager.GetEntities(o => !o.DeleteDate.HasValue && o.Terms.OrderId == order.Id);

            if (fromDate.HasValue && toDate.HasValue)
            {
                termCosts = termCosts.Where(o => o.Terms.Date >= fromDate.Value && o.Terms.Date <= toDate.Value);
            }

            foreach (var termCost in termCosts.ToList())
            {
                var price = CalculatePositionPrice(termCost.Price, 1, PaymentTypes.Standard);

                result += price;

                profit += price - termCost.Costs;
            }


            //TODO get taxes from invoices and calculate taxes only for open positions
            var taxes = CalculateTaxes(taxesManager);

            var taxValue = (result / (double)100) * taxes;
            if (order.Customers.WithTaxes)
            {
                //with taxes
                result += taxValue;
            }

            return result;
        }
        public static double CalculateTotalPrice(Orders order,
                                                 ITermPositionsManager termPositionsManager,
                                                 IPositionsManager positionsManager,
                                                 ITermCostsManager termCostsManager,
                                                 ITaxesManager taxesManager,
                                                 DateTime?fromDate,
                                                 DateTime?toDate,
                                                 ref double profit)
        {
            double result = 0;

            //TODO discuss with customer - take positions where proccessed amount not null (but take with 0)
            var termPositions = termPositionsManager.GetEntities(o => !o.DeleteDate.HasValue && o.Terms.OrderId == order.Id && o.ProccessedAmount.HasValue);

            if (fromDate.HasValue && toDate.HasValue)
            {
                termPositions = termPositions.Where(o => o.Terms.Date >= fromDate.Value && o.Terms.Date <= toDate.Value);
            }

            foreach (var termPosition in termPositions.ToList())
            {
                //positions
                if (termPosition.ProccessedAmount.Value > 0)
                {
                    var positionProfit = CalculatePositionPrice(termPosition.Positions.Price, termPosition.ProccessedAmount.Value,
                                                                termPosition.Positions.Payment);

                    result += positionProfit;

                    //todo calculate profit
                    profit += positionProfit;
                }

                //materials
                foreach (var material in termPosition.TermPositionMaterialRsps.Where(o => !o.DeleteDate.HasValue && o.Amount.HasValue))
                {
                    var amount = material.Amount.Value;
                    if (material.Materials.MaterialAmountTypes == MaterialAmountTypes.Meter)
                    {
                        if (material.Materials.Length != 0)
                        {
                            amount = amount / (double)material.Materials.Length.Value;
                        }
                        else
                        {
                            //todo
                        }
                    }

                    result += CalculatePositionPrice(material.Materials.Price, amount, PaymentTypes.Standard);

                    var materialProfit = material.Materials.Price * amount - material.Materials.BoughtPrice * amount;
                    profit += materialProfit;
                }
            }

            //material positions without terms
            var materialPositionsWithoutTerms = positionsManager.GetEntities(o => o.OrderId == order.Id && !o.DeleteDate.HasValue &&
                                                                             !o.TermId.HasValue && o.MaterialId.HasValue && o.IsMaterialPosition);

            if (fromDate.HasValue && toDate.HasValue)
            {
                materialPositionsWithoutTerms = materialPositionsWithoutTerms.Where(o => o.ChangeDate >= fromDate.Value && o.ChangeDate <= toDate.Value);
            }

            foreach (var position in materialPositionsWithoutTerms.ToList())
            {
                var price = CalculatePositionPrice(position.Price, position.Amount, position.Payment);

                result += price;

                profit += price - position.Materials.BoughtPrice * position.Amount;
            }

            //extra costs
            var termCosts = termCostsManager.GetEntities(o => !o.DeleteDate.HasValue && o.Terms.OrderId == order.Id);

            if (fromDate.HasValue && toDate.HasValue)
            {
                termCosts = termCosts.Where(o => o.Terms.Date >= fromDate.Value && o.Terms.Date <= toDate.Value);
            }

            foreach (var termCost in termCosts.ToList())
            {
                var price = CalculatePositionPrice(termCost.Price, 1, PaymentTypes.Standard);

                result += price;

                profit += price - termCost.Costs;
            }


            //TODO get taxes from invoices and calculate taxes only for open positions
            var taxes = CalculateTaxes(taxesManager);

            var taxValue = (result / (double)100) * taxes;

            if (order.Customers.WithTaxes)
            {
                //with taxes
                result += taxValue;
            }

            return(result);
        }
        protected bool AddInvoicePositions(Orders order, Contracts.Entities.Invoices invoice)
        {
            var result = false;

            var allInvoicePositions = invoicePositionsManager.GetEntities(o => !o.DeleteDate.HasValue &&
                                                                          ((o.PositionId.HasValue && o.Positions.OrderId == order.Id) || (o.TermCostId.HasValue && o.TermCosts.Terms.OrderId == order.Id) ||
                                                                           (o.TermPositionMaterialId.HasValue && o.TermPositionMaterialRsp.TermPositions.Terms.OrderId == order.Id))
                                                                          ).ToList();

            //TODO discuss with customer - take positions where proccessed amount not null (but take with 0)
            var termPositions = termPositionsManager.GetEntities(o => !o.DeleteDate.HasValue && o.Terms.OrderId == order.Id && o.ProccessedAmount.HasValue).ToList();

            foreach (var termPosition in termPositions)
            {
                var invoicePositions = allInvoicePositions.Where(o => o.PositionId.HasValue && o.PositionId.Value == termPosition.PositionId).ToList();

                double amount     = 0;
                var    oldAmount  = invoicePositions.Sum(o => o.Amount);
                double usedAmount = termPositions.Where(o => o.PositionId == termPosition.PositionId).Sum(o => o.ProccessedAmount.Value);
                if (oldAmount == 0)
                {
                    amount = usedAmount;
                }
                else if (usedAmount > oldAmount)
                {
                    amount = usedAmount - oldAmount;
                }

                //positions
                if (amount > 0)
                {
                    var newPosition = new InvoicePositions()
                    {
                        PositionId  = termPosition.PositionId,
                        Invoices    = invoice,
                        Price       = termPosition.Positions.Price,
                        Amount      = amount,
                        CreateDate  = DateTime.Now,
                        ChangeDate  = DateTime.Now,
                        PaymentType = termPosition.Positions.PaymentType
                    };

                    invoice.InvoicePositions.Add(newPosition);

                    allInvoicePositions.Add(newPosition);

                    result = true;
                }

                //materials
                foreach (var material in termPosition.TermPositionMaterialRsps.Where(o => !o.DeleteDate.HasValue && o.Amount.HasValue))
                {
                    invoicePositions = allInvoicePositions.
                                       Where(o => o.TermPositionMaterialId.HasValue && o.TermPositionMaterialId.Value == material.Id).ToList();


                    //old amount
                    oldAmount = invoicePositions.Sum(o => o.Amount);
                    //used amount
                    usedAmount = material.Amount.Value;

                    if (material.Materials.MaterialAmountTypes == MaterialAmountTypes.Meter)
                    {
                        if (material.Materials.Length != 0)
                        {
                            usedAmount = usedAmount / (double)material.Materials.Length.Value;
                        }
                        else
                        {
                            //todo
                        }
                    }


                    amount = 0;
                    if (oldAmount == 0)
                    {
                        amount = usedAmount;
                    }
                    else if (usedAmount > oldAmount)
                    {
                        amount = usedAmount - oldAmount;
                    }


                    if (amount > 0)
                    {
                        var newPosition = new InvoicePositions()
                        {
                            TermPositionMaterialId = material.Id,
                            Invoices    = invoice,
                            Price       = material.Materials.Price,
                            Amount      = amount,
                            CreateDate  = DateTime.Now,
                            ChangeDate  = DateTime.Now,
                            PaymentType = (int)PaymentTypes.Standard
                        };

                        invoice.InvoicePositions.Add(newPosition);
                        result = true;
                    }
                }
            }

            //material positions without terms
            var materialPositionsWithoutTerms = positionsManager.GetEntities(o => o.OrderId == order.Id && !o.DeleteDate.HasValue &&
                                                                             !o.TermId.HasValue && o.MaterialId.HasValue && o.IsMaterialPosition).ToList();

            foreach (var position in materialPositionsWithoutTerms)
            {
                var invoicePositions = allInvoicePositions.
                                       Where(o => o.PositionId.HasValue && o.PositionId.Value == position.Id).ToList();

                double amount = 0;
                //old amount
                var    oldAmount  = invoicePositions.Sum(o => o.Amount);
                double usedAmount = position.Amount;

                if (oldAmount == 0)
                {
                    amount = usedAmount;
                }
                else if (usedAmount > oldAmount)
                {
                    amount = usedAmount - oldAmount;
                }

                if (amount > 0)
                {
                    var newPosition = new InvoicePositions()
                    {
                        Positions   = position,
                        Invoices    = invoice,
                        Price       = position.Materials.Price,
                        Amount      = amount,
                        CreateDate  = DateTime.Now,
                        ChangeDate  = DateTime.Now,
                        PaymentType = (int)PaymentTypes.Standard
                    };

                    invoice.InvoicePositions.Add(newPosition);
                    result = true;
                }
            }

            //extra costs
            var termCosts = termCostsManager.GetEntities(o => !o.DeleteDate.HasValue && o.Terms.OrderId == order.Id).ToList();

            foreach (var termCost in termCosts)
            {
                var invoicePositions = allInvoicePositions.
                                       Where(o => o.TermCostId.HasValue && o.TermCostId.Value == termCost.Id).ToList();

                double amount = 0;
                //old amount
                var oldAmount = invoicePositions.Sum(o => o.Amount);
                if (oldAmount == 0)
                {
                    amount = 1;
                }

                if (amount > 0)
                {
                    var newPosition = new InvoicePositions()
                    {
                        TermCosts   = termCost,
                        Invoices    = invoice,
                        Price       = termCost.Price,
                        Amount      = amount,
                        CreateDate  = DateTime.Now,
                        ChangeDate  = DateTime.Now,
                        PaymentType = (int)PaymentTypes.Standard
                    };

                    invoice.InvoicePositions.Add(newPosition);
                    result = true;
                }
            }

            return(result);
        }