Adding unique constraint on Loan Product name
This commit is contained in:
@@ -0,0 +1 @@
|
||||
INSERT INTO `m_permission` (`id`, `grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES (358, 'transaction_loan', 'REMOVELOANOFFICER_LOAN', 'LOAN', 'REMOVELOANOFFICER', 1);
|
||||
@@ -297,6 +297,10 @@ public class CommandWrapper {
|
||||
return this.actionName.equalsIgnoreCase("UPDATELOANOFFICER") && this.entityName.equalsIgnoreCase("LOAN");
|
||||
}
|
||||
|
||||
public boolean isRemoveLoanOfficer() {
|
||||
return this.actionName.equalsIgnoreCase("REMOVELOANOFFICER") && this.entityName.equalsIgnoreCase("LOAN");
|
||||
}
|
||||
|
||||
public boolean isBulkUpdateLoanOfficer() {
|
||||
return this.actionName.equalsIgnoreCase("BULKREASSIGN") && this.entityName.equalsIgnoreCase("LOAN");
|
||||
}
|
||||
|
||||
+9
@@ -549,6 +549,15 @@ public class CommandWrapperBuilder {
|
||||
this.href = "/loans/" + loanId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder unassignLoanOfficer(final Long loanId) {
|
||||
this.actionName = "REMOVELOANOFFICER";
|
||||
this.entityName = "LOAN";
|
||||
this.entityId = null;
|
||||
this.loanId = loanId;
|
||||
this.href = "/loans/" + loanId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder assignLoanOfficersInBulk() {
|
||||
this.actionName = "BULKREASSIGN";
|
||||
|
||||
+2
@@ -281,6 +281,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
handler = applicationContext.getBean("closeLoanAsRescheduledCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isUpdateLoanOfficer()) {
|
||||
handler = applicationContext.getBean("updateLoanOfficerCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isRemoveLoanOfficer()) {
|
||||
handler = applicationContext.getBean("removeLoanOfficerCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isBulkUpdateLoanOfficer()) {
|
||||
handler = applicationContext.getBean("bulkUpdateLoanOfficerCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isCreate()) {
|
||||
|
||||
+14
@@ -457,4 +457,18 @@ public class LoansApiResource {
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("{loanId}/unassign")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String unassignLoanOfficer(@PathParam("loanId") final Long loanId, final String apiRequestBodyAsJson) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().unassignLoanOfficer(loanId).withJson(apiRequestBodyAsJson)
|
||||
.build();
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
|
||||
/**
|
||||
* Immutable command for loan transactions.
|
||||
*/
|
||||
public class LoanUpdateCommand {
|
||||
|
||||
private final LocalDate unassignedDate;
|
||||
|
||||
public LoanUpdateCommand(final LocalDate unassignDate) {
|
||||
this.unassignedDate = unassignDate;
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
|
||||
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
|
||||
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.transaction");
|
||||
|
||||
baseDataValidator.reset().parameter("unassignedDate").value(this.unassignedDate).notNull();
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||
"Validation errors exist.", dataValidationErrors); }
|
||||
}
|
||||
}
|
||||
+10
-8
@@ -9,7 +9,8 @@ import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
|
||||
/**
|
||||
* Immutable data object for updating relationship between loan officer and a loan.
|
||||
* Immutable data object for updating relationship between loan officer and a
|
||||
* loan.
|
||||
*/
|
||||
public class UpdateLoanOfficerCommand {
|
||||
|
||||
@@ -26,17 +27,18 @@ public class UpdateLoanOfficerCommand {
|
||||
this.loans = null;
|
||||
}
|
||||
|
||||
public UpdateLoanOfficerCommand(final Long fromLoanOfficerId, final Long toLoanOfficerId, final LocalDate assignmentDate, final String[] loans) {
|
||||
public UpdateLoanOfficerCommand(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 void validateForBulkLoanReassignment() {
|
||||
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
|
||||
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loans.reassignment");
|
||||
public void validateForBulkLoanReassignment() {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loans.reassignment");
|
||||
|
||||
baseDataValidator.reset().parameter("fromLoanOfficerId").value(this.fromLoanOfficerId).notNull().integerGreaterThanZero();
|
||||
baseDataValidator.reset().parameter("toLoanOfficerId").value(this.toLoanOfficerId).notNull().integerGreaterThanZero()
|
||||
@@ -51,9 +53,9 @@ public class UpdateLoanOfficerCommand {
|
||||
}
|
||||
|
||||
public void validateForLoanReassignment() {
|
||||
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
|
||||
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loans.reassignment");
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loans.reassignment");
|
||||
|
||||
baseDataValidator.reset().parameter("toLoanOfficerId").value(this.toLoanOfficerId).notNull().integerGreaterThanZero()
|
||||
.notSameAsParameter("fromLoanOfficerId", this.fromLoanOfficerId);
|
||||
|
||||
+17
@@ -1941,6 +1941,18 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void removeLoanOfficer(final LocalDate updatedDate) {
|
||||
|
||||
final LoanOfficerAssignmentHistory latestHistoryRecord = findLatestIncompleteHistoryRecord();
|
||||
|
||||
if (latestHistoryRecord != null) {
|
||||
latestHistoryRecord.updateEndDate(updatedDate);
|
||||
}
|
||||
|
||||
this.loanofficer = null;
|
||||
}
|
||||
|
||||
private LoanOfficerAssignmentHistory findLatestIncompleteHistoryRecord() {
|
||||
|
||||
LoanOfficerAssignmentHistory latestRecordWithNoEndDate = null;
|
||||
@@ -2006,4 +2018,9 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
public Long productId() {
|
||||
return this.loanProduct.getId();
|
||||
}
|
||||
|
||||
public Staff getLoanOfficer() {
|
||||
return this.loanofficer;
|
||||
}
|
||||
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class UnassignLoanOfficerException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public UnassignLoanOfficerException(final Long loanId) {
|
||||
super("error.msg.loan.not.assigned.to.loan.officer", "Loan with identifier " + loanId
|
||||
+ " is not assigned to any loan officer.", loanId);
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class RemoveLoanOfficerCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final LoanWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public RemoveLoanOfficerCommandHandler(final LoanWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.removeLoanOfficer(command.getLoanId(), command);
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.serialization;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.loanaccount.command.LoanStateTransitionCommand;
|
||||
import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* Implementation of {@link FromApiJsonDeserializer} for
|
||||
* {@link LoanStateTransitionCommand}'s.
|
||||
*/
|
||||
@Component
|
||||
public final class LoanUpdateCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer<LoanUpdateCommand> {
|
||||
|
||||
/**
|
||||
* The parameters supported for this command.
|
||||
*/
|
||||
final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("unassignedDate", "locale", "dateFormat"));
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public LoanUpdateCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanUpdateCommand commandFromApiJson(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters);
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
final LocalDate unassignedDate = this.fromApiJsonHelper.extractLocalDateNamed("unassignedDate", element);
|
||||
|
||||
return new LoanUpdateCommand(unassignedDate);
|
||||
}
|
||||
}
|
||||
+2
@@ -32,4 +32,6 @@ public interface LoanWritePlatformService {
|
||||
CommandProcessingResult loanReassignment(Long loanId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult bulkLoanReassignment(JsonCommand command);
|
||||
|
||||
CommandProcessingResult removeLoanOfficer(Long loanId, JsonCommand command);
|
||||
}
|
||||
+41
-2
@@ -32,6 +32,7 @@ import org.mifosplatform.portfolio.client.domain.NoteRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
|
||||
import org.mifosplatform.portfolio.loanaccount.command.LoanStateTransitionCommand;
|
||||
import org.mifosplatform.portfolio.loanaccount.command.LoanTransactionCommand;
|
||||
import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||
@@ -44,9 +45,11 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionNotFoundException;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.UnassignLoanOfficerException;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanChargeCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanStateTransitionCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanTransactionCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanUpdateCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -60,6 +63,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
private final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer;
|
||||
private final LoanTransactionCommandFromApiJsonDeserializer loanTransactionCommandFromApiJsonDeserializer;
|
||||
private final LoanChargeCommandFromApiJsonDeserializer loanChargeCommandFromApiJsonDeserializer;
|
||||
private final LoanUpdateCommandFromApiJsonDeserializer loanUpdateCommandFromApiJsonDeserializer;
|
||||
private final LoanRepository loanRepository;
|
||||
private final NoteRepository noteRepository;
|
||||
private final LoanTransactionRepository loanTransactionRepository;
|
||||
@@ -73,7 +77,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer,
|
||||
final LoanTransactionCommandFromApiJsonDeserializer loanTransactionCommandFromApiJsonDeserializer,
|
||||
final LoanChargeCommandFromApiJsonDeserializer loanChargeCommandFromApiJsonDeserializer, final LoanAssembler loanAssembler,
|
||||
final LoanChargeCommandFromApiJsonDeserializer loanChargeCommandFromApiJsonDeserializer,
|
||||
final LoanUpdateCommandFromApiJsonDeserializer loanUpdateCommandFromApiJsonDeserializer,
|
||||
final LoanAssembler loanAssembler,
|
||||
final LoanRepository loanRepository, final LoanTransactionRepository loanTransactionRepository,
|
||||
final NoteRepository noteRepository, final ChargeRepository chargeRepository, final LoanChargeRepository loanChargeRepository,
|
||||
final ApplicationCurrencyRepository applicationCurrencyRepository,
|
||||
@@ -90,6 +96,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
this.loanChargeRepository = loanChargeRepository;
|
||||
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||
this.loanUpdateCommandFromApiJsonDeserializer = loanUpdateCommandFromApiJsonDeserializer;
|
||||
}
|
||||
|
||||
private boolean isBeforeToday(final LocalDate date) {
|
||||
@@ -695,7 +702,39 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
.withCommandId(command.commandId()) //
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult removeLoanOfficer(final Long loanId, final JsonCommand command) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final LoanUpdateCommand loanUpdateCommand = this.loanUpdateCommandFromApiJsonDeserializer.commandFromApiJson(command
|
||||
.json());
|
||||
|
||||
loanUpdateCommand.validate();
|
||||
|
||||
|
||||
final LocalDate dateOfLoanOfficerunAssigned = command.localDateValueOfParameterNamed("unassignedDate");
|
||||
|
||||
final Loan loan = retrieveLoanBy(loanId);
|
||||
|
||||
if (loan.getLoanOfficer() == null) { throw new UnassignLoanOfficerException(loanId); }
|
||||
|
||||
loan.removeLoanOfficer(dateOfLoanOfficerunAssigned);
|
||||
|
||||
this.loanRepository.saveAndFlush(loan);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(loanId) //
|
||||
.withOfficeId(loan.getOfficeId()) //
|
||||
.withClientId(loan.getClientId()) //
|
||||
.withGroupId(loan.getGroupId()) //
|
||||
.withLoanId(loanId) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private LoanDTO populateLoanDTO(Loan loan, List<LoanTransaction> loanTransactions) {
|
||||
List<LoanTransactionDTO> loanTransactionDTOs = new ArrayList<LoanTransactionDTO>();
|
||||
for (LoanTransaction loanTransaction : loanTransactions) {
|
||||
|
||||
Reference in New Issue
Block a user