Merge pull request #514 from pramodn02/MIFOSX-586

added savings transaction adjustment API
This commit is contained in:
Vishwas Babu A J
2013-08-08 03:01:25 -07:00
14 changed files with 227 additions and 49 deletions
@@ -0,0 +1 @@
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('transaction_savings', 'ADJUSTTRANSACTION_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'ADJUSTTRANSACTION', 0);
@@ -478,6 +478,10 @@ public class CommandWrapper {
return this.actionName.equalsIgnoreCase("UNDOTRANSACTION") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT"); return this.actionName.equalsIgnoreCase("UNDOTRANSACTION") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
} }
public boolean isAdjustSavingsAccountTransaction() {
return this.actionName.equalsIgnoreCase("ADJUSTTRANSACTION") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
}
public boolean isCalendarResource() { public boolean isCalendarResource() {
return this.entityName.equalsIgnoreCase("CALENDAR"); return this.entityName.equalsIgnoreCase("CALENDAR");
} }
@@ -372,30 +372,30 @@ public class CommandWrapperBuilder {
} }
public CommandWrapperBuilder createDBDatatable(final String json) { public CommandWrapperBuilder createDBDatatable(final String json) {
this.actionName = "CREATE"; this.actionName = "CREATE";
this.entityName = "DATATABLE"; this.entityName = "DATATABLE";
this.entityId = null; this.entityId = null;
this.href = "/datatables/"; this.href = "/datatables/";
this.json = json; this.json = json;
return this; return this;
} }
public CommandWrapperBuilder updateDBDatatable(final String datatable, final String json) { public CommandWrapperBuilder updateDBDatatable(final String datatable, final String json) {
this.actionName = "UPDATE"; this.actionName = "UPDATE";
this.entityName = "DATATABLE"; this.entityName = "DATATABLE";
this.entityId = null; this.entityId = null;
this.href = "/datatables/" + datatable; this.href = "/datatables/" + datatable;
this.json = json; this.json = json;
return this; return this;
} }
public CommandWrapperBuilder deleteDBDatatable(final String datatable, final String json) { public CommandWrapperBuilder deleteDBDatatable(final String datatable, final String json) {
this.actionName = "DELETE"; this.actionName = "DELETE";
this.entityName = "DATATABLE"; this.entityName = "DATATABLE";
this.entityId = null; this.entityId = null;
this.href = "/datatables/" + datatable; this.href = "/datatables/" + datatable;
this.json = json; this.json = json;
return this; return this;
} }
public CommandWrapperBuilder createDatatable(final String datatable, final Long apptableId, final Long datatableId) { public CommandWrapperBuilder createDatatable(final String datatable, final Long apptableId, final Long datatableId) {
@@ -845,6 +845,17 @@ public class CommandWrapperBuilder {
return this; return this;
} }
public CommandWrapperBuilder adjustSavingsAccountTransaction(final Long accountId, final Long transactionId) {
this.actionName = "ADJUSTTRANSACTION";
this.entityName = "SAVINGSACCOUNT";
this.savingsId = accountId;
this.entityId = accountId;
this.subentityId = transactionId;
this.transactionId = transactionId.toString();
this.href = "/savingsaccounts/" + accountId + "/transactions/" + transactionId + "?command=modify";
return this;
}
public CommandWrapperBuilder savingsAccountInterestCalculation(final Long accountId) { public CommandWrapperBuilder savingsAccountInterestCalculation(final Long accountId) {
this.actionName = "CALCULATEINTEREST"; this.actionName = "CALCULATEINTEREST";
this.entityName = "SAVINGSACCOUNT"; this.entityName = "SAVINGSACCOUNT";
@@ -1004,7 +1015,7 @@ public class CommandWrapperBuilder {
this.entityName = "GROUP"; this.entityName = "GROUP";
this.entityId = groupId; this.entityId = groupId;
this.groupId = groupId; this.groupId = groupId;
this.href = "/groups/" + groupId +"?command=assignStaff"; this.href = "/groups/" + groupId + "?command=assignStaff";
return this; return this;
} }
@@ -1120,7 +1131,7 @@ public class CommandWrapperBuilder {
this.entityName = "GROUP"; this.entityName = "GROUP";
this.groupId = groupId; this.groupId = groupId;
this.entityId = null; this.entityId = null;
this.href = "/groups/"+groupId+"?command=assignRole"; this.href = "/groups/" + groupId + "?command=assignRole";
return this; return this;
} }
@@ -1129,7 +1140,7 @@ public class CommandWrapperBuilder {
this.entityName = "GROUP"; this.entityName = "GROUP";
this.groupId = groupId; this.groupId = groupId;
this.entityId = roleId; this.entityId = roleId;
this.href = "/groups/"+groupId+"?command=unassignRole"; this.href = "/groups/" + groupId + "?command=unassignRole";
return this; return this;
} }
@@ -1138,7 +1149,7 @@ public class CommandWrapperBuilder {
this.entityName = "GROUP"; this.entityName = "GROUP";
this.groupId = groupId; this.groupId = groupId;
this.entityId = roleId; this.entityId = roleId;
this.href = "/groups/"+groupId+"?command=updateRole"; this.href = "/groups/" + groupId + "?command=updateRole";
return this; return this;
} }
@@ -1196,7 +1207,7 @@ public class CommandWrapperBuilder {
this.actionName = "UPDATE"; this.actionName = "UPDATE";
this.entityName = "SCHEDULER"; this.entityName = "SCHEDULER";
this.entityId = jobId; this.entityId = jobId;
this.href = "/updateJobDetail/" + jobId+"/updateJobDetail"; this.href = "/updateJobDetail/" + jobId + "/updateJobDetail";
return this; return this;
} }
} }
@@ -412,6 +412,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
handler = this.applicationContext.getBean("applyAnnualFeeSavingsAccountCommandHandler", NewCommandSourceHandler.class); handler = this.applicationContext.getBean("applyAnnualFeeSavingsAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isSavingsAccountUndoTransaction()) { } else if (wrapper.isSavingsAccountUndoTransaction()) {
handler = this.applicationContext.getBean("undoTransactionSavingsAccountCommandHandler", NewCommandSourceHandler.class); handler = this.applicationContext.getBean("undoTransactionSavingsAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isAdjustSavingsAccountTransaction()) {
handler = this.applicationContext.getBean("savingsTransactionAdjustmentCommandHandler", NewCommandSourceHandler.class);
} else { } else {
throw new UnsupportedCommandException(wrapper.commandName()); throw new UnsupportedCommandException(wrapper.commandName());
} }
@@ -30,6 +30,11 @@ public class SavingsApiConstants {
public static String deleteApplicationAction = ".delete"; public static String deleteApplicationAction = ".delete";
public static String undoTransactionAction = ".undotransaction"; public static String undoTransactionAction = ".undotransaction";
public static String applyAnnualFeeTransactionAction = ".applyannualfee"; public static String applyAnnualFeeTransactionAction = ".applyannualfee";
public static String adjustTransactionAction = ".adjusttransaction";
// command
public static String COMMAND_UNDO_TRANSACTION = "undo";
public static String COMMAND_ADJUST_TRANSACTION = "modify";
// general // general
public static final String localeParamName = "locale"; public static final String localeParamName = "locale";
@@ -81,6 +86,10 @@ public class SavingsApiConstants {
// transaction parameters // transaction parameters
public static final String transactionDateParamName = "transactionDate"; public static final String transactionDateParamName = "transactionDate";
public static final String transactionAmountParamName = "transactionAmount"; public static final String transactionAmountParamName = "transactionAmount";
public static final String paymentDetailDataParamName = "paymentDetailData";
public static final String runningBalanceParamName = "runningBalance";
public static final String reversedParamName = "reversed";
public static final String dateParamName = "date";
public static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName, public static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
monthDayFormatParamName, nameParamName, descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName, monthDayFormatParamName, nameParamName, descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName,
@@ -135,7 +144,8 @@ public class SavingsApiConstants {
transactionAccountNumberParamName, checkNumberParamName, routingCodeParamName, receiptNumberParamName, bankNumberParamName)); transactionAccountNumberParamName, checkNumberParamName, routingCodeParamName, receiptNumberParamName, bankNumberParamName));
public static final Set<String> SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName, public static final Set<String> SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName,
"accountId", accountNoParamName, "currency", "amount")); "accountId", accountNoParamName, "currency", "amount", dateParamName, paymentDetailDataParamName, runningBalanceParamName,
reversedParamName));
public static final Set<String> SAVINGS_ACCOUNT_ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName, public static final Set<String> SAVINGS_ACCOUNT_ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
dateFormatParamName, activatedOnDateParamName)); dateFormatParamName, activatedOnDateParamName));
@@ -91,6 +91,27 @@ public class SavingsAccountTransactionsApiResource {
SavingsApiConstants.SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS); SavingsApiConstants.SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS);
} }
@GET
@Path("{transactionId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveOne(@PathParam("savingsId") final Long savingsId, @PathParam("transactionId") final Long transactionId,
@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
SavingsAccountTransactionData transactionData = this.savingsAccountReadPlatformService.retrieveSavingsTransaction(savingsId,
transactionId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (settings.isTemplate()) {
final Collection<CodeValueData> paymentTypeOptions = codeValueReadPlatformService
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
transactionData = SavingsAccountTransactionData.templateOnTop(transactionData, paymentTypeOptions);
}
return this.toApiJsonSerializer.serialize(settings, transactionData,
SavingsApiConstants.SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS);
}
@POST @POST
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
@@ -120,7 +141,7 @@ public class SavingsAccountTransactionsApiResource {
@Path("{transactionId}") @Path("{transactionId}")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String undoTransaction(@PathParam("savingsId") final Long savingsId, @PathParam("transactionId") final Long transactionId, public String adjustTransaction(@PathParam("savingsId") final Long savingsId, @PathParam("transactionId") final Long transactionId,
@QueryParam("command") final String commandParam, final String apiRequestBodyAsJson) { @QueryParam("command") final String commandParam, final String apiRequestBodyAsJson) {
String jsonApiRequest = apiRequestBodyAsJson; String jsonApiRequest = apiRequestBodyAsJson;
@@ -131,9 +152,12 @@ public class SavingsAccountTransactionsApiResource {
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(jsonApiRequest); final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(jsonApiRequest);
CommandProcessingResult result = null; CommandProcessingResult result = null;
if (is(commandParam, "undo")) { if (is(commandParam, SavingsApiConstants.COMMAND_UNDO_TRANSACTION)) {
final CommandWrapper commandRequest = builder.undoSavingsAccountTransaction(savingsId, transactionId).build(); final CommandWrapper commandRequest = builder.undoSavingsAccountTransaction(savingsId, transactionId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, SavingsApiConstants.COMMAND_ADJUST_TRANSACTION)) {
final CommandWrapper commandRequest = builder.adjustSavingsAccountTransaction(savingsId, transactionId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} }
if (result == null) { if (result == null) {
@@ -719,8 +719,9 @@ public class SavingsAccount extends AbstractPersistable<Long> {
} }
} }
private void validateAccountBalanceDoesNotBecomeNegativeDueToUndoAction(final List<SavingsAccountTransaction> transactionsSortedByDate) { public void validateAccountBalanceDoesNotBecomeNegative(String transactionAction) {
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
Money runningBalance = Money.zero(this.currency); Money runningBalance = Money.zero(this.currency);
for (final SavingsAccountTransaction transaction : transactionsSortedByDate) { for (final SavingsAccountTransaction transaction : transactionsSortedByDate) {
@@ -734,7 +735,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
// //
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.undoTransactionAction); .resource(SAVINGS_ACCOUNT_RESOURCE_NAME + transactionAction);
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("results.in.balance.going.negative"); baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("results.in.balance.going.negative");
@@ -1396,8 +1397,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
return actualChanges; return actualChanges;
} }
public void undoTransaction(final Long transactionId, final List<Long> reversedTransactionIds, final MathContext mc, public void undoTransaction(final Long transactionId, final List<Long> reversedTransactionIds) {
final LocalDate upToInterestCalculationDate) {
SavingsAccountTransaction transactionToUndo = null; SavingsAccountTransaction transactionToUndo = null;
for (final SavingsAccountTransaction transaction : this.transactions) { for (final SavingsAccountTransaction transaction : this.transactions) {
@@ -1424,9 +1424,6 @@ public class SavingsAccount extends AbstractPersistable<Long> {
} }
} }
calculateInterestUsing(mc, upToInterestCalculationDate);
validateAccountBalanceDoesNotBecomeNegativeDueToUndoAction(retreiveListOfTransactions());
} }
} }
@@ -0,0 +1,12 @@
package org.mifosplatform.portfolio.savings.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
public class SavingsAccountTransactionNotFoundException extends AbstractPlatformResourceNotFoundException {
public SavingsAccountTransactionNotFoundException(final Long savingsId, final Long transactionId) {
super("error.msg.saving.account.trasaction.id.invalid", "Savings account with savings identifier " + savingsId
+ " and trasaction identifier " + transactionId + " does not exist", savingsId, transactionId);
}
}
@@ -0,0 +1,15 @@
package org.mifosplatform.portfolio.savings.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformServiceUnavailableException;
/**
* A {@link RuntimeException} thrown when update not allowed.
*/
public class TransactionUpdateNotAllowedException extends AbstractPlatformServiceUnavailableException {
public TransactionUpdateNotAllowedException(final Long savingsId, final Long transactionId) {
super("error.msg.saving.account.trasaction.update.notallowed",
"Savings Account transaction update not allowed with savings identifier " + savingsId + " and trasaction identifier "
+ transactionId, savingsId, transactionId);
}
}
@@ -0,0 +1,28 @@
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 SavingsTransactionAdjustmentCommandHandler implements NewCommandSourceHandler {
private final SavingsAccountWritePlatformService writePlatformService;
@Autowired
public SavingsTransactionAdjustmentCommandHandler(final SavingsAccountWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
final Long transactionId = Long.valueOf(command.getTransactionId());
return this.writePlatformService.adjustSavingsTransaction(command.getSavingsId(), transactionId, command);
}
}
@@ -28,4 +28,6 @@ public interface SavingsAccountReadPlatformService {
Collection<SavingsAccountTransactionData> retrieveAllTransactions(Long savingsId); Collection<SavingsAccountTransactionData> retrieveAllTransactions(Long savingsId);
Collection<SavingsAccountAnnualFeeData> retrieveAccountsWithAnnualFeeDue(); Collection<SavingsAccountAnnualFeeData> retrieveAccountsWithAnnualFeeDue();
SavingsAccountTransactionData retrieveSavingsTransaction(Long savingsId, Long transactionId);
} }
@@ -507,6 +507,14 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
return this.jdbcTemplate.query(sql, this.transactionsMapper, new Object[] { savingsId }); return this.jdbcTemplate.query(sql, this.transactionsMapper, new Object[] { savingsId });
} }
@Override
public SavingsAccountTransactionData retrieveSavingsTransaction(final Long savingsId, final Long transactionId) {
final String sql = "select " + this.transactionsMapper.schema() + " where sa.id = ? and tr.id= ?";
return this.jdbcTemplate.queryForObject(sql, this.transactionsMapper, new Object[] { savingsId, transactionId });
}
@Override @Override
public Collection<SavingsAccountAnnualFeeData> retrieveAccountsWithAnnualFeeDue() { public Collection<SavingsAccountAnnualFeeData> retrieveAccountsWithAnnualFeeDue() {
final String sql = "select " + annualFeeMapper.schema() final String sql = "select " + annualFeeMapper.schema()
@@ -26,4 +26,6 @@ public interface SavingsAccountWritePlatformService {
CommandProcessingResult undoTransaction(Long savingsId, Long transactionId); CommandProcessingResult undoTransaction(Long savingsId, Long transactionId);
void postInterestForAccounts(); void postInterestForAccounts();
CommandProcessingResult adjustSavingsTransaction(Long savingsId, Long transactionId, JsonCommand command);
} }
@@ -30,6 +30,7 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyReposit
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService; import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionDataValidator; import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionDataValidator;
import org.mifosplatform.portfolio.savings.domain.SavingsAccount; import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountAssembler; import org.mifosplatform.portfolio.savings.domain.SavingsAccountAssembler;
@@ -38,6 +39,8 @@ import org.mifosplatform.portfolio.savings.domain.SavingsAccountRepository;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountStatusType; import org.mifosplatform.portfolio.savings.domain.SavingsAccountStatusType;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction; import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionRepository; import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionRepository;
import org.mifosplatform.portfolio.savings.exception.SavingsAccountTransactionNotFoundException;
import org.mifosplatform.portfolio.savings.exception.TransactionUpdateNotAllowedException;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -274,15 +277,20 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
SavingsAccountTransaction savingsAccountTransaction = this.savingsAccountTransactionRepository.findOneByIdAndSavingsAccountId( SavingsAccountTransaction savingsAccountTransaction = this.savingsAccountTransactionRepository.findOneByIdAndSavingsAccountId(
transactionId, savingsId); transactionId, savingsId);
if (savingsAccountTransaction == null) { if (savingsAccountTransaction == null) { throw new SavingsAccountTransactionNotFoundException(savingsId, transactionId); }
// throw new not found exception
}
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN); final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN);
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId); final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
account.undoTransaction(transactionId, reversedTransactionIds, mc, today); account.undoTransaction(transactionId, reversedTransactionIds);
if ((savingsAccountTransaction.isDeposit() || savingsAccountTransaction.isWithdrawal())
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
account.postInterest(mc, today, newTransactionIds, reversedTransactionIds);
} else {
account.calculateInterestUsing(mc, today);
}
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction);
postJournalEntries(account, newTransactionIds, reversedTransactionIds); postJournalEntries(account, newTransactionIds, reversedTransactionIds);
@@ -295,6 +303,60 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
.build(); .build();
} }
@Override
public CommandProcessingResult adjustSavingsTransaction(final Long savingsId, final Long transactionId, final JsonCommand command) {
SavingsAccountTransaction savingsAccountTransaction = this.savingsAccountTransactionRepository.findOneByIdAndSavingsAccountId(
transactionId, savingsId);
if (savingsAccountTransaction == null) { throw new SavingsAccountTransactionNotFoundException(savingsId, transactionId); }
if (!(savingsAccountTransaction.isDeposit() || savingsAccountTransaction.isWithdrawal()) || savingsAccountTransaction.isReversed()) { throw new TransactionUpdateNotAllowedException(
savingsId, transactionId); }
this.savingsAccountTransactionDataValidator.validate(command);
final LocalDate today = DateUtils.getLocalDateOfTenant();
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
final LocalDate transactionDate = command.localDateValueOfParameterNamed(SavingsApiConstants.transactionDateParamName);
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed(SavingsApiConstants.transactionAmountParamName);
final List<Long> existingTransactionIds = new ArrayList<Long>();
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
PaymentDetail paymentDetail = paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
account.undoTransaction(transactionId, existingReversedTransactionIds);
SavingsAccountTransaction transaction = null;
if (savingsAccountTransaction.isDeposit()) {
transaction = account.deposit(fmt, transactionDate, transactionAmount, existingTransactionIds, existingReversedTransactionIds,
paymentDetail);
} else {
transaction = account.withdraw(fmt, transactionDate, transactionAmount, existingTransactionIds, existingReversedTransactionIds,
paymentDetail);
}
final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction);
if (account.isBeforeLastPostingPeriod(transactionDate)
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
account.postInterest(mc, today, existingTransactionIds, existingReversedTransactionIds);
} else {
account.calculateInterestUsing(mc, today);
}
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.adjustTransactionAction);
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
return new CommandProcessingResultBuilder() //
.withEntityId(newtransactionId) //
.withOfficeId(account.officeId()) //
.withClientId(account.clientId()) //
.withGroupId(account.groupId()) //
.withSavingsId(savingsId) //
.with(changes)//
.build();
}
private void postJournalEntries(final SavingsAccount savingsAccount, final List<Long> existingTransactionIds, private void postJournalEntries(final SavingsAccount savingsAccount, final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds) { final List<Long> existingReversedTransactionIds) {