Esempio n. 1
0
 public RecurringTransaction UpdateRecurringTransaction(
     int id,
     [FromBody] InputRecurringTransaction input,
     [FromQuery] bool updateInstances)
 {
     return(this.manager.UpdateRecurringTransaction(
                id,
                input,
                updateInstances));
 }
Esempio n. 2
0
 public RecurringTransaction CreateRecurringTransaction(InputRecurringTransaction input)
 {
     return(this.manager.CreateRecurringTransaction(input));
 }
        /// <inheritdoc />
        public RecurringTransaction CreateRecurringTransaction(InputRecurringTransaction input)
        {
            this.validator.Description(input.Description);
            var startPeriod = this.validator.DateString(input.StartDateString, "startDate");
            var endPeriod   = input.EndDateString.Select(d => this.validator.DateString(d, "endDate"));

            if (endPeriod.IsSome)
            {
                this.validator.Period(startPeriod, endPeriod);
            }
            this.validator.Interval(input.Interval);
            var type = this.GetTransactionType(input.CategoryId, input.ReceivingAccountId, input.Amount);

            this.validator.Splits(this.splitwiseContext, input.PaymentRequests, input.SplitwiseSplits, type, input.Amount);

            return(this.ConcurrentInvoke(() =>
            {
                var processor = new TransactionProcessor(this.Context, this.splitwiseContext);

                var account = this.Context.Accounts.GetEntity(input.AccountId, false);

                this.validator.AccountType(account.Type);

                var category = input.CategoryId.Select(cId => this.Context.Categories.GetEntity(cId, false));

                AccountEntity receivingAccount = null;
                if (input.ReceivingAccountId.IsSome)
                {
                    receivingAccount = this.Context.Accounts.GetEntity(input.ReceivingAccountId.Value, false);

                    if (receivingAccount.Id == account.Id)
                    {
                        throw new ValidationException("Sender account can not be the same as receiver account.");
                    }

                    this.validator.AccountType(receivingAccount.Type);
                }

                // Verify a Splitwise account exists when adding providing splits.
                if (input.SplitwiseSplits.Any())
                {
                    this.Context.Accounts.GetSplitwiseEntity();
                }

                var entity = new RecurringTransactionEntity
                {
                    Description = input.Description,
                    Type = type,
                    Amount = input.Amount,
                    StartDate = startPeriod,
                    EndDate = endPeriod.ToNullable(),
                    AccountId = input.AccountId,
                    Account = account,
                    CategoryId = input.CategoryId.ToNullable(),
                    Category = category.ToNullIfNone(),
                    ReceivingAccountId = input.ReceivingAccountId.ToNullable(),
                    ReceivingAccount = receivingAccount,
                    Interval = input.Interval,
                    IntervalUnit = input.IntervalUnit,
                    NeedsConfirmation = input.NeedsConfirmation,
                    NextOccurence = startPeriod,
                    PaymentRequests = new List <PaymentRequestEntity>(), // TODO: Payment requests
                    SplitDetails = input.SplitwiseSplits.Select(s => s.ToSplitDetailEntity()).ToList(),
                };

                processor.Process(entity);

                this.Context.RecurringTransactions.Add(entity);
                this.Context.SaveChanges();

                return entity.AsRecurringTransaction();
            }));
        }
        /// <inheritdoc />
        public RecurringTransaction UpdateRecurringTransaction(
            int id, InputRecurringTransaction input, bool updateInstances)
        {
            this.validator.Description(input.Description);
            var startPeriod = this.validator.DateString(input.StartDateString, "startDate");
            var endPeriod   = input.EndDateString.Select(d => this.validator.DateString(d, "endDate"));

            if (endPeriod.IsSome)
            {
                this.validator.Period(startPeriod, endPeriod);
            }
            this.validator.Interval(input.Interval);
            var type = this.GetTransactionType(input.CategoryId, input.ReceivingAccountId, input.Amount);

            this.validator.Splits(this.splitwiseContext, input.PaymentRequests, input.SplitwiseSplits, type, input.Amount);

            return(this.ConcurrentInvoke(() =>
            {
                var processor = new TransactionProcessor(this.Context, this.splitwiseContext);

                var entity = this.Context.RecurringTransactions.GetEntity(id);

                this.validator.AccountType(entity.Account.Type);
                if (entity.ReceivingAccount != null)
                {
                    this.validator.AccountType(entity.ReceivingAccount.Type);
                }

                if (type != entity.Type) // TODO: Add test for this case
                {
                    throw new ValidationException("Changing the type of transaction is not possible.");
                }

                if (!updateInstances && startPeriod != entity.StartDate)
                {
                    throw new ValidationException($"Updating the start date without updating already created instances is not supported.");
                }

                var account = this.Context.Accounts.GetEntity(input.AccountId, false);

                this.validator.AccountType(account.Type);

                var category = input.CategoryId.Select(cId => this.Context.Categories.GetEntity(cId, false));

                AccountEntity receivingAccount = null;
                if (input.ReceivingAccountId.IsSome)
                {
                    receivingAccount = this.Context.Accounts.GetEntity(input.ReceivingAccountId.Value, false);

                    if (receivingAccount.Id == account.Id)
                    {
                        throw new ValidationException("Sender account can not be the same as receiver account.");
                    }

                    this.validator.AccountType(receivingAccount.Type);
                }

                // Verify a Splitwise account exists when adding providing splits.
                if (input.SplitwiseSplits.Any())
                {
                    this.Context.Accounts.GetSplitwiseEntity();
                }

                entity.AccountId = input.AccountId;
                entity.Account = account;
                entity.Description = input.Description;
                entity.StartDate = startPeriod;
                entity.EndDate = endPeriod.ToNullable();
                entity.Amount = input.Amount;
                entity.CategoryId = input.CategoryId.ToNullable();
                entity.Category = category.ToNullIfNone();
                entity.ReceivingAccountId = input.ReceivingAccountId.ToNullable();
                entity.ReceivingAccount = receivingAccount;
                entity.NeedsConfirmation = input.NeedsConfirmation;
                entity.Interval = input.Interval;
                entity.IntervalUnit = input.IntervalUnit;
                entity.SplitDetails = input.SplitwiseSplits.Select(s => s.ToSplitDetailEntity()).ToList();

                var instances = this.Context.Transactions.GetTransactionsFromRecurring(entity.Id);
                var instancesToUpdate = updateInstances
                    ? instances.ToList() // Copy the list
                                         // Always update all unprocessed transactions.
                    : instances.Where(t => !t.Processed).ToList();

                foreach (var instance in instancesToUpdate)
                {
                    processor.RevertIfProcessed(instance);
                    instances.Remove(instance);
                    this.Context.Remove(instance);
                }

                entity.LastOccurence = instances
                                       .OrderByDescending(t => t.Date)
                                       .FirstOrNone()
                                       .Select(t => (LocalDate?)t.Date)
                                       .ValueOrElse(() => (LocalDate?)null);
                entity.SetNextOccurrence();

                processor.Process(entity);

                this.Context.SaveChanges();

                return entity.AsRecurringTransaction();
            }));
        }
        public void Test_CreateRecurringTransaction_SplitwiseSplits()
        {
            this.SplitwiseContextMock.GenerateUser(1, "Wouter", "van Acht");
            this.SplitwiseContextMock.GenerateUser(2, "Jeroen");

            var(account, _) = this.context.GenerateAccount();
            var splitwiseAccount = this.context.GenerateAccount(AccountType.Splitwise);
            var category         = this.context.GenerateCategory();

            this.context.SaveChanges();

            var input = new InputRecurringTransaction
            {
                AccountId          = account.Id,
                Description        = "Transaction",
                StartDateString    = DateTime.Today.ToDateString(),
                EndDateString      = null,
                Amount             = -300,
                CategoryId         = category.Id,
                ReceivingAccountId = Maybe <int> .None,
                NeedsConfirmation  = false,
                Interval           = 1,
                IntervalUnit       = IntervalUnit.Months,
                PaymentRequests    = new List <InputPaymentRequest>(),
                SplitwiseSplits    = new List <InputSplitwiseSplit>
                {
                    new InputSplitwiseSplit
                    {
                        Amount = 100,
                        UserId = 1,
                    },
                    new InputSplitwiseSplit
                    {
                        Amount = 150,
                        UserId = 2,
                    },
                },
            };

            var recurringTransaction = this.RecurringTransactionManager.CreateRecurringTransaction(input);

            this.RefreshContext();

            var transaction = this.context.Transactions.IncludeAll()
                              .Single(t => t.RecurringTransactionId == recurringTransaction.Id);
            var expense =
                this.SplitwiseContextMock.Expenses.Single(e => e.Id == transaction.SplitwiseTransaction.Id);

            account = this.context.Accounts.GetEntity(account.Id);

            Wv8Assert.IsSome(transaction.SplitwiseTransaction.ToMaybe());
            Assert.True(transaction.SplitwiseTransaction.Imported);
            Assert.Equal(250, transaction.SplitwiseTransaction.OwedByOthers);
            Assert.Equal(50, transaction.SplitwiseTransaction.PersonalAmount);
            Assert.Equal(300, transaction.SplitwiseTransaction.PaidAmount);
            Assert.Equal(-50, transaction.PersonalAmount);
            Assert.Equal(-50, recurringTransaction.PersonalAmount);

            Assert.Equal(transaction.SplitwiseTransactionId.Value, expense.Id);
            Assert.Equal(transaction.SplitwiseTransaction.PaidAmount, expense.PaidAmount);
            Assert.Equal(transaction.SplitwiseTransaction.PersonalAmount, expense.PersonalAmount);
            Assert.Equal(transaction.Date, expense.Date);
            Assert.False(expense.IsDeleted);

            Assert.Equal(2, recurringTransaction.SplitDetails.Count);
            Assert.Contains(recurringTransaction.SplitDetails, sd => sd.SplitwiseUserId == 1 && sd.Amount == 100);
            Assert.Contains(recurringTransaction.SplitDetails, sd => sd.SplitwiseUserId == 2 && sd.Amount == 150);
            Assert.Equal(2, transaction.SplitDetails.Count);
            Assert.Contains(transaction.SplitDetails, sd => sd.SplitwiseUserId == 1 && sd.Amount == 100);
            Assert.Contains(transaction.SplitDetails, sd => sd.SplitwiseUserId == 2 && sd.Amount == 150);

            Assert.Equal(-300, account.CurrentBalance);
        }