* Sorting classes into packages in preparation for making more classes
* Fixed multi-charges for repayment by introducing new proportional to
  options and handling them correctly.
diff --git a/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/ChargeProportionalDesignator.java b/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/ChargeProportionalDesignator.java
index 31cd960..5862c6d 100644
--- a/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/ChargeProportionalDesignator.java
+++ b/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/ChargeProportionalDesignator.java
@@ -26,8 +26,10 @@
   MAXIMUM_BALANCE_DESIGNATOR("{maximumbalance}", 1),
   RUNNING_BALANCE_DESIGNATOR("{runningbalance}", 2),
   REQUESTED_DISBURSEMENT_DESIGNATOR("{requesteddisbursement}", 3),
-  REQUESTED_REPAYMENT_DESIGNATOR("{requestedrepayment}", 4),
-  CONTRACTUAL_REPAYMENT_DESIGNATOR("{contractualrepayment}", 5),
+  TO_ACCOUNT_DESIGNATOR("{toAccount}", 4),
+  FROM_ACCOUNT_DESIGNATOR("{fromAccount}", 5),
+  REQUESTED_REPAYMENT_DESIGNATOR("{requestedrepayment}", 6),
+  CONTRACTUAL_REPAYMENT_DESIGNATOR("{contractualrepayment}", 7),
   ;
 
   private final String value;
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java b/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
index 46421e9..6bf90ff 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
@@ -74,6 +74,7 @@
 
   private BigDecimal expectedCurrentBalance = null;
   private BigDecimal interestAccrued = BigDecimal.ZERO.setScale(MINOR_CURRENCY_UNIT_DIGITS, RoundingMode.HALF_EVEN);
+  private BigDecimal nonLateFees = BigDecimal.ZERO.setScale(MINOR_CURRENCY_UNIT_DIGITS, RoundingMode.HALF_EVEN);
 
 
   @Before
@@ -410,7 +411,8 @@
         customerCase.getIdentifier(),
         Action.DISBURSE,
         Sets.newLinkedHashSet(AccountDesignators.ENTRY, AccountDesignators.CUSTOMER_LOAN_GROUP),
-        amount, new CostComponent(whichDisbursementFee, disbursementFeeAmount),
+        amount,
+        new CostComponent(whichDisbursementFee, disbursementFeeAmount),
         new CostComponent(ChargeIdentifiers.LOAN_ORIGINATION_FEE_ID, LOAN_ORIGINATION_FEE_AMOUNT),
         new CostComponent(ChargeIdentifiers.PROCESSING_FEE_ID, PROCESSING_FEE_AMOUNT),
         new CostComponent(ChargeIdentifiers.DISBURSE_PAYMENT_ID, amount));
@@ -441,6 +443,7 @@
     AccountingFixture.verifyTransfer(ledgerManager, debtors, creditors, product.getIdentifier(), customerCase.getIdentifier(), Action.DISBURSE);
 
     expectedCurrentBalance = expectedCurrentBalance.add(amount);
+    nonLateFees = nonLateFees.add(disbursementFeeAmount);
   }
 
   private void step6CalculateInterestAndCheckForLatenessForWeek(
@@ -555,7 +558,13 @@
       final BigDecimal lateFee) throws InterruptedException {
     logger.info("step7PaybackPartialAmount '{}'", amount);
 
-    AccountingFixture.mockBalance(customerLoanPrincipalIdentifier, expectedCurrentBalance);
+    final BigDecimal principal = amount.subtract(interestAccrued).subtract(lateFee).subtract(nonLateFees);
+    final BigDecimal allFees = lateFee.add(nonLateFees);
+    AccountingFixture.mockBalance(customerLoanPrincipalIdentifier, principal);
+    AccountingFixture.mockBalance(customerLoanFeeIdentifier, allFees);
+    AccountingFixture.mockBalance(customerLoanInterestIdentifier, interestAccrued);
+    AccountingFixture.mockBalance(AccountingFixture.LOAN_INTEREST_ACCRUAL_ACCOUNT_IDENTIFIER, interestAccrued);
+    AccountingFixture.mockBalance(AccountingFixture.LATE_FEE_ACCRUAL_ACCOUNT_IDENTIFIER, lateFee);
 
     checkCostComponentForActionCorrect(
         product.getIdentifier(),
@@ -563,7 +572,9 @@
         Action.ACCEPT_PAYMENT,
         new HashSet<>(Arrays.asList(AccountDesignators.ENTRY, AccountDesignators.CUSTOMER_LOAN_GROUP, AccountDesignators.LOAN_FUNDS_SOURCE)),
         amount,
-        new CostComponent(ChargeIdentifiers.REPAY_PRINCIPAL_ID, amount),
+        new CostComponent(ChargeIdentifiers.REPAY_PRINCIPAL_ID, principal),
+        new CostComponent(ChargeIdentifiers.REPAY_INTEREST_ID, interestAccrued),
+        new CostComponent(ChargeIdentifiers.REPAY_FEES_ID, allFees),
         new CostComponent(ChargeIdentifiers.INTEREST_ID, interestAccrued),
         new CostComponent(ChargeIdentifiers.LATE_FEE_ID, lateFee));
     checkStateTransfer(
@@ -580,23 +591,36 @@
         Action.APPLY_INTEREST, Action.MARK_LATE, Action.ACCEPT_PAYMENT, Action.DISBURSE, Action.WRITE_OFF, Action.CLOSE);
 
     final Set<Debtor> debtors = new HashSet<>();
-    debtors.add(new Debtor(AccountingFixture.TELLER_ONE_ACCOUNT_IDENTIFIER, amount.toPlainString()));
-    if (interestAccrued.compareTo(BigDecimal.ZERO) != 0)
+    debtors.add(new Debtor(AccountingFixture.TELLER_ONE_ACCOUNT_IDENTIFIER, principal.toPlainString()));
+    if (interestAccrued.compareTo(BigDecimal.ZERO) != 0) {
+      debtors.add(new Debtor(AccountingFixture.TELLER_ONE_ACCOUNT_IDENTIFIER, interestAccrued.toPlainString()));
       debtors.add(new Debtor(AccountingFixture.LOAN_INTEREST_ACCRUAL_ACCOUNT_IDENTIFIER, interestAccrued.toPlainString()));
-    if (lateFee.compareTo(BigDecimal.ZERO) != 0)
+    }
+    if (allFees.compareTo(BigDecimal.ZERO) != 0) {
+      debtors.add(new Debtor(AccountingFixture.TELLER_ONE_ACCOUNT_IDENTIFIER, allFees.toPlainString()));
+    }
+    if (lateFee.compareTo(BigDecimal.ZERO) != 0) {
       debtors.add(new Debtor(AccountingFixture.LATE_FEE_ACCRUAL_ACCOUNT_IDENTIFIER, lateFee.toPlainString()));
+    }
 
     final Set<Creditor> creditors = new HashSet<>();
-    creditors.add(new Creditor(customerLoanPrincipalIdentifier, amount.toPlainString()));
-    if (interestAccrued.compareTo(BigDecimal.ZERO) != 0)
+    creditors.add(new Creditor(customerLoanPrincipalIdentifier, principal.toPlainString()));
+    if (interestAccrued.compareTo(BigDecimal.ZERO) != 0) {
+      creditors.add(new Creditor(customerLoanInterestIdentifier, interestAccrued.toPlainString()));
       creditors.add(new Creditor(AccountingFixture.CONSUMER_LOAN_INTEREST_ACCOUNT_IDENTIFIER, interestAccrued.toPlainString()));
-    if (lateFee.compareTo(BigDecimal.ZERO) != 0)
+    }
+    if (allFees.compareTo(BigDecimal.ZERO) != 0) {
+      creditors.add(new Creditor(customerLoanFeeIdentifier, allFees.toPlainString()));
+    }
+    if (lateFee.compareTo(BigDecimal.ZERO) != 0) {
       creditors.add(new Creditor(AccountingFixture.LATE_FEE_INCOME_ACCOUNT_IDENTIFIER, lateFee.toPlainString()));
+    }
 
     AccountingFixture.verifyTransfer(ledgerManager, debtors, creditors, product.getIdentifier(), customerCase.getIdentifier(), Action.ACCEPT_PAYMENT);
 
     expectedCurrentBalance = expectedCurrentBalance.subtract(amount).add(lateFee);
     interestAccrued = BigDecimal.ZERO.setScale(MINOR_CURRENCY_UNIT_DIGITS, RoundingMode.HALF_EVEN);
+    nonLateFees = BigDecimal.ZERO.setScale(MINOR_CURRENCY_UNIT_DIGITS, RoundingMode.HALF_EVEN);
   }
 
   private void step8Close() throws InterruptedException {
diff --git a/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java b/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
index c18c710..a55bcea 100644
--- a/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
+++ b/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
@@ -28,10 +28,10 @@
 import io.mifos.individuallending.internal.repository.CaseParametersEntity;
 import io.mifos.individuallending.internal.repository.CaseParametersRepository;
 import io.mifos.individuallending.internal.repository.CreditWorthinessFactorType;
-import io.mifos.individuallending.internal.service.CostComponentService;
+import io.mifos.individuallending.internal.service.costcomponent.CostComponentService;
 import io.mifos.individuallending.internal.service.DataContextOfAction;
 import io.mifos.individuallending.internal.service.DataContextService;
-import io.mifos.individuallending.internal.service.PaymentBuilder;
+import io.mifos.individuallending.internal.service.costcomponent.PaymentBuilder;
 import io.mifos.portfolio.api.v1.domain.*;
 import io.mifos.portfolio.service.ServiceConstants;
 import io.mifos.products.spi.PatternFactory;
@@ -186,6 +186,30 @@
     interestCharge.setChargeMethod(ChargeDefinition.ChargeMethod.INTEREST);
     interestCharge.setReadOnly(true);
 
+    final ChargeDefinition customerFeeRepaymentCharge = new ChargeDefinition();
+    customerFeeRepaymentCharge.setChargeAction(Action.ACCEPT_PAYMENT.name());
+    customerFeeRepaymentCharge.setIdentifier(REPAY_FEES_ID);
+    customerFeeRepaymentCharge.setName(REPAY_FEES_NAME);
+    customerFeeRepaymentCharge.setDescription(REPAY_FEES_NAME);
+    customerFeeRepaymentCharge.setFromAccountDesignator(AccountDesignators.ENTRY);
+    customerFeeRepaymentCharge.setToAccountDesignator(AccountDesignators.CUSTOMER_LOAN_FEES);
+    customerFeeRepaymentCharge.setProportionalTo(ChargeProportionalDesignator.TO_ACCOUNT_DESIGNATOR.getValue());
+    customerFeeRepaymentCharge.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL);
+    customerFeeRepaymentCharge.setAmount(BigDecimal.valueOf(100));
+    customerFeeRepaymentCharge.setReadOnly(true);
+
+    final ChargeDefinition customerInterestRepaymentCharge = new ChargeDefinition();
+    customerInterestRepaymentCharge.setChargeAction(Action.ACCEPT_PAYMENT.name());
+    customerInterestRepaymentCharge.setIdentifier(REPAY_INTEREST_ID);
+    customerInterestRepaymentCharge.setName(REPAY_INTEREST_NAME);
+    customerInterestRepaymentCharge.setDescription(REPAY_INTEREST_NAME);
+    customerInterestRepaymentCharge.setFromAccountDesignator(AccountDesignators.ENTRY);
+    customerInterestRepaymentCharge.setToAccountDesignator(AccountDesignators.CUSTOMER_LOAN_INTEREST);
+    customerInterestRepaymentCharge.setProportionalTo(ChargeProportionalDesignator.TO_ACCOUNT_DESIGNATOR.getValue());
+    customerInterestRepaymentCharge.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL);
+    customerInterestRepaymentCharge.setAmount(BigDecimal.valueOf(100));
+    customerInterestRepaymentCharge.setReadOnly(true);
+
     final ChargeDefinition customerPrincipalRepaymentCharge = new ChargeDefinition();
     customerPrincipalRepaymentCharge.setChargeAction(Action.ACCEPT_PAYMENT.name());
     customerPrincipalRepaymentCharge.setIdentifier(REPAY_PRINCIPAL_ID);
@@ -198,30 +222,6 @@
     customerPrincipalRepaymentCharge.setAmount(BigDecimal.valueOf(100));
     customerPrincipalRepaymentCharge.setReadOnly(true);
 
-    final ChargeDefinition customerInterestRepaymentCharge = new ChargeDefinition();
-    customerInterestRepaymentCharge.setChargeAction(Action.ACCEPT_PAYMENT.name());
-    customerInterestRepaymentCharge.setIdentifier(REPAY_INTEREST_ID);
-    customerInterestRepaymentCharge.setName(REPAY_INTEREST_NAME);
-    customerInterestRepaymentCharge.setDescription(REPAY_INTEREST_NAME);
-    customerInterestRepaymentCharge.setFromAccountDesignator(AccountDesignators.ENTRY);
-    customerInterestRepaymentCharge.setToAccountDesignator(AccountDesignators.CUSTOMER_LOAN_INTEREST);
-    customerInterestRepaymentCharge.setProportionalTo(ChargeProportionalDesignator.REQUESTED_REPAYMENT_DESIGNATOR.getValue()); //TODO: ???
-    customerInterestRepaymentCharge.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL); //TODO: ???
-    customerInterestRepaymentCharge.setAmount(BigDecimal.valueOf(100)); //TODO: ???
-    customerInterestRepaymentCharge.setReadOnly(true);
-
-    final ChargeDefinition customerFeeRepaymentCharge = new ChargeDefinition();
-    customerFeeRepaymentCharge.setChargeAction(Action.ACCEPT_PAYMENT.name());
-    customerFeeRepaymentCharge.setIdentifier(REPAY_FEES_ID);
-    customerFeeRepaymentCharge.setName(REPAY_FEES_NAME);
-    customerFeeRepaymentCharge.setDescription(REPAY_FEES_NAME);
-    customerFeeRepaymentCharge.setFromAccountDesignator(AccountDesignators.ENTRY);
-    customerFeeRepaymentCharge.setToAccountDesignator(AccountDesignators.CUSTOMER_LOAN_INTEREST);
-    customerFeeRepaymentCharge.setProportionalTo(ChargeProportionalDesignator.REQUESTED_REPAYMENT_DESIGNATOR.getValue());  //TODO: ???
-    customerFeeRepaymentCharge.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL); //TODO: ???
-    customerFeeRepaymentCharge.setAmount(BigDecimal.valueOf(100)); //TODO: ???
-    customerFeeRepaymentCharge.setReadOnly(true);
-
     ret.add(disbursePayment);
     ret.add(writeOffAllowanceCharge);
     ret.add(interestCharge);
diff --git a/service/src/main/java/io/mifos/individuallending/internal/command/handler/BeatPublishCommandHandler.java b/service/src/main/java/io/mifos/individuallending/internal/command/handler/BeatPublishCommandHandler.java
index 91c427f..bdcdd3b 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/command/handler/BeatPublishCommandHandler.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/command/handler/BeatPublishCommandHandler.java
@@ -31,6 +31,9 @@
 import io.mifos.individuallending.internal.command.CheckLateCommand;
 import io.mifos.individuallending.internal.command.MarkLateCommand;
 import io.mifos.individuallending.internal.service.*;
+import io.mifos.individuallending.internal.service.DataContextOfAction;
+import io.mifos.individuallending.internal.service.schedule.Period;
+import io.mifos.individuallending.internal.service.schedule.ScheduledActionHelpers;
 import io.mifos.portfolio.api.v1.domain.Case;
 import io.mifos.portfolio.service.config.PortfolioProperties;
 import io.mifos.portfolio.service.internal.command.CreateBeatPublishCommand;
diff --git a/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java b/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java
index c42f31f..f3a3d9f 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java
@@ -30,6 +30,10 @@
 import io.mifos.individuallending.internal.command.*;
 import io.mifos.individuallending.internal.repository.CaseParametersRepository;
 import io.mifos.individuallending.internal.service.*;
+import io.mifos.individuallending.internal.service.costcomponent.CostComponentService;
+import io.mifos.individuallending.internal.service.DataContextOfAction;
+import io.mifos.individuallending.internal.service.costcomponent.PaymentBuilder;
+import io.mifos.individuallending.internal.service.schedule.ScheduledActionHelpers;
 import io.mifos.portfolio.api.v1.domain.AccountAssignment;
 import io.mifos.portfolio.api.v1.domain.Case;
 import io.mifos.portfolio.api.v1.domain.CostComponent;
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/AnnuityPayment.java b/service/src/main/java/io/mifos/individuallending/internal/service/AnnuityPayment.java
index 0350089..dc1dce2 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/AnnuityPayment.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/AnnuityPayment.java
@@ -28,7 +28,7 @@
 /**
  * @author Myrle Krantz
  */
-final class AnnuityPayment implements MonetaryOperator {
+public final class AnnuityPayment implements MonetaryOperator {
   private Rate rate;
   private int periods;
 
@@ -52,10 +52,10 @@
     return new AnnuityPayment(rate, periods);
   }
 
-  static MonetaryAmount calculate(
-          final @Nonnull MonetaryAmount amount,
-          final @Nonnull Rate rate,
-          final @Nonnegative int periods)
+  public static MonetaryAmount calculate(
+      final @Nonnull MonetaryAmount amount,
+      final @Nonnull Rate rate,
+      final @Nonnegative int periods)
   {
     Objects.requireNonNull(amount, "Amount required");
     Objects.requireNonNull(rate, "Rate required");
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/DataContextOfAction.java b/service/src/main/java/io/mifos/individuallending/internal/service/DataContextOfAction.java
index 3d0e968..6f6e066 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/DataContextOfAction.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/DataContextOfAction.java
@@ -68,7 +68,7 @@
     return oneTimeAccountAssignments;
   }
 
-  String getCompoundIdentifer() {
+  public String getCompoundIdentifer() {
     return product.getIdentifier() + "." + customerCase.getIdentifier();
   }
 
@@ -76,7 +76,7 @@
     return getCompoundIdentifer() + "." + action.name();
   }
 
-  BigDecimal getInterest() {
+  public BigDecimal getInterest() {
     return customerCase.getInterest();
   }
 }
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/IndividualLoanService.java b/service/src/main/java/io/mifos/individuallending/internal/service/IndividualLoanService.java
index 25cd63d..2bd5675 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/IndividualLoanService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/IndividualLoanService.java
@@ -20,6 +20,10 @@
 import io.mifos.individuallending.api.v1.domain.caseinstance.PlannedPayment;
 import io.mifos.individuallending.api.v1.domain.caseinstance.PlannedPaymentPage;
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
+import io.mifos.individuallending.internal.service.costcomponent.CostComponentService;
+import io.mifos.individuallending.internal.service.costcomponent.PaymentBuilder;
+import io.mifos.individuallending.internal.service.costcomponent.SimulatedRunningBalances;
+import io.mifos.individuallending.internal.service.schedule.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -51,7 +55,7 @@
 
     final List<ScheduledAction> scheduledActions = ScheduledActionHelpers.getHypotheticalScheduledActions(initialDisbursalDate, dataContextOfAction.getCaseParameters());
 
-    final Set<Action> actionsScheduled = scheduledActions.stream().map(x -> x.action).collect(Collectors.toSet());
+    final Set<Action> actionsScheduled = scheduledActions.stream().map(ScheduledAction::getAction).collect(Collectors.toSet());
 
     final List<ScheduledCharge> scheduledCharges = scheduledChargesService.getScheduledCharges(dataContextOfAction.getProductEntity().getIdentifier(), scheduledActions);
 
@@ -175,9 +179,9 @@
 
   private static Period getPeriodFromScheduledCharge(final ScheduledCharge scheduledCharge) {
     final ScheduledAction scheduledAction = scheduledCharge.getScheduledAction();
-    if (ScheduledActionHelpers.actionHasNoActionPeriod(scheduledAction.action))
+    if (ScheduledActionHelpers.actionHasNoActionPeriod(scheduledAction.getAction()))
       return new Period(null, null);
     else
-      return scheduledAction.repaymentPeriod;
+      return scheduledAction.getRepaymentPeriod();
   }
 }
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/RateCollectors.java b/service/src/main/java/io/mifos/individuallending/internal/service/RateCollectors.java
index fd65ec3..6e4cf09 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/RateCollectors.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/RateCollectors.java
@@ -21,11 +21,11 @@
 /**
  * @author Myrle Krantz
  */
-final class RateCollectors {
+public final class RateCollectors {
 
   private RateCollectors() {}
 
-  static Collector<BigDecimal, ?, BigDecimal> compound(int significantDigits)
+  public static Collector<BigDecimal, ?, BigDecimal> compound(int significantDigits)
   {
     return Collector.of(
             () -> new Compound(significantDigits),
@@ -34,7 +34,7 @@
             Compound::finish);
   }
 
-  static Collector<BigDecimal, ?, BigDecimal> geometricMean(int significantDigits)
+  public static Collector<BigDecimal, ?, BigDecimal> geometricMean(int significantDigits)
   {
     return Collector.of(
             () -> new GeometricMean(significantDigits),
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/CostComponentService.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentService.java
similarity index 95%
rename from service/src/main/java/io/mifos/individuallending/internal/service/CostComponentService.java
rename to service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentService.java
index 69b7c33..8aa2afb 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/CostComponentService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentService.java
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.costcomponent;
 
 import io.mifos.core.lang.ServiceException;
 import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
 import io.mifos.individuallending.api.v1.domain.product.ChargeProportionalDesignator;
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
 import io.mifos.individuallending.internal.repository.CaseParametersEntity;
+import io.mifos.individuallending.internal.service.*;
+import io.mifos.individuallending.internal.service.schedule.*;
 import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
 import io.mifos.portfolio.api.v1.domain.CostComponent;
 import io.mifos.portfolio.service.internal.util.AccountingAdapter;
@@ -296,7 +298,7 @@
       loanPaymentSize = requestedLoanPaymentSize;
     }
     else {
-      if (scheduledAction.actionPeriod != null && scheduledAction.actionPeriod.isLastPeriod()) {
+      if (scheduledAction.getActionPeriod() != null && scheduledAction.getActionPeriod().isLastPeriod()) {
         loanPaymentSize = runningBalances.getBalance(AccountDesignators.CUSTOMER_LOAN_GROUP);
       }
       else {
@@ -421,7 +423,7 @@
     return null;
   }
 
-  static PaymentBuilder getCostComponentsForScheduledCharges(
+  public static PaymentBuilder getCostComponentsForScheduledCharges(
       final Map<ChargeDefinition, CostComponent> accruedCostComponents,
       final Collection<ScheduledCharge> scheduledCharges,
       final BigDecimal maximumBalance,
@@ -433,7 +435,6 @@
       final int minorCurrencyUnitDigits,
       final boolean accrualAccounting) {
     final PaymentBuilder paymentBuilder = new PaymentBuilder(preChargeBalances, accrualAccounting);
-    //TODO: once you've fixed getAmountProportionalTo, use the passed in variable.
 
     for (Map.Entry<ChargeDefinition, CostComponent> entry : accruedCostComponents.entrySet()) {
       final ChargeDefinition chargeDefinition = entry.getKey();
@@ -448,7 +449,7 @@
 
 
     for (final ScheduledCharge scheduledCharge : scheduledCharges) {
-      if (accrualAccounting || !isAccrualChargeForAction(scheduledCharge.getChargeDefinition(), scheduledCharge.getScheduledAction().action)) {
+      if (accrualAccounting || !isAccrualChargeForAction(scheduledCharge.getChargeDefinition(), scheduledCharge.getScheduledAction().getAction())) {
         final BigDecimal amountProportionalTo = getAmountProportionalTo(
             scheduledCharge,
             maximumBalance,
@@ -457,7 +458,6 @@
             requestedDisbursement,
             requestedRepayment,
             paymentBuilder);
-        //TODO: getAmountProportionalTo is programmed under the assumption of non-accrual accounting.
         if (scheduledCharge.getChargeRange().map(x ->
             !x.amountIsWithinRange(amountProportionalTo)).orElse(false))
           continue;
@@ -466,7 +466,7 @@
             .apply(amountProportionalTo)
             .setScale(minorCurrencyUnitDigits, BigDecimal.ROUND_HALF_EVEN);
         paymentBuilder.adjustBalances(
-            scheduledCharge.getScheduledAction().action,
+            scheduledCharge.getScheduledAction().getAction(),
             scheduledCharge.getChargeDefinition(),
             chargeAmount);
       }
@@ -487,6 +487,7 @@
         = ChargeProportionalDesignator.fromString(scheduledCharge.getChargeDefinition().getProportionalTo());
     return optionalChargeProportionalTo.map(chargeProportionalTo ->
         getAmountProportionalTo(
+            scheduledCharge,
             chargeProportionalTo,
             maximumBalance,
             runningBalances,
@@ -498,6 +499,7 @@
   }
 
   static BigDecimal getAmountProportionalTo(
+      final ScheduledCharge scheduledCharge,
       final ChargeProportionalDesignator chargeProportionalTo,
       final BigDecimal maximumBalance,
       final RunningBalances runningBalances,
@@ -519,7 +521,13 @@
       case REQUESTED_DISBURSEMENT_DESIGNATOR:
         return requestedDisbursement;
       case REQUESTED_REPAYMENT_DESIGNATOR:
-        return requestedRepayment;
+        return requestedRepayment.add(paymentBuilder.getBalanceAdjustment(AccountDesignators.ENTRY));
+      case TO_ACCOUNT_DESIGNATOR:
+        return runningBalances.getBalance(scheduledCharge.getChargeDefinition().getToAccountDesignator())
+            .subtract(paymentBuilder.getBalanceAdjustment(scheduledCharge.getChargeDefinition().getToAccountDesignator()));
+      case FROM_ACCOUNT_DESIGNATOR:
+        return runningBalances.getBalance(scheduledCharge.getChargeDefinition().getFromAccountDesignator())
+            .add(paymentBuilder.getBalanceAdjustment(scheduledCharge.getChargeDefinition().getFromAccountDesignator()));
       default:
         return BigDecimal.ZERO;
     }
@@ -565,7 +573,7 @@
         hypotheticalScheduledCharges);
   }
 
-  static BigDecimal getLoanPaymentSize(
+  public static BigDecimal getLoanPaymentSize(
       final BigDecimal maximumBalanceSize,
       final BigDecimal disbursementSize,
       final BigDecimal interest,
@@ -583,7 +591,7 @@
         .collect(RateCollectors.geometricMean(precision));
 
     final List<ScheduledCharge> disbursementFees = scheduledCharges.stream()
-        .filter(x -> x.getScheduledAction().action.equals(Action.DISBURSE))
+        .filter(x -> x.getScheduledAction().getAction().equals(Action.DISBURSE))
         .collect(Collectors.toList());
     final PaymentBuilder paymentBuilder = getCostComponentsForScheduledCharges(
         Collections.emptyMap(),
@@ -597,7 +605,9 @@
         minorCurrencyUnitDigits,
         false
         );
-    final BigDecimal finalDisbursementSize = paymentBuilder.getBalanceAdjustment(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL).negate();
+    final BigDecimal finalDisbursementSize = paymentBuilder.getBalanceAdjustment(
+        AccountDesignators.CUSTOMER_LOAN_PRINCIPAL,
+        AccountDesignators.CUSTOMER_LOAN_FEES).negate();
 
     final MonetaryAmount presentValue = AnnuityPayment.calculate(
         Money.of(finalDisbursementSize, "XXX"),
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/PaymentBuilder.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilder.java
similarity index 83%
rename from service/src/main/java/io/mifos/individuallending/internal/service/PaymentBuilder.java
rename to service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilder.java
index feaabb1..255c6cf 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/PaymentBuilder.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilder.java
@@ -13,12 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.costcomponent;
 
 import com.google.common.collect.Sets;
 import io.mifos.individuallending.IndividualLendingPatternFactory;
 import io.mifos.individuallending.api.v1.domain.caseinstance.PlannedPayment;
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
+import io.mifos.individuallending.internal.service.DesignatorToAccountIdentifierMapper;
 import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
 import io.mifos.portfolio.api.v1.domain.CostComponent;
 import io.mifos.portfolio.api.v1.domain.Payment;
@@ -82,7 +83,7 @@
     return new Payment(costComponentList, balanceAdjustments);
   }
 
-  PlannedPayment accumulatePlannedPayment(final SimulatedRunningBalances balances) {
+  public PlannedPayment accumulatePlannedPayment(final SimulatedRunningBalances balances) {
     final Payment payment = buildPayment();
     balanceAdjustments.forEach(balances::adjustBalance);
     final Map<String, BigDecimal> balancesCopy = balances.snapshot();
@@ -100,8 +101,10 @@
         .collect(Collectors.toList());
   }
 
-  BigDecimal getBalanceAdjustment(final String accountDesignator) {
-    return balanceAdjustments.getOrDefault(accountDesignator, BigDecimal.ZERO);
+  BigDecimal getBalanceAdjustment(final String... accountDesignators) {
+    return Arrays.stream(accountDesignators)
+        .map(accountDesignator -> balanceAdjustments.getOrDefault(accountDesignator, BigDecimal.ZERO))
+        .reduce(BigDecimal.ZERO, BigDecimal::add);
   }
 
   void adjustBalances(
@@ -111,22 +114,19 @@
     BigDecimal adjustedChargeAmount = BigDecimal.ZERO;
     if (this.accrualAccounting && chargeIsAccrued(chargeDefinition)) {
       if (Action.valueOf(chargeDefinition.getAccrueAction()) == action) {
-        final BigDecimal maxDebit = prePaymentBalances.getMaxDebit(chargeDefinition.getFromAccountDesignator(), chargeAmount);
-        adjustedChargeAmount = prePaymentBalances.getMaxCredit(chargeDefinition.getAccrualAccountDesignator(), maxDebit);
+        adjustedChargeAmount = getMaxCharge(chargeDefinition.getFromAccountDesignator(), chargeDefinition.getAccrualAccountDesignator(), chargeAmount);
 
         this.addToBalance(chargeDefinition.getFromAccountDesignator(), adjustedChargeAmount.negate());
         this.addToBalance(chargeDefinition.getAccrualAccountDesignator(), adjustedChargeAmount);
       } else if (Action.valueOf(chargeDefinition.getChargeAction()) == action) {
-        final BigDecimal maxDebit = prePaymentBalances.getMaxDebit(chargeDefinition.getAccrualAccountDesignator(), chargeAmount);
-        adjustedChargeAmount = prePaymentBalances.getMaxCredit(chargeDefinition.getToAccountDesignator(), maxDebit);
+        adjustedChargeAmount = getMaxCharge(chargeDefinition.getAccrualAccountDesignator(), chargeDefinition.getToAccountDesignator(), chargeAmount);
 
         this.addToBalance(chargeDefinition.getAccrualAccountDesignator(), adjustedChargeAmount.negate());
         this.addToBalance(chargeDefinition.getToAccountDesignator(), adjustedChargeAmount);
       }
     }
     else if (Action.valueOf(chargeDefinition.getChargeAction()) == action) {
-      final BigDecimal maxDebit = prePaymentBalances.getMaxDebit(chargeDefinition.getFromAccountDesignator(), chargeAmount);
-      adjustedChargeAmount = prePaymentBalances.getMaxCredit(chargeDefinition.getToAccountDesignator(), maxDebit);
+      adjustedChargeAmount = getMaxCharge(chargeDefinition.getFromAccountDesignator(), chargeDefinition.getToAccountDesignator(), chargeAmount);
 
       this.addToBalance(chargeDefinition.getFromAccountDesignator(), adjustedChargeAmount.negate());
       this.addToBalance(chargeDefinition.getToAccountDesignator(), adjustedChargeAmount);
@@ -136,6 +136,20 @@
     addToCostComponent(chargeDefinition, adjustedChargeAmount);
   }
 
+  private BigDecimal getMaxCharge(
+      final String fromAccountDesignator,
+      final String toAccountDesignator,
+      final BigDecimal plannedCharge) {
+    final BigDecimal expectedImpactOnDebitAccount = plannedCharge.add(this.getBalanceAdjustment(fromAccountDesignator));
+    final BigDecimal maxImpactOnDebitAccount = prePaymentBalances.getMaxDebit(fromAccountDesignator, expectedImpactOnDebitAccount);
+    final BigDecimal maxDebit = maxImpactOnDebitAccount.subtract(this.getBalanceAdjustment(fromAccountDesignator));
+
+    final BigDecimal expectedImpactOnCreditAccount = plannedCharge.add(this.getBalanceAdjustment(toAccountDesignator));
+    final BigDecimal maxImpactOnCreditAccount = prePaymentBalances.getMaxCredit(toAccountDesignator, expectedImpactOnCreditAccount);
+    final BigDecimal maxCredit = maxImpactOnCreditAccount.subtract(this.getBalanceAdjustment(toAccountDesignator));
+    return maxCredit.min(maxDebit);
+  }
+
   private static boolean chargeIsAccrued(final ChargeDefinition chargeDefinition) {
     return chargeDefinition.getAccrualAccountDesignator() != null;
   }
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/PeriodChargeCalculator.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PeriodChargeCalculator.java
similarity index 85%
rename from service/src/main/java/io/mifos/individuallending/internal/service/PeriodChargeCalculator.java
rename to service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PeriodChargeCalculator.java
index 3aaebf5..0ced324 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/PeriodChargeCalculator.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PeriodChargeCalculator.java
@@ -13,9 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.costcomponent;
 
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
+import io.mifos.individuallending.internal.service.RateCollectors;
+import io.mifos.individuallending.internal.service.schedule.Period;
+import io.mifos.individuallending.internal.service.schedule.ScheduledAction;
+import io.mifos.individuallending.internal.service.schedule.ScheduledActionHelpers;
+import io.mifos.individuallending.internal.service.schedule.ScheduledCharge;
 import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
 
 import java.math.BigDecimal;
@@ -37,7 +42,7 @@
       final int precision) {
     return scheduledCharges.stream()
             .filter(PeriodChargeCalculator::accruedInterestCharge)
-            .collect(Collectors.groupingBy(scheduledCharge -> scheduledCharge.getScheduledAction().repaymentPeriod,
+            .collect(Collectors.groupingBy(scheduledCharge -> scheduledCharge.getScheduledAction().getRepaymentPeriod(),
                     Collectors.mapping(x -> chargeAmountPerPeriod(x, interest, precision), RateCollectors.compound(precision))));
   }
 
@@ -46,8 +51,8 @@
     return scheduledCharge.getChargeDefinition().getAccrualAccountDesignator() != null &&
         scheduledCharge.getChargeDefinition().getAccrueAction() != null &&
         scheduledCharge.getChargeDefinition().getAccrueAction().equals(Action.APPLY_INTEREST.name()) &&
-        scheduledCharge.getScheduledAction().action == Action.ACCEPT_PAYMENT &&
-        scheduledCharge.getScheduledAction().actionPeriod != null &&
+        scheduledCharge.getScheduledAction().getAction() == Action.ACCEPT_PAYMENT &&
+        scheduledCharge.getScheduledAction().getActionPeriod() != null &&
         scheduledCharge.getChargeDefinition().getChargeMethod() == ChargeDefinition.ChargeMethod.INTEREST;
   }
 
@@ -65,7 +70,7 @@
 
     final BigDecimal actionPeriodDuration
         = BigDecimal.valueOf(
-        scheduledAction.actionPeriod
+        scheduledAction.getActionPeriod()
             .getDuration()
             .getSeconds());
     final Optional<BigDecimal> accrualPeriodDuration = Optional.ofNullable(chargeDefinition.getAccrueAction())
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/RealRunningBalances.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RealRunningBalances.java
similarity index 92%
rename from service/src/main/java/io/mifos/individuallending/internal/service/RealRunningBalances.java
rename to service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RealRunningBalances.java
index 34a6227..d93b5d1 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/RealRunningBalances.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RealRunningBalances.java
@@ -13,9 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.costcomponent;
 
 import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
+import io.mifos.individuallending.internal.service.DesignatorToAccountIdentifierMapper;
 import io.mifos.portfolio.service.internal.util.AccountingAdapter;
 import net.jodah.expiringmap.ExpirationPolicy;
 import net.jodah.expiringmap.ExpiringMap;
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/RunningBalances.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RunningBalances.java
similarity index 97%
rename from service/src/main/java/io/mifos/individuallending/internal/service/RunningBalances.java
rename to service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RunningBalances.java
index 1a08a7a..212e3b8 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/RunningBalances.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RunningBalances.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.costcomponent;
 
 import io.mifos.individuallending.IndividualLendingPatternFactory;
 import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/SimulatedRunningBalances.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/SimulatedRunningBalances.java
similarity index 92%
rename from service/src/main/java/io/mifos/individuallending/internal/service/SimulatedRunningBalances.java
rename to service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/SimulatedRunningBalances.java
index 9c96574..cda251d 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/SimulatedRunningBalances.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/SimulatedRunningBalances.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.costcomponent;
 
 import java.math.BigDecimal;
 import java.util.HashMap;
@@ -26,7 +26,7 @@
 public class SimulatedRunningBalances implements RunningBalances {
   final private Map<String, BigDecimal> balances;
 
-  SimulatedRunningBalances() {
+  public SimulatedRunningBalances() {
     this.balances = new HashMap<>();
   }
 
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/ChargeRange.java b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ChargeRange.java
similarity index 90%
rename from service/src/main/java/io/mifos/individuallending/internal/service/ChargeRange.java
rename to service/src/main/java/io/mifos/individuallending/internal/service/schedule/ChargeRange.java
index cd293d5..2c8acf8 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/ChargeRange.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ChargeRange.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.schedule;
 
 import java.math.BigDecimal;
 import java.util.Objects;
@@ -22,7 +22,7 @@
 /**
  * @author Myrle Krantz
  */
-class ChargeRange {
+public class ChargeRange {
   final private BigDecimal from;
   @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
   final private Optional<BigDecimal> to;
@@ -34,7 +34,7 @@
     this.to = to;
   }
 
-  boolean amountIsWithinRange(BigDecimal amountProportionalTo) {
+  public boolean amountIsWithinRange(final BigDecimal amountProportionalTo) {
     return to.map(bigDecimal -> from.compareTo(amountProportionalTo) <= 0 &&
         bigDecimal.compareTo(amountProportionalTo) > 0)
         .orElseGet(() -> from.compareTo(amountProportionalTo) <= 0);
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/Period.java b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/Period.java
similarity index 83%
rename from service/src/main/java/io/mifos/individuallending/internal/service/Period.java
rename to service/src/main/java/io/mifos/individuallending/internal/service/schedule/Period.java
index 0ca16cd..0a0532b 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/Period.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/Period.java
@@ -13,9 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
-
-import io.mifos.core.lang.DateConverter;
+package io.mifos.individuallending.internal.service.schedule;
 
 import javax.annotation.Nonnull;
 import java.time.Duration;
@@ -31,25 +29,25 @@
   final private LocalDate endDate;
   final private boolean lastPeriod;
 
-  Period(final LocalDate beginDate, final LocalDate endDateExclusive) {
+  public Period(final LocalDate beginDate, final LocalDate endDateExclusive) {
     this.beginDate = beginDate;
     this.endDate = endDateExclusive;
     this.lastPeriod = false;
   }
 
-  Period(final LocalDate beginDate, final LocalDate endDateExclusive, final boolean lastPeriod) {
+  public Period(final LocalDate beginDate, final LocalDate endDateExclusive, final boolean lastPeriod) {
     this.beginDate = beginDate;
     this.endDate = endDateExclusive;
     this.lastPeriod = lastPeriod;
   }
 
-  Period(final LocalDate beginDate, final int periodLength) {
+  public Period(final LocalDate beginDate, final int periodLength) {
     this.beginDate = beginDate;
     this.endDate = beginDate.plusDays(periodLength);
     this.lastPeriod = false;
   }
 
-  Period(final int periodLength, final LocalDate endDate) {
+  public Period(final int periodLength, final LocalDate endDate) {
     this.beginDate = endDate.minusDays(periodLength);
     this.endDate = endDate;
     this.lastPeriod = false;
@@ -63,15 +61,11 @@
     return endDate;
   }
 
-  boolean isLastPeriod() {
+  public boolean isLastPeriod() {
     return lastPeriod;
   }
 
-  String getEndDateAsString() {
-    return endDate == null ? null : DateConverter.toIsoString(endDate);
-  }
-
-  Duration getDuration() {
+  public Duration getDuration() {
     long days = beginDate.until(endDate, ChronoUnit.DAYS);
     return ChronoUnit.DAYS.getDuration().multipliedBy(days);
   }
@@ -80,10 +74,6 @@
     return this.getBeginDate().compareTo(date) <= 0 && this.getEndDate().compareTo(date) > 0;
   }
 
-  boolean isDefined() {
-    return beginDate != null || endDate != null;
-  }
-
   @Override
   public boolean equals(Object o) {
     if (this == o) return true;
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/ScheduledAction.java b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledAction.java
similarity index 74%
rename from service/src/main/java/io/mifos/individuallending/internal/service/ScheduledAction.java
rename to service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledAction.java
index edcef2e..bca424a 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/ScheduledAction.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledAction.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.schedule;
 
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
 
@@ -28,20 +28,20 @@
 public class ScheduledAction {
   final Action action;
   final LocalDate when;
-  final @Nullable Period actionPeriod;
-  final @Nullable Period repaymentPeriod;
+  private final @Nullable Period actionPeriod;
+  private final @Nullable Period repaymentPeriod;
 
-  ScheduledAction(@Nonnull final Action action,
-                  @Nonnull final LocalDate when,
-                  @Nonnull final Period actionPeriod,
-                  @Nonnull final Period repaymentPeriod) {
+  public ScheduledAction(@Nonnull final Action action,
+                         @Nonnull final LocalDate when,
+                         @Nonnull final Period actionPeriod,
+                         @Nonnull final Period repaymentPeriod) {
     this.action = action;
     this.when = when;
     this.actionPeriod = actionPeriod;
     this.repaymentPeriod = repaymentPeriod;
   }
 
-  ScheduledAction(@Nonnull final Action action,
+  public ScheduledAction(@Nonnull final Action action,
                   @Nonnull final LocalDate when,
                   @Nonnull final Period actionPeriod) {
     this.action = action;
@@ -50,7 +50,7 @@
     this.repaymentPeriod = null;
   }
 
-  ScheduledAction(@Nonnull final Action action,
+  public ScheduledAction(@Nonnull final Action action,
                   @Nonnull final LocalDate when) {
     this.action = action;
     this.when = when;
@@ -87,4 +87,22 @@
             ", repaymentPeriod=" + repaymentPeriod +
             '}';
   }
+
+  @Nullable
+  public Period getActionPeriod() {
+    return actionPeriod;
+  }
+
+  public Action getAction() {
+    return action;
+  }
+
+  @Nullable
+  public Period getRepaymentPeriod() {
+    return repaymentPeriod;
+  }
+
+  public LocalDate getWhen() {
+    return when;
+  }
 }
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/ScheduledActionHelpers.java b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledActionHelpers.java
similarity index 99%
rename from service/src/main/java/io/mifos/individuallending/internal/service/ScheduledActionHelpers.java
rename to service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledActionHelpers.java
index c6f4fc8..af85844 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/ScheduledActionHelpers.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledActionHelpers.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.schedule;
 
 import io.mifos.individuallending.api.v1.domain.caseinstance.CaseParameters;
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/ScheduledCharge.java b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledCharge.java
similarity index 87%
rename from service/src/main/java/io/mifos/individuallending/internal/service/ScheduledCharge.java
rename to service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledCharge.java
index 7b98317..8cfaf43 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/ScheduledCharge.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledCharge.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.schedule;
 
 import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
 
@@ -29,7 +29,7 @@
   @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
   private final Optional<ChargeRange> chargeRange;
 
-  ScheduledCharge(
+  public ScheduledCharge(
       @Nonnull final ScheduledAction scheduledAction,
       @Nonnull final ChargeDefinition chargeDefinition,
       @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @Nonnull final Optional<ChargeRange> chargeRange) {
@@ -38,15 +38,15 @@
     this.chargeRange = chargeRange;
   }
 
-  ScheduledAction getScheduledAction() {
+  public ScheduledAction getScheduledAction() {
     return scheduledAction;
   }
 
-  ChargeDefinition getChargeDefinition() {
+  public ChargeDefinition getChargeDefinition() {
     return chargeDefinition;
   }
 
-  Optional<ChargeRange> getChargeRange() {
+  public Optional<ChargeRange> getChargeRange() {
     return chargeRange;
   }
 
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/ScheduledChargeComparator.java b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargeComparator.java
similarity index 94%
rename from service/src/main/java/io/mifos/individuallending/internal/service/ScheduledChargeComparator.java
rename to service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargeComparator.java
index e597b48..5840cdb 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/ScheduledChargeComparator.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargeComparator.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.schedule;
 
 
 import io.mifos.individuallending.api.v1.domain.product.ChargeProportionalDesignator;
@@ -25,7 +25,7 @@
 /**
  * @author Myrle Krantz
  */
-class ScheduledChargeComparator implements Comparator<ScheduledCharge>
+public class ScheduledChargeComparator implements Comparator<ScheduledCharge>
 {
   @Override
   public int compare(ScheduledCharge o1, ScheduledCharge o2) {
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/ScheduledChargesService.java b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargesService.java
similarity index 98%
rename from service/src/main/java/io/mifos/individuallending/internal/service/ScheduledChargesService.java
rename to service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargesService.java
index b578443..6749c4e 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/ScheduledChargesService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargesService.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.schedule;
 
 import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
 import io.mifos.portfolio.service.internal.repository.BalanceSegmentEntity;
@@ -47,7 +47,7 @@
     this.balanceSegmentRepository = balanceSegmentRepository;
   }
 
-  List<ScheduledCharge> getScheduledCharges(
+  public List<ScheduledCharge> getScheduledCharges(
       final String productIdentifier,
       final @Nonnull List<ScheduledAction> scheduledActions) {
     final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByChargeAction
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/Fixture.java b/service/src/test/java/io/mifos/individuallending/internal/service/Fixture.java
index cf7532b..9ecbd6e 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/Fixture.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/Fixture.java
@@ -18,6 +18,9 @@
 import io.mifos.individuallending.api.v1.domain.caseinstance.CaseParameters;
 import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
+import io.mifos.individuallending.internal.service.schedule.Period;
+import io.mifos.individuallending.internal.service.schedule.ScheduledAction;
+import io.mifos.individuallending.internal.service.schedule.ScheduledCharge;
 import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
 import io.mifos.portfolio.api.v1.domain.PaymentCycle;
 import io.mifos.portfolio.api.v1.domain.TermRange;
@@ -36,11 +39,11 @@
 /**
  * @author Myrle Krantz
  */
-class Fixture {
+public class Fixture {
 
-  static CaseParameters getTestCaseParameters()
+  public static CaseParameters getTestCaseParameters()
   {
-    final CaseParameters ret = new CaseParameters(generateRandomIdentifier("fred"));
+    final CaseParameters ret = new CaseParameters(generateRandomIdentifier());
 
     ret.setMaximumBalance(fixScale(BigDecimal.valueOf(2000L)));
     ret.setTermRange(new TermRange(ChronoUnit.DAYS, 2));
@@ -49,9 +52,9 @@
     return ret;
   }
 
-  private static String generateRandomIdentifier(final String prefix) {
+  private static String generateRandomIdentifier() {
     //prefix followed by a random positive number with less than 4 digits.
-    return prefix + Math.floorMod(Math.abs(new Random().nextInt()), 1000);
+    return "fred" + Math.floorMod(Math.abs(new Random().nextInt()), 1000);
   }
   private static BigDecimal fixScale(final BigDecimal bigDecimal)
   {
@@ -59,10 +62,10 @@
   }
 
 
-  static ScheduledAction scheduledInterestAction(
-          final LocalDate initialDisbursementDate,
-          final int daysIn,
-          final Period repaymentPeriod)
+  public static ScheduledAction scheduledInterestAction(
+      final LocalDate initialDisbursementDate,
+      final int daysIn,
+      final Period repaymentPeriod)
   {
     Assert.assertTrue(daysIn >= 1);
     final LocalDate when = initialDisbursementDate.plusDays(daysIn);
@@ -70,7 +73,7 @@
     return new ScheduledAction(Action.APPLY_INTEREST, when, actionPeriod, repaymentPeriod);
   }
 
-  static List<ScheduledAction> scheduledRepaymentActions(final LocalDate initial, final LocalDate... paymentDates)
+  public static List<ScheduledAction> scheduledRepaymentActions(final LocalDate initial, final LocalDate... paymentDates)
   {
     final List<ScheduledAction> ret = new ArrayList<>();
     LocalDate begin = initial;
@@ -86,7 +89,7 @@
     return new ScheduledAction(Action.ACCEPT_PAYMENT, to, repaymentPeriod, repaymentPeriod);
   }
 
-  static ScheduledCharge scheduledInterestBookingCharge(
+  public static ScheduledCharge scheduledInterestBookingCharge(
       final LocalDate initialDate,
       final int chargeDateDelta,
       final int periodBeginDelta,
@@ -111,7 +114,7 @@
     return new ScheduledCharge(scheduledAction, chargeDefinition, Optional.empty());
   }
 
-  static Period getPeriod(final LocalDate initialDate, final int periodBeginDelta, final int periodLength) {
+  public static Period getPeriod(final LocalDate initialDate, final int periodBeginDelta, final int periodLength) {
     return new Period(initialDate.plusDays(periodBeginDelta), periodLength);
   }
 }
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/IndividualLoanServiceTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/IndividualLoanServiceTest.java
index 8c49177..b87e8f1 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/IndividualLoanServiceTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/IndividualLoanServiceTest.java
@@ -24,6 +24,10 @@
 import io.mifos.individuallending.api.v1.domain.product.ChargeIdentifiers;
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
 import io.mifos.individuallending.internal.mapper.CaseParametersMapper;
+import io.mifos.individuallending.internal.service.schedule.ScheduledAction;
+import io.mifos.individuallending.internal.service.schedule.ScheduledActionHelpers;
+import io.mifos.individuallending.internal.service.schedule.ScheduledCharge;
+import io.mifos.individuallending.internal.service.schedule.ScheduledChargesService;
 import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
 import io.mifos.portfolio.api.v1.domain.CostComponent;
 import io.mifos.portfolio.api.v1.domain.PaymentCycle;
@@ -101,6 +105,8 @@
         INTEREST_ID,
         DISBURSEMENT_FEE_ID,
         REPAY_PRINCIPAL_ID,
+        REPAY_FEES_ID,
+        REPAY_INTEREST_ID,
         DISBURSE_PAYMENT_ID,
         LATE_FEE_ID
         ));
@@ -317,13 +323,18 @@
     final Set<BigDecimal> customerRepayments = Stream.iterate(1, x -> x + 1).limit(allPlannedPayments.size() - 1)
         .map(x ->
         {
-          final BigDecimal valueOfRepaymentCostComponent = allPlannedPayments.get(x).getPayment().getCostComponents().stream()
+          final BigDecimal valueOfRepayPrincipalCostComponent = allPlannedPayments.get(x).getPayment().getCostComponents().stream()
               .filter(costComponent -> costComponent.getChargeIdentifier().equals(ChargeIdentifiers.REPAY_PRINCIPAL_ID))
               .map(CostComponent::getAmount)
               .reduce(BigDecimal::add)
               .orElse(BigDecimal.ZERO);
-          final BigDecimal valueOfInterestCostComponent = allPlannedPayments.get(x).getPayment().getCostComponents().stream()
-              .filter(costComponent -> costComponent.getChargeIdentifier().equals(ChargeIdentifiers.INTEREST_ID))
+          final BigDecimal valueOfRepayFeeCostComponent = allPlannedPayments.get(x).getPayment().getCostComponents().stream()
+              .filter(costComponent -> costComponent.getChargeIdentifier().equals(ChargeIdentifiers.REPAY_FEES_ID))
+              .map(CostComponent::getAmount)
+              .reduce(BigDecimal::add)
+              .orElse(BigDecimal.ZERO);
+          final BigDecimal valueOfRepayInterestCostComponent = allPlannedPayments.get(x).getPayment().getCostComponents().stream()
+              .filter(costComponent -> costComponent.getChargeIdentifier().equals(ChargeIdentifiers.REPAY_INTEREST_ID))
               .map(CostComponent::getAmount)
               .reduce(BigDecimal::add)
               .orElse(BigDecimal.ZERO);
@@ -331,12 +342,12 @@
               getBalanceForPayment(allPlannedPayments, AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, x - 1)
                   .subtract(
                       getBalanceForPayment(allPlannedPayments, AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, x));
-          Assert.assertEquals("Checking payment " + x, valueOfRepaymentCostComponent.subtract(valueOfInterestCostComponent), principalDifference);
+          Assert.assertEquals("Checking payment " + x, valueOfRepayPrincipalCostComponent, principalDifference);
           Assert.assertNotEquals("Remaining principle should always be positive or zero.",
               getBalanceForPayment(allPlannedPayments, AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, x).signum(), -1);
           final boolean containsLateFee = allPlannedPayments.get(x).getPayment().getCostComponents().stream().anyMatch(y -> y.getChargeIdentifier().equals(LATE_FEE_ID));
           Assert.assertFalse("Late fee should not be included in planned payments", containsLateFee);
-          return valueOfRepaymentCostComponent;
+          return valueOfRepayPrincipalCostComponent.add(valueOfRepayInterestCostComponent).add(valueOfRepayFeeCostComponent);
         }
     ).collect(Collectors.toSet());
 
@@ -395,8 +406,8 @@
         scheduledActions);
 
     final List<LocalDate> interestCalculationDates = scheduledCharges.stream()
-        .filter(scheduledCharge -> scheduledCharge.getScheduledAction().action == Action.APPLY_INTEREST)
-        .map(scheduledCharge -> scheduledCharge.getScheduledAction().when)
+        .filter(scheduledCharge -> scheduledCharge.getScheduledAction().getAction() == Action.APPLY_INTEREST)
+        .map(scheduledCharge -> scheduledCharge.getScheduledAction().getWhen())
         .collect(Collectors.toList());
 
     final List<LocalDate> allTheDaysAfterTheInitialDisbursementDate
@@ -407,11 +418,11 @@
     Assert.assertEquals(interestCalculationDates, allTheDaysAfterTheInitialDisbursementDate);
 
     final List<LocalDate> acceptPaymentDates = scheduledCharges.stream()
-        .filter(scheduledCharge -> scheduledCharge.getScheduledAction().action == Action.ACCEPT_PAYMENT)
-        .map(scheduledCharge -> scheduledCharge.getScheduledAction().when)
+        .filter(scheduledCharge -> scheduledCharge.getScheduledAction().getAction() == Action.ACCEPT_PAYMENT)
+        .map(scheduledCharge -> scheduledCharge.getScheduledAction().getWhen())
         .collect(Collectors.toList());
     final long expectedAcceptPayments = scheduledActions.stream()
-        .filter(x -> x.action == Action.ACCEPT_PAYMENT).count();
+        .filter(x -> x.getAction() == Action.ACCEPT_PAYMENT).count();
     final List<ChargeDefinition> chargeDefinitionsMappedToAcceptPayment = chargeDefinitionsByChargeAction.get(Action.ACCEPT_PAYMENT.name());
     final int numberOfChangeDefinitionsMappedToAcceptPayment = chargeDefinitionsMappedToAcceptPayment == null ? 0 : chargeDefinitionsMappedToAcceptPayment.size();
     Assert.assertEquals("check for correct number of scheduled charges for accept payment",
@@ -421,7 +432,7 @@
     final Map<ActionDatePair, Set<ChargeDefinition>> searchableScheduledCharges = scheduledCharges.stream()
         .collect(
             Collectors.groupingBy(scheduledCharge ->
-                new ActionDatePair(scheduledCharge.getScheduledAction().action, scheduledCharge.getScheduledAction().when),
+                new ActionDatePair(scheduledCharge.getScheduledAction().getAction(), scheduledCharge.getScheduledAction().getWhen()),
                 Collectors.mapping(ScheduledCharge::getChargeDefinition, Collectors.toSet())));
 
     testCase.chargeDefinitionsForActions.forEach((key, value) ->
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/CostComponentServiceTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentServiceTest.java
similarity index 97%
rename from service/src/test/java/io/mifos/individuallending/internal/service/CostComponentServiceTest.java
rename to service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentServiceTest.java
index 06931c7..f518ec4 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/CostComponentServiceTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentServiceTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.costcomponent;
 
 import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
 import io.mifos.individuallending.api.v1.domain.product.ChargeProportionalDesignator;
@@ -110,6 +110,7 @@
     final SimulatedRunningBalances runningBalances = new SimulatedRunningBalances();
     runningBalances.adjustBalance(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, testCase.runningBalance.negate());
     final BigDecimal amount = CostComponentService.getAmountProportionalTo(
+        null,
         testCase.chargeProportionalDesignator,
         testCase.maximumBalance,
         runningBalances,
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/PaymentBuilderTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderTest.java
similarity index 95%
rename from service/src/test/java/io/mifos/individuallending/internal/service/PaymentBuilderTest.java
rename to service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderTest.java
index b98742b..2e000ed 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/PaymentBuilderTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.costcomponent;
 
 import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
 import org.junit.Assert;
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/PeriodChargeCalculatorTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PeriodChargeCalculatorTest.java
similarity index 95%
rename from service/src/test/java/io/mifos/individuallending/internal/service/PeriodChargeCalculatorTest.java
rename to service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PeriodChargeCalculatorTest.java
index 71e7b42..15a3578 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/PeriodChargeCalculatorTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PeriodChargeCalculatorTest.java
@@ -13,8 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.costcomponent;
 
+import io.mifos.individuallending.internal.service.schedule.Period;
+import io.mifos.individuallending.internal.service.schedule.ScheduledCharge;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -36,7 +38,7 @@
   private static class TestCase {
     final String description;
     List<ScheduledCharge> scheduledCharges;
-    int precision;
+    int precision = 20;
     Map<Period, BigDecimal> expectedPeriodRates;
     private BigDecimal interest;
 
@@ -49,11 +51,6 @@
       return this;
     }
 
-    TestCase precision(final int newVal) {
-      this.precision = newVal;
-      return this;
-    }
-
     TestCase expectedPeriodRates(final Map<Period, BigDecimal> newVal) {
       this.expectedPeriodRates = newVal;
       return this;
@@ -98,7 +95,6 @@
     return new TestCase("simpleCase")
         .interest(BigDecimal.ONE)
         .scheduledCharges(scheduledCharges)
-        .precision(20)
         .expectedPeriodRates(expectedPeriodRates);
   }
 
@@ -119,7 +115,6 @@
     return new TestCase("bitOfCompoundingCase")
         .interest(BigDecimal.TEN)
         .scheduledCharges(scheduledCharges)
-        .precision(20)
         .expectedPeriodRates(expectedPeriodRates);
   }
 
@@ -137,7 +132,6 @@
     return new TestCase("zeroInterestPerPeriod")
         .interest(BigDecimal.ZERO)
         .scheduledCharges(scheduledCharges)
-        .precision(20)
         .expectedPeriodRates(expectedPeriodRates);
   }
 
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/ChargeRangeTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/schedule/ChargeRangeTest.java
similarity index 96%
rename from service/src/test/java/io/mifos/individuallending/internal/service/ChargeRangeTest.java
rename to service/src/test/java/io/mifos/individuallending/internal/service/schedule/ChargeRangeTest.java
index 14757d7..c44be6f 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/ChargeRangeTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/schedule/ChargeRangeTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.schedule;
 
 import org.junit.Assert;
 import org.junit.Test;
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/PeriodTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/schedule/PeriodTest.java
similarity index 95%
rename from service/src/test/java/io/mifos/individuallending/internal/service/PeriodTest.java
rename to service/src/test/java/io/mifos/individuallending/internal/service/schedule/PeriodTest.java
index 0235e48..a28d8c1 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/PeriodTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/schedule/PeriodTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.schedule;
 
 import org.junit.Assert;
 import org.junit.BeforeClass;
@@ -66,6 +66,7 @@
     final Period tommorrowPeriod = new Period(tommorrow, dayAfterTommorrow);
 
     Assert.assertTrue(yesterdayPeriod.compareTo(todayPeriod) < 0);
+    //noinspection EqualsWithItself
     Assert.assertTrue(todayPeriod.compareTo(todayPeriod) == 0);
     Assert.assertTrue(tommorrowPeriod.compareTo(todayPeriod) > 0);
   }
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/ScheduledActionHelpersTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/schedule/ScheduledActionHelpersTest.java
similarity index 95%
rename from service/src/test/java/io/mifos/individuallending/internal/service/ScheduledActionHelpersTest.java
rename to service/src/test/java/io/mifos/individuallending/internal/service/schedule/ScheduledActionHelpersTest.java
index 61771b6..23eaa9a 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/ScheduledActionHelpersTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/schedule/ScheduledActionHelpersTest.java
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.schedule;
 
-import io.mifos.portfolio.api.v1.domain.PaymentCycle;
-import io.mifos.portfolio.api.v1.domain.TermRange;
 import io.mifos.individuallending.api.v1.domain.caseinstance.CaseParameters;
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
+import io.mifos.portfolio.api.v1.domain.PaymentCycle;
+import io.mifos.portfolio.api.v1.domain.TermRange;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -371,19 +371,19 @@
     Assert.assertTrue("Case " + testCase.description + " missing these expected results " + missingExpectedResults,
         missingExpectedResults.isEmpty());
     result.forEach(x -> {
-      Assert.assertTrue(x.toString(), testCase.earliestActionDate.isBefore(x.when) || testCase.earliestActionDate.isEqual(x.when));
-      Assert.assertTrue(x.toString(), testCase.latestActionDate.isAfter(x.when) || testCase.latestActionDate.isEqual(x.when));
+      Assert.assertTrue(x.toString(), testCase.earliestActionDate.isBefore(x.getWhen()) || testCase.earliestActionDate.isEqual(x.getWhen()));
+      Assert.assertTrue(x.toString(), testCase.latestActionDate.isAfter(x.getWhen()) || testCase.latestActionDate.isEqual(x.getWhen()));
     });
     Assert.assertEquals(testCase.expectedPaymentCount, countActionsByType(result, Action.ACCEPT_PAYMENT));
     Assert.assertEquals(testCase.expectedInterestCount, countActionsByType(result, Action.APPLY_INTEREST));
     Assert.assertEquals(1, countActionsByType(result, Action.APPROVE));
     Assert.assertEquals(1, countActionsByType(result, Action.CLOSE));
-    result.stream().filter(scheduledAction -> !ScheduledActionHelpers.actionHasNoActionPeriod(scheduledAction.action))
+    result.stream().filter(scheduledAction -> !ScheduledActionHelpers.actionHasNoActionPeriod(scheduledAction.getAction()))
         .forEach(scheduledAction -> {
           Assert.assertNotNull("The action period of " + scheduledAction.toString() + " should not be null.",
-              scheduledAction.actionPeriod);
+              scheduledAction.getActionPeriod());
           Assert.assertNotNull("The repayment period of " + scheduledAction.toString() + " should not be null.",
-              scheduledAction.repaymentPeriod);
+              scheduledAction.getRepaymentPeriod());
         });
     Assert.assertTrue(noDuplicatesInResult(result));
     Assert.assertTrue(maximumOneInterestPerDay(result));
@@ -394,11 +394,11 @@
     final LocalDate roughEndDate = ScheduledActionHelpers.getRoughEndDate(testCase.initialDisbursementDate, testCase.caseParameters);
 
     testCase.expectedResultContents.stream()
-        .filter(x -> x.action == Action.ACCEPT_PAYMENT)
+        .filter(x -> x.getAction() == Action.ACCEPT_PAYMENT)
         .forEach(expectedResultContents -> {
       final ScheduledAction nextScheduledPayment = ScheduledActionHelpers.getNextScheduledPayment(
           testCase.initialDisbursementDate,
-          expectedResultContents.when.minusDays(1),
+          expectedResultContents.getWhen().minusDays(1),
           roughEndDate,
           testCase.caseParameters);
       Assert.assertEquals(expectedResultContents, nextScheduledPayment);
@@ -410,18 +410,18 @@
         roughEndDate,
         testCase.caseParameters);
 
-    Assert.assertNotNull(afterAction.actionPeriod);
-    Assert.assertTrue(afterAction.actionPeriod.isLastPeriod());
+    Assert.assertNotNull(afterAction.getActionPeriod());
+    Assert.assertTrue(afterAction.getActionPeriod().isLastPeriod());
   }
 
   private long countActionsByType(final List<ScheduledAction> scheduledActions, final Action actionToCount) {
-    return scheduledActions.stream().filter(x -> x.action == actionToCount).count();
+    return scheduledActions.stream().filter(x -> x.getAction() == actionToCount).count();
   }
 
   private boolean maximumOneInterestPerDay(final List<ScheduledAction> result) {
     final List<LocalDate> interestDays = result.stream()
-            .filter(x -> x.action == Action.APPLY_INTEREST)
-            .map(x -> x.when)
+            .filter(x -> x.getAction() == Action.APPLY_INTEREST)
+            .map(ScheduledAction::getWhen)
             .collect(Collectors.toList());
 
     final Set<LocalDate> interestDaysSet = new HashSet<>();
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/ScheduledActionTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/schedule/ScheduledActionTest.java
similarity index 95%
rename from service/src/test/java/io/mifos/individuallending/internal/service/ScheduledActionTest.java
rename to service/src/test/java/io/mifos/individuallending/internal/service/schedule/ScheduledActionTest.java
index a287c2f..a8f43ab 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/ScheduledActionTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/schedule/ScheduledActionTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.schedule;
 
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
 import org.junit.Assert;
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/ScheduledChargeComparatorTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargeComparatorTest.java
similarity index 98%
rename from service/src/test/java/io/mifos/individuallending/internal/service/ScheduledChargeComparatorTest.java
rename to service/src/test/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargeComparatorTest.java
index 2e38d67..a2acb4b 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/ScheduledChargeComparatorTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargeComparatorTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.schedule;
 
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
 import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/ScheduledChargesServiceTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargesServiceTest.java
similarity index 98%
rename from service/src/test/java/io/mifos/individuallending/internal/service/ScheduledChargesServiceTest.java
rename to service/src/test/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargesServiceTest.java
index 57cee42..352d034 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/ScheduledChargesServiceTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargesServiceTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.individuallending.internal.service;
+package io.mifos.individuallending.internal.service.schedule;
 
 import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
 import io.mifos.portfolio.service.internal.repository.BalanceSegmentEntity;