1 16 17 package com.opensourcestrategies.financials.financials; 18 19 import java.util.Date ; 20 import java.util.HashMap ; 21 import java.util.Map ; 22 import java.util.Iterator ; 23 import java.util.List ; 24 import java.util.ArrayList ; 25 import java.sql.Timestamp ; 26 import java.math.BigDecimal ; 27 28 import javolution.util.FastMap; 29 30 import org.ofbiz.accounting.util.UtilAccounting; 31 import org.ofbiz.base.util.Debug; 32 import org.ofbiz.base.util.UtilDateTime; 33 import org.ofbiz.base.util.UtilMisc; 34 import org.ofbiz.base.util.UtilNumber; 35 import org.ofbiz.base.util.UtilValidate; 36 import org.ofbiz.entity.GenericDelegator; 37 import org.ofbiz.entity.GenericEntityException; 38 import org.ofbiz.entity.GenericValue; 39 import org.ofbiz.entity.condition.EntityConditionList; 40 import org.ofbiz.entity.condition.EntityExpr; 41 import org.ofbiz.entity.condition.EntityOperator; 42 import org.ofbiz.entity.util.EntityUtil; 43 import org.ofbiz.service.DispatchContext; 44 import org.ofbiz.service.GenericServiceException; 45 import org.ofbiz.service.LocalDispatcher; 46 import org.ofbiz.service.ModelService; 47 import org.ofbiz.service.ServiceUtil; 48 49 import com.opensourcestrategies.financials.util.UtilFinancial; 50 51 58 59 public class FinancialServices { 60 61 public static String module = FinancialServices.class.getName(); 62 63 public static int decimals = UtilNumber.getBigDecimalScale("fin_arithmetic.properties", "financial.statements.decimals"); 64 public static int rounding = UtilNumber.getBigDecimalRoundingMode("fin_arithmetic.properties", "financial.statements.rounding"); 65 public static final BigDecimal ZERO = (new BigDecimal ("0")).setScale(decimals, rounding); 66 67 70 public static Map getIncomeStatementByTimePeriods(DispatchContext dctx, Map context) { 71 String organizationPartyId = (String ) context.get("organizationPartyId"); 72 String glFiscalTypeId = (String ) context.get("glFiscalTypeId"); 73 GenericValue userLogin = (GenericValue) context.get("userLogin"); 74 Map input = UtilMisc.toMap("organizationPartyId", organizationPartyId, "glFiscalTypeId", glFiscalTypeId, "userLogin", userLogin); 75 return reportServiceTimePeriodHelper(dctx, context, "getIncomeStatementByDates", input); 76 } 77 78 81 public static Map getIncomeStatementByDates(DispatchContext dctx, Map context) { 82 LocalDispatcher dispatcher = dctx.getDispatcher(); 83 GenericDelegator delegator = dctx.getDelegator(); 84 Timestamp fromDate = (Timestamp ) context.get("fromDate"); 85 Timestamp thruDate = (Timestamp ) context.get("thruDate"); 86 String organizationPartyId = (String ) context.get("organizationPartyId"); 87 String glFiscalTypeId = (String ) context.get("glFiscalTypeId"); 88 GenericValue userLogin = (GenericValue) context.get("userLogin"); 89 if ((glFiscalTypeId == null) || (glFiscalTypeId.equals(""))) { 91 glFiscalTypeId = "ACTUAL"; 92 } 93 94 try { 95 Map tmpResult = dispatcher.runSync("getIncomeStatementAccountSumsByDate", UtilMisc.toMap("organizationPartyId", organizationPartyId, "fromDate", fromDate, 97 "thruDate", thruDate, "glFiscalTypeId", glFiscalTypeId, "userLogin", userLogin)); 98 if (tmpResult.get("glAccountSums") == null) { 99 return ServiceUtil.returnError("Cannot sum up account balances properly for income statement"); 100 } 101 Map glAccountSums = (HashMap ) tmpResult.get("glAccountSums"); 102 103 glAccountSums = (Map ) tmpResult.get("glAccountSums"); 106 double netIncome = 0.0; 107 List accounts = EntityUtil.orderBy(glAccountSums.keySet(), UtilMisc.toList("glAccountId")); 108 for (Iterator ai = accounts.iterator(); ai.hasNext(); ) { 109 GenericValue account = (GenericValue) ai.next(); 110 double accountSum = ((Double ) glAccountSums.get(account)).doubleValue(); 111 if (UtilAccounting.isRevenueAccount(account) || UtilAccounting.isIncomeAccount(account)) { 112 netIncome += accountSum; 113 } else if (UtilAccounting.isExpenseAccount(account)) { 114 netIncome -= accountSum; 115 glAccountSums.put(account, new Double (-accountSum)); 116 } 117 } 118 119 boolean isClosed = true; 123 EntityConditionList conditions = new EntityConditionList(UtilMisc.toList( 124 new EntityExpr("organizationPartyId", EntityOperator.EQUALS, organizationPartyId), 125 new EntityExpr("isClosed", EntityOperator.NOT_EQUAL, "Y"), 126 new EntityConditionList(UtilMisc.toList( 127 new EntityExpr("fromDate", EntityOperator.GREATER_THAN_EQUAL_TO, fromDate), 128 new EntityExpr("thruDate", EntityOperator.LESS_THAN_EQUAL_TO, thruDate)), EntityOperator.OR)), EntityOperator.AND); 129 List timePeriods = delegator.findByCondition("CustomTimePeriod", conditions, UtilMisc.toList("customTimePeriodId"), UtilMisc.toList("customTimePeriodId")); 130 if (timePeriods.size() > 0) { 131 isClosed = false; 132 } 133 134 String retainedEarningsGlAccountId = null; 136 GenericValue retainedEarningsGlAccount = null; 137 138 tmpResult = dispatcher.runSync("getProductOrgGlAccount", UtilMisc.toMap("organizationPartyId", organizationPartyId, 140 "glAccountTypeId", "RETAINED_EARNINGS", "userLogin", userLogin)); 141 if (tmpResult.get("glAccountId") == null) { 142 return ServiceUtil.returnError("Cannot find a PROFIT_LOSS_ACCOUNT for organization " + organizationPartyId); 143 } else { 144 retainedEarningsGlAccountId = (String ) tmpResult.get("glAccountId"); 145 retainedEarningsGlAccount = delegator.findByPrimaryKeyCache("GlAccount", UtilMisc.toMap("glAccountId", retainedEarningsGlAccountId)); 146 } 147 148 Map result = ServiceUtil.returnSuccess(); 150 result.put("netIncome", new Double (netIncome)); 151 result.put("glAccountSums", glAccountSums); 152 result.put("isClosed", new Boolean (isClosed)); 153 result.put("retainedEarningsGlAccount", retainedEarningsGlAccount); 154 return result; 155 } catch (GenericEntityException ex) { 156 return(ServiceUtil.returnError(ex.getMessage())); 157 } catch (GenericServiceException ex) { 158 return(ServiceUtil.returnError(ex.getMessage())); 159 } 160 } 161 162 165 public static Map getActualNetIncomeSinceLastClosing(DispatchContext dctx, Map context) { 166 LocalDispatcher dispatcher = dctx.getDispatcher(); 167 GenericDelegator delegator = dctx.getDelegator(); 168 String organizationPartyId = (String ) context.get("organizationPartyId"); 169 Timestamp thruDate = (Timestamp ) context.get("thruDate"); 170 GenericValue userLogin = (GenericValue) context.get("userLogin"); 171 String periodTypeId = (String ) context.get("periodTypeId"); 172 173 Timestamp fromDate = null; 174 175 try { 176 Map tmpResult = dispatcher.runSync("findLastClosedDate", UtilMisc.toMap("organizationPartyId", organizationPartyId, 178 "periodTypeId", periodTypeId, "userLogin", userLogin)); 179 if ((tmpResult != null) && (tmpResult.get("lastClosedDate") != null)) { 180 fromDate = (Timestamp ) tmpResult.get("lastClosedDate"); 181 } else { 182 return ServiceUtil.returnError("Cannot get a starting date for net income"); 183 } 184 185 tmpResult = dispatcher.runSync("getIncomeStatementByDates", UtilMisc.toMap("organizationPartyId", organizationPartyId, 186 "glFiscalTypeId", "ACTUAL", "fromDate", fromDate, "thruDate", thruDate, "userLogin", userLogin)); 187 if (!(tmpResult.get(ModelService.RESPONSE_MESSAGE).equals(ModelService.RESPOND_SUCCESS))) { 188 return tmpResult; } else if (tmpResult.get("netIncome") == null) { 190 return ServiceUtil.returnError("Cannot calculate a net income"); } else { 192 Map result = ServiceUtil.returnSuccess(); 194 result.put("netIncome", tmpResult.get("netIncome")); 195 result.put("retainedEarningsGlAccount", tmpResult.get("retainedEarningsGlAccount")); 196 return result; 197 } 198 } catch (GenericServiceException ex) { 199 return(ServiceUtil.returnError(ex.getMessage())); 200 } 201 } 202 203 205 public static Map getBalanceSheetForTimePeriod(DispatchContext dctx, Map context) { 206 LocalDispatcher dispatcher = dctx.getDispatcher(); 207 GenericDelegator delegator = dctx.getDelegator(); 208 String organizationPartyId = (String ) context.get("organizationPartyId"); 209 String customTimePeriodId = (String ) context.get("customTimePeriodId"); 210 GenericValue userLogin = (GenericValue) context.get("userLogin"); 211 212 try { 213 GenericValue currentTimePeriod = delegator.findByPrimaryKey("CustomTimePeriod", UtilMisc.toMap("customTimePeriodId", customTimePeriodId)); 215 boolean isClosed = false; 216 if (currentTimePeriod.getString("isClosed").equals("Y")) { 217 isClosed = true; 218 } 219 EntityConditionList conditions = new EntityConditionList(UtilMisc.toList( 221 new EntityExpr("organizationPartyId", EntityOperator.EQUALS, organizationPartyId), 222 new EntityExpr("customTimePeriodId", EntityOperator.EQUALS, customTimePeriodId), 223 new EntityConditionList(UtilMisc.toList( 224 UtilFinancial.getAssetExpr(delegator), 225 UtilFinancial.getLiabilityExpr(delegator), 226 UtilFinancial.getEquityExpr(delegator)), EntityOperator.OR)), 227 EntityOperator.AND); 228 List selectedFields = UtilMisc.toList("glAccountId", "glAccountTypeId", "glAccountClassId", "accountName", "postedDebits", "postedCredits"); 229 selectedFields.add("endingBalance"); 230 List accounts = delegator.findByCondition("GlAccountAndHistory", conditions, selectedFields, UtilMisc.toList("glAccountId")); 231 232 Map assetAccountBalances = new HashMap (); 236 Map liabilityAccountBalances = new HashMap (); 237 Map equityAccountBalances = new HashMap (); 238 239 for (Iterator ai = accounts.iterator(); ai.hasNext(); ) { 240 GenericValue account = (GenericValue) ai.next(); 241 double balance = 0.0; 242 if (!isClosed) { 243 Double netBalance = UtilAccounting.getNetBalance(account, module); 245 if (netBalance != null) { 246 balance = netBalance.doubleValue(); 247 } else { 248 return ServiceUtil.returnError("Cannot get a net balance for " + account); 249 } 250 } else { 251 balance = account.getDouble("endingBalance").doubleValue(); 253 } 254 if (UtilAccounting.isAssetAccount(account)) { 256 assetAccountBalances.put(account.getRelatedOne("GlAccount"), new Double (balance)); 257 } else if (UtilAccounting.isLiabilityAccount(account)) { 258 liabilityAccountBalances.put(account.getRelatedOne("GlAccount"), new Double (balance)); 259 } else if (UtilAccounting.isEquityAccount(account)) { 260 equityAccountBalances.put(account.getRelatedOne("GlAccount"), new Double (balance)); 261 } 262 } 263 264 GenericValue retainedEarningsGlAccount = null; 266 Double interimNetIncome = null; 267 if (!isClosed) { 268 Map tmpResult = dispatcher.runSync("getActualNetIncomeSinceLastClosing", UtilMisc.toMap("organizationPartyId", organizationPartyId, "thruDate", 270 UtilDateTime.toTimestamp(currentTimePeriod.getDate("thruDate")), "userLogin", userLogin)); 271 if (tmpResult.get("netIncome") == null) { 272 return tmpResult; 273 } else { 274 interimNetIncome = (Double ) tmpResult.get("netIncome"); 276 retainedEarningsGlAccount = (GenericValue) tmpResult.get("retainedEarningsGlAccount"); 277 UtilMisc.addToDoubleInMap(equityAccountBalances, retainedEarningsGlAccount, interimNetIncome); 278 } 279 } 280 281 Map result = ServiceUtil.returnSuccess(); 283 result.put("assetAccountBalances", assetAccountBalances); 284 result.put("liabilityAccountBalances", liabilityAccountBalances); 285 result.put("equityAccountBalances", equityAccountBalances); 286 result.put("isClosed", new Boolean (isClosed)); 287 result.put("retainedEarningsGlAccount", retainedEarningsGlAccount); 288 result.put("interimNetIncomeAmount", interimNetIncome); 289 return result; 290 } catch (GenericEntityException ex) { 291 return(ServiceUtil.returnError(ex.getMessage())); 292 } catch (GenericServiceException ex) { 293 return(ServiceUtil.returnError(ex.getMessage())); 294 } 295 } 296 297 301 302 public static Map getBalanceSheetForDate(DispatchContext dctx, Map context) { 303 LocalDispatcher dispatcher = dctx.getDispatcher(); 304 GenericDelegator delegator = dctx.getDelegator(); 305 String organizationPartyId = (String ) context.get("organizationPartyId"); 306 Timestamp asOfDate = (Timestamp ) context.get("asOfDate"); 307 GenericValue userLogin = (GenericValue) context.get("userLogin"); 308 String glFiscalTypeId = (String ) context.get("glFiscalTypeId"); 309 if ((glFiscalTypeId == null) || (glFiscalTypeId.equals(""))) { 311 glFiscalTypeId = "ACTUAL"; 312 } 313 314 Map assetAccountBalances = new HashMap (); 316 Map liabilityAccountBalances = new HashMap (); 317 Map equityAccountBalances = new HashMap (); 318 319 try { 320 Map tmpResult = dispatcher.runSync("findLastClosedDate", UtilMisc.toMap("organizationPartyId", organizationPartyId, "findDate", asOfDate, "userLogin", userLogin)); 322 323 Timestamp lastClosedDate = null; 325 GenericValue lastClosedTimePeriod = null; 326 if ((tmpResult == null) || (tmpResult.get("lastClosedDate") == null)) { 327 return ServiceUtil.returnError("Cannot get a closed time period before " + asOfDate); 328 } else { 329 lastClosedDate = (Timestamp ) tmpResult.get("lastClosedDate"); 330 } 331 if (tmpResult.get("lastClosedTimePeriod") != null) { 332 lastClosedTimePeriod = (GenericValue) tmpResult.get("lastClosedTimePeriod"); 333 } 334 335 if (tmpResult.get("lastClosedTimePeriod") != null) { 337 tmpResult = dispatcher.runSync("getBalanceSheetForTimePeriod", UtilMisc.toMap("organizationPartyId", organizationPartyId, 338 "customTimePeriodId", lastClosedTimePeriod.getString("customTimePeriodId"), "userLogin", userLogin)); 339 if (tmpResult != null) { 340 assetAccountBalances = (Map ) tmpResult.get("assetAccountBalances"); 341 liabilityAccountBalances = (Map ) tmpResult.get("liabilityAccountBalances"); 342 equityAccountBalances = (Map ) tmpResult.get("equityAccountBalances"); 343 } 344 } 345 346 assetAccountBalances = getAcctgTransAndEntriesForClass(assetAccountBalances, organizationPartyId, lastClosedDate, asOfDate, glFiscalTypeId, "ASSET", userLogin, dispatcher); 348 liabilityAccountBalances = getAcctgTransAndEntriesForClass(liabilityAccountBalances, organizationPartyId, lastClosedDate, asOfDate, glFiscalTypeId, "LIABILITY", userLogin, dispatcher); 349 equityAccountBalances = getAcctgTransAndEntriesForClass(equityAccountBalances, organizationPartyId, lastClosedDate, asOfDate, glFiscalTypeId, "EQUITY", userLogin, dispatcher); 350 351 tmpResult = dispatcher.runSync("getIncomeStatementByDates", UtilMisc.toMap("organizationPartyId", organizationPartyId, "fromDate", lastClosedDate, 353 "glFiscalTypeId", glFiscalTypeId, "thruDate", asOfDate, "userLogin", userLogin)); 354 GenericValue retainedEarningsGlAccount = (GenericValue) tmpResult.get("retainedEarningsGlAccount"); 355 Double interimNetIncome = (Double ) tmpResult.get("netIncome"); 356 UtilMisc.addToDoubleInMap(equityAccountBalances, retainedEarningsGlAccount, interimNetIncome); 357 358 boolean isClosed = true; 360 EntityConditionList conditions = new EntityConditionList(UtilMisc.toList( 361 new EntityExpr("organizationPartyId", EntityOperator.EQUALS, organizationPartyId), 362 new EntityExpr("isClosed", EntityOperator.NOT_EQUAL, "Y"), 363 new EntityConditionList(UtilMisc.toList( 364 new EntityExpr("fromDate", EntityOperator.GREATER_THAN_EQUAL_TO, lastClosedDate), 365 new EntityExpr("thruDate", EntityOperator.LESS_THAN_EQUAL_TO, asOfDate)), EntityOperator.OR)), EntityOperator.AND); 366 List timePeriods = delegator.findByCondition("CustomTimePeriod", conditions, UtilMisc.toList("customTimePeriodId"), UtilMisc.toList("customTimePeriodId")); 367 if (timePeriods.size() > 0) { 368 isClosed = false; 369 } 370 371 Map result = ServiceUtil.returnSuccess(); 373 result.put("assetAccountBalances", assetAccountBalances); 374 result.put("liabilityAccountBalances", liabilityAccountBalances); 375 result.put("equityAccountBalances", equityAccountBalances); 376 result.put("isClosed", new Boolean (isClosed)); 377 result.put("retainedEarningsGlAccount", retainedEarningsGlAccount); 378 result.put("interimNetIncomeAmount", interimNetIncome); 379 return(result); 380 } catch (GenericEntityException ex) { 381 return(ServiceUtil.returnError(ex.getMessage())); 382 } catch (GenericServiceException ex) { 383 return(ServiceUtil.returnError(ex.getMessage())); 384 } 385 386 } 387 388 392 public static Map getAcctgTransAndEntriesByType(DispatchContext dctx, Map context) { 393 GenericDelegator delegator = dctx.getDelegator(); 394 Timestamp fromDate = (Timestamp ) context.get("fromDate"); 395 Timestamp thruDate = (Timestamp ) context.get("thruDate"); 396 String organizationPartyId = (String ) context.get("organizationPartyId"); 397 String glFiscalTypeId = (String ) context.get("glFiscalTypeId"); 398 List glAccountClasses = (List ) context.get("glAccountClasses"); 399 String productId = (String ) context.get("productId"); 400 String partyId = (String ) context.get("partyId"); 401 402 try { 403 List glAccountClassesConsidered = new ArrayList (); 405 for (Iterator gACi = glAccountClasses.iterator(); gACi.hasNext(); ) { 406 String glAccountClassId = (String ) gACi.next(); 407 glAccountClassesConsidered.add(UtilFinancial.getGlAccountClassExpr(glAccountClassId, delegator)); 408 } 409 410 List searchConditions = UtilMisc.toList( 413 new EntityExpr("organizationPartyId", EntityOperator.EQUALS, organizationPartyId), 414 new EntityExpr("isPosted", EntityOperator.EQUALS, "Y"), 415 new EntityExpr("glFiscalTypeId", EntityOperator.EQUALS, glFiscalTypeId), 416 new EntityConditionList(glAccountClassesConsidered, EntityOperator.OR), 417 new EntityExpr("transactionDate", EntityOperator.GREATER_THAN_EQUAL_TO, fromDate), 418 new EntityExpr("transactionDate", EntityOperator.LESS_THAN_EQUAL_TO, thruDate)); 419 if (UtilValidate.isNotEmpty(productId)) { 420 searchConditions.add(new EntityExpr("productId", EntityOperator.EQUALS, productId)); 421 } 422 if (UtilValidate.isNotEmpty(partyId)) { 423 searchConditions.add(new EntityExpr("partyId", EntityOperator.EQUALS, partyId)); 424 } 425 EntityConditionList conditions = new EntityConditionList(searchConditions, EntityOperator.AND); 426 427 List fieldsToGet = UtilMisc.toList("acctgTransId", "acctgTransTypeId", "acctgTransEntrySeqId", "glAccountId", "glAccountClassId", "amount"); 428 fieldsToGet.add("debitCreditFlag"); 429 fieldsToGet.add("productId"); 430 fieldsToGet.add("partyId"); 431 432 List transactionEntries = delegator.findByCondition("AcctgTransAndEntries", conditions, 433 fieldsToGet, UtilMisc.toList("acctgTransId", "acctgTransEntrySeqId")); 436 Map result = ServiceUtil.returnSuccess(); 437 result.put("transactionEntries", transactionEntries); 438 return(result); 439 } catch (GenericEntityException ex) { 440 return(ServiceUtil.returnError(ex.getMessage())); 441 } 442 } 443 444 447 public static Map getIncomeStatementAccountSumsByDate(DispatchContext dctx, Map context) { 448 LocalDispatcher dispatcher = dctx.getDispatcher(); 449 GenericDelegator delegator = dctx.getDelegator(); 450 Timestamp fromDate = (Timestamp ) context.get("fromDate"); 451 Timestamp thruDate = (Timestamp ) context.get("thruDate"); 452 String organizationPartyId = (String ) context.get("organizationPartyId"); 453 String glFiscalTypeId = (String ) context.get("glFiscalTypeId"); 454 GenericValue userLogin = (GenericValue) context.get("userLogin"); 455 456 try { 457 List transactionEntries = null; 460 Map tmpResult = dispatcher.runSync("getAcctgTransAndEntriesByType", UtilMisc.toMap("organizationPartyId", organizationPartyId, "fromDate", fromDate, 461 "thruDate", thruDate, "glFiscalTypeId", glFiscalTypeId, "glAccountClasses", UtilMisc.toList("REVENUE", "EXPENSE", "INCOME"), "userLogin", userLogin)); 462 if ((tmpResult != null) && (tmpResult.get("transactionEntries") != null)) { 463 transactionEntries = (List ) tmpResult.get("transactionEntries"); 464 } 465 transactionEntries = EntityUtil.filterOutByCondition(transactionEntries, new EntityExpr("acctgTransTypeId", EntityOperator.EQUALS, "PERIOD_CLOSING")); 467 468 Map glAccountSums = new HashMap (); 471 tmpResult = dispatcher.runSync("addToAccountBalances", UtilMisc.toMap("glAccountSums", glAccountSums, "transactionEntries", transactionEntries, 472 "userLogin", userLogin)); 473 if (tmpResult.get("glAccountSums") == null) { 474 return ServiceUtil.returnError("Cannot sum up account balances properly for income statement"); 475 } else { 476 Map result = ServiceUtil.returnSuccess(); 477 result.put("glAccountSums", glAccountSums); 478 return result; 479 } 480 } catch (GenericServiceException ex) { 481 return(ServiceUtil.returnError(ex.getMessage())); 482 } 483 } 484 485 489 public static Map addToAccountBalances(DispatchContext dctx, Map context) { 490 LocalDispatcher dispatcher = dctx.getDispatcher(); 491 Map glAccountSums = (Map ) context.get("glAccountSums"); 492 List transactionEntries = (List ) context.get("transactionEntries"); 493 494 499 try { 500 for (Iterator tEi = transactionEntries.iterator(); tEi.hasNext(); ) { 501 GenericValue transactionEntry = (GenericValue) tEi.next(); 502 GenericValue account = transactionEntry.getRelatedOne("GlAccount"); 503 504 double amountToAdd = transactionEntry.getDouble("amount").doubleValue(); 505 if ((UtilAccounting.isDebitAccount(account) && (transactionEntry.getString("debitCreditFlag").equals("C"))) || 506 (UtilAccounting.isCreditAccount(account) && (transactionEntry.getString("debitCreditFlag").equals("D")))) { 507 amountToAdd = -amountToAdd; 508 } 509 510 UtilMisc.addToDoubleInMap(glAccountSums, transactionEntry.getRelatedOne("GlAccount"), new Double (amountToAdd)); 511 } 512 Map result = ServiceUtil.returnSuccess(); 513 result.put("glAccountSums", glAccountSums); 514 return result; 515 } catch (GenericEntityException ex) { 516 return(ServiceUtil.returnError(ex.getMessage())); 517 } 518 } 519 520 521 533 private static Map getAcctgTransAndEntriesForClass(Map accountBalances, String organizationPartyId, Timestamp fromDate, 534 Timestamp thruDate, String glFiscalTypeId, String glAccountClassId, GenericValue userLogin, LocalDispatcher dispatcher) { 535 try { 536 Map tmpResult = dispatcher.runSync("getAcctgTransAndEntriesByType", UtilMisc.toMap("organizationPartyId", organizationPartyId, 538 "fromDate", fromDate, "thruDate", thruDate, "glFiscalTypeId", glFiscalTypeId, "glAccountClasses", UtilMisc.toList(glAccountClassId), "userLogin", userLogin)); 539 List transactionEntries = (List ) tmpResult.get("transactionEntries"); 540 541 tmpResult = dispatcher.runSync("addToAccountBalances", UtilMisc.toMap("glAccountSums", accountBalances, "transactionEntries", transactionEntries, "userLogin", userLogin)); 543 accountBalances = (Map ) tmpResult.get("glAccountSums"); 544 return accountBalances; 545 } catch (GenericServiceException ex) { 546 Debug.logError(ex.getMessage(), module); 547 return null; 548 } 549 } 550 551 public static Map getComparativeBalanceSheet(DispatchContext dctx, Map context) { 552 LocalDispatcher dispatcher = dctx.getDispatcher(); 553 GenericDelegator delegator = dctx.getDelegator(); 554 555 String organizationPartyId = (String ) context.get("organizationPartyId"); 557 String glFiscalTypeId = (String ) context.get("glFiscalTypeId"); 558 Timestamp fromDate = (Timestamp ) context.get("fromDate"); 559 Timestamp thruDate = (Timestamp ) context.get("thruDate"); 560 GenericValue userLogin = (GenericValue) context.get("userLogin"); 561 562 if (fromDate.after(thruDate)) { 564 return ServiceUtil.returnError("Cannot create a comparative balance for a from date that is after the thru date!"); 565 } 566 567 try { 568 Map input = UtilMisc.toMap("organizationPartyId", organizationPartyId, "glFiscalTypeId", glFiscalTypeId, "userLogin", userLogin); 570 input.put("asOfDate", fromDate); 571 Map fromDateResults = dispatcher.runSync("getBalanceSheetForDate", input); 572 if (ServiceUtil.isError(fromDateResults)) { 573 return ServiceUtil.returnError("Failed to create comparative balance sheet.", null, null, fromDateResults); 574 } 575 576 input.put("asOfDate", thruDate); 578 Map thruDateResults = dispatcher.runSync("getBalanceSheetForDate", input); 579 if (ServiceUtil.isError(thruDateResults)) { 580 return ServiceUtil.returnError("Failed to create comparative balance sheet.", null, null, thruDateResults); 581 } 582 583 Map results = ServiceUtil.returnSuccess(); 584 585 results.put("fromDateAccountBalances", fromDateResults); 587 results.put("thruDateAccountBalances", thruDateResults); 588 589 results.put("liabilityAccountBalances", 591 calculateDifferenceBalance((Map ) fromDateResults.get("liabilityAccountBalances"), (Map ) thruDateResults.get("liabilityAccountBalances"))); 592 results.put("assetAccountBalances", 593 calculateDifferenceBalance((Map ) fromDateResults.get("assetAccountBalances"), (Map ) thruDateResults.get("assetAccountBalances"))); 594 results.put("equityAccountBalances", 595 calculateDifferenceBalance((Map ) fromDateResults.get("equityAccountBalances"), (Map ) thruDateResults.get("equityAccountBalances"))); 596 return results; 597 } catch (GenericServiceException e) { 598 Debug.logError(e, "Failed to compute comparative balance: " + e.getMessage(), module); 599 return ServiceUtil.returnError("Failed to compute comparative balance: " + e.getMessage()); 600 } 601 } 602 603 606 private static Map calculateDifferenceBalance(Map fromDateMap, Map thruDateMap) { 607 Map resultMap = FastMap.newInstance(); 608 609 for (Iterator iter = thruDateMap.keySet().iterator(); iter.hasNext(); ) { 611 GenericValue account = (GenericValue) iter.next(); 612 Double thruDateBalance = (Double ) thruDateMap.get(account); 613 Double fromDateBalance = (Double ) fromDateMap.get(account); 614 if (thruDateBalance == null) thruDateBalance = new Double (0); 615 if (fromDateBalance == null) fromDateBalance = new Double (0); 616 double difference = thruDateBalance.doubleValue() - fromDateBalance.doubleValue(); 617 resultMap.put(account, (new BigDecimal (difference)).setScale(decimals, rounding)); 618 } 619 620 for (Iterator iter = fromDateMap.keySet().iterator(); iter.hasNext(); ) { 622 GenericValue account = (GenericValue) iter.next(); 623 if (resultMap.get(account) != null) continue; Double fromDateBalance = (Double ) fromDateMap.get(account); 625 if (fromDateBalance == null) fromDateBalance = new Double (0); 626 double difference = 0 - fromDateBalance.doubleValue(); 627 resultMap.put(account, (new BigDecimal (difference)).setScale(decimals, rounding)); 628 } 629 630 return resultMap; 631 } 632 633 637 private static Map reportServiceTimePeriodHelper(DispatchContext dctx, Map context, String serviceName, Map input) { 638 LocalDispatcher dispatcher = dctx.getDispatcher(); 639 GenericDelegator delegator = dctx.getDelegator(); 640 String fromTimePeriodId = (String ) context.get("fromTimePeriodId"); 641 String thruTimePeriodId = (String ) context.get("thruTimePeriodId"); 642 String organizationPartyId = (String ) input.get("organizationPartyId"); 643 644 try { 645 GenericValue fromTimePeriod = delegator.findByPrimaryKey("CustomTimePeriod", UtilMisc.toMap("customTimePeriodId", fromTimePeriodId)); 647 GenericValue thruTimePeriod = delegator.findByPrimaryKey("CustomTimePeriod", UtilMisc.toMap("customTimePeriodId", thruTimePeriodId)); 648 649 if (fromTimePeriod == null) { 651 return ServiceUtil.returnError("Custom time period " + fromTimePeriodId + " does not exist"); 652 } 653 if (thruTimePeriod == null) { 654 return ServiceUtil.returnError("Custom time period " + thruTimePeriodId + " does not exist"); 655 } 656 if (!(fromTimePeriod.getString("organizationPartyId").equals(organizationPartyId))) { 657 return ServiceUtil.returnError("Custom time period " + fromTimePeriodId + " does not belong to " + organizationPartyId); 658 } 659 if (!(thruTimePeriod.getString("organizationPartyId").equals(organizationPartyId))) { 660 return ServiceUtil.returnError("Custom time period " + thruTimePeriodId + " does not belong to " + organizationPartyId); 661 } 662 if (fromTimePeriod.get("fromDate") == null) { 663 return ServiceUtil.returnError("Cannot get a starting date from custom time period = " + fromTimePeriodId); 664 } else if (thruTimePeriod.get("thruDate") == null) { 665 return ServiceUtil.returnError("Cannot get a starting date from custom time period = " + thruTimePeriodId); 666 } 667 668 input.put("fromDate", UtilDateTime.toTimestamp(fromTimePeriod.getDate("fromDate"))); 670 input.put("thruDate", UtilDateTime.toTimestamp(thruTimePeriod.getDate("thruDate"))); 671 Map result = dispatcher.runSync(serviceName, input); 672 return result; 673 } catch (GenericEntityException ex) { 674 return(ServiceUtil.returnError(ex.getMessage())); 675 } catch (GenericServiceException ex) { 676 return(ServiceUtil.returnError(ex.getMessage())); 677 } 678 } 679 680 public static Map getCashFlowStatementForTimePeriods(DispatchContext dctx, Map context) { 681 String organizationPartyId = (String ) context.get("organizationPartyId"); 682 String glFiscalTypeId = (String ) context.get("glFiscalTypeId"); 683 GenericValue userLogin = (GenericValue) context.get("userLogin"); 684 Map input = UtilMisc.toMap("organizationPartyId", organizationPartyId, "glFiscalTypeId", glFiscalTypeId, "userLogin", userLogin); 685 return reportServiceTimePeriodHelper(dctx, context, "getCashFlowStatementForDates", input); 686 } 687 688 public static Map getCashFlowStatementForDates(DispatchContext dctx, Map context) { 689 LocalDispatcher dispatcher = dctx.getDispatcher(); 690 GenericDelegator delegator = dctx.getDelegator(); 691 GenericValue userLogin = (GenericValue) context.get("userLogin"); 692 693 Timestamp fromDate = (Timestamp ) context.get("fromDate"); 694 Timestamp thruDate = (Timestamp ) context.get("thruDate"); 695 String organizationPartyId = (String ) context.get("organizationPartyId"); 696 String glFiscalTypeId = (String ) context.get("glFiscalTypeId"); 697 698 try { 699 Map input = UtilMisc.toMap("organizationPartyId", organizationPartyId, "glFiscalTypeId", glFiscalTypeId, "userLogin", userLogin); 700 701 input.put("fromDate", fromDate); 703 input.put("thruDate", thruDate); 704 Map comparativeResults = dispatcher.runSync("getComparativeBalanceSheet", input); 705 if (ServiceUtil.isError(comparativeResults)) { 706 return ServiceUtil.returnError("Faild to compute cash flow statement. ", null, null, comparativeResults); 707 } 708 709 Map fromDateAccountBalances = (Map ) comparativeResults.get("fromDateAccountBalances"); 711 Map thruDateAccountBalances = (Map ) comparativeResults.get("thruDateAccountBalances"); 712 713 Map incomeResults = dispatcher.runSync("getIncomeStatementByDates", input); 715 if (ServiceUtil.isError(incomeResults)) { 716 return ServiceUtil.returnError("Faild to compute cash flow statement. ", null, null, incomeResults); 717 } 718 719 BigDecimal netIncome = new BigDecimal (((Double ) incomeResults.get("netIncome")).doubleValue()); 721 722 BigDecimal beginningCashAmount = ZERO; 724 Map beginningCashAccountBalances = FastMap.newInstance(); 725 Map beginningSheet = (Map ) fromDateAccountBalances.get("assetAccountBalances"); for (Iterator iter = beginningSheet.keySet().iterator(); iter.hasNext(); ) { 727 GenericValue account = (GenericValue) iter.next(); 728 if (!UtilAccounting.isAccountClass(account, "CASH_EQUIVALENT")) continue; BigDecimal amount = new BigDecimal (((Double ) beginningSheet.get(account)).doubleValue()); 730 beginningCashAccountBalances.put(account, amount); 731 beginningCashAmount = beginningCashAmount.add(amount).setScale(decimals, rounding); 732 } 733 734 BigDecimal endingCashAmount = ZERO; 736 Map endingCashAccountBalances = FastMap.newInstance(); 737 Map endingSheet = (Map ) thruDateAccountBalances.get("assetAccountBalances"); for (Iterator iter = endingSheet.keySet().iterator(); iter.hasNext(); ) { 739 GenericValue account = (GenericValue) iter.next(); 740 if (!UtilAccounting.isAccountClass(account, "CASH_EQUIVALENT")) continue; BigDecimal amount = new BigDecimal (((Double ) endingSheet.get(account)).doubleValue()); 742 endingCashAccountBalances.put(account, amount); 743 endingCashAmount = endingCashAmount.add(amount).setScale(decimals, rounding); 744 } 745 746 BigDecimal operatingCashFlow = ZERO; 748 BigDecimal investingCashFlow = ZERO; 749 BigDecimal financingCashFlow = ZERO; 750 751 Map operatingCashFlowAccountBalances = FastMap.newInstance(); 753 Map investingCashFlowAccountBalances = FastMap.newInstance(); 754 Map financingCashFlowAccountBalances = FastMap.newInstance(); 755 756 operatingCashFlow = netIncome; 758 759 Map glAccountSums = (Map ) incomeResults.get("glAccountSums"); 761 if ((glAccountSums != null) && (glAccountSums.keySet() != null)) { 762 for (Iterator iter = glAccountSums.keySet().iterator(); iter.hasNext(); ) { 763 GenericValue account = (GenericValue) iter.next(); 764 if (UtilAccounting.isAccountClass(account, "NON_CASH_EXPENSE") && !UtilAccounting.isAccountClass(account, "INVENTORY_ADJUST")) { 765 BigDecimal amount = new BigDecimal (((Double ) glAccountSums.get(account)).doubleValue()); 766 operatingCashFlowAccountBalances.put(account, amount.negate()); 767 operatingCashFlow = operatingCashFlow.subtract(amount).setScale(decimals, rounding); 768 } 769 } 770 } 771 772 Map statement = (Map ) comparativeResults.get("assetAccountBalances"); 774 if ((statement != null) && (statement.keySet() != null)) { 775 for (Iterator iter = statement.keySet().iterator(); iter.hasNext(); ) { 776 GenericValue account = (GenericValue) iter.next(); 777 778 if (UtilAccounting.isAccountClass(account, "CURRENT_ASSET") && !UtilAccounting.isAccountClass(account, "CASH_EQUIVALENT")) { 780 BigDecimal amount = (BigDecimal ) statement.get(account); 781 amount = ZERO.subtract(amount).setScale(decimals, rounding); operatingCashFlowAccountBalances.put(account, amount); 783 operatingCashFlow = operatingCashFlow.add(amount).setScale(decimals, rounding); 784 } 785 786 else if (UtilAccounting.isAccountClass(account, "LONGTERM_ASSET") && 788 !UtilAccounting.isAccountClass(account, "ACCUM_DEPRECIATION") && 789 !UtilAccounting.isAccountClass(account, "ACCUM_AMORTIZATION")) { 790 BigDecimal amount = (BigDecimal ) statement.get(account); 791 investingCashFlowAccountBalances.put(account, amount.negate()); 792 investingCashFlow = investingCashFlow.subtract((BigDecimal ) statement.get(account)).setScale(decimals, rounding); 793 } 794 } 795 } 796 797 statement = (Map ) comparativeResults.get("liabilityAccountBalances"); 799 if ((statement != null) && (statement.keySet() != null)) { 800 for (Iterator iter = statement.keySet().iterator(); iter.hasNext(); ) { 801 GenericValue account = (GenericValue) iter.next(); 802 803 if (UtilAccounting.isAccountClass(account, "CURRENT_LIABILITY")) { 805 operatingCashFlowAccountBalances.put(account, statement.get(account)); 806 operatingCashFlow = operatingCashFlow.add((BigDecimal ) statement.get(account)).setScale(decimals, rounding); 807 } 808 809 else if (UtilAccounting.isAccountClass(account, "LONGTERM_LIABILITY")) { 811 financingCashFlowAccountBalances.put(account, statement.get(account)); 812 financingCashFlow = financingCashFlow.add((BigDecimal ) statement.get(account)).setScale(decimals, rounding); 813 } 814 } 815 } 816 817 statement = (Map ) comparativeResults.get("equityAccountBalances"); 819 if ((statement != null) && (statement.keySet() != null)) { 820 for (Iterator iter = statement.keySet().iterator(); iter.hasNext(); ) { 821 GenericValue account = (GenericValue) iter.next(); 822 823 if (UtilAccounting.isAccountClass(account, "OWNERS_EQUITY")) { 825 financingCashFlowAccountBalances.put(account, statement.get(account)); 826 financingCashFlow = financingCashFlow.add((BigDecimal ) statement.get(account)).setScale(decimals, rounding); 827 } 828 } 829 } 830 831 statement = new HashMap (); statement = getAcctgTransAndEntriesForClass(statement, organizationPartyId, 834 fromDate, thruDate, glFiscalTypeId, "DISTRIBUTION", userLogin, dispatcher); 835 if ((statement != null) && (statement.keySet() != null)) { 836 for (Iterator iter = statement.keySet().iterator(); iter.hasNext(); ) { 837 GenericValue account = (GenericValue) iter.next(); 838 if (statement.get(account) != null) { 839 BigDecimal amount = new BigDecimal (((Double ) statement.get(account)).doubleValue()); 840 financingCashFlowAccountBalances.put(account, amount.negate()); 841 financingCashFlow = financingCashFlow.subtract(amount).setScale(decimals, rounding); 842 } 843 } 844 } 845 846 BigDecimal netCashFlowOne = endingCashAmount.subtract(beginningCashAmount); 848 BigDecimal netCashFlowTwo = operatingCashFlow.add(investingCashFlow).add(financingCashFlow); 849 if (netCashFlowOne.compareTo(netCashFlowTwo) != 0) { 850 Debug.logWarning("Net cash flow computation yielded different values! (ending cash amount - beginning cash amount) = [" 851 + netCashFlowOne.toString() + "]; (operating + investing + financing) = [" + netCashFlowTwo.toString() + "]", module); 852 } 853 854 Map results = ServiceUtil.returnSuccess(); 855 results.put("beginningCashAmount", beginningCashAmount); 856 results.put("beginningCashAccountBalances", beginningCashAccountBalances); 857 results.put("endingCashAmount", endingCashAmount); 858 results.put("endingCashAccountBalances", endingCashAccountBalances); 859 results.put("operatingCashFlowAccountBalances", operatingCashFlowAccountBalances); 860 results.put("investingCashFlowAccountBalances", investingCashFlowAccountBalances); 861 results.put("financingCashFlowAccountBalances", financingCashFlowAccountBalances); 862 results.put("operatingCashFlow", operatingCashFlow); 863 results.put("investingCashFlow", investingCashFlow); 864 results.put("financingCashFlow", financingCashFlow); 865 results.put("netIncome", netIncome); 866 results.put("netCashFlow", netCashFlowTwo); return results; 868 } catch (GenericServiceException e) { 869 Debug.logError(e, "Failed to compute cash flow statement: " + e.getMessage(), module); 870 return ServiceUtil.returnError("Failed to compute cash flow statement: " + e.getMessage()); 871 } catch (GenericEntityException e) { 872 Debug.logError(e, "Failed to compute cash flow statement: " + e.getMessage(), module); 873 return ServiceUtil.returnError("Failed to compute cash flow statement: " + e.getMessage()); 874 } 875 } 876 } 877 | Popular Tags |