An object to encapsulate all necessary data to perform a transfer operation in a LedgerEntry.
Inheritance: INotifyPropertyChanged
 public void ShowDialog(IEnumerable<LedgerBucket> ledgerBuckets)
 {
     Reset();
     TransferFundsDto = new TransferFundsCommand();
     LedgerBuckets = ledgerBuckets.ToList();
     this.dialogCorrelationId = Guid.NewGuid();
     var dialogRequest = new ShellDialogRequestMessage(BudgetAnalyserFeature.LedgerBook, this, ShellDialogType.SaveCancel)
     {
         CorrelationId = this.dialogCorrelationId,
         Title = "Transfer Funds"
     };
     MessengerInstance.Send(dialogRequest);
 }
        public void IsValid_ShouldBeFalse_GivenLedgersAreTheSame()
        {
            var ledger = new SavedUpForLedger
            {
                BudgetBucket = StatementModelTestData.InsHomeBucket,
                StoredInAccount = StatementModelTestData.ChequeAccount
            };
            this.subject = new TransferFundsCommand
            {
                FromLedger = ledger,
                ToLedger = ledger,
                Narrative = "Foo",
                TransferAmount = 1
            };

            Assert.IsFalse(this.subject.IsValid());
        }
 public void IsValid_ShouldBeFalse_GivenBlankNarrative()
 {
     this.subject = new TransferFundsCommand
     {
         FromLedger = new SpentMonthlyLedger()
         {
             BudgetBucket = StatementModelTestData.PhoneBucket,
             StoredInAccount = StatementModelTestData.ChequeAccount
         },
         ToLedger = new SavedUpForLedger()
         {
             BudgetBucket = StatementModelTestData.InsHomeBucket,
             StoredInAccount = StatementModelTestData.ChequeAccount
         },
         Narrative = "",
         TransferAmount = 0M
     };
 }
        public void IsValid_ShouldBeFalse_GivenLedgersAreTheBothSurplusForSameAccount()
        {
            this.subject = new TransferFundsCommand
            {
                FromLedger = new SurplusLedger
                {
                    BudgetBucket = new SurplusBucket(),
                    StoredInAccount = StatementModelTestData.ChequeAccount
                },
                ToLedger = new SurplusLedger
                {
                    BudgetBucket = new SurplusBucket(),
                    StoredInAccount = StatementModelTestData.ChequeAccount
                },
                Narrative = "Foo",
                TransferAmount = 1
            };

            Assert.IsFalse(this.subject.IsValid());
        }
        public void TransferFunds_ShouldCreateAutoMatchingRule_GivenTransferFromChqSurplusToSavingsInsHome()
        {
            var transferFundsData = new TransferFundsCommand
            {
                AutoMatchingReference = "FooTest12345",
                BankTransferRequired = true,
                FromLedger = LedgerBookTestData.SurplusLedger,
                Narrative = "Save excess for November",
                ToLedger = LedgerBookTestData.HouseInsLedgerSavingsAccount,
                TransferAmount = 200M
            };

            this.mockRuleService.Setup(m => m.CreateNewSingleUseRule(transferFundsData.FromLedger.BudgetBucket.Code, null, new[] { "FooTest12345" }, null, -200, true))
                .Returns(new SingleUseMatchingRule(this.mockBucketRepo.Object));
            this.mockRuleService.Setup(m => m.CreateNewSingleUseRule(transferFundsData.ToLedger.BudgetBucket.Code, null, new[] { "FooTest12345" }, null, 200, true))
                .Returns(new SingleUseMatchingRule(this.mockBucketRepo.Object));

            this.subject.TransferFunds(transferFundsData, this.testDataEntryLine);

            this.mockRuleService.VerifyAll();
        }
        public void TransferFunds_ShouldDecreaseChqBalance_GivenTransferFromChqSurplusToSavingsInsHome()
        {
            var transferDetails = new TransferFundsCommand
            {
                FromLedger = this.surplusChqLedger,
                ToLedger = this.insHomeSavLedger,
                TransferAmount = 22.00M,
                Narrative = "Testing 123"
            };

            decimal beforeBalance = this.testDataEntryLine.BankBalances.First(b => b.Account == StatementModelTestData.ChequeAccount).Balance
                                    + this.testDataEntryLine.BankBalanceAdjustments
                                        .Where(a => a.BankAccount == StatementModelTestData.ChequeAccount)
                                        .Sum(a => a.Amount);
            this.subject.TransferFunds(transferDetails, this.testDataEntryLine);
            decimal afterBalance = this.testDataEntryLine.BankBalances.First(b => b.Account == StatementModelTestData.ChequeAccount).Balance
                                   + this.testDataEntryLine.BankBalanceAdjustments
                                       .Where(a => a.BankAccount == StatementModelTestData.ChequeAccount)
                                       .Sum(a => a.Amount);

            Assert.AreEqual(beforeBalance - transferDetails.TransferAmount, afterBalance);
        }
        public void SettingFromLedger_ShouldPopulateAutoMatchingReference_GivenFromAndToLedgersAreDifferent()
        {
            this.subject = new TransferFundsCommand
            {
                FromLedger = new SpentMonthlyLedger
                {
                    BudgetBucket = StatementModelTestData.PhoneBucket,
                    StoredInAccount = StatementModelTestData.ChequeAccount
                },
                ToLedger = new SavedUpForLedger
                {
                    BudgetBucket = StatementModelTestData.InsHomeBucket,
                    StoredInAccount = StatementModelTestData.SavingsAccount
                },
                Narrative = "Foo",
                TransferAmount = 12.34M
            };

            Assert.IsTrue(this.subject.AutoMatchingReference.IsSomething());
        }
        public void IsValid_ShouldIndicateBankTransferRequired_GivenFromAndToLedgersAreDifferent()
        {
            this.subject = new TransferFundsCommand
            {
                FromLedger = new SpentMonthlyLedger
                {
                    BudgetBucket = StatementModelTestData.PhoneBucket,
                    StoredInAccount = StatementModelTestData.ChequeAccount
                },
                ToLedger = new SavedUpForLedger
                {
                    BudgetBucket = StatementModelTestData.InsHomeBucket,
                    StoredInAccount = StatementModelTestData.SavingsAccount
                },
                Narrative = "Foo",
                TransferAmount = 12.34M
            };

            Assert.IsTrue(this.subject.BankTransferRequired);
        }
        public void IsValid_ShouldBeTrue_GivenThisRealExample()
        {
            this.subject = new TransferFundsCommand
            {
                FromLedger = new SurplusLedger
                {
                    BudgetBucket = new SurplusBucket(),
                    StoredInAccount = StatementModelTestData.ChequeAccount
                },
                ToLedger = new SavedUpForLedger
                {
                    BudgetBucket = StatementModelTestData.CarMtcBucket,
                    StoredInAccount = StatementModelTestData.ChequeAccount
                },
                Narrative = "Foo",
                TransferAmount = 12
            };

            Assert.IsTrue(this.subject.IsValid());
        }
        /// <summary>
        ///     Transfer funds from one ledger bucket to another. This is only possible if the current ledger reconciliation is
        ///     unlocked.
        ///     This is usually used during reconciliation.
        /// </summary>
        /// <param name="reconciliation">
        ///     The reconciliation line that this transfer will be created in.  A transfer can only occur
        ///     between two ledgers in the same reconciliation.
        /// </param>
        /// <param name="transferDetails">The details of the requested transfer.</param>
        public void TransferFunds(LedgerEntryLine reconciliation, TransferFundsCommand transferDetails)
        {
            if (reconciliation == null)
            {
                throw new ArgumentNullException(nameof(reconciliation),
                    "There are no reconciliations. Transfer funds can only be used on the most recent reconciliation.");
            }

            this.reconciliationManager.TransferFunds(transferDetails, reconciliation);
        }
 private void Reset()
 {
     TransferFundsDto = null;
     BankTransferConfirmed = false;
     LedgerBuckets = null;
 }
        public void TransferFunds_ShouldNotCreateAutoMatchingRule_GivenTransferFromChqSurplusToChqHairCut()
        {
            var transferFundsData = new TransferFundsCommand
            {
                AutoMatchingReference = "FooTest12345",
                BankTransferRequired = false,
                FromLedger = LedgerBookTestData.SurplusLedger,
                Narrative = "Save excess for November",
                ToLedger = LedgerBookTestData.HairLedger,
                TransferAmount = 400M
            };

            var success = true;
            this.mockRuleService.Setup(m => m.CreateNewSingleUseRule(It.IsAny<string>(), null, new[] { "FooTest12345" }, null, It.IsAny<decimal>(), true))
                .Returns(new SingleUseMatchingRule(this.mockBucketRepo.Object))
                .Callback(() => success = false);

            this.subject.TransferFunds(transferFundsData, this.testDataEntryLine);

            Assert.IsTrue(success);
        }
        public void TransferFunds_ShouldIncreaseSavInsHome_GivenTransferFromChqSurplusToSavingsInsHome()
        {
            var transferDetails = new TransferFundsCommand
            {
                FromLedger = this.surplusChqLedger,
                ToLedger = this.insHomeSavLedger,
                TransferAmount = 22.00M,
                Narrative = "Testing 123"
            };

            decimal beforeBalance = this.testDataEntryLine.Entries.First(e => e.LedgerBucket == this.insHomeSavLedger).Balance;
            this.subject.TransferFunds(transferDetails, this.testDataEntryLine);
            decimal afterBalance = this.testDataEntryLine.Entries.First(e => e.LedgerBucket == this.insHomeSavLedger).Balance;

            Assert.AreEqual(beforeBalance + transferDetails.TransferAmount, afterBalance);
        }
        private void PerformBankTransfer(TransferFundsCommand transferDetails, LedgerEntryLine ledgerEntryLine)
        {
            var sourceTransaction = new CreditLedgerTransaction
            {
                Amount = -transferDetails.TransferAmount,
                AutoMatchingReference = transferDetails.AutoMatchingReference,
                Date = ledgerEntryLine.Date,
                Narrative = transferDetails.Narrative
            };

            var destinationTransaction = new CreditLedgerTransaction
            {
                Amount = transferDetails.TransferAmount,
                AutoMatchingReference = transferDetails.AutoMatchingReference,
                Date = ledgerEntryLine.Date,
                Narrative = transferDetails.Narrative
            };

            if (transferDetails.BankTransferRequired)
            {
                ledgerEntryLine.BalanceAdjustment(-transferDetails.TransferAmount, transferDetails.Narrative,
                    transferDetails.FromLedger.StoredInAccount);
                ledgerEntryLine.BalanceAdjustment(transferDetails.TransferAmount, transferDetails.Narrative,
                    transferDetails.ToLedger.StoredInAccount);
                this.transactionRuleService.CreateNewSingleUseRule(
                    transferDetails.FromLedger.BudgetBucket.Code,
                    null,
                    new[] { transferDetails.AutoMatchingReference },
                    null,
                    -transferDetails.TransferAmount,
                    true);
                this.transactionRuleService.CreateNewSingleUseRule(
                    transferDetails.ToLedger.BudgetBucket.Code,
                    null,
                    new[] { transferDetails.AutoMatchingReference },
                    null,
                    transferDetails.TransferAmount,
                    true);
            }

            // No need for a source transaction for surplus ledger.
            if (!(transferDetails.FromLedger.BudgetBucket is SurplusBucket))
            {
                var ledgerEntry = ledgerEntryLine.Entries.Single(e => e.LedgerBucket == transferDetails.FromLedger);
                ledgerEntry.AddTransaction(sourceTransaction);
            }

            // No need for a destination transaction for surplus ledger.
            if (!(transferDetails.ToLedger.BudgetBucket is SurplusBucket))
            {
                var ledgerEntry = ledgerEntryLine.Entries.Single(e => e.LedgerBucket == transferDetails.ToLedger);
                ledgerEntry.AddTransaction(destinationTransaction);
            }
        }
        /// <summary>
        ///     Performs a funds transfer for the given ledger entry line.
        /// </summary>
        public void TransferFunds(TransferFundsCommand transferDetails, LedgerEntryLine ledgerEntryLine)
        {
            if (transferDetails == null)
            {
                throw new ArgumentNullException(nameof(transferDetails));
            }

            if (ledgerEntryLine == null)
            {
                throw new ArgumentNullException(nameof(ledgerEntryLine));
            }

            if (!transferDetails.IsValid())
            {
                throw new InvalidOperationException(
                    "Code Error: The transfer command is in an invalid state, this should be resolved in the UI.");
            }

            PerformBankTransfer(transferDetails, ledgerEntryLine);
        }
        public void IsValid_ShouldBeFalse_GivenNegativeAmount()
        {
            this.subject = new TransferFundsCommand
            {
                FromLedger = new SpentMonthlyLedger
                {
                    BudgetBucket = StatementModelTestData.PhoneBucket,
                    StoredInAccount = StatementModelTestData.ChequeAccount
                },
                ToLedger = new SavedUpForLedger
                {
                    BudgetBucket = StatementModelTestData.InsHomeBucket,
                    StoredInAccount = StatementModelTestData.ChequeAccount
                },
                Narrative = "Foo",
                TransferAmount = -20M
            };

            Assert.IsFalse(this.subject.IsValid());
        }
        public void TransferFunds_ShouldDecreaseChqSurplus_GivenTransferFromChqSurplusToChqCarMtc()
        {
            var transferDetails = new TransferFundsCommand
            {
                FromLedger = this.surplusChqLedger,
                ToLedger = this.phNetChqLedger,
                TransferAmount = 22.00M,
                Narrative = "Testing 123"
            };

            decimal beforeBalance = this.testDataEntryLine.SurplusBalances.First(b => b.Account == StatementModelTestData.ChequeAccount).Balance;
            this.subject.TransferFunds(transferDetails, this.testDataEntryLine);
            decimal afterBalance = this.testDataEntryLine.SurplusBalances.First(b => b.Account == StatementModelTestData.ChequeAccount).Balance;

            Assert.AreEqual(beforeBalance - transferDetails.TransferAmount, afterBalance);
        }