PageRenderTime 79ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/Release/1.0.1/BillsPresentation/PaymentReminderPresenter.cs

#
C# | 366 lines | 236 code | 36 blank | 94 comment | 37 complexity | 02a033f603e4920dca332bd64fa23235 MD5 | raw file
  1. using System;
  2. using BillsDomain;
  3. using System.ComponentModel;
  4. using System.Globalization;
  5. namespace BillsPresentation
  6. {
  7. /// <summary>
  8. /// Business logic for the payment reminder view
  9. /// </summary>
  10. public class PaymentReminderPresenter
  11. {
  12. /// <summary>
  13. /// Gets or sets the controller.
  14. /// </summary>
  15. /// <value>The controller.</value>
  16. public IScheduledPaymentController Controller { get; set; }
  17. /// <summary>
  18. /// The view
  19. /// </summary>
  20. private IPaymentReminderView view;
  21. /// <summary>
  22. /// The list of all days and their balances for the graph on the view
  23. /// </summary>
  24. private BindingList<CalendarDay> allDaysInARangeForGraph = new BindingList<CalendarDay>();
  25. /// <summary>
  26. /// The list of days with payments for the monthly calendar on the view
  27. /// </summary>
  28. private BindingList<CalendarDay> allDaysInARangeForCalendar = new BindingList<CalendarDay>();
  29. /// <summary>
  30. /// The list of upcoming payments
  31. /// </summary>
  32. private UpcomingPaymentsCollection upcomingPayments = new UpcomingPaymentsCollection();
  33. /// <summary>
  34. /// Initializes a new instance of the PaymentReminderPresenter class.
  35. /// </summary>
  36. /// <param name="view">The view.</param>
  37. /// <param name="controller">The controller.</param>
  38. public PaymentReminderPresenter(IPaymentReminderView view, IScheduledPaymentController controller)
  39. {
  40. this.view = view;
  41. this.Controller = controller;
  42. this.SubscribeViewToEvents();
  43. }
  44. /// <summary>
  45. /// Subscribes the view to events.
  46. /// </summary>
  47. public void SubscribeViewToEvents()
  48. {
  49. this.view.Load += view_Load;
  50. this.view.AsOfDateChanged += this.OnAsOfDateChanged;
  51. this.view.AsOfDateChanged += this.OnProjectedBalanceItemsChanged;
  52. this.view.FormClose += this.OnFormClosing;
  53. this.view.ScheduledPaymentChanged += this.OnScheduledPaymentChanged;
  54. this.Controller.ListChanged += this.OnControllerListChanged;
  55. this.view.DeleteClicked += this.OnDeleteClicked;
  56. this.view.ProjectedBalanceItemsChanged += this.OnProjectedBalanceItemsChanged;
  57. this.view.SpecificDateSelected += OnSpecificDateSelected;
  58. }
  59. /// <summary>
  60. /// Called when a specific date is selected.
  61. /// </summary>
  62. /// <param name="sender">The sender.</param>
  63. /// <param name="e">The <see cref="BillsPresentation.DateSelectedEventArgs"/> instance containing the event data.</param>
  64. private void OnSpecificDateSelected(object sender, DateSelectedEventArgs e)
  65. {
  66. this.PopulateCalendar();
  67. int i = 0;
  68. CalendarDay currentCalendarDay = this.allDaysInARangeForCalendar[i];
  69. while (e.SelectedDate.Date != currentCalendarDay.Date.Date && i < this.allDaysInARangeForCalendar.Count)
  70. {
  71. i++;
  72. currentCalendarDay = this.allDaysInARangeForCalendar[i] as CalendarDay;
  73. }
  74. this.view.PaymentsForADay = currentCalendarDay.Payments;
  75. }
  76. /// <summary>
  77. /// Called when projected balance items changed.
  78. /// </summary>
  79. /// <param name="sender">The sender.</param>
  80. /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
  81. private void OnProjectedBalanceItemsChanged(object sender, EventArgs e)
  82. {
  83. DateTime projectDateAsOfMidnight = new DateTime(this.view.DateForProjection.Year, this.view.DateForProjection.Month, this.view.DateForProjection.Day);
  84. this.view.ProjectedBalance = String.Empty;
  85. this.PopulateGraph();
  86. if (projectDateAsOfMidnight >= this.allDaysInARangeForGraph[0].Date && projectDateAsOfMidnight <= this.allDaysInARangeForGraph[this.allDaysInARangeForGraph.Count - 1].Date)
  87. {
  88. TimeSpan span = projectDateAsOfMidnight - this.allDaysInARangeForGraph[0].Date;
  89. int index = span.Days;
  90. this.view.ProjectedBalance = this.allDaysInARangeForGraph[index].EndOfDayBalance.ToString(CultureInfo.CurrentCulture);
  91. }
  92. else
  93. {
  94. TimeSpan span = projectDateAsOfMidnight - this.view.AsOfDay.Date;
  95. BindingList<CalendarDay> fromAsOfDayUntilProjectionDate = new BindingList<CalendarDay>();
  96. this.GenerateDayRangeOfPayments(this.view.AsOfDay.Date, span.Days + 1, fromAsOfDayUntilProjectionDate);
  97. this.view.ProjectedBalance = fromAsOfDayUntilProjectionDate[span.Days].EndOfDayBalance.ToString(CultureInfo.CurrentCulture);
  98. }
  99. this.UpdateUpcomingPaymentsBalances();
  100. this.view.UpcomingPayments = this.upcomingPayments;
  101. }
  102. /// <summary>
  103. /// Handles the DeleteClicked event of the view control.
  104. /// </summary>
  105. /// <param name="sender">The source of the event.</param>
  106. /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
  107. private void OnDeleteClicked(object sender, EventArgs e)
  108. {
  109. this.Controller.DeleteCurrentPayment();
  110. }
  111. /// <summary>
  112. /// Handles the ListChanged event of the controller control.
  113. /// </summary>
  114. /// <param name="sender">The source of the event.</param>
  115. /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
  116. private void OnControllerListChanged(object sender, EventArgs e)
  117. {
  118. this.LoadViewOnModel();
  119. }
  120. /// <summary>
  121. /// Called when a scheduled payment is changed or added.
  122. /// </summary>
  123. /// <param name="sender">The sender.</param>
  124. /// <param name="e">The <see cref="BillsPresentation.ScheduledPaymentChangedEventArgs"/> instance containing the event data.</param>
  125. private void OnScheduledPaymentChanged(object sender, ScheduledPaymentChangedEventArgs e)
  126. {
  127. this.Controller.SetScheduledPayment(e.SelectedPayment.ScheduledPaymentId);
  128. }
  129. /// <summary>
  130. /// Handles the FormClosing event of the view control.
  131. /// </summary>
  132. /// <param name="sender">The source of the event.</param>
  133. /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
  134. private void OnFormClosing(object sender, EventArgs e)
  135. {
  136. this.Controller.SaveData();
  137. }
  138. /// <summary>
  139. /// Called when the as of date is changed.
  140. /// </summary>
  141. /// <param name="sender">The sender.</param>
  142. /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
  143. private void OnAsOfDateChanged(object sender, EventArgs e)
  144. {
  145. if (this.view.DateForProjection < this.view.AsOfDay)
  146. {
  147. this.view.DateForProjection = this.view.AsOfDay;
  148. }
  149. this.LoadViewOnModel();
  150. }
  151. /// <summary>
  152. /// Populates the graph.
  153. /// </summary>
  154. private void PopulateGraph()
  155. {
  156. this.GenerateDayRangeOfPayments(this.view.AsOfDay, 90, this.allDaysInARangeForGraph);
  157. this.view.DaysAndBalances = this.allDaysInARangeForGraph;
  158. }
  159. /// <summary>
  160. /// Generates the upcoming payments.
  161. /// </summary>
  162. private void GenerateUpcomingPayments()
  163. {
  164. this.upcomingPayments.Clear();
  165. foreach (ScheduledPayment scheduledPayment in this.Controller.ScheduledPayments)
  166. {
  167. if (scheduledPayment.PaymentRecurrence == Recurrence.None && scheduledPayment.FirstDate < this.view.AsOfDay)
  168. {
  169. continue;
  170. }
  171. this.upcomingPayments.Add(new PaymentWithDate()
  172. {
  173. Amount = scheduledPayment.Amount * (scheduledPayment.IsDebit ? -1 : 1),
  174. IsDebit = String.CompareOrdinal(scheduledPayment.PaymentType.Name, PaymentType.Debit.Name) == 0,
  175. Payee = scheduledPayment.Payee,
  176. ScheduledPaymentId = scheduledPayment.Id,
  177. PaymentDate = CalculateNextPaymentDate(this.view.AsOfDay, scheduledPayment),
  178. IncludeInProjection = scheduledPayment.IncludeInProjection
  179. });
  180. }
  181. this.upcomingPayments.Sort();
  182. this.UpdateUpcomingPaymentsBalances();
  183. }
  184. /// <summary>
  185. /// Updates the upcoming payments balances.
  186. /// </summary>
  187. private void UpdateUpcomingPaymentsBalances()
  188. {
  189. decimal currentBalance = this.view.CurrentBalance ?? 0;
  190. int i = 0;
  191. foreach (PaymentWithDate paymentOnDate in this.upcomingPayments)
  192. {
  193. if (paymentOnDate.IncludeInProjection)
  194. {
  195. currentBalance = currentBalance + paymentOnDate.Amount;
  196. }
  197. paymentOnDate.Balance = currentBalance;
  198. this.upcomingPayments.ResetItem(i);
  199. i++;
  200. }
  201. }
  202. /// <summary>
  203. /// Generates the day range of payments.
  204. /// </summary>
  205. /// <param name="startDate">The start date.</param>
  206. /// <param name="numberOfDaysToProject">The number of days to project.</param>
  207. /// <param name="output">The output.</param>
  208. private void GenerateDayRangeOfPayments(DateTime startDate, int numberOfDaysToProject, BindingList<CalendarDay> output)
  209. {
  210. output.Clear();
  211. decimal currentBalance = this.view.CurrentBalance ?? 0;
  212. for (int i = 0; i < numberOfDaysToProject; i++)
  213. {
  214. DateTime currentDate = startDate.AddDays(i).Date;
  215. CalendarDay currentCalendarDay = new CalendarDay() { Date = currentDate };
  216. output.Add(currentCalendarDay);
  217. currentCalendarDay.EndOfDayBalance = currentBalance;
  218. foreach (ScheduledPayment scheduledPayment in this.Controller.ScheduledPayments)
  219. {
  220. if (scheduledPayment.PaymentRecurrence == Recurrence.None && scheduledPayment.FirstDate != currentDate)
  221. {
  222. continue;
  223. }
  224. if (CalculateNextPaymentDate(currentDate, scheduledPayment) == currentDate)
  225. {
  226. currentCalendarDay.Payments.Add(new Payment()
  227. {
  228. Amount = scheduledPayment.Amount * (scheduledPayment.IsDebit ? -1 : 1),
  229. IsDebit = String.CompareOrdinal(scheduledPayment.PaymentType.Name, PaymentType.Debit.Name) == 0,
  230. Payee = scheduledPayment.Payee,
  231. ScheduledPaymentId = scheduledPayment.Id,
  232. IncludeInProjection = scheduledPayment.IncludeInProjection
  233. });
  234. if (scheduledPayment.IncludeInProjection)
  235. {
  236. if (scheduledPayment.IsDebit)
  237. {
  238. currentCalendarDay.EndOfDayBalance = currentCalendarDay.EndOfDayBalance - scheduledPayment.Amount;
  239. }
  240. else
  241. {
  242. currentCalendarDay.EndOfDayBalance = currentCalendarDay.EndOfDayBalance + scheduledPayment.Amount;
  243. }
  244. }
  245. }
  246. }
  247. currentCalendarDay.Payments.Sort();
  248. currentBalance = currentCalendarDay.EndOfDayBalance;
  249. }
  250. }
  251. /// <summary>
  252. /// Populates the calendar.
  253. /// </summary>
  254. private void PopulateCalendar()
  255. {
  256. this.GenerateDayRangeOfPayments(this.view.DayOnCalendar.AddMonths(-2), 180, this.allDaysInARangeForCalendar);
  257. BindingList<CalendarDay> datesWithPayments = new BindingList<CalendarDay>();
  258. foreach (CalendarDay item in allDaysInARangeForCalendar)
  259. {
  260. if (item.Payments.Count > 0)
  261. {
  262. datesWithPayments.Add(item);
  263. }
  264. }
  265. this.view.DatesWithPayments = datesWithPayments;
  266. }
  267. /// <summary>
  268. /// Loads the view on model.
  269. /// </summary>
  270. private void LoadViewOnModel()
  271. {
  272. this.Controller.LoadData();
  273. this.GenerateUpcomingPayments();
  274. this.PopulateGraph();
  275. this.PopulateCalendar();
  276. this.view.UpcomingPayments = this.upcomingPayments;
  277. this.OnSpecificDateSelected(this, new DateSelectedEventArgs() { SelectedDate = this.view.DayOnCalendar });
  278. }
  279. /// <summary>
  280. /// Handles the Load event of the view control.
  281. /// </summary>
  282. /// <param name="sender">The source of the event.</param>
  283. /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
  284. private void view_Load(object sender, EventArgs e)
  285. {
  286. this.view.AsOfDay = DateTime.Today;
  287. LoadViewOnModel();
  288. }
  289. /// <summary>
  290. /// Calculates the next payment date.
  291. /// </summary>
  292. /// <param name="asOfDate">As of date.</param>
  293. /// <param name="scheduledPayment">The scheduled payment.</param>
  294. /// <returns></returns>
  295. private static DateTime CalculateNextPaymentDate(DateTime asOfDate, ScheduledPayment scheduledPayment)
  296. {
  297. DateTime result = scheduledPayment.FirstDate;
  298. DateTime asOfDateAtMidnight = new DateTime(asOfDate.Year, asOfDate.Month, asOfDate.Day);
  299. if (scheduledPayment.PaymentRecurrence == Recurrence.Biweekly)
  300. {
  301. while (result < asOfDateAtMidnight)
  302. {
  303. result = result.AddDays(14);
  304. }
  305. }
  306. else if (scheduledPayment.PaymentRecurrence == Recurrence.Bimonthly)
  307. {
  308. while (result < asOfDateAtMidnight)
  309. {
  310. result = result.AddMonths(2);
  311. }
  312. }
  313. else if (scheduledPayment.PaymentRecurrence == Recurrence.Monthly)
  314. {
  315. while (result < asOfDateAtMidnight)
  316. {
  317. result = result.AddMonths(1);
  318. }
  319. }
  320. else if (scheduledPayment.PaymentRecurrence == Recurrence.Weekly)
  321. {
  322. while (result < asOfDateAtMidnight)
  323. {
  324. result = result.AddDays(7);
  325. }
  326. }
  327. return result;
  328. }
  329. }
  330. }