MIFOSX-397: support apply of annual fees on savings account through manual and scheduled job approach.
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
INSERT INTO `m_permission`
|
||||||
|
(`grouping`,`code`,`entity_name`,`action_name`,`can_maker_checker`)
|
||||||
|
VALUES
|
||||||
|
('transaction_savings', 'APPLYANNUALFEE_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'APPLYANNUALFEE', 1),
|
||||||
|
('transaction_savings', 'APPLYANNUALFEE_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'APPLYANNUALFEE', 0);
|
||||||
@@ -466,6 +466,10 @@ public class CommandWrapper {
|
|||||||
return this.actionName.equalsIgnoreCase("POSTINTEREST") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
return this.actionName.equalsIgnoreCase("POSTINTEREST") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSavingsAccountApplyAnnualFee() {
|
||||||
|
return this.actionName.equalsIgnoreCase("APPLYANNUALFEE") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isSavingsAccountUndoTransaction() {
|
public boolean isSavingsAccountUndoTransaction() {
|
||||||
return this.actionName.equalsIgnoreCase("UNDOTRANSACTION") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
return this.actionName.equalsIgnoreCase("UNDOTRANSACTION") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-1
@@ -47,6 +47,11 @@ public class CommandWrapperBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CommandWrapperBuilder withNoJsonBody() {
|
||||||
|
this.json = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public CommandWrapperBuilder updateGlobalConfiguration() {
|
public CommandWrapperBuilder updateGlobalConfiguration() {
|
||||||
this.actionName = "UPDATE";
|
this.actionName = "UPDATE";
|
||||||
this.entityName = "CONFIGURATION";
|
this.entityName = "CONFIGURATION";
|
||||||
@@ -850,6 +855,15 @@ public class CommandWrapperBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CommandWrapperBuilder savingsAccountApplyAnnualFees(final Long accountId) {
|
||||||
|
this.actionName = "APPLYANNUALFEE";
|
||||||
|
this.entityName = "SAVINGSACCOUNT";
|
||||||
|
this.savingsId = accountId;
|
||||||
|
this.entityId = accountId;
|
||||||
|
this.href = "/savingsaccounts/" + accountId + "?command=applyAnnualFees";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public CommandWrapperBuilder createCalendar(final String supportedEntityType, final Long supportedEntityId) {
|
public CommandWrapperBuilder createCalendar(final String supportedEntityType, final Long supportedEntityId) {
|
||||||
this.actionName = "CREATE";
|
this.actionName = "CREATE";
|
||||||
this.entityName = "CALENDAR";
|
this.entityName = "CALENDAR";
|
||||||
@@ -1168,5 +1182,4 @@ public class CommandWrapperBuilder {
|
|||||||
this.href = "/updateJobDetail/" + jobId+"/updateJobDetail";
|
this.href = "/updateJobDetail/" + jobId+"/updateJobDetail";
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+2
@@ -401,6 +401,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
|||||||
handler = this.applicationContext.getBean("calculateInterestSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
handler = this.applicationContext.getBean("calculateInterestSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||||
} else if (wrapper.isSavingsAccountInterestPosting()) {
|
} else if (wrapper.isSavingsAccountInterestPosting()) {
|
||||||
handler = this.applicationContext.getBean("postInterestSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
handler = this.applicationContext.getBean("postInterestSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||||
|
} else if (wrapper.isSavingsAccountApplyAnnualFee()) {
|
||||||
|
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 {
|
} else {
|
||||||
|
|||||||
+7
-1
@@ -97,7 +97,13 @@ public class FromJsonHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public JsonElement parse(final String json) {
|
public JsonElement parse(final String json) {
|
||||||
return parser.parse(json);
|
|
||||||
|
JsonElement parsedElement = null;
|
||||||
|
if (StringUtils.isNotBlank(json)) {
|
||||||
|
parsedElement = parser.parse(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean parameterExists(final String parameterName, final JsonElement element) {
|
public boolean parameterExists(final String parameterName, final JsonElement element) {
|
||||||
|
|||||||
+1
@@ -29,6 +29,7 @@ public class SavingsApiConstants {
|
|||||||
public static String modifyApplicationAction = ".modify";
|
public static String modifyApplicationAction = ".modify";
|
||||||
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";
|
||||||
|
|
||||||
// general
|
// general
|
||||||
public static final String localeParamName = "locale";
|
public static final String localeParamName = "locale";
|
||||||
|
|||||||
+1
-1
@@ -120,7 +120,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 transaction(@PathParam("savingsId") final Long savingsId, @PathParam("transactionId") final Long transactionId,
|
public String undoTransaction(@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;
|
||||||
|
|||||||
+4
-2
@@ -164,7 +164,6 @@ public class SavingsAccountsApiResource {
|
|||||||
SavingsAccountData templateData = null;
|
SavingsAccountData templateData = null;
|
||||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||||
if (settings.isTemplate()) {
|
if (settings.isTemplate()) {
|
||||||
|
|
||||||
templateData = this.savingsAccountReadPlatformService.retrieveTemplate(savingsAccount.clientId(), savingsAccount.groupId(),
|
templateData = this.savingsAccountReadPlatformService.retrieveTemplate(savingsAccount.clientId(), savingsAccount.groupId(),
|
||||||
savingsAccount.productId(), staffInSelectedOfficeOnly);
|
savingsAccount.productId(), staffInSelectedOfficeOnly);
|
||||||
}
|
}
|
||||||
@@ -217,11 +216,14 @@ public class SavingsAccountsApiResource {
|
|||||||
final CommandWrapper commandRequest = builder.savingsAccountActivation(accountId).build();
|
final CommandWrapper commandRequest = builder.savingsAccountActivation(accountId).build();
|
||||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
} else if (is(commandParam, "calculateInterest")) {
|
} else if (is(commandParam, "calculateInterest")) {
|
||||||
final CommandWrapper commandRequest = builder.withJson(null).savingsAccountInterestCalculation(accountId).build();
|
final CommandWrapper commandRequest = builder.withNoJsonBody().savingsAccountInterestCalculation(accountId).build();
|
||||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
} else if (is(commandParam, "postInterest")) {
|
} else if (is(commandParam, "postInterest")) {
|
||||||
final CommandWrapper commandRequest = builder.savingsAccountInterestPosting(accountId).build();
|
final CommandWrapper commandRequest = builder.savingsAccountInterestPosting(accountId).build();
|
||||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
} else if (is(commandParam, "applyAnnualFees")) {
|
||||||
|
final CommandWrapper commandRequest = builder.savingsAccountApplyAnnualFees(accountId).build();
|
||||||
|
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
|
|||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* 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.data;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
|
||||||
|
public class SavingsAccountAnnualFeeData {
|
||||||
|
|
||||||
|
private final Long id;
|
||||||
|
private final String accountNo;
|
||||||
|
private final LocalDate nextAnnualFeeDueDate;
|
||||||
|
|
||||||
|
public static SavingsAccountAnnualFeeData instance(final Long id, final String accountNo, final LocalDate nextAnnualFeeDueDate) {
|
||||||
|
return new SavingsAccountAnnualFeeData(id, accountNo, nextAnnualFeeDueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SavingsAccountAnnualFeeData(final Long id, final String accountNo, final LocalDate nextAnnualFeeDueDate) {
|
||||||
|
this.id = id;
|
||||||
|
this.accountNo = accountNo;
|
||||||
|
this.nextAnnualFeeDueDate = nextAnnualFeeDueDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccountNo() {
|
||||||
|
return this.accountNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getNextAnnualFeeDueDate() {
|
||||||
|
return this.nextAnnualFeeDueDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
@@ -248,6 +248,10 @@ public class SavingsAccountData {
|
|||||||
this.withdrawalFeeTypeOptions = withdrawalFeeTypeOptions;
|
this.withdrawalFeeTypeOptions = withdrawalFeeTypeOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long id() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
public Long clientId() {
|
public Long clientId() {
|
||||||
return this.clientId;
|
return this.clientId;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -92,7 +92,7 @@ public class SavingsAccountDataValidator {
|
|||||||
|
|
||||||
if (fromApiJsonHelper.parameterExists(fieldOfficerIdParamName, element)) {
|
if (fromApiJsonHelper.parameterExists(fieldOfficerIdParamName, element)) {
|
||||||
final Long fieldOfficerId = fromApiJsonHelper.extractLongNamed(fieldOfficerIdParamName, element);
|
final Long fieldOfficerId = fromApiJsonHelper.extractLongNamed(fieldOfficerIdParamName, element);
|
||||||
baseDataValidator.reset().parameter(fieldOfficerIdParamName).value(fieldOfficerId).notNull().integerGreaterThanZero();
|
baseDataValidator.reset().parameter(fieldOfficerIdParamName).value(fieldOfficerId).ignoreIfNull().integerGreaterThanZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
final LocalDate submittedOnDate = fromApiJsonHelper.extractLocalDateNamed(submittedOnDateParamName, element);
|
final LocalDate submittedOnDate = fromApiJsonHelper.extractLocalDateNamed(submittedOnDateParamName, element);
|
||||||
@@ -276,7 +276,7 @@ public class SavingsAccountDataValidator {
|
|||||||
|
|
||||||
if (fromApiJsonHelper.parameterExists(fieldOfficerIdParamName, element)) {
|
if (fromApiJsonHelper.parameterExists(fieldOfficerIdParamName, element)) {
|
||||||
final Long fieldOfficerId = fromApiJsonHelper.extractLongNamed(fieldOfficerIdParamName, element);
|
final Long fieldOfficerId = fromApiJsonHelper.extractLongNamed(fieldOfficerIdParamName, element);
|
||||||
baseDataValidator.reset().parameter(fieldOfficerIdParamName).value(fieldOfficerId).notNull().integerGreaterThanZero();
|
baseDataValidator.reset().parameter(fieldOfficerIdParamName).value(fieldOfficerId).ignoreIfNull().integerGreaterThanZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fromApiJsonHelper.parameterExists(submittedOnDateParamName, element)) {
|
if (fromApiJsonHelper.parameterExists(submittedOnDateParamName, element)) {
|
||||||
|
|||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* 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.data;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immutable data object representing date
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class TransactionDateData {
|
||||||
|
|
||||||
|
private final LocalDate date;
|
||||||
|
|
||||||
|
public TransactionDateData(final LocalDate date) {
|
||||||
|
this.date = date;
|
||||||
|
}
|
||||||
|
}
|
||||||
+135
-71
@@ -230,7 +230,6 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
@Column(name = "annual_fee_on_day", nullable = true)
|
@Column(name = "annual_fee_on_day", nullable = true)
|
||||||
private Integer annualFeeOnDay;
|
private Integer annualFeeOnDay;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Temporal(TemporalType.DATE)
|
@Temporal(TemporalType.DATE)
|
||||||
@Column(name = "annual_fee_next_due_date", nullable = true)
|
@Column(name = "annual_fee_next_due_date", nullable = true)
|
||||||
private Date annualFeeNextDueDate;
|
private Date annualFeeNextDueDate;
|
||||||
@@ -311,22 +310,11 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
if (annualFeeOnMonthDay != null) {
|
if (annualFeeOnMonthDay != null) {
|
||||||
this.annualFeeOnMonth = annualFeeOnMonthDay.getMonthOfYear();
|
this.annualFeeOnMonth = annualFeeOnMonthDay.getMonthOfYear();
|
||||||
this.annualFeeOnDay = annualFeeOnMonthDay.getDayOfMonth();
|
this.annualFeeOnDay = annualFeeOnMonthDay.getDayOfMonth();
|
||||||
|
|
||||||
updateAnnualFeeNextDueDate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.summary = new SavingsAccountSummary();
|
this.summary = new SavingsAccountSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAnnualFeeNextDueDate() {
|
|
||||||
LocalDate nextDueLocalDate = new LocalDate().withMonthOfYear(this.annualFeeOnMonth).withDayOfMonth(this.annualFeeOnDay);
|
|
||||||
if (nextDueLocalDate.isBefore(DateUtils.getLocalDateOfTenant())) {
|
|
||||||
nextDueLocalDate = nextDueLocalDate.plusYears(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.annualFeeNextDueDate = nextDueLocalDate.toDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used after fetching/hydrating a {@link SavingsAccount} object to inject
|
* Used after fetching/hydrating a {@link SavingsAccount} object to inject
|
||||||
* helper services/components used for update summary details after
|
* helper services/components used for update summary details after
|
||||||
@@ -412,7 +400,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
SavingsAccountTransaction postingTransation = null;
|
SavingsAccountTransaction postingTransation = null;
|
||||||
|
|
||||||
for (SavingsAccountTransaction transaction : this.transactions) {
|
for (SavingsAccountTransaction transaction : this.transactions) {
|
||||||
if (transaction.isInterestPosting() && transaction.occursOn(postingDate)) {
|
if (transaction.isInterestPostingAndNotReversed() && transaction.occursOn(postingDate)) {
|
||||||
postingTransation = transaction;
|
postingTransation = transaction;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -492,7 +480,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
List<SavingsAccountTransaction> orderedNonInterestPostingTransactions = new ArrayList<SavingsAccountTransaction>();
|
List<SavingsAccountTransaction> orderedNonInterestPostingTransactions = new ArrayList<SavingsAccountTransaction>();
|
||||||
|
|
||||||
for (SavingsAccountTransaction transaction : listOfTransactionsSorted) {
|
for (SavingsAccountTransaction transaction : listOfTransactionsSorted) {
|
||||||
if (!transaction.isInterestPosting() && transaction.isNotReversed()) {
|
if (!transaction.isInterestPostingAndNotReversed() && transaction.isNotReversed()) {
|
||||||
orderedNonInterestPostingTransactions.add(transaction);
|
orderedNonInterestPostingTransactions.add(transaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -523,12 +511,10 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
transaction.zeroBalanceFields();
|
transaction.zeroBalanceFields();
|
||||||
} else {
|
} else {
|
||||||
Money transactionAmount = Money.zero(this.currency);
|
Money transactionAmount = Money.zero(this.currency);
|
||||||
if (transaction.isDeposit()) {
|
if (transaction.isCredit()) {
|
||||||
transactionAmount = transactionAmount.plus(transaction.getAmount(this.currency));
|
transactionAmount = transactionAmount.plus(transaction.getAmount(this.currency));
|
||||||
} else if (transaction.isWithdrawal()) {
|
} else if (transaction.isDebit()) {
|
||||||
transactionAmount = transactionAmount.minus(transaction.getAmount(this.currency));
|
transactionAmount = transactionAmount.minus(transaction.getAmount(this.currency));
|
||||||
} else if (transaction.isInterestPosting()) {
|
|
||||||
transactionAmount = transactionAmount.plus(transaction.getAmount(this.currency));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
runningBalance = runningBalance.plus(transactionAmount);
|
runningBalance = runningBalance.plus(transactionAmount);
|
||||||
@@ -705,7 +691,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
boolean transactionBeforeLastInterestPosting = false;
|
boolean transactionBeforeLastInterestPosting = false;
|
||||||
|
|
||||||
for (SavingsAccountTransaction transaction : retreiveListOfTransactions()) {
|
for (SavingsAccountTransaction transaction : retreiveListOfTransactions()) {
|
||||||
if (transaction.isNotReversed() && transaction.isInterestPosting() && transaction.isAfter(transactionDate)) {
|
if (transaction.isNotReversed() && transaction.isInterestPostingAndNotReversed() && transaction.isAfter(transactionDate)) {
|
||||||
transactionBeforeLastInterestPosting = true;
|
transactionBeforeLastInterestPosting = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -720,7 +706,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
Money runningBalance = Money.zero(this.currency);
|
Money runningBalance = Money.zero(this.currency);
|
||||||
|
|
||||||
for (SavingsAccountTransaction transaction : transactionsSortedByDate) {
|
for (SavingsAccountTransaction transaction : transactionsSortedByDate) {
|
||||||
if (transaction.isNotReversed() && transaction.isDeposit() || transaction.isInterestPosting()) {
|
if (transaction.isNotReversed() && transaction.isDeposit() || transaction.isInterestPostingAndNotReversed()) {
|
||||||
runningBalance = runningBalance.plus(transaction.getAmount(this.currency));
|
runningBalance = runningBalance.plus(transaction.getAmount(this.currency));
|
||||||
} else if (transaction.isNotReversed() && transaction.isWithdrawal()) {
|
} else if (transaction.isNotReversed() && transaction.isWithdrawal()) {
|
||||||
runningBalance = runningBalance.minus(transaction.getAmount(this.currency));
|
runningBalance = runningBalance.minus(transaction.getAmount(this.currency));
|
||||||
@@ -740,7 +726,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
Money runningBalance = Money.zero(this.currency);
|
Money runningBalance = Money.zero(this.currency);
|
||||||
|
|
||||||
for (SavingsAccountTransaction transaction : transactionsSortedByDate) {
|
for (SavingsAccountTransaction transaction : transactionsSortedByDate) {
|
||||||
if (transaction.isNotReversed() && transaction.isDeposit() || transaction.isInterestPosting()) {
|
if (transaction.isNotReversed() && transaction.isDeposit() || transaction.isInterestPostingAndNotReversed()) {
|
||||||
runningBalance = runningBalance.plus(transaction.getAmount(this.currency));
|
runningBalance = runningBalance.plus(transaction.getAmount(this.currency));
|
||||||
} else if (transaction.isNotReversed() && transaction.isWithdrawal()) {
|
} else if (transaction.isNotReversed() && transaction.isWithdrawal()) {
|
||||||
runningBalance = runningBalance.minus(transaction.getAmount(this.currency));
|
runningBalance = runningBalance.minus(transaction.getAmount(this.currency));
|
||||||
@@ -759,54 +745,51 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SavingsAccountTransaction addAnnualFee(final MathContext mc, final DateTimeFormatter formatter, final LocalDate transactionDate,
|
public SavingsAccountTransaction addAnnualFee(final MathContext mc, final DateTimeFormatter formatter,
|
||||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
final LocalDate annualFeeTransactionDate, final LocalDate today, final List<Long> existingTransactionIds,
|
||||||
|
final List<Long> existingReversedTransactionIds) {
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||||
|
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.applyAnnualFeeTransactionAction);
|
||||||
|
|
||||||
if (isNotActive()) {
|
if (isNotActive()) {
|
||||||
|
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.not.active");
|
||||||
|
|
||||||
final String defaultUserMessage = "Transaction is not allowed. Account is not active.";
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
final ApiParameterError error = ApiParameterError.parameterError("error.msg.savingsaccount.transaction.account.is.not.active",
|
}
|
||||||
defaultUserMessage, "transactionDate", transactionDate.toString(formatter));
|
|
||||||
|
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
LocalDate nextAnnualFeeDueDate = getNextAnnualFeeDueDate();
|
||||||
dataValidationErrors.add(error);
|
if (nextAnnualFeeDueDate == null || annualFeeSettingsNotSet()) {
|
||||||
|
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("no.annualfee.settings");
|
||||||
|
|
||||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDateInTheFuture(transactionDate)) {
|
if (nextAnnualFeeDueDate.isBefore(getActivationLocalDate())) {
|
||||||
final String defaultUserMessage = "Transaction date cannot be in the future.";
|
|
||||||
final ApiParameterError error = ApiParameterError.parameterError("error.msg.savingsaccount.transaction.in.the.future",
|
|
||||||
defaultUserMessage, "transactionDate", transactionDate.toString(formatter));
|
|
||||||
|
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
baseDataValidator.reset().parameter("annualFeeTransactionDate").value(getActivationLocalDate().toString(formatter))
|
||||||
dataValidationErrors.add(error);
|
.failWithCodeNoParameterAddedToErrorCode("before.activationDate");
|
||||||
|
|
||||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transactionDate.isBefore(getActivationLocalDate())) {
|
if (isDateInTheFuture(annualFeeTransactionDate)) {
|
||||||
final Object[] defaultUserArgs = Arrays.asList(transactionDate.toString(formatter),
|
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.in.the.future");
|
||||||
getActivationLocalDate().toString(formatter)).toArray();
|
|
||||||
final String defaultUserMessage = "Transaction date cannot be before accounts activation date.";
|
|
||||||
final ApiParameterError error = ApiParameterError.parameterError("error.msg.savingsaccount.transaction.before.activation.date",
|
|
||||||
defaultUserMessage, "transactionDate", defaultUserArgs);
|
|
||||||
|
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
|
||||||
dataValidationErrors.add(error);
|
|
||||||
|
|
||||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAccountLocked(transactionDate)) {
|
if (isNotValidAnnualFeeTransactionDate(annualFeeTransactionDate, today)) {
|
||||||
final String defaultUserMessage = "Withdrawal is not allowed. No withdrawals are allowed until after "
|
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("invalid.date");
|
||||||
+ getLockedInUntilLocalDate().toString(formatter);
|
|
||||||
final ApiParameterError error = ApiParameterError.parameterError(
|
|
||||||
"error.msg.savingsaccount.transaction.withdrawals.blocked.during.lockin.period", defaultUserMessage, "transactionDate",
|
|
||||||
transactionDate.toString(formatter), getLockedInUntilLocalDate().toString(formatter));
|
|
||||||
|
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
dataValidationErrors.add(error);
|
}
|
||||||
|
|
||||||
|
Date currentAnnualFeeNextDueDate = findLatestAnnualFeeTransactionDueDate();
|
||||||
|
if (currentAnnualFeeNextDueDate != null && new LocalDate(currentAnnualFeeNextDueDate).isEqual(annualFeeTransactionDate)) {
|
||||||
|
baseDataValidator.reset().parameter("annualFeeTransactionDate").value(annualFeeTransactionDate.toString(formatter))
|
||||||
|
.failWithCodeNoParameterAddedToErrorCode("transaction.exists.on.date");
|
||||||
|
|
||||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
}
|
}
|
||||||
@@ -815,19 +798,67 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||||
|
|
||||||
final Money annualFee = Money.of(this.currency, this.annualFeeAmount);
|
final Money annualFee = Money.of(this.currency, this.annualFeeAmount);
|
||||||
SavingsAccountTransaction annualFeeTransaction = SavingsAccountTransaction.annualFee(this, transactionDate, annualFee);
|
SavingsAccountTransaction annualFeeTransaction = SavingsAccountTransaction.annualFee(this, annualFeeTransactionDate, annualFee);
|
||||||
this.transactions.add(annualFeeTransaction);
|
this.transactions.add(annualFeeTransaction);
|
||||||
|
|
||||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||||
|
|
||||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
|
||||||
calculateInterestUsing(mc, today);
|
calculateInterestUsing(mc, today);
|
||||||
|
|
||||||
updateAnnualFeeNextDueDate();
|
currentAnnualFeeNextDueDate = findLatestAnnualFeeTransactionDueDate();
|
||||||
|
if (currentAnnualFeeNextDueDate != null) {
|
||||||
|
LocalDate newAnnualFeeNextDueDate = new LocalDate(currentAnnualFeeNextDueDate).withMonthOfYear(this.annualFeeOnMonth)
|
||||||
|
.withDayOfMonth(this.annualFeeOnDay).plusYears(1);
|
||||||
|
this.annualFeeNextDueDate = newAnnualFeeNextDueDate.toDate();
|
||||||
|
} else {
|
||||||
|
updateToNextAnnualFeeDueDateFrom(getActivationLocalDate());
|
||||||
|
}
|
||||||
|
|
||||||
return annualFeeTransaction;
|
return annualFeeTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isNotValidAnnualFeeTransactionDate(final LocalDate annualFeeTransactionDate, final LocalDate today) {
|
||||||
|
return !isValidAnnualFeeTransactionDate(annualFeeTransactionDate, today);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidAnnualFeeTransactionDate(final LocalDate annualFeeTransactionDate, final LocalDate today) {
|
||||||
|
|
||||||
|
LocalDate startingDate = getActivationLocalDate();
|
||||||
|
boolean isValid = false;
|
||||||
|
while (!startingDate.isAfter(today) && !isValid) {
|
||||||
|
LocalDate nextDueLocalDate = startingDate.withMonthOfYear(this.annualFeeOnMonth).withDayOfMonth(this.annualFeeOnDay);
|
||||||
|
if (startingDate.isAfter(nextDueLocalDate)) {
|
||||||
|
nextDueLocalDate = nextDueLocalDate.plusYears(1);
|
||||||
|
}
|
||||||
|
isValid = nextDueLocalDate.isEqual(annualFeeTransactionDate);
|
||||||
|
|
||||||
|
startingDate = nextDueLocalDate.plusYears(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateToNextAnnualFeeDueDateFrom(final LocalDate startingDate) {
|
||||||
|
LocalDate nextDueLocalDate = startingDate.withMonthOfYear(this.annualFeeOnMonth).withDayOfMonth(this.annualFeeOnDay);
|
||||||
|
this.annualFeeNextDueDate = nextDueLocalDate.toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocalDate getNextAnnualFeeDueDate() {
|
||||||
|
LocalDate nextAnnualFeeDueDate = null;
|
||||||
|
if (this.annualFeeNextDueDate != null) {
|
||||||
|
nextAnnualFeeDueDate = new LocalDate(this.annualFeeNextDueDate);
|
||||||
|
}
|
||||||
|
return nextAnnualFeeDueDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean annualFeeSettingsNotSet() {
|
||||||
|
return !annualFeeSettingsSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean annualFeeSettingsSet() {
|
||||||
|
return this.annualFeeOnDay != null && this.annualFeeOnMonth != null;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isAutomaticWithdrawalFee() {
|
private boolean isAutomaticWithdrawalFee() {
|
||||||
return this.withdrawalFeeType != null;
|
return this.withdrawalFeeType != null;
|
||||||
}
|
}
|
||||||
@@ -1004,22 +1035,22 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
this.annualFeeAmount = newValue;
|
this.annualFeeAmount = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.isChangeInIntegerParameterNamedDefaultingZeroToNull(annualFeeOnMonthDayParamName, this.annualFeeOnDay)) {
|
if (command.hasParameter(annualFeeOnMonthDayParamName)) {
|
||||||
final MonthDay monthDay = command.extractMonthDayNamed(annualFeeOnMonthDayParamName);
|
final MonthDay monthDay = command.extractMonthDayNamed(annualFeeOnMonthDayParamName);
|
||||||
final String actualValueEntered = command.stringValueOfParameterNamed(annualFeeOnMonthDayParamName);
|
final String actualValueEntered = command.stringValueOfParameterNamed(annualFeeOnMonthDayParamName);
|
||||||
final Integer newValue = monthDay.getDayOfMonth();
|
final Integer dayOfMonthValue = monthDay.getDayOfMonth();
|
||||||
actualChanges.put(annualFeeOnMonthDayParamName, actualValueEntered);
|
if (this.annualFeeOnDay != dayOfMonthValue) {
|
||||||
actualChanges.put(localeParamName, localeAsInput);
|
actualChanges.put(annualFeeOnMonthDayParamName, actualValueEntered);
|
||||||
this.annualFeeOnDay = newValue;
|
actualChanges.put(localeParamName, localeAsInput);
|
||||||
}
|
this.annualFeeOnDay = dayOfMonthValue;
|
||||||
|
}
|
||||||
|
|
||||||
if (command.isChangeInIntegerParameterNamedDefaultingZeroToNull(annualFeeOnMonthDayParamName, this.annualFeeOnMonth)) {
|
final Integer monthOfYear = monthDay.getMonthOfYear();
|
||||||
final MonthDay monthDay = command.extractMonthDayNamed(annualFeeOnMonthDayParamName);
|
if (this.annualFeeOnMonth != monthOfYear) {
|
||||||
final String actualValueEntered = command.stringValueOfParameterNamed(annualFeeOnMonthDayParamName);
|
actualChanges.put(annualFeeOnMonthDayParamName, actualValueEntered);
|
||||||
final Integer newValue = monthDay.getMonthOfYear();
|
actualChanges.put(localeParamName, localeAsInput);
|
||||||
actualChanges.put(annualFeeOnMonthDayParamName, actualValueEntered);
|
this.annualFeeOnMonth = monthOfYear;
|
||||||
actualChanges.put(localeParamName, localeAsInput);
|
}
|
||||||
this.annualFeeOnMonth = newValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set period type to null if frequency is null
|
// set period type to null if frequency is null
|
||||||
@@ -1028,10 +1059,6 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
this.annualFeeOnMonth = null;
|
this.annualFeeOnMonth = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.annualFeeOnDay != null && this.annualFeeOnMonth != null) {
|
|
||||||
updateAnnualFeeNextDueDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
validateLockinDetails();
|
validateLockinDetails();
|
||||||
validateWithdrawalFeeDetails();
|
validateWithdrawalFeeDetails();
|
||||||
validateAnnualFeeDetails();
|
validateAnnualFeeDetails();
|
||||||
@@ -1388,12 +1415,45 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
transactionToUndo.reverse();
|
transactionToUndo.reverse();
|
||||||
reversedTransactionIds.add(transactionId);
|
reversedTransactionIds.add(transactionId);
|
||||||
|
|
||||||
|
if (transactionToUndo.isAnnualFee()) {
|
||||||
|
this.annualFeeNextDueDate = findLatestAnnualFeeTransactionDueDate();
|
||||||
|
if (this.annualFeeNextDueDate == null) {
|
||||||
|
updateToNextAnnualFeeDueDateFrom(getActivationLocalDate());
|
||||||
|
} else {
|
||||||
|
LocalDate newAnnualFeeNextDueDate = new LocalDate(this.annualFeeNextDueDate).withMonthOfYear(this.annualFeeOnMonth)
|
||||||
|
.withDayOfMonth(this.annualFeeOnDay).plusYears(1);
|
||||||
|
this.annualFeeNextDueDate = newAnnualFeeNextDueDate.toDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
calculateInterestUsing(mc, upToInterestCalculationDate);
|
calculateInterestUsing(mc, upToInterestCalculationDate);
|
||||||
|
|
||||||
validateAccountBalanceDoesNotBecomeNegativeDueToUndoAction(retreiveListOfTransactions());
|
validateAccountBalanceDoesNotBecomeNegativeDueToUndoAction(retreiveListOfTransactions());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Date findLatestAnnualFeeTransactionDueDate() {
|
||||||
|
|
||||||
|
Date nextDueDate = null;
|
||||||
|
|
||||||
|
LocalDate lastAnnualFeeTransactionDate = null;
|
||||||
|
for (SavingsAccountTransaction transaction : retreiveOrderedListOfTransactions()) {
|
||||||
|
if (transaction.isAnnualFeeAndNotReversed()) {
|
||||||
|
if (lastAnnualFeeTransactionDate == null) {
|
||||||
|
lastAnnualFeeTransactionDate = transaction.transactionLocalDate();
|
||||||
|
nextDueDate = lastAnnualFeeTransactionDate.toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transaction.transactionLocalDate().isAfter(lastAnnualFeeTransactionDate)) {
|
||||||
|
lastAnnualFeeTransactionDate = transaction.transactionLocalDate();
|
||||||
|
nextDueDate = lastAnnualFeeTransactionDate.toDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextDueDate;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, Object> rejectApplication(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate) {
|
public Map<String, Object> rejectApplication(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate) {
|
||||||
|
|
||||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||||
@@ -1548,6 +1608,10 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
this.activatedBy = currentUser;
|
this.activatedBy = currentUser;
|
||||||
this.lockedInUntilDate = calculateDateAccountIsLockedUntil(getActivationLocalDate());
|
this.lockedInUntilDate = calculateDateAccountIsLockedUntil(getActivationLocalDate());
|
||||||
|
|
||||||
|
if (annualFeeSettingsSet()) {
|
||||||
|
updateToNextAnnualFeeDueDateFrom(getActivationLocalDate());
|
||||||
|
}
|
||||||
|
|
||||||
if (this.client.isActivatedAfter(activationDate)) {
|
if (this.client.isActivatedAfter(activationDate)) {
|
||||||
|
|
||||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern(command.dateFormat()).withLocale(command.extractLocale());
|
final DateTimeFormatter formatter = DateTimeFormat.forPattern(command.dateFormat()).withLocale(command.extractLocale());
|
||||||
|
|||||||
+18
-6
@@ -146,16 +146,20 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isWithdrawal();
|
return SavingsAccountTransactionType.fromInt(this.typeOf).isWithdrawal();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInterestPosting() {
|
public boolean isInterestPostingAndNotReversed() {
|
||||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isInterestPosting() && isNotReversed();
|
return SavingsAccountTransactionType.fromInt(this.typeOf).isInterestPosting() && isNotReversed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isWithdrawalFee() {
|
public boolean isWithdrawalFeeAndNotReversed() {
|
||||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isWithdrawalFee() && isNotReversed();
|
return SavingsAccountTransactionType.fromInt(this.typeOf).isWithdrawalFee() && isNotReversed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAnnualFeeAndNotReversed() {
|
||||||
|
return isAnnualFee() && isNotReversed();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isAnnualFee() {
|
public boolean isAnnualFee() {
|
||||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isAnnualFee() && isNotReversed();
|
return SavingsAccountTransactionType.fromInt(this.typeOf).isAnnualFee();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNotReversed() {
|
public boolean isNotReversed() {
|
||||||
@@ -258,7 +262,7 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
Money endOfDayBalance = openingBalance.copy();
|
Money endOfDayBalance = openingBalance.copy();
|
||||||
if (isDeposit()) {
|
if (isDeposit()) {
|
||||||
endOfDayBalance = openingBalance.plus(getAmount(currency));
|
endOfDayBalance = openingBalance.plus(getAmount(currency));
|
||||||
} else if (isWithdrawal() || isWithdrawalFee()) {
|
} else if (isWithdrawal() || isWithdrawalFeeAndNotReversed()) {
|
||||||
endOfDayBalance = openingBalance.minus(getAmount(currency));
|
endOfDayBalance = openingBalance.minus(getAmount(currency));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,7 +278,7 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
Money endOfDayBalance = openingBalance.copy();
|
Money endOfDayBalance = openingBalance.copy();
|
||||||
if (isDeposit()) {
|
if (isDeposit()) {
|
||||||
endOfDayBalance = openingBalance.plus(getAmount(currency));
|
endOfDayBalance = openingBalance.plus(getAmount(currency));
|
||||||
} else if (isWithdrawal() || isWithdrawalFee()) {
|
} else if (isWithdrawal() || isWithdrawalFeeAndNotReversed()) {
|
||||||
endOfDayBalance = openingBalance.minus(getAmount(currency));
|
endOfDayBalance = openingBalance.minus(getAmount(currency));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,7 +302,7 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
} else {
|
} else {
|
||||||
if (isDeposit()) {
|
if (isDeposit()) {
|
||||||
endOfDayBalance = openingBalance.plus(getAmount(currency));
|
endOfDayBalance = openingBalance.plus(getAmount(currency));
|
||||||
} else if (isWithdrawal() || isWithdrawalFee()) {
|
} else if (isWithdrawal() || isWithdrawalFeeAndNotReversed()) {
|
||||||
endOfDayBalance = openingBalance.minus(getAmount(currency));
|
endOfDayBalance = openingBalance.minus(getAmount(currency));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,4 +333,12 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
public boolean isIdentifiedBy(final Long transactionId) {
|
public boolean isIdentifiedBy(final Long transactionId) {
|
||||||
return this.getId().equals(transactionId);
|
return this.getId().equals(transactionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCredit() {
|
||||||
|
return isDeposit() || isInterestPostingAndNotReversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDebit() {
|
||||||
|
return isWithdrawal() || isWithdrawalFeeAndNotReversed() || isAnnualFeeAndNotReversed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -19,9 +19,9 @@ public class SavingsAccountTransactionComparator implements Comparator<SavingsAc
|
|||||||
final int comparsion = o1.transactionLocalDate().compareTo(o2.transactionLocalDate());
|
final int comparsion = o1.transactionLocalDate().compareTo(o2.transactionLocalDate());
|
||||||
if (comparsion == 0) {
|
if (comparsion == 0) {
|
||||||
// equal transaction dates
|
// equal transaction dates
|
||||||
if (o1.isInterestPosting() && !o2.isInterestPosting()) {
|
if (o1.isInterestPostingAndNotReversed() && !o2.isInterestPostingAndNotReversed()) {
|
||||||
compareResult = -1;
|
compareResult = -1;
|
||||||
} else if (!o1.isInterestPosting() && o2.isInterestPosting()) {
|
} else if (!o1.isInterestPostingAndNotReversed() && o2.isInterestPostingAndNotReversed()) {
|
||||||
compareResult = 1;
|
compareResult = 1;
|
||||||
} else {
|
} else {
|
||||||
compareResult = 0;
|
compareResult = 0;
|
||||||
|
|||||||
+3
-3
@@ -42,7 +42,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
|||||||
public BigDecimal calculateTotalInterestPosted(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
public BigDecimal calculateTotalInterestPosted(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||||
Money total = Money.zero(currency);
|
Money total = Money.zero(currency);
|
||||||
for (SavingsAccountTransaction transaction : transactions) {
|
for (SavingsAccountTransaction transaction : transactions) {
|
||||||
if (transaction.isInterestPosting() && transaction.isNotReversed()) {
|
if (transaction.isInterestPostingAndNotReversed() && transaction.isNotReversed()) {
|
||||||
total = total.plus(transaction.getAmount(currency));
|
total = total.plus(transaction.getAmount(currency));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
|||||||
public BigDecimal calculateTotalWithdrawalFees(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
public BigDecimal calculateTotalWithdrawalFees(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||||
Money total = Money.zero(currency);
|
Money total = Money.zero(currency);
|
||||||
for (SavingsAccountTransaction transaction : transactions) {
|
for (SavingsAccountTransaction transaction : transactions) {
|
||||||
if (transaction.isWithdrawalFee() && transaction.isNotReversed()) {
|
if (transaction.isWithdrawalFeeAndNotReversed() && transaction.isNotReversed()) {
|
||||||
total = total.plus(transaction.getAmount(currency));
|
total = total.plus(transaction.getAmount(currency));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
|||||||
public BigDecimal calculateTotalAnnualFees(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
public BigDecimal calculateTotalAnnualFees(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||||
Money total = Money.zero(currency);
|
Money total = Money.zero(currency);
|
||||||
for (SavingsAccountTransaction transaction : transactions) {
|
for (SavingsAccountTransaction transaction : transactions) {
|
||||||
if (transaction.isAnnualFee() && transaction.isNotReversed()) {
|
if (transaction.isAnnualFeeAndNotReversed() && transaction.isNotReversed()) {
|
||||||
total = total.plus(transaction.getAmount(currency));
|
total = total.plus(transaction.getAmount(currency));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* 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.joda.time.LocalDate;
|
||||||
|
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 ApplyAnnualFeeSavingsAccountCommandHandler implements NewCommandSourceHandler {
|
||||||
|
|
||||||
|
private final SavingsAccountWritePlatformService writePlatformService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public ApplyAnnualFeeSavingsAccountCommandHandler(final SavingsAccountWritePlatformService writePlatformService) {
|
||||||
|
this.writePlatformService = writePlatformService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
|
|
||||||
|
LocalDate annualFeeTransactionDate = command.localDateValueOfParameterNamed("annualFeeTransactionDate");
|
||||||
|
|
||||||
|
return this.writePlatformService.applyAnnualFee(command.getSavingsId(), annualFeeTransactionDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
@@ -9,6 +9,7 @@ import java.util.Collection;
|
|||||||
|
|
||||||
import org.mifosplatform.infrastructure.core.service.Page;
|
import org.mifosplatform.infrastructure.core.service.Page;
|
||||||
import org.mifosplatform.portfolio.group.service.SearchParameters;
|
import org.mifosplatform.portfolio.group.service.SearchParameters;
|
||||||
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountAnnualFeeData;
|
||||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
|
||||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData;
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData;
|
||||||
|
|
||||||
@@ -23,4 +24,6 @@ public interface SavingsAccountReadPlatformService {
|
|||||||
SavingsAccountTransactionData retrieveDepositTransactionTemplate(Long savingsId);
|
SavingsAccountTransactionData retrieveDepositTransactionTemplate(Long savingsId);
|
||||||
|
|
||||||
Collection<SavingsAccountTransactionData> retrieveAllTransactions(Long savingsId);
|
Collection<SavingsAccountTransactionData> retrieveAllTransactions(Long savingsId);
|
||||||
|
|
||||||
|
Collection<SavingsAccountAnnualFeeData> retrieveAccountsWithAnnualFeeDue();
|
||||||
}
|
}
|
||||||
+45
-3
@@ -37,6 +37,7 @@ import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearT
|
|||||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||||
import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType;
|
import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType;
|
||||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||||
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountAnnualFeeData;
|
||||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountApplicationTimelineData;
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountApplicationTimelineData;
|
||||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
|
||||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountStatusEnumData;
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountStatusEnumData;
|
||||||
@@ -63,11 +64,16 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
|||||||
private final SavingsProductReadPlatformService savingsProductReadPlatformService;
|
private final SavingsProductReadPlatformService savingsProductReadPlatformService;
|
||||||
private final StaffReadPlatformService staffReadPlatformService;
|
private final StaffReadPlatformService staffReadPlatformService;
|
||||||
private final SavingsDropdownReadPlatformService dropdownReadPlatformService;
|
private final SavingsDropdownReadPlatformService dropdownReadPlatformService;
|
||||||
|
|
||||||
|
// mappers
|
||||||
private final SavingsAccountTransactionTemplateMapper transactionTemplateMapper;
|
private final SavingsAccountTransactionTemplateMapper transactionTemplateMapper;
|
||||||
private final SavingsAccountTransactionsMapper transactionsMapper;
|
private final SavingsAccountTransactionsMapper transactionsMapper;
|
||||||
|
private final SavingAccountMapper savingAccountMapper;
|
||||||
|
private final SavingsAccountAnnualFeeMapper annualFeeMapper;
|
||||||
|
|
||||||
|
// pagination
|
||||||
private final PaginationHelper<SavingsAccountData> paginationHelper = new PaginationHelper<SavingsAccountData>();
|
private final PaginationHelper<SavingsAccountData> paginationHelper = new PaginationHelper<SavingsAccountData>();
|
||||||
private final SavingAccountMapper savingAccountMapper = new SavingAccountMapper();
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public SavingsAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
|
public SavingsAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
|
||||||
@@ -83,6 +89,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
|||||||
this.dropdownReadPlatformService = dropdownReadPlatformService;
|
this.dropdownReadPlatformService = dropdownReadPlatformService;
|
||||||
this.transactionTemplateMapper = new SavingsAccountTransactionTemplateMapper();
|
this.transactionTemplateMapper = new SavingsAccountTransactionTemplateMapper();
|
||||||
this.transactionsMapper = new SavingsAccountTransactionsMapper();
|
this.transactionsMapper = new SavingsAccountTransactionsMapper();
|
||||||
|
this.savingAccountMapper = new SavingAccountMapper();
|
||||||
|
this.annualFeeMapper = new SavingsAccountAnnualFeeMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -476,8 +484,6 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
|||||||
public SavingsAccountTransactionData retrieveDepositTransactionTemplate(final Long savingsId) {
|
public SavingsAccountTransactionData retrieveDepositTransactionTemplate(final Long savingsId) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.context.authenticatedUser();
|
|
||||||
|
|
||||||
final String sql = "select " + transactionTemplateMapper.schema() + " where sa.id = ?";
|
final String sql = "select " + transactionTemplateMapper.schema() + " where sa.id = ?";
|
||||||
|
|
||||||
return this.jdbcTemplate.queryForObject(sql, transactionTemplateMapper, new Object[] { savingsId });
|
return this.jdbcTemplate.queryForObject(sql, transactionTemplateMapper, new Object[] { savingsId });
|
||||||
@@ -494,6 +500,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 Collection<SavingsAccountAnnualFeeData> retrieveAccountsWithAnnualFeeDue() {
|
||||||
|
final String sql = "select " + annualFeeMapper.schema()
|
||||||
|
+ " where sa.annual_fee_next_due_date not null and sa.annual_fee_next_due_date <= NOW()";
|
||||||
|
|
||||||
|
return this.jdbcTemplate.query(sql, this.annualFeeMapper, new Object[] {});
|
||||||
|
}
|
||||||
|
|
||||||
private static final class SavingsAccountTransactionsMapper implements RowMapper<SavingsAccountTransactionData> {
|
private static final class SavingsAccountTransactionsMapper implements RowMapper<SavingsAccountTransactionData> {
|
||||||
|
|
||||||
private final String schemaSql;
|
private final String schemaSql;
|
||||||
@@ -731,4 +745,32 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
|||||||
annualFeeOnMonthDay, annualFeeNextDueDate, summary);
|
annualFeeOnMonthDay, annualFeeNextDueDate, summary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class SavingsAccountAnnualFeeMapper implements RowMapper<SavingsAccountAnnualFeeData> {
|
||||||
|
|
||||||
|
private final String schemaSql;
|
||||||
|
|
||||||
|
public SavingsAccountAnnualFeeMapper() {
|
||||||
|
final StringBuilder sqlBuilder = new StringBuilder(200);
|
||||||
|
sqlBuilder.append("sa.id as id, sa.account_no as accountNo, ");
|
||||||
|
sqlBuilder.append("sa.annual_fee_next_due_date as annualFeeNextDueDate, ");
|
||||||
|
sqlBuilder.append("from m_savings_account sa ");
|
||||||
|
|
||||||
|
this.schemaSql = sqlBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String schema() {
|
||||||
|
return this.schemaSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SavingsAccountAnnualFeeData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||||
|
|
||||||
|
final Long id = rs.getLong("id");
|
||||||
|
final String accountNo = rs.getString("accountNo");
|
||||||
|
final LocalDate annualFeeNextDueDate = JdbcSupport.getLocalDate(rs, "annualFeeNextDueDate");
|
||||||
|
|
||||||
|
return SavingsAccountAnnualFeeData.instance(id, accountNo, annualFeeNextDueDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+2
-1
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.mifosplatform.portfolio.savings.service;
|
package org.mifosplatform.portfolio.savings.service;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
|
||||||
@@ -16,7 +17,7 @@ public interface SavingsAccountWritePlatformService {
|
|||||||
|
|
||||||
CommandProcessingResult withdrawal(Long savingsId, JsonCommand command);
|
CommandProcessingResult withdrawal(Long savingsId, JsonCommand command);
|
||||||
|
|
||||||
CommandProcessingResult applyAnnualFee(Long savingsId);
|
CommandProcessingResult applyAnnualFee(Long savingsId, LocalDate annualFeeTransactionDate);
|
||||||
|
|
||||||
CommandProcessingResult calculateInterest(Long savingsId);
|
CommandProcessingResult calculateInterest(Long savingsId);
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -205,20 +205,20 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult applyAnnualFee(final Long savingsId) {
|
public CommandProcessingResult applyAnnualFee(final Long savingsId, final LocalDate annualFeeTransactionDate) {
|
||||||
|
|
||||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||||
|
|
||||||
final LocalDate transactionDate = LocalDate.now();
|
|
||||||
|
|
||||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy");
|
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy");
|
||||||
|
|
||||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||||
|
|
||||||
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
|
final MathContext mc = MathContext.DECIMAL64;
|
||||||
final SavingsAccountTransaction annualFee = account.addAnnualFee(mc, fmt, transactionDate,
|
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||||
existingTransactionIds, existingReversedTransactionIds);
|
|
||||||
|
final SavingsAccountTransaction annualFee = account.addAnnualFee(mc, fmt, annualFeeTransactionDate, today, existingTransactionIds,
|
||||||
|
existingReversedTransactionIds);
|
||||||
final Long transactionId = saveTransactionToGenerateTransactionId(annualFee);
|
final Long transactionId = saveTransactionToGenerateTransactionId(annualFee);
|
||||||
this.savingAccountRepository.save(account);
|
this.savingAccountRepository.save(account);
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -209,8 +209,12 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
|
|
||||||
if (changes.containsKey(SavingsApiConstants.fieldOfficerIdParamName)) {
|
if (changes.containsKey(SavingsApiConstants.fieldOfficerIdParamName)) {
|
||||||
final Long fieldOfficerId = command.longValueOfParameterNamed(SavingsApiConstants.fieldOfficerIdParamName);
|
final Long fieldOfficerId = command.longValueOfParameterNamed(SavingsApiConstants.fieldOfficerIdParamName);
|
||||||
final Staff fieldOfficer = this.staffRepository.findOneWithNotFoundDetection(fieldOfficerId);
|
Staff fieldOfficer = null;
|
||||||
|
if (fieldOfficerId != null) {
|
||||||
|
fieldOfficer = this.staffRepository.findOneWithNotFoundDetection(fieldOfficerId);
|
||||||
|
} else {
|
||||||
|
changes.put(SavingsApiConstants.fieldOfficerIdParamName, "");
|
||||||
|
}
|
||||||
account.update(fieldOfficer);
|
account.update(fieldOfficer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-10
@@ -5,12 +5,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.mifosplatform.scheduledjobs.service;
|
package org.mifosplatform.scheduledjobs.service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSourceServiceFactory;
|
import org.mifosplatform.infrastructure.core.service.RoutingDataSourceServiceFactory;
|
||||||
import org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil;
|
import org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
|
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
|
||||||
import org.mifosplatform.infrastructure.jobs.service.JobName;
|
import org.mifosplatform.infrastructure.jobs.service.JobName;
|
||||||
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountAnnualFeeData;
|
||||||
|
import org.mifosplatform.portfolio.savings.service.SavingsAccountReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.savings.service.SavingsAccountWritePlatformService;
|
import org.mifosplatform.portfolio.savings.service.SavingsAccountWritePlatformService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -23,14 +25,18 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService {
|
public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService {
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(ScheduledJobRunnerServiceImpl.class);
|
private final static Logger logger = LoggerFactory.getLogger(ScheduledJobRunnerServiceImpl.class);
|
||||||
|
|
||||||
private final RoutingDataSourceServiceFactory dataSourceServiceFactory;
|
private final RoutingDataSourceServiceFactory dataSourceServiceFactory;
|
||||||
private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
|
private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
|
||||||
|
private final SavingsAccountReadPlatformService savingsAccountReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ScheduledJobRunnerServiceImpl(final RoutingDataSourceServiceFactory dataSourceServiceFactory,
|
public ScheduledJobRunnerServiceImpl(final RoutingDataSourceServiceFactory dataSourceServiceFactory,
|
||||||
final SavingsAccountWritePlatformService savingsAccountWritePlatformService) {
|
final SavingsAccountWritePlatformService savingsAccountWritePlatformService,
|
||||||
|
final SavingsAccountReadPlatformService savingsAccountReadPlatformService) {
|
||||||
this.dataSourceServiceFactory = dataSourceServiceFactory;
|
this.dataSourceServiceFactory = dataSourceServiceFactory;
|
||||||
this.savingsAccountWritePlatformService = savingsAccountWritePlatformService;
|
this.savingsAccountWritePlatformService = savingsAccountWritePlatformService;
|
||||||
|
this.savingsAccountReadPlatformService = savingsAccountReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -193,16 +199,15 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
|||||||
@Override
|
@Override
|
||||||
@CronTarget(jobName = JobName.APPLY_ANNUAL_FEE_FOR_SAVINGS)
|
@CronTarget(jobName = JobName.APPLY_ANNUAL_FEE_FOR_SAVINGS)
|
||||||
public void applyAnnualFeeForSavings() {
|
public void applyAnnualFeeForSavings() {
|
||||||
|
|
||||||
|
final Collection<SavingsAccountAnnualFeeData> annualFeeData = this.savingsAccountReadPlatformService
|
||||||
|
.retrieveAccountsWithAnnualFeeDue();
|
||||||
|
|
||||||
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceServiceFactory.determineDataSourceService().retrieveDataSource());
|
for (SavingsAccountAnnualFeeData savingsAccountReference : annualFeeData) {
|
||||||
|
this.savingsAccountWritePlatformService.applyAnnualFee(savingsAccountReference.getId(),
|
||||||
String sql = "SELECT ms.id as savingsAccountId FROM m_savings_account ms WHERE ms.annual_fee_next_due_date <= NOW() ";
|
savingsAccountReference.getNextAnnualFeeDueDate());
|
||||||
List<Long> savingsIds = jdbcTemplate.queryForList(sql, Long.class);
|
|
||||||
|
|
||||||
for (Long savingsId : savingsIds) {
|
|
||||||
this.savingsAccountWritePlatformService.applyAnnualFee(savingsId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(ThreadLocalContextUtil.getTenant().getName() + ": Results affected by update: " + savingsIds.size());
|
logger.info(ThreadLocalContextUtil.getTenant().getName() + ": Savings accounts affected by update: " + annualFeeData.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user