in applications/product/src/main/java/org/apache/ofbiz/product/price/PriceServices.java [838:1110]
public static Map<String, Object> calcPriceResultFromRules(List<GenericValue> productPriceRules, BigDecimal listPrice, BigDecimal defaultPrice,
BigDecimal promoPrice,
BigDecimal wholesalePrice, GenericValue maximumPriceValue,
GenericValue minimumPriceValue, boolean validPriceFound,
GenericValue averageCostValue, String productId, String virtualProductId,
String prodCatalogId, String productStoreGroupId,
String webSiteId, String partyId, BigDecimal quantity, String currencyUomId,
Delegator delegator, Timestamp nowTimestamp,
Locale locale) throws GenericEntityException {
Map<String, Object> calcResults = new HashMap<>();
List<GenericValue> orderItemPriceInfos = new LinkedList<>();
boolean isSale = false;
// ========= go through each price rule by id and eval all conditions =========
int totalConds = 0;
int totalActions = 0;
int totalRules = 0;
// get some of the base values to calculate with
BigDecimal averageCost = (averageCostValue != null && averageCostValue.get("price") != null) ? averageCostValue.getBigDecimal("price")
: listPrice;
BigDecimal margin = listPrice.subtract(averageCost);
// calculate running sum based on listPrice and rules found
BigDecimal price = listPrice;
for (GenericValue productPriceRule: productPriceRules) {
String productPriceRuleId = productPriceRule.getString("productPriceRuleId");
// check from/thru dates
java.sql.Timestamp fromDate = productPriceRule.getTimestamp("fromDate");
java.sql.Timestamp thruDate = productPriceRule.getTimestamp("thruDate");
if (fromDate != null && fromDate.after(nowTimestamp)) {
// hasn't started yet
continue;
}
if (thruDate != null && thruDate.before(nowTimestamp)) {
// already expired
continue;
}
// check all conditions
boolean allTrue = true;
StringBuilder condsDescription = new StringBuilder();
List<GenericValue> productPriceConds = EntityQuery.use(delegator).from("ProductPriceCond").where("productPriceRuleId",
productPriceRuleId).cache(true).queryList();
for (GenericValue productPriceCond: productPriceConds) {
totalConds++;
if (!checkPriceCondition(productPriceCond, productId, virtualProductId, prodCatalogId, productStoreGroupId, webSiteId, partyId,
quantity, listPrice, currencyUomId, delegator, nowTimestamp)) {
allTrue = false;
break;
}
// add condsDescription string entry
condsDescription.append("[");
GenericValue inputParamEnum = productPriceCond.getRelatedOne("InputParamEnumeration", true);
condsDescription.append(inputParamEnum.getString("enumCode"));
// condsDescription.append(":");
GenericValue operatorEnum = productPriceCond.getRelatedOne("OperatorEnumeration", true);
condsDescription.append(operatorEnum.getString("description"));
// condsDescription.append(":");
condsDescription.append(productPriceCond.getString("condValue"));
condsDescription.append("] ");
}
// add some info about the prices we are calculating from
condsDescription.append("[list:");
condsDescription.append(listPrice);
condsDescription.append(";avgCost:");
condsDescription.append(averageCost);
condsDescription.append(";margin:");
condsDescription.append(margin);
condsDescription.append("] ");
boolean foundFlatOverride = false;
// if all true, perform all actions
if (allTrue) {
// check isSale
if ("Y".equals(productPriceRule.getString("isSale"))) {
isSale = true;
}
List<GenericValue> productPriceActions = EntityQuery.use(delegator).from("ProductPriceAction").where("productPriceRuleId",
productPriceRuleId).cache(true).queryList();
for (GenericValue productPriceAction: productPriceActions) {
totalActions++;
// yeah, finally here, perform the action, ie, modify the price
BigDecimal modifyAmount = BigDecimal.ZERO;
if ("PRICE_POD".equals(productPriceAction.getString("productPriceActionTypeId"))) {
if (productPriceAction.get("amount") != null) {
modifyAmount = defaultPrice.multiply(productPriceAction.getBigDecimal("amount").movePointLeft(2));
price = defaultPrice;
}
} else if ("PRICE_POL".equals(productPriceAction.getString("productPriceActionTypeId"))) {
if (productPriceAction.get("amount") != null) {
modifyAmount = listPrice.multiply(productPriceAction.getBigDecimal("amount").movePointLeft(2));
}
} else if ("PRICE_POAC".equals(productPriceAction.getString("productPriceActionTypeId"))) {
if (productPriceAction.get("amount") != null) {
modifyAmount = averageCost.multiply(productPriceAction.getBigDecimal("amount").movePointLeft(2));
}
} else if ("PRICE_POM".equals(productPriceAction.getString("productPriceActionTypeId"))) {
if (productPriceAction.get("amount") != null) {
modifyAmount = margin.multiply(productPriceAction.getBigDecimal("amount").movePointLeft(2));
}
} else if ("PRICE_POWHS".equals(productPriceAction.getString("productPriceActionTypeId"))) {
if (productPriceAction.get("amount") != null && wholesalePrice != null) {
modifyAmount = wholesalePrice.multiply(productPriceAction.getBigDecimal("amount").movePointLeft(2));
}
} else if ("PRICE_FOL".equals(productPriceAction.getString("productPriceActionTypeId"))) {
if (productPriceAction.get("amount") != null) {
modifyAmount = productPriceAction.getBigDecimal("amount");
}
} else if ("PRICE_FLAT".equals(productPriceAction.getString("productPriceActionTypeId"))) {
// this one is a bit different, break out of the loop because we now have our final price
foundFlatOverride = true;
if (productPriceAction.get("amount") != null) {
price = productPriceAction.getBigDecimal("amount");
} else {
Debug.logInfo("ProductPriceAction had null amount, using default price: " + defaultPrice + " for product with id "
+ productId, MODULE);
price = defaultPrice;
isSale = false; // reverse isSale flag, as this sale rule was actually not applied
}
} else if ("PRICE_PFLAT".equals(productPriceAction.getString("productPriceActionTypeId"))) {
// this one is a bit different too, break out of the loop because we now have our final price
foundFlatOverride = true;
price = promoPrice;
if (productPriceAction.get("amount") != null) {
price = price.add(productPriceAction.getBigDecimal("amount"));
}
if (price.compareTo(BigDecimal.ZERO) == 0) {
if (defaultPrice.compareTo(BigDecimal.ZERO) != 0) {
Debug.logInfo("PromoPrice and ProductPriceAction had null amount, using default price: " + defaultPrice
+ " for product with id " + productId, MODULE);
price = defaultPrice;
} else if (listPrice.compareTo(BigDecimal.ZERO) != 0) {
Debug.logInfo("PromoPrice and ProductPriceAction had null amount and no default price was available, "
+ "using list price: " + listPrice + " for product with id " + productId, MODULE);
price = listPrice;
} else {
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);
price = BigDecimal.ZERO;
}
isSale = false; // reverse isSale flag, as this sale rule was actually not applied
}
} else if ("PRICE_WFLAT".equals(productPriceAction.getString("productPriceActionTypeId"))) {
// same as promo price but using the wholesale price instead
foundFlatOverride = true;
price = wholesalePrice;
if (productPriceAction.get("amount") != null) {
price = price.add(productPriceAction.getBigDecimal("amount"));
}
if (price.compareTo(BigDecimal.ZERO) == 0) {
if (defaultPrice.compareTo(BigDecimal.ZERO) != 0) {
Debug.logInfo("WholesalePrice and ProductPriceAction had null amount, using default price: " + defaultPrice
+ " for product with id " + productId, MODULE);
price = defaultPrice;
} else if (listPrice.compareTo(BigDecimal.ZERO) != 0) {
Debug.logInfo("WholesalePrice and ProductPriceAction had null amount and no default price was available, "
+ "using list price: " + listPrice + " for product with id " + productId, MODULE);
price = listPrice;
} else {
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);
price = BigDecimal.ZERO;
}
isSale = false; // reverse isSale flag, as this sale rule was actually not applied
}
}
// add a orderItemPriceInfo element too, without orderId or orderItemId
StringBuilder priceInfoDescription = new StringBuilder();
priceInfoDescription.append(condsDescription.toString());
priceInfoDescription.append("[");
priceInfoDescription.append(UtilProperties.getMessage(RESOURCE, "ProductPriceConditionType", locale));
priceInfoDescription.append(productPriceAction.getString("productPriceActionTypeId"));
priceInfoDescription.append("]");
GenericValue orderItemPriceInfo = delegator.makeValue("OrderItemPriceInfo");
orderItemPriceInfo.set("productPriceRuleId", productPriceAction.get("productPriceRuleId"));
orderItemPriceInfo.set("productPriceActionSeqId", productPriceAction.get("productPriceActionSeqId"));
orderItemPriceInfo.set("modifyAmount", modifyAmount);
orderItemPriceInfo.set("rateCode", productPriceAction.get("rateCode"));
// make sure description is <= than 250 chars
String priceInfoDescriptionString = priceInfoDescription.toString();
if (priceInfoDescriptionString.length() > 250) {
priceInfoDescriptionString = priceInfoDescriptionString.substring(0, 250);
}
orderItemPriceInfo.set("description", priceInfoDescriptionString);
orderItemPriceInfos.add(orderItemPriceInfo);
if (foundFlatOverride) {
break;
} else {
price = price.add(modifyAmount);
}
}
}
totalRules++;
if (foundFlatOverride) {
break;
}
}
if (Debug.verboseOn()) {
Debug.logVerbose("Unchecked Calculated price: " + price, MODULE);
Debug.logVerbose("PriceInfo:", MODULE);
for (GenericValue orderItemPriceInfo: orderItemPriceInfos) {
if (Debug.verboseOn()) {
Debug.logVerbose(" --- " + orderItemPriceInfo, MODULE);
}
}
}
// if no actions were run on the list price, then use the default price
if (totalActions == 0) {
price = defaultPrice;
// here we will leave validPriceFound as it was originally set for the defaultPrice since that is what we are setting the price to...
} else {
// at least one price rule action was found, so we will consider it valid
validPriceFound = true;
}
// ========= ensure calculated price is not below minSalePrice or above maxSalePrice =========
BigDecimal maxSellPrice = maximumPriceValue != null ? maximumPriceValue.getBigDecimal("price") : null;
if (maxSellPrice != null && price.compareTo(maxSellPrice) > 0) {
price = maxSellPrice;
}
// min price second to override max price, safety net
BigDecimal minSellPrice = minimumPriceValue != null ? minimumPriceValue.getBigDecimal("price") : null;
if (minSellPrice != null && price.compareTo(minSellPrice) < 0) {
price = 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;
}
if (Debug.verboseOn()) {
Debug.logVerbose("Final Calculated price: " + price + ", rules: " + totalRules + ", conds: " + totalConds
+ ", actions: " + totalActions, MODULE);
}
calcResults.put("basePrice", price);
calcResults.put("price", price);
calcResults.put("listPrice", listPrice);
calcResults.put("defaultPrice", defaultPrice);
calcResults.put("averageCost", averageCost);
calcResults.put("orderItemPriceInfos", orderItemPriceInfos);
calcResults.put("isSale", isSale);
calcResults.put("validPriceFound", validPriceFound);
return calcResults;
}