MIFOSX-1700

This commit is contained in:
Vishwas Babu A J
2014-12-06 21:49:20 -08:00
parent 990cab63cf
commit 002ef06d51
14 changed files with 228 additions and 12 deletions
+44
View File
@@ -753,6 +753,14 @@
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>recurringdepositaccounts/{accountId}?command=updateDepositAmount</td>
<td><a href="#rdaccounts_update_deposit_amount">Update recommended deposit amount</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>recurringdepositaccounts/{accountId}?command=close</td>
@@ -23460,6 +23468,42 @@ Request Body:
</div>
</div>
<a id="rdaccounts_update_deposit_amount" name="rdaccounts_update_deposit_amount" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h2>Update the recommended deposit amount for a recurring deposit account</h2>
<p>Updates the recommended deposit amount for a RD account as on the effective date.</p>
</div>
<div class="method-example">
<code class="method-declaration">POST https://Domain Name/api/v1/recurringdepositaccounts/{accountId}?command=updateDepositAmount</code>
<code class="method-request">POST recurringdepositaccounts/4?command=updateDepositAmount
Content-Type: application/json
Request Body:
{
"locale": "en",
"dateFormat": "dd MMMM yyyy",
"effectiveDate": "01 Dec 2014"
"mandatoryRecommendedDepositAmount": 398
}
</code>
<code class="method-response">
{
"officeId": 1,
"clientId": 6,
"savingsId": 4,
"resourceId": 4,
"changes":
{
"mandatoryRecommendedDepositAmount": 398
}
}
</code>
</div>
</div>
<a id="rdaccounts_close" name="rdaccounts_close" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
@@ -7,6 +7,7 @@ package org.mifosplatform.commands.domain;
import org.mifosplatform.infrastructure.accountnumberformat.service.AccountNumberFormatConstants;
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
import org.mifosplatform.portfolio.savings.DepositsApiConstants;
public class CommandWrapper {
@@ -866,9 +867,11 @@ public class CommandWrapper {
public boolean isWithdrawal() {
return this.actionName.equalsIgnoreCase("WITHDRAWAL");
}
public boolean isWithdrawn() {
return this.actionName.equalsIgnoreCase("WITHDRAW");
}
public boolean isReactivated() {
return this.actionName.equalsIgnoreCase("REACTIVATE");
}
@@ -901,6 +904,10 @@ public class CommandWrapper {
return this.actionName.equalsIgnoreCase("PREMATURECLOSE") && isDepositAccountResource();
}
public boolean isDepositAmountUpdateForRecurringDepositAccount() {
return this.actionName.equalsIgnoreCase(DepositsApiConstants.UPDATE_DEPOSIT_AMOUNT.toUpperCase()) && isDepositAccountResource();
}
// End - Deposit accounts
public boolean isFinancialActivityAccountMapping() {
@@ -7,6 +7,7 @@ package org.mifosplatform.commands.service;
import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.infrastructure.accountnumberformat.service.AccountNumberFormatConstants;
import org.mifosplatform.portfolio.savings.DepositsApiConstants;
public class CommandWrapperBuilder {
@@ -428,7 +429,7 @@ public class CommandWrapperBuilder {
this.href = "/clients/" + clientId + "?command=close&template=true";
return this;
}
public CommandWrapperBuilder rejectClient(final Long clientId) {
this.actionName = "REJECT";
this.entityName = "CLIENT";
@@ -437,7 +438,7 @@ public class CommandWrapperBuilder {
this.href = "/clients/" + clientId + "?command=reject&template=true";
return this;
}
public CommandWrapperBuilder withdrawClient(final Long clientId) {
this.actionName = "WITHDRAW";
this.entityName = "CLIENT";
@@ -446,6 +447,7 @@ public class CommandWrapperBuilder {
this.href = "/clients/" + clientId + "?command=withdraw&template=true";
return this;
}
public CommandWrapperBuilder reActivateClient(final Long clientId) {
this.actionName = "REACTIVATE";
this.entityName = "CLIENT";
@@ -454,6 +456,7 @@ public class CommandWrapperBuilder {
this.href = "/clients/" + clientId + "?command=reactivate&template=true";
return this;
}
public CommandWrapperBuilder proposeClientTransfer(final Long clientId) {
this.actionName = "PROPOSETRANSFER";
this.entityName = "CLIENT";
@@ -2027,6 +2030,15 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder updateDepositAmountForRecurringDepositAccount(final Long accountId) {
this.actionName = DepositsApiConstants.UPDATE_DEPOSIT_AMOUNT.toUpperCase();
this.entityName = "RECURRINGDEPOSITACCOUNT";
this.entityId = accountId;
this.savingsId = accountId;
this.href = "/recurringdepositaccounts/" + accountId + "?command=" + DepositsApiConstants.UPDATE_DEPOSIT_AMOUNT;
return this;
}
public CommandWrapperBuilder prematureCloseRecurringDepositAccount(final Long accountId) {
this.actionName = "PREMATURECLOSE";
this.entityName = "RECURRINGDEPOSITACCOUNT";
@@ -204,13 +204,13 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
handler = this.applicationContext.getBean("rejectClientTransferCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUpdateClientSavingsAccount()) {
handler = this.applicationContext.getBean("updateClientSavingsAccountCommandHandler", NewCommandSourceHandler.class);
} else if(wrapper.isReject()){
} else if (wrapper.isReject()) {
handler = this.applicationContext.getBean("rejectClientCommandHandler", NewCommandSourceHandler.class);
}else if(wrapper.isWithdrawn()){
} else if (wrapper.isWithdrawn()) {
handler = this.applicationContext.getBean("withdrawClientCommandHandler", NewCommandSourceHandler.class);
}else if(wrapper.isReactivated()){
} else if (wrapper.isReactivated()) {
handler = this.applicationContext.getBean("reActivateClientCommandHandler", NewCommandSourceHandler.class);
}else {
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
// end of client
@@ -609,6 +609,9 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
} else if (wrapper.isUndoApprovalOfRecurringDepositAccountApplication()) {
handler = this.applicationContext.getBean("recurringDepositAccountApplicationApprovalUndoCommandHandler",
NewCommandSourceHandler.class);
} else if (wrapper.isDepositAmountUpdateForRecurringDepositAccount()) {
handler = this.applicationContext.getBean("recurringDepositAccountUpdateDepositAmountCommandHandler",
NewCommandSourceHandler.class);
} else if (wrapper.isDeposit()) {
handler = this.applicationContext.getBean("recurringDepositAccountDepositCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isWithdrawal()) {
@@ -17,7 +17,7 @@ public class DepositsApiConstants {
public static final String FIXED_DEPOSIT_PRODUCT_RESOURCE_NAME = "fixeddeposit";
public static final String RECURRING_DEPOSIT_PRODUCT_RESOURCE_NAME = "recurringdeposit";
// Deposti accounts
// Deposit accounts
public static final String FIXED_DEPOSIT_ACCOUNT_RESOURCE_NAME = "fixeddepositaccount";
public static final String RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME = "recurringdepositaccount";
@@ -47,6 +47,7 @@ public class DepositsApiConstants {
public static String COMMAND_ADJUST_TRANSACTION = "modify";
public static String COMMAND_WAIVE_CHARGE = "waive";
public static String COMMAND_PAY_CHARGE = "paycharge";
public static String UPDATE_DEPOSIT_AMOUNT = "updateDepositAmount";
// general
public static final String localeParamName = "locale";
@@ -138,6 +139,9 @@ public class DepositsApiConstants {
public static final String reversedParamName = "reversed";
public static final String dateParamName = "date";
// recurring deposits update parameters
public static final String effectiveDateParamName = "effectiveDate";
// charges parameters
public static final String chargeIdParamName = "chargeId";
public static final String chargesParamName = "charges";
@@ -331,6 +335,9 @@ public class DepositsApiConstants {
dateFormatParamName, transactionDateParamName, transactionAmountParamName, paymentTypeIdParamName,
transactionAccountNumberParamName, checkNumberParamName, routingCodeParamName, receiptNumberParamName, bankNumberParamName));
public static final Set<String> DEPOSIT_ACCOUNT_RECOMMENDED_DEPOSIT_AMOUNT_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<>(
Arrays.asList(localeParamName, dateFormatParamName, mandatoryRecommendedDepositAmountParamName, effectiveDateParamName));
public static final Set<String> FIXED_DEPOSIT_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName,
"accountId", accountNoParamName, "currency", "amount", dateParamName, paymentDetailDataParamName, runningBalanceParamName,
reversedParamName));
@@ -262,6 +262,10 @@ public class RecurringDepositAccountsApiResource {
} else if (is(commandParam, "calculateInterest")) {
final CommandWrapper commandRequest = builder.withNoJsonBody().recurringDepositAccountInterestCalculation(accountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, DepositsApiConstants.UPDATE_DEPOSIT_AMOUNT)) {
final CommandWrapper commandRequest = builder.updateDepositAmountForRecurringDepositAccount(accountId)
.withJson(apiRequestBodyAsJson).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "postInterest")) {
final CommandWrapper commandRequest = builder.recurringDepositAccountInterestPosting(accountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
@@ -91,6 +91,32 @@ public class DepositAccountTransactionDataValidator {
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateDepositAmountUpdate(final JsonCommand command) {
final String json = command.json();
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
DepositsApiConstants.DEPOSIT_ACCOUNT_RECOMMENDED_DEPOSIT_AMOUNT_UPDATE_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
final JsonElement element = command.parsedJson();
final LocalDate effectiveDate = this.fromApiJsonHelper.extractLocalDateNamed(DepositsApiConstants.effectiveDateParamName, element);
baseDataValidator.reset().parameter(DepositsApiConstants.effectiveDateParamName).value(effectiveDate).notNull();
final BigDecimal mandatoryRecommendedDepositAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
DepositsApiConstants.mandatoryRecommendedDepositAmountParamName, element);
baseDataValidator.reset().parameter(DepositsApiConstants.mandatoryRecommendedDepositAmountParamName)
.value(mandatoryRecommendedDepositAmount).notNull().positiveAmount();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateActivation(final JsonCommand command) {
final String json = command.json();
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.savings.domain;
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.mandatoryRecommendedDepositAmountParamName;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -18,7 +19,9 @@ import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -92,6 +95,21 @@ public class DepositAccountRecurringDetail extends AbstractPersistable<Long> {
return actualChanges;
}
public Map<String, Object> updateMandatoryRecommendedDepositAmount(BigDecimal newMandatoryRecommendedDepositAmount,
LocalDate effectiveDate, Boolean isSavingsInterestPostingAtCurrentPeriodEnd, Integer financialYearBeginningMonth) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(10);
actualChanges.put(mandatoryRecommendedDepositAmountParamName, newMandatoryRecommendedDepositAmount);
this.mandatoryRecommendedDepositAmount = newMandatoryRecommendedDepositAmount;
RecurringDepositAccount depositAccount = (RecurringDepositAccount) this.account;
depositAccount.updateScheduleInstallmentsWithNewRecommendedDepositAmount(newMandatoryRecommendedDepositAmount, effectiveDate);
depositAccount.updateOverduePayments(DateUtils.getLocalDateOfTenant());
MathContext mc = MathContext.DECIMAL64;
Boolean isPreMatureClosure = false;
depositAccount.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth);
return actualChanges;
}
public DepositRecurringDetail recurringDetail() {
return this.recurringDetail;
}
@@ -828,6 +828,24 @@ public class RecurringDepositAccount extends SavingsAccount {
}
}
public void updateScheduleInstallmentsWithNewRecommendedDepositAmount(BigDecimal newDepositAmount,
LocalDate depositAmountupdatedFromDate) {
// reset all installments to process from the beginning, also update
// deposit amount as necessary
for (RecurringDepositScheduleInstallment currentInstallment : depositScheduleInstallments()) {
if (currentInstallment.dueDate().isAfter(depositAmountupdatedFromDate)) {
currentInstallment.updateDepositAmountAndResetDerivedFields(newDepositAmount);
} else {
currentInstallment.resetDerivedFields();
}
}
final List<SavingsAccountTransaction> orderedDepositTransactions = retreiveOrderedDepositTransactions();
for (SavingsAccountTransaction transaction : orderedDepositTransactions) {
handleScheduleInstallments(transaction);
}
}
private List<SavingsAccountTransaction> retreiveOrderedDepositTransactions() {
final List<SavingsAccountTransaction> listOfTransactionsSorted = retreiveListOfTransactions();
@@ -1123,4 +1141,9 @@ public class RecurringDepositAccount extends SavingsAccount {
public boolean isTransactionsAllowed() {
return isActive() || isAccountMatured();
}
public DepositAccountRecurringDetail getRecurringDetail() {
return this.recurringDetail;
}
}
@@ -31,15 +31,15 @@ public class RecurringDepositScheduleInstallment extends AbstractAuditableCustom
private RecurringDepositAccount account;
@Column(name = "installment", nullable = false)
private Integer installmentNumber;
private final Integer installmentNumber;
@Temporal(TemporalType.DATE)
@Column(name = "fromdate", nullable = true)
private Date fromDate;
private final Date fromDate;
@Temporal(TemporalType.DATE)
@Column(name = "duedate", nullable = false)
private Date dueDate;
private final Date dueDate;
@Column(name = "deposit_amount", scale = 6, precision = 19, nullable = true)
private BigDecimal depositAmount;
@@ -223,4 +223,9 @@ public class RecurringDepositScheduleInstallment extends AbstractAuditableCustom
this.obligationsMet = false;
this.obligationsMetOnDate = null;
}
public void updateDepositAmountAndResetDerivedFields(BigDecimal newDepositAmount) {
this.depositAmount = newDepositAmount;
this.resetDerivedFields();
}
}
@@ -0,0 +1,32 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.savings.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.savings.service.DepositAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class RecurringDepositAccountUpdateDepositAmountCommandHandler implements NewCommandSourceHandler {
private final DepositAccountWritePlatformService depositAccountWritePlatformService;
@Autowired
public RecurringDepositAccountUpdateDepositAmountCommandHandler(
final DepositAccountWritePlatformService depositAccountWritePlatformService) {
this.depositAccountWritePlatformService = depositAccountWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.depositAccountWritePlatformService.updateDepositAmountForRDAccount(command.entityId(), command);
}
}
@@ -21,6 +21,8 @@ public interface DepositAccountWritePlatformService {
CommandProcessingResult activateRDAccount(Long savingsId, JsonCommand command);
CommandProcessingResult updateDepositAmountForRDAccount(Long savingsId, JsonCommand command);
CommandProcessingResult depositToFDAccount(Long savingsId, JsonCommand command);
CommandProcessingResult depositToRDAccount(Long savingsId, JsonCommand command);
@@ -74,6 +74,7 @@ import org.mifosplatform.portfolio.note.domain.NoteRepository;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
import org.mifosplatform.portfolio.savings.DepositAccountType;
import org.mifosplatform.portfolio.savings.DepositsApiConstants;
import org.mifosplatform.portfolio.savings.SavingsAccountTransactionType;
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
import org.mifosplatform.portfolio.savings.data.DepositAccountTransactionDataValidator;
@@ -81,6 +82,7 @@ import org.mifosplatform.portfolio.savings.data.SavingsAccountChargeDataValidato
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionDTO;
import org.mifosplatform.portfolio.savings.domain.DepositAccountAssembler;
import org.mifosplatform.portfolio.savings.domain.DepositAccountDomainService;
import org.mifosplatform.portfolio.savings.domain.DepositAccountRecurringDetail;
import org.mifosplatform.portfolio.savings.domain.FixedDepositAccount;
import org.mifosplatform.portfolio.savings.domain.RecurringDepositAccount;
import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
@@ -348,13 +350,41 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
}
@Transactional
@Override
public CommandProcessingResult updateDepositAmountForRDAccount(Long savingsId, JsonCommand command) {
this.depositAccountTransactionDataValidator.validateDepositAmountUpdate(command);
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
final BigDecimal mandatoryRecommendedDepositAmount = command
.bigDecimalValueOfParameterNamed(DepositsApiConstants.mandatoryRecommendedDepositAmountParamName);
final LocalDate depositAmountUpdateEffectiveFromDate = command
.localDateValueOfParameterNamed(DepositsApiConstants.effectiveDateParamName);
final RecurringDepositAccount recurringDepositAccount = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom(
savingsId, DepositAccountType.RECURRING_DEPOSIT);
DepositAccountRecurringDetail recurringDetail = recurringDepositAccount.getRecurringDetail();
Map<String, Object> changes = recurringDetail.updateMandatoryRecommendedDepositAmount(mandatoryRecommendedDepositAmount,
depositAmountUpdateEffectiveFromDate, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
return new CommandProcessingResultBuilder() //
.withEntityId(savingsId) //
.withOfficeId(recurringDepositAccount.officeId()) //
.withClientId(recurringDepositAccount.clientId()) //
.withGroupId(recurringDepositAccount.groupId()) //
.withSavingsId(savingsId) //
.with(changes) //
.build();
}
@Transactional
@Override
public CommandProcessingResult depositToRDAccount(final Long savingsId, final JsonCommand command) {
boolean isRegularTransaction = true;
this.context.authenticatedUser();
this.depositAccountTransactionDataValidator.validate(command, DepositAccountType.RECURRING_DEPOSIT);
final RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom(savingsId,
@@ -0,0 +1,3 @@
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ( 'transaction_savings', 'UPDATEDEPOSITAMOUNT_RECURRINGDEPOSITACCOUNT', 'RECURRINGDEPOSITACCOUNT', 'UPDATEDEPOSITAMOUNT', 1);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ( 'transaction_savings', 'UPDATEDEPOSITAMOUNT_RECURRINGDEPOSITACCOUNT_CHECKER', 'RECURRINGDEPOSITACCOUNT', 'UPDATEDEPOSITAMOUNT', 1);