0001: /*
0002: * $Id: ShoppingCartItem.java,v 1.27 2004/01/12 17:18:19 jonesde Exp $
0003: *
0004: * Copyright (c) 2001, 2002 The Open For Business Project - www.ofbiz.org
0005: *
0006: * Permission is hereby granted, free of charge, to any person obtaining a
0007: * copy of this software and associated documentation files (the "Software"),
0008: * to deal in the Software without restriction, including without limitation
0009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0010: * and/or sell copies of the Software, and to permit persons to whom the
0011: * Software is furnished to do so, subject to the following conditions:
0012: *
0013: * The above copyright notice and this permission notice shall be included
0014: * in all copies or substantial portions of the Software.
0015: *
0016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
0017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
0019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
0020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
0021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
0022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0023: */
0024: package org.ofbiz.order.shoppingcart;
0025:
0026: import java.util.ArrayList;
0027: import java.util.HashMap;
0028: import java.util.Iterator;
0029: import java.util.LinkedList;
0030: import java.util.List;
0031: import java.util.Locale;
0032: import java.util.Map;
0033:
0034: import org.ofbiz.base.util.Debug;
0035: import org.ofbiz.base.util.UtilDateTime;
0036: import org.ofbiz.base.util.UtilFormatOut;
0037: import org.ofbiz.base.util.UtilMisc;
0038: import org.ofbiz.base.util.UtilProperties;
0039: import org.ofbiz.base.util.UtilValidate;
0040: import org.ofbiz.entity.GenericDelegator;
0041: import org.ofbiz.entity.GenericEntityException;
0042: import org.ofbiz.entity.GenericPK;
0043: import org.ofbiz.entity.GenericValue;
0044: import org.ofbiz.entity.condition.EntityExpr;
0045: import org.ofbiz.entity.condition.EntityOperator;
0046: import org.ofbiz.entity.util.EntityUtil;
0047: import org.ofbiz.order.order.OrderReadHelper;
0048: import org.ofbiz.product.catalog.CatalogWorker;
0049: import org.ofbiz.product.category.CategoryWorker;
0050: import org.ofbiz.product.product.ProductContentWrapper;
0051: import org.ofbiz.product.product.ProductWorker;
0052: import org.ofbiz.service.GenericServiceException;
0053: import org.ofbiz.service.LocalDispatcher;
0054: import org.ofbiz.service.ModelService;
0055:
0056: /**
0057: * <p><b>Title:</b> ShoppingCartItem.java
0058: * <p><b>Description:</b> Shopping cart item object.
0059: *
0060: * @author <a href="mailto:jaz@ofbiz.org.com">Andy Zeneski</a>
0061: * @author <a href="mailto:jonesde@ofbiz.org">David E. Jones</a>
0062: * @version $Revision: 1.27 $
0063: * @since 2.0
0064: */
0065: public class ShoppingCartItem implements java.io.Serializable {
0066:
0067: public static String module = ShoppingCartItem.class.getName();
0068: public static final String resource = "OrderUiLabels";
0069: public static String[] attributeNames = { "shoppingListId",
0070: "shoppingListItemSeqId", "surveyResponses" };
0071:
0072: private transient GenericDelegator delegator = null;
0073: private transient GenericValue _product = null; // the actual product
0074: private transient GenericValue _parentProduct = null; // the virtual product
0075:
0076: private String delegatorName = null;
0077: private String prodCatalogId = null;
0078: private String productId = null;
0079: private String itemType = null;
0080: private String itemComment = null;
0081: private String productCategoryId = null;
0082: private String itemDescription = null; // special field for non-product items
0083: private double quantity = 0.0;
0084: private double basePrice = 0.0;
0085: private double listPrice = 0.0;
0086: private double selectedAmount = 0.0;
0087: private Map attributes = null;
0088: private String orderItemSeqId = null;
0089: private GenericValue orderShipmentPreference = null;
0090:
0091: private Locale locale = null;
0092:
0093: private Map contactMechIdsMap = new HashMap();
0094: private List orderItemPriceInfos = null;
0095: private List itemAdjustments = new LinkedList();
0096: private boolean isPromo = false;
0097: private double promoQuantityUsed = 0;
0098: private Map quantityUsedPerPromoCandidate = new HashMap();
0099: private Map quantityUsedPerPromoFailed = new HashMap();
0100: private Map quantityUsedPerPromoActual = new HashMap();
0101: private Map additionalProductFeatureAndAppls = new HashMap();
0102:
0103: /**
0104: * Makes a ShoppingCartItem and adds it to the cart.
0105: * NOTE: This method will get the product entity and check to make sure it can be purchased.
0106: *
0107: * @param cartLocation The location to place this item; null will place at the end
0108: * @param productId The primary key of the product being added
0109: * @param quantity The quantity to add
0110: * @param additionalProductFeatureAndAppls Product feature/appls map
0111: * @param attributes All unique attributes for this item (NOT features)
0112: * @param prodCatalogId The catalog this item was added from
0113: * @param dispatcher LocalDispatcher object for doing promotions, etc
0114: * @param cart The parent shopping cart object this item will belong to
0115: * @return a new ShoppingCartItem object
0116: * @throws CartItemModifyException
0117: */
0118: public static ShoppingCartItem makeItem(Integer cartLocation,
0119: String productId, double selectedAmount, double quantity,
0120: Map additionalProductFeatureAndAppls, Map attributes,
0121: String prodCatalogId, LocalDispatcher dispatcher,
0122: ShoppingCart cart) throws CartItemModifyException {
0123: GenericDelegator delegator = cart.getDelegator();
0124: GenericValue product = null;
0125:
0126: try {
0127: product = delegator.findByPrimaryKeyCache("Product",
0128: UtilMisc.toMap("productId", productId));
0129:
0130: // first see if there is a purchase allow category and if this product is in it or not
0131: String purchaseProductCategoryId = CatalogWorker
0132: .getCatalogPurchaseAllowCategoryId(delegator,
0133: prodCatalogId);
0134: if (purchaseProductCategoryId != null) {
0135: if (!CategoryWorker.isProductInCategory(delegator,
0136: product.getString("productId"),
0137: purchaseProductCategoryId)) {
0138: // a Purchase allow productCategoryId was found, but the product is not in the category, axe it...
0139: product = null;
0140: }
0141: }
0142: } catch (GenericEntityException e) {
0143: Debug.logWarning(e.toString(), module);
0144: product = null;
0145: }
0146:
0147: if (product == null) {
0148: Map messageMap = UtilMisc.toMap("productId", productId);
0149:
0150: String excMsg = UtilProperties.getMessage(resource,
0151: "item.product_not_found", messageMap, cart
0152: .getLocale());
0153:
0154: Debug.logWarning(excMsg, module);
0155: throw new CartItemModifyException(excMsg);
0156: }
0157:
0158: return makeItem(cartLocation, product, selectedAmount,
0159: quantity, additionalProductFeatureAndAppls, attributes,
0160: prodCatalogId, dispatcher, cart, true);
0161: }
0162:
0163: /**
0164: * Makes a ShoppingCartItem and adds it to the cart.
0165: * WARNING: This method does not check if the product is in a purchase category.
0166: *
0167: * @param cartLocation The location to place this item; null will place at the end
0168: * @param product The product entity relating to the product being added
0169: * @param quantity The quantity to add
0170: * @param additionalProductFeatureAndAppls Product feature/appls map
0171: * @param attributes All unique attributes for this item (NOT features)
0172: * @param prodCatalogId The catalog this item was added from
0173: * @param dispatcher LocalDispatcher object for doing promotions, etc
0174: * @param cart The parent shopping cart object this item will belong to
0175: * @param doPromotions Indicates if we should run promotions
0176: * @return a new ShoppingCartItem object
0177: * @throws CartItemModifyException
0178: */
0179: public static ShoppingCartItem makeItem(Integer cartLocation,
0180: GenericValue product, double selectedAmount,
0181: double quantity, Map additionalProductFeatureAndAppls,
0182: Map attributes, String prodCatalogId,
0183: LocalDispatcher dispatcher, ShoppingCart cart,
0184: boolean doPromotions) throws CartItemModifyException {
0185: ShoppingCartItem newItem = new ShoppingCartItem(product,
0186: additionalProductFeatureAndAppls, attributes,
0187: prodCatalogId, cart.getLocale());
0188:
0189: // check to see if product is virtual
0190: if ("Y".equals(product.getString("isVirtual"))) {
0191: String excMsg = "Tried to add the Virtual Product "
0192: + product.getString("productName")
0193: + " (productId: " + product.getString("productId")
0194: + ") to the cart, not adding.";
0195:
0196: Debug.logWarning(excMsg, module);
0197: throw new CartItemModifyException(excMsg);
0198: }
0199:
0200: java.sql.Timestamp nowTimestamp = UtilDateTime.nowTimestamp();
0201:
0202: // check to see if introductionDate hasn't passed yet
0203: if (product.get("introductionDate") != null
0204: && nowTimestamp.before(product
0205: .getTimestamp("introductionDate"))) {
0206: String excMsg = "Tried to add the Product "
0207: + product.getString("productName")
0208: + " (productId: "
0209: + product.getString("productId")
0210: + ") to the cart. This product has not yet been made available for sale, so not adding.";
0211:
0212: Debug.logWarning(excMsg, module);
0213: throw new CartItemModifyException(excMsg);
0214: }
0215:
0216: // check to see if salesDiscontinuationDate has passed
0217: if (product.get("salesDiscontinuationDate") != null
0218: && nowTimestamp.after(product
0219: .getTimestamp("salesDiscontinuationDate"))) {
0220: String excMsg = "Tried to add the Product "
0221: + product.getString("productName")
0222: + " (productId: "
0223: + product.getString("productId")
0224: + ") to the cart. This product is no longer available for sale, so not adding.";
0225:
0226: Debug.logWarning(excMsg, module);
0227: throw new CartItemModifyException(excMsg);
0228: }
0229:
0230: // add to cart before setting quantity so that we can get order total, etc
0231: if (cartLocation == null) {
0232: cart.addItemToEnd(newItem);
0233: } else {
0234: cart.addItem(cartLocation.intValue(), newItem);
0235: }
0236:
0237: try {
0238: newItem.setQuantity(quantity, dispatcher, cart,
0239: doPromotions);
0240: } catch (CartItemModifyException e) {
0241: cart.removeCartItem(cart.getItemIndex(newItem), dispatcher);
0242: cart.removeEmptyCartItems();
0243: throw e;
0244: }
0245:
0246: if (selectedAmount > 0) {
0247: newItem.setSelectedAmount(selectedAmount);
0248: }
0249: return newItem;
0250: }
0251:
0252: public static ShoppingCartItem makeItem(Integer cartLocation,
0253: GenericValue product, double quantity,
0254: Map additionalProductFeatureAndAppls, Map attributes,
0255: String prodCatalogId, LocalDispatcher dispatcher,
0256: ShoppingCart cart, boolean doPromotions)
0257: throws CartItemModifyException {
0258: return makeItem(cartLocation, product, 0.00, quantity,
0259: additionalProductFeatureAndAppls, attributes,
0260: prodCatalogId, dispatcher, cart, doPromotions);
0261: }
0262:
0263: /**
0264: * Makes a non-product ShoppingCartItem and adds it to the cart.
0265: * NOTE: This is only for non-product items; items without a product entity (work items, bulk items, etc)
0266: *
0267: * @param cartLocation The location to place this item; null will place at the end
0268: * @param itemType The OrderItemTypeId for the item being added
0269: * @param itemDescription The optional description of the item
0270: * @param productCategoryId The optional category the product *will* go in
0271: * @param basePrice The price for this item
0272: * @param quantity The quantity to add
0273: * @param attributes All unique attributes for this item (NOT features)
0274: * @param prodCatalogId The catalog this item was added from
0275: * @param dispatcher LocalDispatcher object for doing promotions, etc
0276: * @param cart The parent shopping cart object this item will belong to
0277: * @param doPromotions Indicates if we should run promotions
0278: * @return a new ShoppingCartItem object
0279: * @throws CartItemModifyException
0280: */
0281: public static ShoppingCartItem makeItem(Integer cartLocation,
0282: String itemType, String itemDescription,
0283: String productCategoryId, double basePrice,
0284: double selectedAmount, double quantity, Map attributes,
0285: String prodCatalogId, LocalDispatcher dispatcher,
0286: ShoppingCart cart, boolean doPromotions)
0287: throws CartItemModifyException {
0288: GenericDelegator delegator = cart.getDelegator();
0289: ShoppingCartItem newItem = new ShoppingCartItem(delegator,
0290: itemType, itemDescription, productCategoryId,
0291: basePrice, attributes, prodCatalogId, cart.getLocale());
0292:
0293: // add to cart before setting quantity so that we can get order total, etc
0294: if (cartLocation == null) {
0295: cart.addItemToEnd(newItem);
0296: } else {
0297: cart.addItem(cartLocation.intValue(), newItem);
0298: }
0299:
0300: try {
0301: newItem.setQuantity(quantity, dispatcher, cart,
0302: doPromotions);
0303: } catch (CartItemModifyException e) {
0304: cart.removeEmptyCartItems();
0305: throw e;
0306: }
0307:
0308: if (selectedAmount > 0) {
0309: newItem.setSelectedAmount(selectedAmount);
0310: }
0311: return newItem;
0312: }
0313:
0314: /** Clone an item. */
0315: public ShoppingCartItem(ShoppingCartItem item) {
0316: try {
0317: this ._product = item.getProduct();
0318: } catch (IllegalStateException e) {
0319: this ._product = null;
0320: }
0321: this .delegator = item.getDelegator();
0322: this .delegatorName = item.delegatorName;
0323: this .prodCatalogId = item.getProdCatalogId();
0324: this .productId = item.getProductId();
0325: this .itemType = item.getItemType();
0326: this .itemComment = item.getItemComment();
0327: this .productCategoryId = item.getProductCategoryId();
0328: this .quantity = item.getQuantity();
0329: this .selectedAmount = item.getSelectedAmount();
0330: this .basePrice = item.getBasePrice();
0331: this .listPrice = item.getListPrice();
0332: this .isPromo = item.getIsPromo();
0333: this .promoQuantityUsed = item.promoQuantityUsed;
0334: this .locale = item.locale;
0335: this .quantityUsedPerPromoCandidate = new HashMap(
0336: item.quantityUsedPerPromoCandidate);
0337: this .quantityUsedPerPromoFailed = new HashMap(
0338: item.quantityUsedPerPromoFailed);
0339: this .quantityUsedPerPromoActual = new HashMap(
0340: item.quantityUsedPerPromoActual);
0341: this .orderItemSeqId = item.getOrderItemSeqId();
0342: this .orderShipmentPreference = new GenericValue(item
0343: .getOrderShipmentPreference());
0344: this .additionalProductFeatureAndAppls = item
0345: .getAdditionalProductFeatureAndAppls() == null ? null
0346: : new HashMap(item
0347: .getAdditionalProductFeatureAndAppls());
0348: this .attributes = item.getAttributes() == null ? null
0349: : new HashMap(item.getAttributes());
0350: this .contactMechIdsMap = item.getOrderItemContactMechIds() == null ? null
0351: : new HashMap(item.getOrderItemContactMechIds());
0352: this .orderItemPriceInfos = item.getOrderItemPriceInfos() == null ? null
0353: : new LinkedList(item.getOrderItemPriceInfos());
0354: this .itemAdjustments = item.getAdjustments() == null ? null
0355: : new LinkedList(item.getAdjustments());
0356: if (this ._product == null) {
0357: this .itemDescription = item.getName();
0358: }
0359: }
0360:
0361: /** Cannot create shopping cart item with no parameters */
0362: protected ShoppingCartItem() {
0363: }
0364:
0365: /** Creates new ShoppingCartItem object. */
0366: protected ShoppingCartItem(GenericValue product,
0367: Map additionalProductFeatureAndAppls, Map attributes,
0368: String prodCatalogId, Locale locale) {
0369: this ._product = product;
0370: this .productId = _product.getString("productId");
0371: this .itemType = "PRODUCT_ORDER_ITEM";
0372: this .prodCatalogId = prodCatalogId;
0373: this .itemComment = null;
0374: this .attributes = attributes;
0375: this .delegator = _product.getDelegator();
0376: this .delegatorName = _product.getDelegator().getDelegatorName();
0377: this .orderShipmentPreference = delegator.makeValue(
0378: "OrderShipmentPreference", null);
0379: this
0380: .addAllProductFeatureAndAppls(additionalProductFeatureAndAppls);
0381: this .locale = locale;
0382: }
0383:
0384: /** Creates new ShopingCartItem object. */
0385: protected ShoppingCartItem(GenericDelegator delegator,
0386: String itemTypeId, String description, String categoryId,
0387: double basePrice, Map attributes, String prodCatalogId,
0388: Locale locale) {
0389: this .delegator = delegator;
0390: this .itemType = itemTypeId;
0391: this .itemDescription = description;
0392: this .productCategoryId = categoryId;
0393: this .basePrice = basePrice;
0394: this .attributes = attributes;
0395: this .prodCatalogId = prodCatalogId;
0396: this .delegatorName = delegator.getDelegatorName();
0397: this .locale = locale;
0398: }
0399:
0400: public String getProdCatalogId() {
0401: return this .prodCatalogId;
0402: }
0403:
0404: /** Sets the user selected amount */
0405: public void setSelectedAmount(double selectedAmount) {
0406: this .selectedAmount = selectedAmount;
0407: }
0408:
0409: /** Returns the user selected amount */
0410: public double getSelectedAmount() {
0411: return this .selectedAmount;
0412: }
0413:
0414: /** Sets the base price for the item; use with caution */
0415: public void setBasePrice(double basePrice) {
0416: this .basePrice = basePrice;
0417: }
0418:
0419: /** Sets the quantity for the item and validates the change in quantity, etc */
0420: public void setQuantity(double quantity,
0421: LocalDispatcher dispatcher, ShoppingCart cart)
0422: throws CartItemModifyException {
0423: setQuantity(quantity, dispatcher, cart, true);
0424: }
0425:
0426: /** Sets the quantity for the item and validates the change in quantity, etc */
0427: public void setQuantity(double quantity,
0428: LocalDispatcher dispatcher, ShoppingCart cart,
0429: boolean doPromotions) throws CartItemModifyException {
0430: if (this .quantity == quantity) {
0431: return;
0432: }
0433:
0434: if (this .isPromo) {
0435: throw new CartItemModifyException(
0436: "Sorry, you can't change the quantity on the promotion item "
0437: + this .getName() + " (product ID: "
0438: + productId + "), not setting quantity.");
0439: }
0440:
0441: // check inventory if new quantity is greater than old quantity; don't worry about inventory getting pulled out from under, that will be handled at checkout time
0442: if (_product != null && quantity > this .quantity) {
0443: String productStoreId = cart.getProductStoreId();
0444:
0445: if (org.ofbiz.product.store.ProductStoreWorker
0446: .isStoreInventoryRequired(productStoreId, this
0447: .getProduct(), this .getDelegator())) {
0448: if (!org.ofbiz.product.store.ProductStoreWorker
0449: .isStoreInventoryAvailable(productStoreId,
0450: productId, quantity, this
0451: .getDelegator(), dispatcher)) {
0452: String excMsg = "Sorry, we do not have enough (you tried "
0453: + UtilFormatOut.formatQuantity(quantity)
0454: + ") of the product "
0455: + this .getName()
0456: + " (product ID: "
0457: + productId
0458: + ") in stock, not adding to cart. Please try a lower quantity, try again later, or call customer service for more information.";
0459:
0460: Debug.logWarning(excMsg, module);
0461: throw new CartItemModifyException(excMsg);
0462: }
0463: }
0464: }
0465:
0466: // set quantity before promos so order total, etc will be updated
0467: this .quantity = quantity;
0468: this .updatePrice(dispatcher, cart);
0469:
0470: // apply/unapply promotions - only for sales orders
0471: if (doPromotions && cart.getOrderType().equals("SALES_ORDER")) {
0472: org.ofbiz.order.shoppingcart.product.ProductPromoWorker
0473: .doPromotions(cart, dispatcher);
0474: }
0475: }
0476:
0477: public void updatePrice(LocalDispatcher dispatcher,
0478: ShoppingCart cart) throws CartItemModifyException {
0479: // set basePrice using the calculateProductPrice service
0480: if (_product != null) {
0481: try {
0482: Map priceContext = new HashMap();
0483:
0484: priceContext.put("currencyUomId", cart.getCurrency());
0485: priceContext.put("product", this .getProduct());
0486: priceContext.put("prodCatalogId", this
0487: .getProdCatalogId());
0488: priceContext.put("webSiteId", cart.getWebSiteId());
0489:
0490: String partyId = cart.getPartyId();
0491: if (partyId != null) {
0492: priceContext.put("partyId", partyId);
0493: }
0494:
0495: priceContext.put("quantity", new Double(this
0496: .getQuantity()));
0497: Map priceResult = dispatcher.runSync(
0498: "calculateProductPrice", priceContext);
0499:
0500: if (ModelService.RESPOND_ERROR.equals(priceResult
0501: .get(ModelService.RESPONSE_MESSAGE))) {
0502: throw new CartItemModifyException(
0503: "There was an error while calculating the price: "
0504: + priceResult
0505: .get(ModelService.ERROR_MESSAGE));
0506: }
0507:
0508: if (priceResult.get("listPrice") != null)
0509: this .listPrice = ((Double) priceResult
0510: .get("listPrice")).doubleValue();
0511: if (cart.getOrderType().equals("PURCHASE_ORDER")) {
0512: if (priceResult.get("averageCost") != null)
0513: this .basePrice = ((Double) priceResult
0514: .get("averageCost")).doubleValue();
0515: } else {
0516: if (priceResult.get("price") != null)
0517: this .basePrice = ((Double) priceResult
0518: .get("price")).doubleValue();
0519: }
0520:
0521: this .orderItemPriceInfos = (List) priceResult
0522: .get("orderItemPriceInfos");
0523: } catch (GenericServiceException e) {
0524: throw new CartItemModifyException(
0525: "There was an error while calculating the price",
0526: e);
0527: }
0528: }
0529: }
0530:
0531: /** Returns the quantity. */
0532: public double getQuantity() {
0533: return this .quantity;
0534: }
0535:
0536: public double getPromoQuantityUsed() {
0537: if (this .getIsPromo()) {
0538: return this .quantity;
0539: } else {
0540: return this .promoQuantityUsed;
0541: }
0542: }
0543:
0544: public double getPromoQuantityAvailable() {
0545: if (this .getIsPromo()) {
0546: return 0;
0547: } else {
0548: return this .quantity - this .promoQuantityUsed;
0549: }
0550: }
0551:
0552: public Iterator getQuantityUsedPerPromoActualIter() {
0553: return this .quantityUsedPerPromoActual.entrySet().iterator();
0554: }
0555:
0556: public Iterator getQuantityUsedPerPromoCandidateIter() {
0557: return this .quantityUsedPerPromoCandidate.entrySet().iterator();
0558: }
0559:
0560: public Iterator getQuantityUsedPerPromoFailedIter() {
0561: return this .quantityUsedPerPromoFailed.entrySet().iterator();
0562: }
0563:
0564: public synchronized double addPromoQuantityCandidateUse(
0565: double quantityDesired,
0566: GenericValue productPromoCondAction,
0567: boolean checkAvailableOnly) {
0568: if (quantityDesired == 0)
0569: return 0;
0570: double promoQuantityAvailable = this
0571: .getPromoQuantityAvailable();
0572: double promoQuantityToUse = quantityDesired;
0573: if (promoQuantityAvailable > 0) {
0574: if (promoQuantityToUse > promoQuantityAvailable) {
0575: promoQuantityToUse = promoQuantityAvailable;
0576: }
0577:
0578: if (!checkAvailableOnly) {
0579: // keep track of candidate promo uses on cartItem
0580: GenericPK productPromoCondActionPK = productPromoCondAction
0581: .getPrimaryKey();
0582: Double existingValue = (Double) this .quantityUsedPerPromoCandidate
0583: .get(productPromoCondActionPK);
0584: if (existingValue == null) {
0585: this .quantityUsedPerPromoCandidate.put(
0586: productPromoCondActionPK, new Double(
0587: promoQuantityToUse));
0588: } else {
0589: this .quantityUsedPerPromoCandidate.put(
0590: productPromoCondActionPK, new Double(
0591: promoQuantityToUse
0592: + existingValue
0593: .doubleValue()));
0594: }
0595:
0596: this .promoQuantityUsed += promoQuantityToUse;
0597: //Debug.logInfo("promoQuantityToUse=" + promoQuantityToUse + ", quantityDesired=" + quantityDesired + ", for promoCondAction: " + productPromoCondAction, module);
0598: //Debug.logInfo("promoQuantityUsed now=" + promoQuantityUsed, module);
0599: }
0600:
0601: return promoQuantityToUse;
0602: } else {
0603: return 0;
0604: }
0605: }
0606:
0607: public double getPromoQuantityCandidateUse(
0608: GenericValue productPromoCondAction) {
0609: GenericPK productPromoCondActionPK = productPromoCondAction
0610: .getPrimaryKey();
0611: Double existingValue = (Double) this .quantityUsedPerPromoCandidate
0612: .get(productPromoCondActionPK);
0613: if (existingValue == null) {
0614: return 0;
0615: } else {
0616: return existingValue.doubleValue();
0617: }
0618: }
0619:
0620: public double getPromoQuantityCandidateUseActionAndAllConds(
0621: GenericValue productPromoAction) {
0622: double totalUse = 0;
0623: String productPromoId = productPromoAction
0624: .getString("productPromoId");
0625: String productPromoRuleId = productPromoAction
0626: .getString("productPromoRuleId");
0627:
0628: GenericPK productPromoActionPK = productPromoAction
0629: .getPrimaryKey();
0630: Double existingValue = (Double) this .quantityUsedPerPromoCandidate
0631: .get(productPromoActionPK);
0632: if (existingValue != null) {
0633: totalUse = existingValue.doubleValue();
0634: }
0635:
0636: Iterator entryIter = this .quantityUsedPerPromoCandidate
0637: .entrySet().iterator();
0638: while (entryIter.hasNext()) {
0639: Map.Entry entry = (Map.Entry) entryIter.next();
0640: GenericPK productPromoCondActionPK = (GenericPK) entry
0641: .getKey();
0642: Double quantityUsed = (Double) entry.getValue();
0643: if (quantityUsed != null) {
0644: // must be in the same rule and be a condition
0645: if (productPromoId.equals(productPromoCondActionPK
0646: .getString("productPromoId"))
0647: && productPromoRuleId
0648: .equals(productPromoCondActionPK
0649: .getString("productPromoRuleId"))
0650: && productPromoCondActionPK
0651: .containsKey("productPromoCondSeqId")) {
0652: totalUse += quantityUsed.doubleValue();
0653: }
0654: }
0655: }
0656:
0657: return totalUse;
0658: }
0659:
0660: public synchronized void resetPromoRuleUse(String productPromoId,
0661: String productPromoRuleId) {
0662: Iterator entryIter = this .quantityUsedPerPromoCandidate
0663: .entrySet().iterator();
0664: while (entryIter.hasNext()) {
0665: Map.Entry entry = (Map.Entry) entryIter.next();
0666: GenericPK productPromoCondActionPK = (GenericPK) entry
0667: .getKey();
0668: Double quantityUsed = (Double) entry.getValue();
0669: if (productPromoId.equals(productPromoCondActionPK
0670: .getString("productPromoId"))
0671: && productPromoRuleId
0672: .equals(productPromoCondActionPK
0673: .getString("productPromoRuleId"))) {
0674: entryIter.remove();
0675: Double existingValue = (Double) this .quantityUsedPerPromoFailed
0676: .get(productPromoCondActionPK);
0677: if (existingValue == null) {
0678: this .quantityUsedPerPromoFailed.put(
0679: productPromoCondActionPK, quantityUsed);
0680: } else {
0681: this .quantityUsedPerPromoFailed.put(
0682: productPromoCondActionPK, new Double(
0683: quantityUsed.doubleValue()
0684: + existingValue
0685: .doubleValue()));
0686: }
0687: this .promoQuantityUsed -= quantityUsed.doubleValue();
0688: }
0689: }
0690: }
0691:
0692: public synchronized void confirmPromoRuleUse(String productPromoId,
0693: String productPromoRuleId) {
0694: Iterator entryIter = this .quantityUsedPerPromoCandidate
0695: .entrySet().iterator();
0696: while (entryIter.hasNext()) {
0697: Map.Entry entry = (Map.Entry) entryIter.next();
0698: GenericPK productPromoCondActionPK = (GenericPK) entry
0699: .getKey();
0700: Double quantityUsed = (Double) entry.getValue();
0701: if (productPromoId.equals(productPromoCondActionPK
0702: .getString("productPromoId"))
0703: && productPromoRuleId
0704: .equals(productPromoCondActionPK
0705: .getString("productPromoRuleId"))) {
0706: entryIter.remove();
0707: Double existingValue = (Double) this .quantityUsedPerPromoActual
0708: .get(productPromoCondActionPK);
0709: if (existingValue == null) {
0710: this .quantityUsedPerPromoActual.put(
0711: productPromoCondActionPK, quantityUsed);
0712: } else {
0713: this .quantityUsedPerPromoActual.put(
0714: productPromoCondActionPK, new Double(
0715: quantityUsed.doubleValue()
0716: + existingValue
0717: .doubleValue()));
0718: }
0719: }
0720: }
0721: }
0722:
0723: public synchronized void clearPromoRuleUseInfo() {
0724: this .quantityUsedPerPromoActual.clear();
0725: this .quantityUsedPerPromoCandidate.clear();
0726: this .quantityUsedPerPromoFailed.clear();
0727: this .promoQuantityUsed = this .getIsPromo() ? this .quantity : 0;
0728: }
0729:
0730: /** Sets the item comment. */
0731: public void setItemComment(String itemComment) {
0732: this .itemComment = itemComment;
0733: }
0734:
0735: /** Returns the item's comment. */
0736: public String getItemComment() {
0737: return itemComment;
0738: }
0739:
0740: /** Sets the item type. */
0741: public void setItemType(String itemType) {
0742: this .itemType = itemType;
0743: }
0744:
0745: /** Returns the item type. */
0746: public String getItemType() {
0747: return itemType;
0748: }
0749:
0750: /** Returns the item type description. */
0751: public String getItemTypeDescription() {
0752: GenericValue orderItemType = null;
0753: try {
0754: orderItemType = this .getDelegator().findByPrimaryKeyCache(
0755: "OrderItemType",
0756: UtilMisc.toMap("orderItemTypeId", this
0757: .getItemType()));
0758: } catch (GenericEntityException e) {
0759: Debug.logWarning(e, "Problems getting OrderItemType for: "
0760: + this .getItemType(), module);
0761: }
0762: if (itemType != null) {
0763: return orderItemType.getString("description");
0764: }
0765: return null;
0766: }
0767:
0768: /** Returns the productCategoryId for the item or null if none. */
0769: public String getProductCategoryId() {
0770: return this .productCategoryId;
0771: }
0772:
0773: public void setOrderItemSeqId(String orderItemSeqId) {
0774: this .orderItemSeqId = orderItemSeqId;
0775: }
0776:
0777: public String getOrderItemSeqId() {
0778: return orderItemSeqId;
0779: }
0780:
0781: public void setShoppingList(String shoppingListId, String itemSeqId) {
0782: attributes.put("shoppingListId", shoppingListId);
0783: attributes.put("shoppingListItemSeqId", itemSeqId);
0784: }
0785:
0786: public String getShoppingListId() {
0787: if (attributes != null
0788: && attributes.containsKey("shoppingListId"))
0789: return (String) attributes.get("shoppingListId");
0790: return null;
0791: }
0792:
0793: public String getShoppingListItemSeqId() {
0794: if (attributes != null
0795: && attributes.containsKey("shoppingListItemSeqId"))
0796: return (String) attributes.get("shoppingListItemSeqId");
0797: return null;
0798: }
0799:
0800: /** Returns true if shipping charges apply to this item. */
0801: public boolean shippingApplies() {
0802: GenericValue product = getProduct();
0803: if (product != null) {
0804: return ProductWorker.shippingApplies(product);
0805: } else {
0806: // we don't ship non-product items
0807: return false;
0808: }
0809: }
0810:
0811: /** Returns true if tax charges apply to this item. */
0812: public boolean taxApplies() {
0813: GenericValue product = getProduct();
0814: if (product != null) {
0815: return ProductWorker.taxApplies(product);
0816: } else {
0817: // we do tax non-product items
0818: return true;
0819: }
0820: }
0821:
0822: /** Returns the item's productId. */
0823: public String getProductId() {
0824: return productId;
0825: }
0826:
0827: /** Returns the item's description. */
0828: public String getName() {
0829: GenericValue product = getProduct();
0830:
0831: if (product != null) {
0832: String productName = ProductContentWrapper
0833: .getProductContentAsText(product, "PRODUCT_NAME",
0834: this .locale);
0835:
0836: // if the productName is null or empty, see if there is an associated virtual product and get the productName of that product
0837: if (UtilValidate.isEmpty(productName)) {
0838: GenericValue parentProduct = this .getParentProduct();
0839: if (parentProduct != null) {
0840: productName = ProductContentWrapper
0841: .getProductContentAsText(parentProduct,
0842: "PRODUCT_NAME", this .locale);
0843: }
0844: }
0845:
0846: if (productName == null) {
0847: return "";
0848: } else {
0849: return productName;
0850: }
0851: } else {
0852: return itemDescription;
0853: }
0854: }
0855:
0856: /** Returns the item's description. */
0857: public String getDescription() {
0858: GenericValue product = getProduct();
0859:
0860: if (product != null) {
0861: String description = ProductContentWrapper
0862: .getProductContentAsText(product, "DESCRIPTION",
0863: this .locale);
0864:
0865: // if the description is null or empty, see if there is an associated virtual product and get the description of that product
0866: if (UtilValidate.isEmpty(description)) {
0867: GenericValue parentProduct = this .getParentProduct();
0868: if (parentProduct != null) {
0869: description = ProductContentWrapper
0870: .getProductContentAsText(parentProduct,
0871: "DESCRIPTION", this .locale);
0872: }
0873: }
0874:
0875: if (description == null) {
0876: return "";
0877: } else {
0878: return description;
0879: }
0880: } else {
0881: return null;
0882: }
0883: }
0884:
0885: /** Returns the item's unit weight */
0886: public double getWeight() {
0887: GenericValue product = getProduct();
0888: if (product != null) {
0889: Double weight = product.getDouble("weight");
0890:
0891: // if the weight is null, see if there is an associated virtual product and get the weight of that product
0892: if (weight == null) {
0893: GenericValue parentProduct = this .getParentProduct();
0894: if (parentProduct != null)
0895: weight = parentProduct.getDouble("weight");
0896: }
0897:
0898: if (weight == null) {
0899: return 0;
0900: } else {
0901: return weight.doubleValue();
0902: }
0903: } else {
0904: // non-product items have 0 weight
0905: return 0;
0906: }
0907: }
0908:
0909: /** Returns the item's size (height * width * depth) */
0910: public double getSize() {
0911: GenericValue product = getProduct();
0912: if (product != null) {
0913: Double height = product.getDouble("productHeight");
0914: Double width = product.getDouble("productWidth");
0915: Double depth = product.getDouble("productDepth");
0916:
0917: // if all are null, see if there is an associated virtual product and get the info of that product
0918: if (height == null & width == null && depth == null) {
0919: GenericValue parentProduct = this .getParentProduct();
0920: if (parentProduct != null) {
0921: height = parentProduct.getDouble("productHeight");
0922: width = product.getDouble("productWidth");
0923: depth = product.getDouble("productDepth");
0924: }
0925: }
0926:
0927: if (height == null)
0928: height = new Double(0);
0929: if (width == null)
0930: width = new Double(0);
0931: if (depth == null)
0932: depth = new Double(0);
0933:
0934: double size = height.doubleValue() * width.doubleValue()
0935: * depth.doubleValue();
0936: return size;
0937: } else {
0938: // non-product items have 0 size
0939: return 0;
0940: }
0941: }
0942:
0943: /** Returns the base price. */
0944: public double getBasePrice() {
0945: if (selectedAmount > 0) {
0946: return basePrice * selectedAmount;
0947: } else {
0948: return basePrice;
0949: }
0950: }
0951:
0952: /** Returns the list price. */
0953: public double getListPrice() {
0954: return listPrice;
0955: }
0956:
0957: /** Returns the "other" adjustments. */
0958: public double getOtherAdjustments() {
0959: return OrderReadHelper.calcItemAdjustments(
0960: new Double(quantity), new Double(getBasePrice()), this
0961: .getAdjustments(), true, false, false, false,
0962: false);
0963: }
0964:
0965: /** Returns the total line price. */
0966: public double getItemSubTotal() {
0967: return (getBasePrice() * quantity) + getOtherAdjustments();
0968: }
0969:
0970: /** Returns the total line price for tax calculation purposes. */
0971: public double getItemSubTotalForTax() {
0972: return (getBasePrice() * quantity)
0973: + OrderReadHelper.calcItemAdjustments(new Double(
0974: quantity), new Double(getBasePrice()), this
0975: .getAdjustments(), true, false, false, true,
0976: false);
0977: }
0978:
0979: /** Returns the total line price for shipping calculation purposes. */
0980: public double getItemSubTotalForShipping() {
0981: return (getBasePrice() * quantity)
0982: + OrderReadHelper.calcItemAdjustments(new Double(
0983: quantity), new Double(getBasePrice()), this
0984: .getAdjustments(), true, false, false, false,
0985: true);
0986: }
0987:
0988: /** Returns the tax adjustments. */
0989: public double getItemTax() {
0990: return OrderReadHelper.calcItemAdjustments(
0991: new Double(quantity), new Double(getBasePrice()), this
0992: .getAdjustments(), false, true, false, false,
0993: false);
0994: }
0995:
0996: /** Returns the shipping adjustments. */
0997: public double getItemShipping() {
0998: return OrderReadHelper.calcItemAdjustments(
0999: new Double(quantity), new Double(getBasePrice()), this
1000: .getAdjustments(), false, false, true, false,
1001: false);
1002: }
1003:
1004: public void addAllProductFeatureAndAppls(
1005: Map productFeatureAndApplsToAdd) {
1006: if (productFeatureAndApplsToAdd == null)
1007: return;
1008: Iterator productFeatureAndApplsToAddIter = productFeatureAndApplsToAdd
1009: .values().iterator();
1010:
1011: while (productFeatureAndApplsToAddIter.hasNext()) {
1012: GenericValue additionalProductFeatureAndAppl = (GenericValue) productFeatureAndApplsToAddIter
1013: .next();
1014:
1015: this
1016: .putAdditionalProductFeatureAndAppl(additionalProductFeatureAndAppl);
1017: }
1018: }
1019:
1020: public void putAdditionalProductFeatureAndAppl(
1021: GenericValue additionalProductFeatureAndAppl) {
1022: if (additionalProductFeatureAndAppl == null)
1023: return;
1024:
1025: // if one already exists with the given type, remove it with the corresponding adjustment
1026: removeAdditionalProductFeatureAndAppl(additionalProductFeatureAndAppl
1027: .getString("productFeatureTypeId"));
1028:
1029: // adds to additional map and creates an adjustment with given price
1030: String featureType = additionalProductFeatureAndAppl
1031: .getString("productFeatureTypeId");
1032: this .additionalProductFeatureAndAppls.put(featureType,
1033: additionalProductFeatureAndAppl);
1034:
1035: GenericValue orderAdjustment = this .getDelegator().makeValue(
1036: "OrderAdjustment", null);
1037: orderAdjustment.set("orderAdjustmentTypeId",
1038: "ADDITIONAL_FEATURE");
1039: orderAdjustment.set("description",
1040: additionalProductFeatureAndAppl.get("description"));
1041: orderAdjustment
1042: .set("productFeatureId",
1043: additionalProductFeatureAndAppl
1044: .get("productFeatureId"));
1045: // NOTE: this is a VERY simple pricing scheme for additional features and will likely need to be extended for most real applications
1046: orderAdjustment.set("amountPerQuantity",
1047: additionalProductFeatureAndAppl.get("amount"));
1048:
1049: this .addAdjustment(orderAdjustment);
1050: }
1051:
1052: public GenericValue getAdditionalProductFeatureAndAppl(
1053: String productFeatureTypeId) {
1054: if (this .additionalProductFeatureAndAppls == null)
1055: return null;
1056: return (GenericValue) this .additionalProductFeatureAndAppls
1057: .get(productFeatureTypeId);
1058: }
1059:
1060: public GenericValue removeAdditionalProductFeatureAndAppl(
1061: String productFeatureTypeId) {
1062: if (this .additionalProductFeatureAndAppls == null)
1063: return null;
1064:
1065: GenericValue oldAdditionalProductFeatureAndAppl = (GenericValue) this .additionalProductFeatureAndAppls
1066: .remove(productFeatureTypeId);
1067:
1068: if (oldAdditionalProductFeatureAndAppl != null) {
1069: removeFeatureAdjustment(oldAdditionalProductFeatureAndAppl
1070: .getString("productFeatureId"));
1071: }
1072:
1073: //if (this.additionalProductFeatureAndAppls.size() == 0) this.additionalProductFeatureAndAppls = null;
1074:
1075: return oldAdditionalProductFeatureAndAppl;
1076: }
1077:
1078: public Map getAdditionalProductFeatureAndAppls() {
1079: return this .additionalProductFeatureAndAppls;
1080: }
1081:
1082: public Map getFeatureIdQtyMap() {
1083: Map featureMap = new HashMap();
1084: GenericValue product = this .getProduct();
1085: if (product != null) {
1086: List featureAppls = null;
1087: try {
1088: featureAppls = product.getRelated("ProductFeatureAppl");
1089: List filterExprs = UtilMisc.toList(new EntityExpr(
1090: "productFeatureApplTypeId",
1091: EntityOperator.EQUALS, "STANDARD_FEATURE"));
1092: filterExprs.add(new EntityExpr(
1093: "productFeatureApplTypeId",
1094: EntityOperator.EQUALS, "REQUIRED_FEATURE"));
1095: featureAppls = EntityUtil.filterByOr(featureAppls,
1096: filterExprs);
1097: } catch (GenericEntityException e) {
1098: Debug.logError(e,
1099: "Unable to get features from product : "
1100: + product.get("productId"), module);
1101: }
1102: if (featureAppls != null) {
1103: Iterator fai = featureAppls.iterator();
1104: while (fai.hasNext()) {
1105: GenericValue appl = (GenericValue) fai.next();
1106: Double lastQuantity = (Double) featureMap.get(appl
1107: .getString("productFeatureId"));
1108: if (lastQuantity == null) {
1109: lastQuantity = new Double(0);
1110: }
1111: Double newQuantity = new Double(lastQuantity
1112: .doubleValue()
1113: + this .getQuantity());
1114: featureMap.put(appl.getString("productFeatureId"),
1115: newQuantity);
1116: }
1117: }
1118: }
1119: if (this .additionalProductFeatureAndAppls != null) {
1120: Iterator aapi = this .additionalProductFeatureAndAppls
1121: .values().iterator();
1122: while (aapi.hasNext()) {
1123: GenericValue appl = (GenericValue) aapi.next();
1124: Double lastQuantity = (Double) featureMap.get(appl
1125: .getString("productFeatureId"));
1126: if (lastQuantity == null) {
1127: lastQuantity = new Double(0);
1128: }
1129: Double newQuantity = new Double(lastQuantity
1130: .doubleValue()
1131: + this .getQuantity());
1132: featureMap.put(appl.getString("productFeatureId"),
1133: newQuantity);
1134: }
1135: }
1136: return featureMap;
1137: }
1138:
1139: /** Removes an item attribute. */
1140: public void removeAttribute(String name) {
1141: if (attributes == null)
1142: attributes = new HashMap();
1143: if (attributes.containsKey(name))
1144: attributes.remove(name);
1145: }
1146:
1147: /** Sets an item attribute. */
1148: public void setAttribute(String name, Object value) {
1149: if (attributes == null)
1150: attributes = new HashMap();
1151: attributes.put(name, value);
1152: }
1153:
1154: /** Return a specific attribute. */
1155: public Object getAttribute(String name) {
1156: if (attributes == null)
1157: return null;
1158: return attributes.get(name);
1159: }
1160:
1161: /** Returns the attributes for the item. */
1162: public Map getAttributes() {
1163: return attributes;
1164: }
1165:
1166: /** Add an adjustment to the order item; don't worry about setting the orderId, orderItemSeqId or orderAdjustmentId; they will be set when the order is created */
1167: public void addAdjustment(GenericValue adjustment) {
1168: itemAdjustments.add(adjustment);
1169: }
1170:
1171: public void removeAdjustment(GenericValue adjustment) {
1172: itemAdjustments.remove(adjustment);
1173: }
1174:
1175: public void removeAdjustment(int index) {
1176: itemAdjustments.remove(index);
1177: }
1178:
1179: public List getAdjustments() {
1180: return itemAdjustments;
1181: }
1182:
1183: public void removeFeatureAdjustment(String productFeatureId) {
1184: if (productFeatureId == null)
1185: return;
1186: Iterator itemAdjustmentsIter = itemAdjustments.iterator();
1187:
1188: while (itemAdjustmentsIter.hasNext()) {
1189: GenericValue itemAdjustment = (GenericValue) itemAdjustmentsIter
1190: .next();
1191:
1192: if (productFeatureId.equals(itemAdjustment
1193: .getString("productFeatureId"))) {
1194: itemAdjustmentsIter.remove();
1195: }
1196: }
1197: }
1198:
1199: public List getOrderItemPriceInfos() {
1200: return orderItemPriceInfos;
1201: }
1202:
1203: /** Add a contact mech to this purpose; the contactMechPurposeTypeId is required */
1204: public void addContactMech(String contactMechPurposeTypeId,
1205: String contactMechId) {
1206: if (contactMechPurposeTypeId == null)
1207: throw new IllegalArgumentException(
1208: "You must specify a contactMechPurposeTypeId to add a ContactMech");
1209: contactMechIdsMap.put(contactMechPurposeTypeId, contactMechId);
1210: }
1211:
1212: /** Get the contactMechId for this item given the contactMechPurposeTypeId */
1213: public String getContactMech(String contactMechPurposeTypeId) {
1214: return (String) contactMechIdsMap.get(contactMechPurposeTypeId);
1215: }
1216:
1217: /** Remove the contactMechId from this item given the contactMechPurposeTypeId */
1218: public String removeContactMech(String contactMechPurposeTypeId) {
1219: return (String) contactMechIdsMap
1220: .remove(contactMechPurposeTypeId);
1221: }
1222:
1223: public Map getOrderItemContactMechIds() {
1224: return contactMechIdsMap;
1225: }
1226:
1227: public void setIsPromo(boolean isPromo) {
1228: this .isPromo = isPromo;
1229: }
1230:
1231: public boolean getIsPromo() {
1232: return this .isPromo;
1233: }
1234:
1235: public GenericValue getOrderShipmentPreference() {
1236: return orderShipmentPreference;
1237: }
1238:
1239: /** Sets the shipment method type. */
1240: public void setShipmentMethodTypeId(String shipmentMethodTypeId) {
1241: orderShipmentPreference.set("shipmentMethodTypeId",
1242: shipmentMethodTypeId);
1243: }
1244:
1245: /** Returns the shipment method type */
1246: public String getShipmentMethodTypeId() {
1247: return orderShipmentPreference
1248: .getString("shipmentMethodTypeId");
1249: }
1250:
1251: /** Sets the shipping instructions. */
1252: public void setShippingInstructions(String shippingInstructions) {
1253: orderShipmentPreference.set("shippingInstructions",
1254: shippingInstructions);
1255: }
1256:
1257: /** Returns the shipping instructions. */
1258: public String getShippingInstructions() {
1259: return orderShipmentPreference
1260: .getString("shippingInstructions");
1261: }
1262:
1263: public void setMaySplit(Boolean maySplit) {
1264: orderShipmentPreference.set("maySplit", maySplit);
1265: }
1266:
1267: /** Returns Boolean.TRUE if the order may be split (null if unspecified) */
1268: public Boolean getMaySplit() {
1269: return orderShipmentPreference.getBoolean("maySplit");
1270: }
1271:
1272: public void setGiftMessage(String giftMessage) {
1273: orderShipmentPreference.set("giftMessage", giftMessage);
1274: }
1275:
1276: public String getGiftMessage() {
1277: return orderShipmentPreference.getString("giftMessage");
1278: }
1279:
1280: public void setIsGift(Boolean isGift) {
1281: orderShipmentPreference.set("isGift", isGift);
1282: }
1283:
1284: public Boolean getIsGift() {
1285: return orderShipmentPreference.getBoolean("isGift");
1286: }
1287:
1288: public void setCarrierPartyId(String carrierPartyId) {
1289: orderShipmentPreference.set("carrierPartyId", carrierPartyId);
1290: }
1291:
1292: public String getCarrierPartyId() {
1293: return orderShipmentPreference.getString("carrierPartyId");
1294: }
1295:
1296: /** Compares the specified object with this cart item. */
1297: public boolean equals(ShoppingCartItem item) {
1298: if (item == null)
1299: return false;
1300: return this .equals(item.getProductId(),
1301: item.additionalProductFeatureAndAppls, item.attributes,
1302: item.prodCatalogId, item.selectedAmount, item
1303: .getIsPromo());
1304: }
1305:
1306: /** Compares the specified object with this cart item. Defaults isPromo to false. */
1307: public boolean equals(String productId,
1308: Map additionalProductFeatureAndAppls, Map attributes,
1309: String prodCatalogId, double selectedAmount) {
1310: return equals(productId, additionalProductFeatureAndAppls,
1311: attributes, prodCatalogId, selectedAmount, false);
1312: }
1313:
1314: /** Compares the specified object with this cart item. */
1315: public boolean equals(String productId,
1316: Map additionalProductFeatureAndAppls, Map attributes,
1317: String prodCatalogId, double selectedAmount, boolean isPromo) {
1318: if (this .productId == null || productId == null) {
1319: // all non-product items are unique
1320: return false;
1321: }
1322: if (!this .productId.equals(productId)) {
1323: return false;
1324: }
1325:
1326: if ((this .prodCatalogId == null && prodCatalogId != null)
1327: || (this .prodCatalogId != null && prodCatalogId == null)) {
1328: return false;
1329: }
1330: if (this .prodCatalogId != null && prodCatalogId != null
1331: && !this .prodCatalogId.equals(prodCatalogId)) {
1332: return false;
1333: }
1334:
1335: if (this .getSelectedAmount() != selectedAmount) {
1336: return false;
1337: }
1338:
1339: if (this .isPromo != isPromo) {
1340: return false;
1341: }
1342:
1343: if ((this .additionalProductFeatureAndAppls != null && additionalProductFeatureAndAppls != null)
1344: && (this .additionalProductFeatureAndAppls.size() != additionalProductFeatureAndAppls
1345: .size())
1346: && !(this .additionalProductFeatureAndAppls
1347: .equals(additionalProductFeatureAndAppls))) {
1348: return false;
1349: }
1350:
1351: if ((this .attributes != null && attributes != null)
1352: && (this .attributes.size() != attributes.size())
1353: && !(this .attributes.equals(attributes))) {
1354: return false;
1355: }
1356:
1357: return true;
1358: }
1359:
1360: /** Gets the Product entity. If it is not already retreived gets it from the delegator */
1361: public GenericValue getProduct() {
1362: if (this ._product != null) {
1363: return this ._product;
1364: }
1365: if (this .productId != null) {
1366: try {
1367: this ._product = this .getDelegator()
1368: .findByPrimaryKeyCache("Product",
1369: UtilMisc.toMap("productId", productId));
1370: } catch (GenericEntityException e) {
1371: throw new RuntimeException(
1372: "Entity Engine error getting Product ("
1373: + e.getMessage() + ")");
1374: }
1375: }
1376: return this ._product;
1377: }
1378:
1379: public GenericValue getParentProduct() {
1380: if (this ._parentProduct != null) {
1381: return this ._parentProduct;
1382: }
1383: if (this .productId == null) {
1384: throw new IllegalStateException("Bad product id");
1385: }
1386:
1387: try {
1388: List virtualProductAssocs = this .getDelegator()
1389: .findByAndCache(
1390: "ProductAssoc",
1391: UtilMisc.toMap("productIdTo", productId,
1392: "productAssocTypeId",
1393: "PRODUCT_VARIANT"),
1394: UtilMisc.toList("-fromDate"));
1395: virtualProductAssocs = EntityUtil.filterByDate(
1396: virtualProductAssocs, true);
1397: if (virtualProductAssocs == null
1398: || virtualProductAssocs.size() == 0) {
1399: //okay, not a variant, try a UNIQUE_ITEM
1400: virtualProductAssocs = this .getDelegator()
1401: .findByAndCache(
1402: "ProductAssoc",
1403: UtilMisc.toMap("productIdTo",
1404: productId,
1405: "productAssocTypeId",
1406: "UNIQUE_ITEM"),
1407: UtilMisc.toList("-fromDate"));
1408: virtualProductAssocs = EntityUtil.filterByDate(
1409: virtualProductAssocs, true);
1410: }
1411: if (virtualProductAssocs != null
1412: && virtualProductAssocs.size() > 0) {
1413: //found one, set this first as the parent product
1414: GenericValue productAssoc = EntityUtil
1415: .getFirst(virtualProductAssocs);
1416: this ._parentProduct = productAssoc
1417: .getRelatedOneCache("MainProduct");
1418: }
1419: } catch (GenericEntityException e) {
1420: throw new RuntimeException(
1421: "Entity Engine error getting Parent Product ("
1422: + e.getMessage() + ")");
1423: }
1424: return this ._parentProduct;
1425: }
1426:
1427: public String getParentProductId() {
1428: GenericValue parentProduct = this .getParentProduct();
1429: if (parentProduct != null) {
1430: return parentProduct.getString("productId");
1431: } else {
1432: return null;
1433: }
1434: }
1435:
1436: public Map getOptionalProductFeatures() {
1437: if (_product != null) {
1438: return ProductWorker.getOptionalProductFeatures(
1439: getDelegator(), this .productId);
1440: } else {
1441: // non-product items do not have features
1442: return new HashMap();
1443: }
1444: }
1445:
1446: public GenericDelegator getDelegator() {
1447: if (delegator == null) {
1448: if (UtilValidate.isEmpty(delegatorName)) {
1449: throw new IllegalStateException("Bad delegator name");
1450: }
1451: delegator = GenericDelegator
1452: .getGenericDelegator(delegatorName);
1453: }
1454: return delegator;
1455: }
1456:
1457: public void explodeItem(ShoppingCart cart,
1458: LocalDispatcher dispatcher) throws CartItemModifyException {
1459: double baseQuantity = this .getQuantity();
1460: int this Index = cart.items().indexOf(this );
1461: List newItems = new ArrayList();
1462:
1463: if (baseQuantity > 1) {
1464: for (int i = 1; i < baseQuantity; i++) {
1465: // clone the item
1466: ShoppingCartItem item = new ShoppingCartItem(this );
1467:
1468: // set the new item's quantity
1469: item.setQuantity(1, dispatcher, cart, false);
1470:
1471: // now copy/calc the adjustments
1472: Debug.logInfo("Clone's adj: " + item.getAdjustments(),
1473: module);
1474: if (item.getAdjustments() != null
1475: && item.getAdjustments().size() > 0) {
1476: List adjustments = new LinkedList(item
1477: .getAdjustments());
1478: Iterator adjIterator = adjustments.iterator();
1479:
1480: while (adjIterator.hasNext()) {
1481: GenericValue adjustment = (GenericValue) adjIterator
1482: .next();
1483:
1484: if (adjustment != null) {
1485: item.removeAdjustment(adjustment);
1486: GenericValue newAdjustment = new GenericValue(
1487: adjustment);
1488: Double adjAmount = newAdjustment
1489: .getDouble("amount");
1490:
1491: // we use != becuase adjustments can be +/-
1492: if (adjAmount != null
1493: && adjAmount.doubleValue() != 0.00)
1494: newAdjustment.set("amount", new Double(
1495: adjAmount.doubleValue()
1496: / baseQuantity));
1497: Debug.logInfo("Cloned adj: "
1498: + newAdjustment, module);
1499: item.addAdjustment(newAdjustment);
1500: } else {
1501: Debug.logInfo("Clone Adjustment is null",
1502: module);
1503: }
1504: }
1505: }
1506: newItems.add(item);
1507: }
1508:
1509: // set this item's quantity
1510: this .setQuantity(1, dispatcher, cart, false);
1511:
1512: Debug.logInfo("BaseQuantity: " + baseQuantity, module);
1513: Debug.logInfo("Item's Adj: " + this .getAdjustments(),
1514: module);
1515:
1516: // re-calc this item's adjustments
1517: if (this .getAdjustments() != null
1518: && this .getAdjustments().size() > 0) {
1519: List adjustments = new LinkedList(this .getAdjustments());
1520: Iterator adjIterator = adjustments.iterator();
1521:
1522: while (adjIterator.hasNext()) {
1523: GenericValue adjustment = (GenericValue) adjIterator
1524: .next();
1525:
1526: if (adjustment != null) {
1527: this .removeAdjustment(adjustment);
1528: GenericValue newAdjustment = new GenericValue(
1529: adjustment);
1530: Double adjAmount = newAdjustment
1531: .getDouble("amount");
1532:
1533: // we use != becuase adjustments can be +/-
1534: if (adjAmount != null
1535: && adjAmount.doubleValue() != 0.00)
1536: newAdjustment.set("amount", new Double(
1537: adjAmount.doubleValue()
1538: / baseQuantity));
1539: Debug.logInfo("Updated adj: " + newAdjustment,
1540: module);
1541: this .addAdjustment(newAdjustment);
1542: }
1543: }
1544: }
1545:
1546: // add the cloned item(s) to the cart
1547: Iterator newItemsItr = newItems.iterator();
1548:
1549: while (newItemsItr.hasNext()) {
1550: cart.addItem(this Index, (ShoppingCartItem) newItemsItr
1551: .next());
1552: }
1553: }
1554: }
1555: }
|