From 3e16891cfb53eadcb5c1e86fbb23118922f4f4d9 Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Mon, 12 Nov 2012 17:16:30 +0000 Subject: [PATCH] MIFOSX-97: some changes around loan officer reassingment capability for loans. --- ...0013-loan_officer_reassignment_history.sql | 1 + .../commands/BulkLoanReassignmentCommand.java | 7 +- .../mifosng/platform/loan/domain/Loan.java | 79 ++++++++++--------- .../domain/LoanOfficerAssignmentHistory.java | 51 ++++++------ ...WritePlatformServiceJpaRepositoryImpl.java | 2 +- .../mifosng/platform/staff/domain/Staff.java | 2 +- 6 files changed, 70 insertions(+), 72 deletions(-) diff --git a/mifosng-db/patches/patch-0013-loan_officer_reassignment_history.sql b/mifosng-db/patches/patch-0013-loan_officer_reassignment_history.sql index d68b716b8..caee211f5 100644 --- a/mifosng-db/patches/patch-0013-loan_officer_reassignment_history.sql +++ b/mifosng-db/patches/patch-0013-loan_officer_reassignment_history.sql @@ -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 , diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/BulkLoanReassignmentCommand.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/BulkLoanReassignmentCommand.java index a685b03c8..8767d1419 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/BulkLoanReassignmentCommand.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/BulkLoanReassignmentCommand.java @@ -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; } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/Loan.java index 421b60073..b15bda1d7 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/Loan.java @@ -149,7 +149,7 @@ public class Loan extends AbstractAuditableCustom { @LazyCollection(LazyCollectionOption.FALSE) @OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true) - private Set loanOfficerAssignmentHistorySet; + private Set loanOfficerHistory; // see // http://stackoverflow.com/questions/4334970/hibernate-cannot-simultaneously-fetch-multiple-bags @@ -188,7 +188,7 @@ public class Loan extends AbstractAuditableCustom { 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 { } else { this.charges = null; } - this.loanOfficerAssignmentHistorySet = null; + this.loanOfficerHistory = null; } private Loan( @@ -240,7 +240,7 @@ public class Loan extends AbstractAuditableCustom { } else { this.charges = null; } - this.loanOfficerAssignmentHistorySet = null; + this.loanOfficerHistory = null; } private BigDecimal deriveSumTotalOfChargesDueAtDisbursement() { @@ -669,15 +669,14 @@ public class Loan extends AbstractAuditableCustom { } } - 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 { 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 { 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; } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanOfficerAssignmentHistory.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanOfficerAssignmentHistory.java index 230597af9..68728f94e 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanOfficerAssignmentHistory.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanOfficerAssignmentHistory.java @@ -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 { - @SuppressWarnings("unused") + @SuppressWarnings("unused") @ManyToOne @JoinColumn(name = "loan_id", nullable = false) private Loan loan; @@ -33,54 +32,50 @@ public class LoanOfficerAssignmentHistory extends AbstractAuditableCustom { return loanOfficerFlag; } - public boolean identifiedBy(Staff staff) { + public boolean identifiedBy(final Staff staff) { return getId().equals(staff.getId()); } } \ No newline at end of file