MIFOSX-746: musoni specific approach to auto penalties on late installments.

This commit is contained in:
Keith Woodlock
2013-11-15 11:43:29 +00:00
parent b43a9472e3
commit 6232e863ed
8 changed files with 164 additions and 154 deletions
@@ -34,6 +34,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Path("/jobs")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Component
public class SchedulerJobApiResource {
@@ -59,8 +61,6 @@ public class SchedulerJobApiResource {
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAll(@Context final UriInfo uriInfo) {
final List<JobDetailData> jobDetailDatas = this.schedulerJobRunnerReadService.findAllJobDeatils();
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
@@ -69,8 +69,6 @@ public class SchedulerJobApiResource {
@GET
@Path("{" + SchedulerJobApiConstants.JOB_ID + "}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveOne(@PathParam(SchedulerJobApiConstants.JOB_ID) final Long jobId, @Context final UriInfo uriInfo) {
final JobDetailData jobDetailData = this.schedulerJobRunnerReadService.retrieveOne(jobId);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
@@ -79,8 +77,6 @@ public class SchedulerJobApiResource {
@GET
@Path("{" + SchedulerJobApiConstants.JOB_ID + "}/" + SchedulerJobApiConstants.JOB_RUN_HISTORY)
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveHistory(@Context final UriInfo uriInfo, @PathParam(SchedulerJobApiConstants.JOB_ID) final Long jobId,
@QueryParam("offset") final Integer offset, @QueryParam("limit") final Integer limit,
@QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder) {
@@ -94,8 +90,6 @@ public class SchedulerJobApiResource {
@POST
@Path("{" + SchedulerJobApiConstants.JOB_ID + "}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response executeJob(@PathParam(SchedulerJobApiConstants.JOB_ID) final Long jobId,
@QueryParam(SchedulerJobApiConstants.COMMAND) final String commandParam) {
Response response = Response.status(400).build();
@@ -110,8 +104,6 @@ public class SchedulerJobApiResource {
@PUT
@Path("{" + SchedulerJobApiConstants.JOB_ID + "}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateJobDetail(@PathParam(SchedulerJobApiConstants.JOB_ID) final Long jobId, final String jsonRequestBody) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
@@ -130,5 +122,4 @@ public class SchedulerJobApiResource {
private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}
}
}
@@ -2,15 +2,20 @@ package org.mifosplatform.infrastructure.jobs.service;
public enum JobName {
UPDATE_LOAN_SUMMARY("Update loan Summary"), UPDATE_LOAN_ARREARS_AGEING("Update Loan Arrears Ageing"), UPDATE_LOAN_PAID_IN_ADVANCE(
"Update Loan Paid In Advance"), APPLY_ANNUAL_FEE_FOR_SAVINGS("Apply Annual Fee For Savings"), APPLY_HOLIDAYS_TO_LOANS(
"Apply Holidays To Loans"), POST_INTEREST_FOR_SAVINGS("Post Interest For Savings"), TRANSFER_FEE_CHARGE_FOR_LOANS(
"Transfer Fee For Loans From Savings"), ACCOUNTING_RUNNING_BALANCE_UPDATE("Update Accounting Running Balances"), PAY_DUE_SAVINGS_CHARGES(
"Pay Due Savings Charges"),APPLY_CHARGE_TO_OVERDUE_LOAN_INSTALLMENT("Apply penalty to overdue loans");
UPDATE_LOAN_SUMMARY("Update loan Summary"), //
UPDATE_LOAN_ARREARS_AGEING("Update Loan Arrears Ageing"), //
UPDATE_LOAN_PAID_IN_ADVANCE("Update Loan Paid In Advance"), //
APPLY_ANNUAL_FEE_FOR_SAVINGS("Apply Annual Fee For Savings"), //
APPLY_HOLIDAYS_TO_LOANS("Apply Holidays To Loans"), //
POST_INTEREST_FOR_SAVINGS("Post Interest For Savings"), //
TRANSFER_FEE_CHARGE_FOR_LOANS("Transfer Fee For Loans From Savings"), //
ACCOUNTING_RUNNING_BALANCE_UPDATE("Update Accounting Running Balances"), //
PAY_DUE_SAVINGS_CHARGES("Pay Due Savings Charges"), //
APPLY_CHARGE_TO_OVERDUE_LOAN_INSTALLMENT("Apply penalty to overdue loans");
private final String name;
JobName(final String name) {
private JobName(final String name) {
this.name = name;
}
@@ -18,4 +23,4 @@ public enum JobName {
public String toString() {
return this.name;
}
}
}
@@ -38,7 +38,7 @@ import org.springframework.stereotype.Service;
* Service class to create and load batch jobs to Scheduler using
* {@link SchedulerFactoryBean} ,{@link MethodInvokingJobDetailFactoryBean} and
* {@link CronTriggerFactoryBean}
*
*
*/
@Service
public class JobRegisterServiceImpl implements JobRegisterService {
@@ -351,10 +351,6 @@ public class JobRegisterServiceImpl implements JobRegisterService {
return cronTriggerFactoryBean.getObject();
}
/**
* @param throwable
* @return
*/
private String getStackTraceAsString(final Throwable throwable) {
final StackTraceElement[] stackTraceElements = throwable.getStackTrace();
final StringBuffer sb = new StringBuffer(throwable.toString());
@@ -2,14 +2,8 @@ package org.mifosplatform.portfolio.loanaccount.loanschedule.data;
import java.math.BigDecimal;
/**
* Created with IntelliJ IDEA.
* User: andrew
* Date: 13-11-13
* Time: 11:53
* To change this template use File | Settings | File Templates.
*/
public class OverdueLoanScheduleData {
private final Long loanId;
private final Long chargeId;
private final String locale;
@@ -17,9 +11,8 @@ public class OverdueLoanScheduleData {
private final String dateFormat;
private final String dueDate;
public OverdueLoanScheduleData(Long loanId, Long chargeId, String dueDate, BigDecimal amount, String dateFormat, String locale) {
public OverdueLoanScheduleData(final Long loanId, final Long chargeId, final String dueDate, final BigDecimal amount,
final String dateFormat, final String locale) {
this.loanId = loanId;
this.chargeId = chargeId;
this.dueDate = dueDate;
@@ -54,12 +47,7 @@ public class OverdueLoanScheduleData {
@Override
public String toString() {
return "{" +
"chargeId:" + chargeId +
", locale:'" + locale + '\'' +
", amount:" + amount +
", dateFormat:'" + dateFormat + '\'' +
", dueDate:'" + dueDate + '\'' +
'}';
return "{" + "chargeId:" + this.chargeId + ", locale:'" + this.locale + '\'' + ", amount:" + this.amount + ", dateFormat:'"
+ this.dateFormat + '\'' + ", dueDate:'" + this.dueDate + '\'' + '}';
}
}
@@ -5,6 +5,8 @@
*/
package org.mifosplatform.portfolio.loanaccount.service;
import java.util.Collection;
import org.mifosplatform.infrastructure.core.service.Page;
import org.mifosplatform.organisation.staff.data.StaffData;
import org.mifosplatform.portfolio.calendar.data.CalendarData;
@@ -15,8 +17,6 @@ import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoan
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
import java.util.Collection;
public interface LoanReadPlatformService {
LoanAccountData retrieveOne(Long loanId);
@@ -55,5 +55,10 @@ public interface LoanReadPlatformService {
Collection<StaffData> retrieveAllowedLoanOfficers(Long selectedOfficeId, boolean staffInSelectedOfficeOnly);
Collection<OverdueLoanScheduleData> retrieveAllOverdueLoans();
/*
* musoni-specific at present - will find overdue scheduled installments that have a special 'overdue charge' associated with the loan product.
*
* The 'overdue-charge' is only ever applied once to an installment and as a result overdue installments with this charge already applied are not returned.
*/
Collection<OverdueLoanScheduleData> retrieveAllLoansWithOverdueInstallmentsNotAlreadyPenalized();
}
@@ -5,6 +5,13 @@
*/
package org.mifosplatform.portfolio.loanaccount.service;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import org.apache.commons.lang.StringUtils;
import org.joda.time.Days;
import org.joda.time.LocalDate;
@@ -40,8 +47,19 @@ import org.mifosplatform.portfolio.group.data.GroupGeneralData;
import org.mifosplatform.portfolio.group.data.GroupRoleData;
import org.mifosplatform.portfolio.group.service.GroupReadPlatformService;
import org.mifosplatform.portfolio.group.service.SearchParameters;
import org.mifosplatform.portfolio.loanaccount.data.*;
import org.mifosplatform.portfolio.loanaccount.domain.*;
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData;
import org.mifosplatform.portfolio.loanaccount.data.LoanApplicationTimelineData;
import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData;
import org.mifosplatform.portfolio.loanaccount.data.LoanSummaryData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionNotFoundException;
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
@@ -64,13 +82,6 @@ import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@Service
public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
@@ -662,7 +673,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final EnumOptionData groupStatus = ClientEnumerations.status(groupStatusEnum);
final LocalDate activationDate = JdbcSupport.getLocalDate(rs, "activationDate");
groupData = GroupGeneralData.instance(groupId, groupName, groupExternalId, groupStatus, activationDate, groupOfficeId,
null, groupParentId, null, groupStaffId, null, groupHierarchy,null);
null, groupParentId, null, groupStaffId, null, groupHierarchy, null);
}
final Integer loanCounter = JdbcSupport.getInteger(rs, "loanCounter");
@@ -678,9 +689,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
feeChargesDueAtDisbursementCharged, syncDisbursementWithMeeting, loanCounter, loanProductCounter);
}
}
private static final class OverdueLoanSchedule implements RowMapper<OverdueLoanScheduleData>{
public String schema(){
private static final class MusoniOverdueLoanScheduleMapper implements RowMapper<OverdueLoanScheduleData> {
public String schema() {
return " ls.loan_id as loanId, ls.installment as period, ls.fromdate as fromDate, ls.duedate as dueDate, ls.obligations_met_on_date as obligationsMetOnDate, ls.completed_derived as complete,"
+ " ls.principal_amount as principalDue, ls.principal_completed_derived as principalPaid, ls.principal_writtenoff_derived as principalWrittenOff, "
+ " ls.interest_amount as interestDue, ls.interest_completed_derived as interestPaid, ls.interest_waived_derived as interestWaived, ls.interest_writtenoff_derived as interestWrittenOff, "
@@ -696,17 +708,16 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
@Override
public OverdueLoanScheduleData mapRow(ResultSet rs, int rowNum) throws SQLException {
public OverdueLoanScheduleData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long chargeId = rs.getLong("chargeId");
final Long loanId = rs.getLong("loanId");
final BigDecimal amount = rs.getBigDecimal("amount");
final String dateFormat = "yyyy-MM-dd";
final String dateFormat = "yyyy-MM-dd";
final String dueDate = rs.getString("dueDate");
final String locale = "en_GB";
final String locale = "en_GB";
OverdueLoanScheduleData overdueLoanScheduleData = new OverdueLoanScheduleData(loanId,chargeId,dueDate,
amount,dateFormat,locale) ;
final OverdueLoanScheduleData overdueLoanScheduleData = new OverdueLoanScheduleData(loanId, chargeId, dueDate, amount,
dateFormat, locale);
return overdueLoanScheduleData;
}
@@ -1129,13 +1140,14 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
@Override
public Collection<OverdueLoanScheduleData> retrieveAllOverdueLoans() {
final OverdueLoanSchedule rm = new OverdueLoanSchedule();
final String sql = "select " + rm.schema() +
" where CURDATE() > ls.duedate "+
" and ls.completed_derived <> 1 and mc.charge_applies_to_enum =1 "+
" and mc.charge_time_enum = 9 and ml.loan_status_id = 300 "+
" and plc.charge_id not in (SELECT charge_id from m_loan_charge as mlc where mlc.loan_id = ml.id and mlc.charge_id = plc.charge_id and mlc.due_for_collection_as_of_date > fromdate AND mlc.due_for_collection_as_of_date <= duedate) ";
return this.jdbcTemplate.query(sql,rm,new Object[] {});
public Collection<OverdueLoanScheduleData> retrieveAllLoansWithOverdueInstallmentsNotAlreadyPenalized() {
final MusoniOverdueLoanScheduleMapper rm = new MusoniOverdueLoanScheduleMapper();
final String sql = "select "
+ rm.schema()
+ " where CURDATE() > ls.duedate "
+ " and ls.completed_derived <> 1 and mc.charge_applies_to_enum =1 "
+ " and mc.charge_time_enum = 9 and ml.loan_status_id = 300 "
+ " and plc.charge_id not in (SELECT charge_id from m_loan_charge as mlc where mlc.loan_id = ml.id and mlc.charge_id = plc.charge_id and mlc.due_for_collection_as_of_date > fromdate AND mlc.due_for_collection_as_of_date <= duedate) ";
return this.jdbcTemplate.query(sql, rm, new Object[] {});
}
}
@@ -5,7 +5,17 @@
*/
package org.mifosplatform.portfolio.loanaccount.service;
import com.google.gson.JsonElement;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
@@ -49,11 +59,15 @@ import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
import org.mifosplatform.portfolio.charge.domain.Charge;
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
import org.mifosplatform.portfolio.charge.exception.*;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException.LOAN_CHARGE_CANNOT_BE_DELETED_REASON;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBePayedException;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBePayedException.LOAN_CHARGE_CANNOT_BE_PAYED_REASON;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeUpdatedException;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeUpdatedException.LOAN_CHARGE_CANNOT_BE_UPDATED_REASON;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON;
import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.exception.ClientNotActiveException;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
@@ -65,7 +79,19 @@ import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanInstallmentChargeData;
import org.mifosplatform.portfolio.loanaccount.domain.*;
import org.mifosplatform.portfolio.loanaccount.domain.ChangedTransactionDetail;
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanAccountDomainService;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanChargeRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanInstallmentCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
import org.mifosplatform.portfolio.loanaccount.exception.LoanDisbursalException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerUnassignmentException;
@@ -93,16 +119,13 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.util.*;
import com.google.gson.JsonElement;
@Service
public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatformService {
private final static Logger logger = LoggerFactory.getLogger(LoanWritePlatformServiceJpaRepositoryImpl.class);
private final PlatformSecurityContext context;
private final LoanEventApiJsonValidator loanEventApiJsonValidator;
private final LoanUpdateCommandFromApiJsonDeserializer loanUpdateCommandFromApiJsonDeserializer;
@@ -129,7 +152,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final LoanReadPlatformService loanReadPlatformService;
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final LoanEventApiJsonValidator loanEventApiJsonValidator,
@@ -146,8 +168,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final AccountTransfersWritePlatformService accountTransfersWritePlatformService,
final AccountTransfersReadPlatformService accountTransfersReadPlatformService,
final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService,
final LoanChargeReadPlatformService loanChargeReadPlatformService,final LoanReadPlatformService loanReadPlatformService,
final FromJsonHelper fromApiJsonHelper ) {
final LoanChargeReadPlatformService loanChargeReadPlatformService, final LoanReadPlatformService loanReadPlatformService,
final FromJsonHelper fromApiJsonHelper) {
this.context = context;
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
this.loanAssembler = loanAssembler;
@@ -257,8 +279,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
for (final LoanCharge loanCharge : loanCharges) {
if (loanCharge.isDueAtDisbursement() && loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
disBuLoanCharges.put(loanCharge.getId(), loanCharge.amount());
}else if(loanCharge.isInstalmentFee() && loanCharge.hasNoLoanInstallmentCharges()){
Set<LoanInstallmentCharge> chargePerInstallments = loan.generateInstallmentLoanCharges(loanCharge);
} else if (loanCharge.isInstalmentFee() && loanCharge.hasNoLoanInstallmentCharges()) {
final Set<LoanInstallmentCharge> chargePerInstallments = loan.generateInstallmentLoanCharges(loanCharge);
loanCharge.addLoanInstallmentCharges(chargePerInstallments);
this.loanChargeRepository.save(loanCharge);
}
@@ -384,8 +406,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
for (final LoanCharge loanCharge : loanCharges) {
if (loanCharge.isDueAtDisbursement() && loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
disBuLoanCharges.put(loanCharge.getId(), loanCharge.amount());
}else if(loanCharge.isInstalmentFee() && loanCharge.hasNoLoanInstallmentCharges()){
Set<LoanInstallmentCharge> chargePerInstallments = loan.generateInstallmentLoanCharges(loanCharge);
} else if (loanCharge.isInstalmentFee() && loanCharge.hasNoLoanInstallmentCharges()) {
final Set<LoanInstallmentCharge> chargePerInstallments = loan.generateInstallmentLoanCharges(loanCharge);
loanCharge.addLoanInstallmentCharges(chargePerInstallments);
this.loanChargeRepository.save(loanCharge);
}
@@ -393,10 +415,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
for (final Map.Entry<Long, BigDecimal> entrySet : disBuLoanCharges.entrySet()) {
final PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loan.getId());
final PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loan
.getId());
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(actualDisbursementDate, entrySet.getValue(),
PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN, savingAccountData.accountId(), loan.getId(), "Loan Charge Payment",
locale, fmt, null, null, LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getValue(), entrySet.getKey(), null);
PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN, savingAccountData.accountId(), loan.getId(),
"Loan Charge Payment", locale, fmt, null, null, LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getValue(),
entrySet.getKey(), null);
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
}
}
@@ -576,7 +600,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
}
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
changes.put("note", noteText);
@@ -653,8 +676,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
}
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
changes.put("note", noteText);
@@ -876,7 +897,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
}
// we post Journal entries only for loans in active status
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
}
@@ -943,28 +963,26 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (loanCharge.isWaived()) {
throw new LoanChargeCannotBeWaivedException(LOAN_CHARGE_CANNOT_BE_WAIVED_REASON.ALREADY_WAIVED, loanCharge.getId());
} else if (loanCharge.isPaid()) { throw new LoanChargeCannotBeWaivedException(LOAN_CHARGE_CANNOT_BE_WAIVED_REASON.ALREADY_PAID,
loanCharge.getId());
}
Integer loanInstallmentNumber = null;
if (loanCharge.isInstalmentFee()){
loanCharge.getId()); }
Integer loanInstallmentNumber = null;
if (loanCharge.isInstalmentFee()) {
LoanInstallmentCharge chargePerInstallment = null;
if(!StringUtils.isBlank(command.json())){
if (!StringUtils.isBlank(command.json())) {
final LocalDate dueDate = command.localDateValueOfParameterNamed("dueDate");
final Integer installmentNumber = command.integerValueOfParameterNamed("installmentNumber");
if(dueDate !=null){
if (dueDate != null) {
chargePerInstallment = loanCharge.getInstallmentLoanCharge(dueDate);
}else if(installmentNumber!=null){
} else if (installmentNumber != null) {
chargePerInstallment = loanCharge.getInstallmentLoanCharge(installmentNumber);
}
}
if(chargePerInstallment == null){
if (chargePerInstallment == null) {
chargePerInstallment = loanCharge.getUnpaidInstallmentLoanCharge();
}
if(chargePerInstallment.isWaived()){
if (chargePerInstallment.isWaived()) {
throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_WAIVED, loanCharge.getId());
}else if(chargePerInstallment.isPaid()){
throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_PAID, loanCharge.getId());
}
} else if (chargePerInstallment.isPaid()) { throw new LoanChargeCannotBePayedException(
LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_PAID, loanCharge.getId()); }
loanInstallmentNumber = chargePerInstallment.getRepaymentInstallment().getInstallmentNumber();
}
@@ -1042,8 +1060,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (loanCharge.isWaived()) {
throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_WAIVED, loanCharge.getId());
} else if (loanCharge.isPaid()) { throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_PAID,
loanCharge.getId());
}
loanCharge.getId()); }
if (!loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) { throw new LoanChargeCannotBePayedException(
LOAN_CHARGE_CANNOT_BE_PAYED_REASON.CHARGE_NOT_ACCOUNT_TRANSFER, loanCharge.getId()); }
@@ -1052,37 +1069,36 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
Integer loanInstallmentNumber = null;
Integer loanInstallmentNumber = null;
BigDecimal amount = loanCharge.amountOutstanding();
if (loanCharge.isInstalmentFee()){
if (loanCharge.isInstalmentFee()) {
LoanInstallmentCharge chargePerInstallment = null;
final LocalDate dueDate = command.localDateValueOfParameterNamed("dueDate");
final Integer installmentNumber = command.integerValueOfParameterNamed("installmentNumber");
if(dueDate !=null){
if (dueDate != null) {
chargePerInstallment = loanCharge.getInstallmentLoanCharge(dueDate);
}else if(installmentNumber!=null){
} else if (installmentNumber != null) {
chargePerInstallment = loanCharge.getInstallmentLoanCharge(installmentNumber);
}
if(chargePerInstallment == null){
if (chargePerInstallment == null) {
chargePerInstallment = loanCharge.getUnpaidInstallmentLoanCharge();
}
if(chargePerInstallment.isWaived()){
if (chargePerInstallment.isWaived()) {
throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_WAIVED, loanCharge.getId());
}else if(chargePerInstallment.isPaid()){
throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_PAID, loanCharge.getId());
}
} else if (chargePerInstallment.isPaid()) { throw new LoanChargeCannotBePayedException(
LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_PAID, loanCharge.getId()); }
loanInstallmentNumber = chargePerInstallment.getRepaymentInstallment().getInstallmentNumber();
amount= chargePerInstallment.getAmountOutstanding();
amount = chargePerInstallment.getAmountOutstanding();
}
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
if (portfolioAccountData == null) {
final String errorMessage = "Charge with id:" + loanChargeId + " requires linked savings account for payment";
throw new LinkedAccountRequiredException("loanCharge.pay", errorMessage, loanChargeId);
}
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(transactionDate, amount,
PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN, portfolioAccountData.accountId(), loanId, "Loan Charge Payment",
locale, fmt, null, null, LoanTransactionType.CHARGE_PAYMENT.getValue(), loanChargeId, loanInstallmentNumber);
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(transactionDate, amount, PortfolioAccountType.SAVINGS,
PortfolioAccountType.LOAN, portfolioAccountData.accountId(), loanId, "Loan Charge Payment", locale, fmt, null, null,
LoanTransactionType.CHARGE_PAYMENT.getValue(), loanChargeId, loanInstallmentNumber);
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
return new CommandProcessingResultBuilder() //
@@ -1103,23 +1119,25 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final StringBuilder sb = new StringBuilder();
if (chargeDatas != null) {
for (final LoanChargeData chargeData : chargeDatas) {
if(chargeData.isInstallmentFee()){
Collection<LoanInstallmentChargeData> chargePerInstallments = this.LoanChargeReadPlatformService.retrieveInstallmentLoanCharges(chargeData.getId(), true);
if (chargeData.isInstallmentFee()) {
final Collection<LoanInstallmentChargeData> chargePerInstallments = this.LoanChargeReadPlatformService
.retrieveInstallmentLoanCharges(chargeData.getId(), true);
PortfolioAccountData portfolioAccountData = null;
for(LoanInstallmentChargeData installmentChargeData : chargePerInstallments){
if(!installmentChargeData.getDueDate().isAfter(new LocalDate())){
if(portfolioAccountData == null){
portfolioAccountData = this.accountAssociationsReadPlatformService
.retriveLoanAssociation(chargeData.getLoanId());
for (final LoanInstallmentChargeData installmentChargeData : chargePerInstallments) {
if (!installmentChargeData.getDueDate().isAfter(new LocalDate())) {
if (portfolioAccountData == null) {
portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(chargeData
.getLoanId());
}
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(new LocalDate(),
installmentChargeData.getAmountOutstanding(), PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN,
portfolioAccountData.accountId(), chargeData.getLoanId(), "Loan Charge Payment", null, null, null, null,
LoanTransactionType.CHARGE_PAYMENT.getValue(), chargeData.getId(), installmentChargeData.getInstallmentNumber());
portfolioAccountData.accountId(), chargeData.getLoanId(), "Loan Charge Payment", null, null, null,
null, LoanTransactionType.CHARGE_PAYMENT.getValue(), chargeData.getId(),
installmentChargeData.getInstallmentNumber());
transferFeeCharge(sb, accountTransferDTO);
}
}
}else if (chargeData.getDueDate() != null && !chargeData.getDueDate().isAfter(new LocalDate())) {
} else if (chargeData.getDueDate() != null && !chargeData.getDueDate().isAfter(new LocalDate())) {
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
.retriveLoanAssociation(chargeData.getLoanId());
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(new LocalDate(),
@@ -1601,22 +1619,25 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Override
@CronTarget(jobName = JobName.APPLY_CHARGE_TO_OVERDUE_LOAN_INSTALLMENT)
public void applyChargeForOverdueLoans() throws JobExecutionException {
final Collection<OverdueLoanScheduleData> overdueLoanScheduleData = this.loanReadPlatformService.retrieveAllOverdueLoans();
if(!overdueLoanScheduleData.isEmpty()) {
for(OverdueLoanScheduleData overdueLoanScheduleData1 : overdueLoanScheduleData){
try{
final JsonElement parsedCommand = fromApiJsonHelper.parse(overdueLoanScheduleData1.toString());
final Collection<OverdueLoanScheduleData> overdueLoanScheduledInstallments = this.loanReadPlatformService.retrieveAllLoansWithOverdueInstallmentsNotAlreadyPenalized();
final JsonCommand command = JsonCommand.from(overdueLoanScheduleData1.toString(),parsedCommand,this.fromApiJsonHelper,null,null,
null,null,null,overdueLoanScheduleData1.getLoanId(),null,null,null,null,null,null,null);
this.applyChargeToOverdueLoanInstallment(overdueLoanScheduleData1.getLoanId(),overdueLoanScheduleData1.getChargeId(),command);
if (!overdueLoanScheduledInstallments.isEmpty()) {
for (final OverdueLoanScheduleData overdueInstallment : overdueLoanScheduledInstallments) {
try {
}catch(final PlatformApiDataValidationException e){
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(overdueInstallment.toString());
final JsonCommand command = JsonCommand.from(overdueInstallment.toString(), parsedCommand, this.fromApiJsonHelper,
null, null, null, null, null, overdueInstallment.getLoanId(), null, null, null, null, null, null, null);
applyChargeToOverdueLoanInstallment(overdueInstallment.getLoanId(), overdueInstallment.getChargeId(), command);
} catch (final PlatformApiDataValidationException e) {
final List<ApiParameterError> errors = e.getErrors();
for (final ApiParameterError error : errors) {
logger.error("Apply Charges due for overdue loans failed for account:" + overdueLoanScheduleData1.getLoanId() + " with message "
+ error.getDeveloperMessage());
logger.error("Apply Charges due for overdue loans failed for account:" + overdueInstallment.getLoanId()
+ " with message " + error.getDeveloperMessage());
}
}
}
@@ -1624,7 +1645,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
@Transactional
public void applyChargeToOverdueLoanInstallment(Long loanId, Long loanChargeId,JsonCommand command) {
public void applyChargeToOverdueLoanInstallment(final Long loanId, final Long loanChargeId, final JsonCommand command) {
final Loan loan = this.loanAssembler.assembleFrom(loanId);
checkClientOrGroupActive(loan);
@@ -1636,6 +1658,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final String errorMessage = "Charge and Loan must have the same currency.";
throw new InvalidCurrencyException("loanCharge", "attach.to.loan", errorMessage);
}
if (loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
if (portfolioAccountData == null) {
@@ -1656,13 +1679,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (loan.status().isActive()) {
final LoanTransaction applyLoanChargeTransaction = loan.handleChargeAppliedTransaction(loanCharge, null);
this.loanTransactionRepository.save(applyLoanChargeTransaction);
/***
* TODO Vishwas Batch save is giving me a
* HibernateOptimisticLockingFailureException, looping and saving
* for the time being, not a major issue for now as this loop is
* entered only in edge cases (when a payment is made before the
* latest payment recorded against the loan)
***/
this.loanRepository.saveAndFlush(loan);
if (changedTransactionDetail != null) {
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
@@ -1671,7 +1687,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
}
// we post Journal entries only for loans in active status
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
}
@@ -37,7 +37,6 @@ import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.calendar.exception.NotValidRecurringDateException;
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
import org.mifosplatform.portfolio.meeting.attendance.domain.ClientAttendance;
import org.mifosplatform.portfolio.meeting.exception.MeetingDateException;
import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -163,7 +162,7 @@ public class Meeting extends AbstractPersistable<Long> {
}
public boolean isMeetingDateBefore(final LocalDate newStartDate) {
return (this.meetingDate != null && newStartDate != null && getMeetingDateLocalDate().isBefore(newStartDate)) ? true : false;
return this.meetingDate != null && newStartDate != null && getMeetingDateLocalDate().isBefore(newStartDate) ? true : false;
}
private static boolean isValidMeetingDate(final CalendarInstance calendarInstance, final Date meetingDate) {
@@ -173,8 +172,7 @@ public class Meeting extends AbstractPersistable<Long> {
meetingDateLocalDate = LocalDate.fromDateFields(meetingDate);
}
if (meetingDateLocalDate == null
|| !calendar.isValidRecurringDate(meetingDateLocalDate)) { return false; }
if (meetingDateLocalDate == null || !calendar.isValidRecurringDate(meetingDateLocalDate)) { return false; }
return true;
}