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 b54cf9c63..177195f92 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 @@ -205,7 +205,7 @@ public class DepositAccountsApiResource { } else if (is(commandParam, "withdrewbyclient")) { EntityIdentifier identifier = this.depositAccountWritePlatformService.withdrawDepositApplication(command); response = Response.ok().entity(identifier).build(); - } else if (is(commandParam, "matureAccount")){ + } else if (is(commandParam, "mature")){ EntityIdentifier identifier = this.depositAccountWritePlatformService.matureDepositApplication(command); response = Response.ok().entity(identifier).build(); } 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 1f834d369..943b8db56 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 @@ -12,6 +12,7 @@ import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; +import javax.persistence.OneToOne; import javax.persistence.OrderBy; import javax.persistence.Table; import javax.persistence.Temporal; @@ -135,6 +136,10 @@ public class DepositAccount extends AbstractAuditableCustom { @LazyCollection(LazyCollectionOption.FALSE) @OneToMany(cascade = CascadeType.ALL, mappedBy = "depositAccount", orphanRemoval = true) private final List depositaccountTransactions = new ArrayList(); + + @OneToOne(optional=true, cascade={CascadeType.PERSIST}) + @JoinColumn(name = "renewed_account_id") + private DepositAccount renewdAccount; public DepositAccount openNew( final Client client, final DepositProduct product, @@ -381,10 +386,22 @@ public class DepositAccount extends AbstractAuditableCustom { public Client client() { return this.client; } + + public DepositProduct product(){ + return this.product; + } + + public String getExternalId() { + return this.externalId; + } + + public boolean isRenewalAllowed() { + return renewalAllowed; + } public void matureDepositApplication(LocalDate maturedOnDate, DepositLifecycleStateMachine depositLifecycleStateMachine) { - if (maturedOnDate.isAfter(maturesOnDate()) || new LocalDate().equals(maturesOnDate())) { + if (maturedOnDate.isAfter(maturesOnDate()) || (new LocalDate().equals(maturesOnDate()) && maturedOnDate.equals(maturesOnDate()))) { DepositAccountStatus statusEnum = depositLifecycleStateMachine.transition( DepositAccountEvent.DEPOSIT_MATURED, DepositAccountStatus.fromInt(this.depositStatus)); @@ -394,19 +411,49 @@ public class DepositAccount extends AbstractAuditableCustom { DepositAccountTransaction depositaccountTransaction = DepositAccountTransaction.withdraw(Money.of(this.currency, this.total), maturedOnDate); depositaccountTransaction.updateAccount(this); this.depositaccountTransactions.add(depositaccountTransaction); + + DepositAccountStatus statusEnumForClose = depositLifecycleStateMachine.transition( + DepositAccountEvent.DEPOSIT_CLOSED, + DepositAccountStatus.fromInt(this.depositStatus)); + this.depositStatus = statusEnumForClose.getValue(); + + this.depositAmount = null; + this.interestRate = null; + this.tenureInMonths = null; + this.interestCompoundedEvery = null; + this.interestCompoundedFrequencyType = null; + this.closedOnDate = maturedOnDate.toDate(); + this.withdrawnOnDate = null; + this.rejectedOnDate = null; + + }else if(this.renewalAllowed){ + DepositAccountStatus statusEnumForClose = depositLifecycleStateMachine.transition( + DepositAccountEvent.DEPOSIT_CLOSED, + DepositAccountStatus.fromInt(this.depositStatus)); + this.depositStatus = statusEnumForClose.getValue(); + this.closedOnDate = maturedOnDate.toDate(); + this.withdrawnOnDate = null; + this.rejectedOnDate = null; } } - - if (maturesOnDate().isBefore(new LocalDate())) { - - final String errorMessage = "The date on which a deposit is rejected cannot be before its submittal date: " + if (maturedOnDate.isBefore(new LocalDate()) || maturedOnDate.isBefore(maturesOnDate())) { + + final String errorMessage = "The date on which a deposit matured is cannot be before its matured date: " + new LocalDate().toString(); - throw new InvalidDepositStateTransitionException("reject", - "cannot.be.before.submittal.date", errorMessage, + throw new InvalidDepositStateTransitionException("matured", + "cannot.be.before.mature.date", errorMessage, maturedOnDate, new LocalDate()); } + + if(maturedOnDate.equals(maturesOnDate())&& !(maturesOnDate().equals(new LocalDate()))){ + final String errorMessage = "You can not manually mature the deposit account till the maturity date reached " + + new LocalDate().toString(); + throw new InvalidDepositStateTransitionException("matured", + "cannot.manual.mature.deposit.account.date", errorMessage, + maturedOnDate, new LocalDate()); + } } public LocalDate maturesOnDate() { @@ -416,4 +463,10 @@ public class DepositAccount extends AbstractAuditableCustom { } return date; } + + public void updateAccount(DepositAccount account) { + + this.renewdAccount = account; + + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccountEvent.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccountEvent.java index 0fed22102..363c95305 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccountEvent.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccountEvent.java @@ -2,6 +2,6 @@ package org.mifosng.platform.saving.domain; public enum DepositAccountEvent { - DEPOSIT_CREATED, DEPOSIT_REJECTED, DEPOSIT_APPROVED, DEPOSIT_APPROVAL_UNDO, DEPOSIT_WITHDRAWN, DEPOSIT_MATURED; + DEPOSIT_CREATED, DEPOSIT_REJECTED, DEPOSIT_APPROVED, DEPOSIT_APPROVAL_UNDO, DEPOSIT_WITHDRAWN, DEPOSIT_MATURED, DEPOSIT_CLOSED; } 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 e79c5881b..f4e480eae 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 @@ -69,6 +69,17 @@ public class DepositLifecycleStateMachineImpl implements throw new InvalidDepositStateTransitionException("mature", "failed", errorMessage,from); } break; + case DEPOSIT_CLOSED: + if (from.hasStateOf(DepositAccountStatus.MATURED) ){ + newState = stateOf(DepositAccountStatus.CLOSED, allowedDepositStatuses); + } + else{ + final String errorMessage = "The DepositApplication can not be closed from "+from.getCode() ; + throw new InvalidDepositStateTransitionException("closed", "failed", errorMessage,from); + } + break; + default: + break; } return newState; 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 17226c3ab..ed6f0699a 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 @@ -109,4 +109,42 @@ public class DepositAccountAssembler { List allowedDepositStatuses = Arrays.asList(DepositAccountStatus.values()); return new DepositLifecycleStateMachineImpl(allowedDepositStatuses); } + + public DepositAccount assembleFrom(DepositAccount account) { + + Client client = account.client(); + + DepositProduct product = account.product(); + + Money deposit = Money.of(product.getCurrency(), account.getDeposit().getAmount()); + + Integer tenureInMonths = product.getTenureInMonths(); + + BigDecimal maturityInterestRate = product.getMaturityDefaultInterestRate(); + + BigDecimal preClosureInterestRate = product.getPreClosureInterestRate(); + + if(product.getMaturityMinInterestRate().compareTo(preClosureInterestRate)==-1){ + throw new DepositAccounDataValidationtException(preClosureInterestRate, product.getMaturityMinInterestRate()); + } + + Integer compoundingInterestEvery = product.getInterestCompoundedEvery(); + + PeriodFrequencyType compoundingInterestFrequency = product.getInterestCompoundedEveryPeriodType(); + + boolean renewalAllowed = product.isRenewalAllowed(); + + boolean preClosureAllowed = product.isPreClosureAllowed(); + + DepositAccount newAccount =new DepositAccount().openNew(client, product, null, + deposit, + maturityInterestRate, preClosureInterestRate, + tenureInMonths, compoundingInterestEvery, compoundingInterestFrequency, + account.maturesOnDate(), + renewalAllowed, preClosureAllowed, this.fixedTermDepositInterestCalculator, defaultDepositLifecycleStateMachine()); + + newAccount.updateAccount(account); + + return newAccount; + } } \ No newline at end of file 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 98de99761..cc8277a06 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 @@ -257,6 +257,12 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo account.matureDepositApplication(eventDate, defaultDepositLifecycleStateMachine()); this.depositAccountRepository.save(account); + if(account.isRenewalAllowed()){ + final DepositAccount renewedAccount = this.depositAccountAssembler.assembleFrom(account); + this.depositAccountRepository.save(renewedAccount); + return new EntityIdentifier(renewedAccount.getId()); //returns the new deposit application id + } + String noteText = command.getNote(); if (StringUtils.isNotBlank(noteText)) { Note note = Note.depositNote(account, noteText);