KickJava   Java API By Example, From Geeks To Geeks.

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


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.*;
44 import java.sql.Timestamp JavaDoc;
45
46 import org.ofbiz.base.util.*;
47 import org.ofbiz.base.util.collections.ResourceBundleMapWrapper;
48 import org.ofbiz.entity.*;
49 import org.ofbiz.entity.condition.*;
50 import org.ofbiz.entity.util.EntityUtil;
51 import org.ofbiz.service.DispatchContext;
52 import org.ofbiz.service.GenericServiceException;
53 import org.ofbiz.service.ModelService;
54 import org.ofbiz.service.LocalDispatcher;
55 import org.ofbiz.service.ServiceUtil;
56 import org.ofbiz.security.Security;
57
58 import com.opensourcestrategies.crmsfa.party.PartyHelper;
59 import com.opensourcestrategies.crmsfa.security.CrmsfaSecurity;
60 import com.opensourcestrategies.crmsfa.util.UtilCommon;
61 import com.opensourcestrategies.crmsfa.forecasts.UtilForecast;
62 import com.opensourcestrategies.crmsfa.opportunities.UtilOpportunity;
63
64 /**
65  * Forecasts services. The service documentation is in services_forecasts.xml.
66  *
67  * @author <a HREF="mailto:leon@opensourcestrategies.com">Leon Torres</a>
68  * @author <a HREF="mailto:sichen@opensourcestrategies.com">Si Chen</a>
69  * @version $Rev: 312 $
70  */

71
72 public class ForecastsServices {
73
74     public static final String JavaDoc module = ForecastsServices.class.getName();
75     
76     protected static final String JavaDoc FORECAST_CHANGE_NOTE_PREFIX_UILABEL = "CrmForecastChangeNotePrefix";
77
78     public static Map updateForecast(DispatchContext dctx, Map context) {
79         GenericDelegator delegator = dctx.getDelegator();
80         LocalDispatcher dispatcher = dctx.getDispatcher();
81         Security security = dctx.getSecurity();
82         GenericValue userLogin = (GenericValue) context.get("userLogin");
83         Locale locale = (Locale) context.get("locale");
84
85         String JavaDoc salesForecastId = (String JavaDoc) context.get("salesForecastId");
86         Double JavaDoc quotaAmount = (Double JavaDoc) context.get("quotaAmount");
87         try {
88             GenericValue forecast = delegator.findByPrimaryKey("SalesForecast", UtilMisc.toMap("salesForecastId", salesForecastId));
89             if (forecast == null) {
90                 return UtilCommon.createAndLogServiceError("Forecast with ID [" + salesForecastId + "] not found.", "CrmErrorComputeForecastFail", locale, module);
91             }
92
93             // compute the fields for the forecast (use the internalPartyId of the existing forecast)
94
Map computed = UtilForecast.computeForecastByOpportunities(quotaAmount, forecast.getString("organizationPartyId"),
95                     forecast.getString("internalPartyId"), forecast.getString("currencyUomId"), forecast.getString("customTimePeriodId"), delegator);
96
97             // make the service input map from the context
98
ModelService service = dctx.getModelService("updateSalesForecast");
99             Map input = service.makeValid(context, "IN");
100
101             // add rest of fields (in this case we preserve the previous internalPartyId)
102
input.put("salesForecastId", salesForecastId);
103             input.putAll(computed);
104             input.put("userLogin", userLogin);
105
106             // run our update/create service
107
Map serviceResults = dispatcher.runSync("updateSalesForecast", input);
108             if (ServiceUtil.isError(serviceResults)) {
109                 return UtilCommon.createAndLogServiceError(serviceResults, "CrmErrorComputeForecastFail", locale, module);
110             }
111
112             // now recompute the parent forecast by calling our service for this with the parent as input
113
// TODO: normally we could use: GenericValue parent = forecast.getRelatedOne("ParentSalesForecast");
114
// TODO: but we can't yet untill we re-arrange the way forecasts are created (create all of them once quarter is selected, then compute values)
115
// TODO: so this is a complete hack:
116
GenericValue period = forecast.getRelatedOne("CustomTimePeriod");
117             List parents = delegator.findByAnd("SalesForecastAndCustomTimePeriod", UtilMisc.toMap("customTimePeriodId", period.getString("parentPeriodId"),
118                         "internalPartyId", forecast.getString("internalPartyId"), "organizationPartyId", forecast.getString("organizationPartyId"),
119                         "periodTypeId", "FISCAL_QUARTER")); // XXX HACK
120
GenericValue parent = (GenericValue) parents.get(0); // XXX HACK
121

122             service = dctx.getModelService("crmsfa.computeForecastParentPeriod");
123             input = service.makeValid(parent.getAllFields(), "IN");
124             input.put("userLogin", userLogin);
125             input.put("parentPeriodId", period.getString("parentPeriodId"));
126             input.put("changeNote", context.get("changeNote")); // also update the change note in parent
127
serviceResults = dispatcher.runSync("crmsfa.computeForecastParentPeriod", input);
128             if (ServiceUtil.isError(serviceResults)) {
129                 return UtilCommon.createAndLogServiceError(serviceResults, "CrmErrorComputeForecastFail", locale, module);
130             }
131         } catch (GenericEntityException e) {
132             return UtilCommon.createAndLogServiceError(e, "CrmErrorComputeForecastFail", locale, module);
133         } catch (GenericServiceException e) {
134             return UtilCommon.createAndLogServiceError(e, "CrmErrorComputeForecastFail", locale, module);
135         }
136         return ServiceUtil.returnSuccess();
137
138     }
139
140     // TODO: The next two methods have a lot of overlapping code. We should try to re-factor.
141
public static Map computeForecastPeriod(DispatchContext dctx, Map context) {
142         GenericDelegator delegator = dctx.getDelegator();
143         LocalDispatcher dispatcher = dctx.getDispatcher();
144         Security security = dctx.getSecurity();
145         GenericValue userLogin = (GenericValue) context.get("userLogin");
146         Locale locale = (Locale) context.get("locale");
147
148         String JavaDoc customTimePeriodId = (String JavaDoc) context.get("customTimePeriodId");
149         String JavaDoc organizationPartyId = (String JavaDoc) context.get("organizationPartyId");
150         String JavaDoc currencyUomId = (String JavaDoc) context.get("currencyUomId");
151
152         // set the quota to 0.00 if the user didn't supply it, that way we get all forecasts for a set of periods rather than a few that had quotas defined
153
Double JavaDoc quotaAmount = (Double JavaDoc) context.get("quotaAmount");
154         if (quotaAmount == null) quotaAmount = new Double JavaDoc(0.00);
155
156         try {
157             String JavaDoc salesForecastId = (String JavaDoc) context.get("salesForecastId");
158             String JavaDoc serviceName = null;
159             String JavaDoc internalPartyId = null;
160
161             // see if we were passed a salesForecastId and determine service to run and party for whom forecast is computed
162
if (salesForecastId == null) {
163                 serviceName = "createSalesForecast";
164                 internalPartyId = userLogin.getString("partyId");
165             } else {
166                 serviceName = "updateSalesForecast";
167                 GenericValue forecast = delegator.findByPrimaryKey("SalesForecast", UtilMisc.toMap("salesForecastId", salesForecastId));
168                 if ((forecast != null) && (forecast.getString("internalPartyId") != null)) {
169                     internalPartyId = forecast.getString("internalPartyId");
170                 } else {
171                     return ServiceUtil.returnError("Invalid forecast or missing forecast.internalPartyId for forecast [" + salesForecastId + "]");
172                 }
173             }
174
175             // compute the fields for the forecast
176
Map computed = UtilForecast.computeForecastByOpportunities(quotaAmount, organizationPartyId, internalPartyId,
177                     currencyUomId, customTimePeriodId, delegator);
178
179             // make the service input map from the context
180
ModelService service = dctx.getModelService(serviceName);
181             Map input = service.makeValid(context, "IN");
182
183             // add our computed fields and the userlogin
184
input.putAll(computed);
185             input.put("userLogin", userLogin);
186             input.put("internalPartyId", internalPartyId);
187
188             // run our update/create service
189
Map serviceResults = dispatcher.runSync(serviceName, input);
190             if (ServiceUtil.isError(serviceResults)) {
191                 return UtilCommon.createAndLogServiceError(serviceResults, "CrmErrorComputeForecastFail", locale, module);
192             }
193         } catch (GenericEntityException e) {
194             return UtilCommon.createAndLogServiceError(e, "CrmErrorComputeForecastFail", locale, module);
195         } catch (GenericServiceException e) {
196             return UtilCommon.createAndLogServiceError(e, "CrmErrorComputeForecastFail", locale, module);
197         }
198         return ServiceUtil.returnSuccess();
199     }
200
201     public static Map computeForecastParentPeriod(DispatchContext dctx, Map context) {
202         GenericDelegator delegator = dctx.getDelegator();
203         LocalDispatcher dispatcher = dctx.getDispatcher();
204         Security security = dctx.getSecurity();
205         GenericValue userLogin = (GenericValue) context.get("userLogin");
206         Locale locale = (Locale) context.get("locale");
207
208         String JavaDoc parentPeriodId = (String JavaDoc) context.get("parentPeriodId");
209         String JavaDoc organizationPartyId = (String JavaDoc) context.get("organizationPartyId");
210         String JavaDoc currencyUomId = (String JavaDoc) context.get("currencyUomId");
211
212         try {
213             // see if we were passed a salesForecastId
214
String JavaDoc salesForecastId = (String JavaDoc) context.get("salesForecastId");
215             String JavaDoc serviceName = null;
216             String JavaDoc internalPartyId = null;
217
218             // see if we were passed a salesForecastId and determine service to run and party for whom forecast is computed
219
if (salesForecastId == null) {
220                 serviceName = "createSalesForecast";
221                 internalPartyId = userLogin.getString("partyId");
222             } else {
223                 serviceName = "updateSalesForecast";
224                 GenericValue forecast = delegator.findByPrimaryKey("SalesForecast", UtilMisc.toMap("salesForecastId", salesForecastId));
225                 if ((forecast != null) && (forecast.getString("internalPartyId") != null)) {
226                     internalPartyId = forecast.getString("internalPartyId");
227                 } else {
228                     return ServiceUtil.returnError("Invalid forecast or missing forecast.internalPartyId for forecast [" + salesForecastId + "]");
229                 }
230             }
231
232             // compute the fields for the forecast
233
Map computed = UtilForecast.computeForecastByChildren(parentPeriodId, organizationPartyId, internalPartyId, currencyUomId, delegator);
234
235             // make the service input map from the context
236
ModelService service = dctx.getModelService(serviceName);
237             Map input = service.makeValid(context, "IN");
238             input.put("customTimePeriodId", parentPeriodId); // the parent period is the custom time period
239

240             // add our computed fields and the userlogin
241
input.putAll(computed);
242             input.put("userLogin", userLogin);
243             input.put("internalPartyId", internalPartyId);
244
245             // run our update/create service
246
Map serviceResults = dispatcher.runSync(serviceName, input);
247             if (ServiceUtil.isError(serviceResults)) {
248                 return UtilCommon.createAndLogServiceError(serviceResults, "CrmErrorComputeForecastFail", locale, module);
249             }
250             // if we had no sales forecast, then return the one we just created
251
if (salesForecastId == null) {
252                 salesForecastId = (String JavaDoc) serviceResults.get("salesForecastId");
253             }
254             
255             Map results = ServiceUtil.returnSuccess();
256             results.put("salesForecastId", salesForecastId);
257             return results;
258         } catch (GenericEntityException e) {
259             return UtilCommon.createAndLogServiceError(e, "CrmErrorComputeForecastFail", locale, module);
260         } catch (GenericServiceException e) {
261             return UtilCommon.createAndLogServiceError(e, "CrmErrorComputeForecastFail", locale, module);
262         }
263     }
264
265     public static Map updateForecastsRelatedToOpportunity(DispatchContext dctx, Map context) {
266         GenericDelegator delegator = dctx.getDelegator();
267         LocalDispatcher dispatcher = dctx.getDispatcher();
268         Security security = dctx.getSecurity();
269         GenericValue userLogin = (GenericValue) context.get("userLogin");
270         Locale locale = (Locale) context.get("locale");
271         ResourceBundleMapWrapper uiLabelMap = (ResourceBundleMapWrapper) UtilProperties.getResourceBundleMap("CRMSFAUiLabels", locale);
272
273         String JavaDoc salesOpportunityId = (String JavaDoc) context.get("salesOpportunityId");
274         String JavaDoc changeNote = (String JavaDoc) context.get("changeNote");
275         Timestamp JavaDoc previousEstimatedCloseDate = (Timestamp JavaDoc) context.get("previousEstimatedCloseDate");
276         
277         // get the organization from the properties
278
String JavaDoc organizationPartyId = (String JavaDoc) UtilProperties.getPropertyValue("crmsfa.properties", "organizationPartyId");
279
280         try {
281             GenericValue opportunity = delegator.findByPrimaryKey("SalesOpportunity", UtilMisc.toMap("salesOpportunityId", salesOpportunityId));
282             
283             // construct the changeNote with a link back to the opportunity (for errors/messages)
284
StringBuffer JavaDoc changeNoteBuff = new StringBuffer JavaDoc((String JavaDoc) uiLabelMap.get(FORECAST_CHANGE_NOTE_PREFIX_UILABEL));
285             changeNoteBuff.append("<a class='buttontext' HREF='viewOpportunity?salesOpportunityId=").append(salesOpportunityId).append("'>")
286                 .append(opportunity.getString("opportunityName")).append(" (").append(salesOpportunityId).append(")</a>");
287             if (changeNote != null) {
288                 changeNoteBuff.append(": ").append(changeNote);
289             }
290
291             /*
292              * Strategy: Build a list of partyIds whose forecasts would be affected by opportunity.
293              *
294              * For account opportunities, get the team members for the one related account.
295              * For lead opportunities, get the LEAD_OWNER partyId.
296              *
297              * Then, find all forecasts for these partyId's in the "affected" periods. An
298              * "affected" time period falls in the opportunity's estimatedCloseDate and the last
299              * estimatedCloseDate (determined from SalesOpportunityHistory). For each FISCAL_MONTH
300              * forecast found, the compute forecast service is called with all the values of that
301              * forecast, as if the forecast were being updated. After doing months, compute the
302              * quarters (FISCAL_QUARTER) in the same manner.
303              */

304
305             String JavaDoc accountPartyId = (String JavaDoc) UtilOpportunity.getOpportunityAccountPartyId(opportunity);
306             String JavaDoc leadPartyId = (String JavaDoc) UtilOpportunity.getOpportunityLeadPartyId(opportunity);
307             boolean isAccountOpportunity = (accountPartyId != null ? true : false);
308             Set partyIds = new HashSet();
309
310             if (isAccountOpportunity) {
311                 // get all the team members and collect their IDs into a Set
312
List teamMembers = UtilOpportunity.getOpportunityTeamMembers(salesOpportunityId, delegator);
313                 for (Iterator iter = teamMembers.iterator(); iter.hasNext(); ) {
314                     GenericValue teamMember = (GenericValue) iter.next();
315                     partyIds.add(teamMember.getString("partyId"));
316                 }
317             } else {
318                 // get the LEAD_OWNER partyId
319
GenericValue leadOwner = PartyHelper.getCurrentLeadOwner(leadPartyId, delegator);
320                 if (leadOwner == null) {
321                     return UtilCommon.createAndLogServiceError("No LEAD_OWNER for lead ["+leadPartyId+"] found!", locale, module);
322                 }
323                 partyIds.add(leadOwner.getString("partyId"));
324             }
325
326             // if no parties found, then we're done
327
if (partyIds.size() == 0) {
328                 return ServiceUtil.returnSuccess();
329             }
330
331             // We want all time periods that contain the new estimatedCloseDate, and the old one if it's different
332
List periodConditions = new ArrayList();
333             periodConditions.add(EntityUtil.getFilterByDateExpr(opportunity.getTimestamp("estimatedCloseDate")));
334             if (previousEstimatedCloseDate != null) {
335                 // because this condition will be joined by OR, we don't need to worry about them being different
336
periodConditions.add(EntityUtil.getFilterByDateExpr(previousEstimatedCloseDate));
337             }
338
339             // get the forecasts (ideally we want a distinct, but the way the query is constructed should guarantee a distinct set anyway)
340
EntityConditionList conditions = new EntityConditionList( UtilMisc.toList(
341                         new EntityConditionList(periodConditions, EntityOperator.OR), // join the periods by OR
342
new EntityExpr("organizationPartyId", EntityOperator.EQUALS, organizationPartyId),
343                         new EntityExpr("internalPartyId", EntityOperator.IN, partyIds)
344                         ), EntityOperator.AND);
345
346             List forecasts = delegator.findByCondition("SalesForecastAndCustomTimePeriod", conditions, null, null);
347
348             // update forecasts of type FISCAL_MONTH first
349
for (Iterator iter = forecasts.iterator(); iter.hasNext(); ) {
350                 GenericValue forecast = (GenericValue) iter.next();
351                 if (!forecast.getString("periodTypeId").equals("FISCAL_MONTH")) continue;
352
353                 Map input = UtilMisc.toMap("userLogin", userLogin, "organizationPartyId", organizationPartyId, "currencyUomId", forecast.get("currencyUomId"));
354                 input.put("customTimePeriodId", forecast.getString("customTimePeriodId"));
355                 input.put("salesForecastId", forecast.getString("salesForecastId"));
356                 input.put("quotaAmount", forecast.getDouble("quotaAmount"));
357                 input.put("changeNote", changeNoteBuff.toString());
358                 Map serviceResults = dispatcher.runSync("crmsfa.computeForecastPeriod", input);
359                 if (ServiceUtil.isError(serviceResults)) {
360                     return UtilCommon.createAndLogServiceError(serviceResults, "CrmErrorComputeForecastFail", locale, module);
361                 }
362                 iter.remove(); // this helps speed up the next iteration
363
}
364
365             // update forecasts of type FISCAL_QUARTER
366
for (Iterator iter = forecasts.iterator(); iter.hasNext(); ) {
367                 GenericValue forecast = (GenericValue) iter.next();
368                 if (!forecast.getString("periodTypeId").equals("FISCAL_QUARTER")) continue;
369
370                 Map input = UtilMisc.toMap("userLogin", userLogin, "organizationPartyId", organizationPartyId, "currencyUomId", forecast.get("currencyUomId"));
371                 input.put("parentPeriodId", forecast.getString("customTimePeriodId"));
372                 input.put("salesForecastId", forecast.getString("salesForecastId"));
373                 input.put("changeNote", changeNoteBuff.toString());
374                 Map serviceResults = dispatcher.runSync("crmsfa.computeForecastParentPeriod", input);
375                 if (ServiceUtil.isError(serviceResults)) {
376                     return UtilCommon.createAndLogServiceError(serviceResults, "CrmErrorComputeForecastFail", locale, module);
377                 }
378             }
379         } catch (GenericEntityException e) {
380             return UtilCommon.createAndLogServiceError(e, "CrmErrorComputeForecastFail", locale, module);
381         } catch (GenericServiceException e) {
382             return UtilCommon.createAndLogServiceError(e, "CrmErrorComputeForecastFail", locale, module);
383         }
384         return ServiceUtil.returnSuccess();
385     }
386 }
387
Popular Tags