blob: 7f3e17180461dc85e9454ac94d1bba2888e90ffc [file] [log] [blame]
/*
* 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.
*/
import org.ofbiz.accounting.util.UtilAccounting;
import org.ofbiz.base.util.UtilDateTime;
import org.ofbiz.base.util.UtilMisc;
import org.ofbiz.base.util.UtilProperties;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.entity.condition.EntityCondition;
import org.ofbiz.entity.condition.EntityOperator;
import org.ofbiz.party.party.PartyWorker;
import java.sql.Date;
import java.sql.Timestamp;
import javolution.util.FastList;
import javolution.util.FastMap;
if (!fromDate) {
return;
}
if (!thruDate) {
thruDate = UtilDateTime.nowTimestamp();
}
if (!parameters.glFiscalTypeId) {
parameters.glFiscalTypeId = "ACTUAL";
}
uiLabelMap = UtilProperties.getResourceBundleMap("AccountingUiLabels", locale);
parametersFromDate = fromDate;
// Setup the divisions for which the report is executed
List partyIds = PartyWorker.getAssociatedPartyIdsByRelationshipType(delegator, organizationPartyId, 'GROUP_ROLLUP');
partyIds.add(organizationPartyId);
// Get the group of account classes that will be used to position accounts in the proper section of the Cash Flow statement
GenericValue glAccountClass = from("GlAccountClass").where("glAccountClassId", "CASH_EQUIVALENT").cache(true).queryOne();
List glAccountClassIds = UtilAccounting.getDescendantGlAccountClassIds(glAccountClass);
List cashFlowBalanceTotalList = [];
// Find the last closed time period to get the fromDate for the transactions in the current period and the ending balances of the last closed period
Map lastClosedTimePeriodResult = runService('findLastClosedDate', ["organizationPartyId":organizationPartyId, "findDate":new Date(parametersFromDate.getTime()),"userLogin":userLogin]);
Timestamp periodClosingFromDate = (Timestamp)lastClosedTimePeriodResult.lastClosedDate;
if (!periodClosingFromDate) {
return;
}
GenericValue lastClosedTimePeriod = (GenericValue)lastClosedTimePeriodResult.lastClosedTimePeriod;
// Get the opening balances of Cash Account
Map openingCashBalances = [:];
if (lastClosedTimePeriod) {
List timePeriodAndExprs = FastList.newInstance();
timePeriodAndExprs.add(EntityCondition.makeCondition("organizationPartyId", EntityOperator.IN, partyIds));
timePeriodAndExprs.add(EntityCondition.makeCondition("glAccountClassId", EntityOperator.IN, glAccountClassIds));
timePeriodAndExprs.add(EntityCondition.makeCondition("endingBalance", EntityOperator.NOT_EQUAL, BigDecimal.ZERO));
timePeriodAndExprs.add(EntityCondition.makeCondition("customTimePeriodId", EntityOperator.EQUALS, lastClosedTimePeriod.customTimePeriodId));
List lastTimePeriodHistories = from("GlAccountAndHistory").where(timePeriodAndExprs).queryList();
lastTimePeriodHistories.each { lastTimePeriodHistory ->
Map accountMap = ["glAccountId":lastTimePeriodHistory.glAccountId, "accountCode":lastTimePeriodHistory.accountCode, "accountName":lastTimePeriodHistory.accountName, "balance":lastTimePeriodHistory.getBigDecimal("endingBalance"), "D":lastTimePeriodHistory.getBigDecimal("postedDebits"), "C":lastTimePeriodHistory.getBigDecimal("postedCredits")];
openingCashBalances.(lastTimePeriodHistory.glAccountId) = accountMap;
}
}
List mainAndExprs = FastList.newInstance();
mainAndExprs.add(EntityCondition.makeCondition("organizationPartyId", EntityOperator.IN, partyIds));
mainAndExprs.add(EntityCondition.makeCondition("isPosted", EntityOperator.EQUALS, "Y"));
mainAndExprs.add(EntityCondition.makeCondition("glFiscalTypeId", EntityOperator.EQUALS, parameters.glFiscalTypeId));
//mainAndExprs.add(EntityCondition.makeCondition("acctgTransTypeId", EntityOperator.NOT_EQUAL, "PERIOD_CLOSING"));
mainAndExprs.add(EntityCondition.makeCondition("glAccountClassId", EntityOperator.IN, glAccountClassIds));
// All GlAccount's transactions (from last closing period to parameter's fromDate)
accountBalanceList = [];
transactionTotals = [];
balanceTotal = BigDecimal.ZERO;
List openingCashBalanceAndExprs = FastList.newInstance(mainAndExprs);
openingCashBalanceAndExprs.add(EntityCondition.makeCondition("transactionDate", EntityOperator.GREATER_THAN_EQUAL_TO, periodClosingFromDate));
openingCashBalanceAndExprs.add(EntityCondition.makeCondition("transactionDate", EntityOperator.LESS_THAN, parametersFromDate));
transactionTotals = select("glAccountId", "accountName", "accountCode", "debitCreditFlag", "amount").from("AcctgTransEntrySums").where(openingCashBalanceAndExprs).orderBy("glAccountId").queryList();
transactionTotalsMap = [:];
transactionTotalsMap.putAll(openingCashBalances);
transactionTotals.each { transactionTotal ->
Map accountMap = (Map)transactionTotalsMap.get(transactionTotal.glAccountId);
if (!accountMap) {
accountMap = UtilMisc.makeMapWritable(transactionTotal);
accountMap.remove("debitCreditFlag");
accountMap.remove("amount");
accountMap.D = BigDecimal.ZERO;
accountMap.C = BigDecimal.ZERO;
accountMap.balance = BigDecimal.ZERO;
}
if (accountMap.debitCreditFlag && accountMap.amount) {
accountMap.remove("debitCreditFlag");
accountMap.remove("amount");
}
if (transactionTotal.debitCreditFlag == "C") {
accountMap.C = ((BigDecimal)accountMap.get("C")).add(transactionTotal.amount);
accountMap.balance = (accountMap.balance).subtract(transactionTotal.amount);
} else {
accountMap.D = ((BigDecimal)accountMap.get("D")).add(transactionTotal.amount);
accountMap.balance = (accountMap.balance).add(transactionTotal.amount);
}
transactionTotalsMap.put(transactionTotal.glAccountId, accountMap);
}
glAccountIdList = [];
accountBalanceList = UtilMisc.sortMaps(transactionTotalsMap.values().asList(), UtilMisc.toList("accountCode"));
accountBalanceList.each { accountBalance ->
balanceTotal = balanceTotal.add(accountBalance.balance);
}
openingCashBalanceTotal = balanceTotal;
context.openingCashBalanceList = accountBalanceList;
cashFlowBalanceTotalList.add("totalName":"AccountingOpeningCashBalance", "balance":balanceTotal);
openingTransactionKeySet = transactionTotalsMap.keySet();
// PERIOD CASH BALANCE
// GlAccounts from parameter's fromDate to parameter's thruDate.
accountBalanceList = [];
transactionTotals = [];
balanceTotal = BigDecimal.ZERO;
List periodCashBalanceAndExprs = FastList.newInstance(mainAndExprs);
periodCashBalanceAndExprs.add(EntityCondition.makeCondition("transactionDate", EntityOperator.GREATER_THAN_EQUAL_TO, parametersFromDate));
periodCashBalanceAndExprs.add(EntityCondition.makeCondition("transactionDate", EntityOperator.LESS_THAN, thruDate));
transactionTotals = select("glAccountId", "accountName", "accountCode", "debitCreditFlag", "amount").from("AcctgTransEntrySums").where(periodCashBalanceAndExprs).orderBy("glAccountId").queryList();
if (transactionTotals) {
Map transactionTotalsMap = [:];
balanceTotalCredit = BigDecimal.ZERO;
balanceTotalDebit = BigDecimal.ZERO;
transactionTotals.each { transactionTotal ->
Map accountMap = (Map)transactionTotalsMap.get(transactionTotal.glAccountId);
if (!accountMap) {
accountMap = UtilMisc.makeMapWritable(transactionTotal);
accountMap.remove("debitCreditFlag");
accountMap.remove("amount");
accountMap.D = BigDecimal.ZERO;
accountMap.C = BigDecimal.ZERO;
accountMap.balance = BigDecimal.ZERO;
}
UtilMisc.addToBigDecimalInMap(accountMap, transactionTotal.debitCreditFlag, transactionTotal.amount);
if ("D".equals(transactionTotal.debitCreditFlag)) {
balanceTotalDebit = balanceTotalDebit.add(transactionTotal.amount);
} else {
balanceTotalCredit = balanceTotalCredit.add(transactionTotal.amount);
}
BigDecimal debitAmount = (BigDecimal)accountMap.D;
BigDecimal creditAmount = (BigDecimal)accountMap.C;
BigDecimal balance = debitAmount.subtract(creditAmount);
accountMap.balance = balance;
transactionTotalsMap.(transactionTotal.glAccountId) = accountMap;
}
accountBalanceList = UtilMisc.sortMaps(transactionTotalsMap.values().asList(), UtilMisc.toList("accountCode"));
balanceTotal = balanceTotalDebit.subtract(balanceTotalCredit);
}
periodCashBalanceTotal = balanceTotal;
context.periodCashBalanceList = accountBalanceList;
context.periodCashBalanceList.add("accountName":uiLabelMap.AccountingTotalPeriodCashBalance, "balance":balanceTotal);
cashFlowBalanceTotalList.add("totalName":"AccountingPeriodCashBalance", "balance":balanceTotal);
// CLOSING BALANCE
// GlAccounts from parameter's fromDate to parameter's thruDate.
accountBalanceList = [];
balanceTotal = BigDecimal.ZERO;
List transactionTotals = FastList.newInstance();
transactionTotals.addAll(FastList.newInstance(context.openingCashBalanceList));
transactionTotals.addAll(FastList.newInstance(context.periodCashBalanceList));
transactionTotals = UtilMisc.sortMaps(transactionTotals, UtilMisc.toList("accountCode"));
closingTransactionKeySet = [];
if (transactionTotals) {
Map transactionTotalsMap = [:];
balanceTotalCredit = BigDecimal.ZERO;
balanceTotalDebit = BigDecimal.ZERO;
transactionTotals.each { transactionTotal ->
if (transactionTotal.D != null) {
if (transactionTotalsMap.(transactionTotal.glAccountId)) {
totalDebitBalance = (transactionTotal.D).add(transactionTotalsMap.(transactionTotal.glAccountId).D);
totalCreditBalance = (transactionTotal.C).add(transactionTotalsMap.(transactionTotal.glAccountId).C);
if (transactionTotalsMap.(transactionTotal.glAccountId).D == 0 && transactionTotalsMap.(transactionTotal.glAccountId).C == 0) {
transactionTotalsMap.(transactionTotal.glAccountId).balance = (transactionTotal.balance).add(transactionTotalsMap.(transactionTotal.glAccountId).balance);
} else {
transactionTotalsMap.(transactionTotal.glAccountId).D = totalDebitBalance;
transactionTotalsMap.(transactionTotal.glAccountId).C = totalCreditBalance;
transactionTotalsMap.(transactionTotal.glAccountId).balance = totalDebitBalance.subtract(totalCreditBalance);
}
} else {
transactionTotalsMap.(transactionTotal.glAccountId) = FastMap.newInstance(transactionTotal);
}
accountBalanceList = UtilMisc.sortMaps(transactionTotalsMap.values().asList(), UtilMisc.toList("accountCode"));
}
}
closingTransactionKeySet = transactionTotalsMap.keySet();
}
accountBalanceList.each { accountBalance ->
balanceTotal = balanceTotal.add(accountBalance.balance);
}
//closingCashBalanceTotal = balanceTotal;
context.closingCashBalanceList = accountBalanceList;
context.closingCashBalanceList.add("accountName":uiLabelMap.AccountingTotalClosingCashBalance, "balance":balanceTotal);
// Get differences of glAccount in closing and opening list and then add difference to opening list.
if (closingTransactionKeySet) {
closingTransactionKeySet.removeAll(openingTransactionKeySet);
closingTransactionKeySet.each { closingTransactionKey ->
glAccount = from("GlAccount").where("glAccountId", closingTransactionKey).cache(true).queryOne();
context.openingCashBalanceList.add(["glAccountId":glAccount.glAccountId, "accountName":glAccount.accountName, accountCode:glAccount.accountCode, balance:BigDecimal.ZERO, D:BigDecimal.ZERO, C:BigDecimal.ZERO]);
}
}
context.openingCashBalanceList.add(["accountName":uiLabelMap.AccountingTotalOpeningCashBalance, "balance":openingCashBalanceTotal]);
// CASH FLOW STATEMENT ENDING BALANCE
// ENDING BALANCE = OPENING CASH BALANCE + PERIOD CASH BALANCE
endingCashBalanceTotal = openingCashBalanceTotal.add(periodCashBalanceTotal);
cashFlowBalanceTotalList.add("totalName":"AccountingEndingCashBalance", "balance":endingCashBalanceTotal);
context.cashFlowBalanceTotalList = cashFlowBalanceTotalList;