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; import org.springframework.stereotype.Component;
@Path("/jobs") @Path("/jobs")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Component @Component
public class SchedulerJobApiResource { public class SchedulerJobApiResource {
@@ -59,8 +61,6 @@ public class SchedulerJobApiResource {
} }
@GET @GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAll(@Context final UriInfo uriInfo) { public String retrieveAll(@Context final UriInfo uriInfo) {
final List<JobDetailData> jobDetailDatas = this.schedulerJobRunnerReadService.findAllJobDeatils(); final List<JobDetailData> jobDetailDatas = this.schedulerJobRunnerReadService.findAllJobDeatils();
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
@@ -69,8 +69,6 @@ public class SchedulerJobApiResource {
@GET @GET
@Path("{" + SchedulerJobApiConstants.JOB_ID + "}") @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) { public String retrieveOne(@PathParam(SchedulerJobApiConstants.JOB_ID) final Long jobId, @Context final UriInfo uriInfo) {
final JobDetailData jobDetailData = this.schedulerJobRunnerReadService.retrieveOne(jobId); final JobDetailData jobDetailData = this.schedulerJobRunnerReadService.retrieveOne(jobId);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
@@ -79,8 +77,6 @@ public class SchedulerJobApiResource {
@GET @GET
@Path("{" + SchedulerJobApiConstants.JOB_ID + "}/" + SchedulerJobApiConstants.JOB_RUN_HISTORY) @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, 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("offset") final Integer offset, @QueryParam("limit") final Integer limit,
@QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder) { @QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder) {
@@ -94,8 +90,6 @@ public class SchedulerJobApiResource {
@POST @POST
@Path("{" + SchedulerJobApiConstants.JOB_ID + "}") @Path("{" + SchedulerJobApiConstants.JOB_ID + "}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response executeJob(@PathParam(SchedulerJobApiConstants.JOB_ID) final Long jobId, public Response executeJob(@PathParam(SchedulerJobApiConstants.JOB_ID) final Long jobId,
@QueryParam(SchedulerJobApiConstants.COMMAND) final String commandParam) { @QueryParam(SchedulerJobApiConstants.COMMAND) final String commandParam) {
Response response = Response.status(400).build(); Response response = Response.status(400).build();
@@ -110,8 +104,6 @@ public class SchedulerJobApiResource {
@PUT @PUT
@Path("{" + SchedulerJobApiConstants.JOB_ID + "}") @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) { public String updateJobDetail(@PathParam(SchedulerJobApiConstants.JOB_ID) final Long jobId, final String jsonRequestBody) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() // final CommandWrapper commandRequest = new CommandWrapperBuilder() //
@@ -130,5 +122,4 @@ public class SchedulerJobApiResource {
private boolean is(final String commandParam, final String commandValue) { private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue); return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
} }
} }
@@ -2,15 +2,20 @@ package org.mifosplatform.infrastructure.jobs.service;
public enum JobName { public enum JobName {
UPDATE_LOAN_SUMMARY("Update loan Summary"), UPDATE_LOAN_ARREARS_AGEING("Update Loan Arrears Ageing"), UPDATE_LOAN_PAID_IN_ADVANCE( UPDATE_LOAN_SUMMARY("Update loan Summary"), //
"Update Loan Paid In Advance"), APPLY_ANNUAL_FEE_FOR_SAVINGS("Apply Annual Fee For Savings"), APPLY_HOLIDAYS_TO_LOANS( UPDATE_LOAN_ARREARS_AGEING("Update Loan Arrears Ageing"), //
"Apply Holidays To Loans"), POST_INTEREST_FOR_SAVINGS("Post Interest For Savings"), TRANSFER_FEE_CHARGE_FOR_LOANS( UPDATE_LOAN_PAID_IN_ADVANCE("Update Loan Paid In Advance"), //
"Transfer Fee For Loans From Savings"), ACCOUNTING_RUNNING_BALANCE_UPDATE("Update Accounting Running Balances"), PAY_DUE_SAVINGS_CHARGES( APPLY_ANNUAL_FEE_FOR_SAVINGS("Apply Annual Fee For Savings"), //
"Pay Due Savings Charges"),APPLY_CHARGE_TO_OVERDUE_LOAN_INSTALLMENT("Apply penalty to overdue loans"); 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; private final String name;
JobName(final String name) { private JobName(final String name) {
this.name = name; this.name = name;
} }
@@ -351,10 +351,6 @@ public class JobRegisterServiceImpl implements JobRegisterService {
return cronTriggerFactoryBean.getObject(); return cronTriggerFactoryBean.getObject();
} }
/**
* @param throwable
* @return
*/
private String getStackTraceAsString(final Throwable throwable) { private String getStackTraceAsString(final Throwable throwable) {
final StackTraceElement[] stackTraceElements = throwable.getStackTrace(); final StackTraceElement[] stackTraceElements = throwable.getStackTrace();
final StringBuffer sb = new StringBuffer(throwable.toString()); final StringBuffer sb = new StringBuffer(throwable.toString());
@@ -2,14 +2,8 @@ package org.mifosplatform.portfolio.loanaccount.loanschedule.data;
import java.math.BigDecimal; 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 { public class OverdueLoanScheduleData {
private final Long loanId; private final Long loanId;
private final Long chargeId; private final Long chargeId;
private final String locale; private final String locale;
@@ -17,9 +11,8 @@ public class OverdueLoanScheduleData {
private final String dateFormat; private final String dateFormat;
private final String dueDate; private final String dueDate;
public OverdueLoanScheduleData(final Long loanId, final Long chargeId, final String dueDate, final BigDecimal amount,
final String dateFormat, final String locale) {
public OverdueLoanScheduleData(Long loanId, Long chargeId, String dueDate, BigDecimal amount, String dateFormat, String locale) {
this.loanId = loanId; this.loanId = loanId;
this.chargeId = chargeId; this.chargeId = chargeId;
this.dueDate = dueDate; this.dueDate = dueDate;
@@ -54,12 +47,7 @@ public class OverdueLoanScheduleData {
@Override @Override
public String toString() { public String toString() {
return "{" + return "{" + "chargeId:" + this.chargeId + ", locale:'" + this.locale + '\'' + ", amount:" + this.amount + ", dateFormat:'"
"chargeId:" + chargeId + + this.dateFormat + '\'' + ", dueDate:'" + this.dueDate + '\'' + '}';
", locale:'" + locale + '\'' +
", amount:" + amount +
", dateFormat:'" + dateFormat + '\'' +
", dueDate:'" + dueDate + '\'' +
'}';
} }
} }
@@ -5,6 +5,8 @@
*/ */
package org.mifosplatform.portfolio.loanaccount.service; package org.mifosplatform.portfolio.loanaccount.service;
import java.util.Collection;
import org.mifosplatform.infrastructure.core.service.Page; import org.mifosplatform.infrastructure.core.service.Page;
import org.mifosplatform.organisation.staff.data.StaffData; import org.mifosplatform.organisation.staff.data.StaffData;
import org.mifosplatform.portfolio.calendar.data.CalendarData; 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.LoanScheduleData;
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData; import org.mifosplatform.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
import java.util.Collection;
public interface LoanReadPlatformService { public interface LoanReadPlatformService {
LoanAccountData retrieveOne(Long loanId); LoanAccountData retrieveOne(Long loanId);
@@ -55,5 +55,10 @@ public interface LoanReadPlatformService {
Collection<StaffData> retrieveAllowedLoanOfficers(Long selectedOfficeId, boolean staffInSelectedOfficeOnly); 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; 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.apache.commons.lang.StringUtils;
import org.joda.time.Days; import org.joda.time.Days;
import org.joda.time.LocalDate; 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.data.GroupRoleData;
import org.mifosplatform.portfolio.group.service.GroupReadPlatformService; import org.mifosplatform.portfolio.group.service.GroupReadPlatformService;
import org.mifosplatform.portfolio.group.service.SearchParameters; import org.mifosplatform.portfolio.group.service.SearchParameters;
import org.mifosplatform.portfolio.loanaccount.data.*; import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
import org.mifosplatform.portfolio.loanaccount.domain.*; 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.LoanNotFoundException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionNotFoundException; import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionNotFoundException;
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData; 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.stereotype.Service;
import org.springframework.util.CollectionUtils; 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 @Service
public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
@@ -678,7 +689,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
feeChargesDueAtDisbursementCharged, syncDisbursementWithMeeting, loanCounter, loanProductCounter); feeChargesDueAtDisbursementCharged, syncDisbursementWithMeeting, loanCounter, loanProductCounter);
} }
} }
private static final class OverdueLoanSchedule implements RowMapper<OverdueLoanScheduleData>{
private static final class MusoniOverdueLoanScheduleMapper implements RowMapper<OverdueLoanScheduleData> {
public String schema() { 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," 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,"
@@ -696,7 +708,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
} }
@Override @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 chargeId = rs.getLong("chargeId");
final Long loanId = rs.getLong("loanId"); final Long loanId = rs.getLong("loanId");
final BigDecimal amount = rs.getBigDecimal("amount"); final BigDecimal amount = rs.getBigDecimal("amount");
@@ -704,9 +716,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final String dueDate = rs.getString("dueDate"); final String dueDate = rs.getString("dueDate");
final String locale = "en_GB"; final String locale = "en_GB";
final OverdueLoanScheduleData overdueLoanScheduleData = new OverdueLoanScheduleData(loanId, chargeId, dueDate, amount,
OverdueLoanScheduleData overdueLoanScheduleData = new OverdueLoanScheduleData(loanId,chargeId,dueDate, dateFormat, locale);
amount,dateFormat,locale) ;
return overdueLoanScheduleData; return overdueLoanScheduleData;
} }
@@ -1129,13 +1140,14 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
} }
@Override @Override
public Collection<OverdueLoanScheduleData> retrieveAllOverdueLoans() { public Collection<OverdueLoanScheduleData> retrieveAllLoansWithOverdueInstallmentsNotAlreadyPenalized() {
final OverdueLoanSchedule rm = new OverdueLoanSchedule(); final MusoniOverdueLoanScheduleMapper rm = new MusoniOverdueLoanScheduleMapper();
final String sql = "select " + rm.schema() + final String sql = "select "
" where CURDATE() > ls.duedate "+ + rm.schema()
" and ls.completed_derived <> 1 and mc.charge_applies_to_enum =1 "+ + " where CURDATE() > ls.duedate "
" and mc.charge_time_enum = 9 and ml.loan_status_id = 300 "+ + " and ls.completed_derived <> 1 and mc.charge_applies_to_enum =1 "
" 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) "; + " 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[] {}); return this.jdbcTemplate.query(sql, rm, new Object[] {});
} }
} }
@@ -5,7 +5,17 @@
*/ */
package org.mifosplatform.portfolio.loanaccount.service; 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.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat; 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.Charge;
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode; import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper; 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.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.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.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.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.domain.Client;
import org.mifosplatform.portfolio.client.exception.ClientNotActiveException; import org.mifosplatform.portfolio.client.exception.ClientNotActiveException;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand; 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.command.LoanUpdateCommand;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData; import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanInstallmentChargeData; 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.LoanDisbursalException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException; import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerUnassignmentException; 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.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.math.BigDecimal; import com.google.gson.JsonElement;
import java.util.*;
@Service @Service
public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatformService { public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatformService {
private final static Logger logger = LoggerFactory.getLogger(LoanWritePlatformServiceJpaRepositoryImpl.class); private final static Logger logger = LoggerFactory.getLogger(LoanWritePlatformServiceJpaRepositoryImpl.class);
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final LoanEventApiJsonValidator loanEventApiJsonValidator; private final LoanEventApiJsonValidator loanEventApiJsonValidator;
private final LoanUpdateCommandFromApiJsonDeserializer loanUpdateCommandFromApiJsonDeserializer; private final LoanUpdateCommandFromApiJsonDeserializer loanUpdateCommandFromApiJsonDeserializer;
@@ -129,7 +152,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final LoanReadPlatformService loanReadPlatformService; private final LoanReadPlatformService loanReadPlatformService;
private final FromJsonHelper fromApiJsonHelper; private final FromJsonHelper fromApiJsonHelper;
@Autowired @Autowired
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final LoanEventApiJsonValidator loanEventApiJsonValidator, final LoanEventApiJsonValidator loanEventApiJsonValidator,
@@ -258,7 +280,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (loanCharge.isDueAtDisbursement() && loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) { if (loanCharge.isDueAtDisbursement() && loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
disBuLoanCharges.put(loanCharge.getId(), loanCharge.amount()); disBuLoanCharges.put(loanCharge.getId(), loanCharge.amount());
} else if (loanCharge.isInstalmentFee() && loanCharge.hasNoLoanInstallmentCharges()) { } else if (loanCharge.isInstalmentFee() && loanCharge.hasNoLoanInstallmentCharges()) {
Set<LoanInstallmentCharge> chargePerInstallments = loan.generateInstallmentLoanCharges(loanCharge); final Set<LoanInstallmentCharge> chargePerInstallments = loan.generateInstallmentLoanCharges(loanCharge);
loanCharge.addLoanInstallmentCharges(chargePerInstallments); loanCharge.addLoanInstallmentCharges(chargePerInstallments);
this.loanChargeRepository.save(loanCharge); this.loanChargeRepository.save(loanCharge);
} }
@@ -385,7 +407,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (loanCharge.isDueAtDisbursement() && loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) { if (loanCharge.isDueAtDisbursement() && loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
disBuLoanCharges.put(loanCharge.getId(), loanCharge.amount()); disBuLoanCharges.put(loanCharge.getId(), loanCharge.amount());
} else if (loanCharge.isInstalmentFee() && loanCharge.hasNoLoanInstallmentCharges()) { } else if (loanCharge.isInstalmentFee() && loanCharge.hasNoLoanInstallmentCharges()) {
Set<LoanInstallmentCharge> chargePerInstallments = loan.generateInstallmentLoanCharges(loanCharge); final Set<LoanInstallmentCharge> chargePerInstallments = loan.generateInstallmentLoanCharges(loanCharge);
loanCharge.addLoanInstallmentCharges(chargePerInstallments); loanCharge.addLoanInstallmentCharges(chargePerInstallments);
this.loanChargeRepository.save(loanCharge); this.loanChargeRepository.save(loanCharge);
} }
@@ -393,10 +415,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Locale locale = command.extractLocale(); final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
for (final Map.Entry<Long, BigDecimal> entrySet : disBuLoanCharges.entrySet()) { 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(), final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(actualDisbursementDate, entrySet.getValue(),
PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN, savingAccountData.accountId(), loan.getId(), "Loan Charge Payment", PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN, savingAccountData.accountId(), loan.getId(),
locale, fmt, null, null, LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getValue(), entrySet.getKey(), null); "Loan Charge Payment", locale, fmt, null, null, LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getValue(),
entrySet.getKey(), null);
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO); this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
} }
} }
@@ -576,7 +600,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
} }
final String noteText = command.stringValueOfParameterNamed("note"); final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) { if (StringUtils.isNotBlank(noteText)) {
changes.put("note", noteText); changes.put("note", noteText);
@@ -653,8 +676,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
} }
final String noteText = command.stringValueOfParameterNamed("note"); final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) { if (StringUtils.isNotBlank(noteText)) {
changes.put("note", noteText); changes.put("note", noteText);
@@ -876,7 +897,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
} }
// we post Journal entries only for loans in active status // we post Journal entries only for loans in active status
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
} }
@@ -943,8 +963,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (loanCharge.isWaived()) { if (loanCharge.isWaived()) {
throw new LoanChargeCannotBeWaivedException(LOAN_CHARGE_CANNOT_BE_WAIVED_REASON.ALREADY_WAIVED, loanCharge.getId()); 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, } else if (loanCharge.isPaid()) { throw new LoanChargeCannotBeWaivedException(LOAN_CHARGE_CANNOT_BE_WAIVED_REASON.ALREADY_PAID,
loanCharge.getId()); loanCharge.getId()); }
}
Integer loanInstallmentNumber = null; Integer loanInstallmentNumber = null;
if (loanCharge.isInstalmentFee()) { if (loanCharge.isInstalmentFee()) {
LoanInstallmentCharge chargePerInstallment = null; LoanInstallmentCharge chargePerInstallment = null;
@@ -962,9 +981,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
if (chargePerInstallment.isWaived()) { if (chargePerInstallment.isWaived()) {
throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_WAIVED, loanCharge.getId()); throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_WAIVED, loanCharge.getId());
}else if(chargePerInstallment.isPaid()){ } else if (chargePerInstallment.isPaid()) { throw new LoanChargeCannotBePayedException(
throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_PAID, loanCharge.getId()); LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_PAID, loanCharge.getId()); }
}
loanInstallmentNumber = chargePerInstallment.getRepaymentInstallment().getInstallmentNumber(); loanInstallmentNumber = chargePerInstallment.getRepaymentInstallment().getInstallmentNumber();
} }
@@ -1042,8 +1060,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (loanCharge.isWaived()) { if (loanCharge.isWaived()) {
throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_WAIVED, loanCharge.getId()); 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, } 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( if (!loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) { throw new LoanChargeCannotBePayedException(
LOAN_CHARGE_CANNOT_BE_PAYED_REASON.CHARGE_NOT_ACCOUNT_TRANSFER, loanCharge.getId()); } LOAN_CHARGE_CANNOT_BE_PAYED_REASON.CHARGE_NOT_ACCOUNT_TRANSFER, loanCharge.getId()); }
@@ -1068,9 +1085,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
if (chargePerInstallment.isWaived()) { if (chargePerInstallment.isWaived()) {
throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_WAIVED, loanCharge.getId()); throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_WAIVED, loanCharge.getId());
}else if(chargePerInstallment.isPaid()){ } else if (chargePerInstallment.isPaid()) { throw new LoanChargeCannotBePayedException(
throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_PAID, loanCharge.getId()); LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_PAID, loanCharge.getId()); }
}
loanInstallmentNumber = chargePerInstallment.getRepaymentInstallment().getInstallmentNumber(); loanInstallmentNumber = chargePerInstallment.getRepaymentInstallment().getInstallmentNumber();
amount = chargePerInstallment.getAmountOutstanding(); amount = chargePerInstallment.getAmountOutstanding();
} }
@@ -1080,9 +1096,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final String errorMessage = "Charge with id:" + loanChargeId + " requires linked savings account for payment"; final String errorMessage = "Charge with id:" + loanChargeId + " requires linked savings account for payment";
throw new LinkedAccountRequiredException("loanCharge.pay", errorMessage, loanChargeId); throw new LinkedAccountRequiredException("loanCharge.pay", errorMessage, loanChargeId);
} }
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(transactionDate, amount, final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(transactionDate, amount, PortfolioAccountType.SAVINGS,
PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN, portfolioAccountData.accountId(), loanId, "Loan Charge Payment", PortfolioAccountType.LOAN, portfolioAccountData.accountId(), loanId, "Loan Charge Payment", locale, fmt, null, null,
locale, fmt, null, null, LoanTransactionType.CHARGE_PAYMENT.getValue(), loanChargeId, loanInstallmentNumber); LoanTransactionType.CHARGE_PAYMENT.getValue(), loanChargeId, loanInstallmentNumber);
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO); this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
@@ -1104,18 +1120,20 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (chargeDatas != null) { if (chargeDatas != null) {
for (final LoanChargeData chargeData : chargeDatas) { for (final LoanChargeData chargeData : chargeDatas) {
if (chargeData.isInstallmentFee()) { if (chargeData.isInstallmentFee()) {
Collection<LoanInstallmentChargeData> chargePerInstallments = this.LoanChargeReadPlatformService.retrieveInstallmentLoanCharges(chargeData.getId(), true); final Collection<LoanInstallmentChargeData> chargePerInstallments = this.LoanChargeReadPlatformService
.retrieveInstallmentLoanCharges(chargeData.getId(), true);
PortfolioAccountData portfolioAccountData = null; PortfolioAccountData portfolioAccountData = null;
for(LoanInstallmentChargeData installmentChargeData : chargePerInstallments){ for (final LoanInstallmentChargeData installmentChargeData : chargePerInstallments) {
if (!installmentChargeData.getDueDate().isAfter(new LocalDate())) { if (!installmentChargeData.getDueDate().isAfter(new LocalDate())) {
if (portfolioAccountData == null) { if (portfolioAccountData == null) {
portfolioAccountData = this.accountAssociationsReadPlatformService portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(chargeData
.retriveLoanAssociation(chargeData.getLoanId()); .getLoanId());
} }
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(new LocalDate(), final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(new LocalDate(),
installmentChargeData.getAmountOutstanding(), PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN, installmentChargeData.getAmountOutstanding(), PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN,
portfolioAccountData.accountId(), chargeData.getLoanId(), "Loan Charge Payment", null, null, null, null, portfolioAccountData.accountId(), chargeData.getLoanId(), "Loan Charge Payment", null, null, null,
LoanTransactionType.CHARGE_PAYMENT.getValue(), chargeData.getId(), installmentChargeData.getInstallmentNumber()); null, LoanTransactionType.CHARGE_PAYMENT.getValue(), chargeData.getId(),
installmentChargeData.getInstallmentNumber());
transferFeeCharge(sb, accountTransferDTO); transferFeeCharge(sb, accountTransferDTO);
} }
} }
@@ -1601,22 +1619,25 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Override @Override
@CronTarget(jobName = JobName.APPLY_CHARGE_TO_OVERDUE_LOAN_INSTALLMENT) @CronTarget(jobName = JobName.APPLY_CHARGE_TO_OVERDUE_LOAN_INSTALLMENT)
public void applyChargeForOverdueLoans() throws JobExecutionException { public void applyChargeForOverdueLoans() throws JobExecutionException {
final Collection<OverdueLoanScheduleData> overdueLoanScheduleData = this.loanReadPlatformService.retrieveAllOverdueLoans();
if(!overdueLoanScheduleData.isEmpty()) { final Collection<OverdueLoanScheduleData> overdueLoanScheduledInstallments = this.loanReadPlatformService.retrieveAllLoansWithOverdueInstallmentsNotAlreadyPenalized();
for(OverdueLoanScheduleData overdueLoanScheduleData1 : overdueLoanScheduleData){
if (!overdueLoanScheduledInstallments.isEmpty()) {
for (final OverdueLoanScheduleData overdueInstallment : overdueLoanScheduledInstallments) {
try { try {
final JsonElement parsedCommand = fromApiJsonHelper.parse(overdueLoanScheduleData1.toString()); final JsonElement parsedCommand = this.fromApiJsonHelper.parse(overdueInstallment.toString());
final JsonCommand command = JsonCommand.from(overdueLoanScheduleData1.toString(),parsedCommand,this.fromApiJsonHelper,null,null, final JsonCommand command = JsonCommand.from(overdueInstallment.toString(), parsedCommand, this.fromApiJsonHelper,
null,null,null,overdueLoanScheduleData1.getLoanId(),null,null,null,null,null,null,null); null, null, null, null, null, overdueInstallment.getLoanId(), null, null, null, null, null, null, null);
this.applyChargeToOverdueLoanInstallment(overdueLoanScheduleData1.getLoanId(),overdueLoanScheduleData1.getChargeId(),command);
applyChargeToOverdueLoanInstallment(overdueInstallment.getLoanId(), overdueInstallment.getChargeId(), command);
} catch (final PlatformApiDataValidationException e) { } catch (final PlatformApiDataValidationException e) {
final List<ApiParameterError> errors = e.getErrors(); final List<ApiParameterError> errors = e.getErrors();
for (final ApiParameterError error : errors) { for (final ApiParameterError error : errors) {
logger.error("Apply Charges due for overdue loans failed for account:" + overdueLoanScheduleData1.getLoanId() + " with message " logger.error("Apply Charges due for overdue loans failed for account:" + overdueInstallment.getLoanId()
+ error.getDeveloperMessage()); + " with message " + error.getDeveloperMessage());
} }
} }
} }
@@ -1624,7 +1645,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
@Transactional @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); final Loan loan = this.loanAssembler.assembleFrom(loanId);
checkClientOrGroupActive(loan); checkClientOrGroupActive(loan);
@@ -1636,6 +1658,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final String errorMessage = "Charge and Loan must have the same currency."; final String errorMessage = "Charge and Loan must have the same currency.";
throw new InvalidCurrencyException("loanCharge", "attach.to.loan", errorMessage); throw new InvalidCurrencyException("loanCharge", "attach.to.loan", errorMessage);
} }
if (loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) { if (loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId); final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
if (portfolioAccountData == null) { if (portfolioAccountData == null) {
@@ -1656,13 +1679,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (loan.status().isActive()) { if (loan.status().isActive()) {
final LoanTransaction applyLoanChargeTransaction = loan.handleChargeAppliedTransaction(loanCharge, null); final LoanTransaction applyLoanChargeTransaction = loan.handleChargeAppliedTransaction(loanCharge, null);
this.loanTransactionRepository.save(applyLoanChargeTransaction); 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); this.loanRepository.saveAndFlush(loan);
if (changedTransactionDetail != null) { if (changedTransactionDetail != null) {
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { 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 // we post Journal entries only for loans in active status
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); 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.CalendarEntityType;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance; import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.calendar.exception.NotValidRecurringDateException; 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.attendance.domain.ClientAttendance;
import org.mifosplatform.portfolio.meeting.exception.MeetingDateException; import org.mifosplatform.portfolio.meeting.exception.MeetingDateException;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -163,7 +162,7 @@ public class Meeting extends AbstractPersistable<Long> {
} }
public boolean isMeetingDateBefore(final LocalDate newStartDate) { 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) { private static boolean isValidMeetingDate(final CalendarInstance calendarInstance, final Date meetingDate) {
@@ -173,8 +172,7 @@ public class Meeting extends AbstractPersistable<Long> {
meetingDateLocalDate = LocalDate.fromDateFields(meetingDate); meetingDateLocalDate = LocalDate.fromDateFields(meetingDate);
} }
if (meetingDateLocalDate == null if (meetingDateLocalDate == null || !calendar.isValidRecurringDate(meetingDateLocalDate)) { return false; }
|| !calendar.isValidRecurringDate(meetingDateLocalDate)) { return false; }
return true; return true;
} }