MIFOSX-97: some changes around loan officer reassingment capability for loans.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
drop table `m_loan_officer_assignment_history`;
|
||||
CREATE TABLE `m_loan_officer_assignment_history` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`loan_id` bigint(20) NOT NULL ,
|
||||
|
||||
+4
-3
@@ -13,11 +13,12 @@ public class BulkLoanReassignmentCommand {
|
||||
|
||||
private final String[] loans;
|
||||
|
||||
public BulkLoanReassignmentCommand(Long fromLoanOfficerId,
|
||||
Long toLoanOfficerId, LocalDate assignmentDate, String[] loans) {
|
||||
public BulkLoanReassignmentCommand(final Long fromLoanOfficerId,
|
||||
final Long toLoanOfficerId, final LocalDate assignmentDate,
|
||||
final String[] loans) {
|
||||
this.fromLoanOfficerId = fromLoanOfficerId;
|
||||
this.toLoanOfficerId = toLoanOfficerId;
|
||||
this.assignmentDate = assignmentDate;
|
||||
this.assignmentDate = assignmentDate;
|
||||
this.loans = loans;
|
||||
}
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
@LazyCollection(LazyCollectionOption.FALSE)
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true)
|
||||
private Set<LoanOfficerAssignmentHistory> loanOfficerAssignmentHistorySet;
|
||||
private Set<LoanOfficerAssignmentHistory> loanOfficerHistory;
|
||||
|
||||
// see
|
||||
// http://stackoverflow.com/questions/4334970/hibernate-cannot-simultaneously-fetch-multiple-bags
|
||||
@@ -188,7 +188,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
this.loanProduct = null;
|
||||
this.loanRepaymentScheduleDetail = null;
|
||||
this.charges = null;
|
||||
this.loanOfficerAssignmentHistorySet = null;
|
||||
this.loanOfficerHistory = null;
|
||||
}
|
||||
|
||||
private Loan(
|
||||
@@ -214,7 +214,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
} else {
|
||||
this.charges = null;
|
||||
}
|
||||
this.loanOfficerAssignmentHistorySet = null;
|
||||
this.loanOfficerHistory = null;
|
||||
}
|
||||
|
||||
private Loan(
|
||||
@@ -240,7 +240,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
} else {
|
||||
this.charges = null;
|
||||
}
|
||||
this.loanOfficerAssignmentHistorySet = null;
|
||||
this.loanOfficerHistory = null;
|
||||
}
|
||||
|
||||
private BigDecimal deriveSumTotalOfChargesDueAtDisbursement() {
|
||||
@@ -669,15 +669,14 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
}
|
||||
|
||||
public void approve(final LocalDate approvedOn,
|
||||
LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
public void approve(final LocalDate approvedOn, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
|
||||
LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVED, LoanStatus.fromInt(this.loanStatus));
|
||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVED, LoanStatus.fromInt(this.loanStatus));
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
|
||||
this.approvedOnDate = approvedOn.toDateTimeAtCurrentTime().toDate();
|
||||
|
||||
LocalDate submittalDate = new LocalDate(this.submittedOnDate);
|
||||
final LocalDate submittalDate = new LocalDate(this.submittedOnDate);
|
||||
if (approvedOn.isBefore(submittalDate)) {
|
||||
final String errorMessage = "The date on which a loan is approved cannot be before its submittal date: "
|
||||
+ submittalDate.toString();
|
||||
@@ -692,22 +691,20 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
getApprovedOnDate());
|
||||
}
|
||||
|
||||
if (this.loanofficer != null){
|
||||
LoanOfficerAssignmentHistory loanOfficerAssignmentHistory =
|
||||
LoanOfficerAssignmentHistory.createNew(this, this.loanofficer, approvedOn);
|
||||
this.loanOfficerAssignmentHistorySet.add(loanOfficerAssignmentHistory);
|
||||
if (this.loanofficer != null) {
|
||||
final LoanOfficerAssignmentHistory loanOfficerAssignmentHistory = LoanOfficerAssignmentHistory.createNew(this, this.loanofficer, approvedOn);
|
||||
this.loanOfficerHistory.add(loanOfficerAssignmentHistory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void undoApproval(LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
|
||||
LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVAL_UNDO, LoanStatus.fromInt(this.loanStatus));
|
||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVAL_UNDO, LoanStatus.fromInt(this.loanStatus));
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
|
||||
this.approvedOnDate = null;
|
||||
|
||||
this.loanOfficerAssignmentHistorySet.clear();
|
||||
this.loanOfficerHistory.clear();
|
||||
}
|
||||
|
||||
public void disburseWithModifiedRepaymentSchedule(
|
||||
@@ -1601,31 +1598,35 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return this.loanRepaymentScheduleDetail.getCurrency();
|
||||
}
|
||||
|
||||
public void updateLoanOfficer(final Staff newLoanOfficer, final LocalDate assignmentDate) {
|
||||
boolean createNewLoanOfficerAssignmentHistoryRecord = true;
|
||||
for (LoanOfficerAssignmentHistory lastLoanOfficerAssignmentHistoryRecord : this.loanOfficerAssignmentHistorySet){
|
||||
if (lastLoanOfficerAssignmentHistoryRecord.getEndDate() == null){
|
||||
if (this.loanofficer.identifiedBy(newLoanOfficer)){
|
||||
lastLoanOfficerAssignmentHistoryRecord.updateStartDate(assignmentDate);
|
||||
createNewLoanOfficerAssignmentHistoryRecord = false;
|
||||
} else if (lastLoanOfficerAssignmentHistoryRecord.getStartDate().isEqual(assignmentDate)){
|
||||
lastLoanOfficerAssignmentHistoryRecord.updateLoanOfficer(newLoanOfficer);
|
||||
createNewLoanOfficerAssignmentHistoryRecord = false;
|
||||
} else if (assignmentDate.isBefore(lastLoanOfficerAssignmentHistoryRecord.getStartDate())){
|
||||
throw new LoanOfficerAssignmentException(this.getId(), assignmentDate);
|
||||
} else {
|
||||
lastLoanOfficerAssignmentHistoryRecord.updateEndDate(assignmentDate);
|
||||
}
|
||||
break;
|
||||
}
|
||||
public void reassignLoanOfficer(final Staff newLoanOfficer, final LocalDate assignmentDate) {
|
||||
|
||||
final LoanOfficerAssignmentHistory latestHistoryRecord = findLatestIncompleteHistoryRecord();
|
||||
|
||||
if (this.loanofficer.identifiedBy(newLoanOfficer)) {
|
||||
latestHistoryRecord.updateStartDate(assignmentDate);
|
||||
} else if (latestHistoryRecord.matchesStartDateOf(assignmentDate)) {
|
||||
latestHistoryRecord.updateLoanOfficer(newLoanOfficer);
|
||||
this.loanofficer = newLoanOfficer;
|
||||
} else if (latestHistoryRecord.hasStartDateBefore(assignmentDate)) {
|
||||
throw new LoanOfficerAssignmentException(this.getId(), assignmentDate);
|
||||
} else {
|
||||
// loan officer correctly changed from previous loan officer to new loan officer
|
||||
latestHistoryRecord.updateEndDate(assignmentDate);
|
||||
|
||||
this.loanofficer = newLoanOfficer;
|
||||
final LoanOfficerAssignmentHistory loanOfficerAssignmentHistory = LoanOfficerAssignmentHistory.createNew(this, this.loanofficer, assignmentDate);
|
||||
this.loanOfficerHistory.add(loanOfficerAssignmentHistory);
|
||||
}
|
||||
}
|
||||
|
||||
if (createNewLoanOfficerAssignmentHistoryRecord){
|
||||
LoanOfficerAssignmentHistory loanOfficerAssignmentHistory =
|
||||
LoanOfficerAssignmentHistory.createNew(this, this.loanofficer, assignmentDate);
|
||||
this.loanOfficerAssignmentHistorySet.add(loanOfficerAssignmentHistory);
|
||||
}
|
||||
|
||||
this.loanofficer = newLoanOfficer;
|
||||
private LoanOfficerAssignmentHistory findLatestIncompleteHistoryRecord() {
|
||||
|
||||
LoanOfficerAssignmentHistory latestRecordWithNoEndDate = null;
|
||||
for (LoanOfficerAssignmentHistory historyRecord : this.loanOfficerHistory){
|
||||
if (historyRecord.isCurrentRecord()) {
|
||||
latestRecordWithNoEndDate = historyRecord;
|
||||
}
|
||||
}
|
||||
return latestRecordWithNoEndDate;
|
||||
}
|
||||
}
|
||||
+23
-28
@@ -1,6 +1,5 @@
|
||||
package org.mifosng.platform.loan.domain;
|
||||
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.infrastructure.AbstractAuditableCustom;
|
||||
import org.mifosng.platform.staff.domain.Staff;
|
||||
@@ -19,7 +18,7 @@ import java.util.Date;
|
||||
@Table(name = "m_loan_officer_assignment_history")
|
||||
public class LoanOfficerAssignmentHistory extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@SuppressWarnings("unused")
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "loan_id", nullable = false)
|
||||
private Loan loan;
|
||||
@@ -33,54 +32,50 @@ public class LoanOfficerAssignmentHistory extends AbstractAuditableCustom<AppUse
|
||||
@Column(name = "start_date")
|
||||
private Date startDate;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "end_date")
|
||||
private Date endDate;
|
||||
|
||||
public static LoanOfficerAssignmentHistory createNew(Loan loan, Staff loanOfficer,
|
||||
LocalDate startDate){
|
||||
public static LoanOfficerAssignmentHistory createNew(final Loan loan, final Staff loanOfficer, final LocalDate startDate) {
|
||||
return new LoanOfficerAssignmentHistory(loan, loanOfficer, startDate.toDate(), null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
protected LoanOfficerAssignmentHistory() {
|
||||
this.loan = null;
|
||||
this.loanOfficer = null;
|
||||
this.startDate = null;
|
||||
this.endDate = null;
|
||||
//
|
||||
}
|
||||
|
||||
private LoanOfficerAssignmentHistory(Loan loan, Staff loanOfficer,
|
||||
Date startDate, Date endDate) {
|
||||
private LoanOfficerAssignmentHistory(final Loan loan, final Staff loanOfficer, final Date startDate, final Date endDate) {
|
||||
this.loan = loan;
|
||||
this.loanOfficer = loanOfficer;
|
||||
this.startDate = startDate;
|
||||
this.endDate = endDate;
|
||||
}
|
||||
|
||||
public Loan getLoan() {
|
||||
return loan;
|
||||
}
|
||||
|
||||
public LocalDate getStartDate() {
|
||||
return new LocalDate(startDate);
|
||||
}
|
||||
|
||||
public Date getEndDate() {
|
||||
return endDate;
|
||||
}
|
||||
|
||||
public void updateLoanOfficer(Staff loanOfficer) {
|
||||
this.loanOfficer = loanOfficer;
|
||||
}
|
||||
|
||||
public void updateStartDate(LocalDate startDate){
|
||||
public void updateStartDate(LocalDate startDate) {
|
||||
this.startDate = startDate.toDate();
|
||||
}
|
||||
|
||||
public void updateEndDate(LocalDate endDate){
|
||||
public void updateEndDate(LocalDate endDate) {
|
||||
this.endDate = endDate.toDate();
|
||||
}
|
||||
|
||||
}
|
||||
public boolean matchesStartDateOf(final LocalDate matchingDate) {
|
||||
return getStartDate().isEqual(matchingDate);
|
||||
}
|
||||
|
||||
private LocalDate getStartDate() {
|
||||
return new LocalDate(startDate);
|
||||
}
|
||||
|
||||
public boolean hasStartDateBefore(final LocalDate matchingDate) {
|
||||
return matchingDate.isBefore(getStartDate());
|
||||
}
|
||||
|
||||
public boolean isCurrentRecord() {
|
||||
return this.endDate == null;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -754,7 +754,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
throw new LoanOfficerAssignmentException(loan.getId(), fromLoanOfficer.getId());
|
||||
}
|
||||
|
||||
loan.updateLoanOfficer(toLoanOfficer, command.getAssignmentDate());
|
||||
loan.reassignLoanOfficer(toLoanOfficer, command.getAssignmentDate());
|
||||
this.loanRepository.save(loan);
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ public class Staff extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return loanOfficerFlag;
|
||||
}
|
||||
|
||||
public boolean identifiedBy(Staff staff) {
|
||||
public boolean identifiedBy(final Staff staff) {
|
||||
return getId().equals(staff.getId());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user