@@ -12704,6 +12704,52 @@ Request Body:
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="savingsaccounts_close" name="savingsaccounts_close" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h2>Close a savings account</h2>
|
||||
<p>Results in an Activated savings application being converted into an 'closed' savings account.</p>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">POST https://Domain Name/api/v1/savingsaccounts/{savingsId}?command=close</code>
|
||||
<code class="method-request">POST savingsaccount/5?command=close
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{
|
||||
"dateFormat":"dd MMMM yyyy",
|
||||
"locale":"en",
|
||||
"closedOnDate":"26 August 2013",
|
||||
"note":"close note"
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"officeId":1,
|
||||
"clientId":1,
|
||||
"savingsId":5,
|
||||
"resourceId":5,
|
||||
"changes":{
|
||||
"status":{
|
||||
"id":600,
|
||||
"code":"savingsAccountStatusType.closed",
|
||||
"value":"Closed",
|
||||
"submittedAndPendingApproval":false,
|
||||
"approved":false,
|
||||
"rejected":false,
|
||||
"withdrawnByApplicant":false,
|
||||
"active":false,
|
||||
"closed":true
|
||||
},
|
||||
"locale":"en",
|
||||
"dateFormat":"dd MMMM yyyy",
|
||||
"closedOnDate":"26 August 2013",
|
||||
"note":"close note"
|
||||
}
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="savingsaccounts_calculate_interest" name="savingsaccounts_calculate_interest" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
@@ -19323,6 +19369,14 @@ GET https://DomainName/api/v1/search?query=000000111
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="alt">
|
||||
<td></td>
|
||||
<td>savingsaccounts/{accountId}?command=close</td>
|
||||
<td><a href="#savingsaccounts_close">Close a savings account</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>savingsaccounts/{accountId}?command=calculateInterest</td>
|
||||
|
||||
@@ -457,6 +457,10 @@ public class CommandWrapper {
|
||||
public boolean isSavingsAccountDeposit() {
|
||||
return this.actionName.equalsIgnoreCase("DEPOSIT") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isSavingsAccountClose() {
|
||||
return this.actionName.equalsIgnoreCase("CLOSE") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isSavingsAccountWithdrawal() {
|
||||
return this.actionName.equalsIgnoreCase("WITHDRAWAL") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||
|
||||
+10
@@ -843,6 +843,16 @@ public class CommandWrapperBuilder {
|
||||
this.href = "/savingsaccounts/" + accountId + "?command=activate";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder closeSavingsAccountApplication(final Long accountId) {
|
||||
this.actionName = "CLOSE";
|
||||
this.entityName = "SAVINGSACCOUNT";
|
||||
this.entityId = accountId;
|
||||
this.savingsId = accountId;
|
||||
this.href = "/savingsaccounts/" + accountId + "?command=close";
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CommandWrapperBuilder createAccountTransfer() {
|
||||
this.actionName = "CREATE";
|
||||
|
||||
+2
@@ -422,6 +422,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
handler = this.applicationContext.getBean("undoTransactionSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isAdjustSavingsAccountTransaction()) {
|
||||
handler = this.applicationContext.getBean("savingsTransactionAdjustmentCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isSavingsAccountClose()) {
|
||||
handler = this.applicationContext.getBean("closeSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
|
||||
+6
@@ -31,6 +31,7 @@ public class SavingsApiConstants {
|
||||
public static String undoTransactionAction = ".undotransaction";
|
||||
public static String applyAnnualFeeTransactionAction = ".applyannualfee";
|
||||
public static String adjustTransactionAction = ".adjusttransaction";
|
||||
public static String closeAction = ".close";
|
||||
|
||||
// command
|
||||
public static String COMMAND_UNDO_TRANSACTION = "undo";
|
||||
@@ -91,6 +92,8 @@ public class SavingsApiConstants {
|
||||
public static final String runningBalanceParamName = "runningBalance";
|
||||
public static final String reversedParamName = "reversed";
|
||||
public static final String dateParamName = "date";
|
||||
|
||||
public static final String noteParamName = "note";
|
||||
|
||||
public static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
monthDayFormatParamName, nameParamName, descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName,
|
||||
@@ -150,4 +153,7 @@ public class SavingsApiConstants {
|
||||
|
||||
public static final Set<String> SAVINGS_ACCOUNT_ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, activatedOnDateParamName));
|
||||
|
||||
public static final Set<String> SAVINGS_ACCOUNT_CLOSE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, closedOnDateParamName, noteParamName));
|
||||
}
|
||||
+4
-1
@@ -224,12 +224,15 @@ public class SavingsAccountsApiResource {
|
||||
} else if (is(commandParam, "applyAnnualFees")) {
|
||||
final CommandWrapper commandRequest = builder.savingsAccountApplyAnnualFees(accountId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "close")) {
|
||||
final CommandWrapper commandRequest = builder.closeSavingsAccountApplication(accountId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
//
|
||||
throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "reject", "withdrawnByApplicant", "approve",
|
||||
"undoapproval", "activate", "calculateInterest", "postInterest" });
|
||||
"undoapproval", "activate", "calculateInterest", "postInterest", "close" });
|
||||
}
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
|
||||
+23
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.savings.data;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.activatedOnDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.bankNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.checkNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.closedOnDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.paymentTypeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.receiptNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.routingCodeParamName;
|
||||
@@ -105,6 +106,28 @@ public class SavingsAccountTransactionDataValidator {
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validateClosing(final JsonCommand command) {
|
||||
final String json = command.json();
|
||||
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
|
||||
SavingsApiConstants.SAVINGS_ACCOUNT_CLOSE_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
final JsonElement element = command.parsedJson();
|
||||
|
||||
final LocalDate activationDate = fromApiJsonHelper.extractLocalDateNamed(closedOnDateParamName, element);
|
||||
baseDataValidator.reset().parameter(closedOnDateParamName).value(activationDate).notNull();
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
|
||||
+57
@@ -1658,6 +1658,63 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public Map<String, Object> close(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.closeAction);
|
||||
|
||||
final SavingsAccountStatusType currentStatus = SavingsAccountStatusType.fromInt(this.status);
|
||||
if (!SavingsAccountStatusType.ACTIVE.hasStateOf(currentStatus)) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("not.in.active.state");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName);
|
||||
|
||||
if (closedDate.isBefore(getActivationLocalDate())) {
|
||||
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
|
||||
.failWithCode("must.be.after.activation.date");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
if (closedDate.isAfter(tenantsTodayDate)) {
|
||||
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
|
||||
.failWithCode("cannot.be.a.future.date");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
List<SavingsAccountTransaction> savingsAccountTransactions = retreiveListOfTransactions();
|
||||
if (savingsAccountTransactions.size() > 0) {
|
||||
SavingsAccountTransaction accountTransaction = savingsAccountTransactions.get(savingsAccountTransactions.size() - 1);
|
||||
if (accountTransaction.isAfter(closedDate)) {
|
||||
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
|
||||
.failWithCode("must.be.after.last.transaction.date");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
}
|
||||
if (getAccountBalance().doubleValue() > 0) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("results.in.balance.not.zero");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
this.status = SavingsAccountStatusType.CLOSED.getValue();
|
||||
actualChanges.put(SavingsApiConstants.statusParamName, SavingsEnumerations.status(this.status));
|
||||
actualChanges.put(SavingsApiConstants.localeParamName, command.locale());
|
||||
actualChanges.put(SavingsApiConstants.dateFormatParamName, command.dateFormat());
|
||||
actualChanges.put(SavingsApiConstants.closedOnDateParamName, closedDate.toString(fmt));
|
||||
|
||||
this.rejectedOnDate = null;
|
||||
this.rejectedBy = null;
|
||||
this.withdrawnOnDate = null;
|
||||
this.withdrawnBy = null;
|
||||
this.closedOnDate = closedDate.toDate();
|
||||
this.closedBy = currentUser;
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
private Date calculateDateAccountIsLockedUntil(final LocalDate activationLocalDate) {
|
||||
|
||||
Date lockedInUntilLocalDate = null;
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
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.SavingsAccountWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class CloseSavingsAccountCommandHandler implements NewCommandSourceHandler{
|
||||
|
||||
private final SavingsAccountWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public CloseSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
|
||||
this.writePlatformService = savingAccountWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.writePlatformService.close(command.getSavingsId(), command);
|
||||
}
|
||||
|
||||
}
|
||||
+2
@@ -28,4 +28,6 @@ public interface SavingsAccountWritePlatformService {
|
||||
void postInterestForAccounts();
|
||||
|
||||
CommandProcessingResult adjustSavingsTransaction(Long savingsId, Long transactionId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult close(Long savingsId, JsonCommand command);
|
||||
}
|
||||
+33
-1
@@ -14,6 +14,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
@@ -32,6 +33,8 @@ import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.client.exception.ClientNotActiveException;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
|
||||
import org.mifosplatform.portfolio.note.domain.Note;
|
||||
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.SavingsApiConstants;
|
||||
@@ -62,6 +65,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper;
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
private final SavingsAccountDomainService savingsAccountDomainService;
|
||||
private final NoteRepository noteRepository;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
@@ -72,7 +76,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final PaymentDetailWritePlatformService paymentDetailWritePlatformService,
|
||||
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService,
|
||||
final SavingsAccountDomainService savingsAccountDomainService) {
|
||||
final SavingsAccountDomainService savingsAccountDomainService, final NoteRepository noteRepository) {
|
||||
this.context = context;
|
||||
this.savingAccountRepository = savingAccountRepository;
|
||||
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
|
||||
@@ -82,6 +86,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper;
|
||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||
this.savingsAccountDomainService = savingsAccountDomainService;
|
||||
this.noteRepository = noteRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -389,4 +394,31 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
if (group.isNotActive()) { throw new GroupNotActiveException(group.getId()); }
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult close(Long savingsId, JsonCommand command) {
|
||||
final AppUser user = this.context.authenticatedUser();
|
||||
|
||||
this.savingsAccountTransactionDataValidator.validateClosing(command);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final Map<String, Object> changes = account.close(user, command, DateUtils.getLocalDateOfTenant());
|
||||
if (!changes.isEmpty()) {
|
||||
this.savingAccountRepository.save(account);
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
final Note note = Note.savingNote(account, noteText);
|
||||
changes.put("note", noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
}
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user