MIFOSX-60 added loan charges api methods.

This commit is contained in:
Michal Dudzinski
2012-09-21 11:05:29 +02:00
parent 4f98144896
commit 3a89d10454
11 changed files with 243 additions and 10 deletions
@@ -24,6 +24,7 @@ import org.apache.commons.lang.StringUtils;
import org.mifosng.platform.api.commands.AdjustLoanTransactionCommand;
import org.mifosng.platform.api.commands.CalculateLoanScheduleCommand;
import org.mifosng.platform.api.commands.LoanApplicationCommand;
import org.mifosng.platform.api.commands.LoanChargeCommand;
import org.mifosng.platform.api.commands.LoanStateTransitionCommand;
import org.mifosng.platform.api.commands.LoanTransactionCommand;
import org.mifosng.platform.api.commands.UndoStateTransitionCommand;
@@ -481,4 +482,49 @@ public class LoansApiResource {
return Response.ok().entity(identifier).build();
}
@POST
@Path("{loanId}/charges")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response addLoanCharge(
@PathParam("loanId") final Long loanId,
final String jsonRequestBody){
LoanChargeCommand command = this.apiDataConversionService.convertJsonToLoanChargeCommand(null, loanId, jsonRequestBody);
EntityIdentifier identifier = this.loanWritePlatformService.addLoanCharge(command);
return Response.ok().entity(identifier).build();
}
@PUT
@Path("{loanId}/charges/{chargeId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response updateLoanCharge(
@PathParam("loanId") final Long loanId,
@PathParam("chargeId") final Long loanChargeId,
final String jsonRequestBody){
LoanChargeCommand command = this.apiDataConversionService.convertJsonToLoanChargeCommand(loanChargeId, loanId, jsonRequestBody);
EntityIdentifier identifier = this.loanWritePlatformService.updateLoanCharge(command);
return Response.ok().entity(identifier).build();
}
@DELETE
@Path("{loanId}/charges/{chargeId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response deleteLoanCharge(
@PathParam("loanId") final Long loanId,
@PathParam("chargeId") final Long loanChargeId){
EntityIdentifier identifier = this.loanWritePlatformService.deleteLoanCharge(loanId, loanChargeId);
return Response.ok().entity(identifier).build();
}
}
@@ -7,6 +7,7 @@ public class LoanChargeCommand {
private final Long id;
private final Long chargeId;
private final Long loanId;
private final BigDecimal amount;
private final Integer chargeTimeType;
@@ -14,11 +15,11 @@ public class LoanChargeCommand {
private final Set<String> modifiedParameters;
public LoanChargeCommand(final Set<String> modifiedParameters, final Long id, final Long chargeId,
final BigDecimal amount, final Integer chargeTimeType, final Integer chargeCalculationType) {
public LoanChargeCommand(Set<String> modifiedParameters, Long id, Long loanId, Long chargeId, BigDecimal amount, Integer chargeTimeType, Integer chargeCalculationType) {
this.modifiedParameters = modifiedParameters;
this.id = id;
this.chargeId = chargeId;
this.loanId = loanId;
this.amount = amount;
this.chargeTimeType = chargeTimeType;
this.chargeCalculationType = chargeCalculationType;
@@ -32,6 +33,10 @@ public class LoanChargeCommand {
return chargeId;
}
public Long getLoanId() {
return loanId;
}
public BigDecimal getAmount() {
return amount;
}
@@ -11,6 +11,7 @@ import org.mifosng.platform.api.commands.DepositStateTransitionApprovalCommand;
import org.mifosng.platform.api.commands.DepositStateTransitionCommand;
import org.mifosng.platform.api.commands.FundCommand;
import org.mifosng.platform.api.commands.GroupCommand;
import org.mifosng.platform.api.commands.LoanChargeCommand;
import org.mifosng.platform.api.commands.LoanProductCommand;
import org.mifosng.platform.api.commands.LoanStateTransitionCommand;
import org.mifosng.platform.api.commands.LoanTransactionCommand;
@@ -49,6 +50,8 @@ public interface ApiDataConversionService {
LoanApplicationCommand convertJsonToLoanApplicationCommand(Long resourceIdentifier, String jsonRequestBody);
LoanChargeCommand convertJsonToLoanChargeCommand(Long loanChargeId, Long loanId, String jsonRequestBody);
LoanStateTransitionCommand convertJsonToLoanStateTransitionCommand(Long resourceIdentifier, String jsonRequestBody);
LoanTransactionCommand convertJsonToLoanTransactionCommand(Long resourceIdentifier, String jsonRequestBody);
@@ -506,7 +506,7 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
Integer chargeTimeType = extractIntegerParameter("chargeTimeType", chargeRequestMap, chargeModifiedParameters);
Integer chargeCalculationType = extractIntegerParameter("chargeCalculationType", chargeRequestMap, chargeModifiedParameters);
charges[i] = new LoanChargeCommand(chargeModifiedParameters, null, chargeId, amount,
charges[i] = new LoanChargeCommand(chargeModifiedParameters, null, null,chargeId, amount,
chargeTimeType, chargeCalculationType);
}
}
@@ -521,8 +521,34 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
loanTermFrequency, loanTermFrequencyType,
inArrearsToleranceValue, charges,loanOfficerId);
}
@Override
@Override
public LoanChargeCommand convertJsonToLoanChargeCommand(Long loanChargeId, Long loanId, 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("chargeId", "amount", "chargeTimeType", "chargeCalculationType", "locale")
);
checkForUnsupportedParameters(requestMap, supportedParams);
Set<String> modifiedParameters = new HashSet<String>();
Long chargeId = extractLongParameter("chargeId", requestMap, modifiedParameters);
BigDecimal amount = extractBigDecimalParameter("amount", requestMap, modifiedParameters);
Integer chargeTimeType = extractIntegerParameter("chargeTimeType", requestMap, modifiedParameters);
Integer chargeCalculationType = extractIntegerParameter("chargeCalculationType", requestMap, modifiedParameters);
return new LoanChargeCommand(modifiedParameters, loanChargeId, loanId, chargeId, amount,
chargeTimeType, chargeCalculationType);
}
@Override
public LoanStateTransitionCommand convertJsonToLoanStateTransitionCommand(final Long resourceIdentifier, final String json) {
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
@@ -577,6 +577,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
doPostLoanTransactionChecks(loanTransaction, loanLifecycleStateMachine);
}
public void updateTotalChargesDueAtDisbursement(){
this.totalChargesDueAtDisbursement = deriveSumTotalOfChargesDueAtDisbursement();
}
public void makeRepayment(final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
handleRepaymentTransaction(loanTransaction, loanLifecycleStateMachine, false);
}
@@ -38,7 +38,11 @@ public class LoanCharge extends AbstractPersistable<Long> {
@Column(name = "charge_calculation_enum")
private Integer chargeCalculation;
public static LoanCharge createNew(final Loan loan, final Charge chargeDefinition, final LoanChargeCommand command) {
return new LoanCharge(loan, chargeDefinition, command);
}
public static LoanCharge createNew(final Charge chargeDefinition, final LoanChargeCommand command) {
return new LoanCharge(null, chargeDefinition, command);
}
@@ -90,6 +94,22 @@ public class LoanCharge extends AbstractPersistable<Long> {
this.loan = loan;
}
public void update(final LoanChargeCommand command){
if (command.isAmountChanged()) {
this.amount = command.getAmount();
}
if (command.isChargeTimeTypeChanged()){
this.chargeTime = ChargeTimeType.fromInt(command.getChargeTimeType()).getValue();
}
if (command.isChargeCalculationTypeChanged()){
this.chargeCalculation = ChargeCalculationType.fromInt(command.getChargeCalculationType()).getValue();
}
}
public boolean isDueAtDisbursement() {
return ChargeTimeType.fromInt(this.chargeTime).equals(ChargeTimeType.DISBURSEMENT);
}
@@ -122,6 +142,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
public LoanChargeCommand toData() {
Set<String> modifiedParameters = new HashSet<String>();
return new LoanChargeCommand(modifiedParameters, this.getId(), this.charge.getId(), this.amount, this.chargeTime, this.chargeCalculation);
return new LoanChargeCommand(modifiedParameters, this.getId(), this.loan.getId(), this.charge.getId(),
this.amount, this.chargeTime, this.chargeCalculation);
}
}
@@ -0,0 +1,8 @@
package org.mifosng.platform.loan.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface LoanChargeRepository extends JpaRepository<LoanCharge, Long>, JpaSpecificationExecutor<LoanCharge> {
// no added behaviour
}
@@ -58,7 +58,7 @@ public class LoanApplicationCommandValidator {
for (LoanChargeCommand loanChargeCommand : this.command.getCharges()){
try {
LoanChargeCommandValidator validator = new LoanChargeCommandValidator(loanChargeCommand);
validator.validate();
validator.validateForCreate();
} catch (PlatformApiDataValidationException e) {
dataValidationErrors.addAll(e.getErrors());
}
@@ -17,7 +17,7 @@ public class LoanChargeCommandValidator {
this.command = command;
}
public void validate(){
public void validateForCreate(){
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("charge");
@@ -31,4 +31,18 @@ public class LoanChargeCommandValidator {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
}
}
public void validateForUpdate(){
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("charge");
baseDataValidator.reset().parameter("amount").value(command.getAmount()).ignoreIfNull().positiveAmount();
baseDataValidator.reset().parameter("chargeTimeType").value(command.getChargeTimeType()).ignoreIfNull().inMinMaxRange(1, 1);
baseDataValidator.reset().parameter("chargeCalculationType").value(command.getChargeCalculationType()).ignoreIfNull().inMinMaxRange(1, 4);
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
}
}
}
@@ -1,6 +1,7 @@
package org.mifosng.platform.loan.service;
import org.mifosng.platform.api.commands.AdjustLoanTransactionCommand;
import org.mifosng.platform.api.commands.LoanChargeCommand;
import org.mifosng.platform.api.commands.LoanStateTransitionCommand;
import org.mifosng.platform.api.commands.LoanTransactionCommand;
import org.mifosng.platform.api.commands.LoanApplicationCommand;
@@ -45,4 +46,13 @@ public interface LoanWritePlatformService {
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')")
EntityIdentifier waiveLoanAmount(LoanTransactionCommand command);
@PreAuthorize(value = "hasRole('ORGANISATION_ADMINISTRATION_SUPER_USER_ROLE')")
EntityIdentifier addLoanCharge(LoanChargeCommand command);
@PreAuthorize(value = "hasRole('ORGANISATION_ADMINISTRATION_SUPER_USER_ROLE')")
EntityIdentifier updateLoanCharge(LoanChargeCommand command);
@PreAuthorize(value = "hasRole('ORGANISATION_ADMINISTRATION_SUPER_USER_ROLE')")
EntityIdentifier deleteLoanCharge(final Long loanId, final Long loanChargeId);
}
@@ -18,12 +18,17 @@ import org.mifosng.platform.api.commands.LoanTransactionCommand;
import org.mifosng.platform.api.commands.UndoStateTransitionCommand;
import org.mifosng.platform.api.data.EntityIdentifier;
import org.mifosng.platform.api.data.LoanSchedulePeriodData;
import org.mifosng.platform.charge.domain.Charge;
import org.mifosng.platform.charge.domain.ChargeRepository;
import org.mifosng.platform.client.domain.Client;
import org.mifosng.platform.client.domain.ClientRepository;
import org.mifosng.platform.client.domain.Note;
import org.mifosng.platform.client.domain.NoteRepository;
import org.mifosng.platform.currency.domain.Money;
import org.mifosng.platform.exceptions.ChargeIsNotActiveException;
import org.mifosng.platform.exceptions.ChargeNotFoundException;
import org.mifosng.platform.exceptions.ClientNotFoundException;
import org.mifosng.platform.exceptions.InvalidCurrencyException;
import org.mifosng.platform.exceptions.LoanNotFoundException;
import org.mifosng.platform.exceptions.LoanNotInSubmittedAndPendingApprovalStateCannotBeDeleted;
import org.mifosng.platform.exceptions.LoanProductNotFoundException;
@@ -33,6 +38,7 @@ import org.mifosng.platform.fund.domain.Fund;
import org.mifosng.platform.loan.domain.DefaultLoanLifecycleStateMachine;
import org.mifosng.platform.loan.domain.Loan;
import org.mifosng.platform.loan.domain.LoanCharge;
import org.mifosng.platform.loan.domain.LoanChargeRepository;
import org.mifosng.platform.loan.domain.LoanLifecycleStateMachine;
import org.mifosng.platform.loan.domain.LoanProduct;
import org.mifosng.platform.loan.domain.LoanProductRepository;
@@ -62,12 +68,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final LoanAssembler loanAssembler;
private final ClientRepository clientRepository;
private final LoanProductRepository loanProductRepository;
private final ChargeRepository chargeRepository;
private final LoanChargeRepository loanChargeRepository;
@Autowired
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final LoanAssembler loanAssembler,
final LoanRepository loanRepository, final LoanTransactionRepository loanTransactionRepository,
final NoteRepository noteRepository, final CalculationPlatformService calculationPlatformService,
final ClientRepository clientRepository, final LoanProductRepository loanProductRepository) {
final ClientRepository clientRepository, final LoanProductRepository loanProductRepository,
final ChargeRepository chargeRepository, final LoanChargeRepository loanChargeRepository) {
this.context = context;
this.loanAssembler = loanAssembler;
this.loanRepository = loanRepository;
@@ -76,6 +85,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.calculationPlatformService = calculationPlatformService;
this.clientRepository = clientRepository;
this.loanProductRepository = loanProductRepository;
this.chargeRepository = chargeRepository;
this.loanChargeRepository = loanChargeRepository;
}
private boolean isBeforeToday(final LocalDate date) {
@@ -533,4 +544,89 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
return new EntityIdentifier(loan.getId());
}
@Override
public EntityIdentifier addLoanCharge(LoanChargeCommand command) {
this.context.authenticatedUser();
LoanChargeCommandValidator validator = new LoanChargeCommandValidator(command);
validator.validateForCreate();
Loan loan = this.loanRepository.findOne(command.getLoanId());
if (loan == null) {
throw new LoanNotFoundException(command.getLoanId());
}
Charge chargeDefinition = this.chargeRepository.findOne(command.getChargeId());
if (chargeDefinition == null) {
throw new ChargeNotFoundException(command.getChargeId());
}
LoanCharge loanCharge = LoanCharge.createNew(loan, chargeDefinition, command);
if (!chargeDefinition.isActive()) {
throw new ChargeIsNotActiveException(chargeDefinition.getId());
}
if (!loan.getCurrency().getCode().equals(chargeDefinition.getCurrencyCode())){
String errorMessage = "Charge and Loan must have the same currency.";
throw new InvalidCurrencyException("charge", "attach.to.loan", errorMessage);
}
this.loanChargeRepository.saveAndFlush(loanCharge);
loan.getCharges().add(loanCharge);
loan.updateTotalChargesDueAtDisbursement();
this.loanRepository.saveAndFlush(loan);
return new EntityIdentifier(loanCharge.getId());
}
@Override
public EntityIdentifier updateLoanCharge(LoanChargeCommand command) {
this.context.authenticatedUser();
LoanChargeCommandValidator validator = new LoanChargeCommandValidator(command);
validator.validateForUpdate();
Loan loan = this.loanRepository.findOne(command.getLoanId());
if (loan == null) {
throw new LoanNotFoundException(command.getLoanId());
}
for (LoanCharge loanCharge : loan.getCharges()){
if (loanCharge.getId().equals(command.getId())){
loanCharge.update(command);
loan.updateTotalChargesDueAtDisbursement();
this.loanRepository.saveAndFlush(loan);
return new EntityIdentifier(loanCharge.getId());
}
}
throw new ChargeNotFoundException(command.getId());
}
@Override
public EntityIdentifier deleteLoanCharge(Long loanId, Long loanChargeId) {
this.context.authenticatedUser();
Loan loan = this.loanRepository.findOne(loanId);
if (loan == null) {
throw new LoanNotFoundException(loanId);
}
for (LoanCharge loanCharge : loan.getCharges()){
if (loanCharge.getId().equals(loanChargeId)){
loan.getCharges().remove(loanCharge);
loan.updateTotalChargesDueAtDisbursement();
this.loanRepository.saveAndFlush(loan);
return new EntityIdentifier(loanCharge.getId());
}
}
throw new ChargeNotFoundException(loanChargeId);
}
}