fix(shares): skip zero-value redeem transaction on account close
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
Closing a share account that already has zero approved shares no longer synthesizes a redeem transaction, so it stops posting a meaningless ₹0.00/₹0.00 GL journal-entry pair. Save/note-capture on close now happen unconditionally instead of being gated on a transaction existing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+12
-6
@@ -1139,13 +1139,19 @@ public class ShareAccountDataSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AppUser approvedUser = this.platformSecurityContext.authenticatedUser();
|
AppUser approvedUser = this.platformSecurityContext.authenticatedUser();
|
||||||
final BigDecimal unitPrice = account.getShareProduct().deriveMarketPrice(DateUtils.getBusinessLocalDate());
|
// Only synthesize a redeem transaction (and its GL posting) when shares actually remain to
|
||||||
ShareAccountTransaction transaction = ShareAccountTransaction.createRedeemTransaction(closedDate, account.getTotalApprovedShares(),
|
// be redeemed — an account closed after every share was already withdrawn has nothing left
|
||||||
unitPrice);
|
// to force-redeem, and posting a zero-share/zero-value transaction just clutters the GL with
|
||||||
account.addAdditionalPurchasedShares(transaction);
|
// a meaningless ₹0.00/₹0.00 entry pair.
|
||||||
|
final Long remainingShares = account.getTotalApprovedShares();
|
||||||
|
if (remainingShares != null && remainingShares > 0) {
|
||||||
|
final BigDecimal unitPrice = account.getShareProduct().deriveMarketPrice(DateUtils.getBusinessLocalDate());
|
||||||
|
ShareAccountTransaction transaction = ShareAccountTransaction.createRedeemTransaction(closedDate, remainingShares, unitPrice);
|
||||||
|
account.addAdditionalPurchasedShares(transaction);
|
||||||
|
handleRedeemSharesChargeTransactions(account, transaction);
|
||||||
|
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, transaction);
|
||||||
|
}
|
||||||
account.close(closedDate, approvedUser);
|
account.close(closedDate, approvedUser);
|
||||||
handleRedeemSharesChargeTransactions(account, transaction);
|
|
||||||
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, transaction);
|
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-12
@@ -484,23 +484,25 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
try {
|
try {
|
||||||
ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
|
ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
|
||||||
Map<String, Object> changes = this.accountDataSerializer.validateAndClose(jsonCommand, account);
|
Map<String, Object> changes = this.accountDataSerializer.validateAndClose(jsonCommand, account);
|
||||||
if (!changes.isEmpty()) {
|
// Account status/closedDate are applied regardless of whether there was anything left to
|
||||||
this.shareAccountRepository.saveAndFlush(account);
|
// redeem — save and note-capture must not be gated on a transaction actually existing.
|
||||||
final String noteText = jsonCommand.stringValueOfParameterNamed("note");
|
this.shareAccountRepository.saveAndFlush(account);
|
||||||
if (StringUtils.isNotBlank(noteText)) {
|
final String noteText = jsonCommand.stringValueOfParameterNamed("note");
|
||||||
final Note note = Note.shareNote(account, noteText);
|
if (StringUtils.isNotBlank(noteText)) {
|
||||||
changes.put("note", noteText);
|
final Note note = Note.shareNote(account, noteText);
|
||||||
this.noteRepository.save(note);
|
this.noteRepository.save(note);
|
||||||
}
|
}
|
||||||
ShareAccountTransaction transaction = (ShareAccountTransaction) changes
|
// Only closures that actually redeemed remaining shares carry a transaction to post GL
|
||||||
.get(ShareAccountApiConstants.requestedshares_paramname);
|
// entries for — an account already at zero shares has none, and posting a zero-value
|
||||||
transaction = account.getShareAccountTransaction(transaction);
|
// transaction would just add a meaningless ₹0.00/₹0.00 entry pair to the GL.
|
||||||
|
final Object transactionChange = changes.get(ShareAccountApiConstants.requestedshares_paramname);
|
||||||
|
if (transactionChange instanceof ShareAccountTransaction) {
|
||||||
|
ShareAccountTransaction transaction = account.getShareAccountTransaction((ShareAccountTransaction) transactionChange);
|
||||||
Set<ShareAccountTransaction> transactions = new HashSet<>();
|
Set<ShareAccountTransaction> transactions = new HashSet<>();
|
||||||
transactions.add(transaction);
|
transactions.add(transaction);
|
||||||
this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, transactions));
|
this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, transactions));
|
||||||
changes.clear();
|
changes.clear();
|
||||||
changes.put(ShareAccountApiConstants.requestedshares_paramname, transaction.getId());
|
changes.put(ShareAccountApiConstants.requestedshares_paramname, transaction.getId());
|
||||||
|
|
||||||
}
|
}
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(jsonCommand.commandId()) //
|
.withCommandId(jsonCommand.commandId()) //
|
||||||
|
|||||||
Reference in New Issue
Block a user