updade code based on the accounting deatils search
This commit is contained in:
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.fineract.accounting.journalentry.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DayWiseSummaryData {
|
||||
|
||||
private LocalDate date;
|
||||
private BigDecimal openingBalance;
|
||||
private BigDecimal totalDebit;
|
||||
private BigDecimal totalCredit;
|
||||
private BigDecimal netMovement;
|
||||
private BigDecimal closingBalance;
|
||||
private int entryCount;
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.fineract.accounting.journalentry.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
||||
import org.apache.fineract.infrastructure.core.service.Page;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class GLAccountLedgerReportData {
|
||||
|
||||
/** GL Account details (name, code, type, description, usage) */
|
||||
private GLAccountData glAccount;
|
||||
|
||||
/** Balance of the account before the fromDate (0 if no fromDate or no glAccountId) */
|
||||
private BigDecimal openingBalance;
|
||||
|
||||
/** Balance of the account as of toDate = openingBalance + netMovement */
|
||||
private BigDecimal closingBalance;
|
||||
|
||||
/** Sum of all DEBIT entries in the requested period */
|
||||
private BigDecimal totalDebit;
|
||||
|
||||
/** Sum of all CREDIT entries in the requested period */
|
||||
private BigDecimal totalCredit;
|
||||
|
||||
/**
|
||||
* Net movement: for ASSET/EXPENSE (debit-normal) = totalDebit - totalCredit;
|
||||
* for LIABILITY/INCOME/EQUITY (credit-normal) = totalCredit - totalDebit
|
||||
*/
|
||||
private BigDecimal netMovement;
|
||||
|
||||
/** true for ASSET and EXPENSE accounts (debit-normal balance convention) */
|
||||
private boolean debitNormal;
|
||||
|
||||
private LocalDate fromDate;
|
||||
private LocalDate toDate;
|
||||
|
||||
/** Day-wise breakdown of balances for the period */
|
||||
private List<DayWiseSummaryData> dayWiseSummary;
|
||||
|
||||
/** Total number of journal entries matching the filter (for the KPI card) */
|
||||
private long totalEntries;
|
||||
|
||||
/** Paginated journal entries for the period */
|
||||
private Page<JournalEntryData> entries;
|
||||
}
|
||||
+8
@@ -19,6 +19,7 @@
|
||||
package org.apache.fineract.accounting.journalentry.service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.accounting.journalentry.data.GLAccountLedgerReportData;
|
||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryAssociationParametersData;
|
||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryData;
|
||||
import org.apache.fineract.accounting.journalentry.data.OfficeOpeningBalancesData;
|
||||
@@ -36,4 +37,11 @@ public interface JournalEntryReadPlatformService {
|
||||
OfficeOpeningBalancesData retrieveOfficeOpeningBalances(Long officeId, String currencyCode);
|
||||
|
||||
Page<JournalEntryData> retrieveJournalEntriesByEntityId(String transactionId, Long entityId, Integer entityType);
|
||||
|
||||
/**
|
||||
* CBS GL Ledger Report: returns opening balance, day-wise summary, and paginated entries for a GL account.
|
||||
* Opening balance is computed as the net balance of all entries before fromDate.
|
||||
*/
|
||||
GLAccountLedgerReportData retrieveGLAccountLedger(Long glAccountId, Long officeId, Boolean onlyManualEntries,
|
||||
LocalDate fromDate, LocalDate toDate, String transactionId, SearchParameters searchParameters);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+811
-22449
File diff suppressed because it is too large
Load Diff
+52
@@ -44,6 +44,7 @@ import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.accounting.journalentry.command.JournalEntryCommand;
|
||||
import org.apache.fineract.accounting.journalentry.data.GLAccountLedgerReportData;
|
||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryAssociationParametersData;
|
||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryData;
|
||||
import org.apache.fineract.accounting.journalentry.data.OfficeOpeningBalancesData;
|
||||
@@ -268,6 +269,57 @@ public class JournalEntriesApiResource {
|
||||
return this.apiJsonSerializerService.serialize(settings, officeOpeningBalancesData);
|
||||
}
|
||||
|
||||
/**
|
||||
* CBS GL Account Ledger Report — returns opening balance, day-wise summary,
|
||||
* period totals, and paginated entries for a given GL account and date range.
|
||||
*
|
||||
* GET /journalentries/ledger?glAccountId=5&fromDate=01 Jan 2025&toDate=31 Jan 2025&dateFormat=dd MMM yyyy&locale=en
|
||||
*/
|
||||
@GET
|
||||
@Path("ledger")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "GL Account Ledger Report",
|
||||
description = "Returns opening balance, day-wise running balance summary, period totals, and paginated journal entries for a GL account.")
|
||||
public String retrieveGLAccountLedger(@Context final UriInfo uriInfo,
|
||||
@QueryParam("glAccountId") @Parameter(description = "glAccountId") final Long glAccountId,
|
||||
@QueryParam("officeId") @Parameter(description = "officeId") final Long officeId,
|
||||
@QueryParam("manualEntriesOnly") @Parameter(description = "manualEntriesOnly") final Boolean onlyManualEntries,
|
||||
@QueryParam("fromDate") @Parameter(description = "fromDate") final DateParam fromDateParam,
|
||||
@QueryParam("toDate") @Parameter(description = "toDate") final DateParam toDateParam,
|
||||
@QueryParam("transactionId") @Parameter(description = "transactionId") final String transactionId,
|
||||
@QueryParam("offset") @Parameter(description = "offset") final Integer offset,
|
||||
@QueryParam("limit") @Parameter(description = "limit") final Integer limit,
|
||||
@QueryParam("orderBy") @Parameter(description = "orderBy") final String orderBy,
|
||||
@QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder,
|
||||
@QueryParam("locale") @Parameter(description = "locale") final String locale,
|
||||
@QueryParam("dateFormat") @Parameter(description = "dateFormat") final String rawDateFormat) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION);
|
||||
|
||||
final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ? null : new DateFormat(rawDateFormat);
|
||||
LocalDate fromDate = null;
|
||||
if (fromDateParam != null) {
|
||||
fromDate = fromDateParam.getDate("fromDate", dateFormat, locale);
|
||||
}
|
||||
LocalDate toDate = null;
|
||||
if (toDateParam != null) {
|
||||
toDate = toDateParam.getDate("toDate", dateFormat, locale);
|
||||
}
|
||||
|
||||
sqlValidator.validate(orderBy);
|
||||
sqlValidator.validate(sortOrder);
|
||||
final SearchParameters searchParameters = SearchParameters.builder()
|
||||
.limit(limit).officeId(officeId).offset(offset)
|
||||
.orderBy(orderBy).sortOrder(sortOrder).build();
|
||||
|
||||
final GLAccountLedgerReportData ledgerData = this.journalEntryReadPlatformService
|
||||
.retrieveGLAccountLedger(glAccountId, officeId, onlyManualEntries, fromDate, toDate, transactionId, searchParameters);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.apiJsonSerializerService.serialize(settings, ledgerData);
|
||||
}
|
||||
|
||||
private boolean is(final String commandParam, final String commandValue) {
|
||||
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
|
||||
}
|
||||
|
||||
+225
-10
@@ -28,6 +28,7 @@ import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -37,6 +38,8 @@ import org.apache.fineract.accounting.financialactivityaccount.domain.FinancialA
|
||||
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
|
||||
import org.apache.fineract.accounting.glaccount.service.GLAccountReadPlatformService;
|
||||
import org.apache.fineract.accounting.journalentry.data.DayWiseSummaryData;
|
||||
import org.apache.fineract.accounting.journalentry.data.GLAccountLedgerReportData;
|
||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryAssociationParametersData;
|
||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryData;
|
||||
import org.apache.fineract.accounting.journalentry.data.OfficeOpeningBalancesData;
|
||||
@@ -213,16 +216,20 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
||||
|
||||
TransactionTypeEnumData transactionTypeEnumData = null;
|
||||
|
||||
if (PortfolioAccountType.fromInt(entityTypeId).isLoanAccount()) {
|
||||
final LoanTransactionEnumData loanTransactionType = LoanEnumerations
|
||||
.transactionType(JdbcSupport.getInteger(rs, "loanTransactionType"));
|
||||
transactionTypeEnumData = new TransactionTypeEnumData(loanTransactionType.getId(), loanTransactionType.getCode(),
|
||||
loanTransactionType.getValue());
|
||||
} else if (PortfolioAccountType.fromInt(entityTypeId).isSavingsAccount()) {
|
||||
final SavingsAccountTransactionEnumData savingsTransactionType = SavingsEnumerations
|
||||
.transactionType(JdbcSupport.getInteger(rs, "savingsTransactionType"));
|
||||
transactionTypeEnumData = new TransactionTypeEnumData(savingsTransactionType.getId(), savingsTransactionType.getCode(),
|
||||
savingsTransactionType.getValue());
|
||||
if (entityTypeId != null && PortfolioAccountType.fromInt(entityTypeId).isLoanAccount()) {
|
||||
final Integer loanTxnTypeId = JdbcSupport.getInteger(rs, "loanTransactionType");
|
||||
if (loanTxnTypeId != null) {
|
||||
final LoanTransactionEnumData loanTransactionType = LoanEnumerations.transactionType(loanTxnTypeId);
|
||||
transactionTypeEnumData = new TransactionTypeEnumData(loanTransactionType.getId(), loanTransactionType.getCode(),
|
||||
loanTransactionType.getValue());
|
||||
}
|
||||
} else if (entityTypeId != null && PortfolioAccountType.fromInt(entityTypeId).isSavingsAccount()) {
|
||||
final Integer savingsTxnTypeId = JdbcSupport.getInteger(rs, "savingsTransactionType");
|
||||
if (savingsTxnTypeId != null) {
|
||||
final SavingsAccountTransactionEnumData savingsTransactionType = SavingsEnumerations.transactionType(savingsTxnTypeId);
|
||||
transactionTypeEnumData = new TransactionTypeEnumData(savingsTransactionType.getId(), savingsTransactionType.getCode(),
|
||||
savingsTransactionType.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
transactionDetailData = new TransactionDetailData(transaction, paymentDetailData, noteData, transactionTypeEnumData);
|
||||
@@ -539,4 +546,212 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
||||
throw new JournalEntriesNotFoundException(entityId, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GLAccountLedgerReportData retrieveGLAccountLedger(final Long glAccountId, final Long officeId,
|
||||
final Boolean onlyManualEntries, final LocalDate fromDate, final LocalDate toDate,
|
||||
final String transactionId, final SearchParameters searchParameters) {
|
||||
|
||||
// ── 1. Fetch GL Account details ──────────────────────────────────────
|
||||
GLAccountData glAccountData = null;
|
||||
boolean isDebitNormal = true; // ASSET / EXPENSE = debit-normal
|
||||
if (glAccountId != null && glAccountId > 0) {
|
||||
glAccountData = this.glAccountReadPlatformService.retrieveGLAccountById(glAccountId,
|
||||
new JournalEntryAssociationParametersData());
|
||||
if (glAccountData != null && glAccountData.getType() != null) {
|
||||
final int typeId = glAccountData.getType().getId().intValue();
|
||||
// 1=ASSET, 2=LIABILITY, 3=EQUITY, 4=INCOME, 5=EXPENSE
|
||||
isDebitNormal = (typeId == 1 || typeId == 5);
|
||||
}
|
||||
}
|
||||
|
||||
// ── 2. Compute opening balance (all entries before fromDate) ─────────
|
||||
BigDecimal openingBalance = BigDecimal.ZERO;
|
||||
if (glAccountId != null && glAccountId > 0 && fromDate != null) {
|
||||
final List<Object> obParams = new ArrayList<>();
|
||||
final StringBuilder obSql = new StringBuilder(
|
||||
"SELECT COALESCE(SUM(CASE WHEN je.type_enum = 2 THEN je.amount ELSE 0 END), 0) AS ob_debit, "
|
||||
+ "COALESCE(SUM(CASE WHEN je.type_enum = 1 THEN je.amount ELSE 0 END), 0) AS ob_credit "
|
||||
+ "FROM acc_gl_journal_entry je "
|
||||
+ "WHERE je.account_id = ? AND je.entry_date < ?");
|
||||
obParams.add(glAccountId);
|
||||
obParams.add(fromDate);
|
||||
if (officeId != null && officeId > 0) {
|
||||
obSql.append(" AND je.office_id = ?");
|
||||
obParams.add(officeId);
|
||||
}
|
||||
final BigDecimal[] ob = this.jdbcTemplate.queryForObject(obSql.toString(),
|
||||
(rs, rowNum) -> new BigDecimal[]{
|
||||
Objects.requireNonNullElse(rs.getBigDecimal("ob_debit"), BigDecimal.ZERO),
|
||||
Objects.requireNonNullElse(rs.getBigDecimal("ob_credit"), BigDecimal.ZERO)
|
||||
}, obParams.toArray());
|
||||
if (ob != null) {
|
||||
openingBalance = isDebitNormal ? ob[0].subtract(ob[1]) : ob[1].subtract(ob[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// ── 3. Day-wise summary for the period ───────────────────────────────
|
||||
final List<DayWiseSummaryData> dayWiseSummary = new ArrayList<>();
|
||||
{
|
||||
final List<Object> dwParams = new ArrayList<>();
|
||||
final StringBuilder dwSql = new StringBuilder(
|
||||
"SELECT je.entry_date AS dw_date, "
|
||||
+ "COALESCE(SUM(CASE WHEN je.type_enum = 2 THEN je.amount ELSE 0 END), 0) AS dw_debit, "
|
||||
+ "COALESCE(SUM(CASE WHEN je.type_enum = 1 THEN je.amount ELSE 0 END), 0) AS dw_credit, "
|
||||
+ "COUNT(*) AS dw_count "
|
||||
+ "FROM acc_gl_journal_entry je "
|
||||
+ "WHERE 1=1");
|
||||
if (glAccountId != null && glAccountId > 0) {
|
||||
dwSql.append(" AND je.account_id = ?");
|
||||
dwParams.add(glAccountId);
|
||||
}
|
||||
if (officeId != null && officeId > 0) {
|
||||
dwSql.append(" AND je.office_id = ?");
|
||||
dwParams.add(officeId);
|
||||
}
|
||||
if (fromDate != null) {
|
||||
dwSql.append(" AND je.entry_date >= ?");
|
||||
dwParams.add(fromDate);
|
||||
}
|
||||
if (toDate != null) {
|
||||
dwSql.append(" AND je.entry_date <= ?");
|
||||
dwParams.add(toDate);
|
||||
}
|
||||
if (onlyManualEntries != null && onlyManualEntries) {
|
||||
dwSql.append(" AND je.manual_entry = true");
|
||||
}
|
||||
dwSql.append(" GROUP BY je.entry_date ORDER BY je.entry_date ASC");
|
||||
|
||||
final boolean debitNormalFinal = isDebitNormal;
|
||||
final List<Map<String, Object>> rows = this.jdbcTemplate.queryForList(dwSql.toString(), dwParams.toArray());
|
||||
|
||||
BigDecimal running = openingBalance;
|
||||
for (final Map<String, Object> row : rows) {
|
||||
// Handle both java.sql.Date (older drivers) and java.time.LocalDate (newer drivers)
|
||||
final Object rawDate = row.get("dw_date");
|
||||
LocalDate date;
|
||||
if (rawDate instanceof LocalDate) {
|
||||
date = (LocalDate) rawDate;
|
||||
} else if (rawDate instanceof java.sql.Date) {
|
||||
date = ((java.sql.Date) rawDate).toLocalDate();
|
||||
} else {
|
||||
date = LocalDate.parse(String.valueOf(rawDate).substring(0, 10));
|
||||
}
|
||||
final BigDecimal dr = Objects.requireNonNullElse((BigDecimal) row.get("dw_debit"), BigDecimal.ZERO);
|
||||
final BigDecimal cr = Objects.requireNonNullElse((BigDecimal) row.get("dw_credit"), BigDecimal.ZERO);
|
||||
final int count = ((Number) row.get("dw_count")).intValue();
|
||||
final BigDecimal net = debitNormalFinal ? dr.subtract(cr) : cr.subtract(dr);
|
||||
final BigDecimal closing = running.add(net);
|
||||
dayWiseSummary.add(DayWiseSummaryData.builder()
|
||||
.date(date)
|
||||
.openingBalance(running)
|
||||
.totalDebit(dr)
|
||||
.totalCredit(cr)
|
||||
.netMovement(net)
|
||||
.closingBalance(closing)
|
||||
.entryCount(count)
|
||||
.build());
|
||||
running = closing;
|
||||
}
|
||||
}
|
||||
|
||||
// ── 4. Paginated journal entries — only fetch if limit > 0 ───────────
|
||||
final JournalEntryAssociationParametersData assocParams = new JournalEntryAssociationParametersData(true, true);
|
||||
final int reqLimit = searchParameters != null && searchParameters.getLimit() != null
|
||||
? searchParameters.getLimit() : 0;
|
||||
final Page<JournalEntryData> entries;
|
||||
if (reqLimit > 0) {
|
||||
entries = retrieveAll(searchParameters, glAccountId, onlyManualEntries,
|
||||
fromDate, toDate, null, null, transactionId, null, assocParams);
|
||||
} else {
|
||||
// Summary-only request — return empty page, no SQL needed
|
||||
entries = new Page<>(new ArrayList<>(), 0);
|
||||
}
|
||||
|
||||
// ── 5. Compute period totals ─────────────────────────────────────────
|
||||
BigDecimal totalDebit = BigDecimal.ZERO;
|
||||
BigDecimal totalCredit = BigDecimal.ZERO;
|
||||
{
|
||||
final List<Object> totParams = new ArrayList<>();
|
||||
final StringBuilder totSql = new StringBuilder(
|
||||
"SELECT COALESCE(SUM(CASE WHEN je.type_enum = 2 THEN je.amount ELSE 0 END), 0) AS totalDebit, "
|
||||
+ "COALESCE(SUM(CASE WHEN je.type_enum = 1 THEN je.amount ELSE 0 END), 0) AS totalCredit "
|
||||
+ "FROM acc_gl_journal_entry je WHERE 1=1");
|
||||
if (glAccountId != null && glAccountId > 0) {
|
||||
totSql.append(" AND je.account_id = ?");
|
||||
totParams.add(glAccountId);
|
||||
}
|
||||
if (officeId != null && officeId > 0) {
|
||||
totSql.append(" AND je.office_id = ?");
|
||||
totParams.add(officeId);
|
||||
}
|
||||
if (fromDate != null) {
|
||||
totSql.append(" AND je.entry_date >= ?");
|
||||
totParams.add(fromDate);
|
||||
}
|
||||
if (toDate != null) {
|
||||
totSql.append(" AND je.entry_date <= ?");
|
||||
totParams.add(toDate);
|
||||
}
|
||||
if (onlyManualEntries != null && onlyManualEntries) {
|
||||
totSql.append(" AND je.manual_entry = true");
|
||||
}
|
||||
final BigDecimal[] totResult = this.jdbcTemplate.queryForObject(totSql.toString(),
|
||||
(rs, rowNum) -> new BigDecimal[]{
|
||||
Objects.requireNonNullElse(rs.getBigDecimal("totalDebit"), BigDecimal.ZERO),
|
||||
Objects.requireNonNullElse(rs.getBigDecimal("totalCredit"), BigDecimal.ZERO)
|
||||
}, totParams.toArray());
|
||||
if (totResult != null) {
|
||||
totalDebit = totResult[0];
|
||||
totalCredit = totResult[1];
|
||||
}
|
||||
}
|
||||
|
||||
final BigDecimal netMovement = isDebitNormal ? totalDebit.subtract(totalCredit) : totalCredit.subtract(totalDebit);
|
||||
final BigDecimal closingBalance = openingBalance.add(netMovement);
|
||||
|
||||
// ── 6. Total entries count ────────────────────────────────────────────
|
||||
long totalEntries = 0L;
|
||||
{
|
||||
final List<Object> cntParams = new ArrayList<>();
|
||||
final StringBuilder cntSql = new StringBuilder(
|
||||
"SELECT COUNT(*) FROM acc_gl_journal_entry je WHERE 1=1");
|
||||
if (glAccountId != null && glAccountId > 0) {
|
||||
cntSql.append(" AND je.account_id = ?");
|
||||
cntParams.add(glAccountId);
|
||||
}
|
||||
if (officeId != null && officeId > 0) {
|
||||
cntSql.append(" AND je.office_id = ?");
|
||||
cntParams.add(officeId);
|
||||
}
|
||||
if (fromDate != null) {
|
||||
cntSql.append(" AND je.entry_date >= ?");
|
||||
cntParams.add(fromDate);
|
||||
}
|
||||
if (toDate != null) {
|
||||
cntSql.append(" AND je.entry_date <= ?");
|
||||
cntParams.add(toDate);
|
||||
}
|
||||
if (onlyManualEntries != null && onlyManualEntries) {
|
||||
cntSql.append(" AND je.manual_entry = true");
|
||||
}
|
||||
final Long cnt = this.jdbcTemplate.queryForObject(cntSql.toString(), Long.class, cntParams.toArray());
|
||||
if (cnt != null) { totalEntries = cnt; }
|
||||
}
|
||||
|
||||
return GLAccountLedgerReportData.builder()
|
||||
.glAccount(glAccountData)
|
||||
.openingBalance(openingBalance)
|
||||
.closingBalance(closingBalance)
|
||||
.totalDebit(totalDebit)
|
||||
.totalCredit(totalCredit)
|
||||
.netMovement(netMovement)
|
||||
.debitNormal(isDebitNormal)
|
||||
.fromDate(fromDate)
|
||||
.toDate(toDate)
|
||||
.dayWiseSummary(dayWiseSummary)
|
||||
.totalEntries(totalEntries)
|
||||
.entries(entries)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
+10
-7
@@ -595,26 +595,29 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
|
||||
return;
|
||||
}
|
||||
|
||||
final String transactionRef = "CA" + account.getId();
|
||||
// Deposit uses CA{accountId} as transaction ref (one per activation)
|
||||
final String depositRef = "CA" + account.getId();
|
||||
|
||||
// Deposits: DR SAVINGS_REFERENCE (cash in), CR SAVINGS_CONTROL (liability)
|
||||
if (depositTxns != null) {
|
||||
for (final org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountTransaction txn : depositTxns) {
|
||||
if (txn.getId() == null || txn.getAmount() == null) continue;
|
||||
postEntry(account, cashAccount, JournalEntryType.DEBIT, txn.getAmount(), txn.getTransactionDate(), transactionRef);
|
||||
postEntry(account, controlAccount, JournalEntryType.CREDIT, txn.getAmount(), txn.getTransactionDate(), transactionRef);
|
||||
postEntry(account, cashAccount, JournalEntryType.DEBIT, txn.getAmount(), txn.getTransactionDate(), depositRef);
|
||||
postEntry(account, controlAccount, JournalEntryType.CREDIT, txn.getAmount(), txn.getTransactionDate(), depositRef);
|
||||
log.info("[GL] Deposit GL posted for account id={}, amount={}", account.getId(), txn.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
// Charges: DR SAVINGS_CONTROL (liability reduced), CR INCOME_FROM_FEES
|
||||
// Charges: each charge gets its own transaction ref = "CAC" + txn.getId()
|
||||
// so each charge appears as a separate transaction in journal entries
|
||||
if (chargeEntries != null && feeIncomeAccount != null) {
|
||||
for (final ChargeGlEntry entry : chargeEntries) {
|
||||
final org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountTransaction txn = entry.txn();
|
||||
if (txn.getId() == null || txn.getAmount() == null) continue;
|
||||
postEntry(account, controlAccount, JournalEntryType.DEBIT, txn.getAmount(), txn.getTransactionDate(), transactionRef);
|
||||
postEntry(account, feeIncomeAccount, JournalEntryType.CREDIT, txn.getAmount(), txn.getTransactionDate(), transactionRef);
|
||||
log.info("[GL] Charge GL posted for account id={}, charge={}, amount={}", account.getId(), entry.charge().getCharge().getName(), txn.getAmount());
|
||||
final String chargeRef = "CAC" + txn.getId();
|
||||
postEntry(account, controlAccount, JournalEntryType.DEBIT, txn.getAmount(), txn.getTransactionDate(), chargeRef);
|
||||
postEntry(account, feeIncomeAccount, JournalEntryType.CREDIT, txn.getAmount(), txn.getTransactionDate(), chargeRef);
|
||||
log.info("[GL] Charge GL posted for account id={}, charge={}, amount={}, ref={}", account.getId(), entry.charge().getCharge().getName(), txn.getAmount(), chargeRef);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
Reference in New Issue
Block a user