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">
+ toolkit:DockPanel.Dock="Right"
+ Content="Cancel"
+ MinWidth="75"
+ MinHeight="23"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center"
+ TabIndex="7" />
+ toolkit:DockPanel.Dock="Right"
+ Content="Save"
+ MinWidth="75"
+ MinHeight="23"
+ Margin="5,0"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center"
+ TabIndex="6" />
+ Text="{Binding Path=Comment, Mode=TwoWay}"
+ VerticalAlignment="Center"
+ IsTabStop="True"
+ TabIndex="5">
diff --git a/src/Fab.Client/MoneyTracker/SearchDashBoardView.xaml b/src/Fab.Client/MoneyTracker/SearchDashBoardView.xaml
index 5b3459d..82aa19f 100644
--- a/src/Fab.Client/MoneyTracker/SearchDashBoardView.xaml
+++ b/src/Fab.Client/MoneyTracker/SearchDashBoardView.xaml
@@ -6,89 +6,99 @@
xmlns:cal="http://www.caliburnproject.org"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:Resources="clr-namespace:Fab.Client.Resources.Actions"
- xmlns:Controls="clr-namespace:SilverlightContrib.Controls;assembly=SilverlightContrib.Controls"
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"
mc:Ignorable="d"
d:DesignHeight="187"
d:DesignWidth="980">
-
-
-
-
+
-
-
+
-
-
-
+
+
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/src/Fab.Client/MoneyTracker/SearchDashBoardViewModel.cs b/src/Fab.Client/MoneyTracker/SearchDashBoardViewModel.cs
index 9fe613c..c11eac2 100644
--- a/src/Fab.Client/MoneyTracker/SearchDashBoardViewModel.cs
+++ b/src/Fab.Client/MoneyTracker/SearchDashBoardViewModel.cs
@@ -4,60 +4,65 @@
//
//------------------------------------------------------------
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
using System.ComponentModel.Composition;
+using System.Windows.Data;
using Caliburn.Micro;
+using Fab.Client.Authentication;
using Fab.Client.Framework;
using Fab.Client.MoneyServiceReference;
-using Fab.Client.MoneyTracker.Categories;
+using Fab.Client.MoneyTracker.Accounts;
+using Fab.Client.MoneyTracker.Postings;
+using Fab.Client.MoneyTracker.Postings.Transactions;
+using Fab.Client.MoneyTracker.Postings.Transfers;
namespace Fab.Client.MoneyTracker
{
///
/// General search screen model.
///
- [Export(typeof(IModule))]
- public class SearchDashBoardViewModel : Conductor.Collection.AllActive, IModule
+ [Export(typeof (IModule))]
+ public class SearchDashBoardViewModel : PostingViewModelBase, IModule, IHandle
{
#region Fields
///
- /// Category repository.
+ /// Accounts repository.
///
- private readonly ICategoriesRepository repository = IoC.Get();
+ private readonly IAccountsRepository accountsRepository = IoC.Get();
#endregion
- #region Deposit categories
+ private readonly CollectionViewSource sourceAccountsViewSource = new CollectionViewSource();
- private CategoriesViewModel depositCategories;
+ public ICollectionView Accounts
+ {
+ get { return sourceAccountsViewSource.View; }
+ }
- public CategoriesViewModel DepositCategories
+ private void InitSourceAccounts()
{
- get { return depositCategories; }
- set
+ sourceAccountsViewSource.Source = accountsRepository.Entities;
+
+ if (!Accounts.IsEmpty)
{
- if (depositCategories != value)
- {
- depositCategories = value;
- NotifyOfPropertyChange(() => DepositCategories);
- }
+ Accounts.MoveCurrentToFirst();
}
}
- #endregion
-
#region Ctor
///
/// Initializes a new instance of the class.
///
[ImportingConstructor]
- public SearchDashBoardViewModel()
+ public SearchDashBoardViewModel(TransactionViewModel transactionDetails, TransferViewModel transferDetails)
+ : base(transactionDetails, transferDetails)
{
- DepositCategories = IoC.Get();
- DepositCategories.CategoryType = CategoryType.Deposit;
-
- repository.Entities.CollectionChanged += (sender, args) => NotifyOfPropertyChange(() => Name);
+ TransactionRecords.CollectionChanged += (sender, args) => NotifyOfPropertyChange(() => Name);
+ InitSourceAccounts();
}
#endregion
@@ -66,22 +71,56 @@ public SearchDashBoardViewModel()
public string Name
{
- get { return "Search (" + repository.Entities.Count + ")"; }
+ get
+ {
+ return TransactionRecords.Count > 0
+ ? "Search (" + TransactionRecords.Count + ")"
+ : "Search";
+ }
}
public void Show()
{
+ if (!Accounts.IsEmpty && Accounts.CurrentItem == null)
+ {
+ Accounts.MoveCurrentToFirst();
+ }
+
//TODO: make this method common for all IModels
- if (Parent is IHaveActiveItem && ((IHaveActiveItem)Parent).ActiveItem == this)
+ if (Parent is IHaveActiveItem && ((IHaveActiveItem) Parent).ActiveItem == this)
{
DisplayName = Name;
}
else
{
- ((IConductor)Parent).ActivateItem(this);
+ ((IConductor) Parent).ActivateItem(this);
}
}
-
+
+ #endregion
+
+ #region Implementation of IHandle
+
+ ///
+ /// Handles the message.
+ ///
+ /// The message.
+ public void Handle(LoggedOutMessage message)
+ {
+ Init();
+ }
+
+ #endregion
+
+ #region Overrides of PostingViewModelBase
+
+ protected override IEnumerable PreAction()
+ {
+ // Initialize account for search postings
+ AccountId = ((AccountDTO)Accounts.CurrentItem).Id;
+ yield break;
+ }
+
#endregion
}
}
\ No newline at end of file
diff --git a/src/Fab.Management/Fab.Management.csproj b/src/Fab.Management/Fab.Management.csproj
index 4eb4482..df0b4b2 100644
--- a/src/Fab.Management/Fab.Management.csproj
+++ b/src/Fab.Management/Fab.Management.csproj
@@ -90,6 +90,9 @@
Framework\Filters\IFilter.cs
+
+ Framework\Results\SingleResult.cs
+
Shell\Messages\ApplicationErrorMessage.cs
@@ -98,7 +101,6 @@
-
diff --git a/src/Fab.Management/Shell/ShellViewModel.cs b/src/Fab.Management/Shell/ShellViewModel.cs
index 746d5b2..3eca458 100644
--- a/src/Fab.Management/Shell/ShellViewModel.cs
+++ b/src/Fab.Management/Shell/ShellViewModel.cs
@@ -12,10 +12,10 @@
using System.Web.Security;
using Caliburn.Micro;
using Fab.Client.Framework.Filters;
+using Fab.Client.Framework.Results;
using Fab.Client.Shell;
using Fab.Managment.AdminServiceReference;
using Fab.Managment.Framework;
-using Fab.Managment.Framework.Results;
using Fab.Managment.Shell.Messages;
using Fab.Managment.Shell.Results;
@@ -70,36 +70,24 @@ public string Password
#region Paging
private int currentPageIndex;
- private int pageSize;
- private int pagesCount;
- private int totalUsers;
- public int TotalUsers
+ public int CurrentPageIndex
{
- get { return totalUsers; }
+ get { return currentPageIndex; }
set
{
- totalUsers = value;
- NotifyOfPropertyChange(() => TotalUsers);
+ currentPageIndex = value;
+ NotifyOfPropertyChange(() => CurrentPageIndex);
+ NotifyOfPropertyChange(() => CanNextPage);
+ NotifyOfPropertyChange(() => CanPrevPage);
}
}
- private long totalUsedSpace;
-
- public long TotalUsedSpace
- {
- get { return totalUsedSpace; }
- set
- {
- totalUsedSpace = value;
- NotifyOfPropertyChange(() => TotalUsedSpace);
- }
- }
+ private int pageSize;
public int PageSize
{
get { return pageSize; }
-
set
{
pageSize = value;
@@ -107,10 +95,11 @@ public int PageSize
}
}
+ private int pagesCount;
+
public int PagesCount
{
get { return pagesCount; }
-
set
{
pagesCount = value;
@@ -118,16 +107,27 @@ public int PagesCount
}
}
- public int CurrentPageIndex
+ private long totalUsedSpace;
+
+ public long TotalUsedSpace
{
- get { return currentPageIndex; }
+ get { return totalUsedSpace; }
+ set
+ {
+ totalUsedSpace = value;
+ NotifyOfPropertyChange(() => TotalUsedSpace);
+ }
+ }
+
+ private int totalUsers;
+ public int TotalUsers
+ {
+ get { return totalUsers; }
set
{
- currentPageIndex = value;
- NotifyOfPropertyChange(() => CurrentPageIndex);
- NotifyOfPropertyChange(() => CanNextPage);
- NotifyOfPropertyChange(() => CanPrevPage);
+ totalUsers = value;
+ NotifyOfPropertyChange(() => TotalUsers);
}
}
diff --git a/src/Fab.Management/Shell/UserViewModel.cs b/src/Fab.Management/Shell/UserViewModel.cs
index bc98e07..aa0f949 100644
--- a/src/Fab.Management/Shell/UserViewModel.cs
+++ b/src/Fab.Management/Shell/UserViewModel.cs
@@ -7,6 +7,7 @@
using System;
using System.Collections.Generic;
using Caliburn.Micro;
+using Fab.Client.Framework.Results;
using Fab.Core.Framework;
using Fab.Managment.AdminServiceReference;
using Fab.Managment.Framework.Results;
diff --git a/src/Fab.Server/Core/Services/MoneyService.cs b/src/Fab.Server/Core/Services/MoneyService.cs
index 3841d77..2352b01 100644
--- a/src/Fab.Server/Core/Services/MoneyService.cs
+++ b/src/Fab.Server/Core/Services/MoneyService.cs
@@ -473,7 +473,7 @@ public int GetJournalsCount(Guid userId, int accountId, IQueryFilter queryFilter
throw new ArgumentNullException("queryFilter");
}
- var count = 0;
+ int count;
// Bug: warning security weakness!
// Check User.IsDisabled + Account.IsDeleted also
@@ -499,7 +499,6 @@ public int GetJournalsCount(Guid userId, int accountId, IQueryFilter queryFilter
{
query = from t in query
where t.Journal.Comment.Contains(textSearchFilter.Contains)
- || t.Category.Name.Contains(textSearchFilter.Contains)
select t;
}
}
@@ -595,7 +594,6 @@ public IList GetJournals(Guid userId, int accountId, IQueryFilter qu
{
query = from t in query
where t.Journal.Comment.Contains(textSearchFilter.Contains)
- || t.Category.Name.Contains(textSearchFilter.Contains)
select t;
}
}