Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.adobe.cq.commerce.common.promotion.PerfectPartnerPromotionHandler Maven / Gradle / Ivy
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* __________________
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/
package com.adobe.cq.commerce.common.promotion;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.felix.scr.annotations.Reference;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.adobe.cq.commerce.api.CommerceException;
import com.adobe.cq.commerce.api.CommerceSession;
import com.adobe.cq.commerce.api.CommerceSession.CartEntry;
import com.adobe.cq.commerce.api.PriceInfo;
import com.adobe.cq.commerce.api.Product;
import com.adobe.cq.commerce.api.promotion.Promotion;
import com.adobe.cq.commerce.api.promotion.PromotionHandler;
import com.adobe.cq.commerce.common.CommerceHelper;
import com.adobe.cq.commerce.common.PriceFilter;
import com.day.cq.i18n.I18n;
import com.day.cq.wcm.api.PageManager;
/**
* PerfectPartnerPromotionHandler
applies a configured discount
* (percentage or absolute) on a product, if the product itself and its partner
* product have been added to the cart.
*
* @deprecated in 6.1 (moved to info.geometrixx.commons.impl.PerfectPartnerPromotionHandler)
*/
@Deprecated
public class PerfectPartnerPromotionHandler implements PromotionHandler {
private final Logger log = LoggerFactory.getLogger(PerfectPartnerPromotionHandler.class);
@Reference
private ResourceResolverFactory resolverFactory = null;
Map promoCache = new HashMap();
private PriceInfo calcDiscount(CartEntry cartEntry, String discountType, BigDecimal discountValue) throws CommerceException {
BigDecimal discount = BigDecimal.ZERO;
final PriceInfo unitPrice = cartEntry.getPriceInfo(new PriceFilter("UNIT")).get(0);
if (discountType.equals("percentage")) {
discount = discount.add(unitPrice.getAmount().multiply(discountValue.divide(new BigDecimal(100.0))));
} else if (discountType.equals("absolute")) {
discount = discount.add(discountValue);
}
discount = discount.multiply(new BigDecimal(cartEntry.getQuantity()));
return new PriceInfo(discount, unitPrice.getLocale());
}
synchronized public PriceInfo applyCartEntryPromotion(CommerceSession commerceSession, Promotion promotion, CartEntry cartEntry) throws CommerceException {
ValueMap config = promotion.getConfig();
String discountType = config.get("discountType", "");
BigDecimal discountValue = config.get("discountValue", BigDecimal.ZERO);
String promoPath = promotion.getPath();
validateCache(promoPath);
if (promoCache.get(promoPath).getCompanion(cartEntry.getProduct(), commerceSession) != null) {
// first product also in cart, so apply discount
return calcDiscount(cartEntry, discountType, discountValue);
}
return null;
}
public PriceInfo applyOrderPromotion(CommerceSession commerceSession, Promotion promotion) throws CommerceException {
return null;
}
public PriceInfo applyShippingPromotion(CommerceSession commerceSession, Promotion promotion) throws CommerceException {
return null;
}
@Deprecated
synchronized public String getMessage(SlingHttpServletRequest request, CommerceSession commerceSession, Promotion promotion) throws CommerceException {
return getDescription(request, commerceSession, promotion);
}
synchronized public String getDescription(SlingHttpServletRequest request, CommerceSession commerceSession, Promotion promotion) throws CommerceException {
String promoPath = promotion.getPath();
validateCache(promoPath);
PairingsCache pairingCache = promoCache.get(promoPath);
List resolved = new ArrayList();
Map potentials = new HashMap();
pairingCache.characterizeCart(commerceSession, resolved, potentials);
PageManager pageManager = request.getResourceResolver().adaptTo(PageManager.class);
I18n i18n = new I18n(request);
String description = "";
for (String pathSet : resolved) {
if (description.length() > 0) {
description += " ";
}
try {
String paths[] = pathSet.split(";");
Product product1 = CommerceHelper.findCurrentProduct(pageManager.getPage(paths[0]));
Product product2 = CommerceHelper.findCurrentProduct(pageManager.getPage(paths[1]));
description += product1.getTitle() + " + " + product2.getTitle();
} catch (Exception e) {
description += i18n.get("error fetching products");
}
}
for (Map.Entry potential : potentials.entrySet()) {
String path1 = potential.getKey();
String path2 = potential.getValue();
if (description.length() > 0) {
description += " ";
}
try {
Product product1 = CommerceHelper.findCurrentProduct(pageManager.getPage(path1));
Product product2 = CommerceHelper.findCurrentProduct(pageManager.getPage(path2));
description += i18n.get("{0} (suggest {1}) ", null, product1.getTitle(), product2.getTitle());
} catch (Exception e) {
description += i18n.get("error fetching products");
}
}
if (description.length() == 0) {
description = i18n.get("no pairings in cart");
}
return description;
}
synchronized public Map getMessages(SlingHttpServletRequest request, CommerceSession commerceSession, Promotion promotion) throws CommerceException {
Map messages = new HashMap();
ValueMap config = promotion.getConfig();
String discountType = config.get("discountType", "");
BigDecimal discountValue = config.get("discountValue", BigDecimal.ZERO);
String messageTemplate = config.get("message", String.class);
if (messageTemplate == null) {
return messages;
}
String promoPath = promotion.getPath();
validateCache(promoPath);
PairingsCache pairingCache = promoCache.get(promoPath);
I18n i18n = new I18n(request);
PageManager pageManager = request.getResourceResolver().adaptTo(PageManager.class);
for (CartEntry entry : commerceSession.getCartEntries()) {
Product product = entry.getProduct();
String companionPath = pairingCache.getCompanion(product, commerceSession);
if (companionPath != null) {
String companionTitle;
try {
Product companion = CommerceHelper.findCurrentProduct(pageManager.getPage(companionPath));
companionTitle = companion.getTitle();
} catch (Exception e) {
companionTitle = i18n.get("unknown product");
}
PriceInfo discount = calcDiscount(entry, discountType, discountValue);
messages.put(entry.getEntryIndex(), MessageFormat.format(messageTemplate, "", companionTitle, discount.getFormattedString()));
}
}
return messages;
}
synchronized public void getPotentials(CommerceSession commerceSession, Promotion promotion, Map potentials) throws CommerceException {
String promoPath = promotion.getPath();
validateCache(promoPath);
PairingsCache pairingCache = promoCache.get(promoPath);
List resolved = new ArrayList();
pairingCache.characterizeCart(commerceSession, resolved, potentials);
}
synchronized public void invalidateCaches() {
promoCache.clear();
}
private class PairingsCache {
//
// Since a particular product might appear in multiple pairings (and on both sides), we
// need to implement separate maps:
//
// 1) a map from firstProduct : list of secondProducts can be used to determine what
// products to generate teasers for when the firstProduct appears in the cart
//
// 2) a map from secondProduct : list of firstProducts can be used to determine whether
// or not to discount the second product
//
private Map> firstProductMap = new HashMap>();
private Map> secondProductMap = new HashMap>();
public void addPairing(String firstProductPath, String secondProductPath) {
if (firstProductPath == null || secondProductPath == null) {
return;
}
if (firstProductMap.containsKey(firstProductPath)) {
firstProductMap.get(firstProductPath).add(secondProductPath);
} else {
List secondProductList = new ArrayList();
secondProductList.add(secondProductPath);
firstProductMap.put(firstProductPath, secondProductList);
}
if (secondProductMap.containsKey(secondProductPath)) {
secondProductMap.get(secondProductPath).add(firstProductPath);
} else {
List firstProductList = new ArrayList();
firstProductList.add(firstProductPath);
secondProductMap.put(secondProductPath, firstProductList);
}
}
public String getCompanion(Product product, CommerceSession commerceSession) throws CommerceException {
// We want to know if a particular secondProduct should be discounted. So grab the list
// of firstProducts which appeared with it in the pairings, and see if any of them are in the
// cart.
String secondProductPath = getProductPagePath(product);
if (secondProductMap.containsKey(secondProductPath)) {
List firstProductList = secondProductMap.get(secondProductPath);
for (String firstProductPath : firstProductList) {
if (productInCart(firstProductPath, commerceSession)) {
return firstProductPath;
}
}
}
return null;
}
public void characterizeCart(CommerceSession commerceSession, List resolved, Map potentials)
throws CommerceException {
for (CartEntry entry : commerceSession.getCartEntries()) {
String firstProductPath = getProductPagePath(entry.getProduct());
if (firstProductMap.containsKey(firstProductPath)) {
List secondProductsList = firstProductMap.get(firstProductPath);
boolean match = false;
for (String secondProductPath : secondProductsList) {
if (productInCart(secondProductPath, commerceSession)) {
resolved.add(firstProductPath + ";" + secondProductPath);
match = true;
}
}
if (!match) {
// TODO: it'd be nice to have the pairings ranked so we could be more discriminating
// But for now, just grab the first:
potentials.put(firstProductPath, secondProductsList.get(0));
}
}
}
}
//
// Turn the product page URL into a simple path for comparison
//
private String getProductPagePath(Product product) {
String href = product.getPagePath();
int extension = href.indexOf(".html");
if (extension > 0) {
return href.substring(0, extension);
} else {
int fragment = href.indexOf('#');
if (fragment > 0) {
return href.substring(0, fragment);
}
}
return href;
}
private boolean productInCart(String productPath, CommerceSession commerceSession) throws CommerceException {
for (CartEntry entry : commerceSession.getCartEntries()) {
if (getProductPagePath(entry.getProduct()).equals(productPath)) {
return true;
}
}
return false;
}
}
//
// Make sure the requested promotion is in the cache.
//
synchronized private void validateCache(String promoPath) {
if (!promoCache.containsKey(promoPath)) {
ResourceResolver serviceResolver = null;
try {
PairingsCache pairingsCache = new PairingsCache();
promoCache.put(promoPath, pairingsCache);
final Map authenticationInfo = new HashMap();
authenticationInfo.put(ResourceResolverFactory.SUBSERVICE, "frontend");
serviceResolver = resolverFactory.getServiceResourceResolver(authenticationInfo);
Resource promoResource = serviceResolver.getResource(promoPath);
Resource pairings = promoResource.getChild("jcr:content").getChild("config").getChild("pairings");
Iterator iterator = pairings.listChildren();
while (iterator.hasNext()) {
ValueMap pair = ResourceUtil.getValueMap(iterator.next());
pairingsCache.addPairing(pair.get("firstProductPath", String.class), pair.get("secondProductPath", String.class));
}
} catch (Exception e) {
log.error("Couldn't construct promotion cache for: " + promoPath, e);
} finally {
if (serviceResolver != null && serviceResolver.isLive()) {
serviceResolver.close();
}
}
}
}
}