0001: /*******************************************************************************
0002: * Licensed to the Apache Software Foundation (ASF) under one
0003: * or more contributor license agreements. See the NOTICE file
0004: * distributed with this work for additional information
0005: * regarding copyright ownership. The ASF licenses this file
0006: * to you under the Apache License, Version 2.0 (the
0007: * "License"); you may not use this file except in compliance
0008: * with the License. You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing,
0013: * software distributed under the License is distributed on an
0014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015: * KIND, either express or implied. See the License for the
0016: * specific language governing permissions and limitations
0017: * under the License.
0018: *******************************************************************************/package org.ofbiz.order.shoppingcart;
0019:
0020: import java.math.BigDecimal;
0021: import java.sql.Timestamp;
0022: import java.util.ArrayList;
0023: import java.util.Arrays;
0024: import java.util.HashMap;
0025: import java.util.Iterator;
0026: import java.util.LinkedList;
0027: import java.util.List;
0028: import java.util.Locale;
0029: import java.util.Map;
0030: import java.util.Set;
0031:
0032: import javolution.util.FastMap;
0033:
0034: import org.apache.commons.collections.set.ListOrderedSet;
0035: import org.ofbiz.base.util.Debug;
0036: import org.ofbiz.base.util.GeneralException;
0037: import org.ofbiz.base.util.UtilDateTime;
0038: import org.ofbiz.base.util.UtilFormatOut;
0039: import org.ofbiz.base.util.UtilMisc;
0040: import org.ofbiz.base.util.UtilProperties;
0041: import org.ofbiz.base.util.UtilValidate;
0042: import org.ofbiz.entity.GenericDelegator;
0043: import org.ofbiz.entity.GenericEntityException;
0044: import org.ofbiz.entity.GenericPK;
0045: import org.ofbiz.entity.GenericValue;
0046: import org.ofbiz.entity.condition.EntityExpr;
0047: import org.ofbiz.entity.condition.EntityOperator;
0048: import org.ofbiz.entity.util.EntityUtil;
0049: import org.ofbiz.order.order.OrderReadHelper;
0050: import org.ofbiz.order.shoppingcart.product.ProductPromoWorker;
0051: import org.ofbiz.order.shoppinglist.ShoppingListEvents;
0052: import org.ofbiz.product.catalog.CatalogWorker;
0053: import org.ofbiz.product.category.CategoryWorker;
0054: import org.ofbiz.product.config.ProductConfigWrapper;
0055: import org.ofbiz.product.product.ProductContentWrapper;
0056: import org.ofbiz.product.product.ProductWorker;
0057: import org.ofbiz.product.store.ProductStoreWorker;
0058: import org.ofbiz.service.GenericServiceException;
0059: import org.ofbiz.service.LocalDispatcher;
0060: import org.ofbiz.service.ModelService;
0061: import org.ofbiz.service.ServiceUtil;
0062:
0063: /**
0064: * <p><b>Title:</b> ShoppingCartItem.java
0065: * <p><b>Description:</b> Shopping cart item object.
0066: */
0067: public class ShoppingCartItem implements java.io.Serializable {
0068:
0069: public static String module = ShoppingCartItem.class.getName();
0070: public static final String resource = "OrderUiLabels";
0071: public static final String resource_error = "OrderErrorUiLabels";
0072: public static String[] attributeNames = { "shoppingListId",
0073: "shoppingListItemSeqId", "surveyResponses",
0074: "itemDesiredDeliveryDate", "itemComment" };
0075:
0076: private transient GenericDelegator delegator = null;
0077: /** the actual or variant product */
0078: private transient GenericValue _product = null;
0079: /** the virtual product if _product is a variant */
0080: private transient GenericValue _parentProduct = null;
0081:
0082: private String delegatorName = null;
0083: private String prodCatalogId = null;
0084: private String productId = null;
0085: private String parentProductId = null;
0086: private String externalId = null;
0087: /** ends up in orderItemTypeId */
0088: private String itemType = null;
0089: private ShoppingCart.ShoppingCartItemGroup itemGroup = null;
0090: private String productCategoryId = null;
0091: private String itemDescription = null;
0092: /** for reservations: date start*/
0093: private Timestamp reservStart = null;
0094: /** for reservations: length */
0095: private double reservLength = 0;
0096: /** for reservations: number of persons using */
0097: private double reservPersons = 0;
0098: private double quantity = 0.0;
0099: private double basePrice = 0.0;
0100: private Double displayPrice = null;
0101: private Double recurringBasePrice = null;
0102: private Double recurringDisplayPrice = null;
0103: /** comes from price calc, used for special promo price promotion action */
0104: private Double specialPromoPrice = null;
0105: /** for reservations: extra % 2nd person */
0106: private double reserv2ndPPPerc = 0.0;
0107: /** for reservations: extra % Nth person */
0108: private double reservNthPPPerc = 0.0;
0109: private double listPrice = 0.0;
0110: /** flag to know if the price have been modified */
0111: private boolean isModifiedPrice = false;
0112: private double selectedAmount = 0.0;
0113: private String requirementId = null;
0114: private String quoteId = null;
0115: private String quoteItemSeqId = null;
0116: // The following three optional fields are used to collect information for the OrderItemAssoc entity
0117: private String associatedOrderId = null; // the order Id, if any, to which the given item is associated (typically a sales order item can be associated to a purchase order item, for example in drop shipments)
0118: private String associatedOrderItemSeqId = null; // the order item Id, if any, to which the given item is associated
0119: private String orderItemAssocTypeId = "PURCHASE_ORDER"; // the type of association between this item and an external item; by default, for backward compatibility, a PURCHASE association is used (i.e. the extarnal order is a sales order and this item is a purchase order item created to fulfill the sales order item
0120:
0121: private String statusId = null;
0122: private Map orderItemAttributes = null;
0123: private Map attributes = null;
0124: private String orderItemSeqId = null;
0125: private Locale locale = null;
0126: private Timestamp shipBeforeDate = null;
0127: private Timestamp shipAfterDate = null;
0128:
0129: private Map contactMechIdsMap = FastMap.newInstance();
0130: private List orderItemPriceInfos = null;
0131: private List itemAdjustments = new LinkedList();
0132: private boolean isPromo = false;
0133: private double promoQuantityUsed = 0;
0134: private Map quantityUsedPerPromoCandidate = new HashMap();
0135: private Map quantityUsedPerPromoFailed = new HashMap();
0136: private Map quantityUsedPerPromoActual = new HashMap();
0137: private Map additionalProductFeatureAndAppls = new HashMap();
0138: private List alternativeOptionProductIds = null;
0139: private ProductConfigWrapper configWrapper = null;
0140: private List featuresForSupplier = new LinkedList();
0141:
0142: /**
0143: * Makes a ShoppingCartItem for a purchase order item and adds it to the cart.
0144: * NOTE: This method will get the product entity and check to make sure it can be purchased.
0145: *
0146: * @param cartLocation The location to place this item; null will place at the end
0147: * @param productId The primary key of the product being added
0148: * @param quantity The quantity to add
0149: * @param additionalProductFeatureAndAppls Product feature/appls map
0150: * @param attributes All unique attributes for this item (NOT features)
0151: * @param prodCatalogId The catalog this item was added from
0152: * @param configWrapper The product configuration wrapper (null if the product is not configurable)
0153: * @param dispatcher LocalDispatcher object for doing promotions, etc
0154: * @param cart The parent shopping cart object this item will belong to
0155: * @param supplierProduct GenericValue of SupplierProduct entity, containing product description and prices
0156: * @param shipBeforeDate Request that the shipment be made before this date
0157: * @param shipAfterDate Request that the shipment be made after this date
0158: * @return a new ShoppingCartItem object
0159: * @throws CartItemModifyException
0160: */
0161: public static ShoppingCartItem makePurchaseOrderItem(
0162: Integer cartLocation, String productId,
0163: Double selectedAmountDbl, double quantity,
0164: Map additionalProductFeatureAndAppls, Map attributes,
0165: String prodCatalogId, ProductConfigWrapper configWrapper,
0166: String itemType,
0167: ShoppingCart.ShoppingCartItemGroup itemGroup,
0168: LocalDispatcher dispatcher, ShoppingCart cart,
0169: GenericValue supplierProduct, Timestamp shipBeforeDate,
0170: Timestamp shipAfterDate) throws CartItemModifyException,
0171: ItemNotFoundException {
0172: GenericDelegator delegator = cart.getDelegator();
0173: GenericValue product = null;
0174:
0175: try {
0176: product = delegator.findByPrimaryKeyCache("Product",
0177: UtilMisc.toMap("productId", productId));
0178: } catch (GenericEntityException e) {
0179: Debug.logWarning(e.toString(), module);
0180: product = null;
0181: }
0182:
0183: if (product == null) {
0184: Map messageMap = UtilMisc.toMap("productId", productId);
0185:
0186: String excMsg = UtilProperties.getMessage(resource,
0187: "item.product_not_found", messageMap, cart
0188: .getLocale());
0189:
0190: Debug.logWarning(excMsg, module);
0191: throw new ItemNotFoundException(excMsg);
0192: }
0193: ShoppingCartItem newItem = new ShoppingCartItem(product,
0194: additionalProductFeatureAndAppls, attributes,
0195: prodCatalogId, configWrapper, cart.getLocale(),
0196: itemType, itemGroup, null);
0197:
0198: // check to see if product is virtual
0199: if ("Y".equals(product.getString("isVirtual"))) {
0200: Map messageMap = UtilMisc.toMap("productName", product
0201: .getString("productName"), "productId", product
0202: .getString("productId"));
0203:
0204: String excMsg = UtilProperties.getMessage(resource,
0205: "item.cannot_add_product_virtual", messageMap, cart
0206: .getLocale());
0207:
0208: Debug.logWarning(excMsg, module);
0209: throw new CartItemModifyException(excMsg);
0210: }
0211:
0212: // Timestamp nowTimestamp = UtilDateTime.nowTimestamp();
0213:
0214: // check to see if the product is fully configured
0215: if ("AGGREGATED".equals(product.getString("productTypeId"))) {
0216: if (configWrapper == null || !configWrapper.isCompleted()) {
0217: Map messageMap = UtilMisc.toMap("productName", product
0218: .getString("productName"), "productId", product
0219: .getString("productId"));
0220:
0221: String excMsg = UtilProperties
0222: .getMessage(
0223: resource,
0224: "item.cannot_add_product_not_configured_correctly",
0225: messageMap, cart.getLocale());
0226:
0227: Debug.logWarning(excMsg, module);
0228: throw new CartItemModifyException(excMsg);
0229: }
0230: }
0231:
0232: // add to cart before setting quantity so that we can get order total, etc
0233: if (cartLocation == null) {
0234: cart.addItemToEnd(newItem);
0235: } else {
0236: cart.addItem(cartLocation.intValue(), newItem);
0237: }
0238:
0239: if (selectedAmountDbl != null) {
0240: newItem.setSelectedAmount(selectedAmountDbl.doubleValue());
0241: }
0242:
0243: // set the ship before/after dates. this needs to happen before setQuantity because setQuantity causes the ship group's dates to be
0244: // checked versus the cart item's
0245: newItem
0246: .setShipBeforeDate(shipBeforeDate != null ? shipBeforeDate
0247: : cart.getDefaultShipBeforeDate());
0248: newItem.setShipAfterDate(shipAfterDate != null ? shipAfterDate
0249: : cart.getDefaultShipAfterDate());
0250:
0251: try {
0252: newItem.setQuantity(quantity, dispatcher, cart, true);
0253: } catch (CartItemModifyException e) {
0254: cart.removeCartItem(cart.getItemIndex(newItem), dispatcher);
0255: cart.clearItemShipInfo(newItem);
0256: cart.removeEmptyCartItems();
0257: throw e;
0258: }
0259:
0260: // specific for purchase orders - description is set to supplierProductId + supplierProductName, price set to lastPrice of SupplierProduct
0261: // if supplierProduct has no supplierProductName, use the regular supplierProductId
0262: if (supplierProduct != null) {
0263: newItem.setName(getPurchaseOrderItemDescription(product,
0264: supplierProduct, cart.getLocale()));
0265: newItem.setBasePrice(supplierProduct.getDouble("lastPrice")
0266: .doubleValue());
0267: } else {
0268: newItem.setName(product.getString("internalName"));
0269: }
0270: return newItem;
0271:
0272: }
0273:
0274: /**
0275: * Makes a ShoppingCartItem and adds it to the cart.
0276: * NOTE: This method will get the product entity and check to make sure it can be purchased.
0277: *
0278: * @param cartLocation The location to place this item; null will place at the end
0279: * @param productId The primary key of the product being added
0280: * @param selectedAmountDbl Optional. Defaults to 0.0. If a selectedAmount is needed (complements the quantity value), pass it in here.
0281: * @param quantity Required. The quantity to add.
0282: * @param unitPriceDbl Optional. Defaults to 0.0, which causes calculation of price.
0283: * @param reservStart Optional. The start of the reservation.
0284: * @param reservLengthDbl Optional. The length of the reservation.
0285: * @param reservPersonsDbl Optional. The number of persons taking advantage of the reservation.
0286: * @param shipBeforeDate Optional. The date to ship the order by.
0287: * @param shipAfterDate Optional. Wait until this date to ship.
0288: * @param additionalProductFeatureAndAppls Optional. Product feature/appls map.
0289: * @param attributes Optional. All unique attributes for this item (NOT features).
0290: * @param prodCatalogId Optional, but strongly recommended. The catalog this item was added from.
0291: * @param configWrapper Optional. The product configuration wrapper (null if the product is not configurable).
0292: * @param itemType Optional. Specifies the type of cart item, corresponds to an OrderItemType and should be a valid orderItemTypeId.
0293: * @param itemGroup Optional. Specifies which item group in the cart this should belong to, if item groups are needed/desired.
0294: * @param dispatcher Required (for price calculation, promos, etc). LocalDispatcher object for doing promotions, etc.
0295: * @param cart Required. The parent shopping cart object this item will belong to.
0296: * @param triggerExternalOpsBool Optional. Defaults to true. Trigger external operations (like promotions and such)?
0297: * @param triggerPriceRulesBool Optional. Defaults to true. Trigger the price rules to calculate the price for this item?
0298: *
0299: * @return a new ShoppingCartItem object
0300: * @throws CartItemModifyException
0301: */
0302: public static ShoppingCartItem makeItem(Integer cartLocation,
0303: String productId, Double selectedAmountDbl,
0304: double quantity, Double unitPriceDbl,
0305: Timestamp reservStart, Double reservLengthDbl,
0306: Double reservPersonsDbl, Timestamp shipBeforeDate,
0307: Timestamp shipAfterDate,
0308: Map additionalProductFeatureAndAppls, Map attributes,
0309: String prodCatalogId, ProductConfigWrapper configWrapper,
0310: String itemType,
0311: ShoppingCart.ShoppingCartItemGroup itemGroup,
0312: LocalDispatcher dispatcher, ShoppingCart cart,
0313: Boolean triggerExternalOpsBool,
0314: Boolean triggerPriceRulesBool, String parentProductId,
0315: Boolean skipInventoryChecks, Boolean skipProductChecks)
0316: throws CartItemModifyException, ItemNotFoundException {
0317: GenericDelegator delegator = cart.getDelegator();
0318: GenericValue product = null;
0319: GenericValue parentProduct = null;
0320:
0321: try {
0322: product = delegator.findByPrimaryKeyCache("Product",
0323: UtilMisc.toMap("productId", productId));
0324:
0325: // first see if there is a purchase allow category and if this product is in it or not
0326: String purchaseProductCategoryId = CatalogWorker
0327: .getCatalogPurchaseAllowCategoryId(delegator,
0328: prodCatalogId);
0329: if (product != null && purchaseProductCategoryId != null) {
0330: if (!CategoryWorker.isProductInCategory(delegator,
0331: product.getString("productId"),
0332: purchaseProductCategoryId)) {
0333: // a Purchase allow productCategoryId was found, but the product is not in the category, axe it...
0334: product = null;
0335: }
0336: }
0337: } catch (GenericEntityException e) {
0338: Debug.logWarning(e.toString(), module);
0339: product = null;
0340: }
0341:
0342: if (product == null) {
0343: Map messageMap = UtilMisc.toMap("productId", productId);
0344: String excMsg = UtilProperties.getMessage(resource,
0345: "item.product_not_found", messageMap, cart
0346: .getLocale());
0347:
0348: Debug.logWarning(excMsg, module);
0349: throw new ItemNotFoundException(excMsg);
0350: }
0351:
0352: if (parentProductId != null) {
0353: try {
0354: parentProduct = delegator.findByPrimaryKeyCache(
0355: "Product", UtilMisc.toMap("productId",
0356: parentProductId));
0357: } catch (GenericEntityException e) {
0358: Debug.logWarning(e.toString(), module);
0359: parentProduct = null;
0360: }
0361: }
0362: return makeItem(cartLocation, product, selectedAmountDbl,
0363: quantity, unitPriceDbl, reservStart, reservLengthDbl,
0364: reservPersonsDbl, shipBeforeDate, shipAfterDate,
0365: additionalProductFeatureAndAppls, attributes,
0366: prodCatalogId, configWrapper, itemType, itemGroup,
0367: dispatcher, cart, triggerExternalOpsBool,
0368: triggerPriceRulesBool, parentProduct,
0369: skipInventoryChecks, skipProductChecks);
0370: }
0371:
0372: /**
0373: * Makes a ShoppingCartItem and adds it to the cart.
0374: * WARNING: This method does not check if the product is in a purchase category.
0375: * rental fields were added.
0376: *
0377: * @param cartLocation The location to place this item; null will place at the end
0378: * @param product The product entity relating to the product being added
0379: * @param selectedAmountDbl Optional. Defaults to 0.0. If a selectedAmount is needed (complements the quantity value), pass it in here.
0380: * @param quantity Required. The quantity to add.
0381: * @param unitPriceDbl Optional. Defaults to 0.0, which causes calculation of price.
0382: * @param reservStart Optional. The start of the reservation.
0383: * @param reservLengthDbl Optional. The length of the reservation.
0384: * @param reservPersonsDbl Optional. The number of persons taking advantage of the reservation.
0385: * @param shipBeforeDate Optional. The date to ship the order by.
0386: * @param shipAfterDate Optional. Wait until this date to ship.
0387: * @param additionalProductFeatureAndAppls Optional. Product feature/appls map.
0388: * @param attributes Optional. All unique attributes for this item (NOT features).
0389: * @param prodCatalogId Optional, but strongly recommended. The catalog this item was added from.
0390: * @param configWrapper Optional. The product configuration wrapper (null if the product is not configurable).
0391: * @param itemType Optional. Specifies the type of cart item, corresponds to an OrderItemType and should be a valid orderItemTypeId.
0392: * @param itemGroup Optional. Specifies which item group in the cart this should belong to, if item groups are needed/desired.
0393: * @param dispatcher Required (for price calculation, promos, etc). LocalDispatcher object for doing promotions, etc.
0394: * @param cart Required. The parent shopping cart object this item will belong to.
0395: * @param triggerExternalOpsBool Optional. Defaults to true. Trigger external operations (like promotions and such)?
0396: * @param triggerPriceRulesBool Optional. Defaults to true. Trigger the price rules to calculate the price for this item?
0397: *
0398: * @return a new ShoppingCartItem object
0399: * @throws CartItemModifyException
0400: */
0401: public static ShoppingCartItem makeItem(Integer cartLocation,
0402: GenericValue product, Double selectedAmountDbl,
0403: double quantity, Double unitPriceDbl,
0404: Timestamp reservStart, Double reservLengthDbl,
0405: Double reservPersonsDbl, Timestamp shipBeforeDate,
0406: Timestamp shipAfterDate,
0407: Map additionalProductFeatureAndAppls, Map attributes,
0408: String prodCatalogId, ProductConfigWrapper configWrapper,
0409: String itemType,
0410: ShoppingCart.ShoppingCartItemGroup itemGroup,
0411: LocalDispatcher dispatcher, ShoppingCart cart,
0412: Boolean triggerExternalOpsBool,
0413: Boolean triggerPriceRulesBool, GenericValue parentProduct,
0414: Boolean skipInventoryChecks, Boolean skipProductChecks)
0415: throws CartItemModifyException {
0416:
0417: ShoppingCartItem newItem = new ShoppingCartItem(product,
0418: additionalProductFeatureAndAppls, attributes,
0419: prodCatalogId, configWrapper, cart.getLocale(),
0420: itemType, itemGroup, parentProduct);
0421:
0422: double selectedAmount = selectedAmountDbl == null ? 0.0
0423: : selectedAmountDbl.doubleValue();
0424: double unitPrice = unitPriceDbl == null ? 0.0 : unitPriceDbl
0425: .doubleValue();
0426: double reservLength = reservLengthDbl == null ? 0.0
0427: : reservLengthDbl.doubleValue();
0428: double reservPersons = reservPersonsDbl == null ? 0.0
0429: : reservPersonsDbl.doubleValue();
0430: boolean triggerPriceRules = triggerPriceRulesBool == null ? true
0431: : triggerPriceRulesBool.booleanValue();
0432: boolean triggerExternalOps = triggerExternalOpsBool == null ? true
0433: : triggerExternalOpsBool.booleanValue();
0434:
0435: // check to see if product is virtual
0436: if ("Y".equals(product.getString("isVirtual"))) {
0437: Map messageMap = UtilMisc.toMap("productName", product
0438: .getString("productName"), "productId", product
0439: .getString("productId"));
0440:
0441: String excMsg = UtilProperties.getMessage(resource,
0442: "item.cannot_add_product_virtual", messageMap, cart
0443: .getLocale());
0444:
0445: Debug.logWarning(excMsg, module);
0446: throw new CartItemModifyException(excMsg);
0447: }
0448:
0449: java.sql.Timestamp nowTimestamp = UtilDateTime.nowTimestamp();
0450:
0451: if (!skipProductChecks.booleanValue()) {
0452: // check to see if introductionDate hasn't passed yet
0453: if (product.get("introductionDate") != null
0454: && nowTimestamp.before(product
0455: .getTimestamp("introductionDate"))) {
0456: Map messageMap = UtilMisc.toMap("productName", product
0457: .getString("productName"), "productId", product
0458: .getString("productId"));
0459:
0460: String excMsg = UtilProperties.getMessage(resource,
0461: "item.cannot_add_product_not_yet_available",
0462: messageMap, cart.getLocale());
0463:
0464: Debug.logWarning(excMsg, module);
0465: throw new CartItemModifyException(excMsg);
0466: }
0467:
0468: // check to see if salesDiscontinuationDate has passed
0469: if (product.get("salesDiscontinuationDate") != null
0470: && nowTimestamp.after(product
0471: .getTimestamp("salesDiscontinuationDate"))) {
0472: Map messageMap = UtilMisc.toMap("productName", product
0473: .getString("productName"), "productId", product
0474: .getString("productId"));
0475:
0476: String excMsg = UtilProperties.getMessage(resource,
0477: "item.cannot_add_product_no_longer_available",
0478: messageMap, cart.getLocale());
0479:
0480: Debug.logWarning(excMsg, module);
0481: throw new CartItemModifyException(excMsg);
0482: }
0483: /*
0484: if (product.get("salesDiscWhenNotAvail") != null && "Y".equals(product.getString("salesDiscWhenNotAvail"))) {
0485: // check atp and if <= 0 then the product is no more available because
0486: // all the units in warehouse are reserved by other sales orders and no new purchase orders will be done
0487: // for this product.
0488: if (!newItem.isInventoryAvailableOrNotRequired(quantity, cart.getProductStoreId(), dispatcher)) {
0489: Map messageMap = UtilMisc.toMap("productName", product.getString("productName"),
0490: "productId", product.getString("productId"));
0491:
0492: String excMsg = UtilProperties.getMessage(resource, "item.cannot_add_product_no_longer_available",
0493: messageMap , cart.getLocale() );
0494:
0495: Debug.logWarning(excMsg, module);
0496: throw new CartItemModifyException(excMsg);
0497: }
0498: }
0499: */
0500: }
0501: // check to see if the product is a rental item
0502: if ("ASSET_USAGE".equals(product.getString("productTypeId"))) {
0503: if (reservStart == null) {
0504: String excMsg = UtilProperties.getMessage(resource,
0505: "item.missing_reservation_starting_date", cart
0506: .getLocale());
0507: throw new CartItemModifyException(excMsg);
0508: }
0509:
0510: if (reservStart.before(UtilDateTime.nowTimestamp())) {
0511: String excMsg = UtilProperties.getMessage(resource,
0512: "item.reservation_from_tomorrow", cart
0513: .getLocale());
0514: throw new CartItemModifyException(excMsg);
0515: }
0516: newItem.setReservStart(reservStart);
0517:
0518: if (reservLength < 1) {
0519: String excMsg = UtilProperties.getMessage(resource,
0520: "item.number_of_days", cart.getLocale());
0521: throw new CartItemModifyException(excMsg);
0522: }
0523: newItem.setReservLength(reservLength);
0524:
0525: if (product.get("reservMaxPersons") != null) {
0526: double reservMaxPersons = product.getDouble(
0527: "reservMaxPersons").doubleValue();
0528: if (reservMaxPersons < reservPersons) {
0529: Map messageMap = UtilMisc.toMap("reservMaxPersons",
0530: product.getString("reservMaxPersons"),
0531: "reservPersons",
0532: (new Double(reservPersons)).toString());
0533: String excMsg = UtilProperties.getMessage(resource,
0534: "item.maximum_number_of_person_renting",
0535: messageMap, cart.getLocale());
0536:
0537: Debug.logInfo(excMsg, module);
0538: throw new CartItemModifyException(excMsg);
0539: }
0540: }
0541: newItem.setReservPersons(reservPersons);
0542:
0543: if (product.get("reserv2ndPPPerc") != null)
0544: newItem.setReserv2ndPPPerc(product.getDouble(
0545: "reserv2ndPPPerc").doubleValue());
0546:
0547: if (product.get("reservNthPPPerc") != null)
0548: newItem.setReservNthPPPerc(product.getDouble(
0549: "reservNthPPPerc").doubleValue());
0550:
0551: // check to see if the related fixed asset is available for rent
0552: String isAvailable = checkAvailability(product
0553: .getString("productId"), quantity, reservStart,
0554: reservLength, cart);
0555: if (isAvailable.compareTo("OK") != 0) {
0556: Map messageMap = UtilMisc.toMap("productId", product
0557: .getString("productId"), "availableMessage",
0558: isAvailable);
0559: String excMsg = UtilProperties.getMessage(resource,
0560: "item.product_not_available", messageMap, cart
0561: .getLocale());
0562: Debug.logInfo(excMsg, module);
0563: throw new CartItemModifyException(isAvailable);
0564: }
0565: }
0566:
0567: // check to see if the product is fully configured
0568: if ("AGGREGATED".equals(product.getString("productTypeId"))) {
0569: if (configWrapper == null || !configWrapper.isCompleted()) {
0570: Map messageMap = UtilMisc.toMap("productName", product
0571: .getString("productName"), "productId", product
0572: .getString("productId"));
0573: String excMsg = UtilProperties
0574: .getMessage(
0575: resource,
0576: "item.cannot_add_product_not_configured_correctly",
0577: messageMap, cart.getLocale());
0578: Debug.logWarning(excMsg, module);
0579: throw new CartItemModifyException(excMsg);
0580: }
0581: }
0582:
0583: // set the ship before and after dates (defaults to cart ship before/after dates)
0584: newItem
0585: .setShipBeforeDate(shipBeforeDate != null ? shipBeforeDate
0586: : cart.getDefaultShipBeforeDate());
0587: newItem.setShipAfterDate(shipAfterDate != null ? shipAfterDate
0588: : cart.getDefaultShipAfterDate());
0589:
0590: // set the product unit price as base price
0591: // if triggerPriceRules is true this price will be overriden
0592: newItem.setBasePrice(unitPrice);
0593:
0594: // add to cart before setting quantity so that we can get order total, etc
0595: if (cartLocation == null) {
0596: cart.addItemToEnd(newItem);
0597: } else {
0598: cart.addItem(cartLocation.intValue(), newItem);
0599: }
0600:
0601: // We have to set the selectedAmount before calling setQuantity because
0602: // selectedAmount changes the item's base price (used in the updatePrice
0603: // method called inside the setQuantity method)
0604: if (selectedAmount > 0) {
0605: newItem.setSelectedAmount(selectedAmount);
0606: }
0607:
0608: try {
0609: newItem.setQuantity((int) quantity, dispatcher, cart,
0610: triggerExternalOps, true, triggerPriceRules,
0611: skipInventoryChecks.booleanValue());
0612: } catch (CartItemModifyException e) {
0613: Debug.logWarning(e.getMessage(), module);
0614: cart.removeCartItem(cart.getItemIndex(newItem), dispatcher);
0615: cart.clearItemShipInfo(newItem);
0616: cart.removeEmptyCartItems();
0617: throw e;
0618: }
0619:
0620: return newItem;
0621: }
0622:
0623: /**
0624: * Makes a non-product ShoppingCartItem and adds it to the cart.
0625: * NOTE: This is only for non-product items; items without a product entity (work items, bulk items, etc)
0626: *
0627: * @param cartLocation The location to place this item; null will place at the end
0628: * @param itemType The OrderItemTypeId for the item being added
0629: * @param itemDescription The optional description of the item
0630: * @param productCategoryId The optional category the product *will* go in
0631: * @param basePrice The price for this item
0632: * @param selectedAmount
0633: * @param quantity The quantity to add
0634: * @param attributes All unique attributes for this item (NOT features)
0635: * @param prodCatalogId The catalog this item was added from
0636: * @param dispatcher LocalDispatcher object for doing promotions, etc
0637: * @param cart The parent shopping cart object this item will belong to
0638: * @param triggerExternalOpsBool Indicates if we should run external operations (promotions, auto-save, etc)
0639: * @return a new ShoppingCartItem object
0640: * @throws CartItemModifyException
0641: */
0642: public static ShoppingCartItem makeItem(Integer cartLocation,
0643: String itemType, String itemDescription,
0644: String productCategoryId, Double basePrice,
0645: Double selectedAmount, double quantity, Map attributes,
0646: String prodCatalogId,
0647: ShoppingCart.ShoppingCartItemGroup itemGroup,
0648: LocalDispatcher dispatcher, ShoppingCart cart,
0649: Boolean triggerExternalOpsBool)
0650: throws CartItemModifyException {
0651:
0652: GenericDelegator delegator = cart.getDelegator();
0653: ShoppingCartItem newItem = new ShoppingCartItem(delegator,
0654: itemType, itemDescription, productCategoryId,
0655: basePrice, attributes, prodCatalogId, cart.getLocale(),
0656: itemGroup);
0657:
0658: // add to cart before setting quantity so that we can get order total, etc
0659: if (cartLocation == null) {
0660: cart.addItemToEnd(newItem);
0661: } else {
0662: cart.addItem(cartLocation.intValue(), newItem);
0663: }
0664:
0665: boolean triggerExternalOps = triggerExternalOpsBool == null ? true
0666: : triggerExternalOpsBool.booleanValue();
0667:
0668: try {
0669: newItem.setQuantity(quantity, dispatcher, cart,
0670: triggerExternalOps);
0671: } catch (CartItemModifyException e) {
0672: cart.removeEmptyCartItems();
0673: throw e;
0674: }
0675:
0676: if (selectedAmount != null) {
0677: newItem.setSelectedAmount(selectedAmount.doubleValue());
0678: }
0679: return newItem;
0680: }
0681:
0682: /** Clone an item. */
0683: public ShoppingCartItem(ShoppingCartItem item) {
0684: try {
0685: this ._product = item.getProduct();
0686: } catch (IllegalStateException e) {
0687: this ._product = null;
0688: }
0689: this .delegator = item.getDelegator();
0690: this .delegatorName = item.delegatorName;
0691: this .prodCatalogId = item.getProdCatalogId();
0692: this .productId = item.getProductId();
0693: this .itemType = item.getItemType();
0694: this .itemGroup = item.getItemGroup();
0695: this .productCategoryId = item.getProductCategoryId();
0696: this .quantity = item.getQuantity();
0697: this .reservStart = item.getReservStart();
0698: this .reservLength = item.getReservLength();
0699: this .reservPersons = item.getReservPersons();
0700: this .selectedAmount = item.getSelectedAmount();
0701: this .setBasePrice(item.getBasePrice());
0702: this .setDisplayPrice(item.getDisplayPrice());
0703: this .setRecurringBasePrice(item.getRecurringBasePrice());
0704: this .setRecurringDisplayPrice(item.getRecurringDisplayPrice());
0705: this .listPrice = item.getListPrice();
0706: this .reserv2ndPPPerc = item.getReserv2ndPPPerc();
0707: this .reservNthPPPerc = item.getReservNthPPPerc();
0708: this .requirementId = item.getRequirementId();
0709: this .quoteId = item.getQuoteId();
0710: this .quoteItemSeqId = item.getQuoteItemSeqId();
0711: this .associatedOrderId = item.getAssociatedOrderId();
0712: this .associatedOrderItemSeqId = item
0713: .getAssociatedOrderItemSeqId();
0714: this .orderItemAssocTypeId = item.getOrderItemAssocTypeId();
0715: this .isPromo = item.getIsPromo();
0716: this .promoQuantityUsed = item.promoQuantityUsed;
0717: this .locale = item.locale;
0718: this .quantityUsedPerPromoCandidate = new HashMap(
0719: item.quantityUsedPerPromoCandidate);
0720: this .quantityUsedPerPromoFailed = new HashMap(
0721: item.quantityUsedPerPromoFailed);
0722: this .quantityUsedPerPromoActual = new HashMap(
0723: item.quantityUsedPerPromoActual);
0724: this .orderItemSeqId = item.getOrderItemSeqId();
0725: this .additionalProductFeatureAndAppls = item
0726: .getAdditionalProductFeatureAndAppls() == null ? null
0727: : new HashMap(item
0728: .getAdditionalProductFeatureAndAppls());
0729: this .attributes = item.getAttributes() == null ? new HashMap()
0730: : new HashMap(item.getAttributes());
0731: this .contactMechIdsMap = item.getOrderItemContactMechIds() == null ? null
0732: : new HashMap(item.getOrderItemContactMechIds());
0733: this .orderItemPriceInfos = item.getOrderItemPriceInfos() == null ? null
0734: : new LinkedList(item.getOrderItemPriceInfos());
0735: this .itemAdjustments = item.getAdjustments() == null ? null
0736: : new LinkedList(item.getAdjustments());
0737: if (this ._product == null) {
0738: this .itemDescription = item.getName();
0739: }
0740: if (item.configWrapper != null) {
0741: this .configWrapper = new ProductConfigWrapper(
0742: item.configWrapper);
0743: }
0744: }
0745:
0746: /** Cannot create shopping cart item with no parameters */
0747: protected ShoppingCartItem() {
0748: }
0749:
0750: /** Creates new ShoppingCartItem object. */
0751: protected ShoppingCartItem(GenericValue product,
0752: Map additionalProductFeatureAndAppls, Map attributes,
0753: String prodCatalogId, Locale locale, String itemType,
0754: ShoppingCart.ShoppingCartItemGroup itemGroup) {
0755: this (product, additionalProductFeatureAndAppls, attributes,
0756: prodCatalogId, null, locale, itemType, itemGroup, null);
0757: if (product != null) {
0758: String productName = ProductContentWrapper
0759: .getProductContentAsText(product, "PRODUCT_NAME",
0760: this .locale, null);
0761: // if the productName is null or empty, see if there is an associated virtual product and get the productName of that product
0762: if (UtilValidate.isEmpty(productName)) {
0763: GenericValue parentProduct = this .getParentProduct();
0764: if (parentProduct != null) {
0765: productName = ProductContentWrapper
0766: .getProductContentAsText(parentProduct,
0767: "PRODUCT_NAME", this .locale, null);
0768: }
0769: }
0770:
0771: if (productName == null) {
0772: this .itemDescription = "";
0773: } else {
0774: this .itemDescription = productName;
0775: }
0776: }
0777: }
0778:
0779: /** Creates new ShoppingCartItem object. */
0780: protected ShoppingCartItem(GenericValue product,
0781: Map additionalProductFeatureAndAppls, Map attributes,
0782: String prodCatalogId, ProductConfigWrapper configWrapper,
0783: Locale locale, String itemType,
0784: ShoppingCart.ShoppingCartItemGroup itemGroup,
0785: GenericValue parentProduct) {
0786: this ._product = product;
0787: this .productId = _product.getString("productId");
0788: this ._parentProduct = parentProduct;
0789: if (parentProduct != null)
0790: this .parentProductId = _parentProduct
0791: .getString("productId");
0792: if (UtilValidate.isEmpty(itemType)) {
0793: if (_product.getString("productTypeId").equals(
0794: "ASSET_USAGE")) {
0795: this .itemType = "RENTAL_ORDER_ITEM"; // will create additional workeffort/asset usage records
0796: } else {
0797: this .itemType = "PRODUCT_ORDER_ITEM";
0798: }
0799: } else {
0800: this .itemType = itemType;
0801: }
0802: this .itemGroup = itemGroup;
0803: this .prodCatalogId = prodCatalogId;
0804: this .attributes = (attributes == null ? FastMap.newInstance()
0805: : attributes);
0806: this .delegator = _product.getDelegator();
0807: this .delegatorName = _product.getDelegator().getDelegatorName();
0808: this
0809: .addAllProductFeatureAndAppls(additionalProductFeatureAndAppls);
0810: this .locale = locale;
0811: this .configWrapper = configWrapper;
0812: }
0813:
0814: /** Creates new ShopingCartItem object. */
0815: protected ShoppingCartItem(GenericDelegator delegator,
0816: String itemTypeId, String description, String categoryId,
0817: Double basePrice, Map attributes, String prodCatalogId,
0818: Locale locale, ShoppingCart.ShoppingCartItemGroup itemGroup) {
0819: this .delegator = delegator;
0820: this .itemType = itemTypeId;
0821: this .itemGroup = itemGroup;
0822: this .itemDescription = description;
0823: this .productCategoryId = categoryId;
0824: if (basePrice != null) {
0825: this .setBasePrice(basePrice.doubleValue());
0826: this .setDisplayPrice(basePrice.doubleValue());
0827: }
0828: this .attributes = (attributes == null ? FastMap.newInstance()
0829: : attributes);
0830: this .prodCatalogId = prodCatalogId;
0831: this .delegatorName = delegator.getDelegatorName();
0832: this .locale = locale;
0833: }
0834:
0835: public String getProdCatalogId() {
0836: return this .prodCatalogId;
0837: }
0838:
0839: public void setExternalId(String externalId) {
0840: this .externalId = externalId;
0841: }
0842:
0843: public String getExternalId() {
0844: return this .externalId;
0845: }
0846:
0847: /** Sets the user selected amount */
0848: public void setSelectedAmount(double selectedAmount) {
0849: this .selectedAmount = selectedAmount;
0850: }
0851:
0852: /** Returns the user selected amount */
0853: public double getSelectedAmount() {
0854: return this .selectedAmount;
0855: }
0856:
0857: /** Sets the base price for the item; use with caution */
0858: public void setBasePrice(double basePrice) {
0859: this .basePrice = basePrice;
0860: }
0861:
0862: /** Sets the display price for the item; use with caution */
0863: public void setDisplayPrice(double displayPrice) {
0864: this .displayPrice = new Double(displayPrice);
0865: }
0866:
0867: /** Sets the base price for the item; use with caution */
0868: public void setRecurringBasePrice(Double recurringBasePrice) {
0869: this .recurringBasePrice = recurringBasePrice;
0870: }
0871:
0872: /** Sets the display price for the item; use with caution */
0873: public void setRecurringDisplayPrice(Double recurringDisplayPrice) {
0874: this .recurringDisplayPrice = recurringDisplayPrice;
0875: }
0876:
0877: public void setSpecialPromoPrice(Double specialPromoPrice) {
0878: this .specialPromoPrice = specialPromoPrice;
0879: }
0880:
0881: /** Sets the extra % for second person */
0882: public void setReserv2ndPPPerc(double reserv2ndPPPerc) {
0883: this .reserv2ndPPPerc = reserv2ndPPPerc;
0884: }
0885:
0886: /** Sets the extra % for third and following person */
0887: public void setReservNthPPPerc(double reservNthPPPerc) {
0888: this .reservNthPPPerc = reservNthPPPerc;
0889: }
0890:
0891: /** Sets the reservation start date */
0892: public void setReservStart(Timestamp reservStart) {
0893: this .reservStart = reservStart;
0894: }
0895:
0896: /** Sets the reservation length */
0897: public void setReservLength(double reservLength) {
0898: this .reservLength = reservLength;
0899: }
0900:
0901: /** Sets number of persons using the reservation */
0902: public void setReservPersons(double reservPersons) {
0903: this .reservPersons = reservPersons;
0904: }
0905:
0906: /** Sets the quantity for the item and validates the change in quantity, etc */
0907: public void setQuantity(double quantity,
0908: LocalDispatcher dispatcher, ShoppingCart cart)
0909: throws CartItemModifyException {
0910: this .setQuantity(quantity, dispatcher, cart, true);
0911: }
0912:
0913: /** Sets the quantity for the item and validates the change in quantity, etc */
0914: public void setQuantity(double quantity,
0915: LocalDispatcher dispatcher, ShoppingCart cart,
0916: boolean triggerExternalOps) throws CartItemModifyException {
0917: this .setQuantity(quantity, dispatcher, cart,
0918: triggerExternalOps, true);
0919: }
0920:
0921: /** Sets the quantity for the item and validates the change in quantity, etc */
0922: public void setQuantity(double quantity,
0923: LocalDispatcher dispatcher, ShoppingCart cart,
0924: boolean triggerExternalOps, boolean resetShipGroup)
0925: throws CartItemModifyException {
0926: this .setQuantity((int) quantity, dispatcher, cart,
0927: triggerExternalOps, resetShipGroup, true, false);
0928: }
0929:
0930: /** Sets the quantity for the item and validates the change in quantity, etc */
0931: public void setQuantity(double quantity,
0932: LocalDispatcher dispatcher, ShoppingCart cart,
0933: boolean triggerExternalOps, boolean resetShipGroup,
0934: boolean updateProductPrice) throws CartItemModifyException {
0935: this .setQuantity((int) quantity, dispatcher, cart,
0936: triggerExternalOps, resetShipGroup, updateProductPrice,
0937: false);
0938: }
0939:
0940: /** returns "OK" when the product can be booked or returns a string with the dates the related fixed Asset is not available */
0941: public static String checkAvailability(String productId,
0942: double quantity, Timestamp reservStart,
0943: double reservLength, ShoppingCart cart) {
0944: GenericDelegator delegator = cart.getDelegator();
0945: // find related fixedAsset
0946: List selFixedAssetProduct = null;
0947: GenericValue fixedAssetProduct = null;
0948: try {
0949: List allFixedAssetProduct = delegator.findByAnd(
0950: "FixedAssetProduct", UtilMisc.toMap("productId",
0951: productId, "fixedAssetProductTypeId",
0952: "FAPT_USE"));
0953: selFixedAssetProduct = EntityUtil.filterByDate(
0954: allFixedAssetProduct, UtilDateTime.nowTimestamp(),
0955: "fromDate", "thruDate", true);
0956: } catch (GenericEntityException e) {
0957: Map messageMap = UtilMisc.toMap("productId", productId);
0958: String msg = UtilProperties.getMessage(resource,
0959: "item.cannot_find_Fixed_Asset", messageMap, cart
0960: .getLocale());
0961: return msg;
0962: }
0963: if (selFixedAssetProduct != null
0964: && selFixedAssetProduct.size() > 0) {
0965: Iterator firstOne = selFixedAssetProduct.iterator();
0966: fixedAssetProduct = (GenericValue) firstOne.next();
0967: } else {
0968: Map messageMap = UtilMisc.toMap("productId", productId);
0969: String msg = UtilProperties.getMessage(resource,
0970: "item.cannot_find_Fixed_Asset", messageMap, cart
0971: .getLocale());
0972: return msg;
0973: }
0974:
0975: // find the fixed asset itself
0976: GenericValue fixedAsset = null;
0977: try {
0978: fixedAsset = fixedAssetProduct.getRelatedOne("FixedAsset");
0979: } catch (GenericEntityException e) {
0980: Map messageMap = UtilMisc.toMap("fixedAssetId",
0981: fixedAssetProduct.getString("fixedAssetId"));
0982: String msg = UtilProperties.getMessage(resource,
0983: "item.fixed_Asset_not_found", messageMap, cart
0984: .getLocale());
0985: return msg;
0986: }
0987: if (fixedAsset == null) {
0988: Map messageMap = UtilMisc.toMap("fixedAssetId",
0989: fixedAssetProduct.getString("fixedAssetId"));
0990: String msg = UtilProperties.getMessage(resource,
0991: "item.fixed_Asset_not_found", messageMap, cart
0992: .getLocale());
0993: return msg;
0994: }
0995: //Debug.logInfo("Checking availability for product: " + productId.toString() + " and related FixedAsset: " + fixedAssetProduct.getString("fixedAssetId"),module);
0996: // see if this fixed asset has a calendar, when no create one and attach to fixed asset
0997: // DEJ20050725 this isn't being used anywhere, commenting out for now and not assigning from the getRelatedOne: GenericValue techDataCalendar = null;
0998: GenericValue techDataCalendar = null;
0999: try {
1000: techDataCalendar = fixedAsset
1001: .getRelatedOne("TechDataCalendar");
1002: } catch (GenericEntityException e) {
1003: Debug.logWarning(e, module);
1004: }
1005: if (techDataCalendar == null) {
1006: // no calendar ok, when not more that total capacity
1007: if (fixedAsset.getDouble("productionCapacity")
1008: .doubleValue() >= quantity) {
1009: String msg = UtilProperties.getMessage(resource,
1010: "item.availableOk", cart.getLocale());
1011: return msg;
1012: } else {
1013: Map messageMap = UtilMisc.toMap("quantityReq",
1014: (new Double(quantity)).toString(),
1015: "quantityAvail", fixedAsset
1016: .getString("productionCapacity"));
1017: String msg = UtilProperties.getMessage(resource,
1018: "item.availableQnt", messageMap, cart
1019: .getLocale());
1020: return msg;
1021: }
1022: }
1023: // now find all the dates and check the availabilty for each date
1024: // please note that calendarId is the same for (TechData)Calendar, CalendarExcDay and CalendarExWeek
1025: long dayCount = 0;
1026: String resultMessage = "";
1027: while (dayCount < (long) reservLength) {
1028: GenericValue techDataCalendarExcDay = null;
1029: // find an existing Day exception record
1030: Timestamp exceptionDateStartTime = new Timestamp(
1031: (long) (reservStart.getTime() + (dayCount++ * 86400000)));
1032: try {
1033: techDataCalendarExcDay = delegator.findByPrimaryKey(
1034: "TechDataCalendarExcDay", UtilMisc.toMap(
1035: "calendarId", fixedAsset
1036: .get("calendarId"),
1037: "exceptionDateStartTime",
1038: exceptionDateStartTime));
1039: } catch (GenericEntityException e) {
1040: Debug.logWarning(e, module);
1041: }
1042: if (techDataCalendarExcDay == null) {
1043: //Debug.logInfo(" No exception day record found, available: " + fixedAsset.getString("productionCapacity") + " Requested now: " + quantity, module);
1044: if (fixedAsset.get("productionCapacity") != null
1045: && fixedAsset.getDouble("productionCapacity")
1046: .doubleValue() < quantity)
1047: resultMessage = resultMessage
1048: .concat(exceptionDateStartTime.toString()
1049: .substring(0, 10)
1050: + ", ");
1051: } else {
1052: // see if we can get the number of assets available
1053: // first try techDataCalendarExcDay(exceptionCapacity) and then FixedAsset(productionCapacity)
1054: // if still zero, do not check availability
1055: double exceptionCapacity = 0.00;
1056: if (techDataCalendarExcDay.get("exceptionCapacity") != null)
1057: exceptionCapacity = techDataCalendarExcDay
1058: .getDouble("exceptionCapacity")
1059: .doubleValue();
1060: if (exceptionCapacity == 0.00
1061: && fixedAsset.get("productionCapacity") != null)
1062: exceptionCapacity = fixedAsset.getDouble(
1063: "productionCapacity").doubleValue();
1064: if (exceptionCapacity != 0.00) {
1065: double usedCapacity = 0.00;
1066: if (techDataCalendarExcDay.get("usedCapacity") != null)
1067: usedCapacity = techDataCalendarExcDay
1068: .getDouble("usedCapacity")
1069: .doubleValue();
1070: if (exceptionCapacity < (quantity + usedCapacity)) {
1071: resultMessage = resultMessage
1072: .concat(exceptionDateStartTime
1073: .toString().substring(0, 10)
1074: + ", ");
1075: Debug
1076: .logInfo(
1077: "No rental fixed Asset available: "
1078: + exceptionCapacity
1079: + " already used: "
1080: + usedCapacity
1081: + " Requested now: "
1082: + quantity, module);
1083: }
1084: }
1085: }
1086: }
1087: if (resultMessage.compareTo("") == 0) {
1088: String msg = UtilProperties.getMessage(resource,
1089: "item.availableOk", cart.getLocale());
1090: return msg;
1091: } else {
1092: Map messageMap = UtilMisc.toMap("resultMessage",
1093: resultMessage);
1094: String msg = UtilProperties.getMessage(resource,
1095: "item.notAvailable", messageMap, cart.getLocale());
1096: return msg;
1097: }
1098: }
1099:
1100: protected boolean isInventoryAvailableOrNotRequired(
1101: double quantity, String productStoreId,
1102: LocalDispatcher dispatcher) throws CartItemModifyException {
1103: boolean inventoryAvailable = true;
1104: try {
1105: Map invReqResult = dispatcher.runSync(
1106: "isStoreInventoryAvailableOrNotRequired", UtilMisc
1107: .toMap("productStoreId", productStoreId,
1108: "productId", productId, "product",
1109: this .getProduct(), "quantity",
1110: new Double(quantity)));
1111: if (ServiceUtil.isError(invReqResult)) {
1112: Debug.logError(
1113: "Error calling isStoreInventoryAvailableOrNotRequired service, result is: "
1114: + invReqResult, module);
1115: throw new CartItemModifyException((String) invReqResult
1116: .get(ModelService.ERROR_MESSAGE));
1117: }
1118: inventoryAvailable = "Y".equals((String) invReqResult
1119: .get("availableOrNotRequired"));
1120: } catch (GenericServiceException e) {
1121: String errMsg = "Fatal error calling inventory checking services: "
1122: + e.toString();
1123: Debug.logError(e, errMsg, module);
1124: throw new CartItemModifyException(errMsg);
1125: }
1126: return inventoryAvailable;
1127: }
1128:
1129: protected void setQuantity(int quantity,
1130: LocalDispatcher dispatcher, ShoppingCart cart,
1131: boolean triggerExternalOps, boolean resetShipGroup,
1132: boolean updateProductPrice, boolean skipInventoryChecks)
1133: throws CartItemModifyException {
1134: if (this .quantity == quantity) {
1135: return;
1136: }
1137:
1138: if (this .isPromo) {
1139: throw new CartItemModifyException(
1140: "Sorry, you can't change the quantity on the promotion item "
1141: + this .getName() + " (product ID: "
1142: + productId + "), not setting quantity.");
1143: }
1144:
1145: // needed for inventory checking and auto-save
1146: String productStoreId = cart.getProductStoreId();
1147:
1148: if (!skipInventoryChecks
1149: && !"PURCHASE_ORDER".equals(cart.getOrderType())) {
1150: // 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
1151: if (_product != null && quantity > this .quantity) {
1152: if (!isInventoryAvailableOrNotRequired(quantity,
1153: productStoreId, dispatcher)) {
1154: String excMsg = "Sorry, we do not have enough (you tried "
1155: + UtilFormatOut.formatQuantity(quantity)
1156: + ") of the product "
1157: + this .getName()
1158: + " (product ID: "
1159: + productId
1160: + ") in stock, not adding to cart. Please try a lower quantity, try again later, or call customer service for more information.";
1161: Debug.logWarning(excMsg, module);
1162: throw new CartItemModifyException(excMsg);
1163: }
1164: }
1165: }
1166:
1167: // set quantity before promos so order total, etc will be updated
1168: this .quantity = quantity;
1169:
1170: if (updateProductPrice) {
1171: this .updatePrice(dispatcher, cart);
1172: }
1173:
1174: // apply/unapply promotions
1175: if (triggerExternalOps) {
1176: ProductPromoWorker.doPromotions(cart, dispatcher);
1177: }
1178:
1179: if (!"PURCHASE_ORDER".equals(cart.getOrderType())) {
1180: // store the auto-save cart
1181: if (triggerExternalOps
1182: && ProductStoreWorker.autoSaveCart(delegator,
1183: productStoreId)) {
1184: try {
1185: ShoppingListEvents.fillAutoSaveList(cart,
1186: dispatcher);
1187: } catch (GeneralException e) {
1188: Debug.logWarning(e, UtilProperties.getMessage(
1189: resource_error,
1190: "OrderUnableToStoreAutoSaveCart", locale));
1191: }
1192: }
1193: }
1194:
1195: // set the item ship group
1196: if (resetShipGroup) {
1197: cart.clearItemShipInfo(this );
1198:
1199: /*
1200:
1201: // Deprecated in favour of ShoppingCart.createDropShipGroups(), called during checkout
1202:
1203: int shipGroupIndex = -1;
1204: if ("PURCHASE_ORDER".equals(cart.getOrderType())) {
1205: shipGroupIndex = 0;
1206: } else {
1207: if (_product != null && "PRODRQM_DS".equals(_product.getString("requirementMethodEnumId"))) {
1208: // this is a drop-ship only product: we need a ship group with supplierPartyId set
1209: Map supplierProductsResult = null;
1210: try {
1211: supplierProductsResult = dispatcher.runSync("getSuppliersForProduct", UtilMisc.toMap("productId", _product.getString("productId"),
1212: "quantity", new Double(quantity),
1213: "currencyUomId", cart.getCurrency(),
1214: "canDropShip", "Y",
1215: "userLogin", cart.getUserLogin()));
1216: List productSuppliers = (List)supplierProductsResult.get("supplierProducts");
1217: GenericValue supplierProduct = EntityUtil.getFirst(productSuppliers);
1218: if (supplierProduct != null) {
1219: String supplierPartyId = supplierProduct.getString("partyId");
1220: List shipGroups = cart.getShipGroups();
1221: for(int i = 0; i < shipGroups.size(); i++) {
1222: ShoppingCart.CartShipInfo csi = (ShoppingCart.CartShipInfo)shipGroups.get(i);
1223: if (supplierPartyId.equals(csi.getSupplierPartyId())) {
1224: shipGroupIndex = i;
1225: break;
1226: }
1227: }
1228: if (shipGroupIndex == -1) {
1229: // create a new ship group
1230: shipGroupIndex = cart.addShipInfo();
1231: cart.setSupplierPartyId(shipGroupIndex, supplierPartyId);
1232: }
1233: }
1234: } catch (Exception e) {
1235: Debug.logWarning("Error calling getSuppliersForProduct service, result is: " + supplierProductsResult, module);
1236: }
1237: }
1238:
1239: if (shipGroupIndex == -1) {
1240: List shipGroups = cart.getShipGroups();
1241: for(int i = 0; i < shipGroups.size(); i++) {
1242: ShoppingCart.CartShipInfo csi = (ShoppingCart.CartShipInfo)shipGroups.get(i);
1243: if (csi.getSupplierPartyId() == null) {
1244: shipGroupIndex = i;
1245: break;
1246: }
1247: }
1248: if (shipGroupIndex == -1) {
1249: // create a new ship group
1250: shipGroupIndex = cart.addShipInfo();
1251: }
1252: }
1253: }
1254: cart.setItemShipGroupQty(this, quantity, shipGroupIndex);
1255: */
1256: cart.setItemShipGroupQty(this , quantity, 0);
1257: }
1258: }
1259:
1260: public void updatePrice(LocalDispatcher dispatcher,
1261: ShoppingCart cart) throws CartItemModifyException {
1262: // set basePrice using the calculateProductPrice service
1263: if (_product != null && isModifiedPrice == false) {
1264: try {
1265: Map priceContext = FastMap.newInstance();
1266: priceContext.put("currencyUomId", cart.getCurrency());
1267:
1268: String partyId = cart.getPartyId();
1269: if (partyId != null) {
1270: priceContext.put("partyId", partyId);
1271: }
1272: priceContext.put("quantity", new Double(this
1273: .getQuantity()));
1274: priceContext.put("product", this .getProduct());
1275: if (cart.getOrderType().equals("PURCHASE_ORDER")) {
1276: Map priceResult = dispatcher.runSync(
1277: "calculatePurchasePrice", priceContext);
1278: if (ServiceUtil.isError(priceResult)) {
1279: throw new CartItemModifyException(
1280: "There was an error while calculating the price: "
1281: + ServiceUtil
1282: .getErrorMessage(priceResult));
1283: }
1284: Boolean validPriceFound = (Boolean) priceResult
1285: .get("validPriceFound");
1286: if (!validPriceFound.booleanValue()) {
1287: throw new CartItemModifyException(
1288: "Could not find a valid price for the product with ID ["
1289: + this .getProductId()
1290: + "] and supplier with ID ["
1291: + partyId
1292: + "], not adding to cart.");
1293: }
1294:
1295: this .setBasePrice(((Double) priceResult
1296: .get("price")).doubleValue());
1297: this .setDisplayPrice(this .basePrice);
1298: this .orderItemPriceInfos = (List) priceResult
1299: .get("orderItemPriceInfos");
1300: } else {
1301: priceContext.put("prodCatalogId", this
1302: .getProdCatalogId());
1303: priceContext.put("webSiteId", cart.getWebSiteId());
1304: priceContext.put("productStoreId", cart
1305: .getProductStoreId());
1306: priceContext.put("agreementId", cart
1307: .getAgreementId());
1308: priceContext.put("productPricePurposeId",
1309: "PURCHASE");
1310: priceContext.put("checkIncludeVat", "Y");
1311: Map priceResult = dispatcher.runSync(
1312: "calculateProductPrice", priceContext);
1313: if (ServiceUtil.isError(priceResult)) {
1314: throw new CartItemModifyException(
1315: "There was an error while calculating the price: "
1316: + ServiceUtil
1317: .getErrorMessage(priceResult));
1318: }
1319:
1320: Boolean validPriceFound = (Boolean) priceResult
1321: .get("validPriceFound");
1322: if (Boolean.FALSE.equals(validPriceFound)) {
1323: throw new CartItemModifyException(
1324: "Could not find a valid price for the product with ID ["
1325: + this .getProductId()
1326: + "], not adding to cart.");
1327: }
1328:
1329: if (priceResult.get("listPrice") != null) {
1330: this .listPrice = ((Double) priceResult
1331: .get("listPrice")).doubleValue();
1332: }
1333:
1334: if (priceResult.get("basePrice") != null) {
1335: this .setBasePrice(((Double) priceResult
1336: .get("basePrice")).doubleValue());
1337: }
1338:
1339: if (priceResult.get("price") != null) {
1340: this .setDisplayPrice(((Double) priceResult
1341: .get("price")).doubleValue());
1342: }
1343:
1344: this .setSpecialPromoPrice((Double) priceResult
1345: .get("specialPromoPrice"));
1346:
1347: this .orderItemPriceInfos = (List) priceResult
1348: .get("orderItemPriceInfos");
1349:
1350: // If product is configurable, the price is taken from the configWrapper.
1351: if (configWrapper != null) {
1352: // TODO: for configurable products need to do something to make them VAT aware... for now base and display prices are the same
1353: this
1354: .setBasePrice(configWrapper
1355: .getTotalPrice());
1356: this .setDisplayPrice(configWrapper
1357: .getTotalPrice());
1358: }
1359:
1360: // no try to do a recurring price calculation; not all products have recurring prices so may be null
1361: Map recurringPriceContext = FastMap.newInstance();
1362: recurringPriceContext.putAll(priceContext);
1363: recurringPriceContext.put("productPricePurposeId",
1364: "RECURRING_CHARGE");
1365: Map recurringPriceResult = dispatcher.runSync(
1366: "calculateProductPrice",
1367: recurringPriceContext);
1368: if (ServiceUtil.isError(recurringPriceResult)) {
1369: throw new CartItemModifyException(
1370: "There was an error while calculating the price: "
1371: + ServiceUtil
1372: .getErrorMessage(recurringPriceResult));
1373: }
1374:
1375: // for the recurring price only set the values iff validPriceFound is true
1376: Boolean validRecurringPriceFound = (Boolean) recurringPriceResult
1377: .get("validPriceFound");
1378: if (Boolean.TRUE.equals(validRecurringPriceFound)) {
1379: if (recurringPriceResult.get("basePrice") != null) {
1380: this
1381: .setRecurringBasePrice((Double) recurringPriceResult
1382: .get("basePrice"));
1383: }
1384: if (recurringPriceResult.get("price") != null) {
1385: this
1386: .setRecurringDisplayPrice((Double) recurringPriceResult
1387: .get("price"));
1388: }
1389: }
1390: }
1391: } catch (GenericServiceException e) {
1392: throw new CartItemModifyException(
1393: "There was an error while calculating the price",
1394: e);
1395: }
1396: }
1397: }
1398:
1399: /** Returns the quantity. */
1400: public double getQuantity() {
1401: return this .quantity;
1402: }
1403:
1404: /** Returns the reservation start date. */
1405: public Timestamp getReservStart() {
1406: return this .getReservStart(0);
1407: }
1408:
1409: /** Returns the reservation start date with a number of days added. */
1410: public Timestamp getReservStart(double addDays) {
1411: if (addDays == 0)
1412: return this .reservStart;
1413: else {
1414: if (this .reservStart != null)
1415: return new Timestamp(
1416: (long) (this .reservStart.getTime() + (addDays * 86400000.0)));
1417: else
1418: return null;
1419: }
1420: }
1421:
1422: /** Returns the reservation length. */
1423: public double getReservLength() {
1424: return this .reservLength;
1425: }
1426:
1427: /** Returns the reservation number of persons. */
1428: public double getReservPersons() {
1429: return this .reservPersons;
1430: }
1431:
1432: public double getPromoQuantityUsed() {
1433: if (this .getIsPromo()) {
1434: return this .quantity;
1435: } else {
1436: return this .promoQuantityUsed;
1437: }
1438: }
1439:
1440: public double getPromoQuantityAvailable() {
1441: if (this .getIsPromo()) {
1442: return 0;
1443: } else {
1444: return this .quantity - this .promoQuantityUsed;
1445: }
1446: }
1447:
1448: public Iterator getQuantityUsedPerPromoActualIter() {
1449: return this .quantityUsedPerPromoActual.entrySet().iterator();
1450: }
1451:
1452: public Iterator getQuantityUsedPerPromoCandidateIter() {
1453: return this .quantityUsedPerPromoCandidate.entrySet().iterator();
1454: }
1455:
1456: public Iterator getQuantityUsedPerPromoFailedIter() {
1457: return this .quantityUsedPerPromoFailed.entrySet().iterator();
1458: }
1459:
1460: public synchronized double addPromoQuantityCandidateUse(
1461: double quantityDesired,
1462: GenericValue productPromoCondAction,
1463: boolean checkAvailableOnly) {
1464: if (quantityDesired == 0)
1465: return 0;
1466: double promoQuantityAvailable = this
1467: .getPromoQuantityAvailable();
1468: double promoQuantityToUse = quantityDesired;
1469: if (promoQuantityAvailable > 0) {
1470: if (promoQuantityToUse > promoQuantityAvailable) {
1471: promoQuantityToUse = promoQuantityAvailable;
1472: }
1473:
1474: if (!checkAvailableOnly) {
1475: // keep track of candidate promo uses on cartItem
1476: GenericPK productPromoCondActionPK = productPromoCondAction
1477: .getPrimaryKey();
1478: Double existingValue = (Double) this .quantityUsedPerPromoCandidate
1479: .get(productPromoCondActionPK);
1480: if (existingValue == null) {
1481: this .quantityUsedPerPromoCandidate.put(
1482: productPromoCondActionPK, new Double(
1483: promoQuantityToUse));
1484: } else {
1485: this .quantityUsedPerPromoCandidate.put(
1486: productPromoCondActionPK, new Double(
1487: promoQuantityToUse
1488: + existingValue
1489: .doubleValue()));
1490: }
1491:
1492: this .promoQuantityUsed += promoQuantityToUse;
1493: //Debug.logInfo("promoQuantityToUse=" + promoQuantityToUse + ", quantityDesired=" + quantityDesired + ", for promoCondAction: " + productPromoCondAction, module);
1494: //Debug.logInfo("promoQuantityUsed now=" + promoQuantityUsed, module);
1495: }
1496:
1497: return promoQuantityToUse;
1498: } else {
1499: return 0;
1500: }
1501: }
1502:
1503: public double getPromoQuantityCandidateUse(
1504: GenericValue productPromoCondAction) {
1505: GenericPK productPromoCondActionPK = productPromoCondAction
1506: .getPrimaryKey();
1507: Double existingValue = (Double) this .quantityUsedPerPromoCandidate
1508: .get(productPromoCondActionPK);
1509: if (existingValue == null) {
1510: return 0;
1511: } else {
1512: return existingValue.doubleValue();
1513: }
1514: }
1515:
1516: public double getPromoQuantityCandidateUseActionAndAllConds(
1517: GenericValue productPromoAction) {
1518: double totalUse = 0;
1519: String productPromoId = productPromoAction
1520: .getString("productPromoId");
1521: String productPromoRuleId = productPromoAction
1522: .getString("productPromoRuleId");
1523:
1524: GenericPK productPromoActionPK = productPromoAction
1525: .getPrimaryKey();
1526: Double existingValue = (Double) this .quantityUsedPerPromoCandidate
1527: .get(productPromoActionPK);
1528: if (existingValue != null) {
1529: totalUse = existingValue.doubleValue();
1530: }
1531:
1532: Iterator entryIter = this .quantityUsedPerPromoCandidate
1533: .entrySet().iterator();
1534: while (entryIter.hasNext()) {
1535: Map.Entry entry = (Map.Entry) entryIter.next();
1536: GenericPK productPromoCondActionPK = (GenericPK) entry
1537: .getKey();
1538: Double quantityUsed = (Double) entry.getValue();
1539: if (quantityUsed != null) {
1540: // must be in the same rule and be a condition
1541: if (productPromoId.equals(productPromoCondActionPK
1542: .getString("productPromoId"))
1543: && productPromoRuleId
1544: .equals(productPromoCondActionPK
1545: .getString("productPromoRuleId"))
1546: && productPromoCondActionPK
1547: .containsKey("productPromoCondSeqId")) {
1548: totalUse += quantityUsed.doubleValue();
1549: }
1550: }
1551: }
1552:
1553: return totalUse;
1554: }
1555:
1556: public synchronized void resetPromoRuleUse(String productPromoId,
1557: String productPromoRuleId) {
1558: Iterator entryIter = this .quantityUsedPerPromoCandidate
1559: .entrySet().iterator();
1560: while (entryIter.hasNext()) {
1561: Map.Entry entry = (Map.Entry) entryIter.next();
1562: GenericPK productPromoCondActionPK = (GenericPK) entry
1563: .getKey();
1564: Double quantityUsed = (Double) entry.getValue();
1565: if (productPromoId.equals(productPromoCondActionPK
1566: .getString("productPromoId"))
1567: && productPromoRuleId
1568: .equals(productPromoCondActionPK
1569: .getString("productPromoRuleId"))) {
1570: entryIter.remove();
1571: Double existingValue = (Double) this .quantityUsedPerPromoFailed
1572: .get(productPromoCondActionPK);
1573: if (existingValue == null) {
1574: this .quantityUsedPerPromoFailed.put(
1575: productPromoCondActionPK, quantityUsed);
1576: } else {
1577: this .quantityUsedPerPromoFailed.put(
1578: productPromoCondActionPK, new Double(
1579: quantityUsed.doubleValue()
1580: + existingValue
1581: .doubleValue()));
1582: }
1583: this .promoQuantityUsed -= quantityUsed.doubleValue();
1584: }
1585: }
1586: }
1587:
1588: public synchronized void confirmPromoRuleUse(String productPromoId,
1589: String productPromoRuleId) {
1590: Iterator entryIter = this .quantityUsedPerPromoCandidate
1591: .entrySet().iterator();
1592: while (entryIter.hasNext()) {
1593: Map.Entry entry = (Map.Entry) entryIter.next();
1594: GenericPK productPromoCondActionPK = (GenericPK) entry
1595: .getKey();
1596: Double quantityUsed = (Double) entry.getValue();
1597: if (productPromoId.equals(productPromoCondActionPK
1598: .getString("productPromoId"))
1599: && productPromoRuleId
1600: .equals(productPromoCondActionPK
1601: .getString("productPromoRuleId"))) {
1602: entryIter.remove();
1603: Double existingValue = (Double) this .quantityUsedPerPromoActual
1604: .get(productPromoCondActionPK);
1605: if (existingValue == null) {
1606: this .quantityUsedPerPromoActual.put(
1607: productPromoCondActionPK, quantityUsed);
1608: } else {
1609: this .quantityUsedPerPromoActual.put(
1610: productPromoCondActionPK, new Double(
1611: quantityUsed.doubleValue()
1612: + existingValue
1613: .doubleValue()));
1614: }
1615: }
1616: }
1617: }
1618:
1619: public synchronized void clearPromoRuleUseInfo() {
1620: this .quantityUsedPerPromoActual.clear();
1621: this .quantityUsedPerPromoCandidate.clear();
1622: this .quantityUsedPerPromoFailed.clear();
1623: this .promoQuantityUsed = this .getIsPromo() ? this .quantity : 0;
1624: }
1625:
1626: /** Sets the item comment. */
1627: public void setItemComment(String itemComment) {
1628: this .setAttribute("itemComment", itemComment);
1629: }
1630:
1631: /** Returns the item's comment. */
1632: public String getItemComment() {
1633: return (String) this .getAttribute("itemComment");
1634: }
1635:
1636: /** Sets the item's customer desired delivery date. */
1637: public void setDesiredDeliveryDate(Timestamp ddDate) {
1638: if (ddDate != null) {
1639: this .setAttribute("itemDesiredDeliveryDate", ddDate
1640: .toString());
1641: }
1642: }
1643:
1644: /** Returns the item's customer desired delivery date. */
1645: public Timestamp getDesiredDeliveryDate() {
1646: String ddDate = (String) this
1647: .getAttribute("itemDesiredDeliveryDate");
1648:
1649: if (ddDate != null) {
1650: try {
1651: return Timestamp.valueOf(ddDate);
1652: } catch (IllegalArgumentException e) {
1653: Debug
1654: .logWarning(
1655: e,
1656: UtilProperties
1657: .getMessage(
1658: resource_error,
1659: "OrderProblemGettingItemDesiredDeliveryDateFor",
1660: UtilMisc
1661: .toMap(
1662: "productId",
1663: this
1664: .getProductId()),
1665: locale));
1666: return null;
1667: }
1668: }
1669: return null;
1670: }
1671:
1672: /** Sets the date to ship before */
1673: public void setShipBeforeDate(Timestamp date) {
1674: this .shipBeforeDate = date;
1675:
1676: }
1677:
1678: /** Returns the date to ship before */
1679: public Timestamp getShipBeforeDate() {
1680: return this .shipBeforeDate;
1681: }
1682:
1683: /** Sets the date to ship after */
1684: public void setShipAfterDate(Timestamp date) {
1685: this .shipAfterDate = date;
1686: }
1687:
1688: /** Returns the date to ship after */
1689: public Timestamp getShipAfterDate() {
1690: return this .shipAfterDate;
1691: }
1692:
1693: /** Sets the item type. */
1694: public void setItemType(String itemType) {
1695: this .itemType = itemType;
1696: }
1697:
1698: /** Returns the item type. */
1699: public String getItemType() {
1700: return this .itemType;
1701: }
1702:
1703: /** Returns the item type. */
1704: public GenericValue getItemTypeGenericValue() {
1705: try {
1706: return this .getDelegator().findByPrimaryKeyCache(
1707: "OrderItemType",
1708: UtilMisc.toMap("orderItemTypeId", this .itemType));
1709: } catch (GenericEntityException e) {
1710: Debug.logError(e,
1711: "Error getting ShippingCartItem's OrderItemType",
1712: module);
1713: return null;
1714: }
1715: }
1716:
1717: /** Sets the item group. */
1718: public void setItemGroup(
1719: ShoppingCart.ShoppingCartItemGroup itemGroup) {
1720: this .itemGroup = itemGroup;
1721: }
1722:
1723: /** Sets the item group. */
1724: public void setItemGroup(String groupNumber, ShoppingCart cart) {
1725: this .itemGroup = cart.getItemGroupByNumber(groupNumber);
1726: }
1727:
1728: /** Returns the item group. */
1729: public ShoppingCart.ShoppingCartItemGroup getItemGroup() {
1730: return this .itemGroup;
1731: }
1732:
1733: public boolean isInItemGroup(String groupNumber) {
1734: if (this .itemGroup == null)
1735: return false;
1736: if (this .itemGroup.getGroupNumber().equals(groupNumber))
1737: return true;
1738: return false;
1739: }
1740:
1741: /** Returns the item type description. */
1742: public String getItemTypeDescription() {
1743: GenericValue orderItemType = null;
1744: if (this .getItemType() != null) {
1745: try {
1746: orderItemType = this .getDelegator()
1747: .findByPrimaryKeyCache(
1748: "OrderItemType",
1749: UtilMisc.toMap("orderItemTypeId", this
1750: .getItemType()));
1751: } catch (GenericEntityException e) {
1752: Debug.logWarning(e, UtilProperties.getMessage(
1753: resource_error,
1754: "OrderProblemsGettingOrderItemTypeFor",
1755: UtilMisc.toMap("orderItemTypeId", this
1756: .getItemType()), locale));
1757: }
1758: }
1759: if (orderItemType != null) {
1760: return orderItemType.getString("description");
1761: }
1762: return null;
1763: }
1764:
1765: /** Returns the productCategoryId for the item or null if none. */
1766: public String getProductCategoryId() {
1767: return this .productCategoryId;
1768: }
1769:
1770: public void setProductCategoryId(String productCategoryId) {
1771: this .productCategoryId = productCategoryId;
1772: }
1773:
1774: public void setOrderItemSeqId(String orderItemSeqId) {
1775: Debug.log("Setting orderItemSeqId - " + orderItemSeqId, module);
1776: this .orderItemSeqId = orderItemSeqId;
1777: }
1778:
1779: public String getOrderItemSeqId() {
1780: return orderItemSeqId;
1781: }
1782:
1783: public void setShoppingList(String shoppingListId, String itemSeqId) {
1784: attributes.put("shoppingListId", shoppingListId);
1785: attributes.put("shoppingListItemSeqId", itemSeqId);
1786: }
1787:
1788: public String getShoppingListId() {
1789: return (String) attributes.get("shoppingListId");
1790: }
1791:
1792: public String getShoppingListItemSeqId() {
1793: return (String) attributes.get("shoppingListItemSeqId");
1794: }
1795:
1796: /** Sets the requirementId. */
1797: public void setRequirementId(String requirementId) {
1798: this .requirementId = requirementId;
1799: }
1800:
1801: /** Returns the requirementId. */
1802: public String getRequirementId() {
1803: return this .requirementId;
1804: }
1805:
1806: /** Sets the quoteId. */
1807: public void setQuoteId(String quoteId) {
1808: this .quoteId = quoteId;
1809: }
1810:
1811: /** Returns the quoteId. */
1812: public String getQuoteId() {
1813: return this .quoteId;
1814: }
1815:
1816: /** Sets the quoteItemSeqId. */
1817: public void setQuoteItemSeqId(String quoteItemSeqId) {
1818: this .quoteItemSeqId = quoteItemSeqId;
1819: }
1820:
1821: /** Returns the quoteItemSeqId. */
1822: public String getQuoteItemSeqId() {
1823: return this .quoteItemSeqId;
1824: }
1825:
1826: /** Sets the orderItemAssocTypeId. */
1827: public void setOrderItemAssocTypeId(String orderItemAssocTypeId) {
1828: if (orderItemAssocTypeId != null) {
1829: this .orderItemAssocTypeId = orderItemAssocTypeId;
1830: }
1831: }
1832:
1833: /** Returns the OrderItemAssocTypeId. */
1834: public String getOrderItemAssocTypeId() {
1835: return this .orderItemAssocTypeId;
1836: }
1837:
1838: /** Sets the associatedOrderId. */
1839: public void setAssociatedOrderId(String associatedOrderId) {
1840: this .associatedOrderId = associatedOrderId;
1841: }
1842:
1843: /** Returns the associatedId. */
1844: public String getAssociatedOrderId() {
1845: return this .associatedOrderId;
1846: }
1847:
1848: /** Sets the associatedOrderItemSeqId. */
1849: public void setAssociatedOrderItemSeqId(
1850: String associatedOrderItemSeqId) {
1851: this .associatedOrderItemSeqId = associatedOrderItemSeqId;
1852: }
1853:
1854: /** Returns the associatedOrderItemSeqId. */
1855: public String getAssociatedOrderItemSeqId() {
1856: return this .associatedOrderItemSeqId;
1857: }
1858:
1859: public String getStatusId() {
1860: return this .statusId;
1861: }
1862:
1863: public void setStatusId(String statusId) {
1864: this .statusId = statusId;
1865: }
1866:
1867: /** Returns true if shipping charges apply to this item. */
1868: public boolean shippingApplies() {
1869: GenericValue product = getProduct();
1870: if (product != null) {
1871: return ProductWorker.shippingApplies(product);
1872: } else {
1873: // we don't ship non-product items
1874: return false;
1875: }
1876: }
1877:
1878: /** Returns true if tax charges apply to this item. */
1879: public boolean taxApplies() {
1880: GenericValue product = getProduct();
1881: if (product != null) {
1882: return ProductWorker.taxApplies(product);
1883: } else {
1884: // we do tax non-product items
1885: return true;
1886: }
1887: }
1888:
1889: /** Returns the item's productId. */
1890: public String getProductId() {
1891: return productId;
1892: }
1893:
1894: /** Set the item's description. */
1895: public void setName(String itemName) {
1896: this .itemDescription = itemName;
1897: }
1898:
1899: /** Returns the item's description. */
1900: public String getName() {
1901: if (itemDescription != null) {
1902: return itemDescription;
1903: } else {
1904: GenericValue product = getProduct();
1905: if (product != null) {
1906: String productName = ProductContentWrapper
1907: .getProductContentAsText(product,
1908: "PRODUCT_NAME", this .locale, null);
1909: // if the productName is null or empty, see if there is an associated virtual product and get the productName of that product
1910: if (UtilValidate.isEmpty(productName)) {
1911: GenericValue parentProduct = this
1912: .getParentProduct();
1913: if (parentProduct != null) {
1914: productName = ProductContentWrapper
1915: .getProductContentAsText(parentProduct,
1916: "PRODUCT_NAME", this .locale,
1917: null);
1918: }
1919: }
1920: if (productName == null) {
1921: return "";
1922: } else {
1923: return productName;
1924: }
1925: } else {
1926: return "";
1927: }
1928: }
1929: }
1930:
1931: /** Returns the item's description. */
1932: public String getDescription() {
1933: GenericValue product = getProduct();
1934:
1935: if (product != null) {
1936: String description = ProductContentWrapper
1937: .getProductContentAsText(product, "DESCRIPTION",
1938: this .locale, null);
1939:
1940: // if the description is null or empty, see if there is an associated virtual product and get the description of that product
1941: if (UtilValidate.isEmpty(description)) {
1942: GenericValue parentProduct = this .getParentProduct();
1943: if (parentProduct != null) {
1944: description = ProductContentWrapper
1945: .getProductContentAsText(parentProduct,
1946: "DESCRIPTION", this .locale, null);
1947: }
1948: }
1949:
1950: if (description == null) {
1951: return "";
1952: } else {
1953: return description;
1954: }
1955: } else {
1956: return null;
1957: }
1958: }
1959:
1960: public ProductConfigWrapper getConfigWrapper() {
1961: return configWrapper;
1962: }
1963:
1964: /** Returns the item's unit weight */
1965: public double getWeight() {
1966: GenericValue product = getProduct();
1967: if (product != null) {
1968: Double weight = product.getDouble("weight");
1969:
1970: // if the weight is null, see if there is an associated virtual product and get the weight of that product
1971: if (weight == null) {
1972: GenericValue parentProduct = this .getParentProduct();
1973: if (parentProduct != null)
1974: weight = parentProduct.getDouble("weight");
1975: }
1976:
1977: if (weight == null) {
1978: return 0;
1979: } else {
1980: return weight.doubleValue();
1981: }
1982: } else {
1983: // non-product items have 0 weight
1984: return 0;
1985: }
1986: }
1987:
1988: /** Returns the item's pieces included */
1989: public long getPiecesIncluded() {
1990: GenericValue product = getProduct();
1991: if (product != null) {
1992: Long pieces = product.getLong("piecesIncluded");
1993:
1994: // if the piecesIncluded is null, see if there is an associated virtual product and get the piecesIncluded of that product
1995: if (pieces == null) {
1996: GenericValue parentProduct = this .getParentProduct();
1997: if (parentProduct != null)
1998: pieces = parentProduct.getLong("piecesIncluded");
1999: }
2000:
2001: if (pieces == null) {
2002: return 1;
2003: } else {
2004: return pieces.longValue();
2005: }
2006: } else {
2007: // non-product item assumed 1 piece
2008: return 1;
2009: }
2010: }
2011:
2012: /** Returns a Set of the item's features */
2013: public Set getFeatureSet() {
2014: Set featureSet = new ListOrderedSet();
2015: GenericValue product = this .getProduct();
2016: if (product != null) {
2017: List featureAppls = null;
2018: try {
2019: featureAppls = product.getRelated("ProductFeatureAppl");
2020: List filterExprs = UtilMisc.toList(new EntityExpr(
2021: "productFeatureApplTypeId",
2022: EntityOperator.EQUALS, "STANDARD_FEATURE"));
2023: filterExprs.add(new EntityExpr(
2024: "productFeatureApplTypeId",
2025: EntityOperator.EQUALS, "REQUIRED_FEATURE"));
2026: featureAppls = EntityUtil.filterByOr(featureAppls,
2027: filterExprs);
2028: } catch (GenericEntityException e) {
2029: Debug.logError(e,
2030: "Unable to get features from product : "
2031: + product.get("productId"), module);
2032: }
2033: if (featureAppls != null) {
2034: Iterator fai = featureAppls.iterator();
2035: while (fai.hasNext()) {
2036: GenericValue appl = (GenericValue) fai.next();
2037: featureSet.add(appl.getString("productFeatureId"));
2038: }
2039: }
2040: }
2041: if (this .additionalProductFeatureAndAppls != null) {
2042: Iterator aapi = this .additionalProductFeatureAndAppls
2043: .values().iterator();
2044: while (aapi.hasNext()) {
2045: GenericValue appl = (GenericValue) aapi.next();
2046: featureSet.add(appl.getString("productFeatureId"));
2047: }
2048: }
2049: return featureSet;
2050: }
2051:
2052: /** Returns a list of the item's standard features */
2053: public List getStandardFeatureList() {
2054: List features = null;
2055: GenericValue product = this .getProduct();
2056: if (product != null) {
2057: try {
2058: List featureAppls = product
2059: .getRelated("ProductFeatureAndAppl");
2060: features = EntityUtil.filterByAnd(featureAppls,
2061: UtilMisc.toMap("productFeatureApplTypeId",
2062: "STANDARD_FEATURE"));
2063: } catch (GenericEntityException e) {
2064: Debug.logError(e,
2065: "Unable to get features from product : "
2066: + product.get("productId"), module);
2067: }
2068: }
2069: return features;
2070: }
2071:
2072: /** Returns a List of the item's features for supplier*/
2073: public List getFeaturesForSupplier(LocalDispatcher dispatcher,
2074: String partyId) {
2075: List featureAppls = getStandardFeatureList();
2076: if (featureAppls != null && featureAppls.size() > 0) {
2077: try {
2078: Map result = dispatcher.runSync(
2079: "convertFeaturesForSupplier", UtilMisc.toMap(
2080: "partyId", partyId, "productFeatures",
2081: featureAppls));
2082: featuresForSupplier = (List) result
2083: .get("convertedProductFeatures");
2084: } catch (GenericServiceException e) {
2085: Debug.logError(e,
2086: "Unable to get features for supplier from product : "
2087: + this .productId, module);
2088: }
2089: }
2090: return featuresForSupplier;
2091: }
2092:
2093: /** Returns the item's size (length + girth) */
2094: public double getSize() {
2095: GenericValue product = getProduct();
2096: if (product != null) {
2097: Double height = product.getDouble("shippingHeight");
2098: Double width = product.getDouble("shippingWidth");
2099: Double depth = product.getDouble("shippingDepth");
2100:
2101: // if all are null, see if there is an associated virtual product and get the info of that product
2102: if (height == null && width == null && depth == null) {
2103: GenericValue parentProduct = this .getParentProduct();
2104: if (parentProduct != null) {
2105: height = parentProduct.getDouble("shippingHeight");
2106: width = parentProduct.getDouble("shippingWidth");
2107: depth = parentProduct.getDouble("shippingDepth");
2108: }
2109: }
2110:
2111: if (height == null)
2112: height = new Double(0);
2113: if (width == null)
2114: width = new Double(0);
2115: if (depth == null)
2116: depth = new Double(0);
2117:
2118: // determine girth (longest field is length)
2119: double[] sizeInfo = { height.doubleValue(),
2120: width.doubleValue(), depth.doubleValue() };
2121: Arrays.sort(sizeInfo);
2122:
2123: return (sizeInfo[0] * 2) + (sizeInfo[1] * 2) + sizeInfo[2];
2124: } else {
2125: // non-product items have 0 size
2126: return 0;
2127: }
2128: }
2129:
2130: public Map getItemProductInfo() {
2131: Map itemInfo = FastMap.newInstance();
2132: itemInfo.put("productId", this .getProductId());
2133: itemInfo.put("weight", new Double(this .getWeight()));
2134: itemInfo.put("size", new Double(this .getSize()));
2135: itemInfo.put("piecesIncluded", new Long(this
2136: .getPiecesIncluded()));
2137: itemInfo.put("featureSet", this .getFeatureSet());
2138: GenericValue product = getProduct();
2139: if (product != null) {
2140: itemInfo.put("inShippingBox", product
2141: .getString("inShippingBox"));
2142: if (product.getString("inShippingBox") != null
2143: && product.getString("inShippingBox").equals("Y")) {
2144: itemInfo.put("shippingHeight", product
2145: .getDouble("shippingHeight"));
2146: itemInfo.put("shippingWidth", product
2147: .getDouble("shippingWidth"));
2148: itemInfo.put("shippingDepth", product
2149: .getDouble("shippingDepth"));
2150: }
2151: }
2152: return itemInfo;
2153: }
2154:
2155: /** Returns the base price. */
2156: public double getBasePrice() {
2157: double curBasePrice;
2158: if (selectedAmount > 0) {
2159: curBasePrice = basePrice * selectedAmount;
2160: } else {
2161: curBasePrice = basePrice;
2162: }
2163: return curBasePrice;
2164: }
2165:
2166: public double getDisplayPrice() {
2167: double curDisplayPrice;
2168: if (this .displayPrice == null) {
2169: curDisplayPrice = this .getBasePrice();
2170: } else {
2171: if (selectedAmount > 0) {
2172: curDisplayPrice = this .displayPrice.doubleValue()
2173: * this .selectedAmount;
2174: } else {
2175: curDisplayPrice = this .displayPrice.doubleValue();
2176: }
2177: }
2178: return curDisplayPrice;
2179: }
2180:
2181: public Double getSpecialPromoPrice() {
2182: return this .specialPromoPrice;
2183: }
2184:
2185: public Double getRecurringBasePrice() {
2186: if (this .recurringBasePrice == null)
2187: return null;
2188:
2189: if (selectedAmount > 0) {
2190: return new Double(this .recurringBasePrice.doubleValue()
2191: * selectedAmount);
2192: } else {
2193: return this .recurringBasePrice;
2194: }
2195: }
2196:
2197: public Double getRecurringDisplayPrice() {
2198: if (this .recurringDisplayPrice == null) {
2199: return this .getRecurringBasePrice();
2200: }
2201:
2202: if (selectedAmount > 0) {
2203: return new Double(this .recurringDisplayPrice.doubleValue()
2204: * this .selectedAmount);
2205: } else {
2206: return this .recurringDisplayPrice;
2207: }
2208: }
2209:
2210: /** Returns the list price. */
2211: public double getListPrice() {
2212: return listPrice;
2213: }
2214:
2215: /** Returns isModifiedPrice */
2216: public boolean getIsModifiedPrice() {
2217: return isModifiedPrice;
2218: }
2219:
2220: /** Set isModifiedPrice */
2221: public void setIsModifiedPrice(boolean isModifiedPrice) {
2222: this .isModifiedPrice = isModifiedPrice;
2223: }
2224:
2225: /** get the percentage for the second person */
2226: public double getReserv2ndPPPerc() {
2227: return reserv2ndPPPerc;
2228: }
2229:
2230: /** get the percentage for the third and following person */
2231: public double getReservNthPPPerc() {
2232: return reservNthPPPerc;
2233: }
2234:
2235: /** Returns the "other" adjustments. */
2236: public double getOtherAdjustments() {
2237: return OrderReadHelper.calcItemAdjustmentsBd(
2238: new BigDecimal(quantity),
2239: new BigDecimal(getBasePrice()), this .getAdjustments(),
2240: true, false, false, false, false).doubleValue();
2241: }
2242:
2243: /** Returns the "other" adjustments. */
2244: public double getOtherAdjustmentsRecurring() {
2245: return OrderReadHelper
2246: .calcItemAdjustmentsRecurringBd(
2247: new BigDecimal(quantity),
2248: new BigDecimal(
2249: getRecurringBasePrice() == null ? 0.0
2250: : getRecurringBasePrice()
2251: .doubleValue()),
2252: this .getAdjustments(), true, false, false,
2253: false, false).doubleValue();
2254: }
2255:
2256: /** calculates for a reservation the percentage/100 extra for more than 1 person. */
2257: // similar code at editShoppingList.bsh
2258: public double getRentalAdjustment() {
2259: if (!"RENTAL_ORDER_ITEM".equals(this .itemType)) {
2260: // not a rental item?
2261: return 1;
2262: }
2263: double persons = this .getReservPersons();
2264: double rentalValue = 0;
2265: if (persons > 1) {
2266: if (persons > 2) {
2267: persons -= 2;
2268: if (getReservNthPPPerc() > 0) {
2269: rentalValue = persons * getReservNthPPPerc();
2270: } else {
2271: rentalValue = persons * getReserv2ndPPPerc();
2272: }
2273: persons = 2;
2274: }
2275: if (persons == 2) {
2276: rentalValue += getReserv2ndPPPerc();
2277: }
2278: }
2279: rentalValue += 100; // add final 100 percent for first person
2280: // Debug.log("rental parameters....Nbr of persons:" + getReservPersons() + " extra% 2nd person:" + getReserv2ndPPPerc()+ " extra% Nth person:" + getReservNthPPPerc() + " total rental adjustment:" + rentalValue/100 * getReservLength() );
2281: return rentalValue / 100 * getReservLength(); // return total rental adjustment
2282: }
2283:
2284: /** Returns the total line price. */
2285: public double getItemSubTotal(double quantity) {
2286: // Debug.logInfo("Price" + getBasePrice() + " quantity" + quantity + " Rental adj:" + getRentalAdjustment() + " other adj:" + getOtherAdjustments(), module);
2287: return (getBasePrice() * quantity * getRentalAdjustment())
2288: + getOtherAdjustments();
2289: }
2290:
2291: public double getItemSubTotal() {
2292: return this .getItemSubTotal(this .getQuantity());
2293: }
2294:
2295: public double getDisplayItemSubTotal() {
2296: return (this .getDisplayPrice() * this .getQuantity() * this
2297: .getRentalAdjustment())
2298: + this .getOtherAdjustments();
2299: }
2300:
2301: public double getDisplayItemSubTotalNoAdj() {
2302: return this .getDisplayPrice() * this .getQuantity();
2303: }
2304:
2305: public double getDisplayItemRecurringSubTotal() {
2306: Double curRecurringDisplayPrice = this
2307: .getRecurringDisplayPrice();
2308:
2309: if (curRecurringDisplayPrice == null) {
2310: return this .getOtherAdjustmentsRecurring();
2311: }
2312:
2313: return (curRecurringDisplayPrice.doubleValue() * this
2314: .getQuantity())
2315: + this .getOtherAdjustmentsRecurring();
2316: }
2317:
2318: public double getDisplayItemRecurringSubTotalNoAdj() {
2319: Double curRecurringDisplayPrice = this
2320: .getRecurringDisplayPrice();
2321: if (curRecurringDisplayPrice == null)
2322: return 0.0;
2323:
2324: return curRecurringDisplayPrice.doubleValue()
2325: * this .getQuantity();
2326: }
2327:
2328: public void addAllProductFeatureAndAppls(
2329: Map productFeatureAndApplsToAdd) {
2330: if (productFeatureAndApplsToAdd == null)
2331: return;
2332: Iterator productFeatureAndApplsToAddIter = productFeatureAndApplsToAdd
2333: .values().iterator();
2334: while (productFeatureAndApplsToAddIter.hasNext()) {
2335: GenericValue additionalProductFeatureAndAppl = (GenericValue) productFeatureAndApplsToAddIter
2336: .next();
2337: this
2338: .putAdditionalProductFeatureAndAppl(additionalProductFeatureAndAppl);
2339: }
2340: }
2341:
2342: public void putAdditionalProductFeatureAndAppl(
2343: GenericValue additionalProductFeatureAndAppl) {
2344: if (additionalProductFeatureAndAppl == null)
2345: return;
2346:
2347: // if one already exists with the given type, remove it with the corresponding adjustment
2348: removeAdditionalProductFeatureAndAppl(additionalProductFeatureAndAppl
2349: .getString("productFeatureTypeId"));
2350:
2351: // adds to additional map and creates an adjustment with given price
2352: String featureType = additionalProductFeatureAndAppl
2353: .getString("productFeatureTypeId");
2354: this .additionalProductFeatureAndAppls.put(featureType,
2355: additionalProductFeatureAndAppl);
2356:
2357: GenericValue orderAdjustment = this .getDelegator().makeValue(
2358: "OrderAdjustment", null);
2359: orderAdjustment.set("orderAdjustmentTypeId",
2360: "ADDITIONAL_FEATURE");
2361: orderAdjustment.set("description",
2362: additionalProductFeatureAndAppl.get("description"));
2363: orderAdjustment
2364: .set("productFeatureId",
2365: additionalProductFeatureAndAppl
2366: .get("productFeatureId"));
2367:
2368: // NOTE: this is a VERY simple pricing scheme for additional features and will likely need to be extended for most real applications
2369: double amount = 0;
2370: Double amountDbl = (Double) additionalProductFeatureAndAppl
2371: .get("amount");
2372: if (amountDbl != null) {
2373: amount = amountDbl.doubleValue() * this .getQuantity();
2374: }
2375: orderAdjustment.set("amount", new Double(amount));
2376:
2377: Double recurringAmountDbl = (Double) additionalProductFeatureAndAppl
2378: .get("recurringAmount");
2379: if (recurringAmountDbl != null) {
2380: double recurringAmount = recurringAmountDbl.doubleValue()
2381: * this .getQuantity();
2382: orderAdjustment.set("recurringAmount", new Double(
2383: recurringAmount));
2384: //Debug.logInfo("Setting recurringAmount " + recurringAmount + " for " + orderAdjustment, module);
2385: }
2386:
2387: this .addAdjustment(orderAdjustment);
2388: }
2389:
2390: public GenericValue getAdditionalProductFeatureAndAppl(
2391: String productFeatureTypeId) {
2392: if (this .additionalProductFeatureAndAppls == null)
2393: return null;
2394: return (GenericValue) this .additionalProductFeatureAndAppls
2395: .get(productFeatureTypeId);
2396: }
2397:
2398: public GenericValue removeAdditionalProductFeatureAndAppl(
2399: String productFeatureTypeId) {
2400: if (this .additionalProductFeatureAndAppls == null)
2401: return null;
2402:
2403: GenericValue oldAdditionalProductFeatureAndAppl = (GenericValue) this .additionalProductFeatureAndAppls
2404: .remove(productFeatureTypeId);
2405:
2406: if (oldAdditionalProductFeatureAndAppl != null) {
2407: removeFeatureAdjustment(oldAdditionalProductFeatureAndAppl
2408: .getString("productFeatureId"));
2409: }
2410:
2411: //if (this.additionalProductFeatureAndAppls.size() == 0) this.additionalProductFeatureAndAppls = null;
2412:
2413: return oldAdditionalProductFeatureAndAppl;
2414: }
2415:
2416: public Map getAdditionalProductFeatureAndAppls() {
2417: return this .additionalProductFeatureAndAppls;
2418: }
2419:
2420: public Map getFeatureIdQtyMap(double quantity) {
2421: Map featureMap = FastMap.newInstance();
2422: GenericValue product = this .getProduct();
2423: if (product != null) {
2424: List featureAppls = null;
2425: try {
2426: featureAppls = product.getRelated("ProductFeatureAppl");
2427: List filterExprs = UtilMisc.toList(new EntityExpr(
2428: "productFeatureApplTypeId",
2429: EntityOperator.EQUALS, "STANDARD_FEATURE"));
2430: filterExprs.add(new EntityExpr(
2431: "productFeatureApplTypeId",
2432: EntityOperator.EQUALS, "REQUIRED_FEATURE"));
2433: featureAppls = EntityUtil.filterByOr(featureAppls,
2434: filterExprs);
2435: } catch (GenericEntityException e) {
2436: Debug.logError(e,
2437: "Unable to get features from product : "
2438: + product.get("productId"), module);
2439: }
2440: if (featureAppls != null) {
2441: Iterator fai = featureAppls.iterator();
2442: while (fai.hasNext()) {
2443: GenericValue appl = (GenericValue) fai.next();
2444: Double lastQuantity = (Double) featureMap.get(appl
2445: .getString("productFeatureId"));
2446: if (lastQuantity == null) {
2447: lastQuantity = new Double(0);
2448: }
2449: Double newQuantity = new Double(lastQuantity
2450: .doubleValue()
2451: + quantity);
2452: featureMap.put(appl.getString("productFeatureId"),
2453: newQuantity);
2454: }
2455: }
2456: }
2457: if (this .additionalProductFeatureAndAppls != null) {
2458: Iterator aapi = this .additionalProductFeatureAndAppls
2459: .values().iterator();
2460: while (aapi.hasNext()) {
2461: GenericValue appl = (GenericValue) aapi.next();
2462: Double lastQuantity = (Double) featureMap.get(appl
2463: .getString("productFeatureId"));
2464: if (lastQuantity == null) {
2465: lastQuantity = new Double(0);
2466: }
2467: Double newQuantity = new Double(lastQuantity
2468: .doubleValue()
2469: + quantity);
2470: featureMap.put(appl.getString("productFeatureId"),
2471: newQuantity);
2472: }
2473: }
2474: return featureMap;
2475: }
2476:
2477: /** Removes an item attribute. */
2478: public void removeAttribute(String name) {
2479: attributes.remove(name);
2480: }
2481:
2482: /** Sets an item attribute. */
2483: public void setAttribute(String name, Object value) {
2484: attributes.put(name, value);
2485: }
2486:
2487: /** Return a specific attribute. */
2488: public Object getAttribute(String name) {
2489: return attributes.get(name);
2490: }
2491:
2492: /** Returns the attributes for the item. */
2493: public Map getAttributes() {
2494: return attributes;
2495: }
2496:
2497: /** Remove an OrderItemAttribute. */
2498: public void removeOrderItemAttribute(String name) {
2499: if (orderItemAttributes != null) {
2500: orderItemAttributes.remove(name);
2501: }
2502: }
2503:
2504: /** Creates an OrderItemAttribute entry. */
2505: public void setOrderItemAttribute(String name, String value) {
2506: if (orderItemAttributes == null)
2507: orderItemAttributes = FastMap.newInstance();
2508: this .orderItemAttributes.put(name, value);
2509: }
2510:
2511: /** Return an OrderItemAttribute. */
2512: public String getOrderItemAttribute(String name) {
2513: if (orderItemAttributes == null)
2514: return null;
2515: return (String) this .orderItemAttributes.get(name);
2516: }
2517:
2518: public Map getOrderItemAttributes() {
2519: Map attrs = FastMap.newInstance();
2520: if (orderItemAttributes != null) {
2521: attrs.putAll(orderItemAttributes);
2522: }
2523: return attrs;
2524: }
2525:
2526: /** 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 */
2527: public int addAdjustment(GenericValue adjustment) {
2528: itemAdjustments.add(adjustment);
2529: return itemAdjustments.indexOf(adjustment);
2530: }
2531:
2532: public void removeAdjustment(GenericValue adjustment) {
2533: itemAdjustments.remove(adjustment);
2534: }
2535:
2536: public void removeAdjustment(int index) {
2537: itemAdjustments.remove(index);
2538: }
2539:
2540: public List getAdjustments() {
2541: return itemAdjustments;
2542: }
2543:
2544: public void removeFeatureAdjustment(String productFeatureId) {
2545: if (productFeatureId == null)
2546: return;
2547: Iterator itemAdjustmentsIter = itemAdjustments.iterator();
2548:
2549: while (itemAdjustmentsIter.hasNext()) {
2550: GenericValue itemAdjustment = (GenericValue) itemAdjustmentsIter
2551: .next();
2552:
2553: if (productFeatureId.equals(itemAdjustment
2554: .getString("productFeatureId"))) {
2555: itemAdjustmentsIter.remove();
2556: }
2557: }
2558: }
2559:
2560: public List getOrderItemPriceInfos() {
2561: return orderItemPriceInfos;
2562: }
2563:
2564: /** Add a contact mech to this purpose; the contactMechPurposeTypeId is required */
2565: public void addContactMech(String contactMechPurposeTypeId,
2566: String contactMechId) {
2567: if (contactMechPurposeTypeId == null)
2568: throw new IllegalArgumentException(
2569: "You must specify a contactMechPurposeTypeId to add a ContactMech");
2570: contactMechIdsMap.put(contactMechPurposeTypeId, contactMechId);
2571: }
2572:
2573: /** Get the contactMechId for this item given the contactMechPurposeTypeId */
2574: public String getContactMech(String contactMechPurposeTypeId) {
2575: return (String) contactMechIdsMap.get(contactMechPurposeTypeId);
2576: }
2577:
2578: /** Remove the contactMechId from this item given the contactMechPurposeTypeId */
2579: public String removeContactMech(String contactMechPurposeTypeId) {
2580: return (String) contactMechIdsMap
2581: .remove(contactMechPurposeTypeId);
2582: }
2583:
2584: public Map getOrderItemContactMechIds() {
2585: return contactMechIdsMap;
2586: }
2587:
2588: public void setIsPromo(boolean isPromo) {
2589: this .isPromo = isPromo;
2590: }
2591:
2592: public boolean getIsPromo() {
2593: return this .isPromo;
2594: }
2595:
2596: public List getAlternativeOptionProductIds() {
2597: return this .alternativeOptionProductIds;
2598: }
2599:
2600: public void setAlternativeOptionProductIds(
2601: List alternativeOptionProductIds) {
2602: this .alternativeOptionProductIds = alternativeOptionProductIds;
2603: }
2604:
2605: /** Compares the specified object with this cart item. */
2606: public boolean equals(ShoppingCartItem item) {
2607: if (item == null)
2608: return false;
2609: return this .equals(item.getProductId(),
2610: item.additionalProductFeatureAndAppls, item.attributes,
2611: item.prodCatalogId, item.selectedAmount, item
2612: .getItemType(), item.getItemGroup(), item
2613: .getIsPromo());
2614: }
2615:
2616: /** Compares the specified object with this cart item. Defaults isPromo to false. Default to no itemGroup. */
2617: public boolean equals(String productId,
2618: Map additionalProductFeatureAndAppls, Map attributes,
2619: String prodCatalogId, double selectedAmount) {
2620: return equals(productId, additionalProductFeatureAndAppls,
2621: attributes, prodCatalogId, selectedAmount, null, null,
2622: false);
2623: }
2624:
2625: /** Compares the specified object with this cart item. Defaults isPromo to false. */
2626: public boolean equals(String productId,
2627: Map additionalProductFeatureAndAppls, Map attributes,
2628: String prodCatalogId, ProductConfigWrapper configWrapper,
2629: String itemType,
2630: ShoppingCart.ShoppingCartItemGroup itemGroup,
2631: double selectedAmount) {
2632: return equals(productId, null, 0.00, 0.00,
2633: additionalProductFeatureAndAppls, attributes,
2634: prodCatalogId, selectedAmount, configWrapper, itemType,
2635: itemGroup, false);
2636: }
2637:
2638: /** Compares the specified object with this cart item including rental data. Defaults isPromo to false. */
2639: public boolean equals(String productId, Timestamp reservStart,
2640: double reservLength, double reservPersons,
2641: Map additionalProductFeatureAndAppls, Map attributes,
2642: String prodCatalogId, ProductConfigWrapper configWrapper,
2643: String itemType,
2644: ShoppingCart.ShoppingCartItemGroup itemGroup,
2645: double selectedAmount) {
2646: return equals(productId, reservStart, reservLength,
2647: reservPersons, additionalProductFeatureAndAppls,
2648: attributes, prodCatalogId, selectedAmount,
2649: configWrapper, itemType, itemGroup, false);
2650: }
2651:
2652: /** Compares the specified object with this cart item. Defaults isPromo to false. */
2653: public boolean equals(String productId,
2654: Map additionalProductFeatureAndAppls, Map attributes,
2655: String prodCatalogId, double selectedAmount,
2656: String itemType,
2657: ShoppingCart.ShoppingCartItemGroup itemGroup,
2658: boolean isPromo) {
2659: return equals(productId, null, 0.00, 0.00,
2660: additionalProductFeatureAndAppls, attributes,
2661: prodCatalogId, selectedAmount, null, itemType,
2662: itemGroup, isPromo);
2663: }
2664:
2665: /** Compares the specified object with this cart item. */
2666: public boolean equals(String productId, Timestamp reservStart,
2667: double reservLength, double reservPersons,
2668: Map additionalProductFeatureAndAppls, Map attributes,
2669: String prodCatalogId, double selectedAmount,
2670: ProductConfigWrapper configWrapper, String itemType,
2671: ShoppingCart.ShoppingCartItemGroup itemGroup,
2672: boolean isPromo) {
2673: if (this .productId == null || productId == null) {
2674: // all non-product items are unique
2675: return false;
2676: }
2677: if (!this .productId.equals(productId)) {
2678: return false;
2679: }
2680:
2681: if ((this .prodCatalogId == null && prodCatalogId != null)
2682: || (this .prodCatalogId != null && prodCatalogId == null)) {
2683: return false;
2684: }
2685: if (this .prodCatalogId != null && prodCatalogId != null
2686: && !this .prodCatalogId.equals(prodCatalogId)) {
2687: return false;
2688: }
2689:
2690: if (this .getSelectedAmount() != selectedAmount) {
2691: return false;
2692: }
2693:
2694: if ((this .reservStart == null && reservStart != null)
2695: || (this .reservStart != null && reservStart == null)) {
2696: return false;
2697: }
2698: if (this .reservStart != null && reservStart != null
2699: && !this .reservStart.equals(reservStart)) {
2700: return false;
2701: }
2702:
2703: if (this .reservLength != reservLength) {
2704: return false;
2705: }
2706:
2707: if (this .reservPersons != reservPersons) {
2708: return false;
2709: }
2710:
2711: if (this .isPromo != isPromo) {
2712: return false;
2713: }
2714:
2715: if ((this .additionalProductFeatureAndAppls != null && additionalProductFeatureAndAppls != null)
2716: && (this .additionalProductFeatureAndAppls.size() != additionalProductFeatureAndAppls
2717: .size())
2718: && !(this .additionalProductFeatureAndAppls
2719: .equals(additionalProductFeatureAndAppls))) {
2720: return false;
2721: }
2722:
2723: if ((this .attributes != null && attributes != null)
2724: && ((this .attributes.size() != attributes.size()) || !(this .attributes
2725: .equals(attributes)))) {
2726: return false;
2727: }
2728:
2729: if (configWrapper != null
2730: && !configWrapper.equals(this .configWrapper)) {
2731: return false;
2732: }
2733:
2734: if (itemType != null && !itemType.equals(this .itemType)) {
2735: return false;
2736: }
2737:
2738: if (itemGroup != null && !itemGroup.equals(this .itemGroup)) {
2739: return false;
2740: }
2741:
2742: if (quoteId != null) {
2743: // all items linked to a quote are unique
2744: return false;
2745: }
2746:
2747: if (requirementId != null) {
2748: // all items linked to a requirement are unique
2749: return false;
2750: }
2751:
2752: return true;
2753: }
2754:
2755: /** Gets the Product entity. If it is not already retreived gets it from the delegator */
2756: public GenericValue getProduct() {
2757: if (this ._product != null) {
2758: return this ._product;
2759: }
2760: if (this .productId != null) {
2761: try {
2762: this ._product = this .getDelegator()
2763: .findByPrimaryKeyCache("Product",
2764: UtilMisc.toMap("productId", productId));
2765: } catch (GenericEntityException e) {
2766: throw new RuntimeException(
2767: "Entity Engine error getting Product ("
2768: + e.getMessage() + ")");
2769: }
2770: }
2771: return this ._product;
2772: }
2773:
2774: public GenericValue getParentProduct() {
2775: if (this ._parentProduct != null) {
2776: return this ._parentProduct;
2777: }
2778: if (this .productId == null) {
2779: throw new IllegalStateException("Bad product id");
2780: }
2781:
2782: this ._parentProduct = ProductWorker.getParentProduct(productId,
2783: this .getDelegator());
2784:
2785: return this ._parentProduct;
2786: }
2787:
2788: public String getParentProductId() {
2789: GenericValue parentProduct = this .getParentProduct();
2790: if (parentProduct != null) {
2791: return parentProduct.getString("productId");
2792: } else {
2793: return null;
2794: }
2795: }
2796:
2797: public Map getOptionalProductFeatures() {
2798: if (_product != null) {
2799: return ProductWorker.getOptionalProductFeatures(
2800: getDelegator(), this .productId);
2801: } else {
2802: // non-product items do not have features
2803: return FastMap.newInstance();
2804: }
2805: }
2806:
2807: public GenericDelegator getDelegator() {
2808: if (delegator == null) {
2809: if (UtilValidate.isEmpty(delegatorName)) {
2810: throw new IllegalStateException("Bad delegator name");
2811: }
2812: delegator = GenericDelegator
2813: .getGenericDelegator(delegatorName);
2814: }
2815: return delegator;
2816: }
2817:
2818: public void explodeItem(ShoppingCart cart,
2819: LocalDispatcher dispatcher) throws CartItemModifyException {
2820: double baseQuantity = this .getQuantity();
2821: int this Index = cart.items().indexOf(this );
2822: List newItems = new ArrayList();
2823:
2824: if (baseQuantity > 1) {
2825: for (int i = 1; i < baseQuantity; i++) {
2826: // clone the item
2827: ShoppingCartItem item = new ShoppingCartItem(this );
2828:
2829: // set the new item's quantity
2830: item.setQuantity(1, dispatcher, cart, false);
2831:
2832: // now copy/calc the adjustments
2833: Debug.logInfo("Clone's adj: " + item.getAdjustments(),
2834: module);
2835: if (item.getAdjustments() != null
2836: && item.getAdjustments().size() > 0) {
2837: List adjustments = new LinkedList(item
2838: .getAdjustments());
2839: Iterator adjIterator = adjustments.iterator();
2840:
2841: while (adjIterator.hasNext()) {
2842: GenericValue adjustment = (GenericValue) adjIterator
2843: .next();
2844:
2845: if (adjustment != null) {
2846: item.removeAdjustment(adjustment);
2847: GenericValue newAdjustment = GenericValue
2848: .create(adjustment);
2849: Double adjAmount = newAdjustment
2850: .getDouble("amount");
2851:
2852: // we use != becuase adjustments can be +/-
2853: if (adjAmount != null
2854: && adjAmount.doubleValue() != 0.00)
2855: newAdjustment.set("amount", new Double(
2856: adjAmount.doubleValue()
2857: / baseQuantity));
2858: Debug.logInfo("Cloned adj: "
2859: + newAdjustment, module);
2860: item.addAdjustment(newAdjustment);
2861: } else {
2862: Debug.logInfo("Clone Adjustment is null",
2863: module);
2864: }
2865: }
2866: }
2867: newItems.add(item);
2868: }
2869:
2870: // set this item's quantity
2871: this .setQuantity(1, dispatcher, cart, false);
2872:
2873: Debug.logInfo("BaseQuantity: " + baseQuantity, module);
2874: Debug.logInfo("Item's Adj: " + this .getAdjustments(),
2875: module);
2876:
2877: // re-calc this item's adjustments
2878: if (this .getAdjustments() != null
2879: && this .getAdjustments().size() > 0) {
2880: List adjustments = new LinkedList(this .getAdjustments());
2881: Iterator adjIterator = adjustments.iterator();
2882:
2883: while (adjIterator.hasNext()) {
2884: GenericValue adjustment = (GenericValue) adjIterator
2885: .next();
2886:
2887: if (adjustment != null) {
2888: this .removeAdjustment(adjustment);
2889: GenericValue newAdjustment = GenericValue
2890: .create(adjustment);
2891: Double adjAmount = newAdjustment
2892: .getDouble("amount");
2893:
2894: // we use != becuase adjustments can be +/-
2895: if (adjAmount != null
2896: && adjAmount.doubleValue() != 0.00)
2897: newAdjustment.set("amount", new Double(
2898: adjAmount.doubleValue()
2899: / baseQuantity));
2900: Debug.logInfo("Updated adj: " + newAdjustment,
2901: module);
2902: this .addAdjustment(newAdjustment);
2903: }
2904: }
2905: }
2906:
2907: // add the cloned item(s) to the cart
2908: Iterator newItemsItr = newItems.iterator();
2909:
2910: while (newItemsItr.hasNext()) {
2911: cart.addItem(this Index, (ShoppingCartItem) newItemsItr
2912: .next());
2913: }
2914: }
2915: }
2916:
2917: public static String getPurchaseOrderItemDescription(
2918: GenericValue product, GenericValue supplierProduct,
2919: Locale locale) {
2920: String itemDescription = "";
2921: String supplierProductId = supplierProduct
2922: .getString("supplierProductId");
2923: if (supplierProductId == null) {
2924: supplierProductId = "";
2925: } else {
2926: supplierProductId += " ";
2927: }
2928: String supplierProductName = supplierProduct
2929: .getString("supplierProductName");
2930: if (supplierProductName == null) {
2931: if (supplierProductName == null) {
2932: supplierProductName = ProductContentWrapper
2933: .getProductContentAsText(product,
2934: "PRODUCT_NAME", locale, null);
2935: }
2936: }
2937: itemDescription = supplierProductId + supplierProductName;
2938: return itemDescription;
2939: }
2940: }
|