public async Task LogNewSpending(long userId, DaoSpending newSpending) { dynamic historyEntry = new ExpandoObject(); // SpendingId historyEntry.SpendingId = newSpending.Id; // Name historyEntry.Name = newSpending.Name; // Money historyEntry.Money = newSpending.MoneyOwed; // Debtors var debtors = newSpending.Debtors .Select(x => new { id = x.DebtorUserId, debt = x.Debt }); historyEntry.Debtors = debtors; // Log await LogHistory(userId, newSpending.GroupId, debtors.Select(x => x.id).ToArray(), DaoLogType.Type.CREATE, DaoLogSubType.Type.SPENDING, historyEntry); }
public async Task CreateNewSpending(long userId, NewSpending newSpending) { var daoGroup = await GroupService.GetGroupOfUser(userId, newSpending.GroupId); if (!newSpending.Debtors.All(x => daoGroup.Members.Any(m => m.UserId == x.DebtorId))) { throw new BusinessException("debtor_not_member"); } if (newSpending.Debtors.Any(x => x.DebtorId == userId)) { throw new BusinessException("self_debt"); } using (var transaction = Context.Database.BeginTransaction()) { try { DaoSpending spending = new DaoSpending() { Name = newSpending.Name, MoneyOwed = newSpending.MoneySpent, CreditorUserId = userId, GroupId = daoGroup.Id, Creditor = await UserService.GetUser(userId), Group = daoGroup }; spending.Debtors = newSpending.Debtors.Select(x => new DaoDebtor() { Spending = spending, DebtorUserId = x.DebtorId, Debt = x.Debt }).ToList(); await Context.Spendings.AddAsync(spending); await OptimizedService.OptimizeForNewSpending(userId, newSpending); await Context.SaveChangesAsync(); // Call log AFTER saving, so ID is present await HistoryService.LogNewSpending(userId, spending); await Context.SaveChangesAsync(); transaction.Commit(); } catch { transaction.Rollback(); throw; } } }
public async Task LogRemoveSpending(long userId, long groupId, DaoSpending deletedSpending, HashSet <long> affectedUsers) { dynamic historyEntry = new ExpandoObject(); // Removed spending historyEntry.DeletedSpending = new { Name = deletedSpending.Name, MoneyOwed = deletedSpending.MoneyOwed, Debtors = deletedSpending.Debtors.Select(d => new { DebtorId = d.DebtorUserId, Debt = d.Debt }) }; await LogHistory(userId, groupId, affectedUsers.ToArray(), DaoLogType.Type.REMOVE, DaoLogSubType.Type.MEMBER, historyEntry); }
public SpendingData ToSpendingData(DaoSpending daoSpending) { return(new SpendingData() { Name = daoSpending.Name, Creditor = new UserData() { Id = daoSpending.Creditor.Id, Name = daoSpending.Creditor.DisplayName }, CreditorUserId = daoSpending.CreditorUserId, Id = daoSpending.Id, MoneyOwed = daoSpending.MoneyOwed, Debtors = daoSpending.Debtors.Select(daoDebtor => new DebtorData() { Id = daoDebtor.DebtorUserId, Name = daoDebtor.Debtor.DisplayName, Debt = daoDebtor.Debt }).ToList() }); }
public async Task LogSpendingUpdate(long userId, DaoSpending oldSpending, SpendingUpdate newSpending) { dynamic historyEntry = new ExpandoObject(); // Make name delta if (oldSpending.Name != newSpending.Name) { historyEntry.oldName = oldSpending.Name; historyEntry.newName = newSpending.Name; } // Make money delta if (oldSpending.MoneyOwed != newSpending.MoneySpent) { historyEntry.oldMoney = oldSpending.MoneyOwed; historyEntry.newMoney = newSpending.MoneySpent; } // Record removed debts var removedDebts = oldSpending.Debtors .Select(x => x.DebtorUserId) .Except(newSpending.Debtors.Select(x => x.DebtorId)) .Join(oldSpending.Debtors.Select(x => (x.Debt, x.DebtorUserId)), (oldD) => oldD, (newD) => newD.DebtorUserId, (id, olddebt) => new { id = id, debt = olddebt.Debt }); if (removedDebts.Any()) { historyEntry.removedDebts = removedDebts; } // Record added debts var addedDebts = newSpending.Debtors .Select(x => x.DebtorId) .Except(oldSpending.Debtors.Select(x => x.DebtorUserId)) .Join(newSpending.Debtors.Select(x => (x.Debt, x.DebtorId)), (oldD) => oldD, (newD) => newD.DebtorId, (id, olddebt) => new { id = id, debt = olddebt.Debt }); if (addedDebts.Any()) { historyEntry.addedDebts = addedDebts; } // Record updated debts var updatedDebts = newSpending.Debtors .Select(x => (x.Debt, x.DebtorId)) .Join(oldSpending.Debtors.Select(x => (x.Debt, x.DebtorUserId)), (oldD) => oldD.DebtorId, (newD) => newD.DebtorUserId, (newdebt, olddebt) => new { id = olddebt.DebtorUserId, // should be same as newdebt.DebtorUserId! oldDebt = olddebt.Debt, newDebt = newdebt.Debt }) .Where(x => x.oldDebt != x.newDebt); if (updatedDebts.Any()) { historyEntry.updatedDebts = updatedDebts; } // Log await LogHistory(userId, oldSpending.GroupId, oldSpending.Debtors.Select(x => x.DebtorUserId).Union(newSpending.Debtors.Select(x => x.DebtorId)).ToArray(), DaoLogType.Type.UPDATE, DaoLogSubType.Type.SPENDING, historyEntry); }
public async Task CreateNewSpending(NewSpending newSpending, long userId) { var currentUser = await DbContext.Users.FindAsync(userId); if (currentUser == null) { throw new ResourceGoneException("current_user_gone"); } var currentGroup = await DbContext.Groups .Include(x => x.Members) .SingleOrDefaultAsync(x => x.Id == newSpending.GroupId); if (currentGroup == null) { throw new ResourceGoneException("group_gone"); } if (newSpending.Debtors.Any(x => newSpending.Debtors.Count(d => d.DebtorId == x.DebtorId) > 1)) { throw new BusinessException("duplicate_debtor_id_found"); } if (!currentGroup.Members.Any(x => x.UserId == userId)) { throw new ResourceForbiddenException("user_not_member"); } if (newSpending.Debtors.Any() && !newSpending.Debtors.All(x => currentGroup.Members.Any(m => m.UserId == x.DebtorId))) { throw new BusinessException("not_all_debtors_are_members"); } if (newSpending.Debtors.Any() && !newSpending.Debtors.All(x => DbContext.Users.Find(x.DebtorId) != null)) { throw new ResourceGoneException("debtor_gone"); } DaoSpending spending = new DaoSpending() { Name = newSpending.Name, MoneyOwed = newSpending.MoneySpent, Group = currentGroup, GroupId = currentGroup.Id, Creditor = currentUser, CreditorUserId = currentUser.Id }; var nonSpecifiedCount = newSpending.Debtors.Any() ? newSpending.Debtors.Count(s => !s.Debt.HasValue) : currentGroup.Members.Count(); var autoCalculatedIndividualDebt = nonSpecifiedCount == 0 ? 0 : (newSpending.MoneySpent - newSpending.Debtors.Sum(x => x.Debt ?? 0)) / nonSpecifiedCount; var debtors = newSpending.Debtors.Select(x => new DaoDebtor() { Spending = spending, DebtorUserId = x.DebtorId, Debt = x.Debt ?? autoCalculatedIndividualDebt }).ToList(); // If there were no debtors, populate it from group members if (!debtors.Any()) { debtors = currentGroup.Members.Select(x => new DaoDebtor() { Spending = spending, DebtorUserId = x.UserId, Debt = autoCalculatedIndividualDebt }).ToList(); } spending.Debtors = debtors.ToList(); var insertCount = 1 + spending.Debtors.Count; await DbContext.Spendings.AddAsync(spending); if (await DbContext.SaveChangesAsync() != insertCount) { throw new DatabaseException("spending_not_inserted"); } }