Fixed inconsistency in interest calculation between planned payment and
payment by accruing interest on the real amount rather than compounding
the calculated daily interest, then applying it for the planned payment.

This resulted in some misbehavior in planned payments around the interest
costcomponent since both accrual and incurral were being added to that
costcomponent.  To fix this I excluded accrued costcomponents from the
payment and changed the basis of journal entry creation from the
costcomponents to the balanceAdjustments in the payment builder.

This approach gives a more accurate result anyways because sometimes
when two identical charges were debitting the same account, one of them
was getting lost in the set.  It also makes it easier to filter out
entries which cancel each other producing a zero debit or credit.
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 0ff31b7..087a9e3 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
@@ -203,8 +203,9 @@
       step6CalculateInterestAndCheckForLatenessForWeek(today, week);
       final BigDecimal nextRepaymentAmount = findNextRepaymentAmount(today.plusDays((week+1)*7));
       final Payment payment = step7PaybackPartialAmount(nextRepaymentAmount, today.plusDays((week + 1) * 7), BigDecimal.ZERO);
-      payment.getBalanceAdjustments().remove(AccountDesignators.INTEREST_ACCRUAL);
-      payment.getBalanceAdjustments().remove(AccountDesignators.LATE_FEE_ACCRUAL); //Remove accrual accounts for comparison.
+      final BigDecimal interestAccrual = payment.getBalanceAdjustments().remove(AccountDesignators.INTEREST_ACCRUAL); //Don't compare these with planned payment.
+      final BigDecimal customerLoanInterest = payment.getBalanceAdjustments().remove(AccountDesignators.CUSTOMER_LOAN_INTEREST);
+      Assert.assertEquals(interestAccrual.negate(), customerLoanInterest);
       Assert.assertEquals(plannedPayments.get(week+1).getPayment(), payment);
       week++;
     }
@@ -251,8 +252,9 @@
         step6CalculateInterestAndCheckForLatenessForWeek(today, week);
         final BigDecimal nextRepaymentAmount = findNextRepaymentAmount(today.plusDays((week + 1) * 7));
         final Payment payment = step7PaybackPartialAmount(nextRepaymentAmount, today.plusDays((week + 1) * 7), BigDecimal.ZERO);
-        payment.getBalanceAdjustments().remove(AccountDesignators.INTEREST_ACCRUAL);
-        payment.getBalanceAdjustments().remove(AccountDesignators.CUSTOMER_LOAN_INTEREST); //Remove accrual accounting components for comparison, since planned payments are done without accrual accounting.
+        final BigDecimal interestAccrual = payment.getBalanceAdjustments().remove(AccountDesignators.INTEREST_ACCRUAL); //Don't compare these with planned payment.
+        final BigDecimal customerLoanInterest = payment.getBalanceAdjustments().remove(AccountDesignators.CUSTOMER_LOAN_INTEREST);
+        Assert.assertEquals(interestAccrual.negate(), customerLoanInterest);
         Assert.assertEquals(plannedPayments.get(week+1).getPayment(), payment);
       }
       week++;
@@ -456,9 +458,7 @@
 
     final Set<Debtor> debtors = new HashSet<>();
     debtors.add(new Debtor(customerLoanPrincipalIdentifier, amount.toPlainString()));
-    debtors.add(new Debtor(customerLoanFeeIdentifier, PROCESSING_FEE_AMOUNT.toPlainString()));
-    debtors.add(new Debtor(customerLoanFeeIdentifier, disbursementFeeAmount.toPlainString()));
-    debtors.add(new Debtor(customerLoanFeeIdentifier, LOAN_ORIGINATION_FEE_AMOUNT.toPlainString()));
+    debtors.add(new Debtor(customerLoanFeeIdentifier, PROCESSING_FEE_AMOUNT.add(disbursementFeeAmount).add(LOAN_ORIGINATION_FEE_AMOUNT).toPlainString()));
 
     final Set<Creditor> creditors = new HashSet<>();
     creditors.add(new Creditor(AccountingFixture.TELLER_ONE_ACCOUNT_IDENTIFIER, amount.toString()));
@@ -545,8 +545,7 @@
         Action.APPLY_INTEREST,
         null,
         null,
-        forDateTime,
-        new CostComponent(ChargeIdentifiers.INTEREST_ID, calculatedInterest));
+        forDateTime);
 
     if (calculatedLateFee.compareTo(BigDecimal.ZERO) != 0) {
       checkCostComponentForActionCorrect(
@@ -555,8 +554,7 @@
           Action.MARK_LATE,
           null,
           null,
-          forDateTime,
-          new CostComponent(ChargeIdentifiers.LATE_FEE_ID, calculatedLateFee));
+          forDateTime);
     }
     final BeatPublish interestBeat = new BeatPublish(beatIdentifier, midnightTimeStamp);
     portfolioBeatListener.publishBeat(interestBeat);
@@ -648,17 +646,18 @@
         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, principal.toPlainString()));
+    BigDecimal tellerOneDebit = principal;
     if (interestAccrued.compareTo(BigDecimal.ZERO) != 0) {
-      debtors.add(new Debtor(AccountingFixture.TELLER_ONE_ACCOUNT_IDENTIFIER, interestAccrued.toPlainString()));
+      tellerOneDebit = tellerOneDebit.add(interestAccrued);
       debtors.add(new Debtor(AccountingFixture.LOAN_INTEREST_ACCRUAL_ACCOUNT_IDENTIFIER, interestAccrued.toPlainString()));
     }
     if (lateFee.add(nonLateFees).compareTo(BigDecimal.ZERO) != 0) {
-      debtors.add(new Debtor(AccountingFixture.TELLER_ONE_ACCOUNT_IDENTIFIER, lateFee.add(nonLateFees).toPlainString()));
+      tellerOneDebit = tellerOneDebit.add(lateFee.add(nonLateFees));
     }
     if (lateFee.compareTo(BigDecimal.ZERO) != 0) {
       debtors.add(new Debtor(AccountingFixture.LATE_FEE_ACCRUAL_ACCOUNT_IDENTIFIER, lateFee.toPlainString()));
     }
+    debtors.add(new Debtor(AccountingFixture.TELLER_ONE_ACCOUNT_IDENTIFIER, tellerOneDebit.toPlainString()));
 
     final Set<Creditor> creditors = new HashSet<>();
     creditors.add(new Creditor(customerLoanPrincipalIdentifier, principal.toPlainString()));
diff --git a/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java b/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
index d4f9246..a1e044d 100644
--- a/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
+++ b/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
@@ -28,10 +28,9 @@
 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.DesignatorToAccountIdentifierMapper;
-import io.mifos.individuallending.internal.service.costcomponent.*;
 import io.mifos.individuallending.internal.service.DataContextOfAction;
 import io.mifos.individuallending.internal.service.DataContextService;
+import io.mifos.individuallending.internal.service.costcomponent.*;
 import io.mifos.portfolio.api.v1.domain.*;
 import io.mifos.portfolio.service.ServiceConstants;
 import io.mifos.portfolio.service.internal.util.AccountingAdapter;
@@ -470,11 +469,9 @@
         throw ServiceException.internalError("Invalid action: ''{0}''.", action.name());
     }
 
-    final DesignatorToAccountIdentifierMapper designatorToAccountIdentifierMapper
-        = new DesignatorToAccountIdentifierMapper(dataContextOfAction);
     final RealRunningBalances runningBalances = new RealRunningBalances(
         accountingAdapter,
-        designatorToAccountIdentifierMapper);
+        dataContextOfAction);
 
     final PaymentBuilder paymentBuilder = paymentBuilderService.getPaymentBuilder(
         dataContextOfAction,
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 eab188d..9bf8a8f 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
@@ -29,9 +29,10 @@
 import io.mifos.individuallending.api.v1.events.IndividualLoanEventConstants;
 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.*;
 import io.mifos.individuallending.internal.service.DataContextOfAction;
+import io.mifos.individuallending.internal.service.DataContextService;
+import io.mifos.individuallending.internal.service.DesignatorToAccountIdentifierMapper;
+import io.mifos.individuallending.internal.service.costcomponent.*;
 import io.mifos.individuallending.internal.service.schedule.ScheduledActionHelpers;
 import io.mifos.portfolio.api.v1.domain.AccountAssignment;
 import io.mifos.portfolio.api.v1.domain.Case;
@@ -42,7 +43,6 @@
 import io.mifos.portfolio.service.internal.repository.CaseRepository;
 import io.mifos.portfolio.service.internal.repository.TaskInstanceRepository;
 import io.mifos.portfolio.service.internal.util.AccountingAdapter;
-import io.mifos.portfolio.service.internal.util.ChargeInstance;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -132,16 +132,15 @@
         = new DesignatorToAccountIdentifierMapper(dataContextOfAction);
     final RealRunningBalances runningBalances = new RealRunningBalances(
         accountingAdapter,
-        designatorToAccountIdentifierMapper);
+        dataContextOfAction);
 
     final PaymentBuilder paymentBuilder
         = openPaymentBuilderService.getPaymentBuilder(dataContextOfAction, BigDecimal.ZERO, CostComponentService.today(), runningBalances);
 
-    final List<ChargeInstance> charges = paymentBuilder.buildCharges(Action.OPEN, designatorToAccountIdentifierMapper);
-
     final LocalDateTime today = today();
 
-    accountingAdapter.bookCharges(charges,
+    accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
+        designatorToAccountIdentifierMapper,
         command.getCommand().getNote(),
         command.getCommand().getCreatedOn(),
         dataContextOfAction.getMessageForCharge(Action.OPEN),
@@ -172,13 +171,11 @@
         = new DesignatorToAccountIdentifierMapper(dataContextOfAction);
     final RealRunningBalances runningBalances = new RealRunningBalances(
         accountingAdapter,
-        designatorToAccountIdentifierMapper);
+        dataContextOfAction);
 
     final PaymentBuilder paymentBuilder
         = denyPaymentBuilderService.getPaymentBuilder(dataContextOfAction, BigDecimal.ZERO, CostComponentService.today(), runningBalances);
 
-    final List<ChargeInstance> charges = paymentBuilder.buildCharges(Action.DENY, designatorToAccountIdentifierMapper);
-
     final LocalDateTime today = today();
 
     final CaseEntity customerCase = dataContextOfAction.getCustomerCaseEntity();
@@ -255,16 +252,15 @@
 
     final RealRunningBalances runningBalances = new RealRunningBalances(
         accountingAdapter,
-        designatorToAccountIdentifierMapper);
+        dataContextOfAction);
 
     final PaymentBuilder paymentBuilder =
         approvePaymentBuilderService.getPaymentBuilder(dataContextOfAction, BigDecimal.ZERO, CostComponentService.today(), runningBalances);
 
-    final List<ChargeInstance> charges = paymentBuilder.buildCharges(Action.APPROVE, designatorToAccountIdentifierMapper);
-
     final LocalDateTime today = today();
 
-    accountingAdapter.bookCharges(charges,
+    accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
+        designatorToAccountIdentifierMapper,
         command.getCommand().getNote(),
         command.getCommand().getCreatedOn(),
         dataContextOfAction.getMessageForCharge(Action.APPROVE),
@@ -296,16 +292,15 @@
         = new DesignatorToAccountIdentifierMapper(dataContextOfAction);
     final RealRunningBalances runningBalances = new RealRunningBalances(
         accountingAdapter,
-        designatorToAccountIdentifierMapper);
+        dataContextOfAction);
 
     final PaymentBuilder paymentBuilder =
         disbursePaymentBuilderService.getPaymentBuilder(dataContextOfAction, disbursalAmount, CostComponentService.today(), runningBalances);
 
-    final List<ChargeInstance> charges = paymentBuilder.buildCharges(Action.DISBURSE, designatorToAccountIdentifierMapper);
-
     final LocalDateTime today = today();
 
-    accountingAdapter.bookCharges(charges,
+    accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
+        designatorToAccountIdentifierMapper,
         command.getCommand().getNote(),
         command.getCommand().getCreatedOn(),
         dataContextOfAction.getMessageForCharge(Action.DISBURSE),
@@ -352,14 +347,13 @@
         = new DesignatorToAccountIdentifierMapper(dataContextOfAction);
     final RealRunningBalances runningBalances = new RealRunningBalances(
         accountingAdapter,
-        designatorToAccountIdentifierMapper);
+        dataContextOfAction);
 
     final PaymentBuilder paymentBuilder =
         applyInterestPaymentBuilderService.getPaymentBuilder(dataContextOfAction, BigDecimal.ZERO, CostComponentService.today(), runningBalances);
 
-    final List<ChargeInstance> charges = paymentBuilder.buildCharges(Action.APPLY_INTEREST, designatorToAccountIdentifierMapper);
-
-    accountingAdapter.bookCharges(charges,
+    accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
+        designatorToAccountIdentifierMapper,
         "Applied interest on " + command.getForTime(),
         command.getForTime(),
         dataContextOfAction.getMessageForCharge(Action.APPLY_INTEREST),
@@ -391,7 +385,7 @@
         = new DesignatorToAccountIdentifierMapper(dataContextOfAction);
     final RealRunningBalances runningBalances = new RealRunningBalances(
         accountingAdapter,
-        designatorToAccountIdentifierMapper);
+        dataContextOfAction);
 
     final PaymentBuilder paymentBuilder =
         acceptPaymentBuilderService.getPaymentBuilder(
@@ -399,11 +393,10 @@
             command.getCommand().getPaymentSize(),
             DateConverter.fromIsoString(command.getCommand().getCreatedOn()).toLocalDate(), runningBalances);
 
-    final List<ChargeInstance> charges = paymentBuilder.buildCharges(Action.ACCEPT_PAYMENT, designatorToAccountIdentifierMapper);
-
     final LocalDateTime today = today();
 
-    accountingAdapter.bookCharges(charges,
+    accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
+        designatorToAccountIdentifierMapper,
         command.getCommand().getNote(),
         command.getCommand().getCreatedOn(),
         dataContextOfAction.getMessageForCharge(Action.ACCEPT_PAYMENT),
@@ -434,17 +427,16 @@
         = new DesignatorToAccountIdentifierMapper(dataContextOfAction);
     final RealRunningBalances runningBalances = new RealRunningBalances(
         accountingAdapter,
-        designatorToAccountIdentifierMapper);
+        dataContextOfAction);
 
     final PaymentBuilder paymentBuilder =
         markLatePaymentBuilderService.getPaymentBuilder(dataContextOfAction, BigDecimal.ZERO, DateConverter.fromIsoString(command.getForTime()).toLocalDate(),
             runningBalances);
 
-    final List<ChargeInstance> charges = paymentBuilder.buildCharges(Action.MARK_LATE, designatorToAccountIdentifierMapper);
-
     final LocalDateTime today = today();
 
-    accountingAdapter.bookCharges(charges,
+    accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
+        designatorToAccountIdentifierMapper,
         "Marked late on " + command.getForTime(),
         command.getForTime(),
         dataContextOfAction.getMessageForCharge(Action.MARK_LATE),
@@ -490,16 +482,15 @@
         = new DesignatorToAccountIdentifierMapper(dataContextOfAction);
     final RealRunningBalances runningBalances = new RealRunningBalances(
         accountingAdapter,
-        designatorToAccountIdentifierMapper);
+        dataContextOfAction);
 
     final PaymentBuilder paymentBuilder =
         closePaymentBuilderService.getPaymentBuilder(dataContextOfAction, BigDecimal.ZERO, CostComponentService.today(), runningBalances);
 
-    final List<ChargeInstance> charges = paymentBuilder.buildCharges(Action.CLOSE, designatorToAccountIdentifierMapper);
-
     final LocalDateTime today = today();
 
-    accountingAdapter.bookCharges(charges,
+    accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
+        designatorToAccountIdentifierMapper,
         command.getCommand().getNote(),
         command.getCommand().getCreatedOn(),
         dataContextOfAction.getMessageForCharge(Action.CLOSE),
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 dc1dce2..a872fbd 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
@@ -59,6 +59,9 @@
   {
     Objects.requireNonNull(amount, "Amount required");
     Objects.requireNonNull(rate, "Rate required");
+    if (rate.get().compareTo(BigDecimal.ZERO) == 0)
+      return amount.divide(periods);
+
     // AP(m) = m*r / [ (1-((1 + r).pow(-n))) ]
 
     return amount.multiply(rate.get()).divide(
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 62d173e..9ae6402 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
@@ -19,7 +19,6 @@
 import io.mifos.individuallending.api.v1.domain.caseinstance.ChargeName;
 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.product.AccountDesignators;
 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;
@@ -154,8 +153,6 @@
       final SortedSet<ScheduledCharge> scheduledChargesInPeriod = orderedScheduledChargesGroupedByPeriod.get(repaymentPeriod);
       final PaymentBuilder paymentBuilder =
               CostComponentService.getCostComponentsForScheduledCharges(
-                  null, //Action doesn't matter because not using accrual accounting.
-                  Collections.emptyMap(),
                   scheduledChargesInPeriod,
                   initialBalance,
                   balances,
@@ -164,7 +161,7 @@
                   requestedRepayment,
                   interest,
                   minorCurrencyUnitDigits,
-                  false);
+                  true);
 
       plannedPayments.add(paymentBuilder.accumulatePlannedPayment(balances, repaymentPeriod.getEndDate()));
     }
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/AcceptPaymentBuilderService.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/AcceptPaymentBuilderService.java
index d10f130..d3bed9b 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/AcceptPaymentBuilderService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/AcceptPaymentBuilderService.java
@@ -16,24 +16,20 @@
 package io.mifos.individuallending.internal.service.costcomponent;
 
 import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
-import io.mifos.individuallending.api.v1.domain.workflow.Action;
 import io.mifos.individuallending.internal.repository.CaseParametersEntity;
 import io.mifos.individuallending.internal.service.DataContextOfAction;
 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 org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
 import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
 
 /**
  * @author Myrle Krantz
@@ -54,14 +50,14 @@
       final BigDecimal requestedLoanPaymentSize,
       final LocalDate forDate,
       final RunningBalances runningBalances) {
-    final LocalDate startOfTerm = runningBalances.getStartOfTermOrThrow(dataContextOfAction);
+    final LocalDateTime startOfTerm = runningBalances.getStartOfTermOrThrow(dataContextOfAction);
 
     final CaseParametersEntity caseParameters = dataContextOfAction.getCaseParametersEntity();
     final String productIdentifier = dataContextOfAction.getProductEntity().getIdentifier();
     final int minorCurrencyUnitDigits = dataContextOfAction.getProductEntity().getMinorCurrencyUnitDigits();
     final ScheduledAction scheduledAction
         = ScheduledActionHelpers.getNextScheduledPayment(
-        startOfTerm,
+        startOfTerm.toLocalDate(),
         forDate,
         dataContextOfAction.getCustomerCaseEntity().getEndOfTerm().toLocalDate(),
         dataContextOfAction.getCaseParameters()
@@ -71,20 +67,6 @@
         productIdentifier,
         Collections.singletonList(scheduledAction));
 
-    final Map<Boolean, List<ScheduledCharge>> chargesSplitIntoScheduledAndAccrued = scheduledChargesForThisAction.stream()
-        .collect(Collectors.partitioningBy(x -> CostComponentService.isAccruedChargeForAction(x.getChargeDefinition(), Action.ACCEPT_PAYMENT)));
-
-    final Map<ChargeDefinition, CostComponent> accruedCostComponents = chargesSplitIntoScheduledAndAccrued.get(true)
-        .stream()
-        .map(ScheduledCharge::getChargeDefinition)
-        .collect(Collectors.toMap(chargeDefinition -> chargeDefinition,
-            chargeDefinition -> PaymentBuilderService.getAccruedCostComponentToApply(
-                runningBalances,
-                dataContextOfAction,
-                startOfTerm,
-                chargeDefinition)));
-
-
     final BigDecimal loanPaymentSize;
 
     if (requestedLoanPaymentSize != null) {
@@ -101,9 +83,7 @@
 
 
     return CostComponentService.getCostComponentsForScheduledCharges(
-        Action.ACCEPT_PAYMENT,
-        accruedCostComponents,
-        chargesSplitIntoScheduledAndAccrued.get(false),
+        scheduledChargesForThisAction,
         caseParameters.getBalanceRangeMaximum(),
         runningBalances,
         dataContextOfAction.getCaseParametersEntity().getPaymentSize(),
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/ApplyInterestPaymentBuilderService.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/ApplyInterestPaymentBuilderService.java
index 5125b49..ad723f8 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/ApplyInterestPaymentBuilderService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/ApplyInterestPaymentBuilderService.java
@@ -22,8 +22,6 @@
 import io.mifos.individuallending.internal.service.schedule.ScheduledAction;
 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 org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -31,8 +29,6 @@
 import java.time.LocalDate;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
 
 /**
  * @author Myrle Krantz
@@ -53,8 +49,6 @@
       final LocalDate forDate,
       final RunningBalances runningBalances)
   {
-    final LocalDate startOfTerm = runningBalances.getStartOfTermOrThrow(dataContextOfAction);
-
     final CaseParametersEntity caseParameters = dataContextOfAction.getCaseParametersEntity();
     final String productIdentifier = dataContextOfAction.getProductEntity().getIdentifier();
     final int minorCurrencyUnitDigits = dataContextOfAction.getProductEntity().getMinorCurrencyUnitDigits();
@@ -64,23 +58,8 @@
         productIdentifier,
         Collections.singletonList(interestAction));
 
-    final Map<Boolean, List<ScheduledCharge>> chargesSplitIntoScheduledAndAccrued = scheduledCharges.stream()
-        .collect(Collectors.partitioningBy(x -> CostComponentService.isAccruedChargeForAction(x.getChargeDefinition(), Action.APPLY_INTEREST)));
-
-    final Map<ChargeDefinition, CostComponent> accruedCostComponents = chargesSplitIntoScheduledAndAccrued.get(true)
-        .stream()
-        .map(ScheduledCharge::getChargeDefinition)
-        .collect(Collectors.toMap(chargeDefinition -> chargeDefinition,
-            chargeDefinition -> PaymentBuilderService.getAccruedCostComponentToApply(
-                runningBalances,
-                dataContextOfAction,
-                startOfTerm,
-                chargeDefinition)));
-
     return CostComponentService.getCostComponentsForScheduledCharges(
-        Action.APPLY_INTEREST,
-        accruedCostComponents,
-        chargesSplitIntoScheduledAndAccrued.get(false),
+        scheduledCharges,
         caseParameters.getBalanceRangeMaximum(),
         runningBalances,
         dataContextOfAction.getCaseParametersEntity().getPaymentSize(),
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/ApprovePaymentBuilderService.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/ApprovePaymentBuilderService.java
index 5e06b98..47afb7d 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/ApprovePaymentBuilderService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/ApprovePaymentBuilderService.java
@@ -58,8 +58,6 @@
         productIdentifier, scheduledActions);
 
     return CostComponentService.getCostComponentsForScheduledCharges(
-        Action.APPROVE,
-        Collections.emptyMap(),
         scheduledCharges,
         caseParameters.getBalanceRangeMaximum(),
         new SimulatedRunningBalances(),
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/ClosePaymentBuilderService.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/ClosePaymentBuilderService.java
index f0fbcdf..1b37c95 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/ClosePaymentBuilderService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/ClosePaymentBuilderService.java
@@ -24,8 +24,6 @@
 import io.mifos.individuallending.internal.service.schedule.ScheduledAction;
 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 org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -33,8 +31,6 @@
 import java.time.LocalDate;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
 
 /**
  * @author Myrle Krantz
@@ -59,7 +55,6 @@
     if (runningBalances.getBalance(AccountDesignators.CUSTOMER_LOAN_GROUP).compareTo(BigDecimal.ZERO) != 0)
       throw ServiceException.conflict("Cannot close loan until the balance is zero.");
 
-    final LocalDate startOfTerm = runningBalances.getStartOfTermOrThrow(dataContextOfAction);
 
     final CaseParametersEntity caseParameters = dataContextOfAction.getCaseParametersEntity();
     final String productIdentifier = dataContextOfAction.getProductEntity().getIdentifier();
@@ -70,23 +65,8 @@
         productIdentifier,
         Collections.singletonList(closeAction));
 
-    final Map<Boolean, List<ScheduledCharge>> chargesSplitIntoScheduledAndAccrued = scheduledCharges.stream()
-        .collect(Collectors.partitioningBy(x -> CostComponentService.isAccruedChargeForAction(x.getChargeDefinition(), Action.CLOSE)));
-
-    final Map<ChargeDefinition, CostComponent> accruedCostComponents = chargesSplitIntoScheduledAndAccrued.get(true)
-        .stream()
-        .map(ScheduledCharge::getChargeDefinition)
-        .collect(Collectors.toMap(chargeDefinition -> chargeDefinition,
-            chargeDefinition -> PaymentBuilderService.getAccruedCostComponentToApply(
-                runningBalances,
-                dataContextOfAction,
-                startOfTerm,
-                chargeDefinition)));
-
     return CostComponentService.getCostComponentsForScheduledCharges(
-        Action.CLOSE,
-        accruedCostComponents,
-        chargesSplitIntoScheduledAndAccrued.get(false),
+        scheduledCharges,
         caseParameters.getBalanceRangeMaximum(),
         runningBalances,
         dataContextOfAction.getCaseParametersEntity().getPaymentSize(),
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentService.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentService.java
index 6880d7c..86e7fd4 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentService.java
@@ -23,7 +23,6 @@
 import io.mifos.individuallending.internal.service.schedule.Period;
 import io.mifos.individuallending.internal.service.schedule.ScheduledCharge;
 import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
-import io.mifos.portfolio.api.v1.domain.CostComponent;
 import org.javamoney.calc.common.Rate;
 import org.javamoney.moneta.Money;
 
@@ -31,7 +30,10 @@
 import java.math.BigDecimal;
 import java.time.Clock;
 import java.time.LocalDate;
-import java.util.*;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -43,8 +45,6 @@
   private static final int RUNNING_CALCULATION_PRECISION = 8;
 
   public static PaymentBuilder getCostComponentsForScheduledCharges(
-      final Action action,
-      final Map<ChargeDefinition, CostComponent> accruedCostComponents,
       final Collection<ScheduledCharge> scheduledCharges,
       final BigDecimal maximumBalance,
       final RunningBalances preChargeBalances,
@@ -56,31 +56,33 @@
       final boolean accrualAccounting) {
     final PaymentBuilder paymentBuilder = new PaymentBuilder(preChargeBalances, accrualAccounting);
 
-    for (Map.Entry<ChargeDefinition, CostComponent> entry : accruedCostComponents.entrySet()) {
-      final ChargeDefinition chargeDefinition = entry.getKey();
-      final BigDecimal chargeAmount = entry.getValue().getAmount();
-
-      paymentBuilder.adjustBalances(action, chargeDefinition, chargeAmount);
-    }
-
-
     for (final ScheduledCharge scheduledCharge : scheduledCharges) {
       if (accrualAccounting || !isAccrualChargeForAction(scheduledCharge.getChargeDefinition(), scheduledCharge.getScheduledAction().getAction())) {
-        final BigDecimal amountProportionalTo = getAmountProportionalTo(
-            scheduledCharge,
-            maximumBalance,
-            preChargeBalances,
-            contractualRepayment,
-            requestedDisbursement,
-            requestedRepayment,
-            paymentBuilder);
-        if (scheduledCharge.getChargeRange().map(x ->
-            !x.amountIsWithinRange(amountProportionalTo)).orElse(false))
-          continue;
+        final BigDecimal chargeAmount;
+        if (!isIncurralActionForAccruedCharge(scheduledCharge.getChargeDefinition(), scheduledCharge.getScheduledAction().getAction()))
+        {
+          final BigDecimal amountProportionalTo = getAmountProportionalTo(
+              scheduledCharge,
+              maximumBalance,
+              preChargeBalances,
+              contractualRepayment,
+              requestedDisbursement,
+              requestedRepayment,
+              paymentBuilder);
+          if (scheduledCharge.getChargeRange().map(x ->
+              !x.amountIsWithinRange(amountProportionalTo)).orElse(false))
+            continue;
 
-        final BigDecimal chargeAmount = howToApplyScheduledChargeToAmount(scheduledCharge, interest)
-            .apply(amountProportionalTo)
-            .setScale(minorCurrencyUnitDigits, BigDecimal.ROUND_HALF_EVEN);
+          chargeAmount = howToApplyScheduledChargeToAmount(scheduledCharge, interest)
+              .apply(amountProportionalTo)
+              .setScale(minorCurrencyUnitDigits, BigDecimal.ROUND_HALF_EVEN);
+        }
+        else
+        {
+          chargeAmount = preChargeBalances.getAccruedBalanceForCharge(scheduledCharge.getChargeDefinition())
+              .add(paymentBuilder.getBalanceAdjustment(scheduledCharge.getChargeDefinition().getAccrualAccountDesignator()));
+        }
+
         paymentBuilder.adjustBalances(
             scheduledCharge.getScheduledAction().getAction(),
             scheduledCharge.getChargeDefinition(),
@@ -198,8 +200,6 @@
         .filter(x -> x.getScheduledAction().getAction().equals(Action.DISBURSE))
         .collect(Collectors.toList());
     final PaymentBuilder paymentBuilder = getCostComponentsForScheduledCharges(
-        null, //Action doesn't matter since there's nothing accrued.
-        Collections.emptyMap(),
         disbursementFees,
         maximumBalanceSize,
         new SimulatedRunningBalances(),
@@ -221,7 +221,7 @@
     return BigDecimal.valueOf(presentValue.getNumber().doubleValueExact()).setScale(minorCurrencyUnitDigits, BigDecimal.ROUND_HALF_EVEN);
   }
 
-  static boolean isAccruedChargeForAction(final ChargeDefinition chargeDefinition, final Action action) {
+  private static boolean isIncurralActionForAccruedCharge(final ChargeDefinition chargeDefinition, final Action action) {
     return chargeDefinition.getAccrueAction() != null &&
         chargeDefinition.getChargeAction().equals(action.name());
   }
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/DenyPaymentBuilderService.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/DenyPaymentBuilderService.java
index 3b3c826..5bf278f 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/DenyPaymentBuilderService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/DenyPaymentBuilderService.java
@@ -57,8 +57,6 @@
         productIdentifier, scheduledActions);
 
     return CostComponentService.getCostComponentsForScheduledCharges(
-        Action.DENY,
-        Collections.emptyMap(),
         scheduledCharges,
         caseParameters.getBalanceRangeMaximum(),
         new SimulatedRunningBalances(),
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/DisbursePaymentBuilderService.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/DisbursePaymentBuilderService.java
index a88c37f..5b909eb 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/DisbursePaymentBuilderService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/DisbursePaymentBuilderService.java
@@ -20,14 +20,10 @@
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
 import io.mifos.individuallending.internal.repository.CaseParametersEntity;
 import io.mifos.individuallending.internal.service.DataContextOfAction;
-import io.mifos.individuallending.internal.service.DesignatorToAccountIdentifierMapper;
 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.service.internal.util.AccountingAdapter;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -35,12 +31,8 @@
 import javax.annotation.Nullable;
 import java.math.BigDecimal;
 import java.time.LocalDate;
-import java.time.LocalDateTime;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Collectors;
 
 /**
  * @author Myrle Krantz
@@ -48,14 +40,11 @@
 @Service
 public class DisbursePaymentBuilderService implements PaymentBuilderService {
   private final ScheduledChargesService scheduledChargesService;
-  private final AccountingAdapter accountingAdapter;
 
   @Autowired
   public DisbursePaymentBuilderService(
-      final ScheduledChargesService scheduledChargesService,
-      final AccountingAdapter accountingAdapter) {
+      final ScheduledChargesService scheduledChargesService) {
     this.scheduledChargesService = scheduledChargesService;
-    this.accountingAdapter = accountingAdapter;
   }
 
   @Override
@@ -65,9 +54,6 @@
       final LocalDate forDate,
       final RunningBalances runningBalances)
   {
-    final DesignatorToAccountIdentifierMapper designatorToAccountIdentifierMapper
-        = new DesignatorToAccountIdentifierMapper(dataContextOfAction);
-    final String customerLoanPrincipalAccountIdentifier = designatorToAccountIdentifierMapper.mapOrThrow(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL);
     final BigDecimal currentBalance = runningBalances.getBalance(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL);
 
     if (requestedDisbursalSize != null &&
@@ -75,9 +61,6 @@
             currentBalance.add(requestedDisbursalSize)) < 0)
       throw ServiceException.conflict("Cannot disburse over the maximum balance.");
 
-    final Optional<LocalDateTime> optionalStartOfTerm = accountingAdapter.getDateOfOldestEntryContainingMessage(
-        customerLoanPrincipalAccountIdentifier,
-        dataContextOfAction.getMessageForCharge(Action.DISBURSE));
     final CaseParametersEntity caseParameters = dataContextOfAction.getCaseParametersEntity();
     final String productIdentifier = dataContextOfAction.getProductEntity().getIdentifier();
     final int minorCurrencyUnitDigits = dataContextOfAction.getProductEntity().getMinorCurrencyUnitDigits();
@@ -93,25 +76,8 @@
         productIdentifier, scheduledActions);
 
 
-    final Map<Boolean, List<ScheduledCharge>> chargesSplitIntoScheduledAndAccrued = scheduledCharges.stream()
-        .collect(Collectors.partitioningBy(x -> CostComponentService.isAccruedChargeForAction(x.getChargeDefinition(), Action.DISBURSE)));
-
-    final Map<ChargeDefinition, CostComponent> accruedCostComponents =
-        optionalStartOfTerm.map(startOfTerm ->
-            chargesSplitIntoScheduledAndAccrued.get(true)
-                .stream()
-                .map(ScheduledCharge::getChargeDefinition)
-                .collect(Collectors.toMap(chargeDefinition -> chargeDefinition,
-                    chargeDefinition -> PaymentBuilderService.getAccruedCostComponentToApply(
-                        runningBalances,
-                        dataContextOfAction,
-                        startOfTerm.toLocalDate(),
-                        chargeDefinition)))).orElse(Collections.emptyMap());
-
     return CostComponentService.getCostComponentsForScheduledCharges(
-        Action.DISBURSE,
-        accruedCostComponents,
-        chargesSplitIntoScheduledAndAccrued.get(false),
+        scheduledCharges,
         caseParameters.getBalanceRangeMaximum(),
         runningBalances,
         dataContextOfAction.getCaseParametersEntity().getPaymentSize(),
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/MarkLatePaymentBuilderService.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/MarkLatePaymentBuilderService.java
index 51aa3fb..c02e10e 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/MarkLatePaymentBuilderService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/MarkLatePaymentBuilderService.java
@@ -21,8 +21,6 @@
 import io.mifos.individuallending.internal.service.schedule.ScheduledAction;
 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 org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -32,8 +30,6 @@
 import java.time.LocalDate;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
 
 /**
  * @author Myrle Krantz
@@ -54,8 +50,6 @@
       final LocalDate forDate,
       final RunningBalances runningBalances)
   {
-    final LocalDate startOfTerm = runningBalances.getStartOfTermOrThrow(dataContextOfAction);
-
     final CaseParametersEntity caseParameters = dataContextOfAction.getCaseParametersEntity();
     final String productIdentifier = dataContextOfAction.getProductEntity().getIdentifier();
     final int minorCurrencyUnitDigits = dataContextOfAction.getProductEntity().getMinorCurrencyUnitDigits();
@@ -67,24 +61,8 @@
         productIdentifier,
         Collections.singletonList(scheduledAction));
 
-    final Map<Boolean, List<ScheduledCharge>> chargesSplitIntoScheduledAndAccrued = scheduledChargesForThisAction.stream()
-        .collect(Collectors.partitioningBy(x -> CostComponentService.isAccruedChargeForAction(x.getChargeDefinition(), Action.MARK_LATE)));
-
-    final Map<ChargeDefinition, CostComponent> accruedCostComponents = chargesSplitIntoScheduledAndAccrued.get(true)
-        .stream()
-        .map(ScheduledCharge::getChargeDefinition)
-        .collect(Collectors.toMap(chargeDefinition -> chargeDefinition,
-            chargeDefinition -> PaymentBuilderService.getAccruedCostComponentToApply(
-                runningBalances,
-                dataContextOfAction,
-                startOfTerm,
-                chargeDefinition)));
-
-
     return CostComponentService.getCostComponentsForScheduledCharges(
-        Action.MARK_LATE,
-        accruedCostComponents,
-        chargesSplitIntoScheduledAndAccrued.get(false),
+        scheduledChargesForThisAction,
         caseParameters.getBalanceRangeMaximum(),
         runningBalances,
         loanPaymentSize,
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/OpenPaymentBuilderService.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/OpenPaymentBuilderService.java
index ed3d3ab..ec2cde7 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/OpenPaymentBuilderService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/OpenPaymentBuilderService.java
@@ -56,8 +56,6 @@
         productIdentifier, scheduledActions);
 
     return CostComponentService.getCostComponentsForScheduledCharges(
-        Action.OPEN,
-        Collections.emptyMap(),
         scheduledCharges,
         caseParameters.getBalanceRangeMaximum(),
         new SimulatedRunningBalances(),
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilder.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilder.java
index d85056a..4c2d646 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilder.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilder.java
@@ -20,12 +20,10 @@
 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;
 import io.mifos.portfolio.api.v1.domain.RequiredAccountAssignment;
-import io.mifos.portfolio.service.internal.util.ChargeInstance;
 
 import javax.annotation.Nullable;
 import java.math.BigDecimal;
@@ -40,6 +38,7 @@
 public class PaymentBuilder {
   private final RunningBalances prePaymentBalances;
   private final Map<ChargeDefinition, CostComponent> costComponents;
+
   private final Map<String, BigDecimal> balanceAdjustments;
   private final boolean accrualAccounting;
 
@@ -109,14 +108,8 @@
     return new PlannedPayment(payment, balancesCopy);
   }
 
-  public List<ChargeInstance> buildCharges(
-      final Action action,
-      final DesignatorToAccountIdentifierMapper designatorToAccountIdentifierMapper) {
-    return stream()
-        .map(entry -> mapCostComponentEntryToChargeInstance(action, entry, designatorToAccountIdentifierMapper))
-        .filter(Optional::isPresent)
-        .map(Optional::get)
-        .collect(Collectors.toList());
+  public Map<String, BigDecimal> getBalanceAdjustments() {
+    return balanceAdjustments;
   }
 
   public BigDecimal getBalanceAdjustment(final String... accountDesignators) {
@@ -129,7 +122,7 @@
       final Action action,
       final ChargeDefinition chargeDefinition,
       final BigDecimal chargeAmount) {
-    BigDecimal adjustedChargeAmount = BigDecimal.ZERO;
+    BigDecimal adjustedChargeAmount;
     if (this.accrualAccounting && chargeIsAccrued(chargeDefinition)) {
       if (Action.valueOf(chargeDefinition.getAccrueAction()) == action) {
         adjustedChargeAmount = getMaxCharge(chargeDefinition.getFromAccountDesignator(), chargeDefinition.getAccrualAccountDesignator(), chargeAmount);
@@ -141,6 +134,8 @@
 
         this.addToBalance(chargeDefinition.getAccrualAccountDesignator(), adjustedChargeAmount.negate());
         this.addToBalance(chargeDefinition.getToAccountDesignator(), adjustedChargeAmount);
+
+        addToCostComponent(chargeDefinition, adjustedChargeAmount);
       }
     }
     else if (Action.valueOf(chargeDefinition.getChargeAction()) == action) {
@@ -148,23 +143,24 @@
 
       this.addToBalance(chargeDefinition.getFromAccountDesignator(), adjustedChargeAmount.negate());
       this.addToBalance(chargeDefinition.getToAccountDesignator(), adjustedChargeAmount);
+
+      addToCostComponent(chargeDefinition, adjustedChargeAmount);
     }
-
-
-    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 expectedImpactOnDebitAccount = plannedCharge.subtract(this.getBalanceAdjustment(fromAccountDesignator));
     final BigDecimal maxImpactOnDebitAccount = prePaymentBalances.getMaxDebit(fromAccountDesignator, expectedImpactOnDebitAccount);
-    final BigDecimal maxDebit = maxImpactOnDebitAccount.subtract(this.getBalanceAdjustment(fromAccountDesignator));
+    final BigDecimal maxDebit = maxImpactOnDebitAccount.add(this.getBalanceAdjustment(fromAccountDesignator))
+        .max(BigDecimal.ZERO);
 
     final BigDecimal expectedImpactOnCreditAccount = plannedCharge.add(this.getBalanceAdjustment(toAccountDesignator));
     final BigDecimal maxImpactOnCreditAccount = prePaymentBalances.getMaxCredit(toAccountDesignator, expectedImpactOnCreditAccount);
-    final BigDecimal maxCredit = maxImpactOnCreditAccount.subtract(this.getBalanceAdjustment(toAccountDesignator));
+    final BigDecimal maxCredit = maxImpactOnCreditAccount.subtract(this.getBalanceAdjustment(toAccountDesignator))
+        .max(BigDecimal.ZERO);
     return maxCredit.min(maxDebit);
   }
 
@@ -236,34 +232,4 @@
     ret.setAmount(BigDecimal.ZERO);
     return ret;
   }
-
-  private static Optional<ChargeInstance> mapCostComponentEntryToChargeInstance(
-      final Action action,
-      final Map.Entry<ChargeDefinition, CostComponent> costComponentEntry,
-      final DesignatorToAccountIdentifierMapper designatorToAccountIdentifierMapper) {
-    final ChargeDefinition chargeDefinition = costComponentEntry.getKey();
-    final BigDecimal chargeAmount = costComponentEntry.getValue().getAmount();
-
-    if (chargeIsAccrued(chargeDefinition)) {
-      if (Action.valueOf(chargeDefinition.getAccrueAction()) == action)
-        return Optional.of(new ChargeInstance(
-            designatorToAccountIdentifierMapper.mapOrThrow(chargeDefinition.getFromAccountDesignator()),
-            designatorToAccountIdentifierMapper.mapOrThrow(chargeDefinition.getAccrualAccountDesignator()),
-            chargeAmount));
-      else if (Action.valueOf(chargeDefinition.getChargeAction()) == action)
-        return Optional.of(new ChargeInstance(
-            designatorToAccountIdentifierMapper.mapOrThrow(chargeDefinition.getAccrualAccountDesignator()),
-            designatorToAccountIdentifierMapper.mapOrThrow(chargeDefinition.getToAccountDesignator()),
-            chargeAmount));
-      else
-        return Optional.empty();
-    }
-    else if (Action.valueOf(chargeDefinition.getChargeAction()) == action)
-      return Optional.of(new ChargeInstance(
-          designatorToAccountIdentifierMapper.mapOrThrow(chargeDefinition.getFromAccountDesignator()),
-          designatorToAccountIdentifierMapper.mapOrThrow(chargeDefinition.getToAccountDesignator()),
-          chargeAmount));
-    else
-      return Optional.empty();
-  }
 }
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderService.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderService.java
index b5b1c61..290ce56 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderService.java
@@ -1,24 +1,12 @@
 package io.mifos.individuallending.internal.service.costcomponent;
 
 import io.mifos.individuallending.internal.service.DataContextOfAction;
-import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
-import io.mifos.portfolio.api.v1.domain.CostComponent;
 
 import javax.annotation.Nonnull;
 import java.math.BigDecimal;
 import java.time.LocalDate;
 
 public interface PaymentBuilderService {
-  static CostComponent getAccruedCostComponentToApply(
-      final RunningBalances runningBalances,
-      final DataContextOfAction dataContextOfAction,
-      final LocalDate startOfTerm,
-      final ChargeDefinition chargeDefinition) {
-    final CostComponent ret = new CostComponent();
-    ret.setChargeIdentifier(chargeDefinition.getIdentifier());
-    ret.setAmount(runningBalances.getAccruedBalanceForCharge(dataContextOfAction, startOfTerm, chargeDefinition));
-    return ret;
-  }
 
   PaymentBuilder getPaymentBuilder(
       final @Nonnull DataContextOfAction dataContextOfAction,
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RealRunningBalances.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RealRunningBalances.java
index 05dc2f6..40b5095 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RealRunningBalances.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RealRunningBalances.java
@@ -15,7 +15,6 @@
  */
 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.workflow.Action;
 import io.mifos.individuallending.internal.service.DataContextOfAction;
@@ -35,15 +34,20 @@
  * @author Myrle Krantz
  */
 public class RealRunningBalances implements RunningBalances {
-  private final DesignatorToAccountIdentifierMapper designatorToAccountIdentifierMapper;
   private final AccountingAdapter accountingAdapter;
+  private final DesignatorToAccountIdentifierMapper designatorToAccountIdentifierMapper;
+  private final DataContextOfAction dataContextOfAction;
   private final ExpiringMap<String, BigDecimal> realAccountBalanceCache;
+  @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
+  private Optional<LocalDateTime> startOfTerm;
 
   public RealRunningBalances(
       final AccountingAdapter accountingAdapter,
-      final DesignatorToAccountIdentifierMapper designatorToAccountIdentifierMapper) {
+      final DataContextOfAction dataContextOfAction) {
     this.accountingAdapter = accountingAdapter;
-    this.designatorToAccountIdentifierMapper = designatorToAccountIdentifierMapper;
+    this.designatorToAccountIdentifierMapper =
+        new DesignatorToAccountIdentifierMapper(dataContextOfAction);
+    this.dataContextOfAction = dataContextOfAction;
     this.realAccountBalanceCache = ExpiringMap.builder()
         .maxSize(20)
         .expirationPolicy(ExpirationPolicy.CREATED)
@@ -59,6 +63,7 @@
           return accountIdentifier.map(accountingAdapter::getCurrentAccountBalance).orElse(BigDecimal.ZERO);
         })
         .build();
+    this.startOfTerm = Optional.empty();
   }
 
   @Override
@@ -67,35 +72,32 @@
   }
 
   @Override
-  public BigDecimal getAccruedBalanceForCharge(
-      final DataContextOfAction dataContextOfAction,
-      final LocalDate startOfTerm,
-      final ChargeDefinition chargeDefinition) {
+  public BigDecimal getAccruedBalanceForCharge(final ChargeDefinition chargeDefinition) {
     final String accrualAccountIdentifier = designatorToAccountIdentifierMapper.mapOrThrow(chargeDefinition.getAccrualAccountDesignator());
 
+    final LocalDate startOfTermLocalDate = getStartOfTermOrThrow(dataContextOfAction).toLocalDate();
+
     final BigDecimal amountAccrued = accountingAdapter.sumMatchingEntriesSinceDate(
         accrualAccountIdentifier,
-        startOfTerm,
+        startOfTermLocalDate,
         dataContextOfAction.getMessageForCharge(Action.valueOf(chargeDefinition.getAccrueAction())));
     final BigDecimal amountApplied = accountingAdapter.sumMatchingEntriesSinceDate(
         accrualAccountIdentifier,
-        startOfTerm,
+        startOfTermLocalDate,
         dataContextOfAction.getMessageForCharge(Action.valueOf(chargeDefinition.getChargeAction())));
     return amountAccrued.subtract(amountApplied);
   }
 
   @Override
-  public LocalDate getStartOfTermOrThrow(final DataContextOfAction dataContextOfAction) {
+  public Optional<LocalDateTime> getStartOfTerm(final DataContextOfAction dataContextOfAction) {
+     if (!startOfTerm.isPresent()) {
+       final String customerLoanPrincipalAccountIdentifier = designatorToAccountIdentifierMapper.mapOrThrow(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL);
 
-    final String customerLoanPrincipalAccountIdentifier = designatorToAccountIdentifierMapper.mapOrThrow(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL);
+       this.startOfTerm = accountingAdapter.getDateOfOldestEntryContainingMessage(
+           customerLoanPrincipalAccountIdentifier,
+           dataContextOfAction.getMessageForCharge(Action.DISBURSE));
+     }
 
-    final Optional<LocalDateTime> firstDisbursalDateTime = accountingAdapter.getDateOfOldestEntryContainingMessage(
-        customerLoanPrincipalAccountIdentifier,
-        dataContextOfAction.getMessageForCharge(Action.DISBURSE));
-
-    return firstDisbursalDateTime.map(LocalDateTime::toLocalDate)
-        .orElseThrow(() -> ServiceException.internalError(
-            "Start of term for loan ''{0}'' could not be acquired from accounting.",
-            dataContextOfAction.getCompoundIdentifer()));
+    return this.startOfTerm;
   }
 }
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RunningBalances.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RunningBalances.java
index f15c31a..db7ecb9 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RunningBalances.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/RunningBalances.java
@@ -15,6 +15,7 @@
  */
 package io.mifos.individuallending.internal.service.costcomponent;
 
+import io.mifos.core.lang.ServiceException;
 import io.mifos.individuallending.IndividualLendingPatternFactory;
 import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
 import io.mifos.individuallending.internal.service.DataContextOfAction;
@@ -23,9 +24,10 @@
 import io.mifos.portfolio.api.v1.domain.RequiredAccountAssignment;
 
 import java.math.BigDecimal;
-import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 
 /**
  * @author Myrle Krantz
@@ -53,11 +55,16 @@
   BigDecimal getAccountBalance(final String accountDesignator);
 
   BigDecimal getAccruedBalanceForCharge(
-      final DataContextOfAction dataContextOfAction,
-      final LocalDate startOfTerm,
       final ChargeDefinition chargeDefinition);
 
-  LocalDate getStartOfTermOrThrow(final DataContextOfAction dataContextOfAction);
+  Optional<LocalDateTime> getStartOfTerm(final DataContextOfAction dataContextOfAction);
+
+  default LocalDateTime getStartOfTermOrThrow(final DataContextOfAction dataContextOfAction) {
+    return this.getStartOfTerm(dataContextOfAction)
+        .orElseThrow(() -> ServiceException.internalError(
+            "Start of term for loan ''{0}'' could not be acquired from accounting.",
+            dataContextOfAction.getCompoundIdentifer()));
+  }
 
   default BigDecimal getLedgerBalance(final String ledgerDesignator) {
     final Pattern individualLendingPattern = IndividualLendingPatternFactory.individualLendingPattern();
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/SimulatedRunningBalances.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/SimulatedRunningBalances.java
index fea96fd..fcd921d 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/SimulatedRunningBalances.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/SimulatedRunningBalances.java
@@ -21,22 +21,23 @@
 
 import java.math.BigDecimal;
 import java.time.Clock;
-import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 
 /**
  * @author Myrle Krantz
  */
 public class SimulatedRunningBalances implements RunningBalances {
   final private Map<String, BigDecimal> balances = new HashMap<>();
-  private final LocalDate startOfTerm;
+  private final LocalDateTime startOfTerm;
 
   public SimulatedRunningBalances() {
-    this.startOfTerm = LocalDate.now(Clock.systemUTC());
+    this.startOfTerm = LocalDateTime.now(Clock.systemUTC());
   }
 
-  SimulatedRunningBalances(final LocalDate startOfTerm) {
+  SimulatedRunningBalances(final LocalDateTime startOfTerm) {
     this.startOfTerm = startOfTerm;
   }
 
@@ -47,16 +48,14 @@
 
   @Override
   public BigDecimal getAccruedBalanceForCharge(
-      final DataContextOfAction dataContextOfAction,
-      final LocalDate startOfTerm,
       final ChargeDefinition chargeDefinition) {
     return balances.getOrDefault(chargeDefinition.getAccrualAccountDesignator(), BigDecimal.ZERO);
     //This is not accurate for all cases, but good enough for the cases it's used in.
   }
 
   @Override
-  public LocalDate getStartOfTermOrThrow(final DataContextOfAction dataContextOfAction) {
-    return startOfTerm;
+  public Optional<LocalDateTime> getStartOfTerm(final DataContextOfAction dataContextOfAction) {
+    return Optional.ofNullable(startOfTerm);
   }
 
   void adjustBalance(final String key, final BigDecimal amount) {
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingAdapter.java b/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingAdapter.java
index 63083d5..0c427d5 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingAdapter.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingAdapter.java
@@ -25,6 +25,7 @@
 import io.mifos.core.lang.DateRange;
 import io.mifos.core.lang.ServiceException;
 import io.mifos.core.lang.listening.EventExpectation;
+import io.mifos.individuallending.internal.service.DesignatorToAccountIdentifierMapper;
 import io.mifos.portfolio.api.v1.domain.AccountAssignment;
 import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
 import io.mifos.portfolio.service.ServiceConstants;
@@ -68,21 +69,36 @@
     this.logger = logger;
   }
 
-  public void bookCharges(final List<ChargeInstance> costComponents,
+  public void bookCharges(final Map<String, BigDecimal> balanceAdjustments,
+                          final DesignatorToAccountIdentifierMapper designatorToAccountIdentifierMapper,
                           final String note,
                           final String transactionDate,
                           final String message,
                           final String transactionType) {
-    final Set<Creditor> creditors = costComponents.stream()
-            .map(AccountingAdapter::mapToCreditor)
-            .filter(Optional::isPresent)
-            .map(Optional::get)
-            .collect(Collectors.toSet());
-    final Set<Debtor> debtors = costComponents.stream()
-            .map(AccountingAdapter::mapToDebtor)
-            .filter(Optional::isPresent)
-            .map(Optional::get)
-            .collect(Collectors.toSet());
+    final JournalEntry journalEntry = new JournalEntry();
+    final Set<Creditor> creditors = new HashSet<>();
+    journalEntry.setCreditors(creditors);
+    final Set<Debtor> debtors = new HashSet<>();
+    journalEntry.setDebtors(debtors);
+    balanceAdjustments.forEach((accountDesignator, balanceAdjustment) -> {
+      final int sign = balanceAdjustment.compareTo(BigDecimal.ZERO);
+      if (sign == 0)
+        return;
+
+      final String accountIdentifier = designatorToAccountIdentifierMapper.mapOrThrow(accountDesignator);
+
+      if (sign < 0) {
+        final Debtor debtor = new Debtor();
+        debtor.setAccountNumber(accountIdentifier);
+        debtor.setAmount(balanceAdjustment.negate().toPlainString());
+        debtors.add(debtor);
+      } else {
+        final Creditor creditor = new Creditor();
+        creditor.setAccountNumber(accountIdentifier);
+        creditor.setAmount(balanceAdjustment.toPlainString());
+        creditors.add(creditor);
+      }
+    });
 
     if (creditors.isEmpty() && !debtors.isEmpty() ||
         debtors.isEmpty() && !creditors.isEmpty())
@@ -92,7 +108,6 @@
     if (creditors.isEmpty() && debtors.isEmpty())
       return;
 
-    final JournalEntry journalEntry = new JournalEntry();
     journalEntry.setCreditors(creditors);
     journalEntry.setDebtors(debtors);
     journalEntry.setClerk(UserContextHolder.checkedGetUser());
@@ -140,30 +155,6 @@
         .map(BigDecimal::valueOf).reduce(BigDecimal.ZERO, BigDecimal::add);
   }
 
-  private static Optional<Debtor> mapToDebtor(final ChargeInstance chargeInstance) {
-    if (chargeInstance.getAmount().compareTo(BigDecimal.ZERO) == 0)
-      return Optional.empty();
-
-    final Debtor ret = new Debtor();
-    ret.setAccountNumber(chargeInstance.getFromAccount());
-    ret.setAmount(chargeInstance.getAmount().toPlainString());
-    return Optional.of(ret);
-  }
-
-  private static Optional<Creditor> mapToCreditor(final ChargeInstance chargeInstance) {
-    if (chargeInstance.getAmount().compareTo(BigDecimal.ZERO) == 0)
-      return Optional.empty();
-
-    final Creditor ret = new Creditor();
-    ret.setAccountNumber(chargeInstance.getToAccount());
-    ret.setAmount(chargeInstance.getAmount().toPlainString());
-    return Optional.of(ret);
-  }
-
-  public BigDecimal getTotalOfCurrentAccountBalances(final String... accountIdentifiers) {
-    return Arrays.stream(accountIdentifiers).map(this::getCurrentAccountBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
-  }
-
   public BigDecimal getCurrentAccountBalance(final String accountIdentifier) {
     try {
       final Account account = ledgerManager.findAccount(accountIdentifier);
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/util/ChargeInstance.java b/service/src/main/java/io/mifos/portfolio/service/internal/util/ChargeInstance.java
deleted file mode 100644
index 0056c84..0000000
--- a/service/src/main/java/io/mifos/portfolio/service/internal/util/ChargeInstance.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2017 The Mifos Initiative.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package io.mifos.portfolio.service.internal.util;
-
-import java.math.BigDecimal;
-import java.util.Objects;
-
-/**
- * @author Myrle Krantz
- */
-public class ChargeInstance {
-  private final String fromAccount;
-  private final String toAccount;
-  private final BigDecimal amount;
-
-  public ChargeInstance(final String fromAccount,
-                        final String toAccount,
-                        final BigDecimal amount) {
-    this.fromAccount = fromAccount;
-    this.toAccount = toAccount;
-    this.amount = amount;
-  }
-
-  public String getFromAccount() {
-    return fromAccount;
-  }
-
-  public String getToAccount() {
-    return toAccount;
-  }
-
-  public BigDecimal getAmount() {
-    return amount;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-    ChargeInstance that = (ChargeInstance) o;
-    return Objects.equals(fromAccount, that.fromAccount) &&
-            Objects.equals(toAccount, that.toAccount) &&
-            Objects.equals(amount, that.amount);
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(fromAccount, toAccount, amount);
-  }
-
-  @Override
-  public String toString() {
-    return "ChargeInstance{" +
-            "fromAccount='" + fromAccount + '\'' +
-            ", toAccount='" + toAccount + '\'' +
-            ", amount=" + amount +
-            '}';
-  }
-}
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 9c8d853..3fb6007 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
@@ -109,7 +109,7 @@
         LATE_FEE_ID
         ));
     private Map<ActionDatePair, List<ChargeDefinition>> chargeDefinitionsForActions = new HashMap<>();
-    //This is an abuse of the ChargeInstance since everywhere else it's intended to contain account identifiers and not
+    //This is an abuse of the ChargeDefinition since everywhere else it's intended to contain account identifiers and not
     //account designators.  Don't copy the code around charge instances in this test without thinking about what you're
     //doing carefully first.
 
@@ -303,10 +303,21 @@
               .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))
+              .map(CostComponent::getAmount)
+              .reduce(BigDecimal::add)
+              .orElse(BigDecimal.ZERO);
+
+          final BigDecimal interestAccrualBalance = allPlannedPayments.get(x).getPayment().getBalanceAdjustments().getOrDefault(AccountDesignators.INTEREST_ACCRUAL, BigDecimal.ZERO);
+          final BigDecimal lateFeeAccrualBalance = allPlannedPayments.get(x).getPayment().getBalanceAdjustments().getOrDefault(AccountDesignators.LATE_FEE_ACCRUAL, BigDecimal.ZERO);
           final BigDecimal principalDifference =
               getBalanceForPayment(allPlannedPayments, AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, x - 1)
                   .subtract(
                       getBalanceForPayment(allPlannedPayments, AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, x));
+          Assert.assertEquals(valueOfRepayInterestCostComponent, valueOfInterestCostComponent);
+          Assert.assertEquals(BigDecimal.ZERO, interestAccrualBalance);
+          Assert.assertEquals(BigDecimal.ZERO, lateFeeAccrualBalance);
           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);
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/AcceptPaymentBuilderServiceTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/AcceptPaymentBuilderServiceTest.java
index b5c8134..9360743 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/AcceptPaymentBuilderServiceTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/AcceptPaymentBuilderServiceTest.java
@@ -23,7 +23,7 @@
     final PaymentBuilder paymentBuilder = PaymentBuilderServiceTestHarness.constructCallToPaymentBuilder(
         AcceptPaymentBuilderService::new, testCase);
 
-    final Payment payment = paymentBuilder.buildPayment(Action.ACCEPT_PAYMENT, Collections.emptySet(), testCase.forDate);
+    final Payment payment = paymentBuilder.buildPayment(Action.ACCEPT_PAYMENT, Collections.emptySet(), testCase.forDate.toLocalDate());
     Assert.assertNotNull(payment);
     final Map<String, CostComponent> mappedCostComponents = payment.getCostComponents().stream()
         .collect(Collectors.toMap(CostComponent::getChargeIdentifier, x -> x));
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/ApplyInterestPaymentBuilderServiceTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/ApplyInterestPaymentBuilderServiceTest.java
index cc2a384..fd597e3 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/ApplyInterestPaymentBuilderServiceTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/ApplyInterestPaymentBuilderServiceTest.java
@@ -1,17 +1,13 @@
 package io.mifos.individuallending.internal.service.costcomponent;
 
 import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
-import io.mifos.individuallending.api.v1.domain.product.ChargeIdentifiers;
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
-import io.mifos.portfolio.api.v1.domain.CostComponent;
 import io.mifos.portfolio.api.v1.domain.Payment;
 import org.junit.Assert;
 import org.junit.Test;
 
 import java.math.BigDecimal;
 import java.util.Collections;
-import java.util.Map;
-import java.util.stream.Collectors;
 
 public class ApplyInterestPaymentBuilderServiceTest {
   @Test
@@ -22,11 +18,9 @@
     final PaymentBuilder paymentBuilder = PaymentBuilderServiceTestHarness.constructCallToPaymentBuilder(
         ApplyInterestPaymentBuilderService::new, testCase);
 
-    final Payment payment = paymentBuilder.buildPayment(Action.APPLY_INTEREST, Collections.emptySet(), testCase.forDate);
+    final Payment payment = paymentBuilder.buildPayment(Action.APPLY_INTEREST, Collections.emptySet(), testCase.forDate.toLocalDate());
     Assert.assertNotNull(payment);
-    final Map<String, CostComponent> mappedCostComponents = payment.getCostComponents().stream()
-        .collect(Collectors.toMap(CostComponent::getChargeIdentifier, x -> x));
 
-    Assert.assertEquals(BigDecimal.valueOf(27, 2), mappedCostComponents.get(ChargeIdentifiers.INTEREST_ID).getAmount());
+    Assert.assertEquals(BigDecimal.valueOf(27, 2), paymentBuilder.getBalanceAdjustments().get(AccountDesignators.INTEREST_ACCRUAL));
   }
 }
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderServiceTestCase.java b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderServiceTestCase.java
index acc5ded..2277925 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderServiceTestCase.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderServiceTestCase.java
@@ -6,9 +6,9 @@
 
 class PaymentBuilderServiceTestCase {
   private final String description;
-  private LocalDate startOfTerm = LocalDate.of(2015, 1, 15);
+  private LocalDateTime startOfTerm = LocalDateTime.of(2015, 1, 15, 0, 0);
   LocalDateTime endOfTerm = LocalDate.of(2015, 8, 15).atStartOfDay();
-  LocalDate forDate = startOfTerm.plusMonths(1);
+  LocalDateTime forDate = startOfTerm.plusMonths(1);
   BigDecimal paymentSize = BigDecimal.valueOf(100_00, 2);
   BigDecimal balance = BigDecimal.valueOf(2000_00, 2);
   BigDecimal balanceRangeMaximum = BigDecimal.valueOf(1000_00, 2);
@@ -26,7 +26,7 @@
     return this;
   }
 
-  PaymentBuilderServiceTestCase forDate(LocalDate forDate) {
+  PaymentBuilderServiceTestCase forDate(LocalDateTime forDate) {
     this.forDate = forDate;
     return this;
   }
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderServiceTestHarness.java b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderServiceTestHarness.java
index c26126e..a59d2ce 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderServiceTestHarness.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/PaymentBuilderServiceTestHarness.java
@@ -44,7 +44,7 @@
     return testSubject.getPaymentBuilder(
         dataContextOfAction,
         testCase.paymentSize,
-        testCase.forDate,
+        testCase.forDate.toLocalDate(),
         testCase.runningBalances);
   }
 }
\ No newline at end of file