diff --git a/src/Fab.Client/App.xaml b/src/Fab.Client/App.xaml index 74a4208..2662a61 100644 --- a/src/Fab.Client/App.xaml +++ b/src/Fab.Client/App.xaml @@ -8,7 +8,7 @@ xmlns:framework="clr-namespace:Fab.Client.Framework" xmlns:converters="clr-namespace:Fab.Client.Framework.Converters" xmlns:Common="clr-namespace:Fab.Client.Common" xmlns:Categories="clr-namespace:Fab.Client.MoneyTracker.Categories" - mc:Ignorable="d"> + xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit" mc:Ignorable="d"> @@ -58,6 +58,118 @@ + + + + + + + + \ No newline at end of file diff --git a/src/Fab.Client/Authentication/LoggedInMessage.cs b/src/Fab.Client/Authentication/LoggedInMessage.cs index f1597b3..ab82f76 100644 --- a/src/Fab.Client/Authentication/LoggedInMessage.cs +++ b/src/Fab.Client/Authentication/LoggedInMessage.cs @@ -1,7 +1,8 @@ -// -// Copyright (c) 2009-2011 nReez. All rights reserved. +//------------------------------------------------------------ +// +// Copyright (c) 2012 nReez. All rights reserved. // -// +//------------------------------------------------------------ namespace Fab.Client.Authentication { diff --git a/src/Fab.Client/Authentication/LoggedOutMessage.cs b/src/Fab.Client/Authentication/LoggedOutMessage.cs index 0b08587..8a52994 100644 --- a/src/Fab.Client/Authentication/LoggedOutMessage.cs +++ b/src/Fab.Client/Authentication/LoggedOutMessage.cs @@ -1,7 +1,8 @@ -// -// Copyright (c) 2009-2011 nReez. All rights reserved. +//------------------------------------------------------------ +// +// Copyright (c) 2012 nReez. All rights reserved. // -// +//------------------------------------------------------------ namespace Fab.Client.Authentication { diff --git a/src/Fab.Client/Authentication/PersonalCornerViewModel.cs b/src/Fab.Client/Authentication/PersonalCornerViewModel.cs index cbe0dae..60886e1 100644 --- a/src/Fab.Client/Authentication/PersonalCornerViewModel.cs +++ b/src/Fab.Client/Authentication/PersonalCornerViewModel.cs @@ -1,7 +1,8 @@ -// -// Copyright (c) 2009-2011 nReez. All rights reserved. +//------------------------------------------------------------ +// +// Copyright (c) 2012 nReez. All rights reserved. // -// +//------------------------------------------------------------ using System.ComponentModel.Composition; using Caliburn.Micro; diff --git a/src/Fab.Client/Authentication/RegisterationResult.cs b/src/Fab.Client/Authentication/RegisterationResult.cs index f456c55..6a47f14 100644 --- a/src/Fab.Client/Authentication/RegisterationResult.cs +++ b/src/Fab.Client/Authentication/RegisterationResult.cs @@ -1,6 +1,6 @@ //------------------------------------------------------------ // -// Copyright (c) 2011 nReez. All rights reserved. +// Copyright (c) 2012 nReez. All rights reserved. // //------------------------------------------------------------ diff --git a/src/Fab.Client/Fab.Client.csproj b/src/Fab.Client/Fab.Client.csproj index b6c54ec..38dbb79 100644 --- a/src/Fab.Client/Fab.Client.csproj +++ b/src/Fab.Client/Fab.Client.csproj @@ -166,6 +166,7 @@ + @@ -178,6 +179,11 @@ + + + + + EditIcon.xaml diff --git a/src/Fab.Client/Framework/IRepository.cs b/src/Fab.Client/Framework/IRepository.cs index 869eced..ca985df 100644 --- a/src/Fab.Client/Framework/IRepository.cs +++ b/src/Fab.Client/Framework/IRepository.cs @@ -1,7 +1,8 @@ +//------------------------------------------------------------ // -// Copyright (c) 2009-2011 nReez. All rights reserved. +// Copyright (c) 2011 nReez. All rights reserved. // -// +//------------------------------------------------------------ using Caliburn.Micro; using Fab.Client.Authentication; diff --git a/src/Fab.Client/Framework/RepositoryBase.cs b/src/Fab.Client/Framework/RepositoryBase.cs index cfcbc8d..57593ca 100644 --- a/src/Fab.Client/Framework/RepositoryBase.cs +++ b/src/Fab.Client/Framework/RepositoryBase.cs @@ -4,6 +4,7 @@ // using System; +using System.Collections.ObjectModel; using System.ComponentModel.Composition; using Caliburn.Micro; using Fab.Client.Authentication; diff --git a/src/Fab.Management/Framework/Results/SingleResult.cs b/src/Fab.Client/Framework/Results/SingleResult.cs similarity index 86% rename from src/Fab.Management/Framework/Results/SingleResult.cs rename to src/Fab.Client/Framework/Results/SingleResult.cs index 05fbbd2..67c1696 100644 --- a/src/Fab.Management/Framework/Results/SingleResult.cs +++ b/src/Fab.Client/Framework/Results/SingleResult.cs @@ -10,7 +10,7 @@ using Caliburn.Micro; using Action = System.Action; -namespace Fab.Managment.Framework.Results +namespace Fab.Client.Framework.Results { /// /// Single that will cause all changed binded properties @@ -31,7 +31,11 @@ public void Execute(ActionExecutionContext context) Action(); // Push all binded properties changes during Action to appear faster on screen +#if SILVERLIGHT + Application.Current.RootVisual.Dispatcher.BeginInvoke(delegate { }); +#else Application.Current.Dispatcher.Invoke(DispatcherPriority.Render, new Action(delegate { })); +#endif Completed(this, new ResultCompletionEventArgs()); } diff --git a/src/Fab.Client/MoneyTracker/Accounts/AccountsRepository.cs b/src/Fab.Client/MoneyTracker/Accounts/AccountsRepository.cs index e92ca6f..9257afc 100644 --- a/src/Fab.Client/MoneyTracker/Accounts/AccountsRepository.cs +++ b/src/Fab.Client/MoneyTracker/Accounts/AccountsRepository.cs @@ -1,7 +1,8 @@ +//------------------------------------------------------------ // -// Copyright (c) 2009-2011 nReez. All rights reserved. +// Copyright (c) 2012 nReez. All rights reserved. // -// +//------------------------------------------------------------ using System; using System.ComponentModel.Composition; @@ -76,6 +77,12 @@ public override void Download() { Entities.Clear(); Entities.AddRange(e.Result); + +// foreach (var item in e.Result) +// { +// Entities.Add(item); +// } + Execute.OnUIThread(() => EventAggregator.Publish(new AccountsUpdatedMessage { Accounts = Entities @@ -109,7 +116,15 @@ public override void Download(int key) { var account = ByKey(key); var index = Entities.IndexOf(account); - Entities[index] = e.Result; + //Entities[index] = e.Result; + Entities[index].AssetTypeId = e.Result.AssetTypeId; + Entities[index].Balance = e.Result.Balance; + Entities[index].Created = e.Result.Created; + Entities[index].FirstPostingDate = e.Result.FirstPostingDate; + Entities[index].Id = e.Result.Id; + Entities[index].LastPostingDate = e.Result.LastPostingDate; + Entities[index].Name = e.Result.Name; + Entities[index].PostingsCount = e.Result.PostingsCount; Execute.OnUIThread(() => EventAggregator.Publish(new AccountUpdatedMessage { diff --git a/src/Fab.Client/MoneyTracker/Accounts/AssetTypes/AssetTypesRepository.cs b/src/Fab.Client/MoneyTracker/Accounts/AssetTypes/AssetTypesRepository.cs index 8c58635..9b7d606 100644 --- a/src/Fab.Client/MoneyTracker/Accounts/AssetTypes/AssetTypesRepository.cs +++ b/src/Fab.Client/MoneyTracker/Accounts/AssetTypes/AssetTypesRepository.cs @@ -57,6 +57,12 @@ public override void Download() { Entities.Clear(); Entities.AddRange(e.Result); + +// foreach (var item in e.Result) +// { +// Entities.Add(item); +// } + Execute.OnUIThread(() => EventAggregator.Publish(new AssetTypesUpdatedMessage { AssetTypes = Entities diff --git a/src/Fab.Client/MoneyTracker/Categories/CategoriesRepository.cs b/src/Fab.Client/MoneyTracker/Categories/CategoriesRepository.cs index 847e80f..3dd4b9d 100644 --- a/src/Fab.Client/MoneyTracker/Categories/CategoriesRepository.cs +++ b/src/Fab.Client/MoneyTracker/Categories/CategoriesRepository.cs @@ -1,7 +1,8 @@ +//------------------------------------------------------------ // -// Copyright (c) 2009-2011 nReez. All rights reserved. +// Copyright (c) 2012 nReez. All rights reserved. // -// +//------------------------------------------------------------ using System; using System.ComponentModel.Composition; @@ -76,6 +77,12 @@ public override void Download() { Entities.Clear(); Entities.AddRange(e.Result); +// +// foreach (var item in e.Result) +// { +// Entities.Add(item); +// } + Execute.OnUIThread(() => EventAggregator.Publish(new CategoriesUpdatedMessage { Categories = Entities diff --git a/src/Fab.Client/MoneyTracker/Categories/CategoriesViewModel.cs b/src/Fab.Client/MoneyTracker/Categories/CategoriesViewModel.cs index 27bbd4b..4ddd7e6 100644 --- a/src/Fab.Client/MoneyTracker/Categories/CategoriesViewModel.cs +++ b/src/Fab.Client/MoneyTracker/Categories/CategoriesViewModel.cs @@ -1,7 +1,8 @@ +//------------------------------------------------------------ // -// Copyright (c) 2009-2011 nReez. All rights reserved. +// Copyright (c) 2012 nReez. All rights reserved. // -// +//------------------------------------------------------------ using System.ComponentModel.Composition; using System.Linq; diff --git a/src/Fab.Client/MoneyTracker/CategoriesDashBoardViewModel.cs b/src/Fab.Client/MoneyTracker/CategoriesDashBoardViewModel.cs index f9cfcf5..1833e3d 100644 --- a/src/Fab.Client/MoneyTracker/CategoriesDashBoardViewModel.cs +++ b/src/Fab.Client/MoneyTracker/CategoriesDashBoardViewModel.cs @@ -1,6 +1,6 @@ //------------------------------------------------------------ // -// Copyright (c) 2011 nReez. All rights reserved. +// Copyright (c) 2012 nReez. All rights reserved. // //------------------------------------------------------------ diff --git a/src/Fab.Client/MoneyTracker/Filters/PostingsFilterViewModel.cs b/src/Fab.Client/MoneyTracker/Filters/PostingsFilterViewModel.cs index 329a946..4ef7763 100644 --- a/src/Fab.Client/MoneyTracker/Filters/PostingsFilterViewModel.cs +++ b/src/Fab.Client/MoneyTracker/Filters/PostingsFilterViewModel.cs @@ -1,6 +1,6 @@ //------------------------------------------------------------ // -// Copyright (c) 2011 nReez. All rights reserved. +// Copyright (c) 2012 nReez. All rights reserved. // //------------------------------------------------------------ @@ -41,18 +41,21 @@ public Tuple SelectedRange get { return selectedRange; } set { - selectedRange = value; - NotifyOfPropertyChange(() => SelectedRange); - - eventAggregator.Publish(new PostingsFilterUpdatedMessage + if (selectedRange != value) { - Start = selectedRange.Item1 < selectedRange.Item2 - ? selectedRange.Item1 - : selectedRange.Item2, - End = selectedRange.Item1 >= selectedRange.Item2 - ? selectedRange.Item1 - : selectedRange.Item2, - }); + selectedRange = value; + NotifyOfPropertyChange(() => SelectedRange); + + eventAggregator.Publish(new PostingsFilterUpdatedMessage + { + Start = selectedRange.Item1 < selectedRange.Item2 + ? selectedRange.Item1 + : selectedRange.Item2, + End = selectedRange.Item1 >= selectedRange.Item2 + ? selectedRange.Item1 + : selectedRange.Item2, + }); + } } } diff --git a/src/Fab.Client/MoneyTracker/Postings/AddTransactionRecordBaseResult.cs b/src/Fab.Client/MoneyTracker/Postings/AddTransactionRecordBaseResult.cs new file mode 100644 index 0000000..e05ee2b --- /dev/null +++ b/src/Fab.Client/MoneyTracker/Postings/AddTransactionRecordBaseResult.cs @@ -0,0 +1,69 @@ +using System; +using Caliburn.Micro; +using Fab.Client.MoneyServiceReference; +using Fab.Client.MoneyTracker.Categories; +using Fab.Core; + +namespace Fab.Client.MoneyTracker.Postings +{ + public class AddTransactionRecordBaseResult : IResult + { + protected readonly JournalDTO Journal; + private readonly ICategoriesRepository categoriesRepository; + + public AddTransactionRecordBaseResult(JournalDTO journal, ICategoriesRepository repository) + { + Journal = journal; + categoriesRepository = repository; + TransactionRecord = new PostingRecord(); + } + + public PostingRecordBase TransactionRecord { get; private set; } + public decimal Income { get; private set; } + public decimal Expense { get; private set; } + + public void Execute(ActionExecutionContext context) + { + InitializeTransactionRecorcd(); + Caliburn.Micro.Execute.OnUIThread(() => Completed(this, new ResultCompletionEventArgs())); + } + + protected virtual void InitializeTransactionRecorcd() + { + CategoryDTO category = null; + + if (Journal is DepositDTO) + { + Income = Journal.Amount; + Expense = 0; + category = (Journal as DepositDTO).CategoryId.LookupIn(categoriesRepository); + } + else if (Journal is WithdrawalDTO) + { + Income = 0; + Expense = -Journal.Amount; + category = (Journal as WithdrawalDTO).CategoryId.LookupIn(categoriesRepository); + } + else if (Journal is IncomingTransferDTO) + { + Income = Journal.Amount; // positive is "TO this account" + Expense = 0; + } + else if (Journal is OutgoingTransferDTO) + { + Income = 0; + Expense = -Journal.Amount; // negative is "FROM this account" + } + + TransactionRecord.TransactionId = Journal.Id; + TransactionRecord.Date = Journal.Date.IsUtc(); + TransactionRecord.Category = category; + TransactionRecord.Income = Income; + TransactionRecord.Expense = Expense; + TransactionRecord.Journal = Journal; + TransactionRecord.Comment = Journal.Comment; + } + + public event EventHandler Completed = delegate { }; + } +} \ No newline at end of file diff --git a/src/Fab.Client/MoneyTracker/Postings/AddTransactionRecordResult.cs b/src/Fab.Client/MoneyTracker/Postings/AddTransactionRecordResult.cs new file mode 100644 index 0000000..ca6abda --- /dev/null +++ b/src/Fab.Client/MoneyTracker/Postings/AddTransactionRecordResult.cs @@ -0,0 +1,24 @@ +using Fab.Client.MoneyServiceReference; +using Fab.Client.MoneyTracker.Categories; + +namespace Fab.Client.MoneyTracker.Postings +{ + public class AddTransactionRecordResult : AddTransactionRecordBaseResult + { + public AddTransactionRecordResult(JournalDTO journal, ICategoriesRepository repository, decimal prevBalance) + : base(journal, repository) + { + ((PostingRecord)TransactionRecord).Balance = prevBalance; + } + + #region Overrides of AddTransactionRecordBaseResult + + protected override void InitializeTransactionRecorcd() + { + base.InitializeTransactionRecorcd(); + ((PostingRecord)TransactionRecord).Balance += Journal.Amount; + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Fab.Client/MoneyTracker/Postings/CountPostingsResult.cs b/src/Fab.Client/MoneyTracker/Postings/CountPostingsResult.cs new file mode 100644 index 0000000..8081bef --- /dev/null +++ b/src/Fab.Client/MoneyTracker/Postings/CountPostingsResult.cs @@ -0,0 +1,60 @@ +//------------------------------------------------------------ +// +// Copyright (c) 2012 nReez. All rights reserved. +// +//------------------------------------------------------------ + +using System; +using Caliburn.Micro; +using Fab.Client.MoneyServiceReference; +using Fab.Client.Shell; +using Fab.Client.Shell.Async; + +namespace Fab.Client.MoneyTracker.Postings +{ + public class CountPostingsResult : IResult + { + /// + /// Gets or sets global instance of the that enables loosely-coupled publication of and subscription to events. + /// + private IEventAggregator EventAggregator { get; set; } + + public CountPostingsResult(Guid userId, int accountId, QueryFilter queryFilter, IEventAggregator eventAggregator) + { + UserId = userId; + AccountId = accountId; + QueryFilter = queryFilter; + EventAggregator = eventAggregator; + } + + public Guid UserId { get; private set; } + public int AccountId { get; private set; } + public QueryFilter QueryFilter { get; private set; } + public int Count { get; private set; } + + public event EventHandler Completed = delegate { }; + + public void Execute(ActionExecutionContext context) + { + var proxy = ServiceFactory.CreateMoneyService(); + proxy.GetJournalsCountCompleted += (s, e) => + { + if (e.Error != null) + { + Caliburn.Micro.Execute.OnUIThread( + () => Completed(this, new ResultCompletionEventArgs { Error = e.Error })); + } + else + { + Count = e.Result; + Caliburn.Micro.Execute.OnUIThread(() => Completed(this, new ResultCompletionEventArgs())); + } + + EventAggregator.Publish(new AsyncOperationCompleteMessage()); + }; + + proxy.GetJournalsCountAsync(UserId, AccountId, QueryFilter); + EventAggregator.Publish(new AsyncOperationStartedMessage { OperationName = "Counting matched postings for account #" + AccountId}); + } + } +} \ No newline at end of file diff --git a/src/Fab.Client/MoneyTracker/Postings/DeleteTransactionResult.cs b/src/Fab.Client/MoneyTracker/Postings/DeleteTransactionResult.cs index 4d5df24..20d76bd 100644 --- a/src/Fab.Client/MoneyTracker/Postings/DeleteTransactionResult.cs +++ b/src/Fab.Client/MoneyTracker/Postings/DeleteTransactionResult.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using Caliburn.Micro; -using Fab.Client.MoneyServiceReference; using Fab.Client.Shell; namespace Fab.Client.MoneyTracker.Postings diff --git a/src/Fab.Client/MoneyTracker/Postings/GetPostingsResult.cs b/src/Fab.Client/MoneyTracker/Postings/GetPostingsResult.cs index 1f92723..5225213 100644 --- a/src/Fab.Client/MoneyTracker/Postings/GetPostingsResult.cs +++ b/src/Fab.Client/MoneyTracker/Postings/GetPostingsResult.cs @@ -1,4 +1,10 @@ -using System; +//------------------------------------------------------------ +// +// Copyright (c) 2012 nReez. All rights reserved. +// +//------------------------------------------------------------ + +using System; using Caliburn.Micro; using Fab.Client.MoneyServiceReference; using Fab.Client.Shell; diff --git a/src/Fab.Client/MoneyTracker/Postings/PostingRecord.cs b/src/Fab.Client/MoneyTracker/Postings/PostingRecord.cs index 8623b97..d2105b1 100644 --- a/src/Fab.Client/MoneyTracker/Postings/PostingRecord.cs +++ b/src/Fab.Client/MoneyTracker/Postings/PostingRecord.cs @@ -1,70 +1,19 @@ //------------------------------------------------------------ -// +// // Copyright (c) 2012 nReez. All rights reserved. // //------------------------------------------------------------ -using System; -using Caliburn.Micro; -using Fab.Client.MoneyServiceReference; - namespace Fab.Client.MoneyTracker.Postings { /// /// Simple "income / expense / balance" data object. /// - public class PostingRecord : PropertyChangedBase + public class PostingRecord : PostingRecordBase { /// - /// Gets or sets unique (for account) transaction ID. - /// - public int TransactionId { get; set; } - - /// - /// Gets or sets operation date. - /// - public DateTime Date { get; set; } - - private CategoryDTO category; - - /// - /// Gets or sets transaction category. - /// - public CategoryDTO Category - { - get { return category; } - set { - if (category != value) - { - category = value; - NotifyOfPropertyChange(() => Category); - } - } - } - - /// - /// Gets or sets income part of the transaction record. - /// - public decimal Income { get; set; } - - /// - /// Gets or sets expense part of the transaction record. - /// - public decimal Expense { get; set; } - - /// - /// Gets or sets balance part of the transaction record. + /// Gets or sets balance after the transaction record. /// public decimal Balance { get; set; } - - /// - /// Gets or sets transaction optional comment. - /// - public string Comment { get; set; } - - /// - /// Gets or sets original transaction data. - /// - public JournalDTO Journal { get; set; } } } \ No newline at end of file diff --git a/src/Fab.Client/MoneyTracker/Postings/PostingRecordBase.cs b/src/Fab.Client/MoneyTracker/Postings/PostingRecordBase.cs new file mode 100644 index 0000000..76cb50d --- /dev/null +++ b/src/Fab.Client/MoneyTracker/Postings/PostingRecordBase.cs @@ -0,0 +1,65 @@ +//------------------------------------------------------------ +// +// Copyright (c) 2012 nReez. All rights reserved. +// +//------------------------------------------------------------ + +using System; +using Caliburn.Micro; +using Fab.Client.MoneyServiceReference; + +namespace Fab.Client.MoneyTracker.Postings +{ + /// + /// Simple "income / expense" data object. + /// + public class PostingRecordBase : PropertyChangedBase + { + private CategoryDTO category; + + /// + /// Gets or sets transaction category. + /// + public CategoryDTO Category + { + get { return category; } + set { + if (category != value) + { + category = value; + NotifyOfPropertyChange(() => Category); + } + } + } + + /// + /// Gets or sets income part of the transaction record. + /// + public decimal Income { get; set; } + + /// + /// Gets or sets expense part of the transaction record. + /// + public decimal Expense { get; set; } + + /// + /// Gets or sets transaction optional comment. + /// + public string Comment { get; set; } + + /// + /// Gets or sets original transaction data. + /// + public JournalDTO Journal { get; set; } + + /// + /// Gets or sets unique (for account) transaction ID. + /// + public int TransactionId { get; set; } + + /// + /// Gets or sets operation date. + /// + public DateTime Date { get; set; } + } +} \ No newline at end of file diff --git a/src/Fab.Client/MoneyTracker/Postings/PostingViewModelBase.cs b/src/Fab.Client/MoneyTracker/Postings/PostingViewModelBase.cs new file mode 100644 index 0000000..dbc82e8 --- /dev/null +++ b/src/Fab.Client/MoneyTracker/Postings/PostingViewModelBase.cs @@ -0,0 +1,673 @@ +//------------------------------------------------------------ +// +// Copyright (c) 2012 nReez. All rights reserved. +// +//------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using Caliburn.Micro; +using Fab.Client.Authentication; +using Fab.Client.Framework; +using Fab.Client.Framework.Results; +using Fab.Client.MoneyServiceReference; +using Fab.Client.MoneyTracker.Accounts; +using Fab.Client.MoneyTracker.Categories; +using Fab.Client.MoneyTracker.Postings.Transactions; +using Fab.Client.MoneyTracker.Postings.Transfers; +using Fab.Core.Framework; + +namespace Fab.Client.MoneyTracker.Postings +{ + public class PostingViewModelBase : Conductor.Collection.OneActive, + ICanBeBusy, + IHandle, + IHandle + { + /// + /// Enables loosely-coupled publication of and subscription to events. + /// + protected readonly IEventAggregator eventAggregator = IoC.Get(); + protected readonly ICategoriesRepository categoriesRepository = IoC.Get(); + private readonly IAccountsRepository accountsRepository = IoC.Get(); + + #region Properties + + private string searchStatus = "Search"; + + public string SearchStatus + { + get { return searchStatus; } + set + { + searchStatus = value; + NotifyOfPropertyChange(() => SearchStatus); + } + } + + private string containsText; + + public string ContainsText + { + get { return containsText; } + set + { + containsText = value; + NotifyOfPropertyChange(() => ContainsText); + } + } + + /// + /// Start date for filtering transactions. + /// + protected DateTime startDate; + + public DateTime StartDate + { + get { return startDate; } + set + { + startDate = value; + NotifyOfPropertyChange(() => StartDate); + } + } + + /// + /// Start date for filtering transactions. + /// + protected DateTime endDate; + + public DateTime EndDate + { + get { return endDate; } + set + { + endDate = value; + NotifyOfPropertyChange(() => EndDate); + } + } + + private bool useEndDate; + + public bool UseEndDate + { + get { return useEndDate; } + set + { + useEndDate = value; + NotifyOfPropertyChange(() => UseEndDate); + } + } + + private bool useStartDate; + + public bool UseStartDate + { + get { return useStartDate; } + + set + { + useStartDate = value; + NotifyOfPropertyChange(() => UseStartDate); + } + } + + + /// + /// Account ID of transactions. + /// + private int accountId; + + /// + /// Gets or sets account ID of transactions. + /// + public int AccountId + { + get { return accountId; } + set + { + if (accountId != value) + { + accountId = value; + IsOutdated = true; + } + } + } + + /// + /// Total income for the filtered period. + /// + private decimal totalIncome; + + /// + /// Gets or sets total income for the filtered period. + /// + public decimal TotalIncome + { + get { return totalIncome; } + set + { + totalIncome = value; + NotifyOfPropertyChange(() => TotalIncome); + NotifyOfPropertyChange(() => BalanceDiff); + NotifyOfPropertyChange(() => EndBalance); + } + } + + /// + /// Total expense for the filtered period. + /// + private decimal totalExpense; + + /// + /// Gets or sets total expense for the filtered period. + /// + public decimal TotalExpense + { + get { return totalExpense; } + set + { + totalExpense = value; + NotifyOfPropertyChange(() => TotalExpense); + NotifyOfPropertyChange(() => BalanceDiff); + NotifyOfPropertyChange(() => EndBalance); + } + } + + /// + /// Indicate whether postings are outdated for current filter period and need to be downloaded from server. + /// + private bool isOutdated = true; + + /// + /// Gets or sets a value indicating whether postings are outdated for current filter period. + /// + public bool IsOutdated + { + get { return isOutdated; } + set + { + if (isOutdated != value) + { + isOutdated = value; + NotifyOfPropertyChange(() => IsOutdated); + } + } + } + + /// + /// Account balance at the moment. + /// + private decimal startBalance; + + /// + /// Gets or sets account balance at the moment. + /// + public decimal StartBalance + { + get { return startBalance; } + set + { + startBalance = value; + NotifyOfPropertyChange(() => StartBalance); + NotifyOfPropertyChange(() => EndBalance); + } + } + + /// + /// Gets or sets account balance at the moment. + /// + public decimal EndBalance + { + get { return StartBalance + BalanceDiff; } + } + + /// + /// Gets or sets account balance difference for the filtered period. + /// + public decimal BalanceDiff + { + get { return TotalIncome + TotalExpense; } + } + + /// + /// Gets transaction records. + /// + public IObservableCollection TransactionRecords { get; private set; } + + private bool isDirty; + + public bool IsDirty + { + get { return isDirty; } + set + { + isDirty = value; + NotifyOfPropertyChange(() => IsDirty); + } + } + + public TransactionViewModel TransactionDetails { get; set; } + public TransferViewModel TransferDetails { get; set; } + + [Import] + public IDialogManager Dialogs { get; set; } + + #endregion + + /// + /// Initializes a new instance of the class. + /// + [ImportingConstructor] + public PostingViewModelBase(TransactionViewModel transactionDetails, TransferViewModel transferDetails) + { + TransactionDetails = transactionDetails; + TransferDetails = transferDetails; + Init(); + eventAggregator.Subscribe(this); + } + + protected void Init() + { + if (TransactionRecords == null) + { + TransactionRecords = new BindableCollection(); + } + else + { + TransactionRecords.Clear(); + } + + StartDate = DateTime.Now; + EndDate = DateTime.Now; + UseStartDate = false; + UseEndDate = false; + ContainsText = string.Empty; + TotalIncome = 0; + TotalExpense = 0; + TotalPostingsCount = 0; + } + + protected virtual IEnumerable PreAction() + { + yield break; + } + + protected virtual AddTransactionRecordBaseResult CreateTransactionRecordResult(JournalDTO r) + { + return new AddTransactionRecordBaseResult(r, categoriesRepository); + } + + /// + /// Download all transactions for specific account of the specific user. + /// + /// Operation result. + /// TODO: Sometimes "from-till" dates with 1 month interval doesn't equal, for example: + /// "2 March - 2 April", but in most cases correct should be "2 March - 1 April" + public IEnumerable DownloadAllTransactions() + { + if (IsBusy) + { + yield break; + } + + yield return new SingleResult + { + Action = () => + { + IsBusy = true; + SearchStatus = "Searching..."; + } + }; + + yield return Loader.Show("Loading..."); + + yield return new SequentialResult(PreAction().GetEnumerator()); + + yield return new SequentialResult(DeterminePagesCount().GetEnumerator()); + + yield return new SequentialResult(LoadPostings().GetEnumerator()); + + SearchStatus = "Search"; + IsBusy = false; + IsOutdated = false; + + yield return Loader.Hide(); + } + + private IEnumerable DeterminePagesCount() + { + var countResult = new CountPostingsResult(UserCredentials.Current.UserId, AccountId, CreateFilter(), eventAggregator); + yield return countResult; + + yield return new SingleResult + { + Action = () => + { + + if (countResult.Count >= 1) + { + TotalPostingsCount = countResult.Count; + PagesCount = PageSize.HasValue + ? countResult.Count/PageSize.Value + + (countResult.Count%PageSize.Value > 0 ? 1 : 0) + : 1; + CurrentPageIndex = PagesCount > 0 ? 1 : 0; + } + else + { + TotalPostingsCount = 0; + PagesCount = 0; + CurrentPageIndex = 0; + } + } + }; + } + + private IEnumerable LoadPostings() + { + // Get filtered transactions during specified time frame + var transactionsResult = new GetPostingsResult(UserCredentials.Current.UserId, AccountId, CreateFilter(PageSize), eventAggregator); + yield return transactionsResult; + + yield return new SingleResult + { + Action = () => + { + TotalIncome = 0; + TotalExpense = 0; + TransactionRecords.Clear(); + } + }; + + foreach (var r in transactionsResult.TransactionRecords) + { + var result = CreateTransactionRecordResult(r); + yield return result; + + TransactionRecords.Add(result.TransactionRecord); + + TotalIncome += result.Income; + TotalExpense -= result.Expense; + } + } + + private TextSearchFilter CreateFilter(int? itemsPerPage = null) + { + var filter = new TextSearchFilter + { + NotOlderThen = UseStartDate + ? StartDate.ToUniversalTime() + : (DateTime?)null, + Upto = UseEndDate + ? EndDate.AddDays(1) /*.AddMilliseconds(1)*/.ToUniversalTime() + : (DateTime?)null, + Contains = !string.IsNullOrEmpty(ContainsText) + ? ContainsText + : null, + Take = itemsPerPage, + Skip = itemsPerPage != null ? (CurrentPageIndex - 1) * itemsPerPage : null, + }; + return filter; + } + + #region Paging + + private int currentPageIndex; + + public int CurrentPageIndex + { + get { return currentPageIndex; } + set + { + currentPageIndex = value; + NotifyOfPropertyChange(() => CurrentPageIndex); + NotifyOfPropertyChange(() => CanNextPage); + NotifyOfPropertyChange(() => CanPrevPage); + } + } + + private int? pageSize; + public int? PageSize + { + get { return pageSize; } + set + { + pageSize = value; + NotifyOfPropertyChange(() => PageSize); + } + } + + private int pagesCount; + public int PagesCount + { + get { return pagesCount; } + set + { + pagesCount = value; + NotifyOfPropertyChange(() => PagesCount); + } + } + + private int totalPostingsCount; + + public int TotalPostingsCount + { + get { return totalPostingsCount; } + set + { + totalPostingsCount = value; + NotifyOfPropertyChange(() => TotalPostingsCount); + } + } + + public IEnumerable NextPage() + { + yield return new SingleResult + { + Action = () => + { + IsBusy = true; + CurrentPageIndex++; + } + }; + + yield return new SequentialResult(DownloadAllTransactions().GetEnumerator()); + + IsBusy = false; + } + + public bool CanNextPage + { + get { return CurrentPageIndex < PagesCount; } + } + + public IEnumerable PrevPage() + { + yield return new SingleResult + { + Action = () => + { + IsBusy = true; + CurrentPageIndex--; + } + }; + + yield return new SequentialResult(DownloadAllTransactions().GetEnumerator()); + + IsBusy = false; + } + + public bool CanPrevPage + { + get { return 1 < CurrentPageIndex; } + } + + #endregion + + #region Implementation of ICanBeBusy + + /// + /// Indicate whether view-model is busy by some background operation. + /// + private bool isBusy; + + /// + /// Gets or sets a value indicating whether view-model is busy by some background operation. + /// + public bool IsBusy + { + get { return isBusy; } + set + { + isBusy = value; + NotifyOfPropertyChange(() => IsBusy); + } + } + + #endregion + + #region Implementation of IHandle + + /// + /// Handles the message. + /// + /// The message. + public void Handle(AccountUpdatedMessage message) + { + if (message.Account.Id == AccountId) + { + IsOutdated = true; + Update(); + } + } + + #endregion + + #region Implementation of IHandle + + /// + /// Handles the message. + /// + /// The message. + public void Handle(CategoryDeletedMessage message) + { + foreach (var transactionRecord in TransactionRecords) + { + if (transactionRecord.Category != null && transactionRecord.Category.Id == message.Category.Id) + { + transactionRecord.Category = null; + } + } + } + + #endregion + + public override void CanClose(Action callback) + { + callback(IsDirty); + } + + public virtual void CancelEdit() + { + ActivateItem(null); + } + + public IEnumerable EditPosting(PostingRecord transactionRecord) + { + if (transactionRecord.Journal is TransactionDTO) + { + TransactionDetails.Edit(transactionRecord.Journal as TransactionDTO, AccountId); + ActivateItem(TransactionDetails); + } + else if (transactionRecord.Journal is TransferDTO) + { + var transferResult = new GetPostingResult(UserCredentials.Current.UserId, AccountId, transactionRecord.TransactionId, eventAggregator); + yield return transferResult; + + var transfer = transferResult.Transaction as TransferDTO; + TransferDetails.Edit(transfer, AccountId); + ActivateItem(TransferDetails); + } + else + { + throw new NotSupportedException("Transaction of type " + transactionRecord.Journal.GetType() + " is not editable."); + } + } + + public IEnumerable DeleteTransaction(PostingRecord transactionRecord) + { + var openConfirmationResult = new OpenConfirmationResult(eventAggregator) + { + Message = + "Do you really want to delete the selected posting #" + + transactionRecord.TransactionId + " ?", + Title = "Confirmation", + Options = MessageBoxOptions.Yes | MessageBoxOptions.Cancel, + }; + + yield return openConfirmationResult; + + if (openConfirmationResult.Selected == MessageBoxOptions.Yes) + { + // Load transaction from server (used below to determine if the deleted posting was transfer) + var request = new GetPostingResult(UserCredentials.Current.UserId, AccountId, transactionRecord.TransactionId, eventAggregator); + yield return request; + + // Remove transaction on server + var request2 = new DeleteTransactionResult(UserCredentials.Current.UserId, AccountId, + transactionRecord.TransactionId); + yield return request2; + + // Update accounts balance + accountsRepository.Download(AccountId); + + // Update category usage + if (transactionRecord.Category != null) + { + categoriesRepository.Download(transactionRecord.Category.Id); + } + + // For transfer the 2-nd account should also be updated + if (request.Transaction is TransferDTO) + { + int secondAccountId = ((TransferDTO) request.Transaction).SecondAccountId.Value; + accountsRepository.Download(secondAccountId); + } + + // Remove transaction locally + var transactionToDelete = + TransactionRecords.Where(record => record.TransactionId == transactionRecord.TransactionId).Single(); + var index = TransactionRecords.IndexOf(transactionToDelete); + TransactionRecords.Remove(transactionToDelete); + + // Correct remained balance for following transactions + if (TransactionRecords.Count > 0 && index < TransactionRecords.Count) + { + var deletedAmount = transactionToDelete.Income > 0 + ? -transactionToDelete.Income + : transactionToDelete.Expense; + + for (int i = index; i < TransactionRecords.Count; i++) + { + ((PostingRecord) TransactionRecords[i]).Balance += deletedAmount; + } + } + } + } + + + /// + /// Download postings if they are outdated for current filter period. + /// + public void Update() + { + if (IsOutdated) + { + Coroutine.BeginExecute(DownloadAllTransactions().GetEnumerator()); + } + } + } +} \ No newline at end of file diff --git a/src/Fab.Client/MoneyTracker/Postings/PostingsViewModel.cs b/src/Fab.Client/MoneyTracker/Postings/PostingsViewModel.cs index e6e1e24..8062099 100644 --- a/src/Fab.Client/MoneyTracker/Postings/PostingsViewModel.cs +++ b/src/Fab.Client/MoneyTracker/Postings/PostingsViewModel.cs @@ -7,13 +7,9 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; -using System.Linq; using Caliburn.Micro; using Fab.Client.Authentication; -using Fab.Client.Framework; using Fab.Client.MoneyServiceReference; -using Fab.Client.MoneyTracker.Accounts; -using Fab.Client.MoneyTracker.Categories; using Fab.Client.MoneyTracker.Postings.Actions; using Fab.Client.MoneyTracker.Postings.Transactions; using Fab.Client.MoneyTracker.Postings.Transfers; @@ -25,190 +21,27 @@ namespace Fab.Client.MoneyTracker.Postings /// [Export(typeof (PostingsViewModel))] [PartCreationPolicy(CreationPolicy.NonShared)] - public class PostingsViewModel : Conductor.Collection.OneActive, IHandle, IHandle + public class PostingsViewModel : PostingViewModelBase { - #region Fields - - /// - /// Enables loosely-coupled publication of and subscription to events. - /// - private readonly IEventAggregator eventAggregator = IoC.Get(); - - private readonly IAccountsRepository accountsRepository = IoC.Get(); - private readonly ICategoriesRepository categoriesRepository = IoC.Get(); - - /// - /// Account ID of transactions. - /// - private int accountId; - - /// - /// Account balance at the moment. - /// - private decimal startBalance; - - /// - /// Account balance at the moment. - /// - private decimal endBalance; - - /// - /// Total income for the filtered period. - /// - private decimal totalIncome; - - /// - /// Total expense for the filtered period. - /// - private decimal totalExpense; - - /// - /// Account balance difference for the filtered period. - /// - private decimal balanceDiff; - - /// - /// Start date for filtering transactions. - /// - private DateTime fromDate; - - /// - /// Start date for filtering transactions. - /// - private DateTime tillDate; - - /// - /// Indicate whether postings are outdated for current filter period and need to be downloaded from server. - /// - private bool isOutdated = true; - - #endregion - #region Properties /// - /// Gets or sets account ID of transactions. - /// - public int AccountId - { - get { return accountId; } - set - { - if (accountId != value) - { - accountId = value; - IsOutdated = true; - } - } - } - - /// - /// Gets transaction records. - /// - public IObservableCollection TransactionRecords { get; private set; } - - /// - /// Gets or sets account balance at the moment. - /// - public decimal StartBalance - { - get { return startBalance; } - set - { - startBalance = value; - NotifyOfPropertyChange(() => StartBalance); - } - } - - /// - /// Gets or sets account balance at the moment. - /// - public decimal EndBalance - { - get { return endBalance; } - set - { - endBalance = value; - NotifyOfPropertyChange(() => EndBalance); - } - } - - /// - /// Gets or sets total income for the filtered period. - /// - public decimal TotalIncome - { - get { return totalIncome; } - set - { - totalIncome = value; - NotifyOfPropertyChange(() => TotalIncome); - } - } - - /// - /// Gets or sets total expense for the filtered period. - /// - public decimal TotalExpense - { - get { return totalExpense; } - set - { - totalExpense = value; - NotifyOfPropertyChange(() => TotalExpense); - } - } - - /// - /// Gets or sets account balance difference for the filtered period. - /// - public decimal BalanceDiff - { - get { return balanceDiff; } - set - { - balanceDiff = value; - NotifyOfPropertyChange(() => BalanceDiff); - } - } - - /// - /// Gets filter date period text ("FromDate - TillDate" or "FromDate" only). + /// Gets filter date period text ("startDate - endDate" or "startDate" only). /// public string Period { get { - return fromDate.Date == tillDate.Date - ? fromDate.Date.ToLongDateString() - : fromDate.Month == tillDate.Month - ? fromDate.Day + " - " + tillDate.Day + " " + fromDate.ToString("MMMM yyyy ã.") + " (" + ((tillDate - fromDate).TotalDays + 1) + " days)" - : fromDate.Date.ToLongDateString() + " - " + tillDate.Date.ToLongDateString() + " (" + ((tillDate - fromDate).TotalDays + 1) + " days)"; + return startDate.Date == endDate.Date + ? startDate.Date.ToLongDateString() + : startDate.Month == endDate.Month + ? startDate.Day + " - " + endDate.Day + " " + startDate.ToString("MMMM yyyy ã.") + " (" + ((endDate - startDate).TotalDays + 1) + " days)" + : startDate.Date.ToLongDateString() + " - " + endDate.Date.ToLongDateString() + " (" + ((endDate - startDate).TotalDays + 1) + " days)"; } } - public TransactionViewModel TransactionDetails { get; set; } - - public TransferViewModel TransferDetails { get; set; } - public PostingActionsViewModel PostingsActions { get; set; } - /// - /// Gets or sets a value indicating whether postings are outdated for current filter period. - /// - public bool IsOutdated - { - get { return isOutdated; } - set - { - if (isOutdated != value) - { - isOutdated = value; - NotifyOfPropertyChange(() => IsOutdated); - } - } - } - #endregion #region Ctors @@ -217,49 +50,26 @@ public bool IsOutdated /// Initializes a new instance of the class. /// [ImportingConstructor] - public PostingsViewModel(PostingActionsViewModel postingsActions, TransactionViewModel transactionDetails, - TransferViewModel transferDetails) + public PostingsViewModel(TransactionViewModel transactionDetails, TransferViewModel transferDetails, + PostingActionsViewModel postingsActions):base(transactionDetails, transferDetails) { - TransactionRecords = new BindableCollection(); + startDate = DateTime.Now; + endDate = DateTime.Now; + UseStartDate = true; + UseEndDate = true; PostingsActions = postingsActions; - TransactionDetails = transactionDetails; - TransferDetails = transferDetails; ActivationProcessed += (sender, args) => { IsDirty = (args.Item != PostingsActions); }; - - fromDate = DateTime.Now.Date; - tillDate = DateTime.Now.Date; - - eventAggregator.Subscribe(this); } #endregion - #region DocumentBase - - private bool isDirty; - - public bool IsDirty - { - get { return isDirty; } - set - { - isDirty = value; - NotifyOfPropertyChange(() => IsDirty); - } - } - - [Import] - public IDialogManager Dialogs { get; set; } - - public override void CanClose(Action callback) - { - callback(IsDirty); - } + #region Overrides of PostingViewModelBase - public void CancelEdit() + public override void CancelEdit() { + //base.CancelEdit(); ActivateItem(PostingsActions); } @@ -296,6 +106,25 @@ protected override void OnActivate() #endregion + #region Overrides of PostingViewModelBase + + protected override IEnumerable PreAction() + { + // Determine previous account balance. + var balanceResult = new GetBalanceResult(UserCredentials.Current.UserId, AccountId, startDate.ToUniversalTime(), + eventAggregator); + yield return balanceResult; + + StartBalance = balanceResult.Balance; + } + + protected override AddTransactionRecordBaseResult CreateTransactionRecordResult(JournalDTO r) + { + return new AddTransactionRecordResult(r, categoriesRepository, StartBalance); + } + + #endregion + #region Methods /// @@ -304,7 +133,7 @@ protected override void OnActivate() public void NewIncome() { TransactionDetails.IsDeposite = true; - TransactionDetails.Create(AccountId, fromDate.Date); + TransactionDetails.Create(AccountId, startDate.Date); ActivateItem(TransactionDetails); } @@ -314,7 +143,7 @@ public void NewIncome() public void NewExpense() { TransactionDetails.IsDeposite = false; - TransactionDetails.Create(AccountId, fromDate.Date); + TransactionDetails.Create(AccountId, startDate.Date); ActivateItem(TransactionDetails); } @@ -323,272 +152,19 @@ public void NewExpense() /// public void NewTransfer() { - TransferDetails.Create(AccountId, fromDate.Date); + TransferDetails.Create(AccountId, startDate.Date); ActivateItem(TransferDetails); } - public IEnumerable EditPosting(PostingRecord transactionRecord) - { - if (transactionRecord.Journal is TransactionDTO) - { - TransactionDetails.Edit(transactionRecord.Journal as TransactionDTO, AccountId); - ActivateItem(TransactionDetails); - } - else if (transactionRecord.Journal is TransferDTO) - { - var transferResult = new GetPostingResult(UserCredentials.Current.UserId, AccountId, transactionRecord.TransactionId, eventAggregator); - yield return transferResult; - - var transfer = transferResult.Transaction as TransferDTO; - TransferDetails.Edit(transfer, AccountId); - ActivateItem(TransferDetails); - } - else - { - throw new NotSupportedException("Transaction of type " + transactionRecord.Journal.GetType() + " is not editable."); - } - - yield break; - } - - public IEnumerable DeleteTransaction(PostingRecord transactionRecord) - { - var openConfirmationResult = new OpenConfirmationResult(eventAggregator) - { - Message = - "Do you really want to delete the selected posting #" + - transactionRecord.TransactionId + " ?", - Title = "Confirmation", - Options = MessageBoxOptions.Yes | MessageBoxOptions.Cancel, - }; - - yield return openConfirmationResult; - - if (openConfirmationResult.Selected == MessageBoxOptions.Yes) - { - // Load transaction from server (used below to determine if the deleted posting was transfer) - var request = new GetPostingResult(UserCredentials.Current.UserId, AccountId, transactionRecord.TransactionId, eventAggregator); - yield return request; - - // Remove transaction on server - var request2 = new DeleteTransactionResult(UserCredentials.Current.UserId, AccountId, - transactionRecord.TransactionId); - yield return request2; - - // Update accounts balance - accountsRepository.Download(AccountId); - - // Update category usage - if (transactionRecord.Category != null) - { - categoriesRepository.Download(transactionRecord.Category.Id); - } - - // For transfer the 2-nd account should also be updated - if (request.Transaction is TransferDTO) - { - int secondAccountId = ((TransferDTO) request.Transaction).SecondAccountId.Value; - accountsRepository.Download(secondAccountId); - } - - // Remove transaction locally - var transactionToDelete = - TransactionRecords.Where(record => record.TransactionId == transactionRecord.TransactionId).Single(); - var index = TransactionRecords.IndexOf(transactionToDelete); - TransactionRecords.Remove(transactionToDelete); - - // Correct remained balance for following transactions - if (TransactionRecords.Count > 0 && index < TransactionRecords.Count) - { - var deletedAmount = transactionToDelete.Income > 0 - ? -transactionToDelete.Income - : transactionToDelete.Expense; - - for (int i = index; i < TransactionRecords.Count; i++) - { - TransactionRecords[i].Balance += deletedAmount; - } - } - } - } - -// private void UpdateTillDate(bool reloadTransactions) -// { -// switch (SelectedDateRange) -// { -// case DateRange.Day: -// TillDate = FromDate.AddDays(1).AddMilliseconds(-1); -// break; -// -// case DateRange.FourDays: -// TillDate = FromDate.AddDays(4).AddMilliseconds(-1); -// break; -// -// case DateRange.Week: -// TillDate = FromDate.AddDays(7).AddMilliseconds(-1); -// break; -// -// case DateRange.Month: -// TillDate = FromDate.AddMonths(1).AddMilliseconds(-1); -// break; -// } -// -// if (reloadTransactions) -// { -// Coroutine.Execute(DownloadAllTransactions().GetEnumerator()); -// } -// } - public void SetFilterPeriod(DateTime startDate, DateTime endDate) { - fromDate = startDate; - tillDate = endDate; + base.startDate = startDate; + base.endDate = endDate; IsOutdated = true; NotifyOfPropertyChange(() => Period); } - /// - /// Download postings if they are outdated for current filter period. - /// - public void Update() - { - if (IsOutdated) - { - Coroutine.BeginExecute(DownloadAllTransactions().GetEnumerator()); - } - } - - /// - /// Download all transactions for specific account of the specific user. - /// - /// Operation result. - private IEnumerable DownloadAllTransactions() - { - yield return Loader.Show("Loading..."); - - // Determine previous account balance - var balanceResult = new GetBalanceResult(UserCredentials.Current.UserId, AccountId, fromDate.ToUniversalTime(), eventAggregator); - yield return balanceResult; - - StartBalance = balanceResult.Balance; - - //TODO: ########################### - // Âûÿñíèòü, ïî÷åìó èíîãäà from-till äàòû ñ èíòåðâàëîì â ìåñÿö íå ñîâïàäàþò, íàïðèìåð: - // 2 ìàðòà - 2 àïðåëÿ, õîòÿ â áîëüøèíñòâå ñëó÷àÿõ ïðàâèëüíî äîëæíî áûòü 2 ìàðòà - 1 àïðåëÿ - - // È óäàëèòü âñå ñòàðîå, ÷òî îñòàëîñü îò èíòåðâàëîâ (îñòàâëÿåì òîëüêî êàëåíäàðèê) - // ################################ - - // Get filtered transactions during specified time frame - var queryFilterDTO = new QueryFilter - { - NotOlderThen = fromDate.ToUniversalTime(), - Upto = tillDate.AddDays(1) /*.AddMilliseconds(1)*/.ToUniversalTime(), - }; - var transactionsResult = new GetPostingsResult(UserCredentials.Current.UserId, AccountId, queryFilterDTO, eventAggregator); - yield return transactionsResult; - - TransactionRecords.Clear(); - - decimal income = 0; - decimal expense = 0; - decimal incomeForPeriod = 0; - decimal expenseForPeriod = 0; - decimal balance = balanceResult.Balance; - CategoryDTO category = null; - - foreach (var r in transactionsResult.TransactionRecords) - { - balance += r.Amount; - - if (r is DepositDTO) - { - income = r.Amount; - incomeForPeriod += r.Amount; - expense = 0; - category = (r as DepositDTO).CategoryId.LookupIn(categoriesRepository); - } - else if (r is WithdrawalDTO) - { - income = 0; - expense = -r.Amount; - expenseForPeriod += r.Amount; - category = (r as WithdrawalDTO).CategoryId.LookupIn(categoriesRepository); - } - else if (r is IncomingTransferDTO) - { - income = r.Amount; // positive is "TO this account" - incomeForPeriod += r.Amount; - expense = 0; - category = null; - } - else if (r is OutgoingTransferDTO) - { - income = 0; - expense = -r.Amount; // negative is "FROM this account" - expenseForPeriod += r.Amount; - category = null; - } - - TransactionRecords.Add(new PostingRecord - { - TransactionId = r.Id, - Date = DateTime.SpecifyKind(r.Date, DateTimeKind.Utc), - Category = category, - Income = income, - Expense = expense, - Balance = balance, - Comment = r.Comment, - Journal = r - }); - } - - EndBalance = balance; - TotalIncome = incomeForPeriod; - TotalExpense = expenseForPeriod; - BalanceDiff = incomeForPeriod + expenseForPeriod; - - IsOutdated = false; - - yield return Loader.Hide(); - } - #endregion - #region Implementation of IHandle - - /// - /// Handles the message. - /// - /// The message. - public void Handle(CategoryDeletedMessage message) - { - foreach (var transactionRecord in TransactionRecords) - { - if(transactionRecord.Category != null && transactionRecord.Category.Id == message.Category.Id) - { - transactionRecord.Category = null; - } - } - } - - #endregion - - #region Implementation of IHandle - - /// - /// Handles the message. - /// - /// The message. - public void Handle(AccountUpdatedMessage message) - { - if (message.Account.Id == AccountId) - { - IsOutdated = true; - Update(); - } - } - - #endregion } } \ No newline at end of file diff --git a/src/Fab.Client/MoneyTracker/Postings/Transfers/TransferView.xaml b/src/Fab.Client/MoneyTracker/Postings/Transfers/TransferView.xaml index deb191e..7af3dd6 100644 --- a/src/Fab.Client/MoneyTracker/Postings/Transfers/TransferView.xaml +++ b/src/Fab.Client/MoneyTracker/Postings/Transfers/TransferView.xaml @@ -1,113 +1,18 @@  + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" + xmlns:local="clr-namespace:Fab.Client.Common" + xmlns:common="clr-namespace:Fab.Client.Framework.Common" + xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit" + xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" + xmlns:Behaviors="clr-namespace:Fab.Client.Framework.Behaviors" + IsEnabled="{Binding Path=IsBusy, Converter={StaticResource boolToNotBool}}" + mc:Ignorable="d"> - @@ -122,143 +27,123 @@ + VerticalAlignment="Center" + IsTabStop="True" + TabIndex="5" /> - - - - - - - - - - + Grid.Column="1" + MinWidth="150" + Margin="5,0" + ToolTipService.ToolTip="From Account" + VerticalAlignment="Center" + HorizontalAlignment="Stretch" + HorizontalContentAlignment="Stretch" + TabIndex="0" + ItemContainerStyle="{StaticResource ComboBoxItemStyle}" + ItemTemplate="{StaticResource AccountBrief}" /> + VerticalAlignment="Center" + Text="->" /> + Grid.Column="3" + MinWidth="150" + Margin="5,0" + ToolTipService.ToolTip="To Account" + VerticalAlignment="Center" + HorizontalAlignment="Stretch" + HorizontalContentAlignment="Stretch" + TabIndex="1" + ItemContainerStyle="{StaticResource ComboBoxItemStyle}"> + Margin="5,0,0,0" + MinWidth="20" + Text="{Binding Path=AssetTypeId, Converter={StaticResource assetTypeIdToString}}" + VerticalAlignment="Center" + HorizontalAlignment="Left" /> + Text="{Binding Path=Balance, StringFormat=\{0:N\}}" + Foreground="{Binding Path=Balance, Converter={StaticResource balanceToColor}}" + Margin="5,0,0,0" + HorizontalAlignment="Right" + VerticalAlignment="Center" /> + FontWeight="Bold" /> + VerticalAlignment="Center" + TabIndex="4" + CaretBrush="Yellow"> + Grid.Row="1">