📄 financialservices.java
字号:
/* * Copyright (C) 2006 Open Source Strategies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */package com.opensourcestrategies.financials.financials;import java.util.Date;import java.util.HashMap;import java.util.Map;import java.util.Iterator;import java.util.List;import java.util.ArrayList;import java.sql.Timestamp;import java.math.BigDecimal;import javolution.util.FastMap;import org.ofbiz.accounting.util.UtilAccounting;import org.ofbiz.base.util.Debug;import org.ofbiz.base.util.UtilDateTime;import org.ofbiz.base.util.UtilMisc;import org.ofbiz.base.util.UtilNumber;import org.ofbiz.entity.GenericDelegator;import org.ofbiz.entity.GenericEntityException;import org.ofbiz.entity.GenericValue;import org.ofbiz.entity.condition.EntityConditionList;import org.ofbiz.entity.condition.EntityExpr;import org.ofbiz.entity.condition.EntityOperator;import org.ofbiz.entity.util.EntityUtil;import org.ofbiz.service.DispatchContext;import org.ofbiz.service.GenericServiceException;import org.ofbiz.service.LocalDispatcher;import org.ofbiz.service.ModelService;import org.ofbiz.service.ServiceUtil;import com.opensourcestrategies.financials.util.UtilFinancial;/** * FinancialServices - Services for generating financial reports and statements * * @author <a href="mailto:sichen@opensourcestrategies.com">Si Chen</a> * @version $Rev: 150 $ * @since 2.2 */public class FinancialServices { public static String module = FinancialServices.class.getName(); public static int decimals = UtilNumber.getBigDecimalScale("fin_arithmetic.properties", "financial.statements.decimals"); public static int rounding = UtilNumber.getBigDecimalRoundingMode("fin_arithmetic.properties", "financial.statements.rounding"); public static final BigDecimal ZERO = (new BigDecimal("0")).setScale(decimals, rounding); /** * Generates an income statement over two CustomTimePeriod entries, returning a Map of GlAccount and amounts and a double */ public static Map getIncomeStatementByTimePeriods(DispatchContext dctx, Map context) { String organizationPartyId = (String) context.get("organizationPartyId"); String glFiscalTypeId = (String) context.get("glFiscalTypeId"); GenericValue userLogin = (GenericValue) context.get("userLogin"); Map input = UtilMisc.toMap("organizationPartyId", organizationPartyId, "glFiscalTypeId", glFiscalTypeId, "userLogin", userLogin); return reportServiceTimePeriodHelper(dctx, context, "getIncomeStatementByDates", input); } /** * generates an income statement over a range of dates, returning a Map of GlAccount and amounts and a netIncome */ public static Map getIncomeStatementByDates(DispatchContext dctx, Map context) { LocalDispatcher dispatcher = dctx.getDispatcher(); GenericDelegator delegator = dctx.getDelegator(); Timestamp fromDate = (Timestamp) context.get("fromDate"); Timestamp thruDate = (Timestamp) context.get("thruDate"); String organizationPartyId = (String) context.get("organizationPartyId"); String glFiscalTypeId = (String) context.get("glFiscalTypeId"); GenericValue userLogin = (GenericValue) context.get("userLogin"); // glFiscalTypeId defaults to ACTUAL if ((glFiscalTypeId == null) || (glFiscalTypeId.equals(""))) { glFiscalTypeId = "ACTUAL"; } try { // get a Map of glAccount -> sums for all income statement accounts for this time period Map tmpResult = dispatcher.runSync("getIncomeStatementAccountSumsByDate", UtilMisc.toMap("organizationPartyId", organizationPartyId, "fromDate", fromDate, "thruDate", thruDate, "glFiscalTypeId", glFiscalTypeId, "userLogin", userLogin)); if (tmpResult.get("glAccountSums") == null) { return ServiceUtil.returnError("Cannot sum up account balances properly for income statement"); } Map glAccountSums = (HashMap) tmpResult.get("glAccountSums"); // final phase - figure out net income by adding and subtracting the sum for each account, depending on whether it is an INCOME or // EXPENSE account. This is the part where we also flip the signs of the sums, so the EXPENSE account amounts show up as NEGATIVE glAccountSums = (Map) tmpResult.get("glAccountSums"); double netIncome = 0.0; List accounts = EntityUtil.orderBy(glAccountSums.keySet(), UtilMisc.toList("glAccountId")); for (Iterator ai = accounts.iterator(); ai.hasNext(); ) { GenericValue account = (GenericValue) ai.next(); double accountSum = ((Double) glAccountSums.get(account)).doubleValue(); if (UtilAccounting.isRevenueAccount(account) || UtilAccounting.isIncomeAccount(account)) { netIncome += accountSum; } else if (UtilAccounting.isExpenseAccount(account)) { netIncome -= accountSum; glAccountSums.put(account, new Double(-accountSum)); } } // was this income statement for periods which are closed? check by seeing if there are any unclosed time periods // in between these dates? If so, then this accounting period has not been closed // TODO: this is not very good. Implement a real service which checks through all interim periods correctly. boolean isClosed = true; EntityConditionList conditions = new EntityConditionList(UtilMisc.toList( new EntityExpr("organizationPartyId", EntityOperator.EQUALS, organizationPartyId), new EntityExpr("isClosed", EntityOperator.NOT_EQUAL, "Y"), new EntityConditionList(UtilMisc.toList( new EntityExpr("fromDate", EntityOperator.GREATER_THAN_EQUAL_TO, fromDate), new EntityExpr("thruDate", EntityOperator.LESS_THAN_EQUAL_TO, thruDate)), EntityOperator.OR)), EntityOperator.AND); List timePeriods = delegator.findByCondition("CustomTimePeriod", conditions, UtilMisc.toList("customTimePeriodId"), UtilMisc.toList("customTimePeriodId")); if (timePeriods.size() > 0) { isClosed = false; } // now get the profit/loss GlAccount for the organization and return it as well String retainedEarningsGlAccountId = null; GenericValue retainedEarningsGlAccount = null; // get retained earnings account for the organization tmpResult = dispatcher.runSync("getProductOrgGlAccount", UtilMisc.toMap("organizationPartyId", organizationPartyId, "glAccountTypeId", "RETAINED_EARNINGS", "userLogin", userLogin)); if (tmpResult.get("glAccountId") == null) { return ServiceUtil.returnError("Cannot find a PROFIT_LOSS_ACCOUNT for organization " + organizationPartyId); } else { retainedEarningsGlAccountId = (String) tmpResult.get("glAccountId"); retainedEarningsGlAccount = delegator.findByPrimaryKeyCache("GlAccount", UtilMisc.toMap("glAccountId", retainedEarningsGlAccountId)); } // all done Map result = ServiceUtil.returnSuccess(); result.put("netIncome", new Double(netIncome)); result.put("glAccountSums", glAccountSums); result.put("isClosed", new Boolean(isClosed)); result.put("retainedEarningsGlAccount", retainedEarningsGlAccount); return result; } catch (GenericEntityException ex) { return(ServiceUtil.returnError(ex.getMessage())); } catch (GenericServiceException ex) { return(ServiceUtil.returnError(ex.getMessage())); } } /** * Calculates net income (of ACTUAL gl fiscal type) since last closed accounting period or, if none exists, since earliest accounting period. * Optionally use periodTypeId to get figure since last closed date of a period type */ public static Map getActualNetIncomeSinceLastClosing(DispatchContext dctx, Map context) { LocalDispatcher dispatcher = dctx.getDispatcher(); GenericDelegator delegator = dctx.getDelegator(); String organizationPartyId = (String) context.get("organizationPartyId"); Timestamp thruDate = (Timestamp) context.get("thruDate"); GenericValue userLogin = (GenericValue) context.get("userLogin"); String periodTypeId = (String) context.get("periodTypeId"); Timestamp fromDate = null; try { // try to get the ending date of the most recent accounting time period which has been closed Map tmpResult = dispatcher.runSync("findLastClosedDate", UtilMisc.toMap("organizationPartyId", organizationPartyId, "periodTypeId", periodTypeId, "userLogin", userLogin)); if ((tmpResult != null) && (tmpResult.get("lastClosedDate") != null)) { fromDate = (Timestamp) tmpResult.get("lastClosedDate"); } else { return ServiceUtil.returnError("Cannot get a starting date for net income"); } tmpResult = dispatcher.runSync("getIncomeStatementByDates", UtilMisc.toMap("organizationPartyId", organizationPartyId, "glFiscalTypeId", "ACTUAL", "fromDate", fromDate, "thruDate", thruDate, "userLogin", userLogin)); if (!(tmpResult.get(ModelService.RESPONSE_MESSAGE).equals(ModelService.RESPOND_SUCCESS))) { return tmpResult; // probably an error message - pass it back up } else if (tmpResult.get("netIncome") == null) { return ServiceUtil.returnError("Cannot calculate a net income"); // no error message, no net income either? } else { // return net income and profit&loss gl account Map result = ServiceUtil.returnSuccess(); result.put("netIncome", tmpResult.get("netIncome")); result.put("retainedEarningsGlAccount", tmpResult.get("retainedEarningsGlAccount")); return result; } } catch (GenericServiceException ex) { return(ServiceUtil.returnError(ex.getMessage())); } } /** * Generates balance sheet for a time period and returns separate maps for balances of asset, liability, and equity accounts */ public static Map getBalanceSheetForTimePeriod(DispatchContext dctx, Map context) { LocalDispatcher dispatcher = dctx.getDispatcher(); GenericDelegator delegator = dctx.getDelegator(); String organizationPartyId = (String) context.get("organizationPartyId"); String customTimePeriodId = (String) context.get("customTimePeriodId"); GenericValue userLogin = (GenericValue) context.get("userLogin"); try { // get the current time period and first use it to assume whether this period has been closed or not GenericValue currentTimePeriod = delegator.findByPrimaryKey("CustomTimePeriod", UtilMisc.toMap("customTimePeriodId", customTimePeriodId)); boolean isClosed = false; if (currentTimePeriod.getString("isClosed").equals("Y")) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -