public static Map<String, Object> calculateProductPrice(DispatchContext dctx, Map<String, ? extends Object> context) {
// UtilTimer utilTimer = new UtilTimer();
// utilTimer.timerString("Starting price calc", module);
// utilTimer.setLog(false);
Delegator delegator = dctx.getDelegator();
LocalDispatcher dispatcher = dctx.getDispatcher();
Map<String, Object> result = FastMap.newInstance();
Timestamp nowTimestamp = UtilDateTime.nowTimestamp();
GenericValue product = (GenericValue) context.get("product");
String productId = product.getString("productId");
String prodCatalogId = (String) context.get("prodCatalogId");
String webSiteId = (String) context.get("webSiteId");
String checkIncludeVat = (String) context.get("checkIncludeVat");
String surveyResponseId = (String) context.get("surveyResponseId");
Map<String, Object> customAttributes = UtilGenerics.checkMap(context.get("customAttributes"));
String findAllQuantityPricesStr = (String) context.get("findAllQuantityPrices");
boolean findAllQuantityPrices = "Y".equals(findAllQuantityPricesStr);
boolean optimizeForLargeRuleSet = "Y".equals(context.get("optimizeForLargeRuleSet"));
String agreementId = (String) context.get("agreementId");
String productStoreId = (String) context.get("productStoreId");
String productStoreGroupId = (String) context.get("productStoreGroupId");
Locale locale = (Locale) context.get("locale");
GenericValue productStore = null;
try {
// we have a productStoreId, if the corresponding ProductStore.primaryStoreGroupId is not empty, use that
productStore = delegator.findByPrimaryKeyCache("ProductStore", UtilMisc.toMap("productStoreId", productStoreId));
} catch (GenericEntityException e) {
Debug.logError(e, "Error getting product store info from the database while calculating price" + e.toString(), module);
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"ProductPriceCannotRetrieveProductStore", UtilMisc.toMap("errorString", e.toString()) , locale));
}
if (UtilValidate.isEmpty(productStoreGroupId)) {
if (productStore != null) {
try {
if (UtilValidate.isNotEmpty(productStore.getString("primaryStoreGroupId"))) {
productStoreGroupId = productStore.getString("primaryStoreGroupId");
} else {
// no ProductStore.primaryStoreGroupId, try ProductStoreGroupMember
List<GenericValue> productStoreGroupMemberList = delegator.findByAndCache("ProductStoreGroupMember", UtilMisc.toMap("productStoreId", productStoreId), UtilMisc.toList("sequenceNum", "-fromDate"));
productStoreGroupMemberList = EntityUtil.filterByDate(productStoreGroupMemberList, true);
if (productStoreGroupMemberList.size() > 0) {
GenericValue productStoreGroupMember = EntityUtil.getFirst(productStoreGroupMemberList);
productStoreGroupId = productStoreGroupMember.getString("productStoreGroupId");
}
}
} catch (GenericEntityException e) {
Debug.logError(e, "Error getting product store info from the database while calculating price" + e.toString(), module);
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"ProductPriceCannotRetrieveProductStore", UtilMisc.toMap("errorString", e.toString()) , locale));
}
}
// still empty, default to _NA_
if (UtilValidate.isEmpty(productStoreGroupId)) {
productStoreGroupId = "_NA_";
}
}
// if currencyUomId is null get from properties file, if nothing there assume USD (USD: American Dollar) for now
String currencyUomId = (String) context.get("currencyUomId");
if (UtilValidate.isEmpty(currencyUomId)) {
currencyUomId = UtilProperties.getPropertyValue("general", "currency.uom.id.default", "USD");
}
// productPricePurposeId is null assume "PURCHASE", which is equivalent to what prices were before the purpose concept
String productPricePurposeId = (String) context.get("productPricePurposeId");
if (UtilValidate.isEmpty(productPricePurposeId)) {
productPricePurposeId = "PURCHASE";
}
// termUomId, for things like recurring prices specifies the term (time/frequency measure for example) of the recurrence
// if this is empty it will simply not be used to constrain the selection
String termUomId = (String) context.get("termUomId");
// if this product is variant, find the virtual product and apply checks to it as well
String virtualProductId = null;
if ("Y".equals(product.getString("isVariant"))) {
try {
virtualProductId = ProductWorker.getVariantVirtualId(product);
} catch (GenericEntityException e) {
Debug.logError(e, "Error getting virtual product id from the database while calculating price" + e.toString(), module);
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"ProductPriceCannotRetrieveVirtualProductId", UtilMisc.toMap("errorString", e.toString()) , locale));
}
}
// get prices for virtual product if one is found; get all ProductPrice entities for this productId and currencyUomId
List<GenericValue> virtualProductPrices = null;
if (virtualProductId != null) {
try {
virtualProductPrices = delegator.findByAndCache("ProductPrice", UtilMisc.toMap("productId", virtualProductId, "currencyUomId", currencyUomId, "productStoreGroupId", productStoreGroupId), UtilMisc.toList("-fromDate"));
} catch (GenericEntityException e) {
Debug.logError(e, "An error occurred while getting the product prices", module);
}
virtualProductPrices = EntityUtil.filterByDate(virtualProductPrices, true);
}
// NOTE: partyId CAN be null
String partyId = (String) context.get("partyId");
if (UtilValidate.isEmpty(partyId) && context.get("userLogin") != null) {
GenericValue userLogin = (GenericValue) context.get("userLogin");
partyId = userLogin.getString("partyId");
}
// check for auto-userlogin for price rules
if (UtilValidate.isEmpty(partyId) && context.get("autoUserLogin") != null) {
GenericValue userLogin = (GenericValue) context.get("autoUserLogin");
partyId = userLogin.getString("partyId");
}
BigDecimal quantity = (BigDecimal) context.get("quantity");
if (quantity == null) quantity = BigDecimal.ONE;
BigDecimal amount = (BigDecimal) context.get("amount");
List<EntityCondition> productPriceEcList = FastList.newInstance();
productPriceEcList.add(EntityCondition.makeCondition("productId", EntityOperator.EQUALS, productId));
// 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
if ("PURCHASE".equals(productPricePurposeId)) {
productPriceEcList.add(EntityCondition.makeCondition(
EntityCondition.makeCondition("productPricePurposeId", EntityOperator.EQUALS, productPricePurposeId),
EntityOperator.OR,
EntityCondition.makeCondition("productPricePurposeId", EntityOperator.EQUALS, null)));
} else {
productPriceEcList.add(EntityCondition.makeCondition("productPricePurposeId", EntityOperator.EQUALS, productPricePurposeId));
}
productPriceEcList.add(EntityCondition.makeCondition("currencyUomId", EntityOperator.EQUALS, currencyUomId));
productPriceEcList.add(EntityCondition.makeCondition("productStoreGroupId", EntityOperator.EQUALS, productStoreGroupId));
if (UtilValidate.isNotEmpty(termUomId)) {
productPriceEcList.add(EntityCondition.makeCondition("termUomId", EntityOperator.EQUALS, termUomId));
}
EntityCondition productPriceEc = EntityCondition.makeCondition(productPriceEcList, EntityOperator.AND);
// for prices, get all ProductPrice entities for this productId and currencyUomId
List<GenericValue> productPrices = null;
try {
productPrices = delegator.findList("ProductPrice", productPriceEc, null, UtilMisc.toList("-fromDate"), null, true);
} catch (GenericEntityException e) {
Debug.logError(e, "An error occurred while getting the product prices", module);
}
productPrices = EntityUtil.filterByDate(productPrices, true);
// ===== get the prices we need: list, default, average cost, promo, min, max =====
List<GenericValue> listPrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "LIST_PRICE"));
GenericValue listPriceValue = EntityUtil.getFirst(listPrices);
if (listPrices != null && listPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
List<GenericValue> defaultPrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "DEFAULT_PRICE"));
GenericValue defaultPriceValue = EntityUtil.getFirst(defaultPrices);
if (defaultPrices != null && defaultPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
// If there is an agreement between the company and the client, and there is
// a price for the product in it, it will override the default price of the
// ProductPrice entity.
if (UtilValidate.isNotEmpty(agreementId)) {
try {
List<GenericValue> agreementPrices = delegator.findByAnd("AgreementItemAndProductAppl", UtilMisc.toMap("agreementId", agreementId, "productId", productId, "currencyUomId", currencyUomId));
GenericValue agreementPriceValue = EntityUtil.getFirst(agreementPrices);
if (agreementPriceValue != null && agreementPriceValue.get("price") != null) {
defaultPriceValue = agreementPriceValue;
}
} catch (GenericEntityException e) {
Debug.logError(e, "Error getting agreement info from the database while calculating price" + e.toString(), module);
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"ProductPriceCannotRetrieveAgreementInfo", UtilMisc.toMap("errorString", e.toString()) , locale));
}
}
List<GenericValue> competitivePrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "COMPETITIVE_PRICE"));
GenericValue competitivePriceValue = EntityUtil.getFirst(competitivePrices);
if (competitivePrices != null && competitivePrices.size() > 1) {
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.getBigDecimal("price"), module);
}
List<GenericValue> averageCosts = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "AVERAGE_COST"));
GenericValue averageCostValue = EntityUtil.getFirst(averageCosts);
if (averageCosts != null && averageCosts.size() > 1) {
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.getBigDecimal("price"), module);
}
List<GenericValue> promoPrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "PROMO_PRICE"));
GenericValue promoPriceValue = EntityUtil.getFirst(promoPrices);
if (promoPrices != null && promoPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
List<GenericValue> minimumPrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "MINIMUM_PRICE"));
GenericValue minimumPriceValue = EntityUtil.getFirst(minimumPrices);
if (minimumPrices != null && minimumPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
List<GenericValue> maximumPrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "MAXIMUM_PRICE"));
GenericValue maximumPriceValue = EntityUtil.getFirst(maximumPrices);
if (maximumPrices != null && maximumPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
List<GenericValue> wholesalePrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "WHOLESALE_PRICE"));
GenericValue wholesalePriceValue = EntityUtil.getFirst(wholesalePrices);
if (wholesalePrices != null && wholesalePrices.size() > 1) {
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.getBigDecimal("price"), module);
}
List<GenericValue> specialPromoPrices = EntityUtil.filterByAnd(productPrices, UtilMisc.toMap("productPriceTypeId", "SPECIAL_PROMO_PRICE"));
GenericValue specialPromoPriceValue = EntityUtil.getFirst(specialPromoPrices);
if (specialPromoPrices != null && specialPromoPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
// if any of these prices is missing and this product is a variant, default to the corresponding price on the virtual product
if (UtilValidate.isNotEmpty(virtualProductPrices)) {
if (listPriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "LIST_PRICE"));
listPriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (defaultPriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "DEFAULT_PRICE"));
defaultPriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (averageCostValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "AVERAGE_COST"));
averageCostValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (promoPriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "PROMO_PRICE"));
promoPriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (minimumPriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "MINIMUM_PRICE"));
minimumPriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (maximumPriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "MAXIMUM_PRICE"));
maximumPriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (wholesalePriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "WHOLESALE_PRICE"));
wholesalePriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (specialPromoPriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(virtualProductPrices, UtilMisc.toMap("productPriceTypeId", "SPECIAL_PROMO_PRICE"));
specialPromoPriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
}
// now if this is a virtual product check each price type, if doesn't exist get from variant with lowest DEFAULT_PRICE
if ("Y".equals(product.getString("isVirtual"))) {
// only do this if there is no default price, consider the others optional for performance reasons
if (defaultPriceValue == null) {
// Debug.logInfo("Product isVirtual and there is no default price for ID " + productId + ", trying variant prices", module);
//use the cache to find the variant with the lowest default price
try {
List<GenericValue> variantAssocList = EntityUtil.filterByDate(delegator.findByAndCache("ProductAssoc", UtilMisc.toMap("productId", product.get("productId"), "productAssocTypeId", "PRODUCT_VARIANT"), UtilMisc.toList("-fromDate")));
BigDecimal minDefaultPrice = null;
List<GenericValue> variantProductPrices = null;
String variantProductId = null;
for (GenericValue variantAssoc: variantAssocList) {
String curVariantProductId = variantAssoc.getString("productIdTo");
List<GenericValue> curVariantPriceList = EntityUtil.filterByDate(delegator.findByAndCache("ProductPrice", UtilMisc.toMap("productId", curVariantProductId), UtilMisc.toList("-fromDate")), nowTimestamp);
List<GenericValue> tempDefaultPriceList = EntityUtil.filterByAnd(curVariantPriceList, UtilMisc.toMap("productPriceTypeId", "DEFAULT_PRICE"));
GenericValue curDefaultPriceValue = EntityUtil.getFirst(tempDefaultPriceList);
if (curDefaultPriceValue != null) {
BigDecimal curDefaultPrice = curDefaultPriceValue.getBigDecimal("price");
if (minDefaultPrice == null || curDefaultPrice.compareTo(minDefaultPrice) < 0) {
// check to see if the product is discontinued for sale before considering it the lowest price
GenericValue curVariantProduct = delegator.findByPrimaryKeyCache("Product", UtilMisc.toMap("productId", curVariantProductId));
if (curVariantProduct != null) {
Timestamp salesDiscontinuationDate = curVariantProduct.getTimestamp("salesDiscontinuationDate");
if (salesDiscontinuationDate == null || salesDiscontinuationDate.after(nowTimestamp)) {
minDefaultPrice = curDefaultPrice;
variantProductPrices = curVariantPriceList;
variantProductId = curVariantProductId;
// Debug.logInfo("Found new lowest price " + minDefaultPrice + " for variant with ID " + variantProductId, module);
}
}
}
}
}
if (variantProductPrices != null) {
// we have some other options, give 'em a go...
if (listPriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "LIST_PRICE"));
listPriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (defaultPriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "DEFAULT_PRICE"));
defaultPriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (competitivePriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "COMPETITIVE_PRICE"));
competitivePriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (averageCostValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "AVERAGE_COST"));
averageCostValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (promoPriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "PROMO_PRICE"));
promoPriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (minimumPriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "MINIMUM_PRICE"));
minimumPriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (maximumPriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "MAXIMUM_PRICE"));
maximumPriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (wholesalePriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "WHOLESALE_PRICE"));
wholesalePriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
if (specialPromoPriceValue == null) {
List<GenericValue> virtualTempPrices = EntityUtil.filterByAnd(variantProductPrices, UtilMisc.toMap("productPriceTypeId", "SPECIAL_PROMO_PRICE"));
specialPromoPriceValue = EntityUtil.getFirst(virtualTempPrices);
if (virtualTempPrices != null && virtualTempPrices.size() > 1) {
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.getBigDecimal("price"), module);
}
}
}
} catch (GenericEntityException e) {
Debug.logError(e, "An error occurred while getting the product prices", module);
}
}
}
//boolean validPromoPriceFound = false;
BigDecimal promoPrice = BigDecimal.ZERO;
if (promoPriceValue != null && promoPriceValue.get("price") != null) {
promoPrice = promoPriceValue.getBigDecimal("price");
//validPromoPriceFound = true;
}
//boolean validWholesalePriceFound = false;
BigDecimal wholesalePrice = BigDecimal.ZERO;
if (wholesalePriceValue != null && wholesalePriceValue.get("price") != null) {
wholesalePrice = wholesalePriceValue.getBigDecimal("price");
//validWholesalePriceFound = true;
}
boolean validPriceFound = false;
BigDecimal defaultPrice = BigDecimal.ZERO;
List<GenericValue> orderItemPriceInfos = FastList.newInstance();
if (defaultPriceValue != null) {
// If a price calc formula (service) is specified, then use it to get the unit price
if ("ProductPrice".equals(defaultPriceValue.getEntityName()) && UtilValidate.isNotEmpty(defaultPriceValue.getString("customPriceCalcService"))) {
GenericValue customMethod = null;
try {
customMethod = defaultPriceValue.getRelatedOne("CustomMethod");
} catch (GenericEntityException gee) {
Debug.logError(gee, "An error occurred while getting the customPriceCalcService", module);
}
if (UtilValidate.isNotEmpty(customMethod) && UtilValidate.isNotEmpty(customMethod.getString("customMethodName"))) {
Map<String, Object> inMap = UtilMisc.toMap("userLogin", context.get("userLogin"), "product", product);
inMap.put("initialPrice", defaultPriceValue.getBigDecimal("price"));
inMap.put("currencyUomId", currencyUomId);
inMap.put("quantity", quantity);
inMap.put("amount", amount);
if (UtilValidate.isNotEmpty(surveyResponseId)) {
inMap.put("surveyResponseId", surveyResponseId);
}
if (UtilValidate.isNotEmpty(customAttributes)) {
inMap.put("customAttributes", customAttributes);
}
try {
Map<String, Object> outMap = dispatcher.runSync(customMethod.getString("customMethodName"), inMap);
if (!ServiceUtil.isError(outMap)) {
BigDecimal calculatedDefaultPrice = (BigDecimal)outMap.get("price");
orderItemPriceInfos = UtilGenerics.checkList(outMap.get("orderItemPriceInfos"));
if (UtilValidate.isNotEmpty(calculatedDefaultPrice)) {
defaultPrice = calculatedDefaultPrice;
validPriceFound = true;
}
}
} catch (GenericServiceException gse) {
Debug.logError(gse, "An error occurred while running the customPriceCalcService [" + customMethod.getString("customMethodName") + "]", module);
}
}
}
if (!validPriceFound && defaultPriceValue.get("price") != null) {
defaultPrice = defaultPriceValue.getBigDecimal("price");
validPriceFound = true;
}
}
BigDecimal listPrice = listPriceValue != null ? listPriceValue.getBigDecimal("price") : null;
if (listPrice == null) {
// no list price, use defaultPrice for the final price
// ========= ensure calculated price is not below minSalePrice or above maxSalePrice =========
BigDecimal maxSellPrice = maximumPriceValue != null ? maximumPriceValue.getBigDecimal("price") : null;
if (maxSellPrice != null && defaultPrice.compareTo(maxSellPrice) > 0) {
defaultPrice = maxSellPrice;
}
// min price second to override max price, safety net
BigDecimal minSellPrice = minimumPriceValue != null ? minimumPriceValue.getBigDecimal("price") : null;
if (minSellPrice != null && defaultPrice.compareTo(minSellPrice) < 0) {
defaultPrice = minSellPrice;
// 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...
validPriceFound = true;
}
result.put("basePrice", defaultPrice);
result.put("price", defaultPrice);
result.put("defaultPrice", defaultPrice);
result.put("competitivePrice", competitivePriceValue != null ? competitivePriceValue.getBigDecimal("price") : null);
result.put("averageCost", averageCostValue != null ? averageCostValue.getBigDecimal("price") : null);
result.put("promoPrice", promoPriceValue != null ? promoPriceValue.getBigDecimal("price") : null);
result.put("specialPromoPrice", specialPromoPriceValue != null ? specialPromoPriceValue.getBigDecimal("price") : null);
result.put("validPriceFound", Boolean.valueOf(validPriceFound));
result.put("isSale", Boolean.FALSE);
result.put("orderItemPriceInfos", orderItemPriceInfos);
Map<String, Object> errorResult = addGeneralResults(result, competitivePriceValue, specialPromoPriceValue, productStore,
checkIncludeVat, currencyUomId, productId, quantity, partyId, dispatcher, locale);
if (errorResult != null) return errorResult;
} else {
try {
List<GenericValue> allProductPriceRules = makeProducePriceRuleList(delegator, optimizeForLargeRuleSet, productId, virtualProductId, prodCatalogId, productStoreGroupId, webSiteId, partyId, currencyUomId);
allProductPriceRules = EntityUtil.filterByDate(allProductPriceRules, true);
List<GenericValue> quantityProductPriceRules = null;
List<GenericValue> nonQuantityProductPriceRules = null;
if (findAllQuantityPrices) {
// split into list with quantity conditions and list without, then iterate through each quantity cond one
quantityProductPriceRules = FastList.newInstance();
nonQuantityProductPriceRules = FastList.newInstance();
for (GenericValue productPriceRule: allProductPriceRules) {
List<GenericValue> productPriceCondList = delegator.findByAndCache("ProductPriceCond", UtilMisc.toMap("productPriceRuleId", productPriceRule.get("productPriceRuleId")));
boolean foundQuantityInputParam = false;
// only consider a rule if all conditions except the quantity condition are true
boolean allExceptQuantTrue = true;
for (GenericValue productPriceCond: productPriceCondList) {