MIFOSX-1417 : added api to run periodic accrules till specific date

This commit is contained in:
Pramod Nuthakki
2014-07-15 21:45:55 +05:30
parent 40b005cbfa
commit 4051afd583
14 changed files with 459 additions and 6 deletions
+73 -1
View File
@@ -1418,7 +1418,14 @@
<td><a href="#financialactivityaccounts_delete">Delete a Financial Activity to Account Mapping</a></td>
</tr>
<tr>
<td><a href="#periodicaccrualaccounting">Periodic Accrual Accounting</a></td>
<td>accrualaccounting</td>
<td><a href="#periodicaccrualaccounting_run">Execute Periodic Accrual Accounting</a><br> </td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</div>
</div>
@@ -29474,6 +29481,71 @@ Content-Type: application/json
</div>
<!-- start Periodic accrual API doc-->
<a id="periodicaccrualaccounting" name="periodicaccrualaccounting" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h3>Periodic Accrual Accounting</h3>
<p>
Periodic Accrual is to accrue the loan income till the specific date or till batch job scheduled time.
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Field Descriptions</div></td>
</tr>
<tr class=alt>
<td>accrueTill</td>
</tr>
<tr>
<td class=fielddesc>which specifies periodic accruals should happen till the given Date
</td>
</tr>
</table>
</div>
</div>
<a id="periodicaccrualaccounting_run" name="periodicaccrualaccounting_run" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Executes Periodic Accrual Accounting</h4>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Mandatory Fields</div></td>
</tr>
<tr class=alt>
<td>accrueTill
</td>
</tr>
</table>
<br />
</div>
<div class="method-example">
<code class="method-declaration">
POST https://DomainName/api/v1/accrualaccounting
</code>
<code class="method-request">
POST financialactivityaccounts
Content-Type: application/json
Request Body:
{
"locale": "en",
"dateFormat": "dd MMMM yyyy",
"accrueTill":"04 June 2014"
}
</code>
<code class="method-response">
</code>
</div>
</div>
<!-- end Periodic accrual API doc-->
<!-- start of Search API doc -->
<a id="search" name="search" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
@@ -0,0 +1 @@
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('accounting', 'EXECUTE_PERIODICACCRUALACCOUNTING', 'PERIODICACCRUALACCOUNTING', 'EXECUTE', 0);
@@ -22,6 +22,7 @@ import org.mifosplatform.integrationtests.common.accounting.Account;
import org.mifosplatform.integrationtests.common.accounting.AccountHelper;
import org.mifosplatform.integrationtests.common.accounting.JournalEntry;
import org.mifosplatform.integrationtests.common.accounting.JournalEntryHelper;
import org.mifosplatform.integrationtests.common.accounting.PeriodicAccrualAccountingHelper;
import org.mifosplatform.integrationtests.common.charges.ChargesHelper;
import org.mifosplatform.integrationtests.common.fixeddeposit.FixedDepositAccountHelper;
import org.mifosplatform.integrationtests.common.fixeddeposit.FixedDepositAccountStatusChecker;
@@ -84,6 +85,7 @@ public class AccountingScenarioIntegrationTest {
private RecurringDepositProductHelper recurringDepositProductHelper;
private RecurringDepositAccountHelper recurringDepositAccountHelper;
private SchedulerJobHelper schedulerJobHelper;
private PeriodicAccrualAccountingHelper periodicAccrualAccountingHelper;
@Before
public void setup() {
@@ -96,6 +98,7 @@ public class AccountingScenarioIntegrationTest {
this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
this.journalEntryHelper = new JournalEntryHelper(this.requestSpec, this.responseSpec);
this.schedulerJobHelper = new SchedulerJobHelper(this.requestSpec, this.responseSpec);
this.periodicAccrualAccountingHelper = new PeriodicAccrualAccountingHelper(this.requestSpec, this.responseSpec);
}
@Test
@@ -722,6 +725,80 @@ public class AccountingScenarioIntegrationTest {
}
@Test
public void checkPeriodicAccrualAccountingAPIFlow() {
final Account assetAccount = this.accountHelper.createAssetAccount();
final Account incomeAccount = this.accountHelper.createIncomeAccount();
final Account expenseAccount = this.accountHelper.createExpenseAccount();
final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
final Integer loanProductID = createLoanProductWithPeriodicAccrualAccountingEnabled(assetAccount, incomeAccount, expenseAccount,
overpaymentAccount);
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, this.DATE_OF_JOINING);
final Integer loanID = applyForLoanApplication(clientID, loanProductID);
final float FEE_PORTION = 50.0f;
final float PENALTY_PORTION = 100.0f;
Integer flat = ChargesHelper.createCharges(requestSpec, responseSpec,
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, String.valueOf(FEE_PORTION), false));
Integer flatSpecifiedDueDate = ChargesHelper.createCharges(requestSpec, responseSpec, ChargesHelper.getLoanSpecifiedDueDateJSON(
ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, String.valueOf(PENALTY_PORTION), true));
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
loanStatusHashMap = this.loanTransactionHelper.approveLoan(this.EXPECTED_DISBURSAL_DATE, loanID);
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
Calendar todayDate = Calendar.getInstance();
final String currentDate = dateFormat.format(todayDate.getTime());
todayDate.add(Calendar.DATE, -4);
final String LOAN_DISBURSEMENT_DATE = dateFormat.format(todayDate.getTime());
todayDate.add(Calendar.MONTH, 2);
final String FIRST_REPAYMENT_DATE = dateFormat.format(todayDate.getTime());
todayDate = Calendar.getInstance();
todayDate.add(Calendar.DATE, -2);
loanStatusHashMap = this.loanTransactionHelper.disburseLoan(LOAN_DISBURSEMENT_DATE, loanID);
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
this.loanTransactionHelper.addChargesForLoan(
loanID,
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(flatSpecifiedDueDate),
dateFormat.format(todayDate.getTime()), String.valueOf(PENALTY_PORTION)));
todayDate.add(Calendar.DATE, 1);
String runOndate = dateFormat.format(todayDate.getTime());
this.loanTransactionHelper
.addChargesForLoan(
loanID,
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(flat), runOndate,
String.valueOf(FEE_PORTION)));
// CHECK ACCOUNT ENTRIES
System.out.println("Entries ......");
final float PRINCIPAL_VALUE_FOR_EACH_PERIOD = 2000.0f;
final float TOTAL_INTEREST = 1000.0f;
final JournalEntry[] assetAccountInitialEntry = { new JournalEntry(this.LP_PRINCIPAL, JournalEntry.TransactionType.CREDIT),
new JournalEntry(this.LP_PRINCIPAL, JournalEntry.TransactionType.DEBIT), };
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, LOAN_DISBURSEMENT_DATE, assetAccountInitialEntry);
this.periodicAccrualAccountingHelper.runPeriodicAccrualAccounting(runOndate);
// MAKE 1
final float INTEREST_3_DAYS = 10.0F;
this.loanTransactionHelper.checkAccrualTransactionForRepayment(getDateAsLocalDate(runOndate), INTEREST_3_DAYS, FEE_PORTION,
PENALTY_PORTION, loanID);
}
private Integer createLoanProductWithPeriodicAccrualAccountingEnabled(final Account... accounts) {
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder().withPrincipal(this.LP_PRINCIPAL.toString()).withRepaymentTypeAsMonth()
@@ -0,0 +1,35 @@
package org.mifosplatform.integrationtests.common.accounting;
import java.util.HashMap;
import org.mifosplatform.integrationtests.common.Utils;
import com.google.gson.Gson;
import com.jayway.restassured.specification.RequestSpecification;
import com.jayway.restassured.specification.ResponseSpecification;
public class PeriodicAccrualAccountingHelper {
private static final String PERIODIC_ACCRUAL_URL = "/mifosng-provider/api/v1/accrualaccounting";
private final RequestSpecification requestSpec;
private final ResponseSpecification responseSpec;
public PeriodicAccrualAccountingHelper(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) {
this.requestSpec = requestSpec;
this.responseSpec = responseSpec;
}
public Object runPeriodicAccrualAccounting(String date) {
String json = getRunPeriodicAccrual(date);
return Utils.performServerPost(this.requestSpec, this.responseSpec, PERIODIC_ACCRUAL_URL + "?" + Utils.TENANT_IDENTIFIER, json, "");
}
private String getRunPeriodicAccrual(String date) {
final HashMap<String, String> map = new HashMap<>();
map.put("dateFormat", "dd MMMM yyyy");
map.put("locale", "en_GB");
map.put("accrueTill", date);
return new Gson().toJson(map);
}
}
@@ -0,0 +1,51 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.accounting.accrual.api;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.commands.service.CommandWrapperBuilder;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Path("/accrualaccounting")
@Component
@Scope("singleton")
public class AccrualAccountingApiResource {
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final DefaultToApiJsonSerializer<String> apiJsonSerializerService;
@Autowired
public AccrualAccountingApiResource(final DefaultToApiJsonSerializer<String> apiJsonSerializerService,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.apiJsonSerializerService = apiJsonSerializerService;
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String executePeriodicAccrualAccounting(final String jsonRequestBody) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().excuteAccrualAccounting().withJson(jsonRequestBody).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.apiJsonSerializerService.serialize(result);
}
}
@@ -0,0 +1,18 @@
package org.mifosplatform.accounting.accrual.api;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class AccrualAccountingConstants {
public static final String accrueTillParamName = "accrueTill";
public static final String localeParamName = "locale";
public static final String dateFormatParamName = "dateFormat";
public static final String PERIODIC_ACCRUAL_ACCOUNTING_RESOURCE_NAME = "periodicaccrual";
public static final String PERIODIC_ACCRUAL_ACCOUNTING_EXECUTION_ERROR_CODE = "execution.failed";
public static final Set<String> LOAN_PERIODIC_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(accrueTillParamName,
localeParamName, dateFormatParamName));
}
@@ -0,0 +1,31 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.accounting.accrual.handler;
import org.mifosplatform.accounting.accrual.service.AccrualAccountingWritePlatformService;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class ExecutePeriodicAccrualCommandHandler implements NewCommandSourceHandler {
private final AccrualAccountingWritePlatformService writePlatformService;
@Autowired
public ExecutePeriodicAccrualCommandHandler(final AccrualAccountingWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.executeLoansPeriodicAccrual(command);
}
}
@@ -0,0 +1,66 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.accounting.accrual.serialization;
import static org.mifosplatform.accounting.accrual.api.AccrualAccountingConstants.LOAN_PERIODIC_REQUEST_DATA_PARAMETERS;
import static org.mifosplatform.accounting.accrual.api.AccrualAccountingConstants.PERIODIC_ACCRUAL_ACCOUNTING_RESOURCE_NAME;
import static org.mifosplatform.accounting.accrual.api.AccrualAccountingConstants.accrueTillParamName;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.loanaccount.guarantor.command.GuarantorCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
/**
* Implementation of {@link FromApiJsonDeserializer} for
* {@link GuarantorCommand}'s.
*/
@Component
public final class AccrualAccountingDataValidator {
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public AccrualAccountingDataValidator(final FromJsonHelper fromApiJsonfromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonfromApiJsonHelper;
}
public void validateLoanPeriodicAccrualData(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, LOAN_PERIODIC_REQUEST_DATA_PARAMETERS);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(PERIODIC_ACCRUAL_ACCOUNTING_RESOURCE_NAME);
final LocalDate date = this.fromApiJsonHelper.extractLocalDateNamed(accrueTillParamName, element);
baseDataValidator.reset().parameter(accrueTillParamName).value(date).notNull().validateDateBefore(LocalDate.now());
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
}
@@ -0,0 +1,15 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.accounting.accrual.service;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
public interface AccrualAccountingWritePlatformService {
CommandProcessingResult executeLoansPeriodicAccrual(JsonCommand command);
}
@@ -0,0 +1,54 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.accounting.accrual.service;
import static org.mifosplatform.accounting.accrual.api.AccrualAccountingConstants.PERIODIC_ACCRUAL_ACCOUNTING_EXECUTION_ERROR_CODE;
import static org.mifosplatform.accounting.accrual.api.AccrualAccountingConstants.PERIODIC_ACCRUAL_ACCOUNTING_RESOURCE_NAME;
import static org.mifosplatform.accounting.accrual.api.AccrualAccountingConstants.accrueTillParamName;
import java.util.ArrayList;
import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.accounting.accrual.serialization.AccrualAccountingDataValidator;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.portfolio.loanaccount.service.LoanAccrualWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class AccrualAccountingWritePlatformServiceImpl implements AccrualAccountingWritePlatformService {
private final LoanAccrualWritePlatformService loanAccrualWritePlatformService;
private final AccrualAccountingDataValidator accountingDataValidator;
@Autowired
public AccrualAccountingWritePlatformServiceImpl(final LoanAccrualWritePlatformService loanAccrualWritePlatformService,
final AccrualAccountingDataValidator accountingDataValidator) {
this.loanAccrualWritePlatformService = loanAccrualWritePlatformService;
this.accountingDataValidator = accountingDataValidator;
}
@Override
public CommandProcessingResult executeLoansPeriodicAccrual(JsonCommand command) {
this.accountingDataValidator.validateLoanPeriodicAccrualData(command.json());
LocalDate tilldate = command.localDateValueOfParameterNamed(accrueTillParamName);
String errorlog = this.loanAccrualWritePlatformService.addPeriodicAccruals(tilldate);
if (errorlog.length() > 0) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(PERIODIC_ACCRUAL_ACCOUNTING_RESOURCE_NAME);
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(PERIODIC_ACCRUAL_ACCOUNTING_EXECUTION_ERROR_CODE, errorlog);
throw new PlatformApiDataValidationException(dataValidationErrors);
}
return CommandProcessingResult.empty();
}
}
@@ -266,6 +266,14 @@ public class CommandWrapper {
public boolean isJournalEntryResource() {
return this.entityName.equalsIgnoreCase("JOURNALENTRY");
}
public boolean isPeriodicAccrualResource() {
return this.entityName.equalsIgnoreCase("PERIODICACCRUALACCOUNTING");
}
public boolean isExecute() {
return this.actionName.equalsIgnoreCase("EXECUTE");
}
public boolean isRevertJournalEntry() {
return this.actionName.equalsIgnoreCase("REVERSE") && this.entityName.equalsIgnoreCase("JOURNALENTRY");
@@ -808,6 +808,14 @@ public class CommandWrapperBuilder {
this.href = "/glclosures/" + glClosureId;
return this;
}
public CommandWrapperBuilder excuteAccrualAccounting() {
this.actionName = "EXECUTE";
this.entityName = "PERIODICACCRUALACCOUNTING";
this.entityId = null;
this.href = "/accrualaccounting";
return this;
}
public CommandWrapperBuilder createGLAccount() {
this.actionName = "CREATE";
@@ -418,6 +418,10 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
} else if (wrapper.isPeriodicAccrualResource()) {
if (wrapper.isExecute()) {
handler = this.applicationContext.getBean("executePeriodicAccrualCommandHandler", NewCommandSourceHandler.class);
}
} else if (wrapper.isSavingsProductResource()) {
if (wrapper.isCreate()) {
handler = this.applicationContext.getBean("createSavingsProductCommandHandler", NewCommandSourceHandler.class);
@@ -122,6 +122,10 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
startDate = accrualData.getFromDateAsLocaldate();
}
int daysToBeAccrued = Days.daysBetween(startDate, tilldate).getDays();
if(daysToBeAccrued < 1){
return;
}
int daysInSchedule = Days.daysBetween(accrualData.getFromDateAsLocaldate(), tilldate).getDays();
switch (accrualData.getRepaymentFrequency()) {
case MONTHS:
totalNumberOfDays = calculateTotalNumberOfDaysForMonth(totalNumberOfDays, accrualData);
@@ -138,7 +142,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
BigDecimal interestportion = null;
BigDecimal feeportion = accrualData.getDueDateFeeIncome();
BigDecimal penaltyportion = accrualData.getDueDatePenaltyIncome();
if (daysToBeAccrued >= totalNumberOfDays) {
if (daysInSchedule >= totalNumberOfDays) {
interestportion = accrualData.getInterestIncome();
} else {
double iterest = interestPerDay * daysToBeAccrued;
@@ -158,20 +162,29 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
if (totalAccFee == null) {
totalAccFee = BigDecimal.ZERO;
}
feeportion = feeportion.subtract(totalAccFee);
amount = amount.add(feeportion);
totalAccFee = totalAccFee.add(feeportion);
if (feeportion.compareTo(BigDecimal.ZERO) == 0) {
feeportion = null;
}
}
BigDecimal totalAccPenalty = accrualData.getAccruedPenaltyIncome();
if (penaltyportion != null) {
if (totalAccPenalty == null) {
totalAccPenalty = BigDecimal.ZERO;
}
penaltyportion = penaltyportion.subtract(totalAccPenalty);
amount = amount.add(penaltyportion);
totalAccFee = totalAccFee.add(penaltyportion);
totalAccPenalty = totalAccFee.add(penaltyportion);
if (penaltyportion.compareTo(BigDecimal.ZERO) == 0) {
penaltyportion = null;
}
}
if (amount.compareTo(BigDecimal.ZERO) != 0) {
addAccrualAccounting(accrualData, amount, interestportion, totalAccInterest, feeportion, totalAccFee, penaltyportion,
totalAccPenalty, tilldate);
}
addAccrualAccounting(accrualData, amount, interestportion, totalAccInterest, feeportion, totalAccFee, penaltyportion,
totalAccPenalty, tilldate);
}
private int calculateTotalNumberOfDaysForMonth(final int totalNumberOfDays, final LoanScheduleAccrualData accrualData) {