FINERACT-130:AccountHold

This commit is contained in:
rrpawar96
2022-04-04 15:50:54 +02:00
committed by Arnold Gálovics
parent e65d896c38
commit 9329b99185
18 changed files with 346 additions and 117 deletions
@@ -80,6 +80,7 @@ public class SavingsApiConstants {
public static final String externalIdParamName = "externalId";
public static final String statusParamName = "status";
public static final String subStatusParamName = "subStatus";
public static final String reasonForBlockParamName = "reasonForBlock";
public static final String clientIdParamName = "clientId";
public static final String isRetailAccountParamName = "isRetailAccount";
public static final String autogenerateTransactionIdParamName = "autogenerateTransactionId";
@@ -479,10 +479,10 @@ public class SavingsAccountsApiResource {
final CommandWrapper commandRequest = builder.unblockCreditsToSavingsAccount(accountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, SavingsApiConstants.COMMAND_BLOCK_ACCOUNT)) {
final CommandWrapper commandRequest = builder.withNoJsonBody().blockSavingsAccount(accountId).build();
final CommandWrapper commandRequest = builder.blockSavingsAccount(accountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, SavingsApiConstants.COMMAND_UNBLOCK_ACCOUNT)) {
final CommandWrapper commandRequest = builder.withNoJsonBody().unblockSavingsAccount(accountId).build();
final CommandWrapper commandRequest = builder.unblockSavingsAccount(accountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
@@ -64,6 +64,7 @@ public final class SavingsAccountData implements Serializable {
private final String fieldOfficerName;
private final SavingsAccountStatusEnumData status;
private final SavingsAccountSubStatusEnumData subStatus;
private final String reasonForBlock;
private final SavingsAccountApplicationTimelineData timeline;
private final CurrencyData currency;
private final BigDecimal nominalAnnualInterestRate;
@@ -174,6 +175,7 @@ public final class SavingsAccountData implements Serializable {
this.fieldOfficerName = null;
this.status = null;
this.subStatus = null;
this.reasonForBlock = null;
this.timeline = null;
this.currency = null;
this.nominalAnnualInterestRate = nominalAnnualInterestRate;
@@ -528,6 +530,7 @@ public final class SavingsAccountData implements Serializable {
this.fieldOfficerName = null;
this.status = null;
this.subStatus = null;
this.reasonForBlock = null;
this.timeline = null;
this.currency = null;
this.nominalAnnualInterestRate = nominalAnnualInterestRate;
@@ -584,7 +587,7 @@ public final class SavingsAccountData implements Serializable {
public static SavingsAccountData instance(final Long id, final String accountNo, final EnumOptionData depositType,
final String externalId, final Long groupId, final String groupName, final Long clientId, final String clientName,
final Long productId, final String productName, final Long fieldOfficerId, final String fieldOfficerName,
final SavingsAccountStatusEnumData status, SavingsAccountSubStatusEnumData subStatus,
final SavingsAccountStatusEnumData status, SavingsAccountSubStatusEnumData subStatus, final String reasonForBlock,
final SavingsAccountApplicationTimelineData timeline, final CurrencyData currency, final BigDecimal interestRate,
final EnumOptionData interestCompoundingPeriodType, final EnumOptionData interestPostingPeriodType,
final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType,
@@ -611,7 +614,7 @@ public final class SavingsAccountData implements Serializable {
final Collection<ChargeData> chargeOptions = null;
return new SavingsAccountData(id, accountNo, depositType, externalId, groupId, groupName, clientId, clientName, productId,
productName, fieldOfficerId, fieldOfficerName, status, subStatus, timeline, currency, interestRate,
productName, fieldOfficerId, fieldOfficerName, status, subStatus, reasonForBlock, timeline, currency, interestRate,
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary,
transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
@@ -676,6 +679,7 @@ public final class SavingsAccountData implements Serializable {
final boolean withHoldTax = false;
final TaxGroupData taxGroup = null;
final SavingsAccountSubStatusEnumData subStatus = null;
final String reasonForBlock = null;
final LocalDate lastActiveTransactionDate = null;
final boolean isDormancyTrackingActive = false;
final Integer daysToInactive = null;
@@ -684,15 +688,15 @@ public final class SavingsAccountData implements Serializable {
final BigDecimal savingsAmountOnHold = null;
return new SavingsAccountData(accountId, accountNo, depositType, externalId, groupId, groupName, clientId, clientName, productId,
productName, fieldOfficerId, fieldOfficerName, status, subStatus, timeline, currency, nominalAnnualInterestRate,
interestPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary,
transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit, minRequiredBalance,
enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft,
minOverdraftForInterestCalculation, withHoldTax, taxGroup, lastActiveTransactionDate, isDormancyTrackingActive,
daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold);
productName, fieldOfficerId, fieldOfficerName, status, subStatus, reasonForBlock, timeline, currency,
nominalAnnualInterestRate, interestPeriodType, interestPostingPeriodType, interestCalculationType,
interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType,
withdrawalFeeForTransfers, summary, transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions,
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit,
minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds,
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup, lastActiveTransactionDate,
isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold);
}
public static SavingsAccountData lookupWithProductDetails(final Long accountId, final String accountNo,
@@ -747,6 +751,7 @@ public final class SavingsAccountData implements Serializable {
final boolean withHoldTax = false;
final TaxGroupData taxGroup = null;
final SavingsAccountSubStatusEnumData subStatus = null;
final String reasonForBlock = null;
final LocalDate lastActiveTransactionDate = null;
final boolean isDormancyTrackingActive = false;
final Integer daysToInactive = null;
@@ -755,15 +760,15 @@ public final class SavingsAccountData implements Serializable {
final BigDecimal savingsAmountOnHold = null;
return new SavingsAccountData(accountId, accountNo, depositType, externalId, groupId, groupName, clientId, clientName, productId,
productName, fieldOfficerId, fieldOfficerName, status, subStatus, timeline, currency, nominalAnnualInterestRate,
interestPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary,
transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit, minRequiredBalance,
enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft,
minOverdraftForInterestCalculation, withHoldTax, taxGroup, lastActiveTransactionDate, isDormancyTrackingActive,
daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold);
productName, fieldOfficerId, fieldOfficerName, status, subStatus, reasonForBlock, timeline, currency,
nominalAnnualInterestRate, interestPeriodType, interestPostingPeriodType, interestCalculationType,
interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType,
withdrawalFeeForTransfers, summary, transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions,
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit,
minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds,
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup, lastActiveTransactionDate,
isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold);
}
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account, final SavingsAccountData template,
@@ -787,18 +792,19 @@ public final class SavingsAccountData implements Serializable {
return new SavingsAccountData(account.id, account.accountNo, account.depositType, account.externalId, account.groupId,
account.groupName, account.clientId, account.clientName, account.savingsProductId, account.savingsProductName,
account.fieldOfficerId, account.fieldOfficerName, account.status, account.subStatus, account.timeline, account.currency,
account.nominalAnnualInterestRate, account.interestCompoundingPeriodType, account.interestPostingPeriodType,
account.interestCalculationType, account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance,
account.lockinPeriodFrequency, account.lockinPeriodFrequencyType, account.withdrawalFeeForTransfers, account.summary,
transactions, template.productOptions, template.fieldOfficerOptions, template.interestCompoundingPeriodTypeOptions,
template.interestPostingPeriodTypeOptions, template.interestCalculationTypeOptions,
template.interestCalculationDaysInYearTypeOptions, template.lockinPeriodFrequencyTypeOptions,
template.withdrawalFeeTypeOptions, charges, template.chargeOptions, account.allowOverdraft, account.overdraftLimit,
account.minRequiredBalance, account.enforceMinRequiredBalance, account.minBalanceForInterestCalculation,
account.onHoldFunds, account.nominalAnnualInterestRateOverdraft, account.minOverdraftForInterestCalculation,
account.withHoldTax, account.taxGroup, account.lastActiveTransactionDate, account.isDormancyTrackingActive,
account.daysToInactive, account.daysToDormancy, account.daysToEscheat, account.savingsAmountOnHold);
account.fieldOfficerId, account.fieldOfficerName, account.status, account.subStatus, account.reasonForBlock,
account.timeline, account.currency, account.nominalAnnualInterestRate, account.interestCompoundingPeriodType,
account.interestPostingPeriodType, account.interestCalculationType, account.interestCalculationDaysInYearType,
account.minRequiredOpeningBalance, account.lockinPeriodFrequency, account.lockinPeriodFrequencyType,
account.withdrawalFeeForTransfers, account.summary, transactions, template.productOptions, template.fieldOfficerOptions,
template.interestCompoundingPeriodTypeOptions, template.interestPostingPeriodTypeOptions,
template.interestCalculationTypeOptions, template.interestCalculationDaysInYearTypeOptions,
template.lockinPeriodFrequencyTypeOptions, template.withdrawalFeeTypeOptions, charges, template.chargeOptions,
account.allowOverdraft, account.overdraftLimit, account.minRequiredBalance, account.enforceMinRequiredBalance,
account.minBalanceForInterestCalculation, account.onHoldFunds, account.nominalAnnualInterestRateOverdraft,
account.minOverdraftForInterestCalculation, account.withHoldTax, account.taxGroup, account.lastActiveTransactionDate,
account.isDormancyTrackingActive, account.daysToInactive, account.daysToDormancy, account.daysToEscheat,
account.savingsAmountOnHold);
}
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account,
@@ -813,17 +819,18 @@ public final class SavingsAccountData implements Serializable {
return new SavingsAccountData(account.id, account.accountNo, account.depositType, account.externalId, account.groupId,
account.groupName, account.clientId, account.clientName, account.savingsProductId, account.savingsProductName,
account.fieldOfficerId, account.fieldOfficerName, account.status, account.subStatus, account.timeline, account.currency,
account.nominalAnnualInterestRate, account.interestCompoundingPeriodType, account.interestPostingPeriodType,
account.interestCalculationType, account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance,
account.lockinPeriodFrequency, account.lockinPeriodFrequencyType, account.withdrawalFeeForTransfers, account.summary,
transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
withdrawalFeeTypeOptions, charges, chargeOptions, account.allowOverdraft, account.overdraftLimit,
account.minRequiredBalance, account.enforceMinRequiredBalance, account.minBalanceForInterestCalculation,
account.onHoldFunds, account.nominalAnnualInterestRateOverdraft, account.minOverdraftForInterestCalculation,
account.withHoldTax, account.taxGroup, account.lastActiveTransactionDate, account.isDormancyTrackingActive,
account.daysToInactive, account.daysToDormancy, account.daysToEscheat, account.savingsAmountOnHold);
account.fieldOfficerId, account.fieldOfficerName, account.status, account.subStatus, account.reasonForBlock,
account.timeline, account.currency, account.nominalAnnualInterestRate, account.interestCompoundingPeriodType,
account.interestPostingPeriodType, account.interestCalculationType, account.interestCalculationDaysInYearType,
account.minRequiredOpeningBalance, account.lockinPeriodFrequency, account.lockinPeriodFrequencyType,
account.withdrawalFeeForTransfers, account.summary, transactions, productOptions, fieldOfficerOptions,
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges,
chargeOptions, account.allowOverdraft, account.overdraftLimit, account.minRequiredBalance,
account.enforceMinRequiredBalance, account.minBalanceForInterestCalculation, account.onHoldFunds,
account.nominalAnnualInterestRateOverdraft, account.minOverdraftForInterestCalculation, account.withHoldTax,
account.taxGroup, account.lastActiveTransactionDate, account.isDormancyTrackingActive, account.daysToInactive,
account.daysToDormancy, account.daysToEscheat, account.savingsAmountOnHold);
}
public static SavingsAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
@@ -880,6 +887,7 @@ public final class SavingsAccountData implements Serializable {
final Collection<SavingsAccountChargeData> charges = null;
final Collection<ChargeData> chargeOptions = null;
final SavingsAccountSubStatusEnumData subStatus = null;
final String reasonForBlock = null;
final LocalDate lastActiveTransactionDate = null;
final boolean isDormancyTrackingActive = false;
final Integer daysToInactive = null;
@@ -888,28 +896,28 @@ public final class SavingsAccountData implements Serializable {
final BigDecimal savingsAmountOnHold = null;
return new SavingsAccountData(id, accountNo, depositType, externalId, groupId, groupName, clientId, clientName, productId,
productName, fieldOfficerId, fieldOfficerName, status, subStatus, timeline, currency, nominalAnnualInterestRate,
interestPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary,
transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit, minRequiredBalance,
enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft,
minOverdraftForInterestCalculation, withHoldTax, taxGroup, lastActiveTransactionDate, isDormancyTrackingActive,
daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold);
productName, fieldOfficerId, fieldOfficerName, status, subStatus, reasonForBlock, timeline, currency,
nominalAnnualInterestRate, interestPeriodType, interestPostingPeriodType, interestCalculationType,
interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType,
withdrawalFeeForTransfers, summary, transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions,
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit,
minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds,
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup, lastActiveTransactionDate,
isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold);
}
private SavingsAccountData(final Long id, final String accountNo, final EnumOptionData depositType, final String externalId,
final Long groupId, final String groupName, final Long clientId, final String clientName, final Long productId,
final String productName, final Long fieldOfficerId, final String fieldOfficerName, final SavingsAccountStatusEnumData status,
final SavingsAccountSubStatusEnumData subStatus, final SavingsAccountApplicationTimelineData timeline,
final CurrencyData currency, final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestPeriodType,
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final boolean withdrawalFeeForTransfers,
final SavingsAccountSummaryData summary, final Collection<SavingsAccountTransactionData> transactions,
final Collection<SavingsProductData> productOptions, final Collection<StaffData> fieldOfficerOptions,
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
final SavingsAccountSubStatusEnumData subStatus, final String reasonForBlock,
final SavingsAccountApplicationTimelineData timeline, final CurrencyData currency, final BigDecimal nominalAnnualInterestRate,
final EnumOptionData interestPeriodType, final EnumOptionData interestPostingPeriodType,
final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType,
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType,
final boolean withdrawalFeeForTransfers, final SavingsAccountSummaryData summary,
final Collection<SavingsAccountTransactionData> transactions, final Collection<SavingsProductData> productOptions,
final Collection<StaffData> fieldOfficerOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
final Collection<EnumOptionData> interestCalculationTypeOptions,
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
@@ -935,6 +943,7 @@ public final class SavingsAccountData implements Serializable {
this.fieldOfficerName = fieldOfficerName;
this.status = status;
this.subStatus = subStatus;
this.reasonForBlock = reasonForBlock;
this.timeline = timeline;
this.currency = currency;
this.nominalAnnualInterestRate = nominalAnnualInterestRate;
@@ -73,6 +73,8 @@ public final class SavingsAccountTransactionData implements Serializable {
private final boolean isManualTransaction;
private final Boolean isReversal;
private final Long originalTransactionId;
private final Long releaseTransactionId;
private final String reasonForBlock;
private Set<SavingsAccountChargesPaidByData> chargesPaidByData = new HashSet<>();
// templates
@@ -347,6 +349,8 @@ public final class SavingsAccountTransactionData implements Serializable {
this.note = null;
this.isReversal = null;
this.originalTransactionId = null;
this.releaseTransactionId = null;
this.reasonForBlock = null;
}
public boolean isChargeTransaction() {
@@ -544,7 +548,8 @@ public final class SavingsAccountTransactionData implements Serializable {
this.isManualTransaction = isManualTransaction;
this.isReversal = null;
this.originalTransactionId = null;
this.releaseTransactionId = null;
this.reasonForBlock = null;
}
private SavingsAccountTransactionData(BigDecimal transactionAmount, LocalDate transactionDate, Long paymentTypeId, String accountNumber,
@@ -582,6 +587,8 @@ public final class SavingsAccountTransactionData implements Serializable {
this.isManualTransaction = false;
this.isReversal = null;
this.originalTransactionId = null;
this.releaseTransactionId = null;
this.reasonForBlock = null;
}
private SavingsAccountTransactionData(Integer id, BigDecimal transactionAmount, LocalDate transactionDate, Long paymentTypeId,
@@ -621,6 +628,8 @@ public final class SavingsAccountTransactionData implements Serializable {
this.isManualTransaction = false;
this.isReversal = null;
this.originalTransactionId = null;
this.releaseTransactionId = null;
this.reasonForBlock = null;
}
public Integer getRowIndex() {
@@ -753,6 +762,8 @@ public final class SavingsAccountTransactionData implements Serializable {
this.isManualTransaction = false;
this.isReversal = null;
this.originalTransactionId = null;
this.releaseTransactionId = null;
this.reasonForBlock = null;
}
public static SavingsAccountTransactionData create(final Long id, final SavingsAccountTransactionEnumData transactionType,
@@ -770,11 +781,12 @@ public final class SavingsAccountTransactionData implements Serializable {
final PaymentDetailData paymentDetailData, final Long savingsId, final String savingsAccountNo, final LocalDate date,
final CurrencyData currency, final BigDecimal amount, final BigDecimal outstandingChargeAmount, final BigDecimal runningBalance,
final boolean reversed, final AccountTransferData transfer, final LocalDate submittedOnDate, final boolean interestedPostedAsOn,
final String submittedByUsername, final String note, final Boolean isReversal, final Long originalTransactionId) {
final String submittedByUsername, final String note, final Boolean isReversal, final Long originalTransactionId,
final Long releaseTransactionId, final String reasonForBlock) {
final Collection<PaymentTypeData> paymentTypeOptions = null;
return new SavingsAccountTransactionData(id, transactionType, paymentDetailData, savingsId, savingsAccountNo, date, currency,
amount, outstandingChargeAmount, runningBalance, reversed, transfer, paymentTypeOptions, submittedOnDate,
interestedPostedAsOn, submittedByUsername, note, isReversal, originalTransactionId);
interestedPostedAsOn, submittedByUsername, note, isReversal, originalTransactionId, releaseTransactionId, reasonForBlock);
}
public static SavingsAccountTransactionData create(final Long id) {
@@ -827,7 +839,7 @@ public final class SavingsAccountTransactionData implements Serializable {
final CurrencyData currency, final BigDecimal amount, final BigDecimal outstandingChargeAmount, final BigDecimal runningBalance,
final boolean reversed, final AccountTransferData transfer, final Collection<PaymentTypeData> paymentTypeOptions,
final LocalDate submittedOnDate, final boolean interestedPostedAsOn, final String submittedByUsername, final String note,
final Boolean isReversal, final Long originalTransactionId) {
final Boolean isReversal, final Long originalTransactionId, final Long releaseTransactionId, final String reasonForBlock) {
this.id = id;
this.transactionType = transactionType;
this.paymentDetailData = paymentDetailData;
@@ -853,6 +865,8 @@ public final class SavingsAccountTransactionData implements Serializable {
this.isManualTransaction = false;
this.isReversal = isReversal;
this.originalTransactionId = originalTransactionId;
this.releaseTransactionId = releaseTransactionId;
this.reasonForBlock = reasonForBlock;
}
private SavingsAccountTransactionData(final Long id, final SavingsAccountTransactionEnumData transactionType,
@@ -886,6 +900,43 @@ public final class SavingsAccountTransactionData implements Serializable {
this.isManualTransaction = false;
this.isReversal = null;
this.originalTransactionId = null;
this.releaseTransactionId = null;
this.reasonForBlock = null;
}
private SavingsAccountTransactionData(final Long id, final SavingsAccountTransactionEnumData transactionType,
final PaymentDetailData paymentDetailData, final Long savingsId, final String savingsAccountNo, final LocalDate date,
final CurrencyData currency, final BigDecimal amount, final BigDecimal outstandingChargeAmount, final BigDecimal runningBalance,
final boolean reversed, final AccountTransferData transfer, final Collection<PaymentTypeData> paymentTypeOptions,
final LocalDate submittedOnDate, final boolean interestedPostedAsOn, final String submittedByUsername, final String note,
final Boolean isReversal, final Long originalTransactionId) {
this.id = id;
this.transactionType = transactionType;
this.paymentDetailData = paymentDetailData;
this.accountId = savingsId;
this.accountNo = savingsAccountNo;
this.date = date;
this.currency = currency;
this.amount = amount;
this.outstandingChargeAmount = outstandingChargeAmount;
this.runningBalance = runningBalance;
this.reversed = reversed;
this.transfer = transfer;
this.paymentTypeOptions = paymentTypeOptions;
if (submittedOnDate != null) {
this.submittedOnDate = Date.from(submittedOnDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
} else {
this.submittedOnDate = null;
}
this.interestedPostedAsOn = interestedPostedAsOn;
this.submittedByUsername = submittedByUsername;
this.note = note;
this.isManualTransaction = false;
this.isReversal = isReversal;
this.originalTransactionId = originalTransactionId;
this.releaseTransactionId = null;
this.reasonForBlock = null;
}
public static SavingsAccountTransactionData withWithDrawalTransactionDetails(
@@ -57,6 +57,8 @@ import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountSubStatusEnum;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
import org.apache.fineract.portfolio.savings.exception.TransactionBeforePivotDateNotAllowed;
import org.apache.fineract.useradministration.domain.AppUser;
@@ -69,14 +71,17 @@ public class SavingsAccountTransactionDataValidator {
private final FromJsonHelper fromApiJsonHelper;
private static final Set<String> SAVINGS_ACCOUNT_HOLD_AMOUNT_REQUEST_DATA_PARAMETERS = new HashSet<>(
Arrays.asList(transactionDateParamName, SavingsApiConstants.dateFormatParamName, SavingsApiConstants.localeParamName,
transactionAmountParamName, lienParamName));
transactionAmountParamName, lienParamName, SavingsApiConstants.reasonForBlockParamName));
private final ConfigurationDomainService configurationDomainService;
private final SavingsAccountAssembler savingAccountAssembler;
@Autowired
public SavingsAccountTransactionDataValidator(final FromJsonHelper fromApiJsonHelper,
final ConfigurationDomainService configurationDomainService) {
final ConfigurationDomainService configurationDomainService, final SavingsAccountAssembler savingAccountAssembler) {
this.fromApiJsonHelper = fromApiJsonHelper;
this.configurationDomainService = configurationDomainService;
this.savingAccountAssembler = savingAccountAssembler;
}
public void validateTransactionWithPivotDate(final LocalDate transactionDate, final SavingsAccount savingsAccount) {
@@ -179,6 +184,13 @@ public class SavingsAccountTransactionDataValidator {
account.getId());
}
if (account.getSubStatus().equals(SavingsAccountSubStatusEnum.BLOCK.getValue())
|| account.getSubStatus().equals(SavingsAccountSubStatusEnum.BLOCK_CREDIT.getValue())
|| account.getSubStatus().equals(SavingsAccountSubStatusEnum.BLOCK_DEBIT.getValue())) {
baseDataValidator.reset().parameter(SavingsApiConstants.subStatusParamName)
.failWithCodeNoParameterAddedToErrorCode("account.is.in.blocked.state");
}
validatePaymentTypeDetails(baseDataValidator, element);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
@@ -225,6 +237,10 @@ public class SavingsAccountTransactionDataValidator {
baseDataValidator.reset().parameter(transactionAmountParamName).value(amount).notNull().positiveAmount();
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(transactionDateParamName, element);
final String reasonForBlock = this.fromApiJsonHelper.extractStringNamed(SavingsApiConstants.reasonForBlockParamName, element);
baseDataValidator.reset().parameter(SavingsApiConstants.reasonForBlockParamName).value(reasonForBlock).notBlank()
.notExceedingLengthOf(100);
baseDataValidator.reset().parameter(transactionDateParamName).value(transactionDate).notNull();
boolean isActive = account.isActive();
@@ -232,21 +248,18 @@ public class SavingsAccountTransactionDataValidator {
baseDataValidator.reset().parameter(SavingsApiConstants.statusParamName)
.failWithCodeNoParameterAddedToErrorCode(SavingsApiConstants.ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE);
}
account.holdAmount(amount);
Boolean lien = false;
if (this.fromApiJsonHelper.parameterExists(lienParamName, element)) {
lien = this.fromApiJsonHelper.extractBooleanNamed(lienParamName, element);
}
if (account.getEnforceMinRequiredBalance()) {
if (account.getWithdrawableBalance().compareTo(BigDecimal.ZERO) < 0) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("insufficient balance", account.getId());
}
}
Boolean lien = false;
if (this.fromApiJsonHelper.parameterExists(lienParamName, element)) {
lien = this.fromApiJsonHelper.extractBooleanNamed(lienParamName, element);
if (!lien) {
if (account.getWithdrawableBalanceWithoutMinimumBalance().compareTo(BigDecimal.ZERO) < 0) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("insufficient balance", account.getId());
if (!lien) {
if (account.getWithdrawableBalanceWithoutMinimumBalance().compareTo(account.getMinRequiredBalance()) < 0) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("insufficient balance", account.getId());
}
}
}
}
@@ -271,6 +284,7 @@ public class SavingsAccountTransactionDataValidator {
SavingsAccountTransaction transaction = SavingsAccountTransaction.holdAmount(account, account.office(), paymentDetails,
transactionDate, Money.of(account.getCurrency(), amount), createdDate, createdUser);
return transaction;
}
@@ -298,6 +312,7 @@ public class SavingsAccountTransactionDataValidator {
throwExceptionIfValidationWarningsExist(dataValidationErrors);
Date createdDate = new Date();
LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
SavingsAccountTransaction transaction = SavingsAccountTransaction.releaseAmount(holdTransaction, transactionDate, createdDate,
createdUser);
return transaction;
@@ -220,6 +220,9 @@ public class SavingsAccount extends AbstractPersistableCustom {
@JoinColumn(name = "closedon_userid", nullable = true)
protected AppUser closedBy;
@Column(name = "reason_for_block", nullable = true)
protected String reasonForBlock;
@Embedded
protected MonetaryCurrency currency;
@@ -1442,8 +1445,16 @@ public class SavingsAccount extends AbstractPersistableCustom {
}
if (this.getSavingsHoldAmount().compareTo(BigDecimal.ZERO) > 0) {
if (runningBalance.minus(this.getSavingsHoldAmount()).isLessThanZero()) {
throw new InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), withdrawalFee, transactionAmount);
if (this.enforceMinRequiredBalance) {
if (runningBalance.minus(minRequiredBalance.plus(this.getSavingsHoldAmount())).isLessThanZero()) {
throw new InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), withdrawalFee,
transactionAmount);
}
} else {
if (runningBalance.minus(this.getSavingsHoldAmount()).isLessThanZero()) {
throw new InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), withdrawalFee,
transactionAmount);
}
}
}
}
@@ -3500,6 +3511,10 @@ public class SavingsAccount extends AbstractPersistableCustom {
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, transactions);
}
public void updateReason(final String reasonForBlock) {
this.reasonForBlock = reasonForBlock;
}
public Map<String, Object> block() {
final Map<String, Object> actualChanges = new LinkedHashMap<>();
@@ -262,6 +262,10 @@ public final class SavingsAccountSummary {
return this.accountBalance;
}
public void setAccountBalance(BigDecimal accountBalance) {
this.accountBalance = accountBalance;
}
public BigDecimal getTotalInterestPosted() {
return this.totalInterestPosted;
}
@@ -127,6 +127,9 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
@Column(name = "release_id_of_hold_amount", length = 20)
private Long releaseIdOfHoldAmountTransaction;
@Column(name = "reason_for_block", nullable = true)
private String reasonForBlock;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "savings_account_transaction_id", referencedColumnName = "id")
private List<Note> notes = new ArrayList<>();
@@ -843,6 +846,10 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
this.releaseIdOfHoldAmountTransaction = releaseId;
}
public void updateReason(String reasonForBlock) {
this.reasonForBlock = reasonForBlock;
}
public Long getReleaseIdOfHoldAmountTransaction() {
return this.releaseIdOfHoldAmountTransaction;
}
@@ -41,7 +41,7 @@ public class BlockCreditsToSavingsAccountCommandHandler implements NewCommandSou
@Transactional
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.writePlatformService.blockCredits(command.getSavingsId());
return this.writePlatformService.blockCredits(command.getSavingsId(), command);
}
}
@@ -41,7 +41,7 @@ public class BlockDebitsFromSavingsAccountCommandHandler implements NewCommandSo
@Transactional
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.writePlatformService.blockDebits(command.getSavingsId());
return this.writePlatformService.blockDebits(command.getSavingsId(), command);
}
}
@@ -41,7 +41,7 @@ public class BlockSavingsAccountCommandHandler implements NewCommandSourceHandle
@Transactional
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.writePlatformService.blockAccount(command.getSavingsId());
return this.writePlatformService.blockAccount(command.getSavingsId(), command);
}
}
@@ -576,7 +576,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final BigDecimal minRequiredBalance = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minRequiredBalance");
final boolean enforceMinRequiredBalance = rs.getBoolean("enforceMinRequiredBalance");
savingsAccountData = SavingsAccountData.instance(id, accountNo, depositType, externalId, null, null, null, null,
productId, null, null, null, status, subStatus, timeline, currency, nominalAnnualInterestRate,
productId, null, null, null, status, subStatus, null, timeline, currency, nominalAnnualInterestRate,
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType,
withdrawalFeeForTransfers, summary, allowOverdraft, overdraftLimit, minRequiredBalance,
@@ -746,6 +746,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
sqlBuilder.append("s.id fieldOfficerId, s.display_name as fieldOfficerName, ");
sqlBuilder.append("sa.status_enum as statusEnum, ");
sqlBuilder.append("sa.sub_status_enum as subStatusEnum, ");
sqlBuilder.append("sa.reason_for_block as reasonForBlock, ");
sqlBuilder.append("sa.submittedon_date as submittedOnDate,");
sqlBuilder.append("sbu.username as submittedByUsername,");
sqlBuilder.append("sbu.firstname as submittedByFirstname, sbu.lastname as submittedByLastname,");
@@ -874,6 +875,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final Integer subStatusEnum = JdbcSupport.getInteger(rs, "subStatusEnum");
final SavingsAccountSubStatusEnumData subStatus = SavingsEnumerations.subStatus(subStatusEnum);
final String reasonForBlock = rs.getString("reasonForBlock");
final LocalDate lastActiveTransactionDate = JdbcSupport.getLocalDate(rs, "lastActiveTransactionDate");
final boolean isDormancyTrackingActive = rs.getBoolean("isDormancyTrackingActive");
@@ -1022,7 +1024,6 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
BigDecimal availableBalance = accountBalance;
if (availableBalance != null && onHoldFunds != null) {
availableBalance = availableBalance.subtract(onHoldFunds);
}
@@ -1052,12 +1053,13 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
}
return SavingsAccountData.instance(id, accountNo, depositType, externalId, groupId, groupName, clientId, clientName, productId,
productName, fieldOfficerId, fieldOfficerName, status, subStatus, timeline, currency, nominalAnnualInterestRate,
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary,
allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation,
onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroupData,
lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat, onHoldAmount);
productName, fieldOfficerId, fieldOfficerName, status, subStatus, reasonForBlock, timeline, currency,
nominalAnnualInterestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType,
withdrawalFeeForTransfers, summary, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance,
minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation,
withHoldTax, taxGroupData, lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy,
daysToEscheat, onHoldAmount);
}
}
@@ -1312,6 +1314,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("tr.id as transactionId, tr.transaction_type_enum as transactionType, ");
sqlBuilder.append("tr.transaction_date as transactionDate, tr.amount as transactionAmount,");
sqlBuilder.append(" tr.release_id_of_hold_amount as releaseTransactionId,");
sqlBuilder.append(" tr.reason_for_block as reasonForBlock,");
sqlBuilder.append("tr.created_date as submittedOnDate,");
sqlBuilder.append(" au.username as submittedByUsername, ");
sqlBuilder.append(" nt.note as transactionNote, ");
@@ -1357,6 +1361,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final LocalDate date = JdbcSupport.getLocalDate(rs, "transactionDate");
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
final BigDecimal amount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "transactionAmount");
final Long releaseTransactionId = rs.getLong("releaseTransactionId");
final String reasonForBlock = rs.getString("reasonForBlock");
final BigDecimal outstandingChargeAmount = null;
final BigDecimal runningBalance = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "runningBalance");
final boolean reversed = rs.getBoolean("reversed");
@@ -1416,7 +1422,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final String note = rs.getString("transactionNote");
return SavingsAccountTransactionData.create(id, transactionType, paymentDetailData, savingsId, accountNo, date, currency,
amount, outstandingChargeAmount, runningBalance, reversed, transfer, submittedOnDate, postInterestAsOn,
submittedByUsername, note, isReversal, originalTransactionId);
submittedByUsername, note, isReversal, originalTransactionId, releaseTransactionId, reasonForBlock);
}
}
@@ -1619,6 +1625,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final BigDecimal savingsAmountOnHold = null;
final SavingsAccountSubStatusEnumData subStatus = null;
final String reasonForBlock = null;
final LocalDate lastActiveTransactionDate = null;
final boolean isDormancyTrackingActive = false;
final Integer daysToInactive = null;
@@ -1628,13 +1635,13 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final SavingsAccountApplicationTimelineData timeline = SavingsAccountApplicationTimelineData.templateDefault();
final EnumOptionData depositType = null;
return SavingsAccountData.instance(null, null, depositType, null, groupId, groupName, clientId, clientName, productId,
productName, fieldOfficerId, fieldOfficerName, status, subStatus, timeline, currency, nominalAnnualIterestRate,
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary,
allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation,
onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroupData,
lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy, daysToEscheat,
savingsAmountOnHold);
productName, fieldOfficerId, fieldOfficerName, status, subStatus, reasonForBlock, timeline, currency,
nominalAnnualIterestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType,
withdrawalFeeForTransfers, summary, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance,
minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation,
withHoldTax, taxGroupData, lastActiveTransactionDate, isDormancyTrackingActive, daysToInactive, daysToDormancy,
daysToEscheat, savingsAmountOnHold);
}
}
@@ -96,17 +96,17 @@ public interface SavingsAccountWritePlatformService {
SavingsAccountData postInterest(SavingsAccountData account, boolean postInterestAs, LocalDate transactionDate,
boolean backdatedTxnsAllowedTill);
CommandProcessingResult blockAccount(Long savingsId);
CommandProcessingResult blockAccount(Long savingsId, JsonCommand command);
CommandProcessingResult unblockAccount(Long savingsId);
CommandProcessingResult holdAmount(Long savingsId, JsonCommand command);
CommandProcessingResult blockCredits(Long savingsId);
CommandProcessingResult blockCredits(Long savingsId, JsonCommand command);
CommandProcessingResult unblockCredits(Long savingsId);
CommandProcessingResult blockDebits(Long savingsId);
CommandProcessingResult blockDebits(Long savingsId, JsonCommand command);
CommandProcessingResult unblockDebits(Long savingsId);
@@ -23,6 +23,7 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.amountParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargeIdParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.transactionAmountParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawBalanceParamName;
@@ -53,6 +54,7 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuild
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
@@ -1762,7 +1764,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
}
@Override
public CommandProcessingResult blockAccount(final Long savingsId) {
public CommandProcessingResult blockAccount(final Long savingsId, final JsonCommand command) {
this.context.authenticatedUser();
@@ -1770,6 +1772,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
checkClientOrGroupActive(account);
final Map<String, Object> changes = account.block();
final String reasonForBlock = command.stringValueOfParameterNamed(SavingsApiConstants.reasonForBlockParamName);
validateReasonForHold(reasonForBlock);
account.updateReason(reasonForBlock);
if (!changes.isEmpty()) {
this.savingAccountRepositoryWrapper.save(account);
@@ -1786,6 +1793,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
checkClientOrGroupActive(account);
final Map<String, Object> changes = account.unblock();
account.updateReason(null);
if (!changes.isEmpty()) {
this.savingAccountRepositoryWrapper.save(account);
@@ -1804,12 +1814,29 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
checkClientOrGroupActive(account);
SavingsAccountTransaction transacton = this.savingsAccountTransactionDataValidator.validateHoldAndAssembleForm(command.json(),
final BigDecimal amount = command.bigDecimalValueOfParameterNamed(transactionAmountParamName);
Money runningBalance = Money.of(account.getCurrency(), account.getAccountBalance());
if (account.getSavingsHoldAmount() != null) {
runningBalance = runningBalance.minus(account.getSavingsHoldAmount()).minus(amount);
} else {
runningBalance = runningBalance.minus(amount);
}
account.holdAmount(amount);
SavingsAccountTransaction transaction = this.savingsAccountTransactionDataValidator.validateHoldAndAssembleForm(command.json(),
account, submittedBy, backdatedTxnsAllowedTill);
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(transacton.getTransactionLocalDate(), account);
transaction.updateRunningBalance(runningBalance);
this.savingsAccountTransactionRepository.saveAndFlush(transacton);
final String reasonForBlock = command.stringValueOfParameterNamed(SavingsApiConstants.reasonForBlockParamName);
transaction.updateReason(reasonForBlock);
account.getAccountBalance();
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(transaction.getTransactionLocalDate(), account);
this.savingsAccountTransactionRepository.saveAndFlush(transaction);
if (backdatedTxnsAllowedTill) {
// Check again whether transactions are modified
@@ -1818,7 +1845,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
this.savingAccountRepositoryWrapper.saveAndFlush(account);
return new CommandProcessingResultBuilder().withEntityId(transacton.getId()).withOfficeId(account.officeId())
return new CommandProcessingResultBuilder().withEntityId(transaction.getId()).withOfficeId(account.officeId())
.withClientId(account.clientId()).withGroupId(account.groupId()).withSavingsId(savingsId).build();
}
@@ -1830,6 +1857,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
SavingsAccountTransaction holdTransaction = this.savingsAccountTransactionRepository
.findOneByIdAndSavingsAccountId(savingsTransactionId, savingsId);
holdTransaction.updateReason(null);
final SavingsAccountTransaction transaction = this.savingsAccountTransactionDataValidator
.validateReleaseAmountAndAssembleForm(holdTransaction, submittedBy);
@@ -1837,6 +1866,15 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, backdatedTxnsAllowedTill);
checkClientOrGroupActive(account);
Money runningBalance = Money.of(account.getCurrency(), account.getAccountBalance());
Money savingsOnHold = Money.of(account.getCurrency(), account.getSavingsHoldAmount());
runningBalance = runningBalance.minus(savingsOnHold);
runningBalance = runningBalance.plus(transaction.getAmount());
transaction.updateRunningBalance(runningBalance);
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(transaction.getTransactionLocalDate(), account);
account.releaseOnHoldAmount(transaction.getAmount());
@@ -1855,12 +1893,16 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
@Override
public CommandProcessingResult blockCredits(final Long savingsId) {
public CommandProcessingResult blockCredits(final Long savingsId, final JsonCommand command) {
this.context.authenticatedUser();
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
checkClientOrGroupActive(account);
final String reasonForBlock = command.stringValueOfParameterNamed(SavingsApiConstants.reasonForBlockParamName);
validateReasonForHold(reasonForBlock);
account.updateReason(reasonForBlock);
final Map<String, Object> changes = account.blockCredits(account.getSubStatus());
if (!changes.isEmpty()) {
@@ -1877,7 +1919,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
checkClientOrGroupActive(account);
account.updateReason(null);
final Map<String, Object> changes = account.unblockCredits();
if (!changes.isEmpty()) {
@@ -1889,12 +1931,16 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
@Override
public CommandProcessingResult blockDebits(final Long savingsId) {
public CommandProcessingResult blockDebits(final Long savingsId, final JsonCommand command) {
this.context.authenticatedUser();
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
checkClientOrGroupActive(account);
final String reasonForBlock = command.stringValueOfParameterNamed(SavingsApiConstants.reasonForBlockParamName);
validateReasonForHold(reasonForBlock);
account.updateReason(reasonForBlock);
final Map<String, Object> changes = account.blockDebits(account.getSubStatus());
if (!changes.isEmpty()) {
@@ -1912,6 +1958,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
checkClientOrGroupActive(account);
account.updateReason(null);
final Map<String, Object> changes = account.unblockDebits();
if (!changes.isEmpty()) {
@@ -1934,4 +1982,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
}
}
private void validateReasonForHold(String reasonForBlock) {
if (StringUtils.isBlank(reasonForBlock)) {
throw new PlatformDataIntegrityException("Reason For Block is Mandatory", "error.msg.reason.for.block.mandatory");
}
}
}
@@ -28,4 +28,5 @@
<include file="parts/0006_product_loan_disallow_expected_disbursements.xml" relativeToChangelogFile="true"/>
<include file="parts/0007_product_loan_higher_than_applied_loan_amount_management.xml" relativeToChangelogFile="true"/>
<include file="parts/0008_loan_charge_add_external_id.xml" relativeToChangelogFile="true"/>
<include file="parts/0009_hold_reason_savings_account.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<changeSet author="fineract" id="1">
<addColumn tableName="m_savings_account">
<column name="reason_for_block" type="VARCHAR(256)"/>
</addColumn>
</changeSet>
<changeSet author="fineract" id="2">
<addColumn tableName="m_savings_account_transaction">
<column name="reason_for_block" type="VARCHAR(256)"/>
</addColumn>
</changeSet>
<changeSet author="fineract" id="3">
<insert tableName="m_code">
<column name="code_name" value="SavingsAccountBlockReasons"/>
<column name="is_system_defined" valueBoolean="true"/>
</insert>
<insert tableName="m_code">
<column name="code_name" value="DebitTransactionFreezeReasons"/>
<column name="is_system_defined" valueBoolean="true"/>
</insert>
<insert tableName="m_code">
<column name="code_name" value="CreditTransactionFreezeReasons"/>
<column name="is_system_defined" valueBoolean="true"/>
</insert>
<insert tableName="m_code">
<column name="code_name" value="SavingsTransactionFreezeReasons"/>
<column name="is_system_defined" valueBoolean="true"/>
</insert>
</changeSet>
</databaseChangeLog>
@@ -2193,7 +2193,7 @@ public class ClientSavingsIntegrationTest {
final String minBalanceForInterestCalculation = null;
final String minRequiredBalance = null;
final String enforceMinRequiredBalance = "false";
final String enforceMinRequiredBalance = "true";
final boolean allowOverdraft = false;
final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE,
minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance, allowOverdraft);
@@ -338,8 +338,8 @@ public class SavingsAccountHelper {
public HashMap blockSavings(final Integer savingsID) {
LOG.info("---------------------------------- BLOCKING SAVINGS ACCOUNT ----------------------------------");
Boolean isBlock = true;
return performSavingApplicationActions(createSavingsOperationURL(BLOCK_SAVINGS_COMMAND, savingsID), getActivatedSavingsAsJSON(),
isBlock);
return performSavingApplicationActions(createSavingsOperationURL(BLOCK_SAVINGS_COMMAND, savingsID),
getActivatedSavingsAsForHoldJSON(), isBlock);
}
public HashMap unblockSavings(final Integer savingsID) {
@@ -353,7 +353,7 @@ public class SavingsAccountHelper {
LOG.info("---------------------------------- BLOCKING DEBIT TRANSACTIONS ----------------------------------");
Boolean isBlock = true;
return performSavingApplicationActions(createSavingsOperationURL(BLOCK_DEBITS_SAVINGS_COMMAND, savingsID),
getActivatedSavingsAsJSON(), isBlock);
getActivatedSavingsAsForHoldJSON(), isBlock);
}
public HashMap unblockDebit(final Integer savingsID) {
@@ -367,7 +367,7 @@ public class SavingsAccountHelper {
LOG.info("---------------------------------- BLOCKING CREDIT TRANSACTIONS ----------------------------------");
Boolean isBlock = true;
return performSavingApplicationActions(createSavingsOperationURL(BLOCK_CREDITS_SAVINGS_COMMAND, savingsID),
getActivatedSavingsAsJSON(), isBlock);
getActivatedSavingsAsForHoldJSON(), isBlock);
}
public HashMap unblockCredit(final Integer savingsID) {
@@ -437,6 +437,17 @@ public class SavingsAccountHelper {
return savingsAccountActivateJson;
}
private String getActivatedSavingsAsForHoldJSON() {
final HashMap<String, String> map = new HashMap<>();
map.put("locale", CommonConstants.LOCALE);
map.put("dateFormat", CommonConstants.DATE_FORMAT);
map.put("activatedOnDate", TRANSACTION_DATE);
map.put("reasonForBlock", "unUsualActivity");
String savingsAccountActivateJson = new Gson().toJson(map);
LOG.info(savingsAccountActivateJson);
return savingsAccountActivateJson;
}
private String getSavingsTransactionJSON(final String amount, final String transactionDate) {
final HashMap<String, String> map = new HashMap<>();
map.put("locale", CommonConstants.LOCALE);
@@ -455,6 +466,7 @@ public class SavingsAccountHelper {
map.put("transactionDate", transactionDate);
map.put("transactionAmount", amount);
map.put("lien", lien);
map.put("reasonForBlock", "unUsualActivity");
String savingsAccountWithdrawalJson = new Gson().toJson(map);
LOG.info(savingsAccountWithdrawalJson);
return savingsAccountWithdrawalJson;