Beispiel #1
0
        static void RegisterServices(IServiceCollection collection, IAccessControlManager accessControlManager)
        {
            //Services
            var restClient = new RestClient("https://api.everydollar.com");

            collection.AddSingleton(accessControlManager);
            collection.AddSingleton <IRestClient>(restClient);
            collection.AddSingleton <IRemoteBudgetCalls, RemoteBudgetCalls>();

            //Models
            var budget  = BudgetBuilder.Build();
            var profile = OnboardingProfileBuilder.Build(budget);

            collection.AddSingleton <BudgetGroupSync>();
            collection.AddSingleton <BudgetSync>();
            collection.AddSingleton <GoalsStatusSync>();
            collection.AddSingleton(budget);
            collection.AddSingleton <BudgetRatio>();
            collection.AddSingleton <BudgetSummary>();
            collection.AddSingleton(profile);

            // View models
            collection.AddSingleton <BudgetViewModel>();
            collection.AddSingleton <BudgetSummaryViewModel>();
            collection.AddSingleton <OnboardingProfileViewModel>();
        }
        public void PropertyChanged_AnyBudgetItemAmountChanged_ExpectABunchOfEvents()
        {
            var budget    = BudgetBuilder.Build();
            var ratios    = Substitute.ForPartsOf <BudgetRatio>(budget);
            var summary   = new BudgetSummary(budget, ratios);
            var viewModel = new BudgetSummaryViewModel(summary);

            List <string> expectedPropertyNames = new List <string>()
            {
                nameof(BudgetSummaryViewModel.HousingGroupWidth),
                nameof(BudgetSummaryViewModel.TransportationGroupWidth),
                nameof(BudgetSummaryViewModel.FoodGroupWidth),
                nameof(BudgetSummaryViewModel.PersonalGroupWidth),
                nameof(BudgetSummaryViewModel.DebtGroupWidth),
                nameof(BudgetSummaryViewModel.GivingGroupWidth),
                nameof(BudgetSummaryViewModel.TransportationGroupOffset),
                nameof(BudgetSummaryViewModel.FoodGroupOffset),
                nameof(BudgetSummaryViewModel.PersonalGroupOffset),
                nameof(BudgetSummaryViewModel.DebtGroupOffset),
                nameof(BudgetSummaryViewModel.GivingGroupOffset),
            };

            List <string> receivedPropertyNames = new List <string>();

            viewModel.PropertyChanged += (o, e) => { receivedPropertyNames.Add(e.PropertyName); };

            budget.IncomeGroup.BudgetItems[0].Amount = 100;

            receivedPropertyNames.Should().Contain(expectedPropertyNames);
        }
        public void Constructor_ValidModel_ExpectPresentation()
        {
            var budget = BudgetBuilder.Build();
            var ratios = new BudgetRatio(budget);

            var summary = new BudgetSummary(budget, ratios);

            summary.HousingGroupWidth.Should().Be(summary.Width);
            summary.TransportationGroupWidth.Should().Be(summary.Width);
            summary.FoodGroupWidth.Should().Be(summary.Width);
            summary.PersonalGroupWidth.Should().Be(summary.Width);
            summary.GivingGroupWidth.Should().Be(summary.Width);
            summary.DebtGroupWidth.Should().Be(summary.Width);

            summary.TransportationGroupOffset.Should().Be(summary.HousingGroupWidth);
            summary.FoodGroupOffset.Should().Be(summary.TransportationGroupOffset + summary.TransportationGroupWidth);
            summary.PersonalGroupOffset.Should().Be(summary.FoodGroupOffset + summary.FoodGroupWidth);
            summary.GivingGroupOffset.Should().Be(summary.PersonalGroupOffset + summary.PersonalGroupWidth);
            summary.DebtGroupOffset.Should().Be(summary.GivingGroupOffset + summary.GivingGroupWidth);

            summary.BudgetDelta.Should().Be(0m);
            summary.IsOverBudget.Should().Be(false);
            summary.IsUnderBudget.Should().Be(false);
            summary.IsOnBudget.Should().Be(true);
        }
        public void Constructor_ValidModel_ExpectPresentation()
        {
            var budget  = BudgetBuilder.Build();
            var ratios  = new BudgetRatio(budget);
            var summary = new BudgetSummary(budget, ratios);

            var viewModel = new BudgetSummaryViewModel(summary);

            viewModel.Width.Should().Be(summary.Width);
            viewModel.HousingGroupWidth.Should().Be(summary.HousingGroupWidth);
            viewModel.TransportationGroupWidth.Should().Be(summary.TransportationGroupWidth);
            viewModel.FoodGroupWidth.Should().Be(summary.FoodGroupWidth);
            viewModel.PersonalGroupWidth.Should().Be(summary.PersonalGroupWidth);
            viewModel.GivingGroupWidth.Should().Be(summary.GivingGroupWidth);
            viewModel.DebtGroupWidth.Should().Be(summary.DebtGroupWidth);

            viewModel.TransportationGroupOffset.Should().Be(summary.TransportationGroupOffset);
            viewModel.FoodGroupOffset.Should().Be(summary.FoodGroupOffset);
            viewModel.PersonalGroupOffset.Should().Be(summary.PersonalGroupOffset);
            viewModel.GivingGroupOffset.Should().Be(summary.GivingGroupOffset);
            viewModel.DebtGroupOffset.Should().Be(summary.DebtGroupOffset);

            viewModel.BudgetDelta.Should().Be(summary.BudgetDelta.ToCurrencyString());
            viewModel.IsOverBudget.Should().Be(summary.IsOverBudget);
            viewModel.IsUnderBudget.Should().Be(summary.IsUnderBudget);
            viewModel.IsOnBudget.Should().Be(summary.IsOnBudget);
        }
Beispiel #5
0
        public async Task RemoteSyncBudget_ExpectAllBudgetGroupsSyncs()
        {
            var remoteBudgetCalls = Substitute.For <IRemoteBudgetCalls>();
            //????
            var budgetGroupSync = Substitute.ForPartsOf <BudgetGroupSync>(remoteBudgetCalls);
            //????
            var    sync       = new BudgetSync(remoteBudgetCalls, budgetGroupSync);
            Budget budget     = BudgetBuilder.Build();
            var    testBudget = CreateTestRemoteBudget();

            remoteBudgetCalls.GetCurrentBudget().ReturnsForAnyArgs(testBudget);


            await sync.RemoteSyncBudget(budget);


            await budgetGroupSync.Received().SyncBudgetGroup(testBudget, budget.IncomeGroup);

            await budgetGroupSync.Received().SyncBudgetGroup(testBudget, budget.HousingGroup);

            await budgetGroupSync.Received().SyncBudgetGroup(testBudget, budget.TransportationGroup);

            await budgetGroupSync.Received().SyncBudgetGroup(testBudget, budget.FoodGroup);

            await budgetGroupSync.Received().SyncBudgetGroup(testBudget, budget.PersonalGroup);

            await budgetGroupSync.Received().SyncBudgetGroup(testBudget, budget.GivingGroup);

            await budgetGroupSync.Received().SyncBudgetGroup(testBudget, budget.DebtGroup);


            await budgetGroupSync.Received(7).SyncBudgetGroup(Arg.Any <RemoteBudget.RemoteBudget>(), Arg.Any <BudgetGroup>());
        }
Beispiel #6
0
        public async Task RemoteSyncBudget_SyncStatus_ExpectChanges()
        {
            var    remoteBudgetCalls = Substitute.For <IRemoteBudgetCalls>();
            var    budgetGroupSync   = Substitute.ForPartsOf <BudgetGroupSync>(remoteBudgetCalls);
            var    budgetSync        = new BudgetSync(remoteBudgetCalls, budgetGroupSync);
            Budget budget            = BudgetBuilder.Build();

            var testBudget = CreateTestRemoteBudget();

            remoteBudgetCalls.GetCurrentBudget().ReturnsForAnyArgs(testBudget);

            bool   statusChanged = false;
            string status        = "";

            budgetSync.PropertyChanged += (sender, args) =>
            {
                if (args.PropertyName == nameof(budgetSync.SyncingStatus))
                {
                    statusChanged = true;
                    status        = (sender as BudgetSync).SyncingStatus;
                }
            };

            await budgetSync.RemoteSyncBudget(budget);

            statusChanged.Should().BeTrue();
            status.Should().NotBeNullOrWhiteSpace();
        }
Beispiel #7
0
        public void IncomeRemaining_VariousAmount_CorrectAmount()
        {
            var budget = BudgetBuilder.Build();

            // Some easy ratios for testing
            budget.IncomeGroup.BudgetItems[0].Amount = 100m;
            budget.IncomeRemaining.Should().Be(100);

            budget.HousingGroup.BudgetItems[0].Amount = 1m;
            budget.IncomeRemaining.Should().Be(99);

            budget.TransportationGroup.BudgetItems[0].Amount = 2m;
            budget.IncomeRemaining.Should().Be(97);

            budget.FoodGroup.BudgetItems[0].Amount = 3m;
            budget.IncomeRemaining.Should().Be(94);

            budget.PersonalGroup.BudgetItems[0].Amount = 4m;
            budget.IncomeRemaining.Should().Be(90);

            budget.DebtGroup.BudgetItems[0].Amount = 5m;
            budget.IncomeRemaining.Should().Be(85);

            budget.GivingGroup.BudgetItems[0].Amount = 6m;
            budget.IncomeRemaining.Should().Be(79);
        }
        public void Constructor_NullStatus_ExpectException()
        {
            var budget = BudgetBuilder.Build();
            var goals  = new TitledIconList();

            Action testAction = () => new OnboardingProfile(budget, goals, null);

            testAction.Should().Throw <ArgumentNullException>().WithMessage("*status*");
        }
Beispiel #9
0
        [Fact] public void GroupRatios_HalfwayAmount_ExpectOneHalfRatio()
        {
            var budget = BudgetBuilder.Build();
            var ratios = new BudgetRatio(budget);

            budget.IncomeGroup.BudgetItems[0].Amount  = 200m;
            budget.HousingGroup.BudgetItems[1].Amount = 100;
            ratios.HousingGroupRatio.Should().Be(0.5);
        }
        public void Constructor_NullRatios_ExpectException()
        {
            var budget = BudgetBuilder.Build();

            // TEST: construct view model
            Action testAction = () => new BudgetSummary(budget, null);

            testAction.Should().Throw <ArgumentNullException>();
        }
Beispiel #11
0
        public void GroupRatios_FullAmount_ExpectOneRatio()
        {
            var budget = BudgetBuilder.Build();
            var ratios = new BudgetRatio(budget);

            budget.IncomeGroup.BudgetItems[0].Amount  = 200m;
            budget.HousingGroup.BudgetItems[0].Amount = 200m;
            ratios.HousingGroupRatio.Should().Be(1);
        }
        public void HousingGroupWidth_VariousWidthsAndRatios_MatchesExpectResult()
        {
            double ratio   = 0.5;
            var    budget  = BudgetBuilder.Build();
            var    ratios  = Substitute.ForPartsOf <BudgetRatio>(budget);
            var    summary = new BudgetSummary(budget, ratios);

            ratios.HousingGroupRatio.Returns(ratio);
            summary.HousingGroupWidth.Should().Be(summary.Width * ratio);
        }
        public void Constructor_ExpectPopulatedParameters()
        {
            var budget = BudgetBuilder.Build();
            var goals  = new TitledIconList();
            var status = new TitledIconList();

            var profile = new OnboardingProfile(budget, goals, status);

            profile.Budget.Should().NotBeNull();
            profile.Goals.Should().NotBeNull();
            profile.Status.Should().NotBeNull();
        }
        public void Build_ExpectPopulatedBudget()
        {
            var budget = BudgetBuilder.Build();

            budget.IncomeGroup.Should().NotBeNull();
            budget.HousingGroup.Should().NotBeNull();
            budget.TransportationGroup.Should().NotBeNull();
            budget.FoodGroup.Should().NotBeNull();
            budget.PersonalGroup.Should().NotBeNull();
            budget.GivingGroup.Should().NotBeNull();
            budget.DebtGroup.Should().NotBeNull();
            budget.BasicExpensesDisplayGroup.Should().NotBeNull();
        }
        static void RegisterServices(IServiceCollection collection)
        {
            var budget  = BudgetBuilder.Build();
            var profile = OnboardingProfileBuilder.Build(budget);

            // Models
            collection.AddSingleton(budget);
            collection.AddSingleton(profile);

            // View models
            collection.AddSingleton <BudgetViewModel>();
            collection.AddSingleton <OnboardingProfileViewModel>();
        }
        public async Task SyncBudgetGroup_DeleteBudgetItem_ExpectRemoteItemDelete()
        {
            var remoteBudgetCalls = Substitute.For <IRemoteBudgetCalls>();
            var budgetGroupSync   = new BudgetGroupSync(remoteBudgetCalls);
            var remoteBudget      = CreateTestRemoteBudget();
            var budget            = BudgetBuilder.Build();

            budget.IncomeGroup.BudgetItems.RemoveAt(0);

            await budgetGroupSync.SyncBudgetGroup(remoteBudget, budget.IncomeGroup);

            await remoteBudgetCalls.Received()
            .DeleteBudgetItem(remoteBudget.Id, remoteBudget.BudgetGroups[0].BudgetItems[0].Id);
        }
        public void HousingGroupWidth_MoreWidthsAndRatios_MatchesExpectResult()
        {
            var budget  = BudgetBuilder.Build();
            var ratios  = new BudgetRatio(budget);
            var summary = new BudgetSummary(budget, ratios);

            budget.IncomeGroup.BudgetItems[0].Amount  = 100;
            budget.HousingGroup.BudgetItems[0].Amount = 75;
            budget.FoodGroup.BudgetItems[0].Amount    = 25;

            summary.HousingGroupWidth.Should().Be(summary.Width * 0.75);
            summary.FoodGroupWidth.Should().Be(summary.Width * 0.25);
            summary.FoodGroupOffset.Should().Be(summary.HousingGroupWidth);
        }
Beispiel #18
0
        public void Constructor_ValidModel_ExpectPresentation()
        {
            var budget    = BudgetBuilder.Build();
            var viewModel = new BudgetViewModel(budget);

            viewModel.IncomeGroup.BudgetGroup.Should().Be(budget.IncomeGroup);
            viewModel.HousingGroup.BudgetGroup.Should().Be(budget.HousingGroup);
            viewModel.TransportationGroup.BudgetGroup.Should().Be(budget.TransportationGroup);
            viewModel.FoodGroup.BudgetGroup.Should().Be(budget.FoodGroup);
            viewModel.PersonalGroup.BudgetGroup.Should().Be(budget.PersonalGroup);
            viewModel.GivingGroup.BudgetGroup.Should().Be(budget.GivingGroup);
            viewModel.DebtGroup.BudgetGroup.Should().Be(budget.DebtGroup);
            viewModel.BasicExpensesDisplayGroup.BudgetGroup.Should().Be(budget.BasicExpensesDisplayGroup);
        }
        public void Width_Set_ExpectSetAndUsedInRatios()
        {
            var budget  = BudgetBuilder.Build();
            var ratios  = Substitute.ForPartsOf <BudgetRatio>(budget);
            var summary = new BudgetSummary(budget, ratios);

            ratios.HousingGroupRatio.Returns(1);
            double width = 200;

            // TEST: new width
            summary.Width = width;

            summary.Width.Should().Be(width);
            summary.HousingGroupWidth.Should().Be(width);
        }
        public async Task SyncBudgetGroup_UpdateBudgetItem_ExpectRemoteItemUpdate()
        {
            var     remoteBudgetCalls = Substitute.For <IRemoteBudgetCalls>();
            var     budgetGroupSync   = new BudgetGroupSync(remoteBudgetCalls);
            var     remoteBudget      = CreateTestRemoteBudget();
            var     budget            = BudgetBuilder.Build();
            decimal amount            = 123.45m;

            budget.IncomeGroup.BudgetItems[0].Amount = amount;

            await budgetGroupSync.SyncBudgetGroup(remoteBudget, budget.IncomeGroup);

            await remoteBudgetCalls.Received()
            .UpdateBudgetItem(remoteBudget.Id, remoteBudget.BudgetGroups[0].BudgetItems[0].Id, amount);
        }
        public void Width_Set_ExpectSetAndUsedInRatio()
        {
            var budget    = BudgetBuilder.Build();
            var ratios    = Substitute.ForPartsOf <BudgetRatio>(budget);
            var summary   = new BudgetSummary(budget, ratios);
            var viewModel = new BudgetSummaryViewModel(summary);

            ratios.HousingGroupRatio.Returns(1);//what is the difference of using Configure or not
            double width = 200;

            viewModel.Width = width;

            viewModel.Width.Should().Be(width);
            viewModel.HousingGroupWidth.Should().Be(width);
        }
Beispiel #22
0
        public void AddingNewBudget()
        {
            var budget = BudgetBuilder.CreateDefault().Build();

            Driver.LogBudgetUser();
            Driver.AnnualReportsPage()
            .GetYear(budget)
            .NewBudget()
            .FillBasicData(budget)
            .FillValuesSection(budget)
            .WorkingDays()
            .Limits(budget)
            .Validation(PercentageMax)
            .Generate();
        }
Beispiel #23
0
        public void BudgetState_VariousAmount_CorrectState()
        {
            var budget = BudgetBuilder.Build();

            // Some easy ratios for testing
            budget.IncomeGroup.BudgetItems[0].Amount = 100m;
            budget.BudgetState.Should().Be(BudgetState.UnderBudget);

            budget.HousingGroup.BudgetItems[0].Amount = 99m;
            budget.BudgetState.Should().Be(BudgetState.UnderBudget);

            budget.HousingGroup.BudgetItems[0].Amount = 100m;
            budget.BudgetState.Should().Be(BudgetState.OnBudget);

            budget.HousingGroup.BudgetItems[0].Amount = 101m;
            budget.BudgetState.Should().Be(BudgetState.OverBudget);
        }
Beispiel #24
0
        public void PropertyChanged_BudgetGroupAmountChanged_ExpectRatioChangedEvent()
        {
            var budget = BudgetBuilder.Build();
            var ratios = new BudgetRatio(budget);

            bool wasNotified = false;

            ratios.PropertyChanged += (sender, args) =>
            {
                if (args.PropertyName == BudgetRatio.RatioChangedProperty)
                {
                    wasNotified = true;
                }
            };

            budget.IncomeGroup.BudgetItems[0].Amount = 100m;
            wasNotified.Should().BeTrue();

            wasNotified = false;
            budget.HousingGroup.BudgetItems[0].Amount = 1m;
            wasNotified.Should().BeTrue();

            wasNotified = false;
            budget.TransportationGroup.BudgetItems[0].Amount = 1m;
            wasNotified.Should().BeTrue();

            wasNotified = false;
            budget.FoodGroup.BudgetItems[0].Amount = 1m;
            wasNotified.Should().BeTrue();

            wasNotified = false;
            budget.PersonalGroup.BudgetItems[0].Amount = 1m;
            wasNotified.Should().BeTrue();

            wasNotified = false;
            budget.DebtGroup.BudgetItems[0].Amount = 1m;
            wasNotified.Should().BeTrue();

            wasNotified = false;
            budget.GivingGroup.BudgetItems[0].Amount = 1m;
            wasNotified.Should().BeTrue();
        }
Beispiel #25
0
        public void GroupRatios_VariousAmount_CorrectRatios()
        {
            var budget = BudgetBuilder.Build();
            var ratios = new BudgetRatio(budget);

            budget.IncomeGroup.BudgetItems[0].Amount         = 100m;
            budget.HousingGroup.BudgetItems[0].Amount        = 1m;
            budget.TransportationGroup.BudgetItems[0].Amount = 2m;
            budget.FoodGroup.BudgetItems[0].Amount           = 3m;
            budget.PersonalGroup.BudgetItems[0].Amount       = 4m;
            budget.DebtGroup.BudgetItems[0].Amount           = 5m;
            budget.GivingGroup.BudgetItems[0].Amount         = 6m;

            ratios.HousingGroupRatio.Should().Be(0.01);
            ratios.TransportationGroupRatio.Should().Be(0.02);
            ratios.FoodGroupRatio.Should().Be(0.03);
            ratios.PersonalGroupRatio.Should().Be(0.04);
            ratios.DebtGroupRatio.Should().Be(0.05);
            ratios.GivingGroupRatio.Should().Be(0.06);
        }
Beispiel #26
0
        public void GroupRatios_ZeroValues_ExpectOneRatios()
        {
            var budget = BudgetBuilder.Build();
            var ratios = new BudgetRatio(budget);

            //some ratios
            budget.IncomeGroup.BudgetItems[0].Amount         = 0;
            budget.HousingGroup.BudgetItems[0].Amount        = -1;
            budget.TransportationGroup.BudgetItems[0].Amount = 123.4m;
            budget.FoodGroup.BudgetItems[0].Amount           = 0;
            budget.PersonalGroup.BudgetItems[0].Amount       = 0;
            budget.DebtGroup.BudgetItems[0].Amount           = 0;
            budget.GivingGroup.BudgetItems[0].Amount         = 0;

            ratios.HousingGroupRatio.Should().Be(1);
            ratios.TransportationGroupRatio.Should().Be(1);
            ratios.FoodGroupRatio.Should().Be(1);
            ratios.PersonalGroupRatio.Should().Be(1);
            ratios.DebtGroupRatio.Should().Be(1);
            ratios.GivingGroupRatio.Should().Be(1);
        }
Beispiel #27
0
        public void IncomeRemaining_AllGroupsSet_ExpectNotifyForEveryGroup()
        {
            var  budget      = BudgetBuilder.Build();
            bool wasNotified = false;

            budget.PropertyChanged += (o, e) =>
            {
                if (e.PropertyName == nameof(budget.IncomeRemaining))
                {
                    wasNotified = true;
                }
            };

            budget.IncomeGroup.BudgetItems[0].Amount = 1.23m;
            wasNotified.Should().BeTrue();

            wasNotified = false;
            budget.HousingGroup.BudgetItems[0].Amount = 1.23m;
            wasNotified.Should().BeTrue();

            wasNotified = false;
            budget.TransportationGroup.BudgetItems[0].Amount = 1.23m;
            wasNotified.Should().BeTrue();

            wasNotified = false;
            budget.FoodGroup.BudgetItems[0].Amount = 1.23m;
            wasNotified.Should().BeTrue();

            wasNotified = false;
            budget.PersonalGroup.BudgetItems[0].Amount = 1.23m;
            wasNotified.Should().BeTrue();

            wasNotified = false;
            budget.DebtGroup.BudgetItems[0].Amount = 1.23m;
            wasNotified.Should().BeTrue();

            wasNotified = false;
            budget.GivingGroup.BudgetItems[0].Amount = 1.23m;
            wasNotified.Should().BeTrue();
        }
        public void PropertyChanged_AnyBudgetItemAmountChanged_ExpectBudgetEvents()
        {
            var budget  = BudgetBuilder.Build();
            var ratios  = Substitute.ForPartsOf <BudgetRatio>(budget);
            var summary = new BudgetSummary(budget, ratios);

            List <string> expectedPropertyNames = new List <string>()
            {
                nameof(BudgetSummary.BudgetDelta),
                nameof(BudgetSummary.IsOverBudget),
                nameof(BudgetSummary.IsOnBudget),
                nameof(BudgetSummary.IsUnderBudget),
            };

            List <string> receivedPropertyNames = new List <string>();

            summary.PropertyChanged += (o, e) => { receivedPropertyNames.Add(e.PropertyName); };

            budget.IncomeGroup.BudgetItems[0].Amount = 100;

            receivedPropertyNames.Should().Contain(expectedPropertyNames);
        }
        public async Task SyncBudgetGroup_AddBudgetItem_ExpectRemoteAdd()
        {
            var remoteBudgetCalls = Substitute.For <IRemoteBudgetCalls>();
            var budgetGroupSync   = new BudgetGroupSync(remoteBudgetCalls);
            var remoteBudget      = CreateTestRemoteBudget();
            var budget            = BudgetBuilder.Build();

            // Create an income group with 2 existing populated amounts and 1 new addition
            budget.IncomeGroup.BudgetItems[0].Amount = 10m;
            budget.IncomeGroup.BudgetItems[1].Amount = 10m;
            budget.IncomeGroup.AddNewBudgetItem();
            var newItem = budget.IncomeGroup.BudgetItems.Last();
            var index   = budget.IncomeGroup.BudgetItems.IndexOf(newItem);

            budget.IncomeGroup.BudgetItems[index].Name   = "test";
            budget.IncomeGroup.BudgetItems[index].Amount = 13m;

            await budgetGroupSync.SyncBudgetGroup(remoteBudget, budget.IncomeGroup);

            await remoteBudgetCalls.Received().CreateBudgetItem(remoteBudget.Id, remoteBudget.BudgetGroups[0].Id,
                                                                newItem.Type, newItem.Name,
                                                                newItem.Amount);;
        }
 public static OnboardingProfile Build() => Build(BudgetBuilder.Build());