PageRenderTime 27ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/Release/1/Dev/BillsPresentation/PaymentReminderPresenter.cs

#
C# | 361 lines | 232 code | 35 blank | 94 comment | 36 complexity | fb5eb4beb40a345c5156d696135b47cd 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. this.LoadViewOnModel();
  146. }
  147. /// <summary>
  148. /// Populates the graph.
  149. /// </summary>
  150. private void PopulateGraph()
  151. {
  152. this.GenerateDayRangeOfPayments(this.view.AsOfDay, 90, this.allDaysInARangeForGraph);
  153. this.view.DaysAndBalances = this.allDaysInARangeForGraph;
  154. }
  155. /// <summary>
  156. /// Generates the upcoming payments.
  157. /// </summary>
  158. private void GenerateUpcomingPayments()
  159. {
  160. this.upcomingPayments.Clear();
  161. foreach (ScheduledPayment scheduledPayment in this.Controller.BetterScheduledPayments)
  162. {
  163. if (scheduledPayment.PaymentRecurrence == Recurrence.None && scheduledPayment.FirstDate < this.view.AsOfDay)
  164. {
  165. continue;
  166. }
  167. this.upcomingPayments.Add(new PaymentWithDate()
  168. {
  169. Amount = scheduledPayment.Amount * (scheduledPayment.IsDebit ? -1 : 1),
  170. IsDebit = String.CompareOrdinal(scheduledPayment.PaymentType.Name, PaymentType.Debit.Name) == 0,
  171. Payee = scheduledPayment.Payee,
  172. ScheduledPaymentId = scheduledPayment.Id,
  173. PaymentDate = CalculateNextPaymentDate(this.view.AsOfDay, scheduledPayment),
  174. IncludeInProjection = scheduledPayment.IncludeInProjection
  175. });
  176. }
  177. this.upcomingPayments.Sort();
  178. this.UpdateUpcomingPaymentsBalances();
  179. }
  180. /// <summary>
  181. /// Updates the upcoming payments balances.
  182. /// </summary>
  183. private void UpdateUpcomingPaymentsBalances()
  184. {
  185. decimal currentBalance = this.view.CurrentBalance ?? 0;
  186. int i = 0;
  187. foreach (PaymentWithDate paymentOnDate in this.upcomingPayments)
  188. {
  189. if (paymentOnDate.IncludeInProjection)
  190. {
  191. currentBalance = currentBalance + paymentOnDate.Amount;
  192. }
  193. paymentOnDate.Balance = currentBalance;
  194. this.upcomingPayments.ResetItem(i);
  195. i++;
  196. }
  197. }
  198. /// <summary>
  199. /// Generates the day range of payments.
  200. /// </summary>
  201. /// <param name="startDate">The start date.</param>
  202. /// <param name="numberOfDaysToProject">The number of days to project.</param>
  203. /// <param name="output">The output.</param>
  204. private void GenerateDayRangeOfPayments(DateTime startDate, int numberOfDaysToProject, BindingList<CalendarDay> output)
  205. {
  206. output.Clear();
  207. decimal currentBalance = this.view.CurrentBalance ?? 0;
  208. for (int i = 0; i < numberOfDaysToProject; i++)
  209. {
  210. DateTime currentDate = startDate.AddDays(i).Date;
  211. CalendarDay currentCalendarDay = new CalendarDay() { Date = currentDate };
  212. output.Add(currentCalendarDay);
  213. currentCalendarDay.EndOfDayBalance = currentBalance;
  214. foreach (ScheduledPayment scheduledPayment in this.Controller.BetterScheduledPayments)
  215. {
  216. if (scheduledPayment.PaymentRecurrence == Recurrence.None && scheduledPayment.FirstDate != currentDate)
  217. {
  218. continue;
  219. }
  220. if (CalculateNextPaymentDate(currentDate, scheduledPayment) == currentDate)
  221. {
  222. currentCalendarDay.Payments.Add(new Payment()
  223. {
  224. Amount = scheduledPayment.Amount * (scheduledPayment.IsDebit ? -1 : 1),
  225. IsDebit = String.CompareOrdinal(scheduledPayment.PaymentType.Name, PaymentType.Debit.Name) == 0,
  226. Payee = scheduledPayment.Payee,
  227. ScheduledPaymentId = scheduledPayment.Id,
  228. IncludeInProjection = scheduledPayment.IncludeInProjection
  229. });
  230. if (scheduledPayment.IncludeInProjection)
  231. {
  232. if (scheduledPayment.IsDebit)
  233. {
  234. currentCalendarDay.EndOfDayBalance = currentCalendarDay.EndOfDayBalance - scheduledPayment.Amount;
  235. }
  236. else
  237. {
  238. currentCalendarDay.EndOfDayBalance = currentCalendarDay.EndOfDayBalance + scheduledPayment.Amount;
  239. }
  240. }
  241. }
  242. }
  243. currentCalendarDay.Payments.Sort();
  244. currentBalance = currentCalendarDay.EndOfDayBalance;
  245. }
  246. }
  247. /// <summary>
  248. /// Populates the calendar.
  249. /// </summary>
  250. private void PopulateCalendar()
  251. {
  252. this.GenerateDayRangeOfPayments(this.view.DayOnCalendar.AddMonths(-2), 180, this.allDaysInARangeForCalendar);
  253. BindingList<CalendarDay> datesWithPayments = new BindingList<CalendarDay>();
  254. foreach (CalendarDay item in allDaysInARangeForCalendar)
  255. {
  256. if (item.Payments.Count > 0)
  257. {
  258. datesWithPayments.Add(item);
  259. }
  260. }
  261. this.view.DatesWithPayments = datesWithPayments;
  262. }
  263. /// <summary>
  264. /// Loads the view on model.
  265. /// </summary>
  266. private void LoadViewOnModel()
  267. {
  268. this.Controller.LoadData();
  269. this.GenerateUpcomingPayments();
  270. this.PopulateGraph();
  271. this.PopulateCalendar();
  272. this.view.UpcomingPayments = this.upcomingPayments;
  273. this.OnSpecificDateSelected(this, new DateSelectedEventArgs() { SelectedDate = this.view.DayOnCalendar });
  274. }
  275. /// <summary>
  276. /// Handles the Load event of the view control.
  277. /// </summary>
  278. /// <param name="sender">The source of the event.</param>
  279. /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
  280. private void view_Load(object sender, EventArgs e)
  281. {
  282. this.view.AsOfDay = DateTime.Today;
  283. LoadViewOnModel();
  284. }
  285. /// <summary>
  286. /// Calculates the next payment date.
  287. /// </summary>
  288. /// <param name="asOfDate">As of date.</param>
  289. /// <param name="scheduledPayment">The scheduled payment.</param>
  290. /// <returns></returns>
  291. private static DateTime CalculateNextPaymentDate(DateTime asOfDate, ScheduledPayment scheduledPayment)
  292. {
  293. DateTime result = scheduledPayment.FirstDate;
  294. DateTime asOfDateAtMidnight = new DateTime(asOfDate.Year, asOfDate.Month, asOfDate.Day);
  295. if (scheduledPayment.PaymentRecurrence == Recurrence.Biweekly)
  296. {
  297. while (result < asOfDateAtMidnight)
  298. {
  299. result = result.AddDays(14);
  300. }
  301. }
  302. else if (scheduledPayment.PaymentRecurrence == Recurrence.Bimonthly)
  303. {
  304. while (result < asOfDateAtMidnight)
  305. {
  306. result = result.AddMonths(2);
  307. }
  308. }
  309. else if (scheduledPayment.PaymentRecurrence == Recurrence.Monthly)
  310. {
  311. while (result < asOfDateAtMidnight)
  312. {
  313. result = result.AddMonths(1);
  314. }
  315. }
  316. else if (scheduledPayment.PaymentRecurrence == Recurrence.Weekly)
  317. {
  318. while (result < asOfDateAtMidnight)
  319. {
  320. result = result.AddDays(7);
  321. }
  322. }
  323. return result;
  324. }
  325. }
  326. }