Пример #1
0
        public void SetUp()
        {
            var expenseItem = new ExpenseLineItem(1, "Somu", 234);

            _items.Add(expenseItem);
            _expenseCalculatorFactory = new ExpenseCalculatorFactory(_items);
        }
        public void SetUp()
        {
            var expenseItem1 = new ExpenseLineItem(1, "Somu", 234);
            var expenseItem2 = new ExpenseLineItem(2, "Somu1", 455);
            var expenseItem3 = new ExpenseLineItem(1, "Somu", 343);

            _items.Add(expenseItem1);
            _items.Add(expenseItem2);
            _items.Add(expenseItem3);
            _moqExpenseCalculatorFactory = new Mock <IExpenseCalculatorFactory>();


            _moqExpenseCalculatorFactory.Setup(x => x.CreateExpenseCalculator()).Returns(new ExpenseCalculator(_items));
        }
Пример #3
0
        public ExpenseRepaymentCollection Post([FromBody] IEnumerable <User> users)
        {
            if (users == null || !users.Any() || users.All(u => !u.Expenses.Any()))
            {
                // empty result passed
                ThrowResponseException(HttpStatusCode.BadRequest, "Empty list of users entered");
            }

            if (users.SelectMany(u => u.Expenses).Any(exp => exp < 0))
            {
                // one or more expenses has a negative amount
                ThrowResponseException(HttpStatusCode.BadRequest, "One or more Expense line items have a negative expense amount");
            }

            ExpenseRepaymentCollection result = new ExpenseRepaymentCollection();

            // Flatten list into 1 expense line item per name, with their total expenditure
            var totalExpenses = users.GroupBy(u => u.Name)
                                .Select(x =>
                                        new ExpenseLineItem()
            {
                Name          = x.Key,
                ExpenseAmount = x.SelectMany(y => y.Expenses).Sum()
            }
                                        ).ToList();

            decimal totalExpenditure = 0;

            try
            {
                totalExpenditure = totalExpenses.Sum(e => e.ExpenseAmount);
            }
            catch (OverflowException)
            {
                ThrowResponseException(HttpStatusCode.BadRequest, "Expenses entered are total greater than maximum precision");
            }


            if (totalExpenditure == 0)
            {
                return(result);
            }

            decimal equalShares = totalExpenditure / totalExpenses.Count;

            if (totalExpenses.All(e => e.EqualWithinOneCent(equalShares)))
            {
                // All users have already paid equally, no repayments need to be done
                return(result);
            }

            //Because we only ever need to look at the front of the line, a stack is more efficient
            Stack <ExpenseLineItem> paidMoreThanEqual = new Stack <ExpenseLineItem>(totalExpenses.Where(e => e.ExpenseAmount > equalShares));
            Stack <ExpenseLineItem> paidLessThanEqual = new Stack <ExpenseLineItem>(totalExpenses.Where(e => e.ExpenseAmount < equalShares));

            List <ExpenseRepayment> repayments = new List <ExpenseRepayment>();

            while (paidMoreThanEqual.Any() && paidLessThanEqual.Any())
            {
                ExpenseLineItem currentUnderpayer = paidLessThanEqual.Peek();
                ExpenseLineItem currentOverpayer  = paidMoreThanEqual.Peek();

                decimal amountToPay = Math.Min(currentOverpayer.ExpenseAmount - equalShares, equalShares - currentUnderpayer.ExpenseAmount);

                repayments.Add(new ExpenseRepayment()
                {
                    PayFrom = currentUnderpayer.Name, PayTo = currentOverpayer.Name, Amout = amountToPay
                });

                currentOverpayer.ExpenseAmount  -= amountToPay;
                currentUnderpayer.ExpenseAmount += amountToPay;

                if (currentUnderpayer.EqualWithinOneCent(equalShares))
                {
                    paidLessThanEqual.Pop();
                }

                if (currentOverpayer.EqualWithinOneCent(equalShares))
                {
                    paidMoreThanEqual.Pop();
                }
            }

            result.Repayments = repayments.ToArray();
            result.Status     = (byte)(result.Repayments.Any() ? 1 : 0);
            return(result);
        }
Пример #4
0
        private static void InsertExpensive()
        {
            var item = new ExpenseLineItem { Amount = 3000, Description = "Expensive Item" };

            var expense = new Expense
            {
                Description = "Expensive Description",
                Title = "Expensive Title"
            };
            expense.AddLineItem(item);

            using (var uow = new UnitOfWork())
            {
                var repository = uow.GetRepository<ExpenseRepository>();

                repository.Save(expense);

                uow.Commit();
            }
        }
Пример #5
0
        private static void InsertWithItems()
        {
            var item1 = new ExpenseLineItem { Amount = 10, Description = "Item 1" };
            var item2 = new ExpenseLineItem { Amount = 300, Description = "Item 2" };

            var expense = new Expense
            {
                Description = "Expense",
                Title = "Title"
            };
            expense.AddLineItem(item1);
            expense.AddLineItem(item2);

            using (var uow = new UnitOfWork())
            {
                var repository = uow.GetRepository<ExpenseRepository>();

                repository.Save(expense);

                uow.Commit();
            }
        }