Schedule Service

This page discusses scheduling in general, the rationale for creating a separate scheduling service, and a first cut at its organization.

Background

Scheduling and schedules

All accounts in Mifos have schedules:

  • Loans have repayment schedules.
  • Savings accounts have deposit schedules.
  • Customers have meeting schedules.

A customer with a loan and a savings account can have all three schedules, and they may or may not be the same. For example, a loan's repayment schedule can be independent of the customer's meeting schedule (the "teller" model).

Schedules are constructed under many constraints:

  • start date, which itself is determined by the type of account, when the account was created, etc.,
  • end date (not all accounts have end dates)
  • frequency (weekly, monthly, biweekly, etc)
  • meeting date (e.g. Tuesdays, 3rd Wednesday of the month)
  • relationships between schedules. Two examples: a loan repayment schedule may or may not be tied to the customer's meeting schedule; a loan fee schedule is linked to a customer's loan schedule but its constraints may differ from the loan's.
  • holidays and their rules for how to reschedule dates that fall in holidays. (Rules are encapsulated in the misnamed class RepaymentRule).
    MeetingBO

hnull. The class

The code that uses these constraints to create or modify schedules resides in class MeetingBO, in the several methods named getAllDates(). {{MeetingBO}}s are children of parent accounts. This class has many responsibilities:

  • managing the scheduling constraints for its parent account
  • generating schedules
  • implementing complex rules for determining dates based on constraints – see, for example, getNextDateForMonth(), getNextDateForMonth(), isMeetingMatched(), getNextDateForMonthWithRepaymentIndepOfMeetingEnabled(),
  • delegating some responsibility to HolidayBO and DateUtils.

Many of these responsibilities do not involve MeetingBO's parent at all, but just involve manipulating dates and calendars subject to the schedule's constraints.

Finally, the structure of MeetingBO seems overly complex. Here is its child tree:

MeetingBO   <-----------------
  |                           |
   --> MeetingDetailsEntity --
         |
          --> RecurrenceTypeEntity <----     
                (holds int value of enum| RecurrenceType)
         |                              |
          --> MeetingRecurrenceEntity --
                        (holds int value of enum WeekDay)
                |
                 --> WeekDaysEntity
                |
                 --> RankOfDaysEntity (seems poorly named)
                        (holds int value of enum RankType)

In addition, implementing Moratorium will add complexity to the logic.

A Scheduling Service

While implementing Moratorium we will create a scheduling service, responsible for all schedule processing. This will have three benefits:

  • By separating existing scheduling code from new code, it allows development of Moratorium code on the main development trunk while not altering existing scheduling code. It will be straightforward to cut over to the new code all at once.
  • It makes progress toward the goal of re-engineering Mifos into a more modular and understandable structure, reducing the cost of maintaining and enhancing Mifos.
  • It will facilitate the effort to remove stored schedules from the Mifos database – see RedesignAccountsSchedulesAndMeetings.
  • It will facilitate future refactoring, such as the proposal to replace many entity classes with their corresponding enum.
  • Many of MeetingBO's purely calendar-oriented responsibilities can be moved more appropriate classes such as DateUtils.

A starting point for the design of the service is a proposed service-architecture approach as described in LoanCreationRefactoring. That approach requires clients of a service to request services using DTOs to pass data, rather than naked objects. In this case, however, the scheduling service is strictly back-office, serving only other internal objects, most likely only accounts. Therefore this service's interface will permit exchange of domain objects.