Merge pull request #24 from myrlen/develop

Loan repayment should not be restricted to current teller balance.
diff --git a/api/src/test/java/io/mifos/portfolio/api/v1/domain/PaymentCycleTest.java b/api/src/test/java/io/mifos/portfolio/api/v1/domain/PaymentCycleTest.java
index 499fb53..1a466f6 100644
--- a/api/src/test/java/io/mifos/portfolio/api/v1/domain/PaymentCycleTest.java
+++ b/api/src/test/java/io/mifos/portfolio/api/v1/domain/PaymentCycleTest.java
@@ -54,7 +54,7 @@
             .adjustment(x -> x.setAlignmentDay(null))
             .valid(true));
     ret.add(new ValidationTestCase<PaymentCycle>("invalidAlignmentWeek")
-            .adjustment(x -> x.setAlignmentWeek(3))
+            .adjustment(x -> x.setAlignmentWeek(5))
             .valid(false));
     ret.add(new ValidationTestCase<PaymentCycle>("nullTemporalUnit")
             .adjustment(x -> x.setTemporalUnit(null))
diff --git a/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java b/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
index 5337030..8fb45cd 100644
--- a/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
+++ b/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
@@ -312,11 +312,11 @@
         new ChargeDefinitionEvent(productIdentifier, feeId)));
   }
 
-  AccountAssignment assignEntryToTeller() {
+  List<AccountAssignment> assignEntry(final String accountIdentifier) {
     final AccountAssignment entryAccountAssignment = new AccountAssignment();
     entryAccountAssignment.setDesignator(AccountDesignators.ENTRY);
-    entryAccountAssignment.setAccountIdentifier(AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
-    return entryAccountAssignment;
+    entryAccountAssignment.setAccountIdentifier(accountIdentifier);
+    return Collections.singletonList(entryAccountAssignment);
   }
 
   AccountAssignment assignExpenseToGeneralExpense() {
diff --git a/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java b/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java
index 3dd3e79..aeebdb1 100644
--- a/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java
+++ b/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java
@@ -62,6 +62,7 @@
   static final String PROCESSING_FEE_INCOME_ACCOUNT_IDENTIFIER = "1312";
   static final String DISBURSEMENT_FEE_INCOME_ACCOUNT_IDENTIFIER = "1313";
   static final String CUSTOMERS_DEPOSIT_ACCOUNT = "7352";
+  static final String TELLER_ONE_ACCOUNT = "7354";
   static final String LOAN_INTEREST_ACCRUAL_ACCOUNT_IDENTIFIER = "7810";
   static final String CONSUMER_LOAN_INTEREST_ACCOUNT_IDENTIFIER = "1103";
   static final String LATE_FEE_INCOME_ACCOUNT_IDENTIFIER = "1311";
@@ -168,8 +169,8 @@
   private static Ledger accruedIncomeLedger() {
     final Ledger ret = new Ledger();
     ret.setIdentifier(ACCRUED_INCOME_LEDGER_IDENTIFIER);
-    ret.setParentLedgerIdentifier(ASSET_LEDGER_IDENTIFIER);
-    ret.setType(AccountType.ASSET.name());
+    ret.setParentLedgerIdentifier(ASSET_LEDGER_IDENTIFIER); //TODO: This is inaccurate for a revenue account.
+    ret.setType(AccountType.REVENUE.name());
     ret.setCreatedOn(DateConverter.toIsoString(universalCreationDate));
     return ret;
 
@@ -180,6 +181,7 @@
     ret.setIdentifier(LOAN_FUNDS_SOURCE_ACCOUNT_IDENTIFIER);
     ret.setLedger(CASH_LEDGER_IDENTIFIER);
     ret.setType(AccountType.ASSET.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
@@ -188,6 +190,7 @@
     ret.setIdentifier(PROCESSING_FEE_INCOME_ACCOUNT_IDENTIFIER);
     ret.setLedger(FEES_AND_CHARGES_LEDGER_IDENTIFIER);
     ret.setType(AccountType.REVENUE.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
@@ -196,6 +199,7 @@
     ret.setIdentifier(LOAN_ORIGINATION_FEES_ACCOUNT_IDENTIFIER);
     ret.setLedger(FEES_AND_CHARGES_LEDGER_IDENTIFIER);
     ret.setType(AccountType.REVENUE.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
@@ -204,14 +208,25 @@
     ret.setIdentifier(DISBURSEMENT_FEE_INCOME_ACCOUNT_IDENTIFIER);
     ret.setLedger(FEES_AND_CHARGES_LEDGER_IDENTIFIER);
     ret.setType(AccountType.REVENUE.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
   private static Account tellerOneAccount() {
     final Account ret = new Account();
-    ret.setIdentifier(CUSTOMERS_DEPOSIT_ACCOUNT);
+    ret.setIdentifier(TELLER_ONE_ACCOUNT);
     ret.setLedger(CASH_LEDGER_IDENTIFIER);
     ret.setType(AccountType.ASSET.name());
+    ret.setBalance(0.0);
+    return ret;
+  }
+
+  private static Account customerDepositAccount() {
+    final Account ret = new Account();
+    ret.setIdentifier(CUSTOMERS_DEPOSIT_ACCOUNT);
+    ret.setLedger(CASH_LEDGER_IDENTIFIER); //TODO: The ledger here is wrong.
+    ret.setType(AccountType.LIABILITY.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
@@ -219,7 +234,8 @@
     final Account ret = new Account();
     ret.setIdentifier(LOAN_INTEREST_ACCRUAL_ACCOUNT_IDENTIFIER);
     ret.setLedger(ACCRUED_INCOME_LEDGER_IDENTIFIER);
-    ret.setType(AccountType.ASSET.name());
+    ret.setType(AccountType.REVENUE.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
@@ -228,6 +244,7 @@
     ret.setIdentifier(CONSUMER_LOAN_INTEREST_ACCOUNT_IDENTIFIER);
     ret.setLedger(LOAN_INCOME_LEDGER_IDENTIFIER);
     ret.setType(AccountType.REVENUE.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
@@ -236,6 +253,7 @@
     ret.setIdentifier(LATE_FEE_INCOME_ACCOUNT_IDENTIFIER);
     ret.setLedger(FEES_AND_CHARGES_LEDGER_IDENTIFIER);
     ret.setType(AccountType.REVENUE.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
@@ -244,6 +262,7 @@
     ret.setIdentifier(LATE_FEE_ACCRUAL_ACCOUNT_IDENTIFIER);
     ret.setLedger(ACCRUED_INCOME_LEDGER_IDENTIFIER);
     ret.setType(AccountType.REVENUE.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
@@ -252,6 +271,7 @@
     ret.setIdentifier(PRODUCT_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER);
     ret.setLedger(CUSTOMER_LOAN_LEDGER_IDENTIFIER);
     ret.setType(AccountType.ASSET.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
@@ -259,6 +279,7 @@
     final Account ret = new Account();
     ret.setIdentifier(GENERAL_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER);
     ret.setType(AccountType.EXPENSE.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
@@ -266,6 +287,7 @@
     final Account ret = new Account();
     ret.setIdentifier(GENERAL_EXPENSE_ACCOUNT_IDENTIFIER);
     ret.setType(AccountType.EXPENSE.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
@@ -273,6 +295,7 @@
     final Account ret = new Account();
     ret.setIdentifier(IMPORTED_CUSTOMER_LOAN_PRINCIPAL_ACCOUNT);
     ret.setType(AccountType.ASSET.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
@@ -280,6 +303,7 @@
     final Account ret = new Account();
     ret.setIdentifier(IMPORTED_CUSTOMER_LOAN_INTEREST_ACCOUNT);
     ret.setType(AccountType.ASSET.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
@@ -287,16 +311,20 @@
     final Account ret = new Account();
     ret.setIdentifier(IMPORTED_CUSTOMER_LOAN_FEES_ACCOUNT);
     ret.setType(AccountType.ASSET.name());
+    ret.setBalance(0.0);
     return ret;
   }
 
   private static AccountPage customerLoanAccountsPage() {
     final Account customerLoanAccount1 = new Account();
     customerLoanAccount1.setIdentifier("customerLoanAccount1");
+    customerLoanAccount1.setBalance(0.0);
     final Account customerLoanAccount2 = new Account();
     customerLoanAccount2.setIdentifier("customerLoanAccount2");
+    customerLoanAccount2.setBalance(0.0);
     final Account customerLoanAccount3 = new Account();
     customerLoanAccount3.setIdentifier("customerLoanAccount3");
+    customerLoanAccount3.setBalance(0.0);
 
     final AccountPage ret = new AccountPage();
     ret.setTotalElements(3L);
@@ -594,6 +622,7 @@
     makeAccountResponsive(processingFeeIncomeAccount(), universalCreationDate, ledgerManagerMock);
     makeAccountResponsive(disbursementFeeIncomeAccount(), universalCreationDate, ledgerManagerMock);
     makeAccountResponsive(tellerOneAccount(), universalCreationDate, ledgerManagerMock);
+    makeAccountResponsive(customerDepositAccount(), universalCreationDate, ledgerManagerMock);
     makeAccountResponsive(loanInterestAccrualAccount(), universalCreationDate, ledgerManagerMock);
     makeAccountResponsive(consumerLoanInterestAccount(), universalCreationDate, ledgerManagerMock);
     makeAccountResponsive(lateFeeIncomeAccount(), universalCreationDate, ledgerManagerMock);
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 d551dae..d390d79 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
@@ -121,7 +121,12 @@
         Assert.assertEquals(IMPORTED_NEXT_REPAYMENT_AMOUNT, nextRepaymentAmount);
       else
         Assert.assertEquals(totalDue, nextRepaymentAmount);
-      final Payment payment = step7PaybackPartialAmount(nextRepaymentAmount, today.plusDays((week + 1) * 7), BigDecimal.ZERO);
+      final Payment payment = step7PaybackPartialAmount(
+          nextRepaymentAmount,
+          today.plusDays((week + 1) * 7),
+          BigDecimal.ZERO,
+          nextRepaymentAmount,
+          AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
       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("week " + week, interestAccrual.negate(), customerLoanInterest);
@@ -143,10 +148,13 @@
     step2CreateCase();
     step3IImportCaseWhenAccountsExist(initialDisbursalDate);
 
+    final BigDecimal payment = expectedCurrentPrincipal.add(nonLateFees).add(interestAccrued);
     step7PaybackPartialAmount(
-        expectedCurrentPrincipal.add(nonLateFees).add(interestAccrued),
+        payment,
         today,
-        BigDecimal.ZERO);
+        BigDecimal.ZERO,
+        payment,
+        AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
     step8Close(today);
   }
 
@@ -203,6 +211,10 @@
     );
   }
 
+  //TODO: once we've upgraded to junit 5 replace workflowTerminatingInEarlyLoanPayoff,
+  // and workflowDisbursalAndPayoffFromTellerAccount with one test annotated with
+  //@ParameterizedTest
+  //@ValueSource(strings = { AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT, AccountingFixture.TELLER_ONE_ACCOUNT })
   @Test
   public void workflowTerminatingInEarlyLoanPayoff() throws InterruptedException {
     final LocalDateTime today = midnightToday();
@@ -214,12 +226,44 @@
     step5Disburse(
         BigDecimal.valueOf(2_000_00, MINOR_CURRENCY_UNIT_DIGITS),
         today,
-        UPPER_RANGE_DISBURSEMENT_FEE_ID, BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS));
+        UPPER_RANGE_DISBURSEMENT_FEE_ID,
+        BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS),
+        BigDecimal.ZERO,
+        AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
     step6CalculateInterestAccrualAndCheckForLateness(midnightToday(), BigDecimal.ZERO);
+    final BigDecimal payment = expectedCurrentPrincipal.add(nonLateFees).add(interestAccrued);
     step7PaybackPartialAmount(
-        expectedCurrentPrincipal.add(nonLateFees).add(interestAccrued),
+        payment,
         today,
-        BigDecimal.ZERO);
+        BigDecimal.ZERO,
+        payment,
+        AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
+    step8Close(today);
+  }
+
+  @Test
+  public void workflowDisbursalAndPayoffFromTellerAccount() throws InterruptedException {
+    final LocalDateTime today = midnightToday();
+
+    step1CreateProduct();
+    step2CreateCase();
+    step3OpenCase(today);
+    step4ApproveCase(today);
+    step5Disburse(
+        BigDecimal.valueOf(2_000_00, MINOR_CURRENCY_UNIT_DIGITS),
+        today,
+        UPPER_RANGE_DISBURSEMENT_FEE_ID,
+        BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS),
+        BigDecimal.valueOf(2_000_00, MINOR_CURRENCY_UNIT_DIGITS),
+        AccountingFixture.TELLER_ONE_ACCOUNT);
+    step6CalculateInterestAccrualAndCheckForLateness(midnightToday(), BigDecimal.ZERO);
+    final BigDecimal payment = expectedCurrentPrincipal.add(nonLateFees).add(interestAccrued);
+    step7PaybackPartialAmount(
+        payment,
+        today,
+        BigDecimal.ZERO,
+        BigDecimal.ZERO, //payback should work even if there's *nothing* in the teller account at initiation.
+        AccountingFixture.TELLER_ONE_ACCOUNT);
     step8Close(today);
   }
 
@@ -234,16 +278,25 @@
     step5Disburse(
         BigDecimal.valueOf(500_00, MINOR_CURRENCY_UNIT_DIGITS),
         today,
-        ChargeIdentifiers.DISBURSEMENT_FEE_ID, BigDecimal.valueOf(10_00, MINOR_CURRENCY_UNIT_DIGITS));
+        ChargeIdentifiers.DISBURSEMENT_FEE_ID,
+        BigDecimal.valueOf(10_00, MINOR_CURRENCY_UNIT_DIGITS),
+        BigDecimal.ZERO,
+        AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
     step5Disburse(
         BigDecimal.valueOf(1_500_00, MINOR_CURRENCY_UNIT_DIGITS),
         today,
-        UPPER_RANGE_DISBURSEMENT_FEE_ID, BigDecimal.valueOf(15_00, MINOR_CURRENCY_UNIT_DIGITS));
+        UPPER_RANGE_DISBURSEMENT_FEE_ID,
+        BigDecimal.valueOf(15_00, MINOR_CURRENCY_UNIT_DIGITS),
+        BigDecimal.ZERO,
+        AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
     step6CalculateInterestAccrualAndCheckForLateness(midnightToday(), BigDecimal.ZERO);
+    final BigDecimal payment = expectedCurrentPrincipal.add(nonLateFees).add(interestAccrued);
     step7PaybackPartialAmount(
-        expectedCurrentPrincipal.add(nonLateFees).add(interestAccrued),
+        payment,
         today,
-        BigDecimal.ZERO);
+        BigDecimal.ZERO,
+        payment,
+        AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
     step8Close(today);
   }
 
@@ -258,14 +311,25 @@
     step5Disburse(
         BigDecimal.valueOf(2_000_00, MINOR_CURRENCY_UNIT_DIGITS),
         today,
-        UPPER_RANGE_DISBURSEMENT_FEE_ID, BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS));
+        UPPER_RANGE_DISBURSEMENT_FEE_ID,
+        BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS),
+        BigDecimal.ZERO,
+        AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
     step6CalculateInterestAccrualAndCheckForLateness(midnightToday(), BigDecimal.ZERO);
-    final BigDecimal repayment1 = expectedCurrentPrincipal.divide(BigDecimal.valueOf(2), BigDecimal.ROUND_HALF_EVEN);
+    final BigDecimal repayment1 = expectedCurrentPrincipal.divide(BigDecimal.valueOf(2), BigDecimal.ROUND_HALF_EVEN)
+        .setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN);
     step7PaybackPartialAmount(
-        repayment1.setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN),
+        repayment1,
         today,
-        BigDecimal.ZERO);
-    step7PaybackPartialAmount(expectedCurrentPrincipal, today, BigDecimal.ZERO);
+        BigDecimal.ZERO,
+        repayment1,
+        AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
+    step7PaybackPartialAmount(
+        expectedCurrentPrincipal,
+        today,
+        BigDecimal.ZERO,
+        expectedCurrentPrincipal,
+        AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
     step8Close(today);
   }
 
@@ -278,9 +342,13 @@
     step3OpenCase(today);
     step4ApproveCase(today);
     try {
-      step5Disburse(BigDecimal.valueOf(-2).setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN),
+      step5Disburse(
+          BigDecimal.valueOf(-2).setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN),
           today,
-          UPPER_RANGE_DISBURSEMENT_FEE_ID, BigDecimal.ZERO.setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN));
+          UPPER_RANGE_DISBURSEMENT_FEE_ID,
+          BigDecimal.ZERO.setScale(MINOR_CURRENCY_UNIT_DIGITS,BigDecimal.ROUND_HALF_EVEN),
+          BigDecimal.ZERO,
+          AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
       Assert.fail("Expected an IllegalArgumentException.");
     }
     catch (IllegalArgumentException ignored) { }
@@ -304,7 +372,10 @@
     step5Disburse(
         BigDecimal.valueOf(2_000_00, MINOR_CURRENCY_UNIT_DIGITS),
         today,
-        UPPER_RANGE_DISBURSEMENT_FEE_ID, BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS));
+        UPPER_RANGE_DISBURSEMENT_FEE_ID,
+        BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS),
+        BigDecimal.ZERO,
+        AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
 
     int week = 0;
     while (expectedCurrentPrincipal.compareTo(BigDecimal.ZERO) > 0) {
@@ -312,7 +383,12 @@
       step6CalculateInterestAndCheckForLatenessForWeek(today, week);
       final BigDecimal interestAccruedBeforePayment = interestAccrued;
       final BigDecimal nextRepaymentAmount = findNextRepaymentAmount(today.plusDays((week+1)*7));
-      final Payment payment = step7PaybackPartialAmount(nextRepaymentAmount, today.plusDays((week + 1) * 7), BigDecimal.ZERO);
+      final Payment payment = step7PaybackPartialAmount(
+          nextRepaymentAmount,
+          today.plusDays((week + 1) * 7),
+          BigDecimal.ZERO,
+          nextRepaymentAmount,
+          AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
       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("week " + week, interestAccrual.negate(), customerLoanInterest);
@@ -344,7 +420,10 @@
     step5Disburse(
         BigDecimal.valueOf(2_000_00, MINOR_CURRENCY_UNIT_DIGITS),
         today,
-        UPPER_RANGE_DISBURSEMENT_FEE_ID, BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS));
+        UPPER_RANGE_DISBURSEMENT_FEE_ID,
+        BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS),
+        BigDecimal.ZERO,
+        AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
 
     int week = 0;
     final int weekOfLateRepayment = 3;
@@ -359,12 +438,22 @@
             7,
             lateFee);
         final BigDecimal nextRepaymentAmount = findNextRepaymentAmount(today.plusDays((week + 1) * 7 + 2));
-        step7PaybackPartialAmount(nextRepaymentAmount, today.plusDays((week + 1) * 7 + 2), lateFee);
+        step7PaybackPartialAmount(
+            nextRepaymentAmount,
+            today.plusDays((week + 1) * 7 + 2),
+            lateFee,
+            nextRepaymentAmount,
+            AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
       }
       else {
         step6CalculateInterestAndCheckForLatenessForWeek(today, week);
         final BigDecimal nextRepaymentAmount = findNextRepaymentAmount(today.plusDays((week + 1) * 7));
-        final Payment payment = step7PaybackPartialAmount(nextRepaymentAmount, today.plusDays((week + 1) * 7), BigDecimal.ZERO);
+        final Payment payment = step7PaybackPartialAmount(
+            nextRepaymentAmount,
+            today.plusDays((week + 1) * 7),
+            BigDecimal.ZERO,
+            nextRepaymentAmount,
+            AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
         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);
@@ -388,7 +477,10 @@
     step5Disburse(
         BigDecimal.valueOf(2_000_00, MINOR_CURRENCY_UNIT_DIGITS),
         today,
-        UPPER_RANGE_DISBURSEMENT_FEE_ID, BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS));
+        UPPER_RANGE_DISBURSEMENT_FEE_ID,
+        BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS),
+        BigDecimal.ZERO,
+        AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT);
 
     final BigDecimal lateFee = BigDecimal.valueOf(15_36, MINOR_CURRENCY_UNIT_DIGITS); //??? TODO: check the late fee value.
     step6CalculateInterestAndCheckForLatenessForRangeOfDays(
@@ -514,7 +606,7 @@
         customerCase.getIdentifier(),
         Action.OPEN,
         forDateTime,
-        Collections.singletonList(assignEntryToTeller()),
+        assignEntry(AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT),
         IndividualLoanEventConstants.OPEN_INDIVIDUALLOAN_CASE,
         Case.State.PENDING);
     checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(), Action.APPROVE, Action.DENY);
@@ -689,7 +781,7 @@
         customerCase.getIdentifier(),
         Action.DENY,
         forDateTime,
-        Collections.singletonList(assignEntryToTeller()),
+        assignEntry(AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT),
         IndividualLoanEventConstants.DENY_INDIVIDUALLOAN_CASE,
         Case.State.CLOSED);
     checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier());
@@ -716,7 +808,7 @@
         customerCase.getIdentifier(),
         Action.APPROVE,
         forDateTime,
-        Collections.singletonList(assignEntryToTeller()),
+        assignEntry(AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT),
         IndividualLoanEventConstants.APPROVE_INDIVIDUALLOAN_CASE,
         Case.State.APPROVED);
     checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(), Action.DISBURSE, Action.CLOSE);
@@ -745,9 +837,14 @@
       final BigDecimal amount,
       final LocalDateTime forDateTime,
       final String whichDisbursementFee,
-      final BigDecimal disbursementFeeAmount) throws InterruptedException {
+      final BigDecimal disbursementFeeAmount,
+      final BigDecimal balanceInEntryAccount,
+      final String entryAccountIdentifier) throws InterruptedException {
     logger.info("step5Disburse  '{}'", amount);
     final BigDecimal provisionForLosses = amount.multiply(BigDecimal.valueOf(0.01)).setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN);
+
+    AccountingFixture.mockBalance(entryAccountIdentifier, balanceInEntryAccount);
+
     checkCostComponentForActionCorrect(
         product.getIdentifier(),
         customerCase.getIdentifier(),
@@ -765,7 +862,7 @@
         customerCase.getIdentifier(),
         Action.DISBURSE,
         forDateTime,
-        Collections.singletonList(assignEntryToTeller()),
+        assignEntry(entryAccountIdentifier),
         amount,
         IndividualLoanEventConstants.DISBURSE_INDIVIDUALLOAN_CASE,
         Case.State.ACTIVE);
@@ -778,7 +875,7 @@
     debtors.add(new Debtor(AccountingFixture.GENERAL_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER, provisionForLosses.toPlainString()));
 
     final Set<Creditor> creditors = new HashSet<>();
-    creditors.add(new Creditor(AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT, amount.toString()));
+    creditors.add(new Creditor(entryAccountIdentifier, amount.toString()));
     creditors.add(new Creditor(AccountingFixture.PROCESSING_FEE_INCOME_ACCOUNT_IDENTIFIER, PROCESSING_FEE_AMOUNT.toPlainString()));
     creditors.add(new Creditor(AccountingFixture.DISBURSEMENT_FEE_INCOME_ACCOUNT_IDENTIFIER, disbursementFeeAmount.toPlainString()));
     creditors.add(new Creditor(AccountingFixture.LOAN_ORIGINATION_FEES_ACCOUNT_IDENTIFIER, LOAN_ORIGINATION_FEE_AMOUNT.toPlainString()));
@@ -1092,11 +1189,13 @@
   private Payment step7PaybackPartialAmount(
       final BigDecimal amount,
       final LocalDateTime forDateTime,
-      final BigDecimal lateFee) throws InterruptedException {
+      final BigDecimal lateFee,
+      final BigDecimal balanceInEntryAccount,
+      final String entryAccountIdentifier) throws InterruptedException {
     logger.info("step7PaybackPartialAmount '{}' '{}'", amount, forDateTime);
     final BigDecimal principal = amount.subtract(interestAccrued).subtract(lateFee.add(nonLateFees));
 
-    AccountingFixture.mockBalance(AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT, amount);
+    AccountingFixture.mockBalance(entryAccountIdentifier, balanceInEntryAccount);
 
     final Payment payment = checkCostComponentForActionCorrect(
         product.getIdentifier(),
@@ -1116,7 +1215,7 @@
         customerCase.getIdentifier(),
         Action.ACCEPT_PAYMENT,
         forDateTime,
-        Collections.singletonList(assignEntryToTeller()),
+        assignEntry(entryAccountIdentifier),
         amount,
         IndividualLoanEventConstants.ACCEPT_PAYMENT_INDIVIDUALLOAN_CASE,
         Case.State.ACTIVE); //Close has to be done explicitly.
@@ -1124,18 +1223,18 @@
         Action.APPLY_INTEREST, Action.MARK_LATE, Action.ACCEPT_PAYMENT, Action.DISBURSE, Action.MARK_IN_ARREARS, Action.WRITE_OFF, Action.CLOSE);
 
     final Set<Debtor> debtors = new HashSet<>();
-    BigDecimal tellerOneDebit = principal;
+    BigDecimal customerDepositAccountDebit = principal;
     if (interestAccrued.compareTo(BigDecimal.ZERO) != 0) {
-      tellerOneDebit = tellerOneDebit.add(interestAccrued);
+      customerDepositAccountDebit = customerDepositAccountDebit.add(interestAccrued);
       debtors.add(new Debtor(AccountingFixture.LOAN_INTEREST_ACCRUAL_ACCOUNT_IDENTIFIER, interestAccrued.toPlainString()));
     }
     if (lateFee.add(nonLateFees).compareTo(BigDecimal.ZERO) != 0) {
-      tellerOneDebit = tellerOneDebit.add(lateFee.add(nonLateFees));
+      customerDepositAccountDebit = customerDepositAccountDebit.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.CUSTOMERS_DEPOSIT_ACCOUNT, tellerOneDebit.toPlainString()));
+    debtors.add(new Debtor(entryAccountIdentifier, customerDepositAccountDebit.toPlainString()));
 
     final Set<Creditor> creditors = new HashSet<>();
     creditors.add(new Creditor(customerLoanPrincipalIdentifier, principal.toPlainString()));
@@ -1180,7 +1279,7 @@
         customerCase.getIdentifier(),
         Action.CLOSE,
         forDateTime,
-        Collections.singletonList(assignEntryToTeller()),
+        assignEntry(AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT),
         IndividualLoanEventConstants.CLOSE_INDIVIDUALLOAN_CASE,
         Case.State.CLOSED); //Close has to be done explicitly.
 
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestCases.java b/component-test/src/main/java/io/mifos/portfolio/TestCases.java
index 63f8b0b..79f5d70 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestCases.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestCases.java
@@ -68,7 +68,7 @@
 
     final Case caseInstance = Fixture.getTestCase(product.getIdentifier());
     final CaseParameters caseParameters = Fixture.getTestCaseParameters();
-    caseParameters.getPaymentCycle().setAlignmentWeek(4);
+    caseParameters.getPaymentCycle().setAlignmentWeek(5);
     final Gson gson = new Gson();
     caseInstance.setParameters(gson.toJson(caseParameters));
 
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestCommands.java b/component-test/src/main/java/io/mifos/portfolio/TestCommands.java
index e6a2828..9f2856f 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestCommands.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestCommands.java
@@ -22,7 +22,6 @@
 
 import java.time.Clock;
 import java.time.LocalDateTime;
-import java.util.Collections;
 
 import static io.mifos.individuallending.api.v1.events.IndividualLoanEventConstants.*;
 
@@ -43,7 +42,7 @@
         product.getIdentifier(),
         customerCase.getIdentifier(),
         Action.APPROVE,
-        Collections.singletonList(assignEntryToTeller()),
+        assignEntry(AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT),
         APPROVE_INDIVIDUALLOAN_CASE,
         Case.State.CREATED);
   }
@@ -58,7 +57,7 @@
         customerCase.getIdentifier(),
         Action.OPEN,
         LocalDateTime.now(Clock.systemUTC()),
-        Collections.singletonList(assignEntryToTeller()),
+        assignEntry(AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT),
         OPEN_INDIVIDUALLOAN_CASE,
         Case.State.PENDING);
 
@@ -66,7 +65,7 @@
         product.getIdentifier(),
         customerCase.getIdentifier(),
         Action.DISBURSE,
-        Collections.singletonList(assignEntryToTeller()),
+        assignEntry(AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT),
         DISBURSE_INDIVIDUALLOAN_CASE,
         Case.State.PENDING);
   }
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestTaskInstances.java b/component-test/src/main/java/io/mifos/portfolio/TestTaskInstances.java
index 5aa6e7a..f67f7be 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestTaskInstances.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestTaskInstances.java
@@ -35,7 +35,6 @@
 import java.time.Clock;
 import java.time.LocalDateTime;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 
@@ -194,7 +193,7 @@
           product.getIdentifier(),
           customerCase.getIdentifier(),
           Action.OPEN,
-          Collections.singletonList(assignEntryToTeller()),
+          assignEntry(AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT),
           IndividualLoanEventConstants.OPEN_INDIVIDUALLOAN_CASE,
           Case.State.CREATED);
     }
@@ -207,7 +206,7 @@
         customerCase.getIdentifier(),
         Action.OPEN,
         LocalDateTime.now(Clock.systemUTC()),
-        Collections.singletonList(assignEntryToTeller()),
+        assignEntry(AccountingFixture.CUSTOMERS_DEPOSIT_ACCOUNT),
         IndividualLoanEventConstants.OPEN_INDIVIDUALLOAN_CASE,
         Case.State.PENDING);
   }
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/AvailableRunningBalancesWithLimits.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/AvailableRunningBalancesWithLimits.java
index 046106a..b97c124 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/AvailableRunningBalancesWithLimits.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/AvailableRunningBalancesWithLimits.java
@@ -39,6 +39,12 @@
     upperLimits.put(designator, limit);
   }
 
+
+  @Override
+  public BigDecimal getAccountSign(final String accountDesignator) {
+    return decoratedRunningBalances.getAccountSign(accountDesignator);
+  }
+
   @Override
   public BigDecimal getAvailableBalance(final String designator, final BigDecimal requestedAmount) {
     final BigDecimal balance = getBalance(designator).orElse(requestedAmount);
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 a394f2c..5dbd64c 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,6 +15,8 @@
  */
 package io.mifos.individuallending.internal.service.costcomponent;
 
+import io.mifos.accounting.api.v1.domain.Account;
+import io.mifos.accounting.api.v1.domain.AccountType;
 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;
@@ -37,7 +39,7 @@
   private final AccountingAdapter accountingAdapter;
   private final DesignatorToAccountIdentifierMapper designatorToAccountIdentifierMapper;
   private final DataContextOfAction dataContextOfAction;
-  private final ExpiringMap<String, Optional<BigDecimal>> realAccountBalanceCache;
+  private final ExpiringMap<String, Optional<Account>> accountCache;
   @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
   private Optional<LocalDateTime> startOfTerm;
 
@@ -48,27 +50,58 @@
     this.designatorToAccountIdentifierMapper =
         new DesignatorToAccountIdentifierMapper(dataContextOfAction);
     this.dataContextOfAction = dataContextOfAction;
-    this.realAccountBalanceCache = ExpiringMap.builder()
-        .maxSize(20)
+    this.accountCache = ExpiringMap.builder()
+        .maxSize(40)
         .expirationPolicy(ExpirationPolicy.CREATED)
-        .expiration(30,TimeUnit.SECONDS)
+        .expiration(60,TimeUnit.SECONDS)
         .entryLoader((String accountDesignator) -> {
           final Optional<String> accountIdentifier;
-          if (accountDesignator.equals(AccountDesignators.ENTRY)) {
+          if (accountDesignator.equals(AccountDesignators.ENTRY) || accountDesignator.equals(AccountDesignators.EXPENSE)) {
             accountIdentifier = designatorToAccountIdentifierMapper.map(accountDesignator);
           }
           else {
             accountIdentifier = Optional.of(designatorToAccountIdentifierMapper.mapOrThrow(accountDesignator));
           }
-          return accountIdentifier.map(accountingAdapter::getCurrentAccountBalance);
+          return accountIdentifier.map(accountingAdapter::getAccount);
         })
         .build();
     this.startOfTerm = Optional.empty();
   }
 
   @Override
+  public BigDecimal getAccountSign(final String accountDesignator) {
+    return accountCache.get(accountDesignator)
+        .map(Account::getType)
+        .map(AccountType::valueOf)
+        .flatMap(x -> {
+          switch (x)
+          {
+            case LIABILITY:
+            case REVENUE:
+            case EQUITY:
+              return Optional.of(POSITIVE);
+
+            default:
+            case ASSET:
+            case EXPENSE:
+              return Optional.of(NEGATIVE);
+          }
+        })
+        .orElseGet(() -> {
+          switch (accountDesignator) {
+            case AccountDesignators.EXPENSE:
+              return NEGATIVE;
+            case AccountDesignators.ENTRY:
+              return POSITIVE;
+            default:
+              return NEGATIVE;
+          }}
+        );
+  }
+
+  @Override
   public Optional<BigDecimal> getAccountBalance(final String accountDesignator) {
-    return realAccountBalanceCache.get(accountDesignator);
+    return accountCache.get(accountDesignator).map(Account::getBalance).map(BigDecimal::valueOf);
   }
 
   @Override
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 b18edaf..0f2706d 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
@@ -25,35 +25,21 @@
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Optional;
 
 /**
  * @author Myrle Krantz
  */
 public interface RunningBalances {
-  Map<String, BigDecimal> ACCOUNT_SIGNS = new HashMap<String, BigDecimal>() {{
-    final BigDecimal negative = BigDecimal.valueOf(-1);
-    final BigDecimal positive = BigDecimal.valueOf(1);
+  BigDecimal NEGATIVE = BigDecimal.valueOf(-1);
+  BigDecimal POSITIVE = BigDecimal.valueOf(1);
 
-    this.put(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, negative);
-    this.put(AccountDesignators.CUSTOMER_LOAN_FEES, negative);
-    this.put(AccountDesignators.CUSTOMER_LOAN_INTEREST, negative);
-    this.put(AccountDesignators.LOAN_FUNDS_SOURCE, negative);
-    this.put(AccountDesignators.PROCESSING_FEE_INCOME, positive);
-    this.put(AccountDesignators.ORIGINATION_FEE_INCOME, positive);
-    this.put(AccountDesignators.DISBURSEMENT_FEE_INCOME, positive);
-    this.put(AccountDesignators.INTEREST_INCOME, positive);
-    this.put(AccountDesignators.INTEREST_ACCRUAL, positive);
-    this.put(AccountDesignators.LATE_FEE_INCOME, positive);
-    this.put(AccountDesignators.LATE_FEE_ACCRUAL, positive);
-    this.put(AccountDesignators.PRODUCT_LOSS_ALLOWANCE, negative);
-    this.put(AccountDesignators.GENERAL_LOSS_ALLOWANCE, negative);
-    this.put(AccountDesignators.EXPENSE, negative);
-    this.put(AccountDesignators.ENTRY, positive);
-    //TODO: derive signs from IndividualLendingPatternFactory.individualLendingRequiredAccounts instead.
-  }};
+  /**
+   * Most accounts assignments have a required type, but some (entry for example) can change from request to request.
+   *
+   * @return NEGATIVE or POSITIVE constant as defined above depending on the type of the underlying account.
+   */
+  BigDecimal getAccountSign(final String accountDesignator);
 
   Optional<BigDecimal> getAccountBalance(final String accountDesignator);
 
@@ -62,6 +48,11 @@
 
   Optional<LocalDateTime> getStartOfTerm();
 
+  default boolean isAccountNegative(final String accountDesignator) {
+    return getAccountSign(accountDesignator).signum() == -1;
+  }
+
+
   default LocalDateTime getStartOfTermOrThrow(final DataContextOfAction dataContextOfAction) {
     return this.getStartOfTerm()
         .orElseThrow(() -> ServiceException.internalError(
@@ -108,7 +99,7 @@
   }
 
   default BigDecimal getMaxDebit(final String accountDesignator, final BigDecimal amount) {
-    if (ACCOUNT_SIGNS.get(accountDesignator).signum() == -1)
+    if (isAccountNegative(accountDesignator))
       return amount;
     else
       return amount.min(getAvailableBalance(accountDesignator, amount));
@@ -122,7 +113,7 @@
     //expense account can achieve a "relative" negative balance, and
     // both loss allowance accounts can achieve an "absolute" negative balance.
 
-    if (ACCOUNT_SIGNS.get(accountDesignator).signum() != -1)
+    if (!isAccountNegative(accountDesignator))
       return amount;
     else
       return amount.min(getAvailableBalance(accountDesignator, amount));
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 05505fa..f2a28ee 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
@@ -16,6 +16,7 @@
 
 package io.mifos.individuallending.internal.service.costcomponent;
 
+import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
 import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
 
 import java.math.BigDecimal;
@@ -29,6 +30,24 @@
  * @author Myrle Krantz
  */
 public class SimulatedRunningBalances implements RunningBalances {
+  private final static Map<String, BigDecimal> ACCOUNT_SIGNS = new HashMap<String, BigDecimal>() {{
+    this.put(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, NEGATIVE);
+    this.put(AccountDesignators.CUSTOMER_LOAN_FEES, NEGATIVE);
+    this.put(AccountDesignators.CUSTOMER_LOAN_INTEREST, NEGATIVE);
+    this.put(AccountDesignators.LOAN_FUNDS_SOURCE, NEGATIVE);
+    this.put(AccountDesignators.PROCESSING_FEE_INCOME, POSITIVE);
+    this.put(AccountDesignators.ORIGINATION_FEE_INCOME, POSITIVE);
+    this.put(AccountDesignators.DISBURSEMENT_FEE_INCOME, POSITIVE);
+    this.put(AccountDesignators.INTEREST_INCOME, POSITIVE);
+    this.put(AccountDesignators.INTEREST_ACCRUAL, POSITIVE);
+    this.put(AccountDesignators.LATE_FEE_INCOME, POSITIVE);
+    this.put(AccountDesignators.LATE_FEE_ACCRUAL, POSITIVE);
+    this.put(AccountDesignators.PRODUCT_LOSS_ALLOWANCE, NEGATIVE);
+    this.put(AccountDesignators.GENERAL_LOSS_ALLOWANCE, NEGATIVE);
+    this.put(AccountDesignators.EXPENSE, NEGATIVE);
+    this.put(AccountDesignators.ENTRY, POSITIVE);
+    //TODO: derive signs from IndividualLendingPatternFactory.individualLendingRequiredAccounts instead.
+  }};
   final private Map<String, BigDecimal> balances = new HashMap<>();
   private final LocalDateTime startOfTerm;
 
@@ -41,6 +60,11 @@
   }
 
   @Override
+  public BigDecimal getAccountSign(final String accountDesignator) {
+    return ACCOUNT_SIGNS.get(accountDesignator);
+  }
+
+  @Override
   public Optional<BigDecimal> getAccountBalance(final String accountDesignator) {
     return Optional.ofNullable(balances.get(accountDesignator));
   }
@@ -57,11 +81,11 @@
     return Optional.ofNullable(startOfTerm);
   }
 
-  public void adjustBalance(final String key, final BigDecimal amount) {
-    final BigDecimal sign = ACCOUNT_SIGNS.get(key);
-    final BigDecimal currentValue = balances.getOrDefault(key, BigDecimal.ZERO);
-    final BigDecimal newValue = currentValue.add(amount.multiply(sign));
-    balances.put(key, newValue);
+  public void adjustBalance(final String accountDesignator, final BigDecimal amount) {
+    final BigDecimal currentValue = balances.getOrDefault(accountDesignator, BigDecimal.ZERO);
+    final BigDecimal newValue = isAccountNegative(accountDesignator) ? currentValue.add(amount.negate())
+        : currentValue.add(amount);
+    balances.put(accountDesignator, newValue);
   }
 
   Map<String, BigDecimal> snapshot() {
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 9a0afd6..14bc95e 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
@@ -198,12 +198,12 @@
         .map(BigDecimal::valueOf).reduce(BigDecimal.ZERO, BigDecimal::add);
   }
 
-  public BigDecimal getCurrentAccountBalance(final String accountIdentifier) {
+  public Account getAccount(final String accountIdentifier) {
     try {
       final Account account = ledgerManager.findAccount(accountIdentifier);
-      if (account == null || account.getBalance() == null)
+      if (account == null || account.getBalance() == null || account.getType() == null)
         throw ServiceException.internalError("Could not find the account with identifier ''{0}''", accountIdentifier);
-      return BigDecimal.valueOf(account.getBalance());
+      return account;
     }
     catch (final AccountNotFoundException e) {
      throw ServiceException.internalError("Could not find the account with identifier ''{0}''", accountIdentifier);