From 2132a5dccb3d17aff1279f452b8780972d31262c Mon Sep 17 00:00:00 2001 From: Madhukar Date: Mon, 27 Aug 2012 13:08:43 +0530 Subject: [PATCH] Mifosx-43 fixed bugs from pull #21 --- .../api/DepositAccountsApiResource.java | 12 ++-- ...DepositStateTransitionApprovalCommand.java | 57 +++++++++++++++++++ .../platform/api/data/DepositAccountData.java | 37 +++++++++++- .../ApiDataConversionService.java | 3 + .../ApiDataConversionServiceImpl.java | 28 +++++++++ .../GoogleGsonApiJsonSerializerService.java | 3 +- .../saving/domain/DepositAccount.java | 37 +++++++----- .../saving/domain/DepositApprovalData.java | 47 +++++++++++++++ .../DepositLifecycleStateMachineImpl.java | 24 +++++++- .../service/DepositAccountAssembler.java | 26 +++++++++ ...DepositAccountReadPlatformServiceImpl.java | 10 +++- .../DepositAccountWritePlatformService.java | 3 +- ...WritePlatformServiceJpaRepositoryImpl.java | 17 ++++-- ...ateTransitionApprovalCommandValidator.java | 39 +++++++++++++ 14 files changed, 311 insertions(+), 32 deletions(-) create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/api/commands/DepositStateTransitionApprovalCommand.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositApprovalData.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositStateTransitionApprovalCommandValidator.java diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/DepositAccountsApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/DepositAccountsApiResource.java index dc7b26e53..4e9616076 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/DepositAccountsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/DepositAccountsApiResource.java @@ -22,6 +22,7 @@ import javax.ws.rs.core.UriInfo; import org.apache.commons.lang.StringUtils; import org.mifosng.platform.api.commands.DepositAccountCommand; +import org.mifosng.platform.api.commands.DepositStateTransitionApprovalCommand; import org.mifosng.platform.api.commands.DepositStateTransitionCommand; import org.mifosng.platform.api.commands.UndoStateTransitionCommand; import org.mifosng.platform.api.data.DepositAccountData; @@ -67,7 +68,7 @@ public class DepositAccountsApiResource { "deposit", "maturityInterestRate", "tenureInMonths", "interestCompoundedEvery", "interestCompoundedEveryPeriodType", "renewalAllowed", - "preClosureAllowed", "preClosureInterestRate")); + "preClosureAllowed", "preClosureInterestRate", "statusEnum","withdrawnonDate","rejectedonDate","closedonDate")); @POST @@ -187,23 +188,26 @@ public class DepositAccountsApiResource { public Response SubmitDepositApplication(@PathParam("accountId") final Long accountId, @QueryParam("command") final String commandParam, final String jsonRequestBody) { - DepositStateTransitionCommand command=apiDataConversionService.convertJsonToDepositStateTransitionCommand(accountId, jsonRequestBody); + Response response=null; if (is(commandParam, "approve")) { - + + DepositStateTransitionApprovalCommand command=apiDataConversionService.convertJsonToDepositStateTransitionApprovalCommand(accountId, jsonRequestBody); EntityIdentifier identifier = this.depositAccountWritePlatformService.approveDepositApplication(command); response = Response.ok().entity(identifier).build(); } else if (is(commandParam, "reject")) { + DepositStateTransitionCommand command=apiDataConversionService.convertJsonToDepositStateTransitionCommand(accountId, jsonRequestBody); EntityIdentifier identifier = this.depositAccountWritePlatformService.rejectDepositApplication(command); response = Response.ok().entity(identifier).build(); } else if (is(commandParam, "withdrewbyclient")) { - + + DepositStateTransitionCommand command=apiDataConversionService.convertJsonToDepositStateTransitionCommand(accountId, jsonRequestBody); EntityIdentifier identifier = this.depositAccountWritePlatformService.withdrawDepositApplication(command); response = Response.ok().entity(identifier).build(); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/DepositStateTransitionApprovalCommand.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/DepositStateTransitionApprovalCommand.java new file mode 100644 index 000000000..b7654ee4c --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/DepositStateTransitionApprovalCommand.java @@ -0,0 +1,57 @@ +package org.mifosng.platform.api.commands; + +import java.math.BigDecimal; + +import org.joda.time.LocalDate; + +public class DepositStateTransitionApprovalCommand { + + private final Long accountId; + private final Long productId; + private final LocalDate eventDate; + private final BigDecimal depositAmount; + private final Integer tenureInMonths; + private final Integer interestCompoundedEveryPeriodType; + private final Integer interestCompoundedEvery; + + public DepositStateTransitionApprovalCommand(Long resourceIdentifier, Long productId, LocalDate eventDate, Integer tenureInMonths, BigDecimal depositAmount, Integer interestCompoundedEveryPeriodType, Integer interestCompoundedEvery) { + + this.accountId=resourceIdentifier; + this.eventDate=eventDate; + this.depositAmount=depositAmount; + this.tenureInMonths=tenureInMonths; + this.interestCompoundedEveryPeriodType=interestCompoundedEveryPeriodType; + this.productId=productId; + this.interestCompoundedEvery=interestCompoundedEvery; + + } + + public Long getAccountId() { + return accountId; + } + + public LocalDate getEventDate() { + return eventDate; + } + + public BigDecimal getDepositAmount() { + return depositAmount; + } + + public Integer getTenureInMonths() { + return tenureInMonths; + } + + public Integer getInterestCompoundedEveryPeriodType() { + return interestCompoundedEveryPeriodType; + } + + public Long getProductId() { + return productId; + } + + public Integer getInterestCompoundedEvery() { + return interestCompoundedEvery; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/DepositAccountData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/DepositAccountData.java index 8d946f1c8..a858d7aea 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/DepositAccountData.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/DepositAccountData.java @@ -29,6 +29,9 @@ public class DepositAccountData { private final LocalDate actualCommencementDate; private final LocalDate projectedMaturityDate; private final LocalDate actualMaturityDate; + private final LocalDate withdrawnonDate; + private final LocalDate rejectedonDate; + private final LocalDate closedonDate; private final BigDecimal projectedInterestAccrued; private final BigDecimal actualInterestAccrued; private final BigDecimal projectedMaturityAmount; @@ -41,7 +44,6 @@ public class DepositAccountData { private final BigDecimal preClosureInterestRate; private final List interestCompoundedEveryPeriodTypeOptions; - private final List productOptions; /* @@ -81,6 +83,10 @@ public class DepositAccountData { this.interestCompoundedEveryPeriodTypeOptions = new ArrayList(); this.productOptions = new ArrayList(); + + this.withdrawnonDate=null; + this.closedonDate=null; + this.rejectedonDate=null; } public DepositAccountData( @@ -114,6 +120,10 @@ public class DepositAccountData { this.interestCompoundedEveryPeriodTypeOptions = interestCompoundedEveryPeriodTypeOptions; this.productOptions = new ArrayList(productOptions); + + this.withdrawnonDate=account.getWithdrawnonDate(); + this.rejectedonDate=account.getRejectedonDate(); + this.closedonDate=account.getClosedonDate(); } public DepositAccountData( @@ -139,7 +149,10 @@ public class DepositAccountData { final EnumOptionData interestCompoundedEveryPeriodType, final boolean renewalAllowed, final boolean preClosureAllowed, - final BigDecimal preClosureInterestRate) { + final BigDecimal preClosureInterestRate, + final LocalDate withdrawnonDate, + final LocalDate rejectedonDate, + final LocalDate closedonDate) { this.id=id; this.externalId = externalId; this.status = status; @@ -167,6 +180,10 @@ public class DepositAccountData { this.interestCompoundedEveryPeriodTypeOptions = new ArrayList(); this.productOptions = new ArrayList(); + + this.withdrawnonDate = withdrawnonDate; + this.rejectedonDate = rejectedonDate; + this.closedonDate = closedonDate; } public DepositAccountData( @@ -209,6 +226,10 @@ public class DepositAccountData { this.interestCompoundedEveryPeriodTypeOptions = new ArrayList(); this.productOptions = new ArrayList(); + + this.withdrawnonDate=null; + this.closedonDate=null; + this.rejectedonDate=null; } public Long getId() { @@ -314,4 +335,16 @@ public class DepositAccountData { public List getProductOptions() { return productOptions; } + + public LocalDate getWithdrawnonDate() { + return withdrawnonDate; + } + + public LocalDate getRejectedonDate() { + return rejectedonDate; + } + + public LocalDate getClosedonDate() { + return closedonDate; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionService.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionService.java index 9fe66c670..5edb0d5de 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionService.java @@ -6,6 +6,7 @@ import org.mifosng.platform.api.commands.ChargeCommand; import org.mifosng.platform.api.commands.ClientCommand; import org.mifosng.platform.api.commands.DepositAccountCommand; import org.mifosng.platform.api.commands.DepositProductCommand; +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; @@ -60,4 +61,6 @@ public interface ApiDataConversionService { DepositAccountCommand convertJsonToDepositAccountCommand(Long resourceIdentifier, String jsonRequestBody); DepositStateTransitionCommand convertJsonToDepositStateTransitionCommand(Long resourceIdentifier, String jsonRequestBody); + + DepositStateTransitionApprovalCommand convertJsonToDepositStateTransitionApprovalCommand(Long resourceIdentifier, String jsonRequestBody); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java index 01eefcc46..73ac3590e 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java @@ -23,6 +23,7 @@ import org.mifosng.platform.api.commands.ChargeCommand; import org.mifosng.platform.api.commands.ClientCommand; import org.mifosng.platform.api.commands.DepositAccountCommand; import org.mifosng.platform.api.commands.DepositProductCommand; +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; @@ -1027,4 +1028,31 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService { return new DepositStateTransitionCommand(resourceIdentifier, eventDate); } + + @Override + public DepositStateTransitionApprovalCommand convertJsonToDepositStateTransitionApprovalCommand( + Long resourceIdentifier, String json) { + + if (StringUtils.isBlank(json)) { + throw new InvalidJsonException(); + } + + Type typeOfMap = new TypeToken>(){}.getType(); + Map requestMap = gsonConverter.fromJson(json, typeOfMap); + + Set supportedParams = new HashSet( Arrays.asList("locale","eventDate", "dateFormat", "tenureInMonths", "depositAmount", "interestCompoundedEveryPeriodType", "productId","interestCompoundedEvery")); + + checkForUnsupportedParameters(requestMap, supportedParams); + + Set modifiedParameters = new HashSet(); + + LocalDate eventDate = extractLocalDateParameter("eventDate", requestMap, modifiedParameters); + BigDecimal depositAmount=extractBigDecimalParameter("depositAmount", requestMap, modifiedParameters); + Integer tenureInMonths = extractIntegerParameter("tenureInMonths", requestMap, modifiedParameters); + Integer interestCompoundedEveryPeriodType = extractIntegerParameter("interestCompoundedEveryPeriodType", requestMap, modifiedParameters); + Integer interestCompoundedEvery = extractIntegerParameter("interestCompoundedEvery", requestMap, modifiedParameters); + Long productId = extractLongParameter("productId", requestMap, modifiedParameters); + + return new DepositStateTransitionApprovalCommand(resourceIdentifier, productId, eventDate, tenureInMonths, depositAmount, interestCompoundedEveryPeriodType,interestCompoundedEvery); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/GoogleGsonApiJsonSerializerService.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/GoogleGsonApiJsonSerializerService.java index 3dd4019ff..e04f63404 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/GoogleGsonApiJsonSerializerService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/GoogleGsonApiJsonSerializerService.java @@ -101,7 +101,8 @@ public class GoogleGsonApiJsonSerializerService implements "id", "externalId", "clientId", "clientName", "productId", "productName", "status", "currency", "deposit", "maturityInterestRate", "tenureInMonths", "interestCompoundedEvery", "interestCompoundedEveryPeriodType", - "renewalAllowed","preClosureAllowed","preClosureInterestRate" + "renewalAllowed","preClosureAllowed","preClosureInterestRate", + "withdrawnonDate","rejectedonDate","closedonDate" ) ); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccount.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccount.java index dc3c9f8b2..71641579d 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccount.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccount.java @@ -103,17 +103,17 @@ public class DepositAccount extends AbstractAuditableCustom { @Column(name = "status_enum", nullable = false) private Integer depositStatus; - @Temporal(TemporalType.TIMESTAMP) + @Temporal(TemporalType.DATE) @Column(name = "closedon_date") private Date closedOnDate; - @Temporal(TemporalType.TIMESTAMP) + @Temporal(TemporalType.DATE) @Column(name = "rejectedon_date") private Date rejectedOnDate; - @Temporal(TemporalType.TIMESTAMP) + @Temporal(TemporalType.DATE) @Column(name = "withdrawnon_date") - private Date withdrawnOnDate; + private Date withdrawnOnDate; public DepositAccount openNew( final Client client, final DepositProduct product, @@ -202,30 +202,37 @@ public class DepositAccount extends AbstractAuditableCustom { } - public void approve(final LocalDate actualCommencementDate, DepositLifecycleStateMachine depositLifecycleStateMachine) { + public void approve(final LocalDate actualCommencementDate, DepositLifecycleStateMachine depositLifecycleStateMachine, DepositApprovalData depositApprovalData, BigDecimal depositAmount) { DepositStatus statusEnum = depositLifecycleStateMachine.transition(DepositEvent.DEPOSIT_APPROVED, DepositStatus.fromInt(this.depositStatus)); this.depositStatus = statusEnum.getValue(); + + this.tenureInMonths = depositApprovalData.getTenureInMonths(); + this.depositAmount = depositAmount; + this.interestCompoundedFrequencyType = depositApprovalData.getInterestCompoundedEveryPeriodType(); - this.actualCommencementDate = actualCommencementDate - .toDateTimeAtCurrentTime().toDate(); + this.actualCommencementDate = actualCommencementDate.toDateTimeAtCurrentTime().toDate(); if(this.actualCommencementDate != null) this.actualMaturityDate = new LocalDate(this.actualCommencementDate).plusMonths(this.tenureInMonths).toDate(); + + FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator = depositApprovalData.getFixedTermDepositInterestCalculator(); + + Money futureValueOnMaturity = fixedTermDepositInterestCalculator.calculateInterestOnMaturityFor(depositApprovalData.getDeposit(), depositApprovalData.getTenureInMonths(), + depositApprovalData.getMaturityInterestRate(), depositApprovalData.getInterestCompoundedEvery(), depositApprovalData.getInterestCompoundedEveryPeriodType()); + + this.projectedInterestAccruedOnMaturity = futureValueOnMaturity.minus(depositApprovalData.getDeposit()).getAmount(); + this.projectedTotalOnMaturity = futureValueOnMaturity.getAmount(); + LocalDate submittalDate = new LocalDate(this.projectedCommencementDate); if (actualCommencementDate.isBefore(submittalDate)) { - final String errorMessage = "The date on which a deposit is approved cannot be before its submittal date: " - + submittalDate.toString(); - throw new InvalidDepositStateTransitionException("approval", - "cannot.be.before.submittal.date", errorMessage, - getActualCommencementDate(), submittalDate); + final String errorMessage = "The date on which a deposit is approved cannot be before its submittal date: " + submittalDate.toString(); + throw new InvalidDepositStateTransitionException("approval", "cannot.be.before.submittal.date", errorMessage, getActualCommencementDate(), submittalDate); } if (actualCommencementDate.isAfter(new LocalDate())) { final String errorMessage = "The date on which a deposit is approved cannot be in the future."; - throw new InvalidDepositStateTransitionException("approval", - "cannot.be.a.future.date", errorMessage, - getActualCommencementDate()); + throw new InvalidDepositStateTransitionException("approval", "cannot.be.a.future.date", errorMessage, getActualCommencementDate()); } } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositApprovalData.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositApprovalData.java new file mode 100644 index 000000000..ba54f74fb --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositApprovalData.java @@ -0,0 +1,47 @@ +package org.mifosng.platform.saving.domain; + +import java.math.BigDecimal; + +import org.mifosng.platform.currency.domain.Money; +import org.mifosng.platform.loan.domain.PeriodFrequencyType; + +public class DepositApprovalData { + + private final Integer tenureInMonths; + private final Money deposit; + private final BigDecimal maturityInterestRate; + private final Integer interestCompoundedEvery; + private final PeriodFrequencyType interestCompoundedEveryPeriodType; + private final FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator; + + + public DepositApprovalData(final Integer tenureInMonths,final Money deposit,final BigDecimal maturityInterestRate,final Integer interestCompoundedEvery,final PeriodFrequencyType interestCompoundedEveryPeriodType,final FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator) { + this.tenureInMonths=tenureInMonths; + this.deposit=deposit; + this.maturityInterestRate=maturityInterestRate; + this.interestCompoundedEvery=interestCompoundedEvery; + this.interestCompoundedEveryPeriodType=interestCompoundedEveryPeriodType; + this.fixedTermDepositInterestCalculator=fixedTermDepositInterestCalculator; + } + + + public Integer getTenureInMonths() { + return tenureInMonths; + } + public Money getDeposit() { + return deposit; + } + public BigDecimal getMaturityInterestRate() { + return maturityInterestRate; + } + public Integer getInterestCompoundedEvery() { + return interestCompoundedEvery; + } + public PeriodFrequencyType getInterestCompoundedEveryPeriodType() { + return interestCompoundedEveryPeriodType; + } + public FixedTermDepositInterestCalculator getFixedTermDepositInterestCalculator() { + return fixedTermDepositInterestCalculator; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositLifecycleStateMachineImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositLifecycleStateMachineImpl.java index 5b57fb6eb..2662b34c1 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositLifecycleStateMachineImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositLifecycleStateMachineImpl.java @@ -2,6 +2,8 @@ package org.mifosng.platform.saving.domain; import java.util.List; +import org.mifosng.platform.exceptions.InvalidDepositStateTransitionException; + public class DepositLifecycleStateMachineImpl implements DepositLifecycleStateMachine { @@ -26,28 +28,46 @@ public class DepositLifecycleStateMachineImpl implements if (from.hasStateOf(DepositStatus.SUBMITED_AND_PENDING_APPROVAL)) { newState = stateOf(DepositStatus.REJECTED, allowedDepositStatuses); } + else{ + final String errorMessage = "The DepositApplication can not be rejected from "+from.getCode() ; + throw new InvalidDepositStateTransitionException("rejection", "failed", errorMessage,from); + } break; case DEPOSIT_APPROVED: if (from.hasStateOf(DepositStatus.SUBMITED_AND_PENDING_APPROVAL)) { newState = stateOf(DepositStatus.APPROVED, allowedDepositStatuses); } + else{ + final String errorMessage = "The DepositApplication can not be approved from "+from.getCode() ; + throw new InvalidDepositStateTransitionException("approve", "failed", errorMessage,from); + } break; case DEPOSIT_WITHDRAWN: if (this.anyOfAllowedWhenComingFrom(from, DepositStatus.SUBMITED_AND_PENDING_APPROVAL, DepositStatus.APPROVED)) { newState = stateOf(DepositStatus.WITHDRAWN_BY_CLIENT, allowedDepositStatuses); } + else{ + final String errorMessage = "The DepositApplication can not be withdrawn from "+from.getCode() ; + throw new InvalidDepositStateTransitionException("withdrawbyclient", "failed", errorMessage,from); + } break; case DEPOSIT_APPROVAL_UNDO: if (from.hasStateOf(DepositStatus.APPROVED)) { newState = stateOf(DepositStatus.SUBMITED_AND_PENDING_APPROVAL, allowedDepositStatuses); } + else{ + final String errorMessage = "The DepositApplication can not be unapproved from "+from.getCode() ; + throw new InvalidDepositStateTransitionException("unapprove", "failed", errorMessage,from); + } break; case DEPOSIT_MATURED: if (from.hasStateOf(DepositStatus.APPROVED) ){ newState = stateOf(DepositStatus.MATURED, allowedDepositStatuses); } - break; - default: + else{ + final String errorMessage = "The DepositApplication can not be matured from "+from.getCode() ; + throw new InvalidDepositStateTransitionException("mature", "failed", errorMessage,from); + } break; } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountAssembler.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountAssembler.java index 0e29b830a..19abfddd4 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountAssembler.java @@ -4,14 +4,18 @@ import java.math.BigDecimal; import java.util.Arrays; import java.util.List; +import org.joda.time.LocalDate; import org.mifosng.platform.api.commands.DepositAccountCommand; +import org.mifosng.platform.api.commands.DepositStateTransitionApprovalCommand; import org.mifosng.platform.client.domain.Client; import org.mifosng.platform.client.domain.ClientRepository; import org.mifosng.platform.currency.domain.Money; import org.mifosng.platform.exceptions.ClientNotFoundException; import org.mifosng.platform.exceptions.DepositProductNotFoundException; +import org.mifosng.platform.exceptions.NoAuthorizationException; import org.mifosng.platform.loan.domain.PeriodFrequencyType; import org.mifosng.platform.saving.domain.DepositAccount; +import org.mifosng.platform.saving.domain.DepositApprovalData; import org.mifosng.platform.saving.domain.DepositLifecycleStateMachine; import org.mifosng.platform.saving.domain.DepositLifecycleStateMachineImpl; import org.mifosng.platform.saving.domain.DepositStatus; @@ -95,6 +99,28 @@ public class DepositAccountAssembler { return account; } + public DepositApprovalData assembleFrom(DepositStateTransitionApprovalCommand command){ + + DepositProduct product = this.depositProductRepository.findOne(command.getProductId()); + if (product == null || product.isDeleted()) { + throw new DepositProductNotFoundException(command.getProductId()); + } + + PeriodFrequencyType interestCompoundedEveryPeriodType= product.getInterestCompoundedEveryPeriodType(); + if (command.getInterestCompoundedEveryPeriodType() != null) { + interestCompoundedEveryPeriodType = PeriodFrequencyType.fromInt(command.getInterestCompoundedEveryPeriodType()); + } + + Integer tenureInMonths = command.getTenureInMonths(); + Money deposit = Money.of(product.getCurrency(), command.getDepositAmount()); + BigDecimal maturityInterestRate = product.getMaturityDefaultInterestRate(); + Integer interestCompoundedEvery = product.getInterestCompoundedEvery(); + + return new DepositApprovalData(tenureInMonths, deposit, maturityInterestRate, interestCompoundedEvery, interestCompoundedEveryPeriodType, this.fixedTermDepositInterestCalculator); + + } + + private DepositLifecycleStateMachine defaultDepositLifecycleStateMachine() { List allowedDepositStatuses = Arrays.asList(DepositStatus.values()); return new DepositLifecycleStateMachineImpl(allowedDepositStatuses); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountReadPlatformServiceImpl.java index abff6abde..5781b6073 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountReadPlatformServiceImpl.java @@ -115,7 +115,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead private static final class DepositAccountMapper implements RowMapper { public String schema() { - return "da.id as id, da.external_id as externalId, da.client_id as clientId, da.product_id as productId," + return "da.id as id, da.external_id as externalId, da.client_id as clientId, da.product_id as productId, " + " da.currency_code as currencyCode, da.currency_digits as currencyDigits, " + " da.deposit_amount as depositAmount, da.status_enum as statusId, " + " da.maturity_nominal_interest_rate as interestRate, da.tenure_months as termInMonths, da.projected_commencement_date as projectedCommencementDate," @@ -124,6 +124,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead + " da.projected_total_maturity_amount as projectedMaturityAmount, da.actual_total_amount as actualMaturityAmount, " + " da.interest_compounded_every as interestCompoundedEvery, da.interest_compounded_every_period_enum as interestCompoundedEveryPeriodType, " + " da.is_renewal_allowed as renewalAllowed, da.is_preclosure_allowed as preClosureAllowed, da.pre_closure_interest_rate as preClosureInterestRate, " + + " da.withdrawnon_date as withdrawnonDate, da.rejectedon_date as rejectedonDate, da.closedon_date as closedonDate, " + " c.firstname as firstname, c.lastname as lastname, pd.name as productName," + " curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol" + " from m_deposit_account da " @@ -177,11 +178,16 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead BigDecimal preClosureInterestRate = rs.getBigDecimal("preClosureInterestRate"); + LocalDate withdrawnonDate = JdbcSupport.getLocalDate(rs, "withdrawnonDate"); + LocalDate rejectedonDate = JdbcSupport.getLocalDate(rs, "rejectedonDate"); + LocalDate closedonDate = JdbcSupport.getLocalDate(rs, "closedonDate"); + return new DepositAccountData(id, externalId, status, clientId, clientName, productId, productName, currencyData, depositAmount, interestRate, termInMonths, projectedCommencementDate, actualCommencementDate, projectedMaturityDate, actualMaturityDate, projectedInterestAccrued, actualInterestAccrued, projectedMaturityAmount, actualMaturityAmount, interestCompoundedEvery, interestCompoundedEveryPeriodType, - renewalAllowed, preClosureAllowed, preClosureInterestRate); + renewalAllowed, preClosureAllowed, preClosureInterestRate, + withdrawnonDate,rejectedonDate,closedonDate); } } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountWritePlatformService.java index 878d4ba13..e99a1673b 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountWritePlatformService.java @@ -1,6 +1,7 @@ package org.mifosng.platform.saving.service; import org.mifosng.platform.api.commands.DepositAccountCommand; +import org.mifosng.platform.api.commands.DepositStateTransitionApprovalCommand; import org.mifosng.platform.api.commands.DepositStateTransitionCommand; import org.mifosng.platform.api.commands.UndoStateTransitionCommand; import org.mifosng.platform.api.data.EntityIdentifier; @@ -18,7 +19,7 @@ public interface DepositAccountWritePlatformService { EntityIdentifier deleteDepositAccount(Long productId); @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_APPROVE_DEPOSIT_ROLE', 'CAN_APPROVE_DEPOSIT_IN_THE_PAST_ROLE')") - EntityIdentifier approveDepositApplication(DepositStateTransitionCommand command); + EntityIdentifier approveDepositApplication(DepositStateTransitionApprovalCommand command); @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_APPROVE_DEPOSIT_ROLE', 'CAN_APPROVE_DEPOSIT_IN_THE_PAST_ROLE')") EntityIdentifier rejectDepositApplication(DepositStateTransitionCommand command); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java index 1f18582fb..ca56e78f3 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java @@ -1,10 +1,12 @@ package org.mifosng.platform.saving.service; +import java.math.BigDecimal; import java.util.Arrays; import java.util.List; import org.joda.time.LocalDate; import org.mifosng.platform.api.commands.DepositAccountCommand; +import org.mifosng.platform.api.commands.DepositStateTransitionApprovalCommand; import org.mifosng.platform.api.commands.DepositStateTransitionCommand; import org.mifosng.platform.api.commands.UndoStateTransitionCommand; import org.mifosng.platform.api.data.EntityIdentifier; @@ -14,6 +16,7 @@ import org.mifosng.platform.exceptions.PlatformDataIntegrityException; import org.mifosng.platform.exceptions.ProductNotFoundException; import org.mifosng.platform.saving.domain.DepositAccount; import org.mifosng.platform.saving.domain.DepositAccountRepository; +import org.mifosng.platform.saving.domain.DepositApprovalData; import org.mifosng.platform.saving.domain.DepositLifecycleStateMachine; import org.mifosng.platform.saving.domain.DepositLifecycleStateMachineImpl; import org.mifosng.platform.saving.domain.DepositStatus; @@ -126,11 +129,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo @Transactional @Override - public EntityIdentifier approveDepositApplication(DepositStateTransitionCommand command) { + public EntityIdentifier approveDepositApplication(DepositStateTransitionApprovalCommand command) { AppUser currentUser = context.authenticatedUser(); - DepositStateTransitionCommandValidator validator = new DepositStateTransitionCommandValidator(command); + DepositStateTransitionApprovalCommandValidator validator = new DepositStateTransitionApprovalCommandValidator(command); validator.validate(); @@ -139,12 +142,16 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo throw new DepositAccountNotFoundException(command.getAccountId()); } + DepositApprovalData depositApprovalData=this.depositAccountAssembler.assembleFrom(command); + LocalDate eventDate = command.getEventDate(); if (this.isBeforeToday(eventDate) && currentUser.canNotApproveLoanInPast()) { throw new NoAuthorizationException("User has no authority to approve deposit with a date in the past."); } - account.approve(eventDate, defaultDepositLifecycleStateMachine()); + BigDecimal depositAmount = command.getDepositAmount(); + + account.approve(eventDate, defaultDepositLifecycleStateMachine(), depositApprovalData,depositAmount); this.depositAccountRepository.save(account); return new EntityIdentifier(account.getId()); @@ -204,7 +211,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo } account.withdraw(eventDate, defaultDepositLifecycleStateMachine()); - return null; + return new EntityIdentifier(account.getId()); } @Transactional @@ -221,6 +228,6 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo account.undoDepositApproval(defaultDepositLifecycleStateMachine()); this.depositAccountRepository.save(account); - return null; + return new EntityIdentifier(account.getId()); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositStateTransitionApprovalCommandValidator.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositStateTransitionApprovalCommandValidator.java new file mode 100644 index 000000000..cc5b96212 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositStateTransitionApprovalCommandValidator.java @@ -0,0 +1,39 @@ +package org.mifosng.platform.saving.service; + +import java.util.ArrayList; +import java.util.List; + +import org.mifosng.platform.DataValidatorBuilder; +import org.mifosng.platform.api.commands.DepositStateTransitionApprovalCommand; +import org.mifosng.platform.api.data.ApiParameterError; +import org.mifosng.platform.exceptions.PlatformApiDataValidationException; + +public class DepositStateTransitionApprovalCommandValidator { + + + + private final DepositStateTransitionApprovalCommand command; + + public DepositStateTransitionApprovalCommandValidator(final DepositStateTransitionApprovalCommand command) { + this.command=command; + } + + public void validate(){ + + List dataValidationErrors = new ArrayList(); + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("deposit.transition"); + baseDataValidator.reset().parameter("accountId").value(command.getAccountId()).notNull().integerGreaterThanZero(); + baseDataValidator.reset().parameter("eventDate").value(command.getEventDate()).notNull(); + + baseDataValidator.reset().parameter("depositAmount").value(command.getDepositAmount()).notNull().zeroOrPositiveAmount(); + baseDataValidator.reset().parameter("tenureInMonths").value(command.getTenureInMonths()).ignoreIfNull().integerGreaterThanZero(); + baseDataValidator.reset().parameter("interestCompoundedEveryPeriodType").value(command.getInterestCompoundedEveryPeriodType()).ignoreIfNull().inMinMaxRange(2, 2); + + if (!dataValidationErrors.isEmpty()) { + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); + } + } + + + +}