Skip to content

Commit 857ff33

Browse files
FINERACT-2463: Allow undo of Fixed Deposit transactions
1 parent 9eb94dd commit 857ff33

5 files changed

Lines changed: 166 additions & 4 deletions

File tree

fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2419,6 +2419,17 @@ public CommandWrapperBuilder undoFixedDepositAccountApplication(final Long accou
24192419
return this;
24202420
}
24212421

2422+
public CommandWrapperBuilder undoFixedDepositAccountTransaction(final Long accountId, final Long transactionId) {
2423+
this.actionName = "UNDOTRANSACTION";
2424+
this.entityName = "FIXEDDEPOSITACCOUNT";
2425+
this.savingsId = accountId;
2426+
this.entityId = accountId;
2427+
this.subentityId = transactionId;
2428+
this.transactionId = transactionId.toString();
2429+
this.href = "/fixeddepositaccounts/" + accountId + "/transactions/" + transactionId + "?command=undo";
2430+
return this;
2431+
}
2432+
24222433
public CommandWrapperBuilder fixedDepositAccountActivation(final Long accountId) {
24232434
this.actionName = "ACTIVATE";
24242435
this.entityName = "FIXEDDEPOSITACCOUNT";

fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositAccountTransactionsApiResource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public String adjustTransaction(@PathParam("fixedDepositAccountId") final Long f
157157

158158
CommandProcessingResult result = null;
159159
if (is(commandParam, DepositsApiConstants.COMMAND_UNDO_TRANSACTION)) {
160-
final CommandWrapper commandRequest = builder.undoSavingsAccountTransaction(fixedDepositAccountId, transactionId).build();
160+
final CommandWrapper commandRequest = builder.undoFixedDepositAccountTransaction(fixedDepositAccountId, transactionId).build();
161161
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
162162
} else if (is(commandParam, DepositsApiConstants.COMMAND_ADJUST_TRANSACTION)) {
163163
final CommandWrapper commandRequest = builder.adjustSavingsAccountTransaction(fixedDepositAccountId, transactionId).build();

fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -542,10 +542,69 @@ private void postInterest(final SavingsAccount account) {
542542
}
543543

544544
@Override
545-
public CommandProcessingResult undoFDTransaction(final Long savingsId, @SuppressWarnings("unused") final Long transactionId,
546-
@SuppressWarnings("unused") final boolean allowAccountTransferModification) {
545+
public CommandProcessingResult undoFDTransaction(final Long savingsId, final Long transactionId,
546+
final boolean allowAccountTransferModification) {
547+
548+
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
549+
.isSavingsInterestPostingAtCurrentPeriodEnd();
550+
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
551+
552+
final FixedDepositAccount account = (FixedDepositAccount) this.depositAccountAssembler.assembleFrom(savingsId,
553+
DepositAccountType.FIXED_DEPOSIT);
554+
final Set<Long> existingTransactionIds = new HashSet<>();
555+
final Set<Long> existingReversedTransactionIds = new HashSet<>();
556+
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
557+
558+
final SavingsAccountTransaction savingsAccountTransaction = this.savingsAccountTransactionRepository
559+
.findOneByIdAndSavingsAccountId(transactionId, savingsId);
560+
if (savingsAccountTransaction == null) {
561+
throw new SavingsAccountTransactionNotFoundException(savingsId, transactionId);
562+
}
563+
564+
if (!allowAccountTransferModification
565+
&& this.accountTransfersReadPlatformService.isAccountTransfer(transactionId, PortfolioAccountType.SAVINGS)) {
566+
throw new PlatformServiceUnavailableException("error.msg.fixed.deposit.account.transfer.transaction.update.not.allowed",
567+
"Fixed deposit account transaction:" + transactionId + " update not allowed as it involves in account transfer",
568+
transactionId);
569+
}
570+
571+
final LocalDate today = DateUtils.getBusinessLocalDate();
572+
final MathContext mc = MathContext.DECIMAL64;
573+
574+
if (!account.isTransactionsAllowed()) {
575+
throwValidationForActiveStatus(SavingsApiConstants.undoTransactionAction);
576+
}
577+
account.undoTransaction(transactionId);
578+
boolean isInterestTransfer = false;
579+
LocalDate postInterestOnDate = null;
580+
checkClientOrGroupActive(account);
581+
final boolean backdatedTxnsAllowedTill = false;
582+
final boolean postReversals = false;
583+
if (savingsAccountTransaction.isPostInterestCalculationRequired()
584+
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.getTransactionDate(), false)) {
585+
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
586+
postInterestOnDate, backdatedTxnsAllowedTill);
587+
} else {
588+
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
589+
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
590+
}
591+
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
592+
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
593+
depositAccountOnHoldTransactions = this.depositAccountOnHoldTransactionRepository
594+
.findBySavingsAccountAndReversedFalseOrderByCreatedDateAsc(account);
595+
}
596+
597+
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction, depositAccountOnHoldTransactions,
598+
false);
599+
final boolean isPreMatureClosure = false;
600+
account.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
601+
financialYearBeginningMonth);
602+
603+
this.savingAccountRepositoryWrapper.saveAndFlush(account);
604+
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
547605

548-
throw new DepositAccountTransactionNotAllowedException(savingsId, "undo", DepositAccountType.FIXED_DEPOSIT);
606+
return new CommandProcessingResultBuilder().withEntityId(savingsId).withOfficeId(account.officeId())
607+
.withClientId(account.clientId()).withGroupId(account.groupId()).withSavingsId(savingsId).build();
549608
}
550609

551610
@Override

integration-tests/src/test/java/org/apache/fineract/integrationtests/FixedDepositTest.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2952,6 +2952,73 @@ private Integer createTaxGroup(final String percentage, final Account liabilityA
29522952
/**
29532953
* Delete the Liability transfer account
29542954
*/
2955+
@Test
2956+
public void testFixedDepositAccountUndoTransaction() {
2957+
this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec);
2958+
this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec);
2959+
2960+
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US);
2961+
2962+
Calendar todaysDate = Calendar.getInstance();
2963+
todaysDate.add(Calendar.MONTH, -3);
2964+
final String VALID_FROM = dateFormat.format(todaysDate.getTime());
2965+
todaysDate.add(Calendar.YEAR, 10);
2966+
final String VALID_TO = dateFormat.format(todaysDate.getTime());
2967+
2968+
todaysDate = Calendar.getInstance();
2969+
todaysDate.add(Calendar.MONTH, -1);
2970+
final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate.getTime());
2971+
final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime());
2972+
final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime());
2973+
2974+
Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
2975+
Assertions.assertNotNull(clientId);
2976+
2977+
final String accountingRule = NONE;
2978+
Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule);
2979+
Assertions.assertNotNull(fixedDepositProductId);
2980+
2981+
Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(),
2982+
SUBMITTED_ON_DATE, WHOLE_TERM);
2983+
Assertions.assertNotNull(fixedDepositAccountId);
2984+
2985+
HashMap fixedDepositAccountStatusHashMap = FixedDepositAccountStatusChecker.getStatusOfFixedDepositAccount(this.requestSpec,
2986+
this.responseSpec, fixedDepositAccountId.toString());
2987+
FixedDepositAccountStatusChecker.verifyFixedDepositIsPending(fixedDepositAccountStatusHashMap);
2988+
2989+
fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.approveFixedDeposit(fixedDepositAccountId, APPROVED_ON_DATE);
2990+
FixedDepositAccountStatusChecker.verifyFixedDepositIsApproved(fixedDepositAccountStatusHashMap);
2991+
2992+
fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.activateFixedDeposit(fixedDepositAccountId, ACTIVATION_DATE);
2993+
FixedDepositAccountStatusChecker.verifyFixedDepositIsActive(fixedDepositAccountStatusHashMap);
2994+
2995+
this.fixedDepositAccountHelper.calculateInterestForFixedDeposit(fixedDepositAccountId);
2996+
2997+
Integer postInterestResult = this.fixedDepositAccountHelper.postInterestForFixedDeposit(fixedDepositAccountId);
2998+
Assertions.assertNotNull(postInterestResult);
2999+
3000+
ArrayList transactions = this.fixedDepositAccountHelper.getFixedDepositTransactions(fixedDepositAccountId);
3001+
Assertions.assertNotNull(transactions);
3002+
3003+
Integer interestTransactionId = null;
3004+
for (Object txnObj : transactions) {
3005+
HashMap txn = (HashMap) txnObj;
3006+
HashMap txnType = (HashMap) txn.get("transactionType");
3007+
if (Boolean.TRUE.equals(txnType.get("interestPosting"))) {
3008+
interestTransactionId = (Integer) txn.get("id");
3009+
break;
3010+
}
3011+
}
3012+
Assertions.assertNotNull(interestTransactionId);
3013+
3014+
Integer undoResult = this.fixedDepositAccountHelper.undoFixedDepositTransaction(fixedDepositAccountId, interestTransactionId);
3015+
Assertions.assertNotNull(undoResult);
3016+
3017+
HashMap accountSummary = this.fixedDepositAccountHelper.getFixedDepositSummary(fixedDepositAccountId);
3018+
Float totalInterestPosted = (Float) accountSummary.get("totalInterestPosted");
3019+
Assertions.assertEquals(0f, totalInterestPosted, 0.01f);
3020+
}
3021+
29553022
@AfterEach
29563023
public void tearDown() {
29573024
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();

integration-tests/src/test/java/org/apache/fineract/integrationtests/common/fixeddeposit/FixedDepositAccountHelper.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,4 +636,29 @@ public FixedDepositAccountHelper withCharges(List<HashMap<String, String>> charg
636636
this.charges = charges;
637637
return this;
638638
}
639+
640+
// TODO: Rewrite to use fineract-client instead!
641+
// Example: org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper.disburseLoan(java.lang.Long,
642+
// org.apache.fineract.client.models.PostLoansLoanIdRequest)
643+
@Deprecated(forRemoval = true)
644+
public ArrayList getFixedDepositTransactions(final Integer fixedDepositAccountId) {
645+
LOG.info("-------------------- RETRIEVING FIXED DEPOSIT TRANSACTIONS ---------------------");
646+
final String url = FIXED_DEPOSIT_ACCOUNT_URL + "/" + fixedDepositAccountId + "?associations=transactions&"
647+
+ Utils.TENANT_IDENTIFIER;
648+
HashMap accountDetails = Utils.performServerGet(this.requestSpec, this.responseSpec, url, "");
649+
return (ArrayList) accountDetails.get("transactions");
650+
}
651+
652+
// TODO: Rewrite to use fineract-client instead!
653+
// Example: org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper.disburseLoan(java.lang.Long,
654+
// org.apache.fineract.client.models.PostLoansLoanIdRequest)
655+
@Deprecated(forRemoval = true)
656+
public Integer undoFixedDepositTransaction(final Integer fixedDepositAccountId, final Integer transactionId) {
657+
LOG.info("--------------------------------- UNDO FIXED DEPOSIT TRANSACTION --------------------------------");
658+
final String undoTransactionUrl = FIXED_DEPOSIT_ACCOUNT_URL + "/" + fixedDepositAccountId + "/transactions/" + transactionId
659+
+ "?command=undo&" + Utils.TENANT_IDENTIFIER;
660+
return (Integer) Utils.performServerPost(this.requestSpec, this.responseSpec, undoTransactionUrl, "{}",
661+
CommonConstants.RESPONSE_RESOURCE_ID);
662+
}
663+
639664
}

0 commit comments

Comments
 (0)