blob: cacaadf627011dd0e0ff148bbd3abb110cea586f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License") you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.ofbiz.base.util.Debug
import org.apache.ofbiz.base.util.UtilDateTime
import org.apache.ofbiz.base.util.UtilMisc
import org.apache.ofbiz.entity.GenericValue
import org.apache.ofbiz.order.shoppingcart.ShoppingCart
import org.apache.ofbiz.order.shoppingcart.ShoppingCartItem
import org.apache.ofbiz.order.shoppingcart.product.ProductPromoWorker
import org.apache.ofbiz.service.GenericServiceException
import org.apache.ofbiz.service.ServiceUtil
import org.apache.ofbiz.service.calendar.RecurrenceInfo
import org.apache.ofbiz.service.calendar.RecurrenceInfoException
import java.math.MathContext
import java.math.RoundingMode
import java.sql.Timestamp
/*
* ================================================================
* ProductPromoCond Services
* ================================================================
*/
/**
* This function return success if the conditions have been met for the product amount
* @return result
*/
def productAmount() {
Map result = success()
int compareBase = -1
result.operatorEnumId = "PPC_EQ"
GenericValue productPromoCond = parameters.productPromoCond
ShoppingCart cart = parameters.shoppingCart
String condValue = productPromoCond.condValue
// this type of condition requires items involved to not be involved in any other quantity consuming cond/action, and does not pro-rate the price, just uses the base price
BigDecimal amountNeeded = BigDecimal.ZERO
if (condValue) {
amountNeeded = new BigDecimal(condValue)
}
Set<String> productIds = ProductPromoWorker.getPromoRuleCondProductIds(productPromoCond, delegator, nowTimestamp)
List<ShoppingCartItem> lineOrderedByBasePriceList = cart.getLineListOrderedByBasePrice(false)
Iterator<ShoppingCartItem> lineOrderedByBasePriceIter = lineOrderedByBasePriceList.iterator()
while (amountNeeded.compareTo(BigDecimal.ZERO) > 0 && lineOrderedByBasePriceIter.hasNext()) {
ShoppingCartItem cartItem = lineOrderedByBasePriceIter.next()
// only include if it is in the productId Set for this check and if it is not a Promo (GWP) item
GenericValue product = cartItem.getProduct()
String parentProductId = cartItem.getParentProductId()
boolean passedItemConds = ProductPromoWorker.checkConditionsForItem(productPromoCond, cart, cartItem, delegator, dispatcher, nowTimestamp)
boolean checkAmount = passedItemConds && !cartItem.getIsPromo() &&
(productIds.contains(cartItem.getProductId()) || (parentProductId && productIds.contains(parentProductId))) &&
(!product || !product.includeInPromotions || 'N' != product.includeInPromotions)
if (checkAmount) {
MathContext generalRounding = new MathContext(10)
BigDecimal basePrice = cartItem.getBasePrice()
// get a rough price, round it up to an integer
BigDecimal quantityNeeded = amountNeeded.divide(basePrice, generalRounding).setScale(0, RoundingMode.CEILING)
// reduce amount still needed to qualify for promo (amountNeeded)
BigDecimal quantity = cartItem.addPromoQuantityCandidateUse(quantityNeeded, productPromoCond, false)
// get pro-rated amount based on discount
amountNeeded = amountNeeded.subtract(quantity.multiply(basePrice))
}
}
// if amountNeeded > 0 then the promo condition failed, so remove candidate promo uses and increment the promoQuantityUsed to restore it
if (amountNeeded.compareTo(BigDecimal.ZERO) > 0) {
// failed, reset the entire rule, ie including all other conditions that might have been done before
cart.resetPromoRuleUse(productPromoCond.productPromoId, productPromoCond.productPromoRuleId)
compareBase = -1
} else {
// we got it, the conditions are in place...
compareBase = 0
// NOTE: don't confirm promo rule use here, wait until actions are complete for the rule to do that
}
result.compareBase = compareBase
return result
}
/**
* This function return success if the conditions have been met for the product total
* @return result
*/
def productTotal() {
Map result = success()
int compareBase = -1
GenericValue productPromoCond = parameters.productPromoCond
ShoppingCart cart = parameters.shoppingCart
String condValue = productPromoCond.condValue
Timestamp nowTimestamp = UtilDateTime.nowTimestamp()
if (condValue) {
BigDecimal amountNeeded = new BigDecimal(condValue)
BigDecimal amountAvailable = BigDecimal.ZERO
Set<String> productIds = ProductPromoWorker.getPromoRuleCondProductIds(productPromoCond, delegator, nowTimestamp)
List<ShoppingCartItem> lineOrderedByBasePriceList = cart.getLineListOrderedByBasePrice(false)
for (ShoppingCartItem cartItem : lineOrderedByBasePriceList) {
// only include if it is in the productId Set for this check and if it is not a Promo (GWP) item
GenericValue product = cartItem.getProduct()
String parentProductId = cartItem.getParentProductId()
boolean passedItemConds = ProductPromoWorker.checkConditionsForItem(productPromoCond, cart, cartItem, delegator, dispatcher, nowTimestamp)
if (passedItemConds && !cartItem.getIsPromo()
&& (productIds.contains(cartItem.getProductId()) || (parentProductId && productIds.contains(parentProductId)))
&& (!product || 'N' != product.includeInPromotions)) {
// just count the entire sub-total of the item
amountAvailable = amountAvailable.add(cartItem.getItemSubTotal())
}
}
compareBase = amountAvailable.compareTo(amountNeeded)
}
result.compareBase = Integer.valueOf(compareBase)
return result
}
/**
* This function return success if the conditions have been met for the product quantity
* @return result
*/
def productQuant() {
Map result = success()
GenericValue productPromoCond = parameters.productPromoCond
String operatorEnumId = productPromoCond.operatorEnumId
ShoppingCart cart = parameters.shoppingCart
String condValue = productPromoCond.condValue
Timestamp nowTimestamp = UtilDateTime.nowTimestamp()
if (!operatorEnumId) {
// if the operator is not specified in the condition, then assume as default PPC_EQ (for backward compatibility)
operatorEnumId = "PPC_EQ"
}
BigDecimal quantityNeeded = BigDecimal.ONE
if (condValue) {
quantityNeeded = new BigDecimal(condValue)
}
Set<String> productIds = ProductPromoWorker.getPromoRuleCondProductIds(productPromoCond, delegator, nowTimestamp)
List<ShoppingCartItem> lineOrderedByBasePriceList = cart.getLineListOrderedByBasePrice(false)
Iterator<ShoppingCartItem> lineOrderedByBasePriceIter = lineOrderedByBasePriceList.iterator()
while (quantityNeeded.compareTo(BigDecimal.ZERO) > 0 && lineOrderedByBasePriceIter.hasNext()) {
ShoppingCartItem cartItem = lineOrderedByBasePriceIter.next()
// only include if it is in the productId Set for this check and if it is not a Promo (GWP) item
GenericValue product = cartItem.getProduct()
String parentProductId = cartItem.getParentProductId()
boolean passedItemConds = ProductPromoWorker.checkConditionsForItem(productPromoCond, cart, cartItem, delegator, dispatcher, nowTimestamp)
if (passedItemConds && !cartItem.getIsPromo() &&
(productIds.contains(cartItem.getProductId()) || (parentProductId && productIds.contains(parentProductId))) &&
(!product || 'N' != product.includeInPromotions)) {
// reduce quantity still needed to qualify for promo (quantityNeeded)
quantityNeeded = quantityNeeded.subtract(cartItem.addPromoQuantityCandidateUse(quantityNeeded, productPromoCond, "PPC_EQ" != operatorEnumId))
}
}
// if quantityNeeded > 0 then the promo condition failed, so remove candidate promo uses and increment the promoQuantityUsed to restore it
if (quantityNeeded.compareTo(BigDecimal.ZERO) > 0) {
// failed, reset the entire rule, ie including all other conditions that might have been done before
cart.resetPromoRuleUse(productPromoCond.productPromoId, productPromoCond.productPromoRuleId)
compareBase = -1
} else {
// we got it, the conditions are in place...
compareBase = 0
// NOTE: don't confirm rpomo rule use here, wait until actions are complete for the rule to do that
}
result.compareBase = Integer.valueOf(compareBase)
return result
}
/**
* This function return success if the conditions have been met for new accounts
* @return result
*/
def productNewACCT() {
// promotion description="Account Days Since Created"
Map result = success()
GenericValue productPromoCond = parameters.productPromoCond
ShoppingCart cart = parameters.shoppingCart
String condValue = productPromoCond.condValue
Timestamp nowTimestamp = UtilDateTime.nowTimestamp()
int compareBase = -1
if (condValue) {
BigDecimal acctDays = cart.getPartyDaysSinceCreated(nowTimestamp)
if (acctDays) {
compareBase = acctDays.compareTo(new BigDecimal(condValue))
}
}
result.compareBase = Integer.valueOf(compareBase)
return result
}
/**
* This function return success if the conditions have been met for the party ID
* @return result
*/
def productPartyID() {
Map result = success()
Map productPromoCond = parameters.productPromoCond
ShoppingCart cart = parameters.shoppingCart
String condValue = productPromoCond.condValue
String partyId = cart.getPartyId()
int compareBase = 1
if (partyId && condValue) {
compareBase = partyId.compareTo(condValue)
}
result.compareBase = Integer.valueOf(compareBase)
return result
}
/**
* This function return success if the conditions have been met for the party group member
* @return result
*/
def productPartyGM() {
Map result = success()
GenericValue productPromoCond = parameters.productPromoCond
ShoppingCart cart = parameters.shoppingCart
String condValue = productPromoCond.condValue
String partyId = cart.getPartyId()
int compareBase = 1
if (partyId && condValue) {
String groupPartyId = condValue
if (partyId == groupPartyId) {
compareBase = 0
} else {
// look for PartyRelationship with partyRelationshipTypeId=GROUP_ROLLUP, the partyIdTo is the group member, so the partyIdFrom is the groupPartyId
// and from/thru date within range
List<GenericValue> partyRelationshipList = from("PartyRelationship").where("partyIdFrom", groupPartyId, "partyIdTo", partyId, "partyRelationshipTypeId", "GROUP_ROLLUP").cache(true).filterByDate().queryList()
if (partyRelationshipList) {
compareBase = 0
} else {
compareBase = ProductPromoWorker.checkConditionPartyHierarchy(delegator, nowTimestamp, groupPartyId, partyId)
}
}
}
result.compareBase = Integer.valueOf(compareBase)
return result
}
/**
* This function return success if the conditions have been met for the party class
* @return result
*/
def productPartyClass() {
Map result = success()
GenericValue productPromoCond = parameters.productPromoCond
ShoppingCart cart = parameters.shoppingCart
String condValue = productPromoCond.condValue
String partyId = cart.getPartyId()
int compareBase = 1
if (partyId && condValue) {
String partyClassificationGroupId = condValue
// find any PartyClassification
// and from/thru date within range
List<GenericValue> partyClassificationList = from("PartyClassification").where("partyId", partyId, "partyClassificationGroupId", partyClassificationGroupId).cache(true).filterByDate().queryList()
// then 0 (equals), otherwise 1 (not equals)
compareBase = partyClassificationList? 0: 1
}
result.compareBase = Integer.valueOf(compareBase)
return result
}
/**
* This function return success if the conditions have been met for the role type
* @return result
*/
def productRoleType() {
Map result = success()
GenericValue productPromoCond = parameters.productPromoCond
ShoppingCart cart = parameters.shoppingCart
String condValue = productPromoCond.condValue
String partyId = cart.getPartyId()
int compareBase = 1
if (partyId && condValue) {
// if a PartyRole exists for this partyId and the specified roleTypeId
GenericValue partyRole = from("PartyRole").where("partyId", partyId, "roleTypeId", condValue).cache(true).queryOne()
// then 0 (equals), otherwise 1 (not equals)
compareBase = partyRole? 0: 1
}
result.compareBase = Integer.valueOf(compareBase)
return result
}
/**
* This function return success if the conditions have been met for the shipping destination
* @return result
*/
def productGeoID() {
Map result = success()
GenericValue productPromoCond = parameters.productPromoCond
String condValue = productPromoCond.condValue
ShoppingCart cart = parameters.shoppingCart
GenericValue shippingAddress = cart.getShippingAddress()
int compareBase = 1
if (condValue && shippingAddress) {
if (condValue == shippingAddress.countryGeoId
|| condValue == shippingAddress.countyGeoId
|| condValue == shippingAddress.postalCodeGeoId
|| condValue == shippingAddress.stateProvinceGeoId) {
compareBase = 0
} else {
List<GenericValue> geoAssocList = from("GeoAssoc").where("geoIdTo", condValue).queryList()
for (GenericValue geo : geoAssocList) {
if (geo.geoId == shippingAddress.countryGeoId
|| geo.geoId == shippingAddress.countyGeoId
|| geo.geoId == shippingAddress.postalCodeGeoId
|| geo.geoId == shippingAddress.stateProvinceGeoId) {
compareBase = 0
break
}
}
}
}
result.compareBase = Integer.valueOf(compareBase)
return result
}
/**
* This function return success if the conditions have been met for the product order total
* @return result
*/
def productOrderTotal() {
Map result = success()
int compareBase = 1
GenericValue productPromoCond = parameters.productPromoCond
ShoppingCart cart = parameters.shoppingCart
String condValue = productPromoCond.condValue
if (condValue) {
BigDecimal orderSubTotal = cart.getSubTotalForPromotions()
if (Debug.infoOn()) logInfo("Doing order total compare: orderSubTotal=" + orderSubTotal)
compareBase = orderSubTotal.compareTo(new BigDecimal(condValue))
}
result.compareBase = Integer.valueOf(compareBase)
return result
}
/**
* This function return success if the conditions have been met for the product order sub-total X in last Y Months
* @return result
*/
def productOrderHist() {
// description="Order sub-total X in last Y Months"
GenericValue productPromoCond = parameters.productPromoCond
ShoppingCart cart = parameters.shoppingCart
String condValue = productPromoCond.condValue
String otherValue = productPromoCond.otherValue
String partyId = cart.getPartyId()
GenericValue userLogin = cart.getUserLogin()
Map result = success()
int compareBase = -1
result.operatorEnumId = "PPC_GTE"
if (partyId && userLogin && condValue) {
// call the getOrderedSummaryInformation service to get the sub-total
int monthsToInclude = 12
if (otherValue != null) {
monthsToInclude = Integer.parseInt(otherValue)
}
Map<String, Object> serviceIn = [partyId: partyId, roleTypeId: "PLACING_CUSTOMER", orderTypeId: "SALES_ORDER", statusId: "ORDER_COMPLETED",
monthsToInclude: Integer.valueOf(monthsToInclude), userLogin: userLogin]
try {
Map<String, Object> serviceResult = run service: "getOrderedSummaryInformation", with: serviceIn
if (ServiceUtil.isError(serviceResult)) {
logError("Error calling getOrderedSummaryInformation service for the PPIP_ORST_HIST ProductPromo condition input value: " + ServiceUtil.getErrorMessage(result))
return serviceResult
} else {
BigDecimal orderSubTotal = serviceResult.get("totalSubRemainingAmount")
BigDecimal orderSubTotalAndCartSubTotal = orderSubTotal.add(cart.getSubTotal())
if (Debug.verboseOn()) logVerbose("Doing order history sub-total compare: orderSubTotal=" + orderSubTotal + ", for the last " + monthsToInclude + " months.")
compareBase = orderSubTotalAndCartSubTotal.compareTo(new BigDecimal(condValue))
}
} catch (GenericServiceException e) {
logError(e, "Error getting order history sub-total in the getOrderedSummaryInformation service, evaluating condition to false.")
return ServiceUtil.returnError("Error getting order history")
}
}
result.compareBase = compareBase
return result
}
/**
* This function return success if the conditions have been met for the product order of the current year
* @return result
*/
def productOrderYear() {
Map result = success()
compareBase = 1
GenericValue productPromoCond = parameters.productPromoCond
ShoppingCart cart = parameters.shoppingCart
String condValue = productPromoCond.condValue
GenericValue userLogin = cart.getUserLogin()
String partyId = cart.getPartyId()
// description="Order sub-total X since beginning of current year"
if (partyId && userLogin && condValue) {
// call the getOrderedSummaryInformation service to get the sub-total
Calendar calendar = Calendar.getInstance()
calendar.setTime(nowTimestamp)
int monthsToInclude = calendar.get(Calendar.MONTH) + 1
Map<String, Object> serviceIn = UtilMisc.<String, Object> toMap("partyId", partyId,
"roleTypeId", "PLACING_CUSTOMER",
"orderTypeId", "SALES_ORDER",
"statusId", "ORDER_COMPLETED",
"monthsToInclude", Integer.valueOf(monthsToInclude),
"userLogin", userLogin)
try {
Map<String, Object> serviceResult = dispatcher.runSync("getOrderedSummaryInformation", serviceIn)
if (ServiceUtil.isError(result)) {
logError("Error calling getOrderedSummaryInformation service for the PPIP_ORST_YEAR ProductPromo condition input value: " + ServiceUtil.getErrorMessage(result))
return serviceResult
} else {
BigDecimal orderSubTotal = result.get("totalSubRemainingAmount")
if (Debug.verboseOn()) logVerbose("Doing order history sub-total compare: orderSubTotal=" + orderSubTotal + ", for the last " + monthsToInclude + " months.")
compareBase = orderSubTotal.compareTo(new BigDecimal((condValue)))
}
} catch (GenericServiceException e) {
logError(e, "Error getting order history sub-total in the getOrderedSummaryInformation service, evaluating condition to false.")
return ServiceUtil.returnError("Error getting order history")
}
}
result.compareBase = Integer.valueOf(compareBase)
return result
}
/**
* This function return success if the conditions have been met for the product order last year
* @return result
*/
def productOrderLastYear() {
// description="Order sub-total X since beginning of last year"
Map result = success()
compareBase = 1
GenericValue productPromoCond = parameters.productPromoCond
ShoppingCart cart = parameters.shoppingCart
String condValue = productPromoCond.condValue
GenericValue userLogin = cart.getUserLogin()
String partyId = cart.getPartyId()
if (partyId && userLogin && condValue) {
// call the getOrderedSummaryInformation service to get the sub-total
Calendar calendar = Calendar.getInstance()
calendar.setTime(nowTimestamp)
int lastYear = calendar.get(Calendar.YEAR) - 1
Calendar fromDateCalendar = Calendar.getInstance()
fromDateCalendar.set(lastYear, 0, 0, 0, 0)
Timestamp fromDate = new Timestamp(fromDateCalendar.getTime().getTime())
Calendar thruDateCalendar = Calendar.getInstance()
thruDateCalendar.set(lastYear, 12, 0, 0, 0)
Timestamp thruDate = new Timestamp(thruDateCalendar.getTime().getTime())
Map<String, Object> serviceIn = UtilMisc.toMap("partyId", partyId,
"roleTypeId", "PLACING_CUSTOMER",
"orderTypeId", "SALES_ORDER",
"statusId", "ORDER_COMPLETED",
"fromDate", fromDate,
"thruDate", thruDate,
"userLogin", userLogin)
try {
Map<String, Object> serviceResult = dispatcher.runSync("getOrderedSummaryInformation", serviceIn)
if (ServiceUtil.isError(serviceResult)) {
logError("Error calling getOrderedSummaryInformation service for the PPIP_ORST_LAST_YEAR ProductPromo condition input value: " + ServiceUtil.getErrorMessage(result))
return serviceResult
} else {
Double orderSubTotal = (Double) result.get("totalSubRemainingAmount")
if (Debug.verboseOn()) logVerbose("Doing order history sub-total compare: orderSubTotal=" + orderSubTotal + ", for last year.")
compareBase = orderSubTotal.compareTo(Double.valueOf(condValue))
}
} catch (GenericServiceException e) {
logError(e, "Error getting order history sub-total in the getOrderedSummaryInformation service, evaluating condition to false.")
return ServiceUtil.returnError("Error getting order history")
}
}
result.compareBase = Integer.valueOf(compareBase)
return result
}
/**
* This function return success if the conditions have been met for the product promo recurrence
* @return result
*/
def productPromoRecurrence() {
Map result = success()
int compareBase = 1
GenericValue productPromoCond = parameters.productPromoCond
String condValue = productPromoCond.condValue
if (condValue) {
GenericValue recurrenceInfo = from("RecurrenceInfo").where("recurrenceInfoId", condValue).cache().queryOne();
if (recurrenceInfo) {
RecurrenceInfo recurrence = null
try {
recurrence = new RecurrenceInfo(recurrenceInfo)
} catch (RecurrenceInfoException e) {
logError(e, module)
}
// check the current recurrence
if (recurrence && recurrence.isValidCurrent()) {
compareBase = 0
}
}
}
result.compareBase = Integer.valueOf(compareBase)
return result
}
/**
* This function return success if the conditions have been met for the product total shipping
* @return result
*/
def productShipTotal() {
Map result = success()
compareBase = 1
GenericValue productPromoCond = parameters.productPromoCond
String condValue = productPromoCond.condValue
ShoppingCart cart = parameters.shoppingCart
if (condValue) {
BigDecimal orderTotalShipping = cart.getTotalShipping()
if (Debug.verboseOn()) {
logVerbose("Doing order total Shipping compare: ordertotalShipping=" + orderTotalShipping)
}
compareBase = orderTotalShipping.compareTo(new BigDecimal(condValue))
}
result.compareBase = Integer.valueOf(compareBase)
return result
}
/**
* This function do nothing except to return true for the product list price minimum amount
* @return true
*/
def productListPriceMinAmount() {
// does nothing on order level, only checked on item level, so ignore by always considering passed
return true
}
/**
* This function do nothing except to return true for the product list percent minimum amount
* @return true
*/
def productListPriceMinPercent() {
// does nothing on order level, only checked on item level, so ignore by always considering passed
return true
}