KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ofbiz > product > price > PriceServices


1 /*
2  * $Id: PriceServices.java 7275 2006-04-11 08:59:24Z jonesde $
3  *
4  * Copyright (c) 2001-2005 The Open For Business Project - www.ofbiz.org
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */

24 package org.ofbiz.product.price;
25
26 import java.math.BigDecimal JavaDoc;
27 import java.sql.Timestamp JavaDoc;
28 import java.util.Collection JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.LinkedList JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.TreeSet JavaDoc;
35
36 import javolution.util.FastList;
37
38 import org.ofbiz.base.util.Debug;
39 import org.ofbiz.base.util.UtilDateTime;
40 import org.ofbiz.base.util.UtilMisc;
41 import org.ofbiz.base.util.UtilProperties;
42 import org.ofbiz.base.util.UtilValidate;
43 import org.ofbiz.entity.GenericDelegator;
44 import org.ofbiz.entity.GenericEntityException;
45 import org.ofbiz.entity.GenericValue;
46 import org.ofbiz.entity.condition.EntityCondition;
47 import org.ofbiz.entity.condition.EntityConditionList;
48 import org.ofbiz.entity.condition.EntityExpr;
49 import org.ofbiz.entity.condition.EntityOperator;
50 import org.ofbiz.entity.util.EntityUtil;
51 import org.ofbiz.product.product.ProductWorker;
52 import org.ofbiz.service.DispatchContext;
53 import org.ofbiz.service.GenericServiceException;
54 import org.ofbiz.service.LocalDispatcher;
55 import org.ofbiz.service.ServiceUtil;
56
57 /**
58  * PriceServices - Workers and Services class for product price related functionality
59  *
60  * @author <a HREF="mailto:jonesde@ofbiz.org">David E. Jones</a>
61  * @author <a HREF="mailto:jaz@ofbiz.org">Andy Zeneski</a>
62  * @version $Rev: 7275 $
63  * @since 2.0
64  */

65 public class PriceServices {
66
67     public static final String JavaDoc module = PriceServices.class.getName();
68     public static final BigDecimal JavaDoc ONE_BASE = new BigDecimal JavaDoc("1.000");
69     public static final BigDecimal JavaDoc PERCENT_SCALE = new BigDecimal JavaDoc("100.000");
70
71     /**
72      * <p>Calculates the price of a product from pricing rules given the following input, and of course access to the database:</p>
73      * <ul>
74      * <li>productId
75      * <li>partyId
76      * <li>prodCatalogId
77      * <li>webSiteId
78      * <li>productStoreId
79      * <li>productStoreGroupId
80      * <li>quantity
81      * <li>currencyUomId
82      * <li>checkIncludeVat
83      * </ul>
84      */

85     public static Map JavaDoc calculateProductPrice(DispatchContext dctx, Map JavaDoc context) {
86         boolean optimizeForLargeRuleSet = false;
87
88         // UtilTimer utilTimer = new UtilTimer();
89
// utilTimer.timerString("Starting price calc", module);
90
// utilTimer.setLog(false);
91

92         GenericDelegator delegator = dctx.getDelegator();
93         LocalDispatcher dispatcher = dctx.getDispatcher();
94         Map JavaDoc result = new HashMap JavaDoc();
95         Timestamp JavaDoc nowTimestamp = UtilDateTime.nowTimestamp();
96
97         boolean isSale = false;
98         List JavaDoc orderItemPriceInfos = new LinkedList JavaDoc();
99
100         GenericValue product = (GenericValue) context.get("product");
101         String JavaDoc productId = product.getString("productId");
102         String JavaDoc prodCatalogId = (String JavaDoc) context.get("prodCatalogId");
103         String JavaDoc webSiteId = (String JavaDoc) context.get("webSiteId");
104         String JavaDoc checkIncludeVat = (String JavaDoc) context.get("checkIncludeVat");
105
106         String JavaDoc productStoreId = (String JavaDoc) context.get("productStoreId");
107         String JavaDoc productStoreGroupId = (String JavaDoc) context.get("productStoreGroupId");
108         GenericValue productStore = null;
109         try {
110             // we have a productStoreId, if the corresponding ProductStore.primaryStoreGroupId is not empty, use that
111
productStore = delegator.findByPrimaryKeyCache("ProductStore", UtilMisc.toMap("productStoreId", productStoreId));
112         } catch (GenericEntityException e) {
113             String JavaDoc errMsg = "Error getting product store info from the database while calculating price" + e.toString();
114             Debug.logError(e, errMsg, module);
115             return ServiceUtil.returnError(errMsg);
116         }
117         if (UtilValidate.isEmpty(productStoreGroupId)) {
118             if (productStore != null) {
119                 try {
120                     if (UtilValidate.isNotEmpty(productStore.getString("primaryStoreGroupId"))) {
121                         productStoreGroupId = productStore.getString("primaryStoreGroupId");
122                     } else {
123                         // no ProductStore.primaryStoreGroupId, try ProductStoreGroupMember
124
List JavaDoc productStoreGroupMemberList = delegator.findByAndCache("ProductStoreGroupMember", UtilMisc.toMap("productStoreId", productStoreId), UtilMisc.toList("sequenceNum", "-fromDate"));
125                         productStoreGroupMemberList = EntityUtil.filterByDate(productStoreGroupMemberList, true);
126                         if (productStoreGroupMemberList.size() > 0) {
127                             GenericValue productStoreGroupMember = EntityUtil.getFirst(productStoreGroupMemberList);
128                             productStoreGroupId = productStoreGroupMember.getString("productStoreGroupId");
129                         }
130                     }
131                 } catch (GenericEntityException e) {
132                     String JavaDoc errMsg = "Error getting product store info from the database while calculating price" + e.toString();
133                     Debug.logError(e, errMsg, module);
134                     return ServiceUtil.returnError(errMsg);
135                 }
136             }
137
138             // still empty, default to _NA_
139
if (UtilValidate.isEmpty(productStoreGroupId)) {
140                 productStoreGroupId = "_NA_";
141             }
142         }
143         
144         // if currencyUomId is null get from properties file, if nothing there assume USD (USD: American Dollar) for now
145
String JavaDoc currencyUomId = (String JavaDoc) context.get("currencyUomId");
146         if (UtilValidate.isEmpty(currencyUomId)) {
147             currencyUomId = UtilProperties.getPropertyValue("general", "currency.uom.id.default", "USD");
148         }
149
150         // productPricePurposeId is null assume "PURCHASE", which is equivalent to what prices were before the purpose concept
151
String JavaDoc productPricePurposeId = (String JavaDoc) context.get("productPricePurposeId");
152         if (UtilValidate.isEmpty(productPricePurposeId)) {
153             productPricePurposeId = "PURCHASE";
154         }
155         
156         // termUomId, for things like recurring prices specifies the term (time/frequency measure for example) of the recurrence
157
// if this is empty it will simply not be used to constrain the selection
158
String JavaDoc termUomId = (String JavaDoc) context.get("termUomId");
159
160         // if this product is variant, find the virtual product and apply checks to it as well
161
String JavaDoc virtualProductId = null;
162         if ("Y".equals(product.getString("isVariant"))) {
163             try {
164                 virtualProductId = ProductWorker.getVariantVirtualId(product);
165             } catch (GenericEntityException e) {
166                 String JavaDoc errMsg = "Error getting virtual product id from the database while calculating price" + e.toString();
167                 Debug.logError(e, errMsg, module);
168                 return ServiceUtil.returnError(errMsg);
169             }
170         }
171
172         // get prices for virtual product if one is found; get all ProductPrice entities for this productId and currencyUomId
173
List JavaDoc virtualProductPrices = null;
174         if (virtualProductId != null) {
175             try {
176                 virtualProductPrices = delegator.findByAndCache("ProductPrice", UtilMisc.toMap("productId", virtualProductId, "currencyUomId", currencyUomId, "productStoreGroupId", productStoreGroupId), UtilMisc.toList("-fromDate"));
177             } catch (GenericEntityException e) {
178                 Debug.logError(e, "An error occurred while getting the product prices", module);
179             }
180             virtualProductPrices = EntityUtil.filterByDate(virtualProductPrices, true);
181         }
182
183         // NOTE: partyId CAN be null
184
String JavaDoc partyId = (String JavaDoc) context.get("partyId");
185         if (UtilValidate.isEmpty(partyId) && context.get("userLogin") != null) {
186             GenericValue userLogin = (GenericValue) context.get("userLogin");
187             partyId = userLogin.getString("partyId");
188         }
189
190         // check for auto-userlogin for price rules
191
if (UtilValidate.isEmpty(partyId) && context.get("autoUserLogin") != null) {
192             GenericValue userLogin = (GenericValue) context.get("autoUserLogin");
193             partyId = userLogin.getString("partyId");
194         }
195
196         Double JavaDoc quantityDbl = (Double JavaDoc) context.get("quantity");
197         if (quantityDbl == null) quantityDbl = new Double JavaDoc(1.0);
198         double quantity = quantityDbl.doubleValue();
199         
200         List JavaDoc productPriceEcList = FastList.newInstance();
201         productPriceEcList.add(new EntityExpr("productId", EntityOperator.EQUALS, productId));
202         // this funny statement is for backward compatibility purposes; the productPricePurposeId is a new pk field on the ProductPrice entity and in order databases may not be populated, until the pk is updated and such; this will ease the transition somewhat
203
if ("PURCHASE".equals(productPricePurposeId)) {
204             productPriceEcList.add(new EntityExpr(
205                     new EntityExpr("productPricePurposeId", EntityOperator.EQUALS, productPricePurposeId),
206                     EntityOperator.OR,
207                     new EntityExpr("productPricePurposeId", EntityOperator.EQUALS, null)));
208         } else {
209             productPriceEcList.add(new EntityExpr("productPricePurposeId", EntityOperator.EQUALS, productPricePurposeId));
210         }
211         productPriceEcList.add(new EntityExpr("currencyUomId", EntityOperator.EQUALS, currencyUomId));
212         productPriceEcList.add(new EntityExpr("productStoreGroupId", EntityOperator.EQUALS, productStoreGroupId));
213         if (UtilValidate.isNotEmpty(termUomId)) {
214             productPriceEcList.add(new EntityExpr("termUomId", EntityOperator.EQUALS, termUomId));
215         }
216         EntityCondition productPriceEc = new EntityConditionList(productPriceEcList, EntityOperator.AND);
217
218         // for prices, get all ProductPrice entities for this productId and currencyUomId
219
List JavaDoc productPrices = null;
220         try {
221             productPrices = delegator.findByConditionCache("ProductPrice", productPriceEc, null, UtilMisc.toList("-fromDate"));
222         } catch (GenericEntityException e) {
223             Debug.logError(e, "An error occurred while getting the product prices", module);
224         }
225         productPrices = EntityUtil.filterByDate(productPrices, true);
226
227         // ===== get the prices we need: list, default, average cost, promo, min, max =====
228
List JavaDoc listPrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "LIST_PRICE"));
229         GenericValue listPriceValue = EntityUtil.getFirst(listPrices);
230         if (listPrices != null && listPrices.size() > 1) {
231             if (Debug.infoOn()) Debug.logInfo("There is more than one LIST_PRICE with the currencyUomId " + currencyUomId + " and productId " + productId + ", using the latest found with price: " + listPriceValue.getDouble("price"), module);
232         }
233
234         List JavaDoc defaultPrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "DEFAULT_PRICE"));
235         GenericValue defaultPriceValue = EntityUtil.getFirst(defaultPrices);
236         if (defaultPrices != null && defaultPrices.size() > 1) {
237             if (Debug.infoOn()) Debug.logInfo("There is more than one DEFAULT_PRICE with the currencyUomId " + currencyUomId + " and productId " + productId + ", using the latest found with price: " + defaultPriceValue.getDouble("price"), module);
238         }
239
240         List JavaDoc competitivePrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "COMPETITIVE_PRICE"));
241         GenericValue competitivePriceValue = EntityUtil.getFirst(competitivePrices);
242         if (competitivePrices != null && competitivePrices.size() > 1) {
243             if (Debug.infoOn()) Debug.logInfo("There is more than one COMPETITIVE_PRICE with the currencyUomId " + currencyUomId + " and productId " + productId + ", using the latest found with price: " + competitivePriceValue.getDouble("price"), module);
244         }
245
246         List JavaDoc averageCosts = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "AVERAGE_COST"));
247         GenericValue averageCostValue = EntityUtil.getFirst(averageCosts);
248         if (averageCosts != null && averageCosts.size() > 1) {
249             if (Debug.infoOn()) Debug.logInfo("There is more than one AVERAGE_COST with the currencyUomId " + currencyUomId + " and productId " + productId + ", using the latest found with price: " + averageCostValue.getDouble("price"), module);
250         }
251
252         List JavaDoc promoPrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "PROMO_PRICE"));
253         GenericValue promoPriceValue = EntityUtil.getFirst(promoPrices);
254         if (promoPrices != null && promoPrices.size() > 1) {
255             if (Debug.infoOn()) Debug.logInfo("There is more than one PROMO_PRICE with the currencyUomId " + currencyUomId + " and productId " + productId + ", using the latest found with price: " + promoPriceValue.getDouble("price"), module);
256         }
257
258         List JavaDoc minimumPrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "MINIMUM_PRICE"));
259         GenericValue minimumPriceValue = EntityUtil.getFirst(minimumPrices);
260         if (minimumPrices != null && minimumPrices.size() > 1) {
261             if (Debug.infoOn()) Debug.logInfo("There is more than one MINIMUM_PRICE with the currencyUomId " + currencyUomId + " and productId " + productId + ", using the latest found with price: " + minimumPriceValue.getDouble("price"), module);
262         }
263
264         List JavaDoc maximumPrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "MAXIMUM_PRICE"));
265         GenericValue maximumPriceValue = EntityUtil.getFirst(maximumPrices);
266         if (maximumPrices != null && maximumPrices.size() > 1) {
267             if (Debug.infoOn()) Debug.logInfo("There is more than one MAXIMUM_PRICE with the currencyUomId " + currencyUomId + " and productId " + productId + ", using the latest found with price: " + maximumPriceValue.getDouble("price"), module);
268         }
269
270         List JavaDoc wholesalePrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "WHOLESALE_PRICE"));
271         GenericValue wholesalePriceValue = EntityUtil.getFirst(wholesalePrices);
272         if (wholesalePrices != null && wholesalePrices.size() > 1) {
273             if (Debug.infoOn()) Debug.logInfo("There is more than one WHOLESALE_PRICE with the currencyUomId " + currencyUomId + " and productId " + productId + ", using the latest found with price: " + wholesalePriceValue.getDouble("price"), module);
274         }
275
276         List JavaDoc specialPromoPrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "SPECIAL_PROMO_PRICE"));
277         GenericValue specialPromoPriceValue = EntityUtil.getFirst(specialPromoPrices);
278         if (specialPromoPrices != null && specialPromoPrices.size() > 1) {
279             if (Debug.infoOn()) Debug.logInfo("There is more than one SPECIAL_PROMO_PRICE with the currencyUomId " + currencyUomId + " and productId " + productId + ", using the latest found with price: " + specialPromoPriceValue.getDouble("price"), module);
280         }
281
282         // if any of these prices is missing and this product is a variant, default to the corresponding price on the virtual product
283
if (virtualProductPrices != null && virtualProductPrices.size() > 0) {
284             if (listPriceValue == null) {
285                 List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "LIST_PRICE"));
286                 listPriceValue = EntityUtil.getFirst(virtualTempPrices);
287                 if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
288                     if (Debug.infoOn()) Debug.logInfo("There is more than one LIST_PRICE with the currencyUomId " + currencyUomId + " and productId " + virtualProductId + ", using the latest found with price: " + listPriceValue.getDouble("price"), module);
289                 }
290             }
291             if (defaultPriceValue == null) {
292                 List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "DEFAULT_PRICE"));
293                 defaultPriceValue = EntityUtil.getFirst(virtualTempPrices);
294                 if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
295                     if (Debug.infoOn()) Debug.logInfo("There is more than one DEFAULT_PRICE with the currencyUomId " + currencyUomId + " and productId " + virtualProductId + ", using the latest found with price: " + defaultPriceValue.getDouble("price"), module);
296                 }
297             }
298             if (averageCostValue == null) {
299                 List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "AVERAGE_COST"));
300                 averageCostValue = EntityUtil.getFirst(virtualTempPrices);
301                 if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
302                     if (Debug.infoOn()) Debug.logInfo("There is more than one AVERAGE_COST with the currencyUomId " + currencyUomId + " and productId " + virtualProductId + ", using the latest found with price: " + averageCostValue.getDouble("price"), module);
303                 }
304             }
305             if (promoPriceValue == null) {
306                 List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "PROMO_PRICE"));
307                 promoPriceValue = EntityUtil.getFirst(virtualTempPrices);
308                 if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
309                     if (Debug.infoOn()) Debug.logInfo("There is more than one PROMO_PRICE with the currencyUomId " + currencyUomId + " and productId " + virtualProductId + ", using the latest found with price: " + promoPriceValue.getDouble("price"), module);
310                 }
311             }
312             if (minimumPriceValue == null) {
313                 List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "MINIMUM_PRICE"));
314                 minimumPriceValue = EntityUtil.getFirst(virtualTempPrices);
315                 if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
316                     if (Debug.infoOn()) Debug.logInfo("There is more than one MINIMUM_PRICE with the currencyUomId " + currencyUomId + " and productId " + virtualProductId + ", using the latest found with price: " + minimumPriceValue.getDouble("price"), module);
317                 }
318             }
319             if (maximumPriceValue == null) {
320                 List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "MAXIMUM_PRICE"));
321                 maximumPriceValue = EntityUtil.getFirst(virtualTempPrices);
322                 if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
323                     if (Debug.infoOn()) Debug.logInfo("There is more than one MAXIMUM_PRICE with the currencyUomId " + currencyUomId + " and productId " + virtualProductId + ", using the latest found with price: " + maximumPriceValue.getDouble("price"), module);
324                 }
325             }
326             if (wholesalePriceValue == null) {
327                 List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "WHOLESALE_PRICE"));
328                 wholesalePriceValue = EntityUtil.getFirst(virtualTempPrices);
329                 if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
330                     if (Debug.infoOn()) Debug.logInfo("There is more than one WHOLESALE_PRICE with the currencyUomId " + currencyUomId + " and productId " + virtualProductId + ", using the latest found with price: " + wholesalePriceValue.getDouble("price"), module);
331                 }
332             }
333             if (specialPromoPriceValue == null) {
334                 List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "SPECIAL_PROMO_PRICE"));
335                 specialPromoPriceValue = EntityUtil.getFirst(virtualTempPrices);
336                 if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
337                     if (Debug.infoOn()) Debug.logInfo("There is more than one SPECIAL_PROMO_PRICE with the currencyUomId " + currencyUomId + " and productId " + virtualProductId + ", using the latest found with price: " + specialPromoPriceValue.getDouble("price"), module);
338                 }
339             }
340         }
341
342         // now if this is a virtual product check each price type, if doesn't exist get from variant with lowest DEFAULT_PRICE
343
if ("Y".equals(product.getString("isVirtual"))) {
344             // only do this if there is no default price, consider the others optional for performance reasons
345
if (defaultPriceValue == null) {
346                 // Debug.logInfo("Product isVirtual and there is no default price for ID " + productId + ", trying variant prices", module);
347

348                 //use the cache to find the variant with the lowest default price
349
try {
350                     List JavaDoc variantAssocList = EntityUtil.filterByDate(delegator.findByAndCache("ProductAssoc", UtilMisc.toMap("productId", product.get("productId"), "productAssocTypeId", "PRODUCT_VARIANT"), UtilMisc.toList("-fromDate")));
351                     Iterator JavaDoc variantAssocIter = variantAssocList.iterator();
352                     double minDefaultPrice = Double.MAX_VALUE;
353                     List JavaDoc variantProductPrices = null;
354                     String JavaDoc variantProductId = null;
355                     while (variantAssocIter.hasNext()) {
356                         GenericValue variantAssoc = (GenericValue) variantAssocIter.next();
357                         String JavaDoc curVariantProductId = variantAssoc.getString("productIdTo");
358                         List JavaDoc curVariantPriceList = EntityUtil.filterByDate(delegator.findByAndCache("ProductPrice", UtilMisc.toMap("productId", curVariantProductId), UtilMisc.toList("-fromDate")), nowTimestamp);
359                         List JavaDoc tempDefaultPriceList = EntityUtil.filterByAnd(curVariantPriceList, UtilMisc.toMap("productPriceTypeId", "DEFAULT_PRICE"));
360                         GenericValue curDefaultPriceValue = EntityUtil.getFirst(tempDefaultPriceList);
361                         if (curDefaultPriceValue != null) {
362                             Double JavaDoc curDefaultPrice = curDefaultPriceValue.getDouble("price");
363                             if (curDefaultPrice.doubleValue() < minDefaultPrice) {
364                                 // check to see if the product is discontinued for sale before considering it the lowest price
365
GenericValue curVariantProduct = delegator.findByPrimaryKeyCache("Product", UtilMisc.toMap("productId", curVariantProductId));
366                                 if (curVariantProduct != null) {
367                                     Timestamp JavaDoc salesDiscontinuationDate = curVariantProduct.getTimestamp("salesDiscontinuationDate");
368                                     if (salesDiscontinuationDate == null || salesDiscontinuationDate.after(nowTimestamp)) {
369                                         minDefaultPrice = curDefaultPrice.doubleValue();
370                                         variantProductPrices = curVariantPriceList;
371                                         variantProductId = curVariantProductId;
372                                         // Debug.logInfo("Found new lowest price " + minDefaultPrice + " for variant with ID " + variantProductId, module);
373
}
374                                 }
375                             }
376                         }
377                     }
378
379                     if (variantProductPrices != null) {
380                         // we have some other options, give 'em a go...
381
if (listPriceValue == null) {
382                             List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "LIST_PRICE"));
383                             listPriceValue = EntityUtil.getFirst(virtualTempPrices);
384                             if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
385                                 if (Debug.infoOn()) Debug.logInfo("There is more than one LIST_PRICE with the currencyUomId " + currencyUomId + " and productId " + variantProductId + ", using the latest found with price: " + listPriceValue.getDouble("price"), module);
386                             }
387                         }
388                         if (defaultPriceValue == null) {
389                             List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "DEFAULT_PRICE"));
390                             defaultPriceValue = EntityUtil.getFirst(virtualTempPrices);
391                             if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
392                                 if (Debug.infoOn()) Debug.logInfo("There is more than one DEFAULT_PRICE with the currencyUomId " + currencyUomId + " and productId " + variantProductId + ", using the latest found with price: " + defaultPriceValue.getDouble("price"), module);
393                             }
394                         }
395                         if (competitivePriceValue == null) {
396                             List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "COMPETITIVE_PRICE"));
397                             competitivePriceValue = EntityUtil.getFirst(virtualTempPrices);
398                             if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
399                                 if (Debug.infoOn()) Debug.logInfo("There is more than one COMPETITIVE_PRICE with the currencyUomId " + currencyUomId + " and productId " + variantProductId + ", using the latest found with price: " + competitivePriceValue.getDouble("price"), module);
400                             }
401                         }
402                         if (averageCostValue == null) {
403                             List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "AVERAGE_COST"));
404                             averageCostValue = EntityUtil.getFirst(virtualTempPrices);
405                             if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
406                                 if (Debug.infoOn()) Debug.logInfo("There is more than one AVERAGE_COST with the currencyUomId " + currencyUomId + " and productId " + variantProductId + ", using the latest found with price: " + averageCostValue.getDouble("price"), module);
407                             }
408                         }
409                         if (promoPriceValue == null) {
410                             List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "PROMO_PRICE"));
411                             promoPriceValue = EntityUtil.getFirst(virtualTempPrices);
412                             if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
413                                 if (Debug.infoOn()) Debug.logInfo("There is more than one PROMO_PRICE with the currencyUomId " + currencyUomId + " and productId " + variantProductId + ", using the latest found with price: " + promoPriceValue.getDouble("price"), module);
414                             }
415                         }
416                         if (minimumPriceValue == null) {
417                             List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "MINIMUM_PRICE"));
418                             minimumPriceValue = EntityUtil.getFirst(virtualTempPrices);
419                             if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
420                                 if (Debug.infoOn()) Debug.logInfo("There is more than one MINIMUM_PRICE with the currencyUomId " + currencyUomId + " and productId " + variantProductId + ", using the latest found with price: " + minimumPriceValue.getDouble("price"), module);
421                             }
422                         }
423                         if (maximumPriceValue == null) {
424                             List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "MAXIMUM_PRICE"));
425                             maximumPriceValue = EntityUtil.getFirst(virtualTempPrices);
426                             if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
427                                 if (Debug.infoOn()) Debug.logInfo("There is more than one MAXIMUM_PRICE with the currencyUomId " + currencyUomId + " and productId " + variantProductId + ", using the latest found with price: " + maximumPriceValue.getDouble("price"), module);
428                             }
429                         }
430                         if (wholesalePriceValue == null) {
431                             List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "WHOLESALE_PRICE"));
432                             wholesalePriceValue = EntityUtil.getFirst(virtualTempPrices);
433                             if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
434                                 if (Debug.infoOn()) Debug.logInfo("There is more than one WHOLESALE_PRICE with the currencyUomId " + currencyUomId + " and productId " + variantProductId + ", using the latest found with price: " + wholesalePriceValue.getDouble("price"), module);
435                             }
436                         }
437                         if (specialPromoPriceValue == null) {
438                             List JavaDoc virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "SPECIAL_PROMO_PRICE"));
439                             specialPromoPriceValue = EntityUtil.getFirst(virtualTempPrices);
440                             if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
441                                 if (Debug.infoOn()) Debug.logInfo("There is more than one SPECIAL_PROMO_PRICE with the currencyUomId " + currencyUomId + " and productId " + variantProductId + ", using the latest found with price: " + wholesalePriceValue.getDouble("price"), module);
442                             }
443                         }
444                     }
445                 } catch (GenericEntityException e) {
446                     Debug.logError(e, "An error occurred while getting the product prices", module);
447                 }
448             }
449         }
450
451         //boolean validPromoPriceFound = false;
452
double promoPrice = 0;
453         if (promoPriceValue != null && promoPriceValue.get("price") != null) {
454             promoPrice = promoPriceValue.getDouble("price").doubleValue();
455             //validPromoPriceFound = true;
456
}
457
458         //boolean validWholesalePriceFound = false;
459
double wholesalePrice = 0;
460         if (wholesalePriceValue != null && wholesalePriceValue.get("price") != null) {
461             wholesalePrice = wholesalePriceValue.getDouble("price").doubleValue();
462             //validWholesalePriceFound = true;
463
}
464
465         boolean validPriceFound = false;
466         double defaultPrice = 0;
467         if (defaultPriceValue != null && defaultPriceValue.get("price") != null) {
468             defaultPrice = defaultPriceValue.getDouble("price").doubleValue();
469             validPriceFound = true;
470         }
471
472         Double JavaDoc listPriceDbl = listPriceValue != null ? listPriceValue.getDouble("price") : null;
473
474         if (listPriceDbl == null) {
475             // no list price, use defaultPrice for the final price
476

477             // ========= ensure calculated price is not below minSalePrice or above maxSalePrice =========
478
Double JavaDoc maxSellPrice = maximumPriceValue != null ? maximumPriceValue.getDouble("price") : null;
479             if (maxSellPrice != null && defaultPrice > maxSellPrice.doubleValue()) {
480                 defaultPrice = maxSellPrice.doubleValue();
481             }
482             // min price second to override max price, safety net
483
Double JavaDoc minSellPrice = minimumPriceValue != null ? minimumPriceValue.getDouble("price") : null;
484             if (minSellPrice != null && defaultPrice < minSellPrice.doubleValue()) {
485                 defaultPrice = minSellPrice.doubleValue();
486                 // since we have found a minimum price that has overriden a the defaultPrice, even if no valid one was found, we will consider it as if one had been...
487
validPriceFound = true;
488             }
489
490             result.put("basePrice", new Double JavaDoc(defaultPrice));
491             result.put("price", new Double JavaDoc(defaultPrice));
492             result.put("defaultPrice", new Double JavaDoc(defaultPrice));
493             result.put("competitivePrice", competitivePriceValue != null ? competitivePriceValue.getDouble("price") : null);
494             result.put("averageCost", averageCostValue != null ? averageCostValue.getDouble("price") : null);
495             result.put("promoPrice", promoPriceValue != null ? promoPriceValue.getDouble("price") : null);
496             result.put("specialPromoPrice", specialPromoPriceValue != null ? specialPromoPriceValue.getDouble("price") : null);
497         } else {
498             try {
499                 // get some of the base values to calculate with
500
double listPrice = listPriceDbl.doubleValue();
501                 double averageCost = (averageCostValue != null && averageCostValue.get("price") != null) ? averageCostValue.getDouble("price").doubleValue() : listPrice;
502                 double margin = listPrice - averageCost;
503
504                 // calculate running sum based on listPrice and rules found
505
double price = listPrice;
506
507                 Collection JavaDoc productPriceRules = null;
508
509                 // At this point we have two options: optimize for large ruleset, or optimize for small ruleset
510
// NOTE: This only effects the way that the rules to be evaluated are selected.
511
// For large rule sets we can do a cached pre-filter to limit the rules that need to be evaled for a specific product.
512
// Genercally I don't think that rule sets will get that big though, so the default is optimize for smaller rule set.
513
if (optimizeForLargeRuleSet) {
514                     // ========= find all rules that must be run for each input type; this is kind of like a pre-filter to slim down the rules to run =========
515
// utilTimer.timerString("Before create rule id list", module);
516
TreeSet JavaDoc productPriceRuleIds = new TreeSet JavaDoc();
517
518                     // ------- These are all of the conditions that DON'T depend on the current inputs -------
519

520                     // by productCategoryId
521
// for we will always include any rules that go by category, shouldn't be too many to iterate through each time and will save on cache entries
522
// note that we always want to put the category, quantity, etc ones that find all rules with these conditions in separate cache lists so that they can be easily cleared
523
Collection JavaDoc productCategoryIdConds = delegator.findByAndCache("ProductPriceCond", UtilMisc.toMap("inputParamEnumId", "PRIP_PROD_CAT_ID"));
524                     if (productCategoryIdConds != null && productCategoryIdConds.size() > 0) {
525                         Iterator JavaDoc productCategoryIdCondsIter = productCategoryIdConds.iterator();
526                         while (productCategoryIdCondsIter.hasNext()) {
527                             GenericValue productCategoryIdCond = (GenericValue) productCategoryIdCondsIter.next();
528                             productPriceRuleIds.add(productCategoryIdCond.getString("productPriceRuleId"));
529                         }
530                     }
531
532                     // by quantity -- should we really do this one, ie is it necessary?
533
// we could say that all rules with quantity on them must have one of these other values
534
// but, no we'll do it the other way, any that have a quantity will always get compared
535
Collection JavaDoc quantityConds = delegator.findByAndCache("ProductPriceCond", UtilMisc.toMap("inputParamEnumId", "PRIP_QUANTITY"));
536                     if (quantityConds != null && quantityConds.size() > 0) {
537                         Iterator JavaDoc quantityCondsIter = quantityConds.iterator();
538                         while (quantityCondsIter.hasNext()) {
539                             GenericValue quantityCond = (GenericValue) quantityCondsIter.next();
540                             productPriceRuleIds.add(quantityCond.getString("productPriceRuleId"));
541                         }
542                     }
543
544                     // by roleTypeId
545
Collection JavaDoc roleTypeIdConds = delegator.findByAndCache("ProductPriceCond", UtilMisc.toMap("inputParamEnumId", "PRIP_ROLE_TYPE"));
546                     if (roleTypeIdConds != null && roleTypeIdConds.size() > 0) {
547                         Iterator JavaDoc roleTypeIdCondsIter = roleTypeIdConds.iterator();
548                         while (roleTypeIdCondsIter.hasNext()) {
549                             GenericValue roleTypeIdCond = (GenericValue) roleTypeIdCondsIter.next();
550                             productPriceRuleIds.add(roleTypeIdCond.getString("productPriceRuleId"));
551                         }
552                     }
553
554                     // TODO, not supported yet: by groupPartyId
555
// TODO, not supported yet: by partyClassificationGroupId
556
// later: (by partyClassificationTypeId)
557

558                     // by listPrice
559
Collection JavaDoc listPriceConds = delegator.findByAndCache("ProductPriceCond", UtilMisc.toMap("inputParamEnumId", "PRIP_LIST_PRICE"));
560                     if (listPriceConds != null && listPriceConds.size() > 0) {
561                         Iterator JavaDoc listPriceCondsIter = listPriceConds.iterator();
562                         while (listPriceCondsIter.hasNext()) {
563                             GenericValue listPriceCond = (GenericValue) listPriceCondsIter.next();
564                             productPriceRuleIds.add(listPriceCond.getString("productPriceRuleId"));
565                         }
566                     }
567
568                     // ------- These are all of them that DO depend on the current inputs -------
569

570                     // by productId
571
Collection JavaDoc productIdConds = delegator.findByAndCache("ProductPriceCond", UtilMisc.toMap("inputParamEnumId", "PRIP_PRODUCT_ID", "condValue", productId));
572                     if (productIdConds != null && productIdConds.size() > 0) {
573                         Iterator JavaDoc productIdCondsIter = productIdConds.iterator();
574                         while (productIdCondsIter.hasNext()) {
575                             GenericValue productIdCond = (GenericValue) productIdCondsIter.next();
576                             productPriceRuleIds.add(productIdCond.getString("productPriceRuleId"));
577                         }
578                     }
579
580                     // by virtualProductId, if not null
581
if (virtualProductId != null) {
582                         Collection JavaDoc virtualProductIdConds = delegator.findByAndCache("ProductPriceCond", UtilMisc.toMap("inputParamEnumId", "PRIP_PRODUCT_ID", "condValue", virtualProductId));
583                         if (virtualProductIdConds != null && virtualProductIdConds.size() > 0) {
584                             Iterator JavaDoc virtualProductIdCondsIter = virtualProductIdConds.iterator();
585                             while (virtualProductIdCondsIter.hasNext()) {
586                                 GenericValue virtualProductIdCond = (GenericValue) virtualProductIdCondsIter.next();
587                                 productPriceRuleIds.add(virtualProductIdCond.getString("productPriceRuleId"));
588                             }
589                         }
590                     }
591
592                     // by prodCatalogId - which is optional in certain cases
593
if (UtilValidate.isNotEmpty(prodCatalogId)) {
594                         Collection JavaDoc prodCatalogIdConds = delegator.findByAndCache("ProductPriceCond", UtilMisc.toMap("inputParamEnumId", "PRIP_PROD_CLG_ID", "condValue", prodCatalogId));
595                         if (prodCatalogIdConds != null && prodCatalogIdConds.size() > 0) {
596                             Iterator JavaDoc prodCatalogIdCondsIter = prodCatalogIdConds.iterator();
597                             while (prodCatalogIdCondsIter.hasNext()) {
598                                 GenericValue prodCatalogIdCond = (GenericValue) prodCatalogIdCondsIter.next();
599                                 productPriceRuleIds.add(prodCatalogIdCond.getString("productPriceRuleId"));
600                             }
601                         }
602                     }
603
604                     // by productStoreGroupId
605
if (UtilValidate.isNotEmpty(productStoreGroupId)) {
606                         Collection JavaDoc storeGroupConds = delegator.findByAndCache("ProductPriceCond", UtilMisc.toMap("inputParamEnumId", "PRIP_PROD_SGRP_ID", "condValue", productStoreGroupId));
607                         if (storeGroupConds != null && storeGroupConds.size() > 0) {
608                             Iterator JavaDoc storeGroupCondsIter = storeGroupConds.iterator();
609                             while (storeGroupCondsIter.hasNext()) {
610                                 GenericValue storeGroupCond = (GenericValue) storeGroupCondsIter.next();
611                                 productPriceRuleIds.add(storeGroupCond.getString("productPriceRuleId"));
612                             }
613                         }
614                     }
615
616                     // by webSiteId
617
if (UtilValidate.isNotEmpty(webSiteId)) {
618                         Collection JavaDoc webSiteIdConds = delegator.findByAndCache("ProductPriceCond", UtilMisc.toMap("inputParamEnumId", "PRIP_WEBSITE_ID", "condValue", webSiteId));
619                         if (webSiteIdConds != null && webSiteIdConds.size() > 0) {
620                             Iterator JavaDoc webSiteIdCondsIter = webSiteIdConds.iterator();
621                             while (webSiteIdCondsIter.hasNext()) {
622                                 GenericValue webSiteIdCond = (GenericValue) webSiteIdCondsIter.next();
623                                 productPriceRuleIds.add(webSiteIdCond.getString("productPriceRuleId"));
624                             }
625                         }
626                     }
627
628                     // by partyId
629
if (UtilValidate.isNotEmpty(partyId)) {
630                         Collection JavaDoc partyIdConds = delegator.findByAndCache("ProductPriceCond", UtilMisc.toMap("inputParamEnumId", "PRIP_PARTY_ID", "condValue", partyId));
631                         if (partyIdConds != null && partyIdConds.size() > 0) {
632                             Iterator JavaDoc partyIdCondsIter = partyIdConds.iterator();
633                             while (partyIdCondsIter.hasNext()) {
634                                 GenericValue partyIdCond = (GenericValue) partyIdCondsIter.next();
635                                 productPriceRuleIds.add(partyIdCond.getString("productPriceRuleId"));
636                             }
637                         }
638                     }
639
640                     // by currencyUomId
641
Collection JavaDoc currencyUomIdConds = delegator.findByAndCache("ProductPriceCond", UtilMisc.toMap("inputParamEnumId", "PRIP_CURRENCY_UOMID", "condValue", currencyUomId));
642                     if (currencyUomIdConds != null && currencyUomIdConds.size() > 0) {
643                         Iterator JavaDoc currencyUomIdCondsIter = currencyUomIdConds.iterator();
644                         while (currencyUomIdCondsIter.hasNext()) {
645                             GenericValue currencyUomIdCond = (GenericValue) currencyUomIdCondsIter.next();
646                             productPriceRuleIds.add(currencyUomIdCond.getString("productPriceRuleId"));
647                         }
648                     }
649
650                     productPriceRules = new LinkedList JavaDoc();
651                     Iterator JavaDoc productPriceRuleIdsIter = productPriceRuleIds.iterator();
652                     while (productPriceRuleIdsIter.hasNext()) {
653                         String JavaDoc productPriceRuleId = (String JavaDoc) productPriceRuleIdsIter.next();
654                         GenericValue productPriceRule = delegator.findByPrimaryKeyCache("ProductPriceRule", UtilMisc.toMap("productPriceRuleId", productPriceRuleId));
655                         if (productPriceRule == null) continue;
656                         productPriceRules.add(productPriceRule);
657                     }
658                 } else {
659                     // this would be nice, but we can't cache this so easily...
660
// List pprExprs = UtilMisc.toList(new EntityExpr("thruDate", EntityOperator.EQUALS, null),
661
// new EntityExpr("thruDate", EntityOperator.GREATER_THAN, UtilDateTime.nowTimestamp()));
662
// productPriceRules = delegator.findByOr("ProductPriceRule", pprExprs);
663

664                     productPriceRules = delegator.findAllCache("ProductPriceRule");
665                     if (productPriceRules == null) productPriceRules = new LinkedList JavaDoc();
666                 }
667
668                 // ========= go through each price rule by id and eval all conditions =========
669
// utilTimer.timerString("Before eval rules", module);
670
int totalConds = 0;
671                 int totalActions = 0;
672                 int totalRules = 0;
673
674                 Iterator JavaDoc productPriceRulesIter = productPriceRules.iterator();
675                 while (productPriceRulesIter.hasNext()) {
676                     GenericValue productPriceRule = (GenericValue) productPriceRulesIter.next();
677                     String JavaDoc productPriceRuleId = productPriceRule.getString("productPriceRuleId");
678
679                     // check from/thru dates
680
java.sql.Timestamp JavaDoc fromDate = productPriceRule.getTimestamp("fromDate");
681                     java.sql.Timestamp JavaDoc thruDate = productPriceRule.getTimestamp("thruDate");
682
683                     if (fromDate != null && fromDate.after(nowTimestamp)) {
684                         // hasn't started yet
685
continue;
686                     }
687                     if (thruDate != null && thruDate.before(nowTimestamp)) {
688                         // already expired
689
continue;
690                     }
691
692                     // check all conditions
693
boolean allTrue = true;
694                     StringBuffer JavaDoc condsDescription = new StringBuffer JavaDoc();
695                     Collection JavaDoc productPriceConds = delegator.findByAndCache("ProductPriceCond", UtilMisc.toMap("productPriceRuleId", productPriceRuleId));
696                     Iterator JavaDoc productPriceCondsIter = UtilMisc.toIterator(productPriceConds);
697
698                     while (productPriceCondsIter != null && productPriceCondsIter.hasNext()) {
699                         GenericValue productPriceCond = (GenericValue) productPriceCondsIter.next();
700
701                         totalConds++;
702
703                         if (!checkPriceCondition(productPriceCond, productId, prodCatalogId, productStoreGroupId, webSiteId, partyId, quantity, listPrice, currencyUomId, delegator)) {
704                             // if there is a virtualProductId, try that given that this one has failed
705
if (virtualProductId != null) {
706                                 if (!checkPriceCondition(productPriceCond, virtualProductId, prodCatalogId, productStoreGroupId, webSiteId, partyId, quantity, listPrice, currencyUomId, delegator)) {
707                                     allTrue = false;
708                                     break;
709                                 }
710                                 // otherwise, okay, this one made it so carry on checking
711
} else {
712                                 allTrue = false;
713                                 break;
714                             }
715                         }
716
717                         // add condsDescription string entry
718
condsDescription.append("[");
719                         GenericValue inputParamEnum = productPriceCond.getRelatedOneCache("InputParamEnumeration");
720
721                         condsDescription.append(inputParamEnum.getString("enumCode"));
722                         // condsDescription.append(":");
723
GenericValue operatorEnum = productPriceCond.getRelatedOneCache("OperatorEnumeration");
724
725                         condsDescription.append(operatorEnum.getString("description"));
726                         // condsDescription.append(":");
727
condsDescription.append(productPriceCond.getString("condValue"));
728                         condsDescription.append("] ");
729                     }
730
731                     // add some info about the prices we are calculating from
732
condsDescription.append("[list:");
733                     condsDescription.append(listPrice);
734                     condsDescription.append(";avgCost:");
735                     condsDescription.append(averageCost);
736                     condsDescription.append(";margin:");
737                     condsDescription.append(margin);
738                     condsDescription.append("] ");
739
740                     boolean foundFlatOverride = false;
741
742                     // if all true, perform all actions
743
if (allTrue) {
744                         // check isSale
745
if ("Y".equals(productPriceRule.getString("isSale"))) {
746                             isSale = true;
747                         }
748
749                         Collection JavaDoc productPriceActions = delegator.findByAndCache("ProductPriceAction", UtilMisc.toMap("productPriceRuleId", productPriceRuleId));
750                         Iterator JavaDoc productPriceActionsIter = UtilMisc.toIterator(productPriceActions);
751
752                         while (productPriceActionsIter != null && productPriceActionsIter.hasNext()) {
753                             GenericValue productPriceAction = (GenericValue) productPriceActionsIter.next();
754
755                             totalActions++;
756
757                             // yeah, finally here, perform the action, ie, modify the price
758
double modifyAmount = 0;
759
760                             if ("PRICE_POD".equals(productPriceAction.getString("productPriceActionTypeId"))) {
761                                 if (productPriceAction.get("amount") != null) {
762                                     modifyAmount = defaultPrice * (productPriceAction.getDouble("amount").doubleValue() / 100.0);
763                                 }
764                             } else if ("PRICE_POL".equals(productPriceAction.getString("productPriceActionTypeId"))) {
765                                 if (productPriceAction.get("amount") != null) {
766                                     modifyAmount = listPrice * (productPriceAction.getDouble("amount").doubleValue() / 100.0);
767                                 }
768                             } else if ("PRICE_POAC".equals(productPriceAction.getString("productPriceActionTypeId"))) {
769                                 if (productPriceAction.get("amount") != null) {
770                                     modifyAmount = averageCost * (productPriceAction.getDouble("amount").doubleValue() / 100.0);
771                                 }
772                             } else if ("PRICE_POM".equals(productPriceAction.getString("productPriceActionTypeId"))) {
773                                 if (productPriceAction.get("amount") != null) {
774                                     modifyAmount = margin * (productPriceAction.getDouble("amount").doubleValue() / 100.0);
775                                 }
776                             } else if ("PRICE_FOL".equals(productPriceAction.getString("productPriceActionTypeId"))) {
777                                 if (productPriceAction.get("amount") != null) {
778                                     modifyAmount = productPriceAction.getDouble("amount").doubleValue();
779                                 }
780                             } else if ("PRICE_FLAT".equals(productPriceAction.getString("productPriceActionTypeId"))) {
781                                 // this one is a bit different, break out of the loop because we now have our final price
782
foundFlatOverride = true;
783                                 if (productPriceAction.get("amount") != null) {
784                                     price = productPriceAction.getDouble("amount").doubleValue();
785                                 } else {
786                                     Debug.logInfo("ProductPriceAction had null amount, using default price: " + defaultPrice + " for product with id " + productId, module);
787                                     price = defaultPrice;
788                                     isSale = false; // reverse isSale flag, as this sale rule was actually not applied
789
}
790                             } else if ("PRICE_PFLAT".equals(productPriceAction.getString("productPriceActionTypeId"))) {
791                                 // this one is a bit different too, break out of the loop because we now have our final price
792
foundFlatOverride = true;
793                                 price = promoPrice;
794                                 if (productPriceAction.get("amount") != null) {
795                                     price += productPriceAction.getDouble("amount").doubleValue();
796                                 }
797                                 if (price == 0.00) {
798                                     if (defaultPrice != 0.00) {
799                                         Debug.logInfo("PromoPrice and ProductPriceAction had null amount, using default price: " + defaultPrice + " for product with id " + productId, module);
800                                         price = defaultPrice;
801                                     } else if (listPrice != 0.00) {
802                                         Debug.logInfo("PromoPrice and ProductPriceAction had null amount and no default price was available, using list price: " + listPrice + " for product with id " + productId, module);
803                                         price = listPrice;
804                                     } else {
805                                         Debug.logError("PromoPrice and ProductPriceAction had null amount and no default or list price was available, so price is set to zero for product with id " + productId, module);
806                                         price = 0.00;
807                                     }
808                                     isSale = false; // reverse isSale flag, as this sale rule was actually not applied
809
}
810                             } else if ("PRICE_WFLAT".equals(productPriceAction.getString("productPriceActionTypeId"))) {
811                                 // same as promo price but using the wholesale price instead
812
foundFlatOverride = true;
813                                 price = wholesalePrice;
814                                 if (productPriceAction.get("amount") != null) {
815                                     price += productPriceAction.getDouble("amount").doubleValue();
816                                 }
817                                 if (price == 0.00) {
818                                     if (defaultPrice != 0.00) {
819                                         Debug.logInfo("WholesalePrice and ProductPriceAction had null amount, using default price: " + defaultPrice + " for product with id " + productId, module);
820                                         price = defaultPrice;
821                                     } else if (listPrice != 0.00) {
822                                         Debug.logInfo("WholesalePrice and ProductPriceAction had null amount and no default price was available, using list price: " + listPrice + " for product with id " + productId, module);
823                                         price = listPrice;
824                                     } else {
825                                         Debug.logError("WholesalePrice and ProductPriceAction had null amount and no default or list price was available, so price is set to zero for product with id " + productId, module);
826                                         price = 0.00;
827                                     }
828                                     isSale = false; // reverse isSale flag, as this sale rule was actually not applied
829
}
830                             }
831
832                             // add a orderItemPriceInfo element too, without orderId or orderItemId
833
StringBuffer JavaDoc priceInfoDescription = new StringBuffer JavaDoc();
834
835                             priceInfoDescription.append(condsDescription.toString());
836                             priceInfoDescription.append("[type:");
837                             priceInfoDescription.append(productPriceAction.getString("productPriceActionTypeId"));
838                             priceInfoDescription.append("]");
839
840                             GenericValue orderItemPriceInfo = delegator.makeValue("OrderItemPriceInfo", null);
841
842                             orderItemPriceInfo.set("productPriceRuleId", productPriceAction.get("productPriceRuleId"));
843                             orderItemPriceInfo.set("productPriceActionSeqId", productPriceAction.get("productPriceActionSeqId"));
844                             orderItemPriceInfo.set("modifyAmount", new Double JavaDoc(modifyAmount));
845                             // make sure description is <= than 250 chars
846
String JavaDoc priceInfoDescriptionString = priceInfoDescription.toString();
847
848                             if (priceInfoDescriptionString.length() > 250) {
849                                 priceInfoDescriptionString = priceInfoDescriptionString.substring(0, 250);
850                             }
851                             orderItemPriceInfo.set("description", priceInfoDescriptionString);
852                             orderItemPriceInfos.add(orderItemPriceInfo);
853
854                             if (foundFlatOverride) {
855                                 break;
856                             } else {
857                                 price += modifyAmount;
858                             }
859                         }
860                     }
861
862                     totalRules++;
863
864                     if (foundFlatOverride) {
865                         break;
866                     }
867                 }
868
869                 if (Debug.verboseOn()) {
870                     Debug.logVerbose("Unchecked Calculated price: " + price, module);
871                     Debug.logVerbose("PriceInfo:", module);
872                     Iterator JavaDoc orderItemPriceInfosIter = orderItemPriceInfos.iterator();
873                     while (orderItemPriceInfosIter.hasNext()) {
874                         GenericValue orderItemPriceInfo = (GenericValue) orderItemPriceInfosIter.next();
875
876                         Debug.logVerbose(" --- " + orderItemPriceInfo.toString(), module);
877                     }
878                 }
879
880                 // if no actions were run on the list price, then use the default price
881
if (totalActions == 0) {
882                     price = defaultPrice;
883                     // here we will leave validPriceFound as it was originally set for the defaultPrice since that is what we are setting the price to...
884
} else {
885                     // at least one price rule action was found, so we will consider it valid
886
validPriceFound = true;
887                 }
888
889                 // ========= ensure calculated price is not below minSalePrice or above maxSalePrice =========
890
Double JavaDoc maxSellPrice = maximumPriceValue != null ? maximumPriceValue.getDouble("price") : null;
891                 if (maxSellPrice != null && price > maxSellPrice.doubleValue()) {
892                     price = maxSellPrice.doubleValue();
893                 }
894                 // min price second to override max price, safety net
895
Double JavaDoc minSellPrice = minimumPriceValue != null ? minimumPriceValue.getDouble("price") : null;
896                 if (minSellPrice != null && price < minSellPrice.doubleValue()) {
897                     price = minSellPrice.doubleValue();
898                     // since we have found a minimum price that has overriden a the defaultPrice, even if no valid one was found, we will consider it as if one had been...
899
validPriceFound = true;
900                 }
901
902                 if (Debug.verboseOn()) Debug.logVerbose("Final Calculated price: " + price + ", rules: " + totalRules + ", conds: " + totalConds + ", actions: " + totalActions, module);
903
904                 result.put("basePrice", new Double JavaDoc(price));
905                 result.put("price", new Double JavaDoc(price));
906                 result.put("listPrice", new Double JavaDoc(listPrice));
907                 result.put("defaultPrice", new Double JavaDoc(defaultPrice));
908                 result.put("averageCost", new Double JavaDoc(averageCost));
909             } catch (GenericEntityException e) {
910                 Debug.logError(e, "Error getting rules from the database while calculating price", module);
911                 return ServiceUtil.returnError("Error getting rules from the database while calculating price: " + e.toString());
912             }
913         }
914
915         result.put("competitivePrice", competitivePriceValue != null ? competitivePriceValue.getDouble("price") : null);
916         result.put("specialPromoPrice", specialPromoPriceValue != null ? specialPromoPriceValue.getDouble("price") : null);
917         result.put("orderItemPriceInfos", orderItemPriceInfos);
918         result.put("isSale", new Boolean JavaDoc(isSale));
919         result.put("validPriceFound", new Boolean JavaDoc(validPriceFound));
920         result.put("currencyUsed", currencyUomId);
921
922         // okay, now we have the calculated price, see if we should add in tax and if so do it
923
if ("Y".equals(checkIncludeVat) && productStore != null && "Y".equals(productStore.getString("showPricesWithVatTax"))) {
924             Map JavaDoc calcTaxForDisplayContext = UtilMisc.toMap("productStoreId", productStoreId,
925                     "productId", productId, "quantity", new BigDecimal JavaDoc(quantity),
926                     "basePrice", new BigDecimal JavaDoc(((Double JavaDoc) result.get("price")).doubleValue()));
927             if (UtilValidate.isNotEmpty(partyId)) {
928                 calcTaxForDisplayContext.put("billToPartyId", partyId);
929             }
930             
931             try {
932                 Map JavaDoc calcTaxForDisplayResult = dispatcher.runSync("calcTaxForDisplay", calcTaxForDisplayContext);
933                 if (ServiceUtil.isError(calcTaxForDisplayResult)) {
934                     return ServiceUtil.returnError("Error calculating VAT tax (with calcTaxForDisplay service)", null, null, calcTaxForDisplayResult);
935                 }
936                 // taxTotal, taxPercentage, priceWithTax
937
result.put("price", new Double JavaDoc(((BigDecimal JavaDoc) calcTaxForDisplayResult.get("priceWithTax")).doubleValue()));
938
939                 // based on the taxPercentage calculate the other amounts, including: listPrice, defaultPrice, averageCost, promoPrice, competitivePrice
940
BigDecimal JavaDoc taxPercentage = (BigDecimal JavaDoc) calcTaxForDisplayResult.get("taxPercentage");
941                 BigDecimal JavaDoc taxMultiplier = ONE_BASE.add(taxPercentage.divide(PERCENT_SCALE, 3));
942                 if (result.get("listPrice") != null) result.put("listPrice", new Double JavaDoc((new BigDecimal JavaDoc (((Double JavaDoc) result.get("listPrice")).doubleValue())).multiply(taxMultiplier).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()));
943                 if (result.get("defaultPrice") != null) result.put("defaultPrice", new Double JavaDoc((new BigDecimal JavaDoc (((Double JavaDoc) result.get("defaultPrice")).doubleValue())).multiply(taxMultiplier).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()));
944                 if (result.get("averageCost") != null) result.put("averageCost", new Double JavaDoc((new BigDecimal JavaDoc (((Double JavaDoc) result.get("averageCost")).doubleValue())).multiply(taxMultiplier).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()));
945                 
946                 if (result.get("promoPrice") != null) result.put("promoPrice", new Double JavaDoc((new BigDecimal JavaDoc (((Double JavaDoc) result.get("promoPrice")).doubleValue())).multiply(taxMultiplier).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()));
947                 if (result.get("competitivePrice") != null) result.put("competitivePrice", new Double JavaDoc((new BigDecimal JavaDoc (((Double JavaDoc) result.get("competitivePrice")).doubleValue())).multiply(taxMultiplier).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()));
948                 
949             } catch (GenericServiceException e) {
950                 String JavaDoc errMsg = "Error calculating VAT tax (with calcTaxForDisplay service): " + e.toString();
951                 Debug.logError(e, errMsg, module);
952                 return ServiceUtil.returnError(errMsg);
953             }
954         }
955
956         // utilTimer.timerString("Finished price calc [productId=" + productId + "]", module);
957
return result;
958     }
959
960     public static boolean checkPriceCondition(GenericValue productPriceCond, String JavaDoc productId, String JavaDoc prodCatalogId,
961             String JavaDoc productStoreGroupId, String JavaDoc webSiteId, String JavaDoc partyId, double quantity, double listPrice,
962             String JavaDoc currencyUomId, GenericDelegator delegator) throws GenericEntityException {
963         if (Debug.verboseOn()) Debug.logVerbose("Checking price condition: " + productPriceCond, module);
964         int compare = 0;
965
966         if ("PRIP_PRODUCT_ID".equals(productPriceCond.getString("inputParamEnumId"))) {
967             compare = productId.compareTo(productPriceCond.getString("condValue"));
968         } else if ("PRIP_PROD_CAT_ID".equals(productPriceCond.getString("inputParamEnumId"))) {
969             // if a ProductCategoryMember exists for this productId and the specified productCategoryId
970
String JavaDoc productCategoryId = productPriceCond.getString("condValue");
971             List JavaDoc productCategoryMembers = delegator.findByAndCache("ProductCategoryMember",
972                     UtilMisc.toMap("productId", productId, "productCategoryId", productCategoryId));
973             // and from/thru date within range
974
productCategoryMembers = EntityUtil.filterByDate(productCategoryMembers, true);
975             // then 0 (equals), otherwise 1 (not equals)
976
if (productCategoryMembers != null && productCategoryMembers.size() > 0) {
977                 compare = 0;
978             } else {
979                 compare = 1;
980             }
981         } else if ("PRIP_PROD_CLG_ID".equals(productPriceCond.getString("inputParamEnumId"))) {
982             if (UtilValidate.isNotEmpty(prodCatalogId)) {
983                 compare = prodCatalogId.compareTo(productPriceCond.getString("condValue"));
984             } else {
985                 // this shouldn't happen because if prodCatalogId is null no PRIP_PROD_CLG_ID prices will be in the list
986
compare = 1;
987             }
988         } else if ("PRIP_PROD_SGRP_ID".equals(productPriceCond.getString("inputParamEnumId"))) {
989             if (UtilValidate.isNotEmpty(productStoreGroupId)) {
990                 compare = productStoreGroupId.compareTo(productPriceCond.getString("condValue"));
991             } else {
992                 compare = 1;
993             }
994         } else if ("PRIP_WEBSITE_ID".equals(productPriceCond.getString("inputParamEnumId"))) {
995             if (UtilValidate.isNotEmpty(webSiteId)) {
996                 compare = webSiteId.compareTo(productPriceCond.getString("condValue"));
997             } else {
998                 compare = 1;
999             }
1000        } else if ("PRIP_QUANTITY".equals(productPriceCond.getString("inputParamEnumId"))) {
1001            Double JavaDoc quantityValue = new Double JavaDoc(quantity);
1002            compare = quantityValue.compareTo(Double.valueOf(productPriceCond.getString("condValue")));
1003        } else if ("PRIP_PARTY_ID".equals(productPriceCond.getString("inputParamEnumId"))) {
1004            if (UtilValidate.isNotEmpty(partyId)) {
1005                compare = partyId.compareTo(productPriceCond.getString("condValue"));
1006            } else {
1007                compare = 1;
1008            }
1009        } else if ("PRIP_PARTY_GRP_MEM".equals(productPriceCond.getString("inputParamEnumId"))) {
1010            if (UtilValidate.isEmpty(partyId)) {
1011                compare = 1;
1012            } else {
1013                String JavaDoc groupPartyId = productPriceCond.getString("condValue");
1014                if (partyId.equals(groupPartyId)) {
1015                    compare = 0;
1016                } else {
1017                    // look for PartyRelationship with partyRelationshipTypeId=GROUP_ROLLUP, the partyIdTo is the group member, so the partyIdFrom is the groupPartyId
1018
List JavaDoc partyRelationshipList = delegator.findByAndCache("PartyRelationship", UtilMisc.toMap("partyIdFrom", groupPartyId, "partyIdTo", partyId, "partyRelationshipTypeId", "GROUP_ROLLUP"));
1019                    // and from/thru date within range
1020
partyRelationshipList = EntityUtil.filterByDate(partyRelationshipList, true);
1021                    // then 0 (equals), otherwise 1 (not equals)
1022
if (partyRelationshipList != null && partyRelationshipList.size() > 0) {
1023                        compare = 0;
1024                    } else {
1025                        compare = 1;
1026                    }
1027                }
1028            }
1029        } else if ("PRIP_PARTY_CLASS".equals(productPriceCond.getString("inputParamEnumId"))) {
1030            if (UtilValidate.isEmpty(partyId)) {
1031                compare = 1;
1032            } else {
1033                String JavaDoc partyClassificationGroupId = productPriceCond.getString("condValue");
1034                // find any PartyClassification
1035
List JavaDoc partyClassificationList = delegator.findByAndCache("PartyClassification", UtilMisc.toMap("partyId", partyId, "partyClassificationGroupId", partyClassificationGroupId));
1036                // and from/thru date within range
1037
partyClassificationList = EntityUtil.filterByDate(partyClassificationList, true);
1038                // then 0 (equals), otherwise 1 (not equals)
1039
if (partyClassificationList != null && partyClassificationList.size() > 0) {
1040                    compare = 0;
1041                } else {
1042                    compare = 1;
1043                }
1044            }
1045        } else if ("PRIP_ROLE_TYPE".equals(productPriceCond.getString("inputParamEnumId"))) {
1046            if (partyId != null) {
1047                // if a PartyRole exists for this partyId and the specified roleTypeId
1048
GenericValue partyRole = delegator.findByPrimaryKeyCache("PartyRole",
1049                        UtilMisc.toMap("partyId", partyId, "roleTypeId", productPriceCond.getString("condValue")));
1050
1051                // then 0 (equals), otherwise 1 (not equals)
1052
if (partyRole != null) {
1053                    compare = 0;
1054                } else {
1055                    compare = 1;
1056                }
1057            } else {
1058                compare = 1;
1059            }
1060        } else if ("PRIP_LIST_PRICE".equals(productPriceCond.getString("inputParamEnumId"))) {
1061            Double JavaDoc listPriceValue = new Double JavaDoc(listPrice);
1062
1063            compare = listPriceValue.compareTo(Double.valueOf(productPriceCond.getString("condValue")));
1064        } else if ("PRIP_CURRENCY_UOMID".equals(productPriceCond.getString("inputParamEnumId"))) {
1065            compare = currencyUomId.compareTo(productPriceCond.getString("condValue"));
1066        } else {
1067            Debug.logWarning("An un-supported productPriceCond input parameter (lhs) was used: " + productPriceCond.getString("inputParamEnumId") + ", returning false, ie check failed", module);
1068            return false;
1069        }
1070
1071        if (Debug.verboseOn()) Debug.logVerbose("Price Condition compare done, compare=" + compare, module);
1072
1073        if ("PRC_EQ".equals(productPriceCond.getString("operatorEnumId"))) {
1074            if (compare == 0) return true;
1075        } else if ("PRC_NEQ".equals(productPriceCond.getString("operatorEnumId"))) {
1076            if (compare != 0) return true;
1077        } else if ("PRC_LT".equals(productPriceCond.getString("operatorEnumId"))) {
1078            if (compare < 0) return true;
1079        } else if ("PRC_LTE".equals(productPriceCond.getString("operatorEnumId"))) {
1080            if (compare <= 0) return true;
1081        } else if ("PRC_GT".equals(productPriceCond.getString("operatorEnumId"))) {
1082            if (compare > 0) return true;
1083        } else if ("PRC_GTE".equals(productPriceCond.getString("operatorEnumId"))) {
1084            if (compare >= 0) return true;
1085        } else {
1086            Debug.logWarning("An un-supported productPriceCond condition was used: " + productPriceCond.getString("operatorEnumId") + ", returning false, ie check failed", module);
1087            return false;
1088        }
1089        return false;
1090    }
1091
1092    /**
1093     * Calculates the purchase price of a product
1094     */

1095    public static Map JavaDoc calculatePurchasePrice(DispatchContext dctx, Map JavaDoc context) {
1096
1097        GenericDelegator delegator = dctx.getDelegator();
1098        LocalDispatcher dispatcher = dctx.getDispatcher();
1099        Map JavaDoc result = new HashMap JavaDoc();
1100        Timestamp JavaDoc nowTimestamp = UtilDateTime.nowTimestamp();
1101
1102        List JavaDoc orderItemPriceInfos = new LinkedList JavaDoc();
1103        boolean validPriceFound = false;
1104        double price = 0.0;
1105
1106        GenericValue product = (GenericValue)context.get("product");
1107        String JavaDoc productId = product.getString("productId");
1108        String JavaDoc currencyUomId = (String JavaDoc)context.get("currencyUomId");
1109        String JavaDoc partyId = (String JavaDoc)context.get("partyId");
1110        Double JavaDoc quantity = (Double JavaDoc)context.get("quantity");
1111        
1112        // a) Get the Price from the Agreement* data model
1113
// TODO: Implement this
1114

1115        // b) If no price can be found, get the lastPrice from the SupplierProduct entity
1116
if (!validPriceFound) {
1117            Map JavaDoc priceContext = UtilMisc.toMap("currencyUomId", currencyUomId, "partyId", partyId, "productId", productId, "quantity", quantity);
1118            List JavaDoc productSuppliers = null;
1119            try {
1120                Map JavaDoc priceResult = dispatcher.runSync("getSuppliersForProduct", priceContext);
1121                if (ServiceUtil.isError(priceResult)) {
1122                    String JavaDoc errMsg = ServiceUtil.getErrorMessage(priceResult);
1123                    Debug.logError(errMsg, module);
1124                    return ServiceUtil.returnError(errMsg);
1125                }
1126                productSuppliers = (List JavaDoc) priceResult.get("supplierProducts");
1127            } catch(GenericServiceException gse) {
1128                Debug.logError(gse, module);
1129                return ServiceUtil.returnError(gse.getMessage());
1130            }
1131            if (productSuppliers != null) {
1132                for (int i = 0; i < productSuppliers.size(); i++) {
1133                    GenericValue productSupplier = (GenericValue) productSuppliers.get(i);
1134                    if (!validPriceFound) {
1135                        price = ((Double JavaDoc)productSupplier.get("lastPrice")).doubleValue();
1136                        validPriceFound = true;
1137                    }
1138                    // add a orderItemPriceInfo element too, without orderId or orderItemId
1139
StringBuffer JavaDoc priceInfoDescription = new StringBuffer JavaDoc();
1140                    priceInfoDescription.append("SupplierProduct ");
1141                    priceInfoDescription.append("[minimumOrderQuantity:");
1142                    priceInfoDescription.append("" + productSupplier.getDouble("minimumOrderQuantity").doubleValue());
1143                    priceInfoDescription.append(", lastPrice: " + productSupplier.getDouble("lastPrice").doubleValue());
1144                    priceInfoDescription.append("]");
1145                    GenericValue orderItemPriceInfo = delegator.makeValue("OrderItemPriceInfo", null);
1146                    //orderItemPriceInfo.set("productPriceRuleId", productPriceAction.get("productPriceRuleId"));
1147
//orderItemPriceInfo.set("productPriceActionSeqId", productPriceAction.get("productPriceActionSeqId"));
1148
//orderItemPriceInfo.set("modifyAmount", new Double(modifyAmount));
1149
// make sure description is <= than 250 chars
1150
String JavaDoc priceInfoDescriptionString = priceInfoDescription.toString();
1151                    if (priceInfoDescriptionString.length() > 250) {
1152                        priceInfoDescriptionString = priceInfoDescriptionString.substring(0, 250);
1153                    }
1154                    orderItemPriceInfo.set("description", priceInfoDescriptionString);
1155                    orderItemPriceInfos.add(orderItemPriceInfo);
1156                }
1157            }
1158        }
1159
1160        // c) If no price can be found, get the averageCost from the ProductPrice entity
1161
if (!validPriceFound) {
1162            List JavaDoc prices = null;
1163            try {
1164                prices = delegator.findByAnd("ProductPrice", UtilMisc.toMap("productId", productId,
1165                        "productPricePurposeId", "PURCHASE"), UtilMisc.toList("-fromDate"));
1166
1167                // if no prices are found; find the prices of the parent product
1168
if (prices == null || prices.size() == 0) {
1169                    GenericValue parentProduct = ProductWorker.getParentProduct(productId, delegator);
1170                    if (parentProduct != null) {
1171                        String JavaDoc parentProductId = parentProduct.getString("productId");
1172                        prices = delegator.findByAnd("ProductPrice", UtilMisc.toMap("productId", parentProductId,
1173                                "productPricePurposeId", "PURCHASE"), UtilMisc.toList("-fromDate"));
1174                    }
1175                }
1176            } catch (GenericEntityException e) {
1177                Debug.logError(e, module);
1178                return ServiceUtil.returnError(e.getMessage());
1179            }
1180
1181            // filter out the old prices
1182
prices = EntityUtil.filterByDate(prices);
1183
1184            // first check for the AVERAGE_COST price type
1185
List JavaDoc pricesToUse = EntityUtil.filterByAnd(prices, UtilMisc.toMap("productPriceTypeId", "AVERAGE_COST"));
1186            if (pricesToUse == null || pricesToUse.size() == 0) {
1187                // next go with default price
1188
pricesToUse = EntityUtil.filterByAnd(prices, UtilMisc.toMap("productPriceTypeId", "DEFAULT_PRICE"));
1189                if (pricesToUse == null || pricesToUse.size() == 0) {
1190                    // finally use list price
1191
pricesToUse = EntityUtil.filterByAnd(prices, UtilMisc.toMap("productPriceTypeId", "LIST_PRICE"));
1192                }
1193            }
1194
1195            // use the most current price
1196
GenericValue thisPrice = EntityUtil.getFirst(pricesToUse);
1197            if (thisPrice != null) {
1198                price = thisPrice.getDouble("price").doubleValue();
1199                validPriceFound = true;
1200            }
1201        }
1202
1203        result.put("price", new Double JavaDoc(price));
1204        result.put("validPriceFound", new Boolean JavaDoc(validPriceFound));
1205        result.put("orderItemPriceInfos", orderItemPriceInfos);
1206        return result;
1207    }
1208}
1209
Popular Tags