Added product arrears configuration, and began drawing on it to
calculate loan loss provisioning upon disbursement.
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 3fd48ff..fb78e89 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
@@ -35,6 +35,8 @@
   String INTEREST_ACCRUAL = "ia";
   String LATE_FEE_INCOME = "lfi";
   String LATE_FEE_ACCRUAL = "lfa";
-  String ARREARS_ALLOWANCE = "aa";
+  String PRODUCT_LOSS_ALLOWANCE = "pa";
+  String GENERAL_LOSS_ALLOWANCE = "aa";
+  String GENERAL_EXPENSE = "ge";
   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 2f570ac..8167c85 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
@@ -42,6 +42,8 @@
   String REPAY_INTEREST_ID = "repay-interest";
   String REPAY_FEES_NAME = "Repay fees";
   String REPAY_FEES_ID = "repay-fees";
+  String PROVISION_FOR_LOSSES_NAME = "Provision for losses";
+  String PROVISION_FOR_LOSSES_ID = "loss-provisioning";
 
   static String nameToIdentifier(String name) {
     return name.toLowerCase(Locale.US).replace(" ", "-");
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 3a77a72..5054006 100644
--- a/component-test/src/main/java/io/mifos/portfolio/Fixture.java
+++ b/component-test/src/main/java/io/mifos/portfolio/Fixture.java
@@ -67,7 +67,9 @@
     accountAssignments.add(new AccountAssignment(INTEREST_ACCRUAL, LOAN_INTEREST_ACCRUAL_ACCOUNT_IDENTIFIER));
     accountAssignments.add(new AccountAssignment(LATE_FEE_INCOME, LATE_FEE_INCOME_ACCOUNT_IDENTIFIER));
     accountAssignments.add(new AccountAssignment(LATE_FEE_ACCRUAL, LATE_FEE_ACCRUAL_ACCOUNT_IDENTIFIER));
-    accountAssignments.add(new AccountAssignment(ARREARS_ALLOWANCE, ARREARS_ALLOWANCE_ACCOUNT_IDENTIFIER));
+    accountAssignments.add(new AccountAssignment(PRODUCT_LOSS_ALLOWANCE, ARREARS_ALLOWANCE_ACCOUNT_IDENTIFIER));
+    accountAssignments.add(new AccountAssignment(GENERAL_LOSS_ALLOWANCE, ARREARS_ALLOWANCE_ACCOUNT_IDENTIFIER));
+    accountAssignments.add(new AccountAssignment(GENERAL_EXPENSE, ARREARS_ALLOWANCE_ACCOUNT_IDENTIFIER));
     //accountAssignments.add(new AccountAssignment(ENTRY, ...));
     // Don't assign entry account in test since it usually will not be assigned IRL.
     accountAssignments.add(new AccountAssignment(LOAN_FUNDS_SOURCE, LOAN_FUNDS_SOURCE_ACCOUNT_IDENTIFIER));
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestChargeDefinitions.java b/component-test/src/main/java/io/mifos/portfolio/TestChargeDefinitions.java
index 36e1023..59c0c31 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestChargeDefinitions.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestChargeDefinitions.java
@@ -75,7 +75,7 @@
     chargeDefinitionToDelete.setDescription("blah blah blah");
     chargeDefinitionToDelete.setChargeAction(Action.APPROVE.name());
     chargeDefinitionToDelete.setChargeMethod(ChargeDefinition.ChargeMethod.FIXED);
-    chargeDefinitionToDelete.setToAccountDesignator(AccountDesignators.ARREARS_ALLOWANCE);
+    chargeDefinitionToDelete.setToAccountDesignator(AccountDesignators.GENERAL_LOSS_ALLOWANCE);
     chargeDefinitionToDelete.setFromAccountDesignator(AccountDesignators.INTEREST_ACCRUAL);
     portfolioManager.createChargeDefinition(product.getIdentifier(), chargeDefinitionToDelete);
     Assert.assertTrue(this.eventRecorder.wait(EventConstants.POST_CHARGE_DEFINITION,
diff --git a/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java b/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
index cf00030..59c2f47 100644
--- a/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
+++ b/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
@@ -100,8 +100,14 @@
         AccountDesignators.LATE_FEE_ACCRUAL,
         AccountType.REVENUE.name()));
     individualLendingRequiredAccounts.add(new RequiredAccountAssignment(
-        AccountDesignators.ARREARS_ALLOWANCE,
-        AccountType.LIABILITY.name())); //TODO: type?
+        AccountDesignators.PRODUCT_LOSS_ALLOWANCE,
+        AccountType.ASSET.name()));
+    individualLendingRequiredAccounts.add(new RequiredAccountAssignment(
+        AccountDesignators.GENERAL_LOSS_ALLOWANCE,
+        AccountType.EXPENSE.name()));
+    individualLendingRequiredAccounts.add(new RequiredAccountAssignment(
+        AccountDesignators.GENERAL_EXPENSE,
+        AccountType.EXPENSE.name()));
     individualLendingRequiredAccounts.add(new RequiredAccountAssignment(
         AccountDesignators.ENTRY,
         AccountType.LIABILITY.name()));
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/ChargeDefinitionService.java b/service/src/main/java/io/mifos/individuallending/internal/service/ChargeDefinitionService.java
index 413668f..78d8ef5 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/ChargeDefinitionService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/ChargeDefinitionService.java
@@ -102,22 +102,14 @@
     disbursePayment.setAmount(BigDecimal.valueOf(100));
     disbursePayment.setReadOnly(true);
 
-    //TODO: Make multiple write off allowance defaultCharges.
-    /*final ChargeDefinition writeOffAllowanceCharge = charge(
-        ALLOW_FOR_WRITE_OFF_NAME,
-        Action.MARK_LATE,
-        BigDecimal.valueOf(30),
-        AccountDesignators.LOAN_FUNDS_SOURCE,
-        AccountDesignators.ARREARS_ALLOWANCE);
-    writeOffAllowanceCharge.setProportionalTo(ChargeProportionalDesignator.RUNNING_BALANCE_DESIGNATOR.getValue());
-    writeOffAllowanceCharge.setReadOnly(true);*/
-
-    final ChargeDefinition interestCharge = charge(
-        INTEREST_NAME,
-        Action.ACCEPT_PAYMENT,
-        BigDecimal.valueOf(100),
-        AccountDesignators.CUSTOMER_LOAN_INTEREST,
-        AccountDesignators.INTEREST_INCOME);
+    final ChargeDefinition interestCharge = new ChargeDefinition();
+    interestCharge.setIdentifier(INTEREST_ID);
+    interestCharge.setName(INTEREST_NAME);
+    interestCharge.setDescription(INTEREST_NAME);
+    interestCharge.setChargeAction(Action.ACCEPT_PAYMENT.name());
+    interestCharge.setAmount(BigDecimal.valueOf(100));
+    interestCharge.setFromAccountDesignator(AccountDesignators.CUSTOMER_LOAN_INTEREST);
+    interestCharge.setToAccountDesignator(AccountDesignators.INTEREST_INCOME);
     interestCharge.setForCycleSizeUnit(ChronoUnit.YEARS);
     interestCharge.setAccrueAction(Action.APPLY_INTEREST.name());
     interestCharge.setAccrualAccountDesignator(AccountDesignators.INTEREST_ACCRUAL);
@@ -162,7 +154,6 @@
     customerPrincipalRepaymentCharge.setReadOnly(true);
 
     ret.add(disbursePayment);
-    //ret.add(writeOffAllowanceCharge);
     ret.add(interestCharge);
     ret.add(customerPrincipalRepaymentCharge);
     ret.add(customerInterestRepaymentCharge);
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/DataContextOfAction.java b/service/src/main/java/io/mifos/individuallending/internal/service/DataContextOfAction.java
index 597bf00..03c1fac 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/DataContextOfAction.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/DataContextOfAction.java
@@ -21,6 +21,7 @@
 import io.mifos.individuallending.internal.repository.CaseParametersEntity;
 import io.mifos.portfolio.api.v1.domain.AccountAssignment;
 import io.mifos.portfolio.service.internal.repository.CaseEntity;
+import io.mifos.portfolio.service.internal.repository.ProductArrearsConfigurationEntity;
 import io.mifos.portfolio.service.internal.repository.ProductEntity;
 
 import javax.annotation.Nonnull;
@@ -36,15 +37,20 @@
   private final ProductEntity product;
   private final CaseEntity customerCase;
   private final CaseParametersEntity caseParameters;
+  private final List<ProductArrearsConfigurationEntity> productArrearsConfigurationEntities;
   private final List<AccountAssignment> oneTimeAccountAssignments;
 
-  public DataContextOfAction(final @Nonnull ProductEntity product,
-                             final @Nonnull CaseEntity customerCase,
-                             final @Nonnull CaseParametersEntity caseParameters,
-                             final @Nullable List<AccountAssignment> oneTimeAccountAssignments) {
+  public DataContextOfAction(
+      final @Nonnull ProductEntity product,
+      final @Nonnull CaseEntity customerCase,
+      final @Nonnull CaseParametersEntity caseParameters,
+      final List<ProductArrearsConfigurationEntity> productArrearsConfigurationEntities,
+      final @Nullable List<AccountAssignment> oneTimeAccountAssignments)
+  {
     this.product = product;
     this.customerCase = customerCase;
     this.caseParameters = caseParameters;
+    this.productArrearsConfigurationEntities = productArrearsConfigurationEntities;
     this.oneTimeAccountAssignments = oneTimeAccountAssignments == null ? Collections.emptyList() : oneTimeAccountAssignments;
   }
 
@@ -64,6 +70,10 @@
     return CaseParametersMapper.mapEntity(caseParameters, product.getMinorCurrencyUnitDigits());
   }
 
+  public @Nonnull List<ProductArrearsConfigurationEntity> getProductArrearsConfigurationEntities() {
+    return productArrearsConfigurationEntities;
+  }
+
   @Nonnull List<AccountAssignment> getOneTimeAccountAssignments() {
     return oneTimeAccountAssignments;
   }
@@ -79,4 +89,4 @@
   public BigDecimal getInterest() {
     return customerCase.getInterest();
   }
-}
+}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/DataContextService.java b/service/src/main/java/io/mifos/individuallending/internal/service/DataContextService.java
index 388ae0c..eb04895 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/DataContextService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/DataContextService.java
@@ -19,10 +19,7 @@
 import io.mifos.individuallending.internal.repository.CaseParametersEntity;
 import io.mifos.individuallending.internal.repository.CaseParametersRepository;
 import io.mifos.portfolio.api.v1.domain.AccountAssignment;
-import io.mifos.portfolio.service.internal.repository.CaseEntity;
-import io.mifos.portfolio.service.internal.repository.CaseRepository;
-import io.mifos.portfolio.service.internal.repository.ProductEntity;
-import io.mifos.portfolio.service.internal.repository.ProductRepository;
+import io.mifos.portfolio.service.internal.repository.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -37,15 +34,18 @@
   private final ProductRepository productRepository;
   private final CaseRepository caseRepository;
   private final CaseParametersRepository caseParametersRepository;
+  private final ProductArrearsConfigurationRepository productArrearsConfigurationRepository;
 
   @Autowired
   public DataContextService(
       final ProductRepository productRepository,
       final CaseRepository caseRepository,
-      final CaseParametersRepository caseParametersRepository) {
+      final CaseParametersRepository caseParametersRepository,
+      final ProductArrearsConfigurationRepository productArrearsConfigurationRepository) {
     this.productRepository = productRepository;
     this.caseRepository = caseRepository;
     this.caseParametersRepository = caseParametersRepository;
+    this.productArrearsConfigurationRepository = productArrearsConfigurationRepository;
   }
 
   public DataContextOfAction checkedGetDataContext(
@@ -66,6 +66,14 @@
                 "Individual loan not found ''{0}.{1}''.",
                 productIdentifier, caseIdentifier));
 
-    return new DataContextOfAction(product, customerCase, caseParameters, oneTimeAccountAssignments);
+    final List<ProductArrearsConfigurationEntity> productArrearsConfigurationEntities
+        = productArrearsConfigurationRepository.findByProductId(product.getId());
+
+    return new DataContextOfAction(
+        product,
+        customerCase,
+        caseParameters,
+        productArrearsConfigurationEntities,
+        oneTimeAccountAssignments);
   }
-}
+}
\ No newline at end of file
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 fd62325..6bb7b51 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
@@ -51,7 +51,7 @@
       final BigDecimal contractualRepayment,
       final BigDecimal requestedDisbursement,
       final BigDecimal requestedRepayment,
-      final BigDecimal interest,
+      final BigDecimal percentPoints,
       final int minorCurrencyUnitDigits,
       final boolean accrualAccounting) {
     final PaymentBuilder paymentBuilder = new PaymentBuilder(preChargeBalances, accrualAccounting);
@@ -73,7 +73,7 @@
               !x.amountIsWithinRange(amountProportionalTo)).orElse(false))
             continue;
 
-          chargeAmount = howToApplyScheduledChargeToAmount(scheduledCharge, interest)
+          chargeAmount = howToApplyScheduledChargeToAmount(scheduledCharge, percentPoints)
               .apply(amountProportionalTo)
               .setScale(minorCurrencyUnitDigits, BigDecimal.ROUND_HALF_EVEN);
         }
@@ -156,7 +156,7 @@
   }
 
   private static Function<BigDecimal, BigDecimal> howToApplyScheduledChargeToAmount(
-      final ScheduledCharge scheduledCharge, final BigDecimal interest)
+      final ScheduledCharge scheduledCharge, final BigDecimal percentPoints)
   {
     switch (scheduledCharge.getChargeDefinition().getChargeMethod())
     {
@@ -168,7 +168,7 @@
         return chargeAmountPerPeriod::multiply;
       }
       case INTEREST: {
-        final BigDecimal chargeAmountPerPeriod = PeriodChargeCalculator.chargeAmountPerPeriod(scheduledCharge, interest, RUNNING_CALCULATION_PRECISION);
+        final BigDecimal chargeAmountPerPeriod = PeriodChargeCalculator.chargeAmountPerPeriod(scheduledCharge, percentPoints, RUNNING_CALCULATION_PRECISION);
         return chargeAmountPerPeriod::multiply;
       }
       default: {
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 5b909eb..57a80f4 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,10 +20,7 @@
 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.individuallending.internal.service.schedule.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -33,6 +30,7 @@
 import java.time.LocalDate;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 /**
  * @author Myrle Krantz
@@ -40,11 +38,14 @@
 @Service
 public class DisbursePaymentBuilderService implements PaymentBuilderService {
   private final ScheduledChargesService scheduledChargesService;
+  private final LossProvisioningService lossProvisioningService;
 
   @Autowired
   public DisbursePaymentBuilderService(
-      final ScheduledChargesService scheduledChargesService) {
+      final ScheduledChargesService scheduledChargesService,
+      final LossProvisioningService lossProvisioningService) {
     this.scheduledChargesService = scheduledChargesService;
+    this.lossProvisioningService = lossProvisioningService;
   }
 
   @Override
@@ -74,7 +75,9 @@
 
     final List<ScheduledCharge> scheduledCharges = scheduledChargesService.getScheduledCharges(
         productIdentifier, scheduledActions);
-
+    final Optional<ScheduledCharge> initialLossProvisionCharge = lossProvisioningService.getScheduledChargeForDisbursement(
+        dataContextOfAction, forDate);
+    initialLossProvisionCharge.ifPresent(scheduledCharges::add);
 
     return CostComponentService.getCostComponentsForScheduledCharges(
         scheduledCharges,
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 db7ecb9..31f325f 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
@@ -48,8 +48,11 @@
     this.put(AccountDesignators.INTEREST_ACCRUAL, positive);
     this.put(AccountDesignators.LATE_FEE_INCOME, positive);
     this.put(AccountDesignators.LATE_FEE_ACCRUAL, positive);
-    this.put(AccountDesignators.ARREARS_ALLOWANCE, positive);
+    this.put(AccountDesignators.PRODUCT_LOSS_ALLOWANCE, negative);
+    this.put(AccountDesignators.GENERAL_LOSS_ALLOWANCE, negative);
+    this.put(AccountDesignators.GENERAL_EXPENSE, negative);
     this.put(AccountDesignators.ENTRY, positive);
+    //TODO: derive signs from IndividualLendingPatternFactory.individualLendingRequiredAccounts instead.
   }};
 
   BigDecimal getAccountBalance(final String accountDesignator);
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/schedule/LossProvisioningService.java b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/LossProvisioningService.java
new file mode 100644
index 0000000..bdfb7fe
--- /dev/null
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/LossProvisioningService.java
@@ -0,0 +1,102 @@
+/*
+ * 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.schedule;
+
+import io.mifos.core.lang.ServiceException;
+import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
+import io.mifos.individuallending.api.v1.domain.product.ChargeProportionalDesignator;
+import io.mifos.individuallending.api.v1.domain.workflow.Action;
+import io.mifos.individuallending.internal.service.DataContextOfAction;
+import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
+import io.mifos.portfolio.service.internal.repository.ProductArrearsConfigurationEntity;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+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;
+
+/**
+ * @author Myrle Krantz
+ */
+@Service
+public class LossProvisioningService {
+  public Optional<ScheduledCharge> getScheduledChargeForMarkLate(
+      final DataContextOfAction dataContextOfAction,
+      final LocalDate forDate,
+      final int daysLate)
+  {
+    return getScheduledLossProvisioningCharge(dataContextOfAction, forDate, daysLate, Action.MARK_LATE);
+  }
+
+
+  public Optional<ScheduledCharge> getScheduledChargeForDisbursement(
+      final DataContextOfAction dataContextOfAction,
+      final LocalDate forDate)
+  {
+    return getScheduledLossProvisioningCharge(dataContextOfAction, forDate, 0, Action.DISBURSE);
+  }
+
+  private Optional<ScheduledCharge> getScheduledLossProvisioningCharge(
+      final DataContextOfAction dataContextOfAction,
+      final LocalDate forDate,
+      final int daysLate, Action action) {
+    final Optional<ChargeDefinition> optionalChargeDefinition = percentProvision(dataContextOfAction, daysLate)
+        .map(this::getLossProvisionCharge);
+
+    return optionalChargeDefinition.map(chargeDefinition -> {
+      final ScheduledAction scheduledAction = new ScheduledAction(action, forDate);
+      return new ScheduledCharge(scheduledAction, chargeDefinition, Optional.empty());
+    });
+  }
+
+  private Optional<BigDecimal> percentProvision(
+      final DataContextOfAction dataContextOfAction,
+      final int daysLate)
+  {
+    final List<ProductArrearsConfigurationEntity> arrearsConfigurationForGivenDaysLate =
+        dataContextOfAction.getProductArrearsConfigurationEntities().stream()
+            .filter(x -> x.getDaysLate() == daysLate)
+            .collect(Collectors.toList());
+
+    if (arrearsConfigurationForGivenDaysLate.size() > 1)
+      throw ServiceException.internalError("There should not be more than one arrears allocation for given # of days late.");
+    if (arrearsConfigurationForGivenDaysLate.size() == 0)
+      return Optional.empty(); //None
+
+    return Optional.of(arrearsConfigurationForGivenDaysLate.get(0).getPercentProvision());
+  }
+
+  private ChargeDefinition getLossProvisionCharge(final BigDecimal percentProvision) {
+    final ChargeDefinition ret = new ChargeDefinition();
+    ret.setChargeAction(Action.MARK_LATE.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.setToAccountDesignator(AccountDesignators.GENERAL_EXPENSE);
+    ret.setProportionalTo(ChargeProportionalDesignator.PRINCIPAL_DESIGNATOR.getValue());
+    ret.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL);
+    ret.setAmount(percentProvision);
+    ret.setReadOnly(true);
+    return ret;
+  }
+}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledAction.java b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledAction.java
index bca424a..098877e 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledAction.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledAction.java
@@ -26,32 +26,35 @@
  * @author Myrle Krantz
  */
 public class ScheduledAction {
-  final Action action;
-  final LocalDate when;
+  private final Action action;
+  private final LocalDate when;
   private final @Nullable Period actionPeriod;
   private final @Nullable Period repaymentPeriod;
 
-  public ScheduledAction(@Nonnull final Action action,
-                         @Nonnull final LocalDate when,
-                         @Nonnull final Period actionPeriod,
-                         @Nonnull final Period repaymentPeriod) {
+  public ScheduledAction(
+      @Nonnull final Action action,
+      @Nonnull final LocalDate when,
+      @Nonnull final Period actionPeriod,
+      @Nonnull final Period repaymentPeriod) {
     this.action = action;
     this.when = when;
     this.actionPeriod = actionPeriod;
     this.repaymentPeriod = repaymentPeriod;
   }
 
-  public ScheduledAction(@Nonnull final Action action,
-                  @Nonnull final LocalDate when,
-                  @Nonnull final Period actionPeriod) {
+  public ScheduledAction(
+      @Nonnull final Action action,
+      @Nonnull final LocalDate when,
+      @Nonnull final Period actionPeriod) {
     this.action = action;
     this.when = when;
     this.actionPeriod = actionPeriod;
     this.repaymentPeriod = null;
   }
 
-  public ScheduledAction(@Nonnull final Action action,
-                  @Nonnull final LocalDate when) {
+  public ScheduledAction(
+      @Nonnull final Action action,
+      @Nonnull final LocalDate when) {
     this.action = action;
     this.when = when;
     this.actionPeriod = null;
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledActionHelpers.java b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledActionHelpers.java
index af85844..1807136 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledActionHelpers.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledActionHelpers.java
@@ -61,7 +61,7 @@
     final LocalDate effectiveEndOfTerm = fromDate.isAfter(endOfTerm) ? fromDate : endOfTerm;
 
     return getHypotheticalScheduledActionsForDisbursedLoan(startOfTerm, effectiveEndOfTerm, caseParameters)
-        .filter(x -> x.action.equals(Action.ACCEPT_PAYMENT))
+        .filter(x -> x.getAction().equals(Action.ACCEPT_PAYMENT))
         .filter(x -> x.actionIsOnOrAfter(fromDate))
         .findFirst()
         .orElseGet(() -> new ScheduledAction(Action.ACCEPT_PAYMENT, fromDate));
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargeComparator.java b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargeComparator.java
index 5840cdb..9478c28 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargeComparator.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargeComparator.java
@@ -33,11 +33,11 @@
   }
 
   static int compareScheduledCharges(ScheduledCharge o1, ScheduledCharge o2) {
-    int ret = o1.getScheduledAction().when.compareTo(o2.getScheduledAction().when);
+    int ret = o1.getScheduledAction().getWhen().compareTo(o2.getScheduledAction().getWhen());
     if (ret != 0)
       return ret;
 
-    ret = o1.getScheduledAction().action.compareTo(o2.getScheduledAction().action);
+    ret = o1.getScheduledAction().getAction().compareTo(o2.getScheduledAction().getAction());
     if (ret != 0)
       return ret;
 
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargesService.java b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargesService.java
index 9ec708f..bd18737 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargesService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/schedule/ScheduledChargesService.java
@@ -147,13 +147,13 @@
       final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByAccrueAction,
       final ScheduledAction scheduledAction) {
     final List<ChargeDefinition> chargeMappingList = chargeDefinitionsMappedByChargeAction
-        .get(scheduledAction.action.name());
+        .get(scheduledAction.getAction().name());
     Stream<ChargeDefinition> chargeMapping = chargeMappingList == null ? Stream.empty() : chargeMappingList.stream();
     if (chargeMapping == null)
       chargeMapping = Stream.empty();
 
     final List<ChargeDefinition> accrueMappingList = chargeDefinitionsMappedByAccrueAction
-        .get(scheduledAction.action.name());
+        .get(scheduledAction.getAction().name());
     Stream<ChargeDefinition> accrueMapping = accrueMappingList == null ? Stream.empty() : accrueMappingList.stream();
     if (accrueMapping == null)
       accrueMapping = Stream.empty();
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/repository/ProductArrearsConfigurationEntity.java b/service/src/main/java/io/mifos/portfolio/service/internal/repository/ProductArrearsConfigurationEntity.java
new file mode 100644
index 0000000..f2ff9b9
--- /dev/null
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/repository/ProductArrearsConfigurationEntity.java
@@ -0,0 +1,88 @@
+/*
+ * 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.portfolio.service.internal.repository;
+
+import javax.persistence.*;
+import java.math.BigDecimal;
+import java.util.Objects;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings("unused")
+@Entity
+@Table(name = "bastet_p_arrears_config")
+public class ProductArrearsConfigurationEntity {
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id")
+  private Long id;
+
+  @Column(name = "product_id", nullable = false)
+  private Long productId;
+
+  @Column(name = "days_late", nullable = false)
+  private Integer daysLate;
+
+  @Column(name = "percent_provision", nullable = false)
+  private BigDecimal percentProvision;
+
+  public Long getId() {
+    return id;
+  }
+
+  public void setId(Long id) {
+    this.id = id;
+  }
+
+  public Long getProductId() {
+    return productId;
+  }
+
+  public void setProductId(Long productId) {
+    this.productId = productId;
+  }
+
+  public Integer getDaysLate() {
+    return daysLate;
+  }
+
+  public void setDaysLate(Integer daysLate) {
+    this.daysLate = daysLate;
+  }
+
+  public BigDecimal getPercentProvision() {
+    return percentProvision;
+  }
+
+  public void setPercentProvision(BigDecimal percentProvision) {
+    this.percentProvision = percentProvision;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+    ProductArrearsConfigurationEntity that = (ProductArrearsConfigurationEntity) o;
+    return Objects.equals(productId, that.productId) &&
+        Objects.equals(daysLate, that.daysLate);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(productId, daysLate);
+  }
+}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/repository/ProductArrearsConfigurationRepository.java b/service/src/main/java/io/mifos/portfolio/service/internal/repository/ProductArrearsConfigurationRepository.java
new file mode 100644
index 0000000..01bdfb4
--- /dev/null
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/repository/ProductArrearsConfigurationRepository.java
@@ -0,0 +1,29 @@
+/*
+ * 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.portfolio.service.internal.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * @author Myrle Krantz
+ */
+@Repository
+public interface ProductArrearsConfigurationRepository extends JpaRepository<ProductArrearsConfigurationEntity, Long> {
+  List<ProductArrearsConfigurationEntity> findByProductId(Long id);
+}
diff --git a/service/src/main/resources/db/migrations/mariadb/V9__arrears_determination.sql b/service/src/main/resources/db/migrations/mariadb/V9__arrears_determination.sql
index 2c91530..9fd882f 100644
--- a/service/src/main/resources/db/migrations/mariadb/V9__arrears_determination.sql
+++ b/service/src/main/resources/db/migrations/mariadb/V9__arrears_determination.sql
@@ -25,4 +25,15 @@
   CONSTRAINT bastet_case_commands_pk PRIMARY KEY (id),
   CONSTRAINT bastet_case_commands_uq UNIQUE (thoth_transaction_uq, action_name, case_id),
   CONSTRAINT bastet_case_commands_fk FOREIGN KEY (case_id) REFERENCES bastet_cases (id)
+);
+
+CREATE TABLE bastet_p_arrears_config (
+  id BIGINT NOT NULL AUTO_INCREMENT,
+  product_id               BIGINT         NOT NULL,
+  days_late                INT            NOT NULL,
+  percent_provision        DECIMAL(5,2)   NOT NULL,
+
+  CONSTRAINT bastet_p_arrears_config_pk PRIMARY KEY (id),
+  CONSTRAINT bastet_p_arrears_config_uq UNIQUE (product_id, days_late),
+  CONSTRAINT bastet_p_arrears_config_fk FOREIGN KEY (product_id) REFERENCES bastet_products (id)
 );
\ No newline at end of file
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 3fb6007..4bc8051 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
@@ -157,7 +157,12 @@
       final CaseEntity customerCase = new CaseEntity();
       customerCase.setInterest(interest);
 
-      return new DataContextOfAction(product, customerCase, CaseParametersMapper.map(1L, caseParameters), Collections.emptyList());
+      return new DataContextOfAction(
+          product,
+          customerCase,
+          CaseParametersMapper.map(1L, caseParameters),
+          Collections.emptyList(),
+          Collections.emptyList());
     }
 
     @Override
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 99a5c17..84b3f38 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
@@ -55,6 +55,7 @@
         product,
         customerCase,
         caseParameters,
+        Collections.emptyList(),
         Collections.emptyList());
     return testSubject.getPaymentBuilder(
         dataContextOfAction,