예제 #1
0
        Load <TThirdPartyType, TOwnedType>(
            ISpreadsheet spreadsheet,
            IFileIO <TOwnedType> pending_file_io,
            ICSVFile <TOwnedType> pending_file,
            IFileIO <TThirdPartyType> third_party_file_io,
            IFileIO <TOwnedType> owned_file_io,
            BudgetingMonths budgeting_months,
            DataLoadingInformation <TThirdPartyType, TOwnedType> data_loading_info,
            IMatcher matcher)
            where TThirdPartyType : ICSVRecord, new()
            where TOwnedType : ICSVRecord, new()
        {
            Load_pending_data(pending_file_io, pending_file, data_loading_info);
            Merge_budget_data(spreadsheet, pending_file, budgeting_months, data_loading_info);
            Merge_other_data(spreadsheet, pending_file, budgeting_months, data_loading_info);
            Generate_ad_hoc_data(spreadsheet, pending_file, budgeting_months, data_loading_info);
            Merge_unreconciled_data(spreadsheet, pending_file, data_loading_info);
            var reconciliator = Load_third_party_and_owned_files_into_reconciliator <TThirdPartyType, TOwnedType>(
                data_loading_info,
                third_party_file_io,
                owned_file_io,
                spreadsheet);
            var reconciliation_interface = Create_reconciliation_interface(data_loading_info, reconciliator, matcher);

            return(reconciliation_interface);
        }
예제 #2
0
 public void Merge_bespoke_data_with_pending_file(
     IInputOutput input_output,
     ISpreadsheet spreadsheet,
     ICSVFile <BankRecord> pending_file,
     BudgetingMonths budgeting_months,
     DataLoadingInformation <ActualBankRecord, BankRecord> data_loading_info)
 {
 }
예제 #3
0
 public void Generate_ad_hoc_data(
     IInputOutput input_output,
     ISpreadsheet spreadsheet,
     ICSVFile <BankRecord> pending_file,
     BudgetingMonths budgeting_months,
     DataLoadingInformation <ActualBankRecord, BankRecord> data_loading_info)
 {
 }
예제 #4
0
 public void Generate_ad_hoc_data(
     IInputOutput input_output,
     ISpreadsheet spreadsheet,
     ICSVFile <CredCard2InOutRecord> pending_file,
     BudgetingMonths budgeting_months,
     DataLoadingInformation <CredCard2Record, CredCard2InOutRecord> data_loading_info)
 {
 }
예제 #5
0
        public void Merge_bespoke_data_with_pending_file(
            IInputOutput input_output,
            ISpreadsheet spreadsheet,
            ICSVFile <CredCard2InOutRecord> pending_file,
            BudgetingMonths budgeting_months,
            DataLoadingInformation <CredCard2Record, CredCard2InOutRecord> data_loading_info)
        {
            var most_recent_cred_card_direct_debit = spreadsheet.Get_most_recent_row_containing_text <BankRecord>(
                MainSheetNames.Bank_out,
                ReconConsts.Cred_card2_dd_description,
                new List <int> {
                ReconConsts.DescriptionColumn, ReconConsts.DdDescriptionColumn
            });

            var statement_date = new DateTime();
            var next_date      = most_recent_cred_card_direct_debit.Date.AddMonths(1);
            var input          = input_output.Get_input(string.Format(
                                                            ReconConsts.AskForCredCardDirectDebit,
                                                            ReconConsts.Cred_card2_name,
                                                            next_date.ToShortDateString()));
            double new_balance = 0;

            while (input != "0")
            {
                if (double.TryParse(input, out new_balance))
                {
                    new_balance = new_balance * -1;
                    pending_file.Records.Add(new CredCard2InOutRecord
                    {
                        Date                = next_date,
                        Description         = ReconConsts.Cred_card2_regular_pymt_description,
                        Unreconciled_amount = new_balance
                    });
                }
                statement_date = next_date.AddMonths(-1);
                next_date      = next_date.Date.AddMonths(1);
                input          = input_output.Get_input(string.Format(
                                                            ReconConsts.AskForCredCardDirectDebit,
                                                            ReconConsts.Cred_card2_name,
                                                            next_date.ToShortDateString()));
            }

            if (!new_balance.Double_equals(0))
            {
                spreadsheet.Update_balance_on_totals_sheet(
                    Codes.Cred_card2_bal,
                    new_balance,
                    string.Format(
                        ReconConsts.CredCardBalanceDescription,
                        ReconConsts.Cred_card2_name,
                        $"{statement_date.ToString("MMM")} {statement_date.Year}"),
                    balance_column: 5,
                    text_column: 6,
                    code_column: 4,
                    input_output: input_output);
            }
        }
 private void Merge_other_data <TThirdPartyType, TOwnedType>(
     ISpreadsheet spreadsheet,
     ICSVFile <TOwnedType> pending_file,
     BudgetingMonths budgeting_months,
     DataLoadingInformation <TThirdPartyType, TOwnedType> data_loading_info)
     where TThirdPartyType : ICSVRecord, new()
     where TOwnedType : ICSVRecord, new()
 {
     data_loading_info.Loader.Merge_bespoke_data_with_pending_file(_input_output, spreadsheet, pending_file, budgeting_months, data_loading_info);
 }
        public void M_WhenDoingExpenseMatchingWillFilterOwnedFileForWagesRowsAndExpenseTransactionsOnly()
        {
            // Arrange
            var mock_bank_and_bank_in_loader = new Mock <IBankAndBankInLoader>();
            var mock_bank_in_file_io         = new Mock <IFileIO <BankRecord> >();
            var wages_description            =
                $"Wages ({ReconConsts.Employer_expense_description}) (!! in an inestimable manner, not forthwith - forever 1st outstanding)";

            mock_bank_in_file_io.Setup(x => x.Load(It.IsAny <List <string> >(), null))
            .Returns(new List <BankRecord> {
                new BankRecord {
                    Type = Codes.Expenses, Description = Codes.Expenses + "1"
                },
                new BankRecord {
                    Type = "Chq", Description = "something"
                },
                new BankRecord {
                    Type = Codes.Expenses, Description = Codes.Expenses + "2"
                },
                new BankRecord {
                    Type = Codes.Expenses, Description = Codes.Expenses + "3"
                },
                new BankRecord {
                    Type = "Chq", Description = "something"
                },
                new BankRecord {
                    Type = "PCL", Description = wages_description
                }
            });
            var bank_in_file             = new GenericFile <BankRecord>(new CSVFile <BankRecord>(mock_bank_in_file_io.Object));
            var mock_actual_bank_file_io = new Mock <IFileIO <ActualBankRecord> >();

            mock_actual_bank_file_io.Setup(x => x.Load(It.IsAny <List <string> >(), null))
            .Returns(new List <ActualBankRecord> {
                new ActualBankRecord {
                    Description = $"\"'{ReconConsts.Employer_expense_description}\""
                }
            });
            var actual_bank_file  = new ActualBankInFile(new CSVFile <ActualBankRecord>(mock_actual_bank_file_io.Object));
            var data_loading_info = new DataLoadingInformation <ActualBankRecord, BankRecord> {
                Sheet_name = MainSheetNames.Bank_in
            };
            var reconciliator = new Reconciliator <ActualBankRecord, BankRecord>(data_loading_info, actual_bank_file, bank_in_file);
            var matcher       = new BankAndBankInMatcher(this, new FakeSpreadsheetRepoFactory(), mock_bank_and_bank_in_loader.Object);

            // Act
            matcher.Filter_for_all_wages_rows_and_expense_transactions_from_expected_in(reconciliator);

            // Assert
            Assert.AreEqual(4, reconciliator.Owned_file.Records.Count);
            Assert.AreEqual(Codes.Expenses + "1", reconciliator.Owned_file.Records[0].Description);
            Assert.AreEqual(Codes.Expenses + "2", reconciliator.Owned_file.Records[1].Description);
            Assert.AreEqual(Codes.Expenses + "3", reconciliator.Owned_file.Records[2].Description);
            Assert.AreEqual(wages_description, reconciliator.Owned_file.Records[3].Description);
        }
예제 #8
0
 private void Generate_ad_hoc_data <TThirdPartyType, TOwnedType>(
     ISpreadsheet spreadsheet,
     ICSVFile <TOwnedType> pending_file,
     BudgetingMonths budgeting_months,
     DataLoadingInformation <TThirdPartyType, TOwnedType> data_loading_info)
     where TThirdPartyType : ICSVRecord, new()
     where TOwnedType : ICSVRecord, new()
 {
     _input_output.Output_line("Generating ad hoc data...");
     data_loading_info.Loader.Generate_ad_hoc_data(_input_output, spreadsheet, pending_file, budgeting_months, data_loading_info);
 }
 public void Load_pending_data <TThirdPartyType, TOwnedType>(
     IFileIO <TOwnedType> pending_file_io,
     ICSVFile <TOwnedType> pending_file,
     DataLoadingInformation <TThirdPartyType, TOwnedType> data_loading_info)
     where TThirdPartyType : ICSVRecord, new()
     where TOwnedType : ICSVRecord, new()
 {
     _input_output.Output_line(
         "Loading data from pending file (which you should have already split out, if necessary)...");
     pending_file_io.Set_file_paths(data_loading_info.File_paths.Main_path, data_loading_info.Pending_file_name);
     pending_file.Load(true, data_loading_info.Default_separator);
     // The separator we loaded with had to match the source. Then we convert it here to match its destination.
     pending_file.Convert_source_line_separators(data_loading_info.Default_separator, data_loading_info.Loading_separator);
 }
        public void M_WillFilterOwnedFileForSpecifiedTransactionsOnly()
        {
            // Arrange
            var mock_cred_card2_in_out_file_io = new Mock <IFileIO <CredCard2InOutRecord> >();

            mock_cred_card2_in_out_file_io.Setup(x => x.Load(It.IsAny <List <string> >(), null))
            .Returns(new List <CredCard2InOutRecord> {
                new CredCard2InOutRecord {
                    Description = ReconConsts.iTunes_description + "1"
                },
                new CredCard2InOutRecord {
                    Description = "something"
                },
                new CredCard2InOutRecord {
                    Description = ReconConsts.iTunes_description + "2"
                },
                new CredCard2InOutRecord {
                    Description = ReconConsts.iTunes_description + "3"
                },
                new CredCard2InOutRecord {
                    Description = "something else"
                }
            });
            var cred_card2_in_out_file  = new GenericFile <CredCard2InOutRecord>(new CSVFile <CredCard2InOutRecord>(mock_cred_card2_in_out_file_io.Object));
            var mock_cred_card2_file_io = new Mock <IFileIO <CredCard2Record> >();

            mock_cred_card2_file_io.Setup(x => x.Load(It.IsAny <List <string> >(), null))
            .Returns(new List <CredCard2Record> {
                new CredCard2Record {
                    Description = $"\"HOLLYHILL {ReconConsts.iTunes_description}\""
                }
            });
            var cred_card2_file   = new GenericFile <CredCard2Record>(new CSVFile <CredCard2Record>(mock_cred_card2_file_io.Object));
            var data_loading_info = new DataLoadingInformation <CredCard2Record, CredCard2InOutRecord>
            {
                Sheet_name = MainSheetNames.Cred_card2, Loader = new CredCard2AndCredCard2InOutLoader()
            };
            var reconciliator = new Reconciliator <CredCard2Record, CredCard2InOutRecord>(data_loading_info, cred_card2_file, cred_card2_in_out_file);
            var matcher       = new CredCard2AndCredCard2InOutMatcher(this);

            // Act
            matcher.SetiTunesStrings();
            matcher.Filter_matching_transactions_from_cred_card2_in_out(reconciliator);

            // Assert
            Assert.AreEqual(3, reconciliator.Owned_file.Records.Count);
            Assert.AreEqual(ReconConsts.iTunes_description + "1", reconciliator.Owned_file.Records[0].Description);
            Assert.AreEqual(ReconConsts.iTunes_description + "2", reconciliator.Owned_file.Records[1].Description);
            Assert.AreEqual(ReconConsts.iTunes_description + "3", reconciliator.Owned_file.Records[2].Description);
        }
 private void Merge_budget_data <TThirdPartyType, TOwnedType>(
     ISpreadsheet spreadsheet,
     ICSVFile <TOwnedType> pending_file,
     BudgetingMonths budgeting_months,
     DataLoadingInformation <TThirdPartyType, TOwnedType> data_loading_info)
     where TThirdPartyType : ICSVRecord, new()
     where TOwnedType : ICSVRecord, new()
 {
     _input_output.Output_line("Merging budget data with pending data...");
     spreadsheet.Add_budgeted_monthly_data_to_pending_file(budgeting_months, pending_file, data_loading_info.Monthly_budget_data);
     if (null != data_loading_info.Annual_budget_data)
     {
         spreadsheet.Add_budgeted_annual_data_to_pending_file(budgeting_months, pending_file, data_loading_info.Annual_budget_data);
     }
 }
예제 #12
0
        public void M_WillCallGenerateAdHocDataWithPendingFile_ForPassedInLoader()
        {
            // Arrange
            var mock_input_output        = new Mock <IInputOutput>();
            var reconciliate             = new FileLoader(mock_input_output.Object, new Clock());
            var mock_spreadsheet         = new Mock <ISpreadsheet>();
            var mock_pending_file_io     = new Mock <IFileIO <BankRecord> >();
            var mock_pending_file        = new Mock <ICSVFile <BankRecord> >();
            var mock_actual_bank_file_io = new Mock <IFileIO <ActualBankRecord> >();
            var mock_bank_out_file_io    = new Mock <IFileIO <BankRecord> >();
            var budgeting_months         = new BudgetingMonths {
                Start_year = 2020, Next_unplanned_month = 6, Last_month_for_budget_planning = 6
            };

            mock_actual_bank_file_io.Setup(x => x.Load(It.IsAny <List <string> >(), null))
            .Returns(new List <ActualBankRecord>());
            mock_bank_out_file_io.Setup(x => x.Load(It.IsAny <List <string> >(), null))
            .Returns(new List <BankRecord>());
            var mock_loader = new Mock <ILoader <ActualBankRecord, BankRecord> >();

            mock_loader.Setup(x => x.Create_new_third_party_file(It.IsAny <IFileIO <ActualBankRecord> >())).Returns(new ActualBankInFile(new CSVFile <ActualBankRecord>(mock_actual_bank_file_io.Object)));
            mock_loader.Setup(x => x.Create_new_owned_file(It.IsAny <IFileIO <BankRecord> >())).Returns(new GenericFile <BankRecord>(new CSVFile <BankRecord>(mock_bank_out_file_io.Object)));
            var loading_info = new DataLoadingInformation <ActualBankRecord, BankRecord>
            {
                Loader     = mock_loader.Object,
                File_paths = new FilePaths()
            };
            var mock_matcher = new Mock <IMatcher>();

            // Act
            var reconciliation_interface = reconciliate.Load <ActualBankRecord, BankRecord>(
                mock_spreadsheet.Object,
                mock_pending_file_io.Object,
                mock_pending_file.Object,
                mock_actual_bank_file_io.Object,
                mock_bank_out_file_io.Object,
                budgeting_months,
                loading_info,
                mock_matcher.Object);

            // Assert
            mock_loader.Verify(x => x.Generate_ad_hoc_data(
                                   mock_input_output.Object,
                                   mock_spreadsheet.Object,
                                   mock_pending_file.Object,
                                   budgeting_months,
                                   loading_info), Times.Exactly(1));
        }
        private void Merge_unreconciled_data <TThirdPartyType, TOwnedType>(
            ISpreadsheet spreadsheet,
            ICSVFile <TOwnedType> pending_file,
            DataLoadingInformation <TThirdPartyType, TOwnedType> data_loading_info)
            where TThirdPartyType : ICSVRecord, new()
            where TOwnedType : ICSVRecord, new()
        {
            _input_output.Output_line("Merging unreconciled rows from spreadsheet with pending and budget data...");
            spreadsheet.Add_unreconciled_rows_to_csv_file <TOwnedType>(data_loading_info.Sheet_name, pending_file);

            _input_output.Output_line("Copying merged data (from pending, unreconciled, and budgeting) into main 'owned' csv file...");
            pending_file.Update_source_lines_for_output(data_loading_info.Loading_separator);
            pending_file.Write_to_file_as_source_lines(data_loading_info.File_paths.Owned_file_name);

            _input_output.Output_line("...");
        }
        Create_reconciliation_interface <TThirdPartyType, TOwnedType>(
            DataLoadingInformation <TThirdPartyType, TOwnedType> data_loading_info,
            Reconciliator <TThirdPartyType, TOwnedType> reconciliator,
            IMatcher matcher)
            where TThirdPartyType : ICSVRecord, new()
            where TOwnedType : ICSVRecord, new()
        {
            _input_output.Output_line("Creating reconciliation interface...");
            var reconciliation_interface = new ReconciliationInterface <TThirdPartyType, TOwnedType>(
                new InputOutput(),
                reconciliator,
                data_loading_info.Third_party_descriptor,
                data_loading_info.Owned_file_descriptor,
                matcher);

            return(reconciliation_interface);
        }
        public void Merge_bespoke_data_with_pending_file(
            IInputOutput input_output,
            ISpreadsheet spreadsheet,
            ICSVFile <BankRecord> pending_file,
            BudgetingMonths budgeting_months,
            DataLoadingInformation <ActualBankRecord, BankRecord> data_loading_info)
        {
            input_output.Output_line(ReconConsts.Loading_expenses);
            _expected_income_csv_file.Load(false);

            spreadsheet.Add_unreconciled_rows_to_csv_file <ExpectedIncomeRecord>(MainSheetNames.Expected_in, _expected_income_file.File);
            _expected_income_csv_file.Populate_source_records_from_records();
            _expected_income_file.Filter_for_employer_expenses_and_bank_transactions_only();

            _expected_income_file.Copy_to_pending_file(pending_file);
            _expected_income_csv_file.Populate_records_from_original_file_load();
        }
        Load_files_and_merge_data <TThirdPartyType, TOwnedType>(
            DataLoadingInformation <TThirdPartyType, TOwnedType> data_loading_info,
            ISpreadsheetRepoFactory spreadsheet_factory,
            IMatcher matcher)
            where TThirdPartyType : ICSVRecord, new()
            where TOwnedType : ICSVRecord, new()
        {
            ReconciliationInterface <TThirdPartyType, TOwnedType> reconciliation_interface = null;

            try
            {
                // NB This is the only function the spreadsheet is used in, until the very end (Reconciliator.Finish, called from
                // ReconciliationInterface), when another spreadsheet instance gets created by FileIO so it can call
                // WriteBackToMainSpreadsheet. Between now and then, everything is done using csv files.
                var             spreadsheet_repo = spreadsheet_factory.Create_spreadsheet_repo();
                var             spreadsheet      = new Spreadsheet(spreadsheet_repo);
                BudgetingMonths budgeting_months = Recursively_ask_for_budgeting_months(spreadsheet);
                _input_output.Output_line("Loading data...");

                var pending_file_io     = new FileIO <TOwnedType>(spreadsheet_factory);
                var third_party_file_io = new FileIO <TThirdPartyType>(spreadsheet_factory);
                var owned_file_io       = new FileIO <TOwnedType>(spreadsheet_factory);
                var pending_file        = new CSVFile <TOwnedType>(pending_file_io);

                reconciliation_interface = Load <TThirdPartyType, TOwnedType>(
                    spreadsheet,
                    pending_file_io,
                    pending_file,
                    third_party_file_io,
                    owned_file_io,
                    budgeting_months,
                    data_loading_info,
                    matcher);
            }
            finally
            {
                spreadsheet_factory.Dispose_of_spreadsheet_repo();
            }

            _input_output.Output_line("");
            _input_output.Output_line("");

            return(reconciliation_interface);
        }
        Load_third_party_and_owned_files_into_reconciliator <TThirdPartyType, TOwnedType>(
            DataLoadingInformation <TThirdPartyType, TOwnedType> data_loading_info,
            IFileIO <TThirdPartyType> third_party_file_io,
            IFileIO <TOwnedType> owned_file_io)
            where TThirdPartyType : ICSVRecord, new() where TOwnedType : ICSVRecord, new()
        {
            _input_output.Output_line("Loading data back in from 'owned' and 'third party' files...");
            third_party_file_io.Set_file_paths(data_loading_info.File_paths.Main_path, data_loading_info.File_paths.Third_party_file_name);
            owned_file_io.Set_file_paths(data_loading_info.File_paths.Main_path, data_loading_info.File_paths.Owned_file_name);
            var third_party_file = data_loading_info.Loader.Create_new_third_party_file(third_party_file_io);
            var owned_file       = data_loading_info.Loader.Create_new_owned_file(owned_file_io);

            var reconciliator = new Reconciliator <TThirdPartyType, TOwnedType>(
                data_loading_info,
                third_party_file,
                owned_file);

            return(reconciliator);
        }
        public void Generate_ad_hoc_data(
            IInputOutput input_output,
            ISpreadsheet spreadsheet,
            ICSVFile <BankRecord> pending_file,
            BudgetingMonths budgeting_months,
            DataLoadingInformation <ActualBankRecord, BankRecord> data_loading_info)
        {
            if (budgeting_months.Do_expected_out_budgeting)
            {
                Update_owed_CHB(input_output, spreadsheet, budgeting_months);

                Update_weekly_item(input_output, spreadsheet, budgeting_months, "weekly spends", Codes.Code004, Codes.Code074);
                Update_weekly_item(input_output, spreadsheet, budgeting_months, "grocery shopping", Codes.Code005, Codes.Code075);

                Update_monthly_item(input_output, spreadsheet, budgeting_months, "yoga", Codes.Code078, Codes.Code078);
                Update_monthly_item(input_output, spreadsheet, budgeting_months, "fuel", Codes.Code006, Codes.Code006);
                Update_monthly_item(input_output, spreadsheet, budgeting_months, "vet", Codes.Code007, Codes.Code007);
                Update_monthly_item(input_output, spreadsheet, budgeting_months, "domain hosting", Codes.Code011, Codes.Code011);
            }
        }
        public void Merge_bespoke_data_with_pending_file(
            IInputOutput input_output,
            ISpreadsheet spreadsheet,
            ICSVFile <BankRecord> pending_file,
            BudgetingMonths budgeting_months,
            DataLoadingInformation <ActualBankRecord, BankRecord> data_loading_info)
        {
            Add_most_recent_credit_card_direct_debits(
                input_output,
                spreadsheet,
                pending_file,
                ReconConsts.Cred_card1_name,
                ReconConsts.Cred_card1_dd_description);

            Add_most_recent_credit_card_direct_debits(
                input_output,
                spreadsheet,
                pending_file,
                ReconConsts.Cred_card2_name,
                ReconConsts.Cred_card2_dd_description);
        }
        public void M_WillFilterActualBankFileForExpenseTransactionsOnly()
        {
            // Arrange
            var mock_bank_and_bank_in_loader = new Mock <IBankAndBankInLoader>();
            var mock_actual_bank_file_io     = new Mock <IFileIO <ActualBankRecord> >();

            mock_actual_bank_file_io.Setup(x => x.Load(It.IsAny <List <string> >(), null))
            .Returns(new List <ActualBankRecord> {
                new ActualBankRecord {
                    Description = $"\"'{ReconConsts.Employer_expense_description}\""
                },
                new ActualBankRecord {
                    Description = "something else"
                }
            });
            var actual_bank_file     = new ActualBankInFile(new CSVFile <ActualBankRecord>(mock_actual_bank_file_io.Object));
            var mock_bank_in_file_io = new Mock <IFileIO <BankRecord> >();

            mock_bank_in_file_io.Setup(x => x.Load(It.IsAny <List <string> >(), null))
            .Returns(new List <BankRecord> {
                new BankRecord {
                    Type = Codes.Expenses, Description = Codes.Expenses + "1"
                }
            });
            var bank_in_file      = new GenericFile <BankRecord>(new CSVFile <BankRecord>(mock_bank_in_file_io.Object));
            var data_loading_info = new DataLoadingInformation <ActualBankRecord, BankRecord> {
                Sheet_name = MainSheetNames.Bank_in
            };
            var reconciliator = new Reconciliator <ActualBankRecord, BankRecord>(data_loading_info, actual_bank_file, bank_in_file);
            var matcher       = new BankAndBankInMatcher(this, new FakeSpreadsheetRepoFactory(), mock_bank_and_bank_in_loader.Object);

            // Act
            matcher.Filter_for_all_expense_transactions_from_actual_bank_in(reconciliator);

            // Assert
            Assert.AreEqual(1, reconciliator.Third_party_file.Records.Count);
            Assert.AreEqual(ReconConsts.Employer_expense_description, reconciliator.Third_party_file.Records[0].Description.Remove_punctuation());
        }
        public void Merge_bespoke_data_with_pending_file(
            IInputOutput input_output,
            ISpreadsheet spreadsheet,
            ICSVFile <BankRecord> pending_file,
            BudgetingMonths budgeting_months,
            DataLoadingInformation <ActualBankRecord, BankRecord> data_loading_info)
        {
            Add_most_recent_credit_card_direct_debits(
                input_output,
                spreadsheet,
                pending_file,
                ReconConsts.Cred_card1_name,
                ReconConsts.Cred_card1_dd_description);

            Add_most_recent_credit_card_direct_debits(
                input_output,
                spreadsheet,
                pending_file,
                ReconConsts.Cred_card2_name,
                ReconConsts.Cred_card2_dd_description);

            // Note that we can't update bank balance here because we don't have access to third party file,
            // so we do it below in Do_actions_which_require_third_party_data_access.
        }
        public void Will_not_lose_previously_matched_records_when_files_are_refreshed()
        {
            // Arrange
            var some_other_actual_bank_description = "Some other ActualBank description";
            var some_other_bank_description        = "Some other bank description";
            var actual_bank_data = new List <ActualBankRecord>
            {
                new ActualBankRecord {
                    Description = ReconConsts.Employer_expense_description
                },
                new ActualBankRecord {
                    Description = some_other_actual_bank_description
                }
            };
            var mock_actual_bank_file_io = new Mock <IFileIO <ActualBankRecord> >();

            mock_actual_bank_file_io.Setup(x => x.Load(It.IsAny <List <string> >(), null)).Returns(actual_bank_data);
            var actual_bank_file = new GenericFile <ActualBankRecord>(new CSVFile <ActualBankRecord>(mock_actual_bank_file_io.Object));
            var bank_data        = new List <BankRecord>
            {
                new BankRecord {
                    Description = "BankRecord01", Type = Codes.Expenses
                },
                new BankRecord {
                    Description = "BankRecord02", Type = Codes.Expenses
                },
                new BankRecord {
                    Description = "BankRecord03", Type = Codes.Expenses
                },
                new BankRecord {
                    Description = some_other_bank_description, Type = "Not an expense"
                }
            };
            var mock_bank_file_io = new Mock <IFileIO <BankRecord> >();

            mock_bank_file_io.Setup(x => x.Load(It.IsAny <List <string> >(), null)).Returns(bank_data);
            var bank_file         = new GenericFile <BankRecord>(new CSVFile <BankRecord>(mock_bank_file_io.Object));
            var data_loading_info = new DataLoadingInformation <ActualBankRecord, BankRecord> {
                Sheet_name = MainSheetNames.Bank_in
            };
            var reconciliator = new Reconciliator <ActualBankRecord, BankRecord>(data_loading_info, actual_bank_file, bank_file);
            var expected_potential_matches = new List <PotentialMatch>
            {
                new PotentialMatch
                {
                    Actual_records = new List <ICSVRecord> {
                        bank_data[0], bank_data[1]
                    },
                    Console_lines = new List <ConsoleLine> {
                        new ConsoleLine {
                            Description_string = "Console Description"
                        }
                    }
                }
            };
            var mock_bank_and_bank_in_loader = new Mock <IBankAndBankInLoader>();
            var matcher = new BankAndBankInMatcher(this, new FakeSpreadsheetRepoFactory(), mock_bank_and_bank_in_loader.Object);

            matcher.Filter_for_all_expense_transactions_from_actual_bank_in(reconciliator);
            matcher.Filter_for_all_wages_rows_and_expense_transactions_from_expected_in(reconciliator);
            reconciliator.Set_match_finder((record, file) => expected_potential_matches);
            reconciliator.Set_record_matcher(matcher.Match_specified_records);
            reconciliator.Find_reconciliation_matches_for_next_third_party_record();
            reconciliator.Match_current_record(0);
            Assert.AreEqual(1, reconciliator.Third_party_file.Records.Count);
            Assert.AreEqual(2, reconciliator.Owned_file.Records.Count);
            Assert.IsFalse(reconciliator.Owned_file.Records[0].Matched);
            Assert.IsTrue(reconciliator.Owned_file.Records[1].Matched);
            Assert.IsTrue(reconciliator.Owned_file.Records[1].Description.Contains(ReconConsts.SeveralExpenses));

            // Act
            reconciliator.Refresh_files();

            // Assert
            Assert.AreEqual(2, reconciliator.Third_party_file.Records.Count);
            Assert.AreEqual(some_other_actual_bank_description, reconciliator.Third_party_file.Records[1].Description);
            Assert.AreEqual(3, reconciliator.Owned_file.Records.Count);
            Assert.IsFalse(reconciliator.Owned_file.Records[0].Matched);
            Assert.AreEqual(some_other_bank_description, reconciliator.Owned_file.Records[1].Description);
            Assert.AreEqual(actual_bank_data[0], reconciliator.Owned_file.Records[2].Match);
            Assert.IsTrue(reconciliator.Owned_file.Records[2].Matched);
            Assert.IsTrue(reconciliator.Owned_file.Records[2].Description.Contains(ReconConsts.SeveralExpenses));
        }
        public void Will_not_lose_previously_matched_records_when_files_are_refreshed()
        {
            // Arrange
            var some_other_third_party_description = "Some other third party Cred Card 2 description";
            var some_other_owned_description       = "Some other owned Cred Card 2 description";
            var third_party_data = new List <CredCard2Record>
            {
                new CredCard2Record {
                    Description = ReconConsts.Amazon_description
                },
                new CredCard2Record {
                    Description = some_other_third_party_description
                }
            };
            var mock_cred_card2_file_io = new Mock <IFileIO <CredCard2Record> >();

            mock_cred_card2_file_io.Setup(x => x.Load(It.IsAny <List <string> >(), null)).Returns(third_party_data);
            var cred_card2_file = new GenericFile <CredCard2Record>(new CSVFile <CredCard2Record>(mock_cred_card2_file_io.Object));
            var owned_data      = new List <CredCard2InOutRecord>
            {
                new CredCard2InOutRecord {
                    Description = $"{ReconConsts.Amazon_description} CredCard2InOutRecord01"
                },
                new CredCard2InOutRecord {
                    Description = $"{ReconConsts.Amazon_description} CredCard2InOutRecord02"
                },
                new CredCard2InOutRecord {
                    Description = $"{ReconConsts.Amazon_description} CredCard2InOutRecord03"
                },
                new CredCard2InOutRecord {
                    Description = some_other_owned_description
                }
            };
            var mock_cred_card2_in_out_file_io = new Mock <IFileIO <CredCard2InOutRecord> >();

            mock_cred_card2_in_out_file_io.Setup(x => x.Load(It.IsAny <List <string> >(), null)).Returns(owned_data);
            var cred_card2_in_out_file = new GenericFile <CredCard2InOutRecord>(new CSVFile <CredCard2InOutRecord>(mock_cred_card2_in_out_file_io.Object));
            var data_loading_info      = new DataLoadingInformation <CredCard2Record, CredCard2InOutRecord>
            {
                Sheet_name = MainSheetNames.Cred_card2, Loader = new CredCard2AndCredCard2InOutLoader()
            };
            var reconciliator = new Reconciliator <CredCard2Record, CredCard2InOutRecord>(data_loading_info, cred_card2_file, cred_card2_in_out_file);
            var expected_potential_matches = new List <PotentialMatch>
            {
                new PotentialMatch
                {
                    Actual_records = new List <ICSVRecord> {
                        owned_data[0], owned_data[1]
                    },
                    Console_lines = new List <ConsoleLine> {
                        new ConsoleLine {
                            Description_string = "Console Description"
                        }
                    }
                }
            };
            var matcher = new CredCard2AndCredCard2InOutMatcher(this);

            matcher.Filter_matching_transactions_from_cred_card2(reconciliator);
            matcher.Filter_matching_transactions_from_cred_card2_in_out(reconciliator);
            reconciliator.Set_match_finder((record, file) => expected_potential_matches);
            reconciliator.Set_record_matcher(matcher.Match_specified_records);
            reconciliator.Find_reconciliation_matches_for_next_third_party_record();
            reconciliator.Match_current_record(0);
            Assert.AreEqual(1, reconciliator.Third_party_file.Records.Count);
            Assert.AreEqual(2, reconciliator.Owned_file.Records.Count);
            Assert.IsFalse(reconciliator.Owned_file.Records[0].Matched);
            Assert.IsTrue(reconciliator.Owned_file.Records[1].Matched);
            Assert.IsTrue(reconciliator.Owned_file.Records[1].Description.Contains(ReconConsts.SeveralAmazonTransactions));

            // Act
            matcher.SetAmazonStrings();
            reconciliator.Refresh_files();

            // Assert
            Assert.AreEqual(2, reconciliator.Third_party_file.Records.Count);
            Assert.AreEqual(some_other_third_party_description, reconciliator.Third_party_file.Records[1].Description);
            Assert.AreEqual(3, reconciliator.Owned_file.Records.Count);
            Assert.IsFalse(reconciliator.Owned_file.Records[0].Matched);
            Assert.AreEqual(some_other_owned_description, reconciliator.Owned_file.Records[1].Description);
            Assert.AreEqual(third_party_data[0], reconciliator.Owned_file.Records[2].Match);
            Assert.IsTrue(reconciliator.Owned_file.Records[2].Matched);
            Assert.IsTrue(reconciliator.Owned_file.Records[2].Description.Contains(ReconConsts.SeveralAmazonTransactions));
        }