changeset 898:97c104efbb5e

IN 32: Adds unit test for when the reconciled balance or reconciled transactions do not sum up to the unused balance distribution.
author John Schneiderman <JohnMS@member.fsf.org>
date Mon, 03 Oct 2022 17:52:12 +0200
parents 2b0bc66b951f
children 563ef254bc3a
files src/navigation/internal/BudgetBankLedgers.h src/navigation/unit-tests/ProjectedSurvey-unit-tests.cpp
diffstat 2 files changed, 166 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/navigation/internal/BudgetBankLedgers.h	Mon Oct 03 17:32:38 2022 +0200
+++ b/src/navigation/internal/BudgetBankLedgers.h	Mon Oct 03 17:52:12 2022 +0200
@@ -549,12 +549,11 @@
 	 * @param allReconciled All the transactions that were deemed correct.
 	 * @param allAdded Additional transactions needed to meet the reconciliation balance.
 	 * @param unusedBudget The balance expected after reconciliation and how it's distributed
-	 * between the budget item accounts.
+	 * between the budget item accounts. In bank statements, this is often the reconciled balance.
 	 */
 	void completedSurvey(
 		const ::QDate& completedOn,
 		const banking::BankAccount& ba,
-// 		const pecunia::currency::Money& expectedBalance, // TODO: May be needed to verify that allReconciled + allAdded = expectedBalance = unusedBudget.
 		const std::vector<accounting::TransactionNumber> allReconciled,
 		const std::vector<accounting::Transaction>& allAdded,
 		const std::map<budgeting::BudgetItemIdentifier, pecunia::currency::Money>& unusedBudget
--- a/src/navigation/unit-tests/ProjectedSurvey-unit-tests.cpp	Mon Oct 03 17:32:38 2022 +0200
+++ b/src/navigation/unit-tests/ProjectedSurvey-unit-tests.cpp	Mon Oct 03 17:52:12 2022 +0200
@@ -971,8 +971,82 @@
 			}
 		}
 	}
+	void bill_completedReconciledTxnMismatch_ShouldThrow()
+	{
+		this->budgetBankLedger_.add(this->streaming_);
+		const auto txns{
+			this->simulateBillPosting(
+				1,
+				this->clothingId_,
+				this->clothing_.source(),
+				this->clothing_.amount(),
+				this->clothing_.nextOccurOn()
+			)
+		};
+		const auto survey{
+			this->budgetBankLedger_.projectSurvey(
+				this->bankAccount_.bank_,
+				this->bankAccount_.account_.code_.number(),
+				this->surveyOn_,
+				40h,
+				Days{5}
+			)
+		};
+		vector<TransactionNumber> expectedReconciled{};
+		transform(
+			txns.cbegin(),
+			txns.cend(),
+			back_inserter(expectedReconciled),
+			[] (const auto& txn)
+			{
+				return *txn.number();
+			}
+		);
+		const vector<Transaction> expectedAdded{};
+		map<BudgetItemIdentifier, Money> expectedUnusedBudget{
+			{
+				{this->salaryId_, Money{Iso4217Codes::USD}},
+				{this->clothingId_, Money{Iso4217Codes::USD}},
+				{this->streamingId_, Money{50, 0u, Iso4217Codes::USD}}
+			}
+		};
+		const auto& bankAccount{survey.reconciled().bankAccount()};
+		const auto originalBalance{
+			this->budgetBankLedger_.generalLedger().ledger(this->bankAccount_.account_.code_).account_
+				.balance()
+		};
+		QVERIFY_EXCEPTION_THROWN(
+			this->budgetBankLedger_.completedSurvey(
+				this->surveyOn_,
+				bankAccount,
+				expectedReconciled,
+				expectedAdded,
+				expectedUnusedBudget
+			),
+			BankError
+		);
+		QVERIFY_THAT(
+			this->budgetBankLedger_.surveys().count(bankAccount),
+			equals(static_cast<size_t>(0))
+		);
 
-	void bill_completedSurveyBalanceMismatch_ShouldThrow()
+		for (const auto& codeLedgerAccount : this->budgetBankLedger_.generalLedger().ledgers())
+		{
+			const auto& accountCode{codeLedgerAccount.first};
+			const auto& ledgerAccount{codeLedgerAccount.second};
+
+			for (const auto& txnNumberTxn : codeLedgerAccount.second.transactions_)
+			{
+				const auto& txn{txnNumberTxn.second};
+				QVERIFY_THAT(txn.status(), equals(TransactionStatuses::Unreconciled));
+
+				if (accountCode == this->bankAccount_.account_.code_)
+					QVERIFY_THAT(ledgerAccount.account_.balance(), equals(originalBalance));
+			}
+		}
+	}
+
+	void bill_completedSurveyUnusedBalanceMismatch_ShouldThrow()
 	{
 		this->budgetBankLedger_.add(this->streaming_);
 		const auto txns{
@@ -1052,6 +1126,96 @@
 		}
 	}
 
+	void bill_completedSurveyAdditionalExpenseMismatch_ShouldThrow()
+	{
+		this->budgetBankLedger_.add(this->streaming_);
+		const auto txns{
+			this->simulateBillPosting(
+				1,
+				this->clothingId_,
+				this->clothing_.source(),
+				this->clothing_.amount(),
+				this->clothing_.nextOccurOn()
+			)
+		};
+		const auto survey{
+			this->budgetBankLedger_.projectSurvey(
+				this->bankAccount_.bank_,
+				this->bankAccount_.account_.code_.number(),
+				this->surveyOn_,
+				40h,
+				Days{5}
+			)
+		};
+		vector<TransactionNumber> expectedReconciled{
+			{
+				this->budgetBankLedger_.generalLedger().ledger(this->salaryAccount_)
+					.transactions_.begin()->first
+			}
+		};
+		transform(
+			txns.cbegin(),
+			txns.cend(),
+			back_inserter(expectedReconciled),
+			[] (const auto& txn)
+			{
+				return *txn.number();
+			}
+		);
+		const vector<Transaction> expectedAdded{
+			{
+				{
+					this->surveyOn_,
+					this->clothingAccount_,
+					this->bankAccount_.account_.code_,
+					this->clothing_.amount(),
+					QStringLiteral("Additional missed transaction.")
+				}
+			}
+		};
+		map<BudgetItemIdentifier, Money> expectedUnusedBudget{
+			{
+				{this->salaryId_, Money{Iso4217Codes::USD}},
+				{this->clothingId_, Money{Iso4217Codes::USD}},
+				{this->streamingId_, Money{50, 0u, Iso4217Codes::USD}}
+			}
+		};
+		const auto& bankAccount{survey.reconciled().bankAccount()};
+		const auto originalBalance{
+			this->budgetBankLedger_.generalLedger().ledger(this->bankAccount_.account_.code_).account_
+			.balance()
+		};
+		QVERIFY_EXCEPTION_THROWN(
+			this->budgetBankLedger_.completedSurvey(
+				this->surveyOn_,
+				bankAccount,
+				expectedReconciled,
+				expectedAdded,
+				expectedUnusedBudget
+			),
+			BankError
+		);
+		QVERIFY_THAT(
+			this->budgetBankLedger_.surveys().count(bankAccount),
+			equals(static_cast<size_t>(0))
+		);
+
+		for (const auto& codeLedgerAccount : this->budgetBankLedger_.generalLedger().ledgers())
+		{
+			const auto& accountCode{codeLedgerAccount.first};
+			const auto& ledgerAccount{codeLedgerAccount.second};
+
+			for (const auto& txnNumberTxn : codeLedgerAccount.second.transactions_)
+			{
+				const auto& txn{txnNumberTxn.second};
+				QVERIFY_THAT(txn.status(), equals(TransactionStatuses::Unreconciled));
+
+				if (accountCode == this->bankAccount_.account_.code_)
+					QVERIFY_THAT(ledgerAccount.account_.balance(), equals(originalBalance));
+			}
+		}
+	}
+
 	void bill_completedSurveyNextMonth_ShouldBeReconciled()
 	{
 		this->budgetBankLedger_.add(this->streaming_);