예제 #1
0
        public async Task UpdateSpending(long userId, SpendingUpdate spendingUpdate)
        {
            var daoGroup = await GroupService.GetGroupOfUser(userId, spendingUpdate.GroupId);

            if (!spendingUpdate.Debtors.All(x => daoGroup.Members.Any(m => m.UserId == x.DebtorId)))
            {
                throw new BusinessException("debtor_not_member");
            }

            var currentSpending = await Context.Spendings
                                  .Include(x => x.Debtors)
                                  .SingleOrDefaultAsync(x => x.Id == spendingUpdate.Id);

            if (currentSpending == null)
            {
                throw new ResourceGoneException("spending");
            }

            if (currentSpending.CreditorUserId != userId)
            {
                throw new ResourceForbiddenException("not_creditor");
            }

            var oldDebts = currentSpending.Debtors
                           .ToDictionary(debtor => debtor.DebtorUserId, debtor => debtor.Debt);

            var newDebts = spendingUpdate.Debtors
                           .ToDictionary(debtor => debtor.DebtorId, debtor => debtor.Debt);

            await HistoryService.LogSpendingUpdate(userId, currentSpending, spendingUpdate);

            currentSpending.Name      = spendingUpdate.Name;
            currentSpending.MoneyOwed = spendingUpdate.MoneySpent;
            Context.Debtors.RemoveRange(currentSpending.Debtors);

            var debtors = spendingUpdate.Debtors.Select(x => new DaoDebtor()
            {
                Spending     = currentSpending,
                DebtorUserId = x.DebtorId,
                Debt         = x.Debt
            }).ToList();

            currentSpending.Debtors = debtors.ToList();

            await OptimizedService.OptimizeForUpdateSpending(spendingUpdate.GroupId, userId, oldDebts, newDebts);

            await Context.SaveChangesAsync();
        }
예제 #2
0
        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);
        }
예제 #3
0
        public async Task UpdateSpending(SpendingUpdate spendingUpdate, 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 == spendingUpdate.GroupId);

            if (currentGroup == null)
            {
                throw new ResourceGoneException("group_gone");
            }

            if (spendingUpdate.Debtors.Any(x => spendingUpdate.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 (spendingUpdate.Debtors.Any() &&
                !spendingUpdate.Debtors.All(x => currentGroup.Members.Any(m => m.UserId == x.DebtorId)))
            {
                throw new BusinessException("not_all_debtors_are_members");
            }

            if (spendingUpdate.Debtors.Any() &&
                !spendingUpdate.Debtors.All(x => DbContext.Users.Find(x.DebtorId) != null))
            {
                throw new ResourceGoneException("debtor_gone");
            }

            var currentSpending = await DbContext.Spendings
                                  .Include(x => x.Debtors)
                                  .SingleOrDefaultAsync(x => x.Id == spendingUpdate.Id);

            if (currentSpending == null)
            {
                throw new ResourceForbiddenException("spending_gone");
            }

            if (currentSpending.CreditorUserId != userId)
            {
                throw new ResourceForbiddenException("user_not_creditor");
            }
            using (var transaction = DbContext.Database.BeginTransaction()) {
                try {
                    await _loggingService.LogForGroup(userId, currentSpending.GroupId, currentSpending);

                    currentSpending.Name      = spendingUpdate.Name;
                    currentSpending.MoneyOwed = spendingUpdate.MoneySpent;

                    DbContext.Debtors.RemoveRange(currentSpending.Debtors);
                    var debtors = spendingUpdate.Debtors.Select(x => new DaoDebtor()
                    {
                        Spending     = currentSpending,
                        DebtorUserId = x.DebtorId,
                        Debt         = x.Debt
                    }).ToList();
                    currentSpending.Debtors = debtors.ToList();

                    if (await DbContext.SaveChangesAsync() == 0)
                    {
                        throw new DatabaseException("spending_not_updated");
                    }

                    transaction.Commit();
                } catch {
                    transaction.Rollback();
                    throw;
                }
            }
        }