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
@@ -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) {