KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > opensourcestrategies > crmsfa > forecasts > UtilForecast


1 /*
2  * Copyright (c) 2006 - 2007 Open Source Strategies, Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the Honest Public License.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * Honest Public License for more details.
11  *
12  * You should have received a copy of the Honest Public License
13  * along with this program; if not, write to Funambol,
14  * 643 Bair Island Road, Suite 305 - Redwood City, CA 94063, USA
15  */

16 /* Copyright (c) 2005-2006 Open Source Strategies, Inc. */
17
18 /*
19  * $Id:$
20  *
21  * Copyright (c) 2001-2005 The Open For Business Project - www.ofbiz.org
22  *
23  * Permission is hereby granted, free of charge, to any person obtaining a
24  * copy of this software and associated documentation files (the "Software"),
25  * to deal in the Software without restriction, including without limitation
26  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
27  * and/or sell copies of the Software, and to permit persons to whom the
28  * Software is furnished to do so, subject to the following conditions:
29  *
30  * The above copyright notice and this permission notice shall be included
31  * in all copies or substantial portions of the Software.
32  *
33  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
34  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
35  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
36  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
37  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
38  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
39  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40  */

41 package com.opensourcestrategies.crmsfa.forecasts;
42
43 import java.util.Map JavaDoc;
44 import java.util.List JavaDoc;
45 import java.util.ArrayList JavaDoc;
46 import java.util.Iterator JavaDoc;
47 import java.sql.Timestamp JavaDoc;
48 import java.math.BigDecimal JavaDoc;
49
50 import org.ofbiz.base.util.Debug;
51 import org.ofbiz.base.util.UtilMisc;
52 import org.ofbiz.base.util.UtilDateTime;
53 import org.ofbiz.base.util.UtilProperties;
54 import org.ofbiz.entity.GenericDelegator;
55 import org.ofbiz.entity.GenericValue;
56 import org.ofbiz.entity.GenericEntityException;
57 import org.ofbiz.entity.condition.EntityConditionList;
58 import org.ofbiz.entity.condition.EntityExpr;
59 import org.ofbiz.entity.condition.EntityOperator;
60 import org.ofbiz.entity.util.EntityFindOptions;
61 import org.ofbiz.entity.util.EntityUtil;
62 import org.ofbiz.entity.util.EntityListIterator;
63 import org.ofbiz.base.util.UtilNumber;
64
65 import com.opensourcestrategies.crmsfa.opportunities.UtilOpportunity;
66
67 /**
68  * Forecast utility methods.
69  *
70  * @author <a HREF="mailto:leon@opensourcestrategies.com">Leon Torres</a>
71  * @version $Rev: 312 $
72  */

73 public class UtilForecast {
74
75     public static final String JavaDoc module = UtilForecast.class.getName();
76
77     // BigDecimal scale and rounding mode
78
public static int BD_FORECAST_DECIMALS = UtilNumber.getBigDecimalScale("crmsfa.properties", "crmsfa.forecast.decimals");
79     public static int BD_FORECAST_PERCENT_ROUNDING = UtilNumber.getBigDecimalRoundingMode("crmsfa.properties", "crmsfa.forecast.rounding");
80     public static int BD_FORECAST_PERCENT_DECIMALS = UtilNumber.getBigDecimalScale("crmsfa.properties", "crmsfa.forecast.percent.decimals");
81     public static int BD_FORECAST_ROUNDING = UtilNumber.getBigDecimalRoundingMode("crmsfa.properties", "crmsfa.forecast.percent.rounding");
82     public static BigDecimal JavaDoc ZERO = new BigDecimal JavaDoc("0");
83
84     /**
85      * Computes the forecast for the indicated time period.
86      * @return Map of SalesForecast fields with the computed amounts as BigDecimals
87      */

88     public static Map JavaDoc computeForecastByOpportunities(Double JavaDoc quotaAmount, String JavaDoc organizationPartyId, String JavaDoc internalPartyId,
89             String JavaDoc currencyUomId, String JavaDoc customTimePeriodId, GenericDelegator delegator)
90         throws GenericEntityException {
91
92         // computation variables
93
BigDecimal JavaDoc closedAmount = ZERO;
94         BigDecimal JavaDoc bestCaseAmount = ZERO;
95         BigDecimal JavaDoc forecastAmount = ZERO;
96         BigDecimal JavaDoc percentOfQuotaForecast = ZERO;
97         BigDecimal JavaDoc percentOfQuotaClosed= ZERO;
98
99         // determine the minimum percet for computing forecast amounts
100
double minimumProbability = 0.0;
101         try {
102             minimumProbability = Double.parseDouble(UtilProperties.getPropertyValue("crmsfa.properties", "crmsfa.forecast.minProbability"));
103         } catch (NumberFormatException JavaDoc ne) {
104             Debug.logWarning("Failed to parse property \"crmsfa.forecast.minProbability\": " + ne.getMessage() + "\nSetting minimum probability to 0.0.", module);
105         }
106
107         // get the opportunities in the time period and loop through them
108
EntityListIterator opportunitiesELI = UtilOpportunity.getOpportunitiesForInternalParty(organizationPartyId, internalPartyId, customTimePeriodId, null, null, delegator);
109         List JavaDoc opportunities = opportunitiesELI.getCompleteList();
110
111         if (opportunities.size() == 0) {
112             Debug.logWarning("no opportunities were found for the internalParty [" + internalPartyId + "] and organizationParty [" + organizationPartyId + "] over time period id [" + customTimePeriodId + "]", module);
113         }
114
115         for (Iterator JavaDoc iter = opportunities.iterator(); iter.hasNext(); ) {
116             GenericValue opportunity = (GenericValue) iter.next();
117             if (Debug.verboseOn()) {
118                 Debug.logVerbose("for timePeriod [" + customTimePeriodId + "] and party [" + internalPartyId + "]. Now working with opportunity: " + opportunity, module);
119             }
120             BigDecimal JavaDoc amount = opportunity.getBigDecimal("estimatedAmount");
121             BigDecimal JavaDoc probability = opportunity.getBigDecimal("estimatedProbability");
122
123             if (amount == null) continue;
124
125             // TODO: conversion
126
String JavaDoc oppCurrencyUomId = opportunity.getString("currencyUomId");
127             if ((oppCurrencyUomId == null) || !oppCurrencyUomId.equals(currencyUomId)) {
128                 Debug.logWarning("Forecast currency unit of measure [" + currencyUomId + "] is different from opportunity ID [" + opportunity.getString("salesOpportunityId")
129                         + "] currency which is [" + oppCurrencyUomId + "]. However, conversion is not currently implemented. Forecast will be incorrect.", module);
130             }
131
132             if (opportunity.getString("opportunityStageId").equals("SOSTG_CLOSED")) {
133
134                 // closed amount, which is the sum of the closed opportunity amounts
135
closedAmount = closedAmount.add(amount).setScale(BD_FORECAST_DECIMALS, BD_FORECAST_ROUNDING);
136             } else {
137
138                 // best case amount, which is the sum of amounts from opportunities scheduled to be closed in the time period plus the closed amount
139
bestCaseAmount = bestCaseAmount.add(amount).setScale(BD_FORECAST_DECIMALS, BD_FORECAST_ROUNDING);
140
141                 // for probabilities above the threshold, add to forecast amount
142
if ((probability != null) && (probability.doubleValue() >= minimumProbability)) {
143                     forecastAmount = forecastAmount.add(probability.multiply(amount)).setScale(BD_FORECAST_DECIMALS, BD_FORECAST_ROUNDING);
144                 }
145             }
146             if (Debug.verboseOn()) {
147                 Debug.logVerbose("Now for timePeriod [" + customTimePeriodId + "] after opportunity [" + opportunity.getString("opportunityId") + "] " +
148                         "closedAmouont = [" + closedAmount + "] bestCaseAmount = [" + bestCaseAmount + "] forecastAmount = [" + forecastAmount + "]" , module);
149             }
150         }
151
152         bestCaseAmount = bestCaseAmount.add(closedAmount).setScale(BD_FORECAST_DECIMALS, BD_FORECAST_ROUNDING);
153         forecastAmount = forecastAmount.add(closedAmount).setScale(BD_FORECAST_DECIMALS, BD_FORECAST_ROUNDING);
154
155         // if the quota was provided, compute percent of quota forecast and closed
156
if (quotaAmount != null && quotaAmount.doubleValue() > 0.0) {
157             BigDecimal JavaDoc quota = new BigDecimal JavaDoc(quotaAmount.doubleValue());
158             percentOfQuotaForecast = forecastAmount.divide(quota, BD_FORECAST_PERCENT_DECIMALS, BD_FORECAST_PERCENT_ROUNDING);
159             percentOfQuotaClosed = closedAmount.divide(quota, BD_FORECAST_PERCENT_DECIMALS, BD_FORECAST_PERCENT_ROUNDING);
160         }
161
162         // reutrn the computation as one big map which is ready to be set as fields of SalesForecast
163
return UtilMisc.toMap("closedAmount", new Double JavaDoc(closedAmount.doubleValue()), "bestCaseAmount", new Double JavaDoc(bestCaseAmount.doubleValue()),
164                 "forecastAmount", new Double JavaDoc(forecastAmount.doubleValue()), "percentOfQuotaForecast", new Double JavaDoc(percentOfQuotaForecast.doubleValue()),
165                 "percentOfQuotaClosed", new Double JavaDoc(percentOfQuotaClosed.doubleValue()));
166     }
167
168     public static Map JavaDoc computeForecastByChildren(String JavaDoc parentPeriodId, String JavaDoc organizationPartyId, String JavaDoc internalPartyId,
169             String JavaDoc currencyUomId, GenericDelegator delegator)
170         throws GenericEntityException {
171
172         // computation variables
173
BigDecimal JavaDoc quotaAmount = ZERO;
174         BigDecimal JavaDoc closedAmount = ZERO;
175         BigDecimal JavaDoc bestCaseAmount = ZERO;
176         BigDecimal JavaDoc forecastAmount = ZERO;
177         BigDecimal JavaDoc percentOfQuotaForecast = ZERO;
178         BigDecimal JavaDoc percentOfQuotaClosed= ZERO;
179
180         // get the children and loop through them TODO: conversion
181
List JavaDoc forecasts = delegator.findByAnd("SalesForecastAndCustomTimePeriod", UtilMisc.toMap("parentPeriodId", parentPeriodId,
182                     "organizationPartyId", organizationPartyId, "internalPartyId", internalPartyId));
183         for (Iterator JavaDoc iter = forecasts.iterator(); iter.hasNext(); ) {
184             GenericValue forecast = (GenericValue) iter.next();
185
186             BigDecimal JavaDoc childQuotaAmount = forecast.getBigDecimal("quotaAmount");
187             if (childQuotaAmount != null) {
188                 quotaAmount = quotaAmount.add(childQuotaAmount).setScale(BD_FORECAST_DECIMALS, BD_FORECAST_ROUNDING);
189             }
190
191             BigDecimal JavaDoc childClosedAmount = forecast.getBigDecimal("closedAmount");
192             if (childClosedAmount != null) {
193                 closedAmount = closedAmount.add(childClosedAmount).setScale(BD_FORECAST_DECIMALS, BD_FORECAST_ROUNDING);
194             }
195
196             BigDecimal JavaDoc childForecastAmount = forecast.getBigDecimal("forecastAmount");
197             if (childForecastAmount != null) {
198                 forecastAmount = forecastAmount.add(childForecastAmount).setScale(BD_FORECAST_DECIMALS, BD_FORECAST_ROUNDING);
199             }
200
201             BigDecimal JavaDoc childBestCaseAmount = forecast.getBigDecimal("bestCaseAmount");
202             if (childBestCaseAmount != null) {
203                 bestCaseAmount = bestCaseAmount.add(childBestCaseAmount).setScale(BD_FORECAST_DECIMALS, BD_FORECAST_ROUNDING);
204             }
205         }
206
207         // if the quota is non-zero, set the percentages
208
if (quotaAmount.signum() != 0) {
209             percentOfQuotaForecast = forecastAmount.divide(quotaAmount, BD_FORECAST_PERCENT_DECIMALS, BD_FORECAST_PERCENT_ROUNDING);
210             percentOfQuotaClosed = closedAmount.divide(quotaAmount, BD_FORECAST_PERCENT_DECIMALS, BD_FORECAST_PERCENT_ROUNDING);
211         }
212
213         // reutrn the computation as one big map which is ready to be set as fields of SalesForecast
214
return UtilMisc.toMap("closedAmount", new Double JavaDoc(closedAmount.doubleValue()), "bestCaseAmount", new Double JavaDoc(bestCaseAmount.doubleValue()),
215                 "forecastAmount", new Double JavaDoc(forecastAmount.doubleValue()), "percentOfQuotaForecast", new Double JavaDoc(percentOfQuotaForecast.doubleValue()),
216                 "percentOfQuotaClosed", new Double JavaDoc(percentOfQuotaClosed.doubleValue()), "quotaAmount", new Double JavaDoc(quotaAmount.doubleValue()));
217     }
218 }
219
Popular Tags