MIFOSX-73: new API for loan officer reassignment.

This commit is contained in:
Michal Dudzinski
2012-11-17 14:18:54 +01:00
parent 35a331debd
commit 015400b08e
13 changed files with 259 additions and 110 deletions
@@ -19,10 +19,12 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.mifosng.platform.api.commands.AdjustLoanTransactionCommand; import org.mifosng.platform.api.commands.AdjustLoanTransactionCommand;
import org.mifosng.platform.api.commands.CalculateLoanScheduleCommand; import org.mifosng.platform.api.commands.CalculateLoanScheduleCommand;
import org.mifosng.platform.api.commands.LoanApplicationCommand; import org.mifosng.platform.api.commands.LoanApplicationCommand;
import org.mifosng.platform.api.commands.LoanChargeCommand; import org.mifosng.platform.api.commands.LoanChargeCommand;
import org.mifosng.platform.api.commands.LoanReassignmentCommand;
import org.mifosng.platform.api.commands.LoanStateTransitionCommand; import org.mifosng.platform.api.commands.LoanStateTransitionCommand;
import org.mifosng.platform.api.commands.LoanTransactionCommand; import org.mifosng.platform.api.commands.LoanTransactionCommand;
import org.mifosng.platform.api.commands.UndoStateTransitionCommand; import org.mifosng.platform.api.commands.UndoStateTransitionCommand;
@@ -36,6 +38,7 @@ import org.mifosng.platform.api.data.LoanBasicDetailsData;
import org.mifosng.platform.api.data.LoanChargeData; import org.mifosng.platform.api.data.LoanChargeData;
import org.mifosng.platform.api.data.LoanPermissionData; import org.mifosng.platform.api.data.LoanPermissionData;
import org.mifosng.platform.api.data.LoanProductData; import org.mifosng.platform.api.data.LoanProductData;
import org.mifosng.platform.api.data.LoanReassignmentData;
import org.mifosng.platform.api.data.LoanTransactionData; import org.mifosng.platform.api.data.LoanTransactionData;
import org.mifosng.platform.api.data.StaffData; import org.mifosng.platform.api.data.StaffData;
import org.mifosng.platform.api.data.TransactionProcessingStrategyData; import org.mifosng.platform.api.data.TransactionProcessingStrategyData;
@@ -226,7 +229,6 @@ public class LoansApiResource {
Collection<EnumOptionData> interestTypeOptions = null; Collection<EnumOptionData> interestTypeOptions = null;
Collection<EnumOptionData> interestCalculationPeriodTypeOptions = null; Collection<EnumOptionData> interestCalculationPeriodTypeOptions = null;
Collection<FundData> fundOptions = null; Collection<FundData> fundOptions = null;
Collection<StaffData> allowedLoanOfficers = null;
Collection<ChargeData> chargeOptions = null; Collection<ChargeData> chargeOptions = null;
ChargeData chargeTemplate = null; ChargeData chargeTemplate = null;
@@ -245,7 +247,6 @@ public class LoansApiResource {
repaymentStrategyOptions = this.dropdownReadPlatformService.retreiveTransactionProcessingStrategies(); repaymentStrategyOptions = this.dropdownReadPlatformService.retreiveTransactionProcessingStrategies();
final boolean feeChargesOnly = false; final boolean feeChargesOnly = false;
chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly); chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(loanBasicDetails.getClientOfficeId());
chargeTemplate = this.chargeReadPlatformService.retrieveLoanChargeTemplate(); chargeTemplate = this.chargeReadPlatformService.retrieveLoanChargeTemplate();
} }
@@ -254,7 +255,7 @@ public class LoansApiResource {
productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
repaymentStrategyOptions, interestRateFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions,
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers); fundOptions, chargeOptions, chargeTemplate, null);
return this.apiJsonSerializerService.serializeLoanAccountDataToJson(prettyPrint, responseParameters, loanAccount); return this.apiJsonSerializerService.serializeLoanAccountDataToJson(prettyPrint, responseParameters, loanAccount);
} }
@@ -584,4 +585,43 @@ public class LoansApiResource {
final EntityIdentifier identifier = this.loanWritePlatformService.deleteLoanCharge(loanId, loanChargeId); final EntityIdentifier identifier = this.loanWritePlatformService.deleteLoanCharge(loanId, loanChargeId);
return this.apiJsonSerializerService.serializeEntityIdentifier(identifier); return this.apiJsonSerializerService.serializeEntityIdentifier(identifier);
} }
@POST
@Path("{loanId}/assign")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response assignLoanOfficer(
@PathParam("loanId") final Long loanId,
final String jsonRequestBody){
final LoanReassignmentCommand command = this.apiDataConversionService.convertJsonToLoanReassignmentCommand(loanId, jsonRequestBody);
EntityIdentifier identifier = this.loanWritePlatformService.loanReassignment(command);
return Response.ok().entity(identifier).build();
}
@GET
@Path("{loanId}/assign/template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String assignLoanOfficerTemplate(
@PathParam("loanId") final Long loanId,
@Context final UriInfo uriInfo){
final Set<String> responseParameters = ApiParameterHelper
.extractFieldsForResponseIfProvided(uriInfo
.getQueryParameters());
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
LoanBasicDetailsData loanBasicDetails = this.loanReadPlatformService.retrieveLoanAccountDetails(loanId);
Collection<StaffData> allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(loanBasicDetails.getOfficeId());
Long fromLoanOfficerId = loanBasicDetails.getLoanOfficerId();
LoanReassignmentData loanReassignmentData = LoanReassignmentData.template(fromLoanOfficerId, allowedLoanOfficers, new LocalDate());
return this.apiJsonSerializerService.serializeLoanReassignmentDataToJson(prettyPrint, responseParameters, loanReassignmentData);
}
} }
@@ -19,7 +19,7 @@ import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosng.platform.api.commands.BulkLoanReassignmentCommand; import org.mifosng.platform.api.commands.LoanReassignmentCommand;
import org.mifosng.platform.api.commands.StaffCommand; import org.mifosng.platform.api.commands.StaffCommand;
import org.mifosng.platform.api.data.EntityIdentifier; import org.mifosng.platform.api.data.EntityIdentifier;
import org.mifosng.platform.api.data.LoanReassignmentData; import org.mifosng.platform.api.data.LoanReassignmentData;
@@ -154,7 +154,7 @@ public class StaffApiResource {
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public Response loanReassignment(final String jsonRequestBody){ public Response loanReassignment(final String jsonRequestBody){
BulkLoanReassignmentCommand command = LoanReassignmentCommand command =
this.apiDataConversionService.convertJsonToBulkLoanReassignmentCommand(jsonRequestBody); this.apiDataConversionService.convertJsonToBulkLoanReassignmentCommand(jsonRequestBody);
EntityIdentifier loanOfficerIdentifier = this.loanWritePlatformService.bulkLoanReassignment(command); EntityIdentifier loanOfficerIdentifier = this.loanWritePlatformService.bulkLoanReassignment(command);
@@ -191,7 +191,7 @@ public class StaffApiResource {
staffAccountSummaryCollectionData = this.readPlatformService.retrieveLoanOfficerAccountSummary(loanOfficerId); staffAccountSummaryCollectionData = this.readPlatformService.retrieveLoanOfficerAccountSummary(loanOfficerId);
} }
final LoanReassignmentData loanReassignmentData = new LoanReassignmentData(officeId, loanOfficerId, final LoanReassignmentData loanReassignmentData = LoanReassignmentData.templateForBulk(officeId, loanOfficerId,
new LocalDate(), offices, loanOfficers, staffAccountSummaryCollectionData); new LocalDate(), offices, loanOfficers, staffAccountSummaryCollectionData);
return this.apiJsonSerializerService.serializeLoanReassignmentDataToJson(prettyPrint, responseParameters, loanReassignmentData); return this.apiJsonSerializerService.serializeLoanReassignmentDataToJson(prettyPrint, responseParameters, loanReassignmentData);
@@ -1,40 +0,0 @@
package org.mifosng.platform.api.commands;
import org.joda.time.LocalDate;
/**
* Immutable data object for reassigning loan officers on loans in bulk.
*/
public class BulkLoanReassignmentCommand {
private final Long fromLoanOfficerId;
private final Long toLoanOfficerId;
private final LocalDate assignmentDate;
private final 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.loans = loans;
}
public Long getFromLoanOfficerId() {
return fromLoanOfficerId;
}
public Long getToLoanOfficerId() {
return toLoanOfficerId;
}
public LocalDate getAssignmentDate() {
return assignmentDate;
}
public String[] getLoans() {
return loans;
}
}
@@ -0,0 +1,55 @@
package org.mifosng.platform.api.commands;
import org.joda.time.LocalDate;
/**
* Immutable data object for reassigning loan officers on loans in bulk.
*/
public class LoanReassignmentCommand {
private final Long loanId;
private final Long fromLoanOfficerId;
private final Long toLoanOfficerId;
private final LocalDate assignmentDate;
private final String[] loans;
public LoanReassignmentCommand(Long loanId, Long fromLoanOfficerId,
Long toLoanOfficerId, LocalDate assignmentDate) {
this.loanId = loanId;
this.fromLoanOfficerId = fromLoanOfficerId;
this.toLoanOfficerId = toLoanOfficerId;
this.assignmentDate = assignmentDate;
this.loans = null;
}
public LoanReassignmentCommand(Long fromLoanOfficerId, Long toLoanOfficerId,
LocalDate assignmentDate, String[] loans) {
this.fromLoanOfficerId = fromLoanOfficerId;
this.toLoanOfficerId = toLoanOfficerId;
this.assignmentDate = assignmentDate;
this.loans = loans;
this.loanId = null;
}
public Long getLoanId() {
return loanId;
}
public Long getFromLoanOfficerId() {
return fromLoanOfficerId;
}
public Long getToLoanOfficerId() {
return toLoanOfficerId;
}
public LocalDate getAssignmentDate() {
return assignmentDate;
}
public String[] getLoans() {
return loans;
}
}
@@ -560,4 +560,15 @@ public class LoanBasicDetailsData {
public DisbursementData toDisburementData() { public DisbursementData toDisburementData() {
return new DisbursementData(this.expectedDisbursementDate, this.actualDisbursementDate, this.principal); return new DisbursementData(this.expectedDisbursementDate, this.actualDisbursementDate, this.principal);
} }
public Long getOfficeId(){
Long officeId = this.clientOfficeId;
if (officeId == null){
officeId = this.groupOfficeId;
}
return officeId;
}
} }
@@ -24,7 +24,22 @@ public class LoanReassignmentData {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final StaffAccountSummaryCollectionData accountSummaryCollection; private final StaffAccountSummaryCollectionData accountSummaryCollection;
public LoanReassignmentData( public static LoanReassignmentData templateForBulk(final Long officeId,
final Long fromLoanOfficerId,
final LocalDate assignmentDate,
final Collection<OfficeLookup> officeOptions,
final Collection<StaffData> loanOfficerOptions,
final StaffAccountSummaryCollectionData accountSummaryCollection) {
return new LoanReassignmentData(officeId, fromLoanOfficerId, assignmentDate, officeOptions, loanOfficerOptions, accountSummaryCollection);
}
public static LoanReassignmentData template(final Long fromLoanOfficerId,
final Collection<StaffData> loanOfficerOptions,
final LocalDate assignmentDate){
return new LoanReassignmentData(null, fromLoanOfficerId, assignmentDate, null, loanOfficerOptions, null);
}
private LoanReassignmentData(
final Long officeId, final Long officeId,
final Long fromLoanOfficerId, final Long fromLoanOfficerId,
final LocalDate assignmentDate, final LocalDate assignmentDate,
@@ -2,7 +2,7 @@ package org.mifosng.platform.api.infrastructure;
import org.mifosng.platform.api.commands.AdjustLoanTransactionCommand; import org.mifosng.platform.api.commands.AdjustLoanTransactionCommand;
import org.mifosng.platform.api.commands.BranchMoneyTransferCommand; import org.mifosng.platform.api.commands.BranchMoneyTransferCommand;
import org.mifosng.platform.api.commands.BulkLoanReassignmentCommand; import org.mifosng.platform.api.commands.LoanReassignmentCommand;
import org.mifosng.platform.api.commands.ChargeCommand; import org.mifosng.platform.api.commands.ChargeCommand;
import org.mifosng.platform.api.commands.ClientCommand; import org.mifosng.platform.api.commands.ClientCommand;
import org.mifosng.platform.api.commands.ClientIdentifierCommand; import org.mifosng.platform.api.commands.ClientIdentifierCommand;
@@ -76,7 +76,9 @@ public interface PortfolioApiDataConversionService {
StaffCommand convertJsonToStaffCommand(Long resourceIdentifier, String json); StaffCommand convertJsonToStaffCommand(Long resourceIdentifier, String json);
BulkLoanReassignmentCommand convertJsonToBulkLoanReassignmentCommand(String json); LoanReassignmentCommand convertJsonToLoanReassignmentCommand(Long resourceIdentifier, String json);
LoanReassignmentCommand convertJsonToBulkLoanReassignmentCommand(String json);
DepositAccountWithdrawalCommand convertJsonToDepositWithdrawalCommand(Long resourceIdentifier, String json); DepositAccountWithdrawalCommand convertJsonToDepositWithdrawalCommand(Long resourceIdentifier, String json);
@@ -19,7 +19,7 @@ import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormat;
import org.mifosng.platform.api.commands.AdjustLoanTransactionCommand; import org.mifosng.platform.api.commands.AdjustLoanTransactionCommand;
import org.mifosng.platform.api.commands.BranchMoneyTransferCommand; import org.mifosng.platform.api.commands.BranchMoneyTransferCommand;
import org.mifosng.platform.api.commands.BulkLoanReassignmentCommand; import org.mifosng.platform.api.commands.LoanReassignmentCommand;
import org.mifosng.platform.api.commands.ChargeCommand; import org.mifosng.platform.api.commands.ChargeCommand;
import org.mifosng.platform.api.commands.ClientCommand; import org.mifosng.platform.api.commands.ClientCommand;
import org.mifosng.platform.api.commands.ClientIdentifierCommand; import org.mifosng.platform.api.commands.ClientIdentifierCommand;
@@ -157,7 +157,32 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo
} }
@Override @Override
public BulkLoanReassignmentCommand convertJsonToBulkLoanReassignmentCommand(final String json) { public LoanReassignmentCommand convertJsonToLoanReassignmentCommand(Long resourceIdentifier, String json) {
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
}
Type typeOfMap = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> requestMap = gsonConverter.fromJson(json, typeOfMap);
Set<String> supportedParams = new HashSet<String>(
Arrays.asList("fromLoanOfficerId", "toLoanOfficerId", "assignmentDate", "locale", "dateFormat")
);
checkForUnsupportedParameters(requestMap, supportedParams);
Set<String> modifiedParameters = new HashSet<String>();
Long fromLoanOfficerId = extractLongParameter("fromLoanOfficerId", requestMap, modifiedParameters);
Long toLoanOfficerId = extractLongParameter("toLoanOfficerId", requestMap, modifiedParameters);
LocalDate assignmentDate = extractLocalDateParameter("assignmentDate", requestMap, modifiedParameters);
return new LoanReassignmentCommand(resourceIdentifier, fromLoanOfficerId, toLoanOfficerId, assignmentDate);
}
@Override
public LoanReassignmentCommand convertJsonToBulkLoanReassignmentCommand(final String json) {
if (StringUtils.isBlank(json)) { if (StringUtils.isBlank(json)) {
throw new InvalidJsonException(); throw new InvalidJsonException();
@@ -196,7 +221,7 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo
} }
// //
return new BulkLoanReassignmentCommand(fromLoanOfficerId, toLoanOfficerId, assignmentDate, loans); return new LoanReassignmentCommand(fromLoanOfficerId, toLoanOfficerId, assignmentDate, loans);
} }
@Override @Override
@@ -448,7 +448,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
public void modifyLoanApplication(final LoanApplicationCommand command, final Client client, final LoanProduct loanProduct, public void modifyLoanApplication(final LoanApplicationCommand command, final Client client, final LoanProduct loanProduct,
final Fund fund, final LoanTransactionProcessingStrategy strategy, final LoanScheduleData modifiedLoanSchedule, final Set<LoanCharge> charges, final Fund fund, final LoanTransactionProcessingStrategy strategy, final LoanScheduleData modifiedLoanSchedule, final Set<LoanCharge> charges,
final Staff loanOfficer,
final LoanLifecycleStateMachine loanLifecycleStateMachine) { final LoanLifecycleStateMachine loanLifecycleStateMachine) {
// FIXME - KW - whilst the methods are named isXXXChanged, this really only is asking has the parameter for that field been passed in request, // FIXME - KW - whilst the methods are named isXXXChanged, this really only is asking has the parameter for that field been passed in request,
@@ -462,9 +461,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
if (command.isFundChanged()) { if (command.isFundChanged()) {
this.fund = fund; this.fund = fund;
} }
if(command.isLoanOfficerChanged()){
this.loanofficer = loanOfficer;
}
if (command.isTransactionStrategyChanged()) { if (command.isTransactionStrategyChanged()) {
this.transactionProcessingStrategy = strategy; this.transactionProcessingStrategy = strategy;
} }
@@ -1602,16 +1598,18 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
final LoanOfficerAssignmentHistory latestHistoryRecord = findLatestIncompleteHistoryRecord(); final LoanOfficerAssignmentHistory latestHistoryRecord = findLatestIncompleteHistoryRecord();
if (this.loanofficer.identifiedBy(newLoanOfficer)) { if (latestHistoryRecord != null && this.loanofficer.identifiedBy(newLoanOfficer)) {
latestHistoryRecord.updateStartDate(assignmentDate); latestHistoryRecord.updateStartDate(assignmentDate);
} else if (latestHistoryRecord.matchesStartDateOf(assignmentDate)) { } else if (latestHistoryRecord != null && latestHistoryRecord.matchesStartDateOf(assignmentDate)) {
latestHistoryRecord.updateLoanOfficer(newLoanOfficer); latestHistoryRecord.updateLoanOfficer(newLoanOfficer);
this.loanofficer = newLoanOfficer; this.loanofficer = newLoanOfficer;
} else if (latestHistoryRecord.hasStartDateBefore(assignmentDate)) { } else if (latestHistoryRecord != null && latestHistoryRecord.hasStartDateBefore(assignmentDate)) {
throw new LoanOfficerAssignmentException(this.getId(), assignmentDate); throw new LoanOfficerAssignmentException(this.getId(), assignmentDate);
} else { } else {
// loan officer correctly changed from previous loan officer to new loan officer if (latestHistoryRecord != null){
latestHistoryRecord.updateEndDate(assignmentDate); // loan officer correctly changed from previous loan officer to new loan officer
latestHistoryRecord.updateEndDate(assignmentDate);
}
this.loanofficer = newLoanOfficer; this.loanofficer = newLoanOfficer;
final LoanOfficerAssignmentHistory loanOfficerAssignmentHistory = LoanOfficerAssignmentHistory.createNew(this, this.loanofficer, assignmentDate); final LoanOfficerAssignmentHistory loanOfficerAssignmentHistory = LoanOfficerAssignmentHistory.createNew(this, this.loanofficer, assignmentDate);
@@ -0,0 +1,54 @@
package org.mifosng.platform.loan.service;
import org.mifosng.platform.DataValidatorBuilder;
import org.mifosng.platform.api.commands.LoanReassignmentCommand;
import org.mifosng.platform.api.data.ApiParameterError;
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
import java.util.ArrayList;
import java.util.List;
public class LoanReassignmentCommandValidator {
private final LoanReassignmentCommand command;
public LoanReassignmentCommandValidator(LoanReassignmentCommand command) {
this.command = command;
}
public void validateForBulkLoanReassignment(){
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loans.reassignment");
baseDataValidator.reset().parameter("fromLoanOfficerId").value(command.getFromLoanOfficerId()).
notNull().integerGreaterThanZero();
baseDataValidator.reset().parameter("toLoanOfficerId").value(command.getToLoanOfficerId()).notNull().
integerGreaterThanZero().notSameAsParameter("fromLoanOfficerId", command.getFromLoanOfficerId());
baseDataValidator.reset().parameter("assignmentDate").value(command.getAssignmentDate()).notNull();
baseDataValidator.reset().parameter("loans").value(command.getLoans()).arrayNotEmpty();
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
}
}
public void validateForLoanReassignment(){
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loans.reassignment");
baseDataValidator.reset().parameter("toLoanOfficerId").value(command.getToLoanOfficerId()).notNull().
integerGreaterThanZero().notSameAsParameter("fromLoanOfficerId", command.getFromLoanOfficerId());
baseDataValidator.reset().parameter("assignmentDate").value(command.getAssignmentDate()).notNull();
baseDataValidator.reset().parameter("loanId").value(command.getLoanId()).notNull();
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
}
}
}
@@ -1,7 +1,7 @@
package org.mifosng.platform.loan.service; package org.mifosng.platform.loan.service;
import org.mifosng.platform.api.commands.AdjustLoanTransactionCommand; import org.mifosng.platform.api.commands.AdjustLoanTransactionCommand;
import org.mifosng.platform.api.commands.BulkLoanReassignmentCommand; import org.mifosng.platform.api.commands.LoanReassignmentCommand;
import org.mifosng.platform.api.commands.LoanChargeCommand; import org.mifosng.platform.api.commands.LoanChargeCommand;
import org.mifosng.platform.api.commands.LoanStateTransitionCommand; import org.mifosng.platform.api.commands.LoanStateTransitionCommand;
import org.mifosng.platform.api.commands.LoanTransactionCommand; import org.mifosng.platform.api.commands.LoanTransactionCommand;
@@ -70,5 +70,8 @@ public interface LoanWritePlatformService {
EntityIdentifier waiveLoanCharge(LoanChargeCommand command); EntityIdentifier waiveLoanCharge(LoanChargeCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'BULKREASSIGN_LOAN')") @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'BULKREASSIGN_LOAN')")
EntityIdentifier bulkLoanReassignment(final BulkLoanReassignmentCommand command); EntityIdentifier bulkLoanReassignment(final LoanReassignmentCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER')")
EntityIdentifier loanReassignment(final LoanReassignmentCommand command);
} }
@@ -10,7 +10,7 @@ import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosng.platform.api.LoanScheduleData; import org.mifosng.platform.api.LoanScheduleData;
import org.mifosng.platform.api.commands.AdjustLoanTransactionCommand; import org.mifosng.platform.api.commands.AdjustLoanTransactionCommand;
import org.mifosng.platform.api.commands.BulkLoanReassignmentCommand; import org.mifosng.platform.api.commands.LoanReassignmentCommand;
import org.mifosng.platform.api.commands.CalculateLoanScheduleCommand; import org.mifosng.platform.api.commands.CalculateLoanScheduleCommand;
import org.mifosng.platform.api.commands.LoanApplicationCommand; import org.mifosng.platform.api.commands.LoanApplicationCommand;
import org.mifosng.platform.api.commands.LoanChargeCommand; import org.mifosng.platform.api.commands.LoanChargeCommand;
@@ -55,7 +55,6 @@ import org.mifosng.platform.loan.domain.LoanTransactionRepository;
import org.mifosng.platform.loan.domain.PeriodFrequencyType; import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.mifosng.platform.security.PlatformSecurityContext; import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.staff.domain.Staff; import org.mifosng.platform.staff.domain.Staff;
import org.mifosng.platform.staff.service.BulkLoanReassignmentCommandValidator;
import org.mifosng.platform.user.domain.AppUser; import org.mifosng.platform.user.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
@@ -158,7 +157,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
final Fund fund = this.loanAssembler.findFundByIdIfProvided(command.getFundId()); final Fund fund = this.loanAssembler.findFundByIdIfProvided(command.getFundId());
final Staff loanOfficer = this.loanAssembler.findLoanOfficerByIdIfProvided(command.getLoanOfficerId());
final LoanTransactionProcessingStrategy strategy = this.loanAssembler.findStrategyByIdIfProvided(command.getTransactionProcessingStrategyId()); final LoanTransactionProcessingStrategy strategy = this.loanAssembler.findStrategyByIdIfProvided(command.getTransactionProcessingStrategyId());
final Set<LoanCharge> charges = this.loanChargeAssembler.assembleFrom(command.getCharges(), loanProduct.getCharges(), loan.getPrincpal().getAmount()); final Set<LoanCharge> charges = this.loanChargeAssembler.assembleFrom(command.getCharges(), loanProduct.getCharges(), loan.getPrincpal().getAmount());
@@ -166,7 +164,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
// FIXME - kw - restrict ability to modify loan to modifying the 'loan application' stage - once it has been disbursed, should be allowed to use this feature // FIXME - kw - restrict ability to modify loan to modifying the 'loan application' stage - once it has been disbursed, should be allowed to use this feature
// - other facilities are in place such as 'undo disbursal' // - other facilities are in place such as 'undo disbursal'
loan.modifyLoanApplication(command, client, loanProduct, fund, strategy, loanSchedule, charges, loanOfficer, defaultLoanLifecycleStateMachine()); loan.modifyLoanApplication(command, client, loanProduct, fund, strategy, loanSchedule, charges, defaultLoanLifecycleStateMachine());
this.loanRepository.save(loan); this.loanRepository.save(loan);
@@ -732,14 +730,39 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
return loanCharge; return loanCharge;
} }
@Transactional @Transactional
@Override @Override
public EntityIdentifier bulkLoanReassignment(final BulkLoanReassignmentCommand command) { public EntityIdentifier loanReassignment(LoanReassignmentCommand command) {
this.context.authenticatedUser(); this.context.authenticatedUser();
BulkLoanReassignmentCommandValidator validator = new BulkLoanReassignmentCommandValidator(command); LoanReassignmentCommandValidator validator = new LoanReassignmentCommandValidator(command);
validator.validateLoanReassignment(); validator.validateForLoanReassignment();
final Staff fromLoanOfficer = loanAssembler.findLoanOfficerByIdIfProvided(command.getFromLoanOfficerId());
final Staff toLoanOfficer = loanAssembler.findLoanOfficerByIdIfProvided(command.getToLoanOfficerId());
final Loan loan = retrieveLoanBy(command.getLoanId());
if (!loan.hasLoanOfficer(fromLoanOfficer)){
throw new LoanOfficerAssignmentException(loan.getId(), fromLoanOfficer.getId());
}
loan.reassignLoanOfficer(toLoanOfficer, command.getAssignmentDate());
this.loanRepository.saveAndFlush(loan);
return new EntityIdentifier(loan.getId());
}
@Transactional
@Override
public EntityIdentifier bulkLoanReassignment(final LoanReassignmentCommand command) {
this.context.authenticatedUser();
LoanReassignmentCommandValidator validator = new LoanReassignmentCommandValidator(command);
validator.validateForBulkLoanReassignment();
Staff fromLoanOfficer = loanAssembler.findLoanOfficerByIdIfProvided(command.getFromLoanOfficerId()); Staff fromLoanOfficer = loanAssembler.findLoanOfficerByIdIfProvided(command.getFromLoanOfficerId());
Staff toLoanOfficer = loanAssembler.findLoanOfficerByIdIfProvided(command.getToLoanOfficerId()); Staff toLoanOfficer = loanAssembler.findLoanOfficerByIdIfProvided(command.getToLoanOfficerId());
@@ -1,37 +0,0 @@
package org.mifosng.platform.staff.service;
import org.mifosng.platform.DataValidatorBuilder;
import org.mifosng.platform.api.commands.BulkLoanReassignmentCommand;
import org.mifosng.platform.api.data.ApiParameterError;
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
import java.util.ArrayList;
import java.util.List;
public class BulkLoanReassignmentCommandValidator {
private final BulkLoanReassignmentCommand command;
public BulkLoanReassignmentCommandValidator(BulkLoanReassignmentCommand command) {
this.command = command;
}
public void validateLoanReassignment(){
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("staff.account.transfer");
baseDataValidator.reset().parameter("fromLoanOfficerId").value(command.getFromLoanOfficerId()).
notNull().integerGreaterThanZero();
baseDataValidator.reset().parameter("toLoanOfficerId").value(command.getToLoanOfficerId()).notNull().
integerGreaterThanZero().notSameAsParameter("fromLoanOfficerId", command.getFromLoanOfficerId());
baseDataValidator.reset().parameter("assignmentDate").value(command.getAssignmentDate()).notNull();
baseDataValidator.reset().parameter("loans").value(command.getLoans()).arrayNotEmpty();
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
}
}
}