feat(cashier): add server-side pagination and date ordering to GL entries endpoint
- Add offset/limit query params with defaults (limit=20, offset=0) - Return totalFilteredRecords + pageItems response structure - Compute totalDr/totalCr from all records (not just current page) - Fix ordering: ORDER BY MAX(created_at) for correct chronological sort Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
19639c9e02
commit
db94056144
+47
-25
@@ -558,34 +558,59 @@ public class CashReportApiResource {
|
||||
@Path("gl-entries")
|
||||
public String glEntries(@QueryParam("date") String date,
|
||||
@QueryParam("cashierId") Long cashierId,
|
||||
@QueryParam("tellerId") Long tellerId) {
|
||||
@QueryParam("tellerId") Long tellerId,
|
||||
@QueryParam("offset") Integer offset,
|
||||
@QueryParam("limit") Integer limit) {
|
||||
|
||||
final String txnDate = (date != null && !date.isBlank()) ? date : LocalDate.now().toString();
|
||||
final int resolvedLimit = (limit != null && limit > 0) ? limit : 20;
|
||||
final int resolvedOffset = (offset != null && offset >= 0) ? offset : 0;
|
||||
|
||||
// Build cashier officer_id filter
|
||||
String officerFilter;
|
||||
Object[] params;
|
||||
Object[] baseParams;
|
||||
|
||||
if (cashierId != null) {
|
||||
officerFilter = "AND std.officer_id IN ("
|
||||
+ "SELECT au.id FROM m_appuser au "
|
||||
+ "JOIN m_cashiers mc ON mc.staff_id = au.staff_id WHERE mc.id = ?)";
|
||||
params = new Object[] { txnDate, cashierId };
|
||||
baseParams = new Object[] { txnDate, cashierId };
|
||||
} else if (tellerId != null) {
|
||||
officerFilter = "AND std.officer_id IN ("
|
||||
+ "SELECT au.id FROM m_appuser au "
|
||||
+ "JOIN m_cashiers mc ON mc.staff_id = au.staff_id "
|
||||
+ "JOIN m_tellers mt ON mt.id = mc.teller_id WHERE mt.id = ?)";
|
||||
params = new Object[] { txnDate, tellerId };
|
||||
baseParams = new Object[] { txnDate, tellerId };
|
||||
} else {
|
||||
officerFilter = "AND std.officer_id IN ("
|
||||
+ "SELECT au.id FROM m_appuser au "
|
||||
+ "JOIN m_cashiers mc ON mc.staff_id = au.staff_id)";
|
||||
params = new Object[] { txnDate };
|
||||
baseParams = new Object[] { txnDate };
|
||||
}
|
||||
|
||||
// One row per transaction — account no, account holder name, dr/cr amount, date, teller, payment type
|
||||
final String sql = "SELECT "
|
||||
// Base grouped query (reused for count, totals, and paged data)
|
||||
final String baseGroupSql = "FROM m_savings_txn_denomination std "
|
||||
+ "LEFT JOIN m_client mc ON mc.id = std.client_id "
|
||||
+ "WHERE std.txn_date = CAST(? AS DATE) "
|
||||
+ officerFilter
|
||||
+ " GROUP BY std.txn_id, std.account_no, mc.display_name, std.cif_no ";
|
||||
|
||||
// 1. Count + totals for all matching records (no pagination)
|
||||
final String totalsSql = "SELECT COUNT(*) AS total_count, "
|
||||
+ " COALESCE(SUM(dr_amount), 0) AS total_dr, "
|
||||
+ " COALESCE(SUM(cr_amount), 0) AS total_cr "
|
||||
+ "FROM (SELECT "
|
||||
+ " SUM(CASE WHEN std.txn_type = 'WITHDRAWAL' THEN std.total_amount ELSE 0 END) AS dr_amount, "
|
||||
+ " SUM(CASE WHEN std.txn_type = 'DEPOSIT' THEN std.total_amount ELSE 0 END) AS cr_amount "
|
||||
+ baseGroupSql + ") sub";
|
||||
|
||||
final Map<String, Object> totalsRow = jdbcTemplate.queryForMap(totalsSql, baseParams);
|
||||
final long totalFilteredRecords = ((Number) totalsRow.get("total_count")).longValue();
|
||||
final java.math.BigDecimal totalDr = (java.math.BigDecimal) totalsRow.get("total_dr");
|
||||
final java.math.BigDecimal totalCr = (java.math.BigDecimal) totalsRow.get("total_cr");
|
||||
|
||||
// 2. Paged data query
|
||||
final String dataSql = "SELECT "
|
||||
+ " std.txn_id AS voucher_no, "
|
||||
+ " std.account_no AS ac_no, "
|
||||
+ " COALESCE(mc.display_name, std.cif_no, '') AS ac_name, "
|
||||
@@ -596,15 +621,18 @@ public class CashReportApiResource {
|
||||
+ " CASE WHEN MAX(std.client_id) IS NULL THEN 'GL' ELSE 'SAVINGS' END AS txn_source, "
|
||||
+ " SUM(CASE WHEN std.txn_type = 'WITHDRAWAL' THEN std.total_amount ELSE 0 END) AS dr_amount, "
|
||||
+ " SUM(CASE WHEN std.txn_type = 'DEPOSIT' THEN std.total_amount ELSE 0 END) AS cr_amount "
|
||||
+ "FROM m_savings_txn_denomination std "
|
||||
+ "LEFT JOIN m_client mc ON mc.id = std.client_id "
|
||||
+ "WHERE std.txn_date = CAST(? AS DATE) "
|
||||
+ officerFilter
|
||||
+ " GROUP BY std.txn_id, std.account_no, mc.display_name, std.cif_no "
|
||||
+ "ORDER BY std.txn_id NULLS LAST, MAX(std.created_at)";
|
||||
+ baseGroupSql
|
||||
+ "ORDER BY MAX(std.created_at) "
|
||||
+ "LIMIT ? OFFSET ?";
|
||||
|
||||
List<Map<String, Object>> rows = jdbcTemplate.query(sql, (rs, rowNum) -> {
|
||||
Map<String, Object> row = new LinkedHashMap<>();
|
||||
// Append limit and offset to params
|
||||
final Object[] pagedParams = new Object[baseParams.length + 2];
|
||||
System.arraycopy(baseParams, 0, pagedParams, 0, baseParams.length);
|
||||
pagedParams[baseParams.length] = resolvedLimit;
|
||||
pagedParams[baseParams.length + 1] = resolvedOffset;
|
||||
|
||||
final List<Map<String, Object>> pageItems = jdbcTemplate.query(dataSql, (rs, rowNum) -> {
|
||||
final Map<String, Object> row = new LinkedHashMap<>();
|
||||
row.put("voucherNo", rs.getLong("voucher_no"));
|
||||
row.put("acNo", rs.getString("ac_no"));
|
||||
row.put("acName", rs.getString("ac_name"));
|
||||
@@ -616,18 +644,12 @@ public class CashReportApiResource {
|
||||
row.put("dr", rs.getBigDecimal("dr_amount"));
|
||||
row.put("cr", rs.getBigDecimal("cr_amount"));
|
||||
return row;
|
||||
}, params);
|
||||
}, pagedParams);
|
||||
|
||||
java.math.BigDecimal totalDr = rows.stream()
|
||||
.map(r -> (java.math.BigDecimal) r.get("dr"))
|
||||
.reduce(java.math.BigDecimal.ZERO, java.math.BigDecimal::add);
|
||||
java.math.BigDecimal totalCr = rows.stream()
|
||||
.map(r -> (java.math.BigDecimal) r.get("cr"))
|
||||
.reduce(java.math.BigDecimal.ZERO, java.math.BigDecimal::add);
|
||||
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
final Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("date", txnDate);
|
||||
result.put("rows", rows);
|
||||
result.put("totalFilteredRecords", totalFilteredRecords);
|
||||
result.put("pageItems", pageItems);
|
||||
result.put("totalDr", totalDr);
|
||||
result.put("totalCr", totalCr);
|
||||
return gson.toJson(result);
|
||||
|
||||
Reference in New Issue
Block a user