@Override
 @Transactional(
     value = "blTransactionManager",
     rollbackFor = {AddToCartException.class})
 public Order addItemWithPriceOverrides(
     Long orderId, OrderItemRequestDTO orderItemRequestDTO, boolean priceOrder)
     throws AddToCartException {
   Order order = findOrderById(orderId);
   if (automaticallyMergeLikeItems) {
     OrderItem item = findMatchingItem(order, orderItemRequestDTO);
     if (item != null) {
       orderItemRequestDTO.setQuantity(item.getQuantity() + orderItemRequestDTO.getQuantity());
       orderItemRequestDTO.setOrderItemId(item.getId());
       try {
         return updateItemQuantity(orderId, orderItemRequestDTO, priceOrder);
       } catch (RemoveFromCartException e) {
         throw new AddToCartException(
             "Unexpected error - system tried to remove item while adding to cart", e);
       } catch (UpdateCartException e) {
         throw new AddToCartException("Could not update quantity for matched item", e);
       }
     }
   }
   try {
     CartOperationRequest cartOpRequest =
         new CartOperationRequest(findOrderById(orderId), orderItemRequestDTO, priceOrder);
     CartOperationContext context =
         (CartOperationContext) addItemWorkflow.doActivities(cartOpRequest);
     return context.getSeedData().getOrder();
   } catch (WorkflowException e) {
     throw new AddToCartException("Could not add to cart", getCartOperationExceptionRootCause(e));
   }
 }
  @Override
  @Transactional("blTransactionManager")
  public Order addItemFromNamedOrder(
      Order namedOrder, OrderItem item, int quantity, boolean priceOrder)
      throws RemoveFromCartException, AddToCartException, UpdateCartException {
    // Validate that the quantity requested makes sense
    if (quantity < 1 || quantity > item.getQuantity()) {
      throw new IllegalArgumentException("Cannot move 0 or less quantity");
    } else if (quantity == item.getQuantity()) {
      return addItemFromNamedOrder(namedOrder, item, priceOrder);
    }

    Order cartOrder = orderDao.readCartForCustomer(namedOrder.getCustomer());
    if (cartOrder == null) {
      cartOrder = createNewCartForCustomer(namedOrder.getCustomer());
    }

    if (moveNamedOrderItems) {
      // Update the old item to its new quantity only if we're moving items
      OrderItemRequestDTO orderItemRequestDTO = new OrderItemRequestDTO();
      orderItemRequestDTO.setOrderItemId(item.getId());
      orderItemRequestDTO.setQuantity(item.getQuantity() - quantity);
      updateItemQuantity(namedOrder.getId(), orderItemRequestDTO, false);
    }

    OrderItemRequestDTO orderItemRequest =
        orderItemService.buildOrderItemRequestDTOFromOrderItem(item);
    orderItemRequest.setQuantity(quantity);
    cartOrder = addItem(cartOrder.getId(), orderItemRequest, priceOrder);

    return cartOrder;
  }
 @Override
 @Transactional(
     value = "blTransactionManager",
     rollbackFor = {AddToCartException.class})
 public Order addItem(Long orderId, OrderItemRequestDTO orderItemRequestDTO, boolean priceOrder)
     throws AddToCartException {
   // Don't allow overrides from this method.
   orderItemRequestDTO.setOverrideRetailPrice(null);
   orderItemRequestDTO.setOverrideSalePrice(null);
   return addItemWithPriceOverrides(orderId, orderItemRequestDTO, priceOrder);
 }
 protected boolean itemMatches(
     Sku item1Sku,
     Product item1Product,
     Map<String, OrderItemAttribute> item1Attributes,
     OrderItemRequestDTO item2) {
   // Must match on SKU and options
   if (item1Sku != null && item2.getSkuId() != null) {
     if (item1Sku.getId().equals(item2.getSkuId())) {
       return true;
     }
   } else {
     if (item1Product != null && item2.getProductId() != null) {
       if (item1Product.getId().equals(item2.getProductId())) {
         return compareAttributes(item1Attributes, item2);
       }
     }
   }
   return false;
 }
 @Override
 @Transactional(
     value = "blTransactionManager",
     rollbackFor = {RemoveFromCartException.class})
 public Order removeItem(Long orderId, Long orderItemId, boolean priceOrder)
     throws RemoveFromCartException {
   try {
     OrderItemRequestDTO orderItemRequestDTO = new OrderItemRequestDTO();
     orderItemRequestDTO.setOrderItemId(orderItemId);
     CartOperationRequest cartOpRequest =
         new CartOperationRequest(findOrderById(orderId), orderItemRequestDTO, priceOrder);
     CartOperationContext context =
         (CartOperationContext) removeItemWorkflow.doActivities(cartOpRequest);
     return context.getSeedData().getOrder();
   } catch (WorkflowException e) {
     throw new RemoveFromCartException(
         "Could not remove from cart", getCartOperationExceptionRootCause(e));
   }
 }
  /**
   * Returns true if the two items attributes exactly match.
   *
   * @param item1
   * @param item2
   * @return
   */
  protected boolean compareAttributes(
      Map<String, OrderItemAttribute> item1Attributes, OrderItemRequestDTO item2) {
    int item1AttributeSize = item1Attributes == null ? 0 : item1Attributes.size();
    int item2AttributeSize =
        item2.getItemAttributes() == null ? 0 : item2.getItemAttributes().size();

    if (item1AttributeSize != item2AttributeSize) {
      return false;
    }

    for (String key : item2.getItemAttributes().keySet()) {
      String itemOneValue =
          (item1Attributes.get(key) == null) ? null : item1Attributes.get(key).getValue();
      String itemTwoValue = item2.getItemAttributes().get(key);
      if (!itemTwoValue.equals(itemOneValue)) {
        return false;
      }
    }
    return true;
  }
  @Override
  @Transactional(
      value = "blTransactionManager",
      rollbackFor = {UpdateCartException.class, RemoveFromCartException.class})
  public Order updateItemQuantity(
      Long orderId, OrderItemRequestDTO orderItemRequestDTO, boolean priceOrder)
      throws UpdateCartException, RemoveFromCartException {
    if (orderItemRequestDTO.getQuantity() == 0) {
      return removeItem(orderId, orderItemRequestDTO.getOrderItemId(), priceOrder);
    }

    try {
      CartOperationRequest cartOpRequest =
          new CartOperationRequest(findOrderById(orderId), orderItemRequestDTO, priceOrder);
      CartOperationContext context =
          (CartOperationContext) updateItemWorkflow.doActivities(cartOpRequest);
      return context.getSeedData().getOrder();
    } catch (WorkflowException e) {
      throw new UpdateCartException(
          "Could not update cart quantity", getCartOperationExceptionRootCause(e));
    }
  }