예제 #1
0
 private static OperationType GetCategoryType(ExpensesContext db, long subcategoryId)
 {
     return((from sub in db.Subcategories
             join cat in db.Categories on sub.CategoryId equals cat.Id
             where sub.Id == subcategoryId
             select cat.Type).First());
 }
예제 #2
0
 protected virtual TEntity UpdateCore(ExpensesContext context, TEntity item)
 {
     BeforeUpdate(context, item);
     context.Entry(item).State = EntityState.Modified;
     context.SaveChanges();
     return(item);
 }
예제 #3
0
 protected override void BeforeAdd(ExpensesContext context, TOperation operation)
 {
     operation.UserId        = m_userId;
     operation.OperationTime = DateTime.Now;
     operation.CheckFields();
     CommitOperation(context, operation);
 }
예제 #4
0
 protected virtual TEntity AddCore(ExpensesContext context, TEntity item)
 {
     BeforeAdd(context, item);
     item = context.Set <TEntity> ().Add(item);
     context.SaveChanges();
     return(item);
 }
예제 #5
0
        public IActionResult SubmitExpenses(AddExpenseViewModel model)
        {
            if (model.Expenses == null || model.Expenses.Count() == 0)
            {
                return(this.Json("No item found"));
            }
            else
            {
                foreach (var item in model.Expenses)
                {
                    if (String.IsNullOrEmpty(item.Address))
                    {
                        item.Address = "Current Location";
                    }
                    if (String.IsNullOrEmpty(item.Description))
                    {
                        item.Description = String.Empty;
                    }
                }

                try
                {
                    ExpensesContext.AddNewExpenses(model.Expenses.Select(x => AutoMapperFactory.ExpenseViewModel_UIExpense.CreateMapper().Map <UIExpense>(x)).Cast <Expense>().ToList(), GetUserInfo());
                }
                catch (Exception ex)
                {
                    return(this.Json("Failed to add new expense item."
                                     + Environment.NewLine + ex.Message));
                }

                ModelState.Clear();
                return(this.Json("Pass"));
            }
        }
        public void OnGet_WhenThereAreThreeMovementsAvailable_ThenMovementsAreDescendingByDateAndBalanceIsTheSum()
        {
            var options = new DbContextOptionsBuilder <ExpensesContext>()
                          .UseInMemoryDatabase(databaseName: "OnGet_WhenThereAreThreeMovementsAvailable_ThenMovementsAreDescendingByDateAndBalanceIsTheSum")
                          .Options;

            using (var expensesContext = new ExpensesContext(options))
            {
                var category = new Category("Default");
                expensesContext.Categories.Add(category);
                expensesContext.Movements.Add(new Movement(-10, "second", category, null, new DateTime(2017, 11, 10)));
                expensesContext.Movements.Add(new Movement(-10, "third", category, null, new DateTime(2017, 11, 11)));
                expensesContext.Movements.Add(new Movement(50, "first", category, null, new DateTime(2017, 11, 9)));
                expensesContext.SaveChanges();
                var model = new IndexModel(expensesContext);

                model.OnGet();

                Assert.NotNull(model.Movements);
                Assert.NotEmpty(model.Movements);
                Assert.Equal(3, model.Movements.Length);
                Assert.Equal("third", model.Movements[0].Reason);
                Assert.Equal("second", model.Movements[1].Reason);
                Assert.Equal("first", model.Movements[2].Reason);
                Assert.True(model.Movements.All(m => m.Category == category));
                Assert.Equal(30, model.Balance);
            }
        }
예제 #7
0
        private static IQueryable <Operation> GetQuery(ExpensesContext db, DateTime?startTime, DateTime?endTime, long?subcategoryId, long?categoryId)
        {
            IQueryable <Operation> query = db.Operations;

            if (categoryId != null)
            {
                query = from op in db.Operations
                        join sub in db.Subcategories on op.SubcategoryId equals sub.Id
                        where sub.CategoryId == categoryId
                        select op;
            }
            if (subcategoryId != null)
            {
                query = query.Where(op => op.SubcategoryId == subcategoryId);
            }
            if (startTime != null)
            {
                query = query.Where(op => op.OperationTime >= startTime);
            }
            if (endTime != null)
            {
                query = query.Where(op => op.OperationTime <= endTime);
            }
            return(query);
        }
예제 #8
0
        public JsonResult GetAllExpenses(int userId, string dbInstance)
        {
            try
            {
                if (userId == 0)
                {
                    throw new APIExpensesControllerException("Invalid input [UserId]");
                }
                if (String.IsNullOrEmpty(dbInstance))
                {
                    throw new APIExpensesControllerException("Invalid input [DBInstance]");
                }

                User usr = new User()
                {
                    UserId = userId, DBInstance = dbInstance
                };
                return(Json(ExpensesContext.LoadUserExpenses(usr)));
            }
            catch (APIExpensesControllerException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                throw new Exception("Data Access error: " + ex.Message);
            }
        }
예제 #9
0
        public static void Import(IList <Expense> expenses, string connectionName)
        {
            using (var db = new ExpensesContext("name=" + connectionName))
                using (var transaction = db.BeginTransaction())
                {
                    var accounts      = new Dictionary <string, Account> ();
                    var currencies    = new Dictionary <string, Currency> ();
                    var categories    = new Dictionary <string, Category> ();
                    var subcategories = new Dictionary <string, Subcategory> ();
                    var user          = db.Users.First();

                    foreach (var expense in expenses.OrderBy(e => e.Date))
                    {
                        var tuple = GetSum(expense);
                        db.Operations.Add(new Operation {
                            AccountId     = GetAccount(db, expense.Account, tuple.Item2, accounts, currencies).Id,
                            Amount        = tuple.Item1,
                            SubcategoryId = GetSubcategory(db, expense.Subcategory, expense.Category, subcategories, categories).Id,
                            OperationTime = expense.Date,
                            UserId        = user.Id,
                            Comment       = expense.Comment
                        });
                    }

                    transaction.Commit();
                }
        }
예제 #10
0
        public void Create_WhenGivenADeposit_ThenTheBalanceIsIncreasedAndANewMovementIsCreated()
        {
            var options = new DbContextOptionsBuilder <ExpensesContext>()
                          .UseInMemoryDatabase(databaseName: "Create_WhenGivenADeposit_ThenTheBalanceIsIncreasedAndANewMovementIsCreated")
                          .Options;

            using (var expensesContext = new ExpensesContext(options))
            {
                expensesContext.Categories.Add(new Category("Foo"));
                var controller = new MovementsController(expensesContext);

                var form = new MovementForm
                {
                    Amount     = 100,
                    Type       = "deposit",
                    CategoryId = 1
                };
                var result = controller.Create(form);

                Assert.IsAssignableFrom <JsonResult>(result);
                dynamic json = ((JsonResult)result).Value;
                //Assert.Equal(100M, (decimal)json.balance);
                //Assert.Equal(100M, (decimal)json.movement.amount);
                Assert.Equal(1, expensesContext.Movements.ToArray().Length);
                Assert.Equal(100M, expensesContext.Movements.Sum(m => m.Amount));
            }
        }
예제 #11
0
 public Handler(
     ExpensesContext db,
     ICurrentUser currentUser)
 {
     _context     = db;
     _currentUser = currentUser;
 }
예제 #12
0
 protected override void BeforeAdd(ExpensesContext db, Debt operation)
 {
     if (operation.RepayedAmount != 0.0)
     {
         throw new InvalidOperationException($"{nameof(Debt.RepayedAmount)} must be zero for new Debt record");
     }
     base.BeforeAdd(db, operation);
 }
예제 #13
0
 protected override TOperation AddCore(ExpensesContext context, TOperation operation)
 {
     using (var transaction = context.BeginTransaction(IsolationLevel.Serializable)) {
         var result = base.AddCore(context, operation);
         transaction.Commit();
         return(result);
     }
 }
예제 #14
0
 public Handler(
     ExpensesContext context,
     IJwtTokenGenerator jwtTokenGenerator,
     IOptions <JwtSettings> jwtSettings)
 {
     _context           = context;
     _jwtTokenGenerator = jwtTokenGenerator;
     _jwtSettings       = jwtSettings;
 }
예제 #15
0
 public Handler(
     ExpensesContext context,
     IJwtTokenGenerator jwtTokenGenerator,
     IJwtSigningCredentials signingCredentials)
 {
     _context            = context;
     _jwtTokenGenerator  = jwtTokenGenerator;
     _signingCredentials = signingCredentials;
 }
예제 #16
0
 public Handler(
     IPasswordHasher passwordHasher,
     IJwtTokenGenerator jwtTokenGenerator,
     ExpensesContext context)
 {
     _passwordHasher    = passwordHasher;
     _jwtTokenGenerator = jwtTokenGenerator;
     _context           = context;
 }
예제 #17
0
 protected override TOperation UpdateCore(ExpensesContext db, TOperation operation)
 {
     using (var transaction = db.BeginTransaction(IsolationLevel.Serializable))
     {
         BeforeUpdate(db, operation);
         db.SaveChanges();
         transaction.Commit();
         return(operation);
     }
 }
예제 #18
0
        protected override void BeforeUpdate(ExpensesContext db, Debt operation)
        {
            var existing = db.Debts.Find(operation.Id);

            if (Math.Abs(operation.RepayedAmount - existing.RepayedAmount) > 0.00001)
            {
                throw new InvalidOperationException("{nameof(Debt.RepayedAmount)} cannot be edited");
            }
            base.BeforeUpdate(db, operation);
        }
예제 #19
0
        protected override void BeforeUpdate(ExpensesContext db, Repayment operation)
        {
            var existing = db.Repayments.Find(operation.Id);

            if (operation.DebtId != existing.DebtId)
            {
                throw new InvalidOperationException($"{nameof(Repayment.DebtId)} cannot be changed");
            }
            base.BeforeUpdate(db, operation);
        }
예제 #20
0
 protected override void CommitOperation(ExpensesContext db, Operation operation, bool rollback)
 {
     CommitAndRound(
         operation,
         db.Accounts.Find(operation.AccountId),
         (from ei in db.Subcategories
          join ec in db.Categories on ei.CategoryId equals ec.Id
          where ei.Id == operation.SubcategoryId
          select ec.Type).First(),
         rollback);
 }
예제 #21
0
        protected override void BeforeUpdate(ExpensesContext db, TOperation operation)
        {
            operation.UserId = m_userId;
            operation.CheckFields();
            var dbOperation = db.Set <TOperation>().Find(operation.Id);

            //Operation time must stay unchanged
            operation.OperationTime = dbOperation.OperationTime;
            RollbackOperation(db, dbOperation);
            CommitOperation(db, operation);
            Cloner.Clone(operation, dbOperation);
        }
예제 #22
0
        public ExpensesContext ReturnDbContext()
        {
            DbContextOptions <ExpensesContext> options;
            var builder = new DbContextOptionsBuilder <ExpensesContext>();

            builder.UseSqlServer(GetConnectionString());
            options = builder.Options;

            var context = new ExpensesContext(options);

            return(context);
        }
예제 #23
0
        protected override void CommitOperation(ExpensesContext db, Repayment operation, bool rollback)
        {
            var da = (from d in db.Debts
                      join a in db.Accounts on d.AccountId equals a.Id
                      where d.Id == operation.DebtId
                      select new { debt = d, account = a }).First();

            OperationsService.CommitAndRound(operation, da.account, da.debt.Type == DebtType.Lend ? OperationType.Income : OperationType.Expense, rollback);
            var debtWrapper = new AmountWrapper(() => da.debt.RepayedAmount, amount => da.debt.RepayedAmount = amount);

            OperationsService.CommitAndRound(operation, debtWrapper, OperationType.Income, rollback);
        }
예제 #24
0
        public IViewComponentResult Invoke(AllExpensePagerViewModel pagerModel)
        {
            AllExpenseViewModel model = null;

            if (ModelState.IsValid)
            {
                try
                {
                    long   lastItemId    = 0;
                    string lastItemIdStr = HttpContext.Session.Get <string>((GetSessionPrefix() + "IM_LASTITEMID"));
                    if (!String.IsNullOrEmpty(lastItemIdStr))
                    {
                        lastItemId = long.Parse(lastItemIdStr);
                    }
                    pagerModel.LastItemId = lastItemId;

                    model       = new AllExpenseViewModel();
                    model.Pager = pagerModel;

                    UIUser usr           = GetUserInfo();
                    var    expenseCategs = LoadUserExpenseCategs(usr);
                    var    list          = ExpensesContext.LoadUserExpensesPagedNav(usr, pagerModel.StartTs, pagerModel.EndTs, pagerModel.PageSize, pagerModel.PageIndex).Select(x => AutoMapperFactory.ExpenseViewModel_UIExpense.CreateMapper().Map <ExpenseViewModel>(new UIExpense(x))).ToList();
                    foreach (var item in list)
                    {
                        item.ExpenseCateg = expenseCategs.FirstOrDefault(x => x.ExpenseCategId == item.ExpenseCategId);

                        lastItemId = item.ExpenseId;
                    }
                    model.Expenses = list;

                    HttpContext.Session.Put((GetSessionPrefix() + "IM_LASTITEMID"), lastItemId.ToString());
                }
                catch (Exception ex)
                {
                    ViewData["WarningMessage"] = ex.Message;
                }

                model.Pager.JsonConvertObject = JsonConvert.SerializeObject(model.Pager);

                return(View(model));
            }
            else
            {
                model = new AllExpenseViewModel()
                {
                    Expenses = new List <ExpenseViewModel>(), Pager = pagerModel
                };
                model.Pager.JsonConvertObject = JsonConvert.SerializeObject(model.Pager);

                return(View(model));
            }
        }
        public void OnGet_WhenThereAreNoMovementsAvailable_ThenMovementsAreAnEmptyArrayAndBalanceIsZero()
        {
            var options = new DbContextOptionsBuilder <ExpensesContext>()
                          .UseInMemoryDatabase(databaseName: "OnGet_WhenThereAreNoMovementsAvailable_ThenMovementsAreAnEmptyArrayAndBalanceIsZero")
                          .Options;

            using (var expensesContext = new ExpensesContext(options))
            {
                var model = new IndexModel(expensesContext);

                model.OnGet();

                Assert.NotNull(model.Movements);
                Assert.Empty(model.Movements);
                Assert.Equal(0, model.Balance);
            }
        }
예제 #26
0
        private static Category GetCategory(ExpensesContext db, string name, IDictionary <string, Category> categories)
        {
            var result = categories.SafeGet(name);

            if (result != null)
            {
                return(result);
            }
            result = db.Categories.FirstOrDefault(item => item.Name == name);
            if (result == null)
            {
                result = db.Categories.Add(new Category {
                    Name = name, Type = OperationType.Expense
                });
                db.SaveChanges();
            }
            categories.Add(name, result);
            return(result);
        }
예제 #27
0
        private static Currency GetCurrency(ExpensesContext db, string name, IDictionary <string, Currency> currencies)
        {
            var result = currencies.SafeGet(name);

            if (result != null)
            {
                return(result);
            }
            result = db.Currencies.FirstOrDefault(item => item.ShortName == name);
            if (result == null)
            {
                result = db.Currencies.Add(new Currency {
                    Name = name, ShortName = name
                });
                db.SaveChanges();
            }
            currencies.Add(name, result);
            return(result);
        }
예제 #28
0
        private static Account GetAccount(ExpensesContext db, string name, string currency, IDictionary <string, Account> accounts, IDictionary <string, Currency> currencies)
        {
            name = $"{name} {currency}";
            var result = accounts.SafeGet(name);

            if (result != null)
            {
                return(result);
            }
            result = db.Accounts.FirstOrDefault(item => item.Name == name);
            if (result == null)
            {
                result = db.Accounts.Add(new Account {
                    Name = name, CurrencyId = GetCurrency(db, currency, currencies).Id
                });
                db.SaveChanges();
            }
            accounts.Add(name, result);
            return(result);
        }
예제 #29
0
        protected override void CommitOperation(ExpensesContext db, Exchange exchange, bool rollback)
        {
            if (exchange.SourceAccountId == exchange.DestAccountId)
            {
                throw new InvalidOperationException("Cannot exchange from an account to itself");
            }
            var source = db.Accounts.Find(exchange.SourceAccountId);
            var dest   = db.Accounts.Find(exchange.DestAccountId);

            if (source.CurrencyId == dest.CurrencyId && Math.Abs(exchange.SourceAmount - exchange.DestAmount) > 0.0001)
            {
                throw new InvalidOperationException("Exchange operation between accounts with the same currency must have equal amounts");
            }
            exchange.SourceAmount = Math.Round(exchange.SourceAmount, 2);
            exchange.DestAmount   = Math.Round(exchange.DestAmount, 2);
            double sign = rollback ? -1.0 : 1.0;

            source.Amount = Math.Round(source.Amount - sign * exchange.SourceAmount);
            dest.Amount   = Math.Round(dest.Amount + sign * exchange.DestAmount);
        }
예제 #30
0
        private static Subcategory GetSubcategory(ExpensesContext db, string name, string category, IDictionary <string, Subcategory> subcategories, IDictionary <string, Category> categories)
        {
            var fullname = $"{name} {category}";
            var result   = subcategories.SafeGet(fullname);

            if (result != null)
            {
                return(result);
            }
            var cat = GetCategory(db, category, categories);

            result = db.Subcategories.FirstOrDefault(item => item.Name == name && item.CategoryId == cat.Id);
            if (result == null)
            {
                result = db.Subcategories.Add(new Subcategory {
                    Name = name, CategoryId = cat.Id
                });
                db.SaveChanges();
            }
            subcategories.Add(fullname, result);
            return(result);
        }