feat(cashier): add GL denomination tracking, live GL balance, and enhanced closing report

- Add CashierGlDenominationApiResource: new POST /v1/cashier/gl-denomination endpoint
  to record denomination breakdown for GL journal entries in m_savings_txn_denomination
- Fix GL account real-time balance in GLAccountReadPlatformServiceImpl using live SUM query
- Add Liquibase migrations 0318/0319/0320: make savings_account_id and txn_id nullable,
  add payment_type column to m_savings_txn_denomination
- Add validCheckSum to 0317b changeset to resolve checksum mismatch on existing installs
- Enhance GL entries closing report SQL with date, time, teller, payment type, txn source

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jaanu423
2026-06-10 15:31:12 +05:30
co-authored by Claude Sonnet 4.6
parent 53b6a94bf8
commit 19639c9e02
9 changed files with 299 additions and 10 deletions
@@ -200,12 +200,21 @@ public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformSe
final StringBuilder sql = new StringBuilder();
sql.append("select ").append(rm.schema());
sql.append(" where gl.id = ?");
if (associationParametersData.isRunningBalanceRequired()) {
sql.append(" and gl_j.is_running_balance_calculated = true ")
.append(" ORDER BY gl_j.entry_date DESC,gl_j.id DESC LIMIT 1");
final GLAccountData glAccount = this.jdbcTemplate.queryForObject(sql.toString(), rm, new Object[] { glAccountId });
// Live balance: sum all non-reversed journal entries so cashier sees real-time balance
// without waiting for the "Update Accounting Running Balances" scheduled job.
if (associationParametersData != null && associationParametersData.isRunningBalanceRequired() && glAccount != null) {
final String liveBalanceSql = "SELECT COALESCE(ABS(SUM(CASE WHEN type_enum = 2 THEN amount ELSE -amount END)), 0) "
+ "FROM acc_gl_journal_entry "
+ "WHERE account_id = ? AND (reversed = false OR reversed IS NULL)";
final java.math.BigDecimal liveBalance = this.jdbcTemplate.queryForObject(liveBalanceSql,
java.math.BigDecimal.class, glAccountId);
glAccount.setOrganizationRunningBalance(liveBalance != null ? liveBalance.longValue() : 0L);
}
return this.jdbcTemplate.queryForObject(sql.toString(), rm, new Object[] { glAccountId });
return glAccount;
} catch (final EmptyResultDataAccessException e) {
throw new GLAccountNotFoundException(glAccountId, e);
}