Adding unique constraint on Loan Product name

This commit is contained in:
Nayan Ambali
2013-02-07 15:28:21 +05:30
parent 22698f09df
commit b7fef480d5
13 changed files with 226 additions and 10 deletions
@@ -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");
}
@@ -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";
@@ -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()) {
@@ -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);
}
}
@@ -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); }
}
}
@@ -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);
@@ -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;
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -32,4 +32,6 @@ public interface LoanWritePlatformService {
CommandProcessingResult loanReassignment(Long loanId, JsonCommand command);
CommandProcessingResult bulkLoanReassignment(JsonCommand command);
CommandProcessingResult removeLoanOfficer(Long loanId, JsonCommand command);
}
@@ -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) {