Write off of principal implemented and tested.
diff --git a/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/AccountDesignators.java b/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/AccountDesignators.java
index fb78e89..424d937 100644
--- a/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/AccountDesignators.java
+++ b/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/AccountDesignators.java
@@ -37,6 +37,6 @@
   String LATE_FEE_ACCRUAL = "lfa";
   String PRODUCT_LOSS_ALLOWANCE = "pa";
   String GENERAL_LOSS_ALLOWANCE = "aa";
-  String GENERAL_EXPENSE = "ge";
+  String EXPENSE = "ee";
   String ENTRY = "ey";
 }
diff --git a/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/ChargeIdentifiers.java b/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/ChargeIdentifiers.java
index 8167c85..ce9600b 100644
--- a/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/ChargeIdentifiers.java
+++ b/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/ChargeIdentifiers.java
@@ -24,8 +24,6 @@
 public interface ChargeIdentifiers {
   String INTEREST_NAME = "Interest";
   String INTEREST_ID = "interest";
-  String ALLOW_FOR_WRITE_OFF_NAME = "Allow for write-off";
-  String ALLOW_FOR_WRITE_OFF_ID = "allow-for-write-off";
   String LATE_FEE_NAME = "Late fee";
   String LATE_FEE_ID = "late-fee";
   String DISBURSEMENT_FEE_NAME = "Disbursement fee";
@@ -44,6 +42,8 @@
   String REPAY_FEES_ID = "repay-fees";
   String PROVISION_FOR_LOSSES_NAME = "Provision for losses";
   String PROVISION_FOR_LOSSES_ID = "loss-provisioning";
+  String WRITE_OFF_NAME = "Write off";
+  String WRITE_OFF_ID = "write-off";
 
   static String nameToIdentifier(String name) {
     return name.toLowerCase(Locale.US).replace(" ", "-");
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 8d46e36..1362783 100644
--- a/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
+++ b/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
@@ -56,7 +56,6 @@
 import javax.validation.Validator;
 import javax.validation.ValidatorFactory;
 import java.math.BigDecimal;
-import java.time.Clock;
 import java.time.LocalDateTime;
 import java.time.temporal.ChronoUnit;
 import java.util.*;
@@ -192,40 +191,41 @@
     return caseInstance;
   }
 
-  void checkStateTransfer(final String productIdentifier,
-                          final String caseIdentifier,
-                          final Action action,
-                          final List<AccountAssignment> oneTimeAccountAssignments,
-                          final String event,
-                          final Case.State nextState) throws InterruptedException {
+  void checkStateTransfer(
+      final String productIdentifier,
+      final String caseIdentifier,
+      final Action action,
+      final LocalDateTime actionDateTime,
+      final List<AccountAssignment> oneTimeAccountAssignments,
+      final String event,
+      final Case.State nextState) throws InterruptedException {
     checkStateTransfer(
         productIdentifier,
         caseIdentifier,
         action,
-        LocalDateTime.now(Clock.systemUTC()),
+        actionDateTime,
         oneTimeAccountAssignments,
         BigDecimal.ZERO,
         event,
-        midnightToday(),
         nextState);
   }
 
-  void checkStateTransfer(final String productIdentifier,
-                          final String caseIdentifier,
-                          final Action action,
-                          final LocalDateTime actionDateTime,
-                          final List<AccountAssignment> oneTimeAccountAssignments,
-                          final BigDecimal paymentSize,
-                          final String event,
-                          final LocalDateTime eventDateTime,
-                          final Case.State nextState) throws InterruptedException {
+  void checkStateTransfer(
+      final String productIdentifier,
+      final String caseIdentifier,
+      final Action action,
+      final LocalDateTime actionDateTime,
+      final List<AccountAssignment> oneTimeAccountAssignments,
+      final BigDecimal paymentSize,
+      final String event,
+      final Case.State nextState) throws InterruptedException {
     final Command command = new Command();
     command.setOneTimeAccountAssignments(oneTimeAccountAssignments);
     command.setPaymentSize(paymentSize);
     command.setCreatedOn(DateConverter.toIsoString(actionDateTime));
     portfolioManager.executeCaseCommand(productIdentifier, caseIdentifier, action.name(), command);
 
-    Assert.assertTrue(eventRecorder.wait(event, new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, DateConverter.toIsoString(eventDateTime))));
+    Assert.assertTrue(eventRecorder.wait(event, new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, DateConverter.toIsoString(actionDateTime))));
 
     final Case customerCase = portfolioManager.getCase(productIdentifier, caseIdentifier);
     Assert.assertEquals(nextState.name(), customerCase.getCurrentState());
@@ -314,6 +314,13 @@
     return entryAccountAssignment;
   }
 
+  AccountAssignment assignExpenseToGeneralExpense() {
+    final AccountAssignment entryAccountAssignment = new AccountAssignment();
+    entryAccountAssignment.setDesignator(AccountDesignators.EXPENSE);
+    entryAccountAssignment.setAccountIdentifier(AccountingFixture.GENERAL_EXPENSE_ACCOUNT_IDENTIFIER);
+    return entryAccountAssignment;
+  }
+
   TaskDefinition createTaskDefinition(Product product) throws InterruptedException {
     final TaskDefinition taskDefinition = getTaskDefinition();
     portfolioManager.createTaskDefinition(product.getIdentifier(), taskDefinition);
diff --git a/component-test/src/main/java/io/mifos/portfolio/Fixture.java b/component-test/src/main/java/io/mifos/portfolio/Fixture.java
index 092052b..ffd241c 100644
--- a/component-test/src/main/java/io/mifos/portfolio/Fixture.java
+++ b/component-test/src/main/java/io/mifos/portfolio/Fixture.java
@@ -69,9 +69,9 @@
     accountAssignments.add(new AccountAssignment(LATE_FEE_ACCRUAL, LATE_FEE_ACCRUAL_ACCOUNT_IDENTIFIER));
     accountAssignments.add(new AccountAssignment(PRODUCT_LOSS_ALLOWANCE, PRODUCT_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER));
     accountAssignments.add(new AccountAssignment(GENERAL_LOSS_ALLOWANCE, GENERAL_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER));
-    accountAssignments.add(new AccountAssignment(GENERAL_EXPENSE, GENERAL_EXPENSE_ACCOUNT_IDENTIFIER));
+    //accountAssignments.add(new AccountAssignment(EXPENSE, ...));
     //accountAssignments.add(new AccountAssignment(ENTRY, ...));
-    // Don't assign entry account in test since it usually will not be assigned IRL.
+    // Don't assign entry and expense accounts in test since they usually will not be assigned IRL.
     accountAssignments.add(new AccountAssignment(LOAN_FUNDS_SOURCE, LOAN_FUNDS_SOURCE_ACCOUNT_IDENTIFIER));
     final AccountAssignment customerLoanPrincipalAccountAssignment = new AccountAssignment();
     customerLoanPrincipalAccountAssignment.setDesignator(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL);
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 1210896..0043728 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
@@ -42,7 +42,6 @@
 import javax.annotation.Nullable;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
-import java.time.Clock;
 import java.time.LocalDateTime;
 import java.time.temporal.ChronoUnit;
 import java.util.*;
@@ -322,7 +321,7 @@
         today,
         1,
         8,
-        8,
+        7,
         lateFee);
     step6ICalculateInterestAndLossAllowancesForLateLoanForRangeOfDays(
         today,
@@ -332,7 +331,7 @@
         new LossProvisionStep(60, BigDecimal.valueOf(60))
     );
 
-    //step8IWriteOff(today.plusDays(61));
+    step8IWriteOff(today.plusDays(68));
   }
 
   private BigDecimal findNextRepaymentAmount(
@@ -439,6 +438,7 @@
         product.getIdentifier(),
         customerCase.getIdentifier(),
         Action.OPEN,
+        forDateTime,
         Collections.singletonList(assignEntryToTeller()),
         IndividualLoanEventConstants.OPEN_INDIVIDUALLOAN_CASE,
         Case.State.PENDING);
@@ -461,6 +461,7 @@
         product.getIdentifier(),
         customerCase.getIdentifier(),
         Action.DENY,
+        forDateTime,
         Collections.singletonList(assignEntryToTeller()),
         IndividualLoanEventConstants.DENY_INDIVIDUALLOAN_CASE,
         Case.State.CLOSED);
@@ -487,6 +488,7 @@
         product.getIdentifier(),
         customerCase.getIdentifier(),
         Action.APPROVE,
+        forDateTime,
         Collections.singletonList(assignEntryToTeller()),
         IndividualLoanEventConstants.APPROVE_INDIVIDUALLOAN_CASE,
         Case.State.APPROVED);
@@ -535,11 +537,10 @@
         product.getIdentifier(),
         customerCase.getIdentifier(),
         Action.DISBURSE,
-        LocalDateTime.now(Clock.systemUTC()),
+        forDateTime,
         Collections.singletonList(assignEntryToTeller()),
         amount,
         IndividualLoanEventConstants.DISBURSE_INDIVIDUALLOAN_CASE,
-        midnightToday(),
         Case.State.ACTIVE);
     checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(), Action.APPLY_INTEREST,
         Action.APPLY_INTEREST, Action.MARK_LATE, Action.ACCEPT_PAYMENT, Action.DISBURSE, Action.MARK_IN_ARREARS, Action.WRITE_OFF, Action.CLOSE);
@@ -625,8 +626,14 @@
         .multiply(dailyInterestRate)
         .setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN);
 
+    final BigDecimal provisionForLosses = calculatedLateFee.equals(BigDecimal.ZERO) ?
+        BigDecimal.ZERO :
+        expectedCurrentPrincipal.multiply(BigDecimal.valueOf(0.09))
+            .setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN);
+
     logger.info("calculatedInterest '{}'", calculatedInterest);
     logger.info("calculatedLateFee '{}'", calculatedLateFee);
+    logger.info("provisionForLosses '{}'", provisionForLosses);
 
 
     checkCostComponentForActionCorrect(
@@ -646,7 +653,8 @@
           null,
           null,
           forDateTime,
-          MINOR_CURRENCY_UNIT_DIGITS);
+          MINOR_CURRENCY_UNIT_DIGITS,
+          new CostComponent(ChargeIdentifiers.PROVISION_FOR_LOSSES_ID, provisionForLosses.negate()));
     }
     final BeatPublish interestBeat = new BeatPublish(beatIdentifier, midnightTimeStamp);
     portfolioBeatListener.publishBeat(interestBeat);
@@ -685,10 +693,6 @@
 
 
     if (calculatedLateFee.compareTo(BigDecimal.ZERO) != 0) {
-      final BigDecimal provisionForLosses =
-          expectedCurrentPrincipal.multiply(BigDecimal.valueOf(0.09))
-              .setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN);
-
       final Set<Debtor> lateFeeDebtors = new HashSet<>();
       lateFeeDebtors.add(new Debtor(
           customerLoanFeeIdentifier,
@@ -728,12 +732,14 @@
       final Map<Integer, BigDecimal> lossProvisionConfiguration = Stream.of(lossProvisionSteps)
           .collect(Collectors.toMap(LossProvisionStep::getDaysLate, LossProvisionStep::getPercentProvision));
 
-      IntStream.rangeClosed(9, 60)
+      IntStream.rangeClosed(9, 67)
           .forEach(day -> {
             try {
+              final int daysLate = day - 7;
               step6ICalculateInterestAndLossAllowancesForLateLoan(
                   referenceDate.plusDays(day),
-                  lossProvisionConfiguration.get(day-7));
+                  daysLate,
+                  lossProvisionConfiguration.get(daysLate));
             } catch (InterruptedException e) {
               throw new RuntimeException(e);
             }
@@ -750,6 +756,7 @@
 
   private void step6ICalculateInterestAndLossAllowancesForLateLoan(
       final LocalDateTime forDateTime,
+      final int daysLate,
       final @Nullable BigDecimal percentProvision) throws InterruptedException
   {
     logger.info("step6ICalculateInterestAndLossAllowancesForLateLoan  '{}'", forDateTime);
@@ -764,8 +771,14 @@
         .multiply(dailyInterestRate)
         .setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN);
 
+    final BigDecimal provisionForLosses = percentProvision == null ?
+        BigDecimal.ZERO :
+        expectedCurrentPrincipal.multiply(percentProvision.divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_HALF_EVEN))
+            .setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN);
+
     logger.info("calculatedInterest '{}'", calculatedInterest);
     logger.info("percentProvision '{}'", percentProvision);
+    logger.info("provisionForLosses '{}'", provisionForLosses);
 
 
     checkCostComponentForActionCorrect(
@@ -777,16 +790,16 @@
         forDateTime,
         MINOR_CURRENCY_UNIT_DIGITS);
 
-    if (percentProvision != null) {
-      checkCostComponentForActionCorrect(
-          product.getIdentifier(),
-          customerCase.getIdentifier(),
-          Action.MARK_IN_ARREARS,
-          null,
-          null,
-          forDateTime,
-          MINOR_CURRENCY_UNIT_DIGITS);
-    }
+    checkCostComponentForActionCorrect(
+        product.getIdentifier(),
+        customerCase.getIdentifier(),
+        Action.MARK_IN_ARREARS,
+        null,
+        BigDecimal.valueOf(daysLate),
+        forDateTime,
+        MINOR_CURRENCY_UNIT_DIGITS,
+        new CostComponent(ChargeIdentifiers.PROVISION_FOR_LOSSES_ID, provisionForLosses.negate()));
+
     final BeatPublish interestBeat = new BeatPublish(beatIdentifier, midnightTimeStamp);
     portfolioBeatListener.publishBeat(interestBeat);
     Assert.assertTrue(this.eventRecorder.wait(io.mifos.rhythm.spi.v1.events.EventConstants.POST_PUBLISHEDBEAT,
@@ -824,20 +837,15 @@
         customerCase.getIdentifier(), Action.APPLY_INTEREST);
 
     if (percentProvision != null) {
-      final BigDecimal calculatedProvisionForLosses =
-          expectedCurrentPrincipal.multiply(percentProvision.divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_HALF_EVEN))
-              .setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN);
-      logger.info("calculatedProvisionForLosses '{}'", calculatedProvisionForLosses);
-
       final Set<Debtor> lateFeeDebtors = new HashSet<>();
       lateFeeDebtors.add(new Debtor(
           AccountingFixture.GENERAL_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER,
-          calculatedProvisionForLosses.toPlainString()));
+          provisionForLosses.toPlainString()));
 
       final Set<Creditor> lateFeeCreditors = new HashSet<>();
       lateFeeCreditors.add(new Creditor(
           AccountingFixture.PRODUCT_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER,
-          calculatedProvisionForLosses.toPlainString()));
+          provisionForLosses.toPlainString()));
       AccountingFixture.verifyTransfer(
           ledgerManager,
           lateFeeDebtors,
@@ -845,7 +853,7 @@
           product.getIdentifier(),
           customerCase.getIdentifier(),
           Action.MARK_IN_ARREARS);
-      productLossAllowance = productLossAllowance.add(calculatedProvisionForLosses);
+      productLossAllowance = productLossAllowance.add(provisionForLosses);
     }
     interestAccrued = interestAccrued.add(calculatedInterest);
 
@@ -882,7 +890,6 @@
         Collections.singletonList(assignEntryToTeller()),
         amount,
         IndividualLoanEventConstants.ACCEPT_PAYMENT_INDIVIDUALLOAN_CASE,
-        midnightToday(),
         Case.State.ACTIVE); //Close has to be done explicitly.
     checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(), Action.APPLY_INTEREST,
         Action.APPLY_INTEREST, Action.MARK_LATE, Action.ACCEPT_PAYMENT, Action.DISBURSE, Action.MARK_IN_ARREARS, Action.WRITE_OFF, Action.CLOSE);
@@ -929,7 +936,7 @@
   private void step8Close(
       final LocalDateTime forDateTime) throws InterruptedException
   {
-    logger.info("step8Close");
+    logger.info("step8Close for '{}'", forDateTime);
 
     checkCostComponentForActionCorrect(
         product.getIdentifier(),
@@ -943,6 +950,7 @@
         product.getIdentifier(),
         customerCase.getIdentifier(),
         Action.CLOSE,
+        forDateTime,
         Collections.singletonList(assignEntryToTeller()),
         IndividualLoanEventConstants.CLOSE_INDIVIDUALLOAN_CASE,
         Case.State.CLOSED); //Close has to be done explicitly.
@@ -952,7 +960,7 @@
 
   private void step8IWriteOff(
       final LocalDateTime forDateTime) throws InterruptedException {
-    logger.info("step8IWriteOff");
+    logger.info("step8IWriteOff for '{}'", forDateTime);
 
     checkCostComponentForActionCorrect(
         product.getIdentifier(),
@@ -961,16 +969,32 @@
         null,
         null,
         forDateTime,
-        MINOR_CURRENCY_UNIT_DIGITS);
+        MINOR_CURRENCY_UNIT_DIGITS,
+        new CostComponent(ChargeIdentifiers.WRITE_OFF_ID, expectedCurrentPrincipal));
     checkStateTransfer(
         product.getIdentifier(),
         customerCase.getIdentifier(),
         Action.WRITE_OFF,
-        Collections.singletonList(assignEntryToTeller()),
+        forDateTime,
+        Collections.singletonList(assignExpenseToGeneralExpense()),
         IndividualLoanEventConstants.WRITE_OFF_INDIVIDUALLOAN_CASE,
         Case.State.CLOSED); //Close has to be done explicitly.
 
     checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier());
+
+    final Set<Debtor> debtors = new HashSet<>();
+    debtors.add(new Debtor(AccountingFixture.GENERAL_EXPENSE_ACCOUNT_IDENTIFIER, expectedCurrentPrincipal.toPlainString()));
+    //TODO:debtors.add(new Debtor(AccountingFixture.LATE_FEE_ACCRUAL_ACCOUNT_IDENTIFIER, lateFees.toPlainString()));
+    //TODO:debtors.add(new Debtor(AccountingFixture.LOAN_INTEREST_ACCRUAL_ACCOUNT_IDENTIFIER, interestAccrued.toPlainString()));
+
+    final Set<Creditor> creditors = new HashSet<>();
+    creditors.add(new Creditor(AccountingFixture.GENERAL_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER, expectedCurrentPrincipal.toPlainString()));
+    //TODO:creditors.add(new Creditor(AccountingFixture.PRODUCT_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER, lateFees.add(interestAccrued).toPlainString()));
+
+    AccountingFixture.verifyTransfer(ledgerManager, debtors, creditors, product.getIdentifier(), customerCase.getIdentifier(), Action.WRITE_OFF);
+
+    productLossAllowance = BigDecimal.ZERO;
+    updateBalanceMock();
   }
 
   private void updateBalanceMock() {
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 f184143..e6a2828 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestCommands.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestCommands.java
@@ -20,7 +20,6 @@
 import io.mifos.portfolio.api.v1.domain.Product;
 import org.junit.Test;
 
-import java.math.BigDecimal;
 import java.time.Clock;
 import java.time.LocalDateTime;
 import java.util.Collections;
@@ -36,57 +35,6 @@
   //public void testHappyWorkflow() throws InterruptedException
 
   @Test
-  public void testBadCustomerWorkflow() throws InterruptedException {
-    final Product product = createAndEnableProduct();
-    final Case customerCase = createCase(product.getIdentifier());
-
-    checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(), Action.OPEN);
-
-
-    checkStateTransfer(
-        product.getIdentifier(),
-        customerCase.getIdentifier(),
-        Action.OPEN,
-        Collections.singletonList(assignEntryToTeller()),
-        OPEN_INDIVIDUALLOAN_CASE,
-        Case.State.PENDING);
-    checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(), Action.APPROVE, Action.DENY);
-
-
-    checkStateTransfer(
-        product.getIdentifier(),
-        customerCase.getIdentifier(),
-        Action.APPROVE,
-        Collections.singletonList(assignEntryToTeller()),
-        APPROVE_INDIVIDUALLOAN_CASE,
-        Case.State.APPROVED);
-    checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(), Action.DISBURSE, Action.CLOSE);
-
-
-    checkStateTransfer(
-        product.getIdentifier(),
-        customerCase.getIdentifier(),
-        Action.DISBURSE,
-        LocalDateTime.now(Clock.systemUTC()),
-        Collections.singletonList(assignEntryToTeller()),
-        BigDecimal.valueOf(2000L),
-        DISBURSE_INDIVIDUALLOAN_CASE,
-        midnightToday(),
-        Case.State.ACTIVE);
-    checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(),
-            Action.APPLY_INTEREST, Action.MARK_LATE, Action.MARK_IN_ARREARS, Action.ACCEPT_PAYMENT, Action.DISBURSE, Action.WRITE_OFF, Action.CLOSE);
-
-    checkStateTransfer(
-        product.getIdentifier(),
-        customerCase.getIdentifier(),
-        Action.WRITE_OFF,
-        Collections.singletonList(assignEntryToTeller()),
-        WRITE_OFF_INDIVIDUALLOAN_CASE,
-        Case.State.CLOSED);
-    checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier());
-  }
-
-  @Test
   public void testApproveBeforeOpen() throws InterruptedException {
     final Product product = createAndEnableProduct();
     final Case customerCase = createCase(product.getIdentifier());
@@ -109,6 +57,7 @@
         product.getIdentifier(),
         customerCase.getIdentifier(),
         Action.OPEN,
+        LocalDateTime.now(Clock.systemUTC()),
         Collections.singletonList(assignEntryToTeller()),
         OPEN_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 0fef315..5aa6e7a 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestTaskInstances.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestTaskInstances.java
@@ -32,6 +32,8 @@
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.time.Clock;
+import java.time.LocalDateTime;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
@@ -204,6 +206,7 @@
         product.getIdentifier(),
         customerCase.getIdentifier(),
         Action.OPEN,
+        LocalDateTime.now(Clock.systemUTC()),
         Collections.singletonList(assignEntryToTeller()),
         IndividualLoanEventConstants.OPEN_INDIVIDUALLOAN_CASE,
         Case.State.PENDING);
diff --git a/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java b/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
index c286fcd..bf37c9c 100644
--- a/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
+++ b/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
@@ -106,7 +106,7 @@
         AccountDesignators.GENERAL_LOSS_ALLOWANCE,
         AccountType.EXPENSE.name()));
     individualLendingRequiredAccounts.add(new RequiredAccountAssignment(
-        AccountDesignators.GENERAL_EXPENSE,
+        AccountDesignators.EXPENSE,
         AccountType.EXPENSE.name()));
     individualLendingRequiredAccounts.add(new RequiredAccountAssignment(
         AccountDesignators.ENTRY,
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 840ab12..a12b605 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
@@ -48,8 +48,6 @@
 
 import javax.annotation.Nullable;
 import java.math.BigDecimal;
-import java.time.Clock;
-import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.util.Collections;
@@ -146,7 +144,6 @@
     final PaymentBuilder paymentBuilder
         = openPaymentBuilderService.getPaymentBuilder(dataContextOfAction, BigDecimal.ZERO, CostComponentService.today(), runningBalances);
 
-    final LocalDateTime today = today();
 
     final Optional<String> transactionUniqueifier = accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
         designatorToAccountIdentifierMapper,
@@ -167,7 +164,7 @@
     customerCase.setCurrentState(Case.State.PENDING.name());
     caseRepository.save(customerCase);
 
-    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, DateConverter.toIsoString(today));
+    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, command.getCommand().getCreatedOn());
   }
 
   @Transactional
@@ -193,7 +190,6 @@
     final PaymentBuilder paymentBuilder
         = denyPaymentBuilderService.getPaymentBuilder(dataContextOfAction, BigDecimal.ZERO, CostComponentService.today(), runningBalances);
 
-    final LocalDateTime today = today();
 
     final Optional<String> transactionUniqueifier = accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
         designatorToAccountIdentifierMapper,
@@ -213,7 +209,7 @@
     customerCase.setCurrentState(Case.State.CLOSED.name());
     caseRepository.save(customerCase);
 
-    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, DateConverter.toIsoString(today));
+    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, command.getCommand().getCreatedOn());
   }
 
   static class InterruptedInALambdaException extends RuntimeException {
@@ -288,8 +284,6 @@
     final PaymentBuilder paymentBuilder =
         approvePaymentBuilderService.getPaymentBuilder(dataContextOfAction, BigDecimal.ZERO, CostComponentService.today(), runningBalances);
 
-    final LocalDateTime today = today();
-
     final Optional<String> transactionUniqueifier = accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
         designatorToAccountIdentifierMapper,
         command.getCommand().getNote(),
@@ -309,7 +303,7 @@
     customerCase.setCurrentState(Case.State.APPROVED.name());
     caseRepository.save(customerCase);
 
-    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, DateConverter.toIsoString(today));
+    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, command.getCommand().getCreatedOn());
   }
 
   @Transactional
@@ -335,8 +329,6 @@
     final PaymentBuilder paymentBuilder =
         disbursePaymentBuilderService.getPaymentBuilder(dataContextOfAction, disbursalAmount, CostComponentService.today(), runningBalances);
 
-    final LocalDateTime today = today();
-
     final Optional<String> transactionUniqueifier = accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
         designatorToAccountIdentifierMapper,
         command.getCommand().getNote(),
@@ -355,7 +347,7 @@
     //Only move to new state if book charges command was accepted.
     if (Case.State.valueOf(dataContextOfAction.getCustomerCaseEntity().getCurrentState()) != Case.State.ACTIVE) {
       final LocalDateTime endOfTerm
-          = ScheduledActionHelpers.getRoughEndDate(today.toLocalDate(), dataContextOfAction.getCaseParameters())
+          = ScheduledActionHelpers.getRoughEndDate(DateConverter.fromIsoString(command.getCommand().getCreatedOn()).toLocalDate(), dataContextOfAction.getCaseParameters())
           .atTime(LocalTime.MIDNIGHT);
       customerCase.setEndOfTerm(endOfTerm);
       customerCase.setCurrentState(Case.State.ACTIVE.name());
@@ -370,7 +362,7 @@
     dataContextOfAction.getCaseParametersEntity().setPaymentSize(newLoanPaymentSize);
     caseParametersRepository.save(dataContextOfAction.getCaseParametersEntity());
 
-    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, DateConverter.toIsoString(today));
+    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, command.getCommand().getCreatedOn());
   }
 
   @Transactional
@@ -447,8 +439,6 @@
             command.getCommand().getPaymentSize(),
             DateConverter.fromIsoString(command.getCommand().getCreatedOn()).toLocalDate(), runningBalances);
 
-    final LocalDateTime today = today();
-
     final Optional<String> transactionUniqueifier = accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
         designatorToAccountIdentifierMapper,
         command.getCommand().getNote(),
@@ -467,7 +457,7 @@
     //TODO: Should this be more sophisticated?  Take into account what the payment amount was?
     markCaseNotLate(dataContextOfAction);
 
-    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, DateConverter.toIsoString(today));
+    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, command.getCommand().getCreatedOn());
   }
 
   @Transactional
@@ -590,8 +580,6 @@
             command.getCommand().getPaymentSize(),
             DateConverter.fromIsoString(command.getCommand().getCreatedOn()).toLocalDate(), runningBalances);
 
-    final LocalDateTime today = today();
-
     final Optional<String> transactionUniqueifier = accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
         designatorToAccountIdentifierMapper,
         command.getCommand().getNote(),
@@ -610,7 +598,7 @@
     customerCase.setCurrentState(Case.State.CLOSED.name());
     caseRepository.save(customerCase);
 
-    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, DateConverter.toIsoString(today));
+    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, command.getCommand().getCreatedOn());
   }
 
   @Transactional
@@ -634,8 +622,6 @@
     final PaymentBuilder paymentBuilder =
         closePaymentBuilderService.getPaymentBuilder(dataContextOfAction, BigDecimal.ZERO, CostComponentService.today(), runningBalances);
 
-    final LocalDateTime today = today();
-
     final Optional<String> transactionIdentifier = accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
         designatorToAccountIdentifierMapper,
         command.getCommand().getNote(),
@@ -647,7 +633,7 @@
     customerCase.setCurrentState(Case.State.CLOSED.name());
     caseRepository.save(customerCase);
 
-    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, DateConverter.toIsoString(today));
+    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, command.getCommand().getCreatedOn());
   }
 
   @Transactional
@@ -671,8 +657,6 @@
     final PaymentBuilder paymentBuilder =
         recoverPaymentBuilderService.getPaymentBuilder(dataContextOfAction, BigDecimal.ZERO, CostComponentService.today(), runningBalances);
 
-    final LocalDateTime today = today();
-
     final Optional<String> transactionUniqueifier = accountingAdapter.bookCharges(paymentBuilder.getBalanceAdjustments(),
         designatorToAccountIdentifierMapper,
         command.getCommand().getNote(),
@@ -691,7 +675,7 @@
     customerCase.setCurrentState(Case.State.CLOSED.name());
     caseRepository.save(customerCase);
 
-    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, DateConverter.toIsoString(today));
+    return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, command.getCommand().getCreatedOn());
   }
 
   private Map<String, BigDecimal> getRequestedChargeAmounts(final @Nullable List<CostComponent> costComponents) {
@@ -746,8 +730,4 @@
       final DataContextOfAction dataContextOfAction) {
     lateCaseRepository.deleteByCaseId(dataContextOfAction.getCustomerCaseEntity().getId());
   }
-
-  private static LocalDateTime today() {
-    return LocalDate.now(Clock.systemUTC()).atStartOfDay();
-  }
 }
\ No newline at end of file
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 d55d9f3..580293f 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
@@ -50,7 +50,7 @@
     this.put(AccountDesignators.LATE_FEE_ACCRUAL, positive);
     this.put(AccountDesignators.PRODUCT_LOSS_ALLOWANCE, negative);
     this.put(AccountDesignators.GENERAL_LOSS_ALLOWANCE, negative);
-    this.put(AccountDesignators.GENERAL_EXPENSE, negative);
+    this.put(AccountDesignators.EXPENSE, negative);
     this.put(AccountDesignators.ENTRY, positive);
     //TODO: derive signs from IndividualLendingPatternFactory.individualLendingRequiredAccounts instead.
   }};
@@ -99,6 +99,7 @@
 
   default BigDecimal getMaxCredit(final String accountDesignator, final BigDecimal amount) {
     if (accountDesignator.equals(AccountDesignators.ENTRY) ||
+        accountDesignator.equals(AccountDesignators.EXPENSE) ||
         accountDesignator.equals(AccountDesignators.PRODUCT_LOSS_ALLOWANCE))
       return amount;
     //entry account can achieve a "relative" negative balance, and
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/WriteOffPaymentBuilderService.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/WriteOffPaymentBuilderService.java
index 3dab27b..c51a300 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/WriteOffPaymentBuilderService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/WriteOffPaymentBuilderService.java
@@ -15,13 +15,14 @@
  */
 package io.mifos.individuallending.internal.service.costcomponent;
 
+import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
+import io.mifos.individuallending.api.v1.domain.product.ChargeProportionalDesignator;
 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.ScheduledCharge;
-import io.mifos.individuallending.internal.service.schedule.ScheduledChargesService;
-import org.springframework.beans.factory.annotation.Autowired;
+import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Nonnull;
@@ -30,19 +31,16 @@
 import java.time.LocalDate;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
+
+import static io.mifos.individuallending.api.v1.domain.product.ChargeIdentifiers.WRITE_OFF_ID;
+import static io.mifos.individuallending.api.v1.domain.product.ChargeIdentifiers.WRITE_OFF_NAME;
 
 /**
  * @author Myrle Krantz
  */
 @Service
 public class WriteOffPaymentBuilderService implements PaymentBuilderService {
-  private final ScheduledChargesService scheduledChargesService;
-
-  @Autowired
-  public WriteOffPaymentBuilderService(final ScheduledChargesService scheduledChargesService) {
-    this.scheduledChargesService = scheduledChargesService;
-  }
-
   @Override
   public PaymentBuilder getPaymentBuilder(
       final @Nonnull DataContextOfAction dataContextOfAction,
@@ -51,11 +49,10 @@
       final RunningBalances runningBalances)
   {
     final CaseParametersEntity caseParameters = dataContextOfAction.getCaseParametersEntity();
-    final String productIdentifier = dataContextOfAction.getProductEntity().getIdentifier();
     final int minorCurrencyUnitDigits = dataContextOfAction.getProductEntity().getMinorCurrencyUnitDigits();
-    final List<ScheduledAction> scheduledActions = Collections.singletonList(new ScheduledAction(Action.WRITE_OFF, forDate));
-    final List<ScheduledCharge> scheduledCharges = scheduledChargesService.getScheduledCharges(
-        productIdentifier, scheduledActions);
+
+    final List<ScheduledCharge> scheduledCharges
+        = Collections.singletonList(getScheduledChargeForWriteOff(forDate));
 
     final BigDecimal loanPaymentSize = dataContextOfAction.getCaseParametersEntity().getPaymentSize();
 
@@ -70,4 +67,22 @@
         minorCurrencyUnitDigits,
         true);
   }
+
+
+  private ScheduledCharge getScheduledChargeForWriteOff(final LocalDate forDate) {
+
+    final ChargeDefinition chargeDefinition = new ChargeDefinition();
+    chargeDefinition.setChargeAction(Action.WRITE_OFF.name());
+    chargeDefinition.setIdentifier(WRITE_OFF_ID);
+    chargeDefinition.setName(WRITE_OFF_NAME);
+    chargeDefinition.setDescription(WRITE_OFF_NAME);
+    chargeDefinition.setFromAccountDesignator(AccountDesignators.EXPENSE);
+    chargeDefinition.setToAccountDesignator(AccountDesignators.GENERAL_LOSS_ALLOWANCE);
+    chargeDefinition.setProportionalTo(ChargeProportionalDesignator.PRINCIPAL_DESIGNATOR.getValue());
+    chargeDefinition.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL);
+    chargeDefinition.setAmount(BigDecimal.valueOf(100));
+    chargeDefinition.setReadOnly(true);
+    final ScheduledAction scheduledAction = new ScheduledAction(Action.WRITE_OFF, forDate);
+    return new ScheduledCharge(scheduledAction, chargeDefinition, Optional.empty());
+  }
 }
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/schedule/LossProvisionChargesService.java b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/LossProvisionChargesService.java
index 6265bb5..a06707c 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/schedule/LossProvisionChargesService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/LossProvisionChargesService.java
@@ -29,8 +29,7 @@
 import java.time.LocalDate;
 import java.util.Optional;
 
-import static io.mifos.individuallending.api.v1.domain.product.ChargeIdentifiers.PROVISION_FOR_LOSSES_ID;
-import static io.mifos.individuallending.api.v1.domain.product.ChargeIdentifiers.PROVISION_FOR_LOSSES_NAME;
+import static io.mifos.individuallending.api.v1.domain.product.ChargeIdentifiers.*;
 
 /**
  * @author Myrle Krantz
@@ -88,14 +87,12 @@
       final BigDecimal percentProvision,
       final Action action) {
     final ChargeDefinition ret = new ChargeDefinition();
-    ret.setChargeAction(Action.WRITE_OFF.name());
+    ret.setChargeAction(action.name());
     ret.setIdentifier(PROVISION_FOR_LOSSES_ID);
     ret.setName(PROVISION_FOR_LOSSES_NAME);
     ret.setDescription(PROVISION_FOR_LOSSES_NAME);
     ret.setFromAccountDesignator(AccountDesignators.PRODUCT_LOSS_ALLOWANCE);
-    ret.setAccrualAccountDesignator(AccountDesignators.GENERAL_LOSS_ALLOWANCE);
-    ret.setAccrueAction(action.name());
-    ret.setToAccountDesignator(AccountDesignators.GENERAL_EXPENSE);
+    ret.setToAccountDesignator(AccountDesignators.GENERAL_LOSS_ALLOWANCE);
     ret.setProportionalTo(ChargeProportionalDesignator.PRINCIPAL_DESIGNATOR.getValue());
     ret.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL);
     ret.setAmount(percentProvision.negate());
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/mapper/ChargeDefinitionMapper.java b/service/src/main/java/io/mifos/portfolio/service/internal/mapper/ChargeDefinitionMapper.java
index fba4800..a56fecd 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/mapper/ChargeDefinitionMapper.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/mapper/ChargeDefinitionMapper.java
@@ -77,7 +77,7 @@
     ret.setFromAccountDesignator(from.getFromAccountDesignator());
     ret.setAccrualAccountDesignator(from.getAccrualAccountDesignator());
     ret.setToAccountDesignator(from.getToAccountDesignator());
-    ret.setReadOnly(Optional.ofNullable(from.getReadOnly()).orElseGet(() -> readOnlyLegacyMapper(from.getIdentifier())));
+    ret.setReadOnly(Optional.ofNullable(from.getReadOnly()).orElse(false));
     if (from.getSegmentSet() != null && from.getFromSegment() != null && from.getToSegment() != null) {
       ret.setForSegmentSet(from.getSegmentSet());
       ret.setFromSegment(from.getFromSegment());
@@ -88,29 +88,6 @@
     return ret;
   }
 
-  private static Boolean readOnlyLegacyMapper(final String identifier) {
-    switch (identifier) {
-      case INTEREST_ID:
-        return false;
-      case ALLOW_FOR_WRITE_OFF_ID:
-        return false;
-      case LATE_FEE_ID:
-        return true;
-      case DISBURSEMENT_FEE_ID:
-        return false;
-      case DISBURSE_PAYMENT_ID:
-        return false;
-      case LOAN_ORIGINATION_FEE_ID:
-        return true;
-      case PROCESSING_FEE_ID:
-        return true;
-      case REPAY_PRINCIPAL_ID:
-        return false;
-      default:
-        return false;
-    }
-  }
-
   private static String proportionalToLegacyMapper(final ChargeDefinitionEntity from,
                                                    final ChargeDefinition.ChargeMethod chargeMethod,
                                                    final String identifier) {
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/WriteOffPaymentBuilderServiceTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/WriteOffPaymentBuilderServiceTest.java
new file mode 100644
index 0000000..3dd53e1
--- /dev/null
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/costcomponent/WriteOffPaymentBuilderServiceTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * 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.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 org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author Myrle Krantz
+ */
+@RunWith(Parameterized.class)
+public class WriteOffPaymentBuilderServiceTest {
+
+  @Parameterized.Parameters
+  public static Collection testCases() {
+    final Collection<PaymentBuilderServiceTestCase> ret = new ArrayList<>();
+    ret.add(simpleCase());
+    //TODO: add use case for when the general loss allowance account doesn't have enough to cover the write off.
+    return ret;
+  }
+
+  private static PaymentBuilderServiceTestCase simpleCase() {
+    final PaymentBuilderServiceTestCase ret = new PaymentBuilderServiceTestCase("simple case");
+    ret.runningBalances.adjustBalance(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, ret.balance.negate());
+    ret.runningBalances.adjustBalance(AccountDesignators.GENERAL_LOSS_ALLOWANCE, ret.balance.negate());
+    return ret;
+  }
+
+  private final PaymentBuilderServiceTestCase testCase;
+
+  public WriteOffPaymentBuilderServiceTest(final PaymentBuilderServiceTestCase testCase) {
+    this.testCase = testCase;
+  }
+
+  @Test
+  public void getPaymentBuilder() throws Exception {
+    final PaymentBuilder paymentBuilder = PaymentBuilderServiceTestHarness.constructCallToPaymentBuilder(
+        (scheduledChargesService) -> new WriteOffPaymentBuilderService(), testCase);
+
+    final Payment payment = paymentBuilder.buildPayment(Action.WRITE_OFF, 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(
+        testCase.balance,
+        mappedCostComponents.get(ChargeIdentifiers.WRITE_OFF_ID).getAmount());
+  }
+
+}