/* * #%L * BroadleafCommerce Framework * %% * Copyright (C) 2009 - 2013 Broadleaf Commerce * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ package org.broadleafcommerce.core.order.service; import org.apache.commons.logging.Log; import org.broadleafcommerce.common.payment.PaymentType; import org.broadleafcommerce.core.offer.domain.OfferCode; import org.broadleafcommerce.core.offer.service.exception.OfferException; import org.broadleafcommerce.core.offer.service.exception.OfferMaxUseExceededException; import org.broadleafcommerce.core.order.dao.OrderDao; import org.broadleafcommerce.core.order.domain.Order; import org.broadleafcommerce.core.order.domain.OrderItem; import org.broadleafcommerce.core.order.service.call.GiftWrapOrderItemRequest; import org.broadleafcommerce.core.order.service.call.OrderItemRequestDTO; import org.broadleafcommerce.core.order.service.exception.AddToCartException; import org.broadleafcommerce.core.order.service.exception.RemoveFromCartException; import org.broadleafcommerce.core.order.service.exception.UpdateCartException; import org.broadleafcommerce.core.order.service.type.OrderStatus; import org.broadleafcommerce.core.payment.domain.OrderPayment; import org.broadleafcommerce.core.payment.domain.secure.Referenced; import org.broadleafcommerce.core.pricing.service.exception.PricingException; import org.broadleafcommerce.core.workflow.WorkflowException; import org.broadleafcommerce.profile.core.domain.Customer; import java.util.List; /** * The general interface for interacting with shopping carts and completed Orders. * In Broadleaf Commerce, a Cart and an Order are the same thing. A "cart" becomes * an order after it has been submitted. * * Most of the methods in this order are used to modify the cart. However, it is also * common to use this service for "named" orders (aka wishlists). */ public interface OrderService { /** * Creates a new Order for the given customer. Generally, you will want to use the customer * that is on the current request, which can be grabbed by utilizing the CustomerState * utility class. * * The default Broadleaf implementation of this method will provision a new Order in the * database and set the current customer as the owner of the order. If the customer has an * email address associated with their profile, that will be copied as well. If the customer * is a new, anonymous customer, his username will be set to his database id. * * @see org.broadleafcommerce.profile.web.core.CustomerState#getCustomer() * * @param customer * @return the newly created order */ public Order createNewCartForCustomer(Customer customer); /** * Creates a new Order for the given customer with the given name. Typically, this represents * a "wishlist" order that the customer can save but not check out with. * * @param name the wishlist name * @param customer * @param args additional arguments to be used by Broadleaf extensions * @return the newly created named order */ public Order createNamedOrderForCustomer(String name, Customer customer); /** * Looks up an Order by the given customer and a specified order name. * * This is typically used to retrieve a "wishlist" order. * * @see #createNamedOrderForCustomer(String name, Customer customer) * * @param name * @param customer * @param args additional arguments to be used by Broadleaf extensions * @return the named order requested */ public Order findNamedOrderForCustomer(String name, Customer customer); /** * Looks up an Order by its database id * * @param orderId * @return the requested Order */ public Order findOrderById(Long orderId); /** * Looks up an Order by its database id * and optionally calls refresh to ensure that the entity manager pulls the instance from the DB and not from cache * * @param orderId * @return the requested Order */ public Order findOrderById(Long orderId, boolean refresh); /** * Looks up the current shopping cart for the customer. Note that a shopping cart is * simply an Order with OrderStatus = IN_PROCESS. If for some reason the given customer * has more than one current IN_PROCESS Order, the default Broadleaf implementation will * return the first match found. Furthermore, also note that the current shopping cart * for a customer must never be named -- an Order with a non-null "name" property indicates * that it is a wishlist and not a shopping cart. * * @param customer * @return the current shopping cart for the customer */ public Order findCartForCustomer(Customer customer); /** * Looks up all Orders for the specified customer, regardless of current OrderStatus * * @param customer * @return the requested Orders */ public List<Order> findOrdersForCustomer(Customer customer); /** * Looks up all Orders for the specified customer that are in the specified OrderStatus. * * @param customer * @param status * @return the requested Orders */ public List<Order> findOrdersForCustomer(Customer customer, OrderStatus status); /** * Looks up Orders and returns the order matching the given orderNumber * * @param orderNumber * @return the requested Order */ public Order findOrderByOrderNumber(String orderNumber); /** * Returns all OrderPayment objects that are associated with the given order * * @param order * @return the list of all OrderPayment objects */ public List<OrderPayment> findPaymentsForOrder(Order order); /** * Associates a given OrderPayment with an Order and then saves the order. Note that it is acceptable for the * securePaymentInfo to be null. For example, if the secure credit card details are * handled by a third party, a given application may never have associated securePaymentInfos * * @param order * @param payment * @param securePaymentInfo - null if it doesn't exist * @return the persisted version of the OrderPayment */ public OrderPayment addPaymentToOrder(Order order, OrderPayment payment, Referenced securePaymentInfo); /** * Persists the given order to the database. If the priceOrder flag is set to true, * the pricing workflow will execute before the order is written to the database. * Generally, you will want to price the order in every request scope once, and * preferrably on the last call to save() for performance reasons. * * However, if you have logic that depends on the Order being priced, there are no * issues with saving as many times as necessary. * * @param order * @param priceOrder * @return the persisted Order, which will be a different instance than the Order passed in * @throws PricingException */ public Order save(Order order, Boolean priceOrder) throws PricingException; /** * Saves the given <b>order</b> while optionally repricing the order (meaning, going through the pricing workflow) * along with updating the prices of individual items in the order, as opposed to just pricing taxes/shipping/etc. * * @param order * @param priceOrder * @param repriceItems whether or not to reprice the items inside of the order via {@link Order#updatePrices()} * @return the persisted Order, which will be a different instance than the Order passed in * @throws PricingException */ public Order save(Order order, boolean priceOrder, boolean repriceItems) throws PricingException; /** * Deletes the given order. Note that the default Broadleaf implementation in * OrderServiceImpl will actually remove the Order instance from the database. * * @param order */ public void cancelOrder(Order order); /** * Adds the given OfferCode to the order. Optionally prices the order as well. * * @param order * @param offerCode * @param priceOrder * @return the modified Order * @throws PricingException * @throws OfferMaxUseExceededException * @throws OfferException */ public Order addOfferCode(Order order, OfferCode offerCode, boolean priceOrder) throws PricingException, OfferException; /** * Adds the given OfferCodes to the order. Optionally prices the order as well. * * @param order * @param offerCodes * @param priceOrder * @return * @throws PricingException * @throws OfferMaxUseExceededException * @throws OfferException */ public Order addOfferCodes(Order order, List<OfferCode> offerCodes, boolean priceOrder) throws PricingException, OfferException; /** * Remove the given OfferCode for the order. Optionally prices the order as well. * * @param order * @param offerCode * @param priceOrder * @return the modified Order * @throws PricingException */ public Order removeOfferCode(Order order, OfferCode offerCode, boolean priceOrder) throws PricingException; /** * Removes all offer codes for the given order. Optionally prices the order as well. * * @param order * @param priceOrder * @return the modified Order * @throws PricingException */ public Order removeAllOfferCodes(Order order, boolean priceOrder) throws PricingException; /** * The null order is the default order for all customers when they initially * enter the site. Upon the first addition of a product to a cart, a non-null order * will be provisioned for the user. * * @see org.broadleafcommerce.core.order.domain.NullOrderImpl for more information * * @return a shared, static, unmodifiable NullOrder */ public Order getNullOrder(); /** * @see #setAutomaticallyMergeLikeItems(boolean) * * @return whether or not like-items will be automatically merged */ public boolean getAutomaticallyMergeLikeItems(); /** * When set to true, the system when items are added to the cart, they will * automatically be merged. For example, when a user adds an item to the cart * and then adds the item again, the item will have its quantity changed to 2 * instead of the cart containing two separate items. * * If this logic needs to be more complex, it is possible to extend the behavior by * overriding OrderOfferProcessor.buildIdentifier(). * * @param automaticallyMergeLikeItems */ public void setAutomaticallyMergeLikeItems(boolean automaticallyMergeLikeItems); /** * Changes the OrderStatus to SUBMITTED * * @param order to confirm * @return the order that was confirmed */ public Order confirmOrder(Order order); /** * Looks through the given order and returns the latest added OrderItem that matches on the skuId * and productId. Generally, this is used to retrieve the OrderItem that was just added to the cart. * The default Broadleaf implementation will attempt to match on skuId first, and failing that, it will * look at the productId. * * Note that the behavior is slightly undeterministic in the case that {@link setAutomaticallyMergeLikeItems} * is set to true and the last added sku matches on a previously added sku. In this case, the sku that has the * merged items would be returned, so the total quantity of the OrderItem might not match exactly what was * just added. * * @param order * @param skuId * @param productId * @return the best matching OrderItem with highest index in the list of OrderItems in the order */ public OrderItem findLastMatchingItem(Order order, Long skuId, Long productId); /** * Adds a GiftWrapItem to the order based on the itemRequest. A GiftWrapItem is a product (for example, * a "Gift Box with Red Ribbon") that contains a list of OrderItems that should be wrapped by this * GiftWrapItem. * * The OrderItems must already exist and belong to an order before they are able to be wrapped by the * GiftWrapItem * * @param order * @param itemRequest * @param priceOrder * @return the GiftWrapItem instance that was created and attached to the order * @throws PricingException */ public OrderItem addGiftWrapItemToOrder(Order order, GiftWrapOrderItemRequest itemRequest, boolean priceOrder) throws PricingException; /** * Initiates the addItem workflow that will attempt to add the given quantity of the specified item * to the Order. The item to be added can be determined in a few different ways. For example, the * SKU can be specified directly or it can be determine based on a Product and potentially some * specified ProductOptions for that given product. * * The minimum required parameters for OrderItemRequest are: productId and quantity or alternatively, skuId and quantity * * When priceOrder is false, the system will not reprice the order. This is more performant in * cases such as bulk adds where the repricing could be done for the last item only. * * This method differs from the {@link #addItemWithPriceOverrides(Long, OrderItemRequestDTO, boolean)} in that it * will clear any values set on the {@link OrderItemRequestDTO} for the overrideSalePrice or overrideRetailPrice. * * This design is intended to ensure that override pricing is not called by mistake. Implementors should * use this method when no manual price overrides are allowed. * * @see OrderItemRequestDTO * @param orderId * @param orderItemRequest * @param priceOrder * @return the order the item was added to * @throws WorkflowException * @throws Throwable */ public Order addItem(Long orderId, OrderItemRequestDTO orderItemRequestDTO, boolean priceOrder) throws AddToCartException; /** * Initiates the addItem workflow that will attempt to add the given quantity of the specified item * to the Order. The item to be added can be determined in a few different ways. For example, the * SKU can be specified directly or it can be determine based on a Product and potentially some * specified ProductOptions for that given product. * * The minimum required parameters for OrderItemRequest are: productId and quantity or alternatively, skuId and quantity * * When priceOrder is false, the system will not reprice the order. This is more performant in * cases such as bulk adds where the repricing could be done for the last item only. * * As opposed to the {@link #addItem(Long, OrderItemRequestDTO, boolean)} method, this method allows * the passed in {@link OrderItemRequestDTO} to contain values for the overrideSale or overrideRetail * price fields. * * This design is intended to ensure that override pricing is not called by mistake. Implementors should * use this method when manual price overrides are allowed. * * @see OrderItemRequestDTO * @param orderId * @param orderItemRequest * @param priceOrder * @return the order the item was added to * @throws WorkflowException * @throws Throwable */ public Order addItemWithPriceOverrides(Long orderId, OrderItemRequestDTO orderItemRequestDTO, boolean priceOrder) throws AddToCartException; /** * Initiates the updateItem workflow that will attempt to update the item quantity for the specified * OrderItem in the given Order. The new quantity is specified in the OrderItemRequestDTO * * Minimum required parameters for OrderItemRequest: orderItemId, quantity * * @see OrderItemRequestDTO * @param orderId * @param orderItemRequest * @param priceOrder * @return the order the item was added to * @throws UpdateCartException * @throws RemoveFromCartException */ public Order updateItemQuantity(Long orderId, OrderItemRequestDTO orderItemRequestDTO, boolean priceOrder) throws UpdateCartException, RemoveFromCartException; /** * Initiates the removeItem workflow that will attempt to remove the specified OrderItem from * the given Order * * @see OrderItemRequestDTO * @param orderId * @param orderItemId * @param priceOrder * @return the order the item was added to * @throws RemoveFromCartException */ public Order removeItem(Long orderId, Long orderItemId, boolean priceOrder) throws RemoveFromCartException; /** * @see #setMoveNamedOrderItems(boolean) * @return whether items will be removed from the wishlist when added to the cart */ public boolean isMoveNamedOrderItems(); /** * Determines whether or not items will be removed from the named order (wishlist) * when they are moved to the Customer's current cart. * * @param moveNamedOrderItems */ public void setMoveNamedOrderItems(boolean moveNamedOrderItems); /** * @see #setDeleteEmptyNamedOrders(boolean) * @return whether empty wishlists will be deleted automatically */ public boolean isDeleteEmptyNamedOrders(); /** * Sets whether or not to delete named orders once all items have been removed. * * @param deleteEmptyNamedOrders */ public void setDeleteEmptyNamedOrders(boolean deleteEmptyNamedOrders); /** * Adds the passed in orderItem to the current cart for the same Customer that owns the * named order. This method will remove the item from the wishlist based on whether the * {@link setMoveNamedOrderItems} flag is set. * * Note that if an item was in a wishlist and is no longer able to be added to the cart, * the item will still be removed from the wishlist. * * Note that this method does not change the association of the OrderItems to the new * order -- instead, those OrderItems is completely removed and a new OrderItem that mirrors * it is created. * * @param namedOrder * @param orderItem * @param priceOrder * @return the cart with the requested orderItem added to it * @throws RemoveFromCartException * @throws AddToCartException */ public Order addItemFromNamedOrder(Order namedOrder, OrderItem orderItem, boolean priceOrder) throws RemoveFromCartException, AddToCartException; /** * This method performs the same function as addItemFromNamedOrder(Order, OrderItem, boolean) * except that instead of adding all of the quantity from the named order to the cart, it will * only add/move the specific quantity requested. * * @see #addItemFromNamedOrder(Order, OrderItem, boolean) * * @param namedOrder * @param orderItem * @param quantity * @param priceOrder * @return the cart with the requested orderItem added to it * @throws RemoveFromCartException * @throws AddToCartException * @throws UpdateCartException */ public Order addItemFromNamedOrder(Order namedOrder, OrderItem orderItem, int quantity, boolean priceOrder) throws RemoveFromCartException, AddToCartException, UpdateCartException; /** * Adds all orderItems to the current cart from the same Customer that owns the named * order. This method will remove the item from the wishlist based on whether the * {@link setMoveNamedOrderItems} flag is set. * * Note that any items that are in the wishlist but are no longer able to be added to a cart * will still be removed from the wishlist. * * Note that this method does not change the association of the OrderItems to the new * order -- instead, those OrderItems is completely removed and a new OrderItem that mirrors * it is created. * * @param namedOrder * @param priceOrder * @return * @throws RemoveFromCartException * @throws AddToCartException */ public Order addAllItemsFromNamedOrder(Order namedOrder, boolean priceOrder) throws RemoveFromCartException, AddToCartException; /** * Deletes all the OrderPayment Info's on the order. * * @param order */ public void removeAllPaymentsFromOrder(Order order); /** * Deletes the OrderPayment Info of the passed in type from the order * Note that this method will also delete any associated Secure OrderPayment Infos if necessary. * * @param order * @param paymentInfoType */ public void removePaymentsFromOrder(Order order, PaymentType paymentInfoType); /** * Deletes the OrderPayment Info from the order. * Note that this method will also delete any associated Secure OrderPayment Infos if necessary. * * @param order * @param paymentInfo */ public void removePaymentFromOrder(Order order, OrderPayment paymentInfo); public void deleteOrder(Order cart); Order removeInactiveItems(Long orderId, boolean priceOrder) throws RemoveFromCartException; /** * Since required product option can be added after the item is in the cart, we use this method * to apply product option on an existing item in the cart. No validation will happen at this time, as the validation * at checkout will take care of any missing product options. * * @param orderId * @param orderItemRequestDTO * @param priceOrder * @return Order * @throws UpdateCartException */ Order updateProductOptionsForItem(Long orderId, OrderItemRequestDTO orderItemRequestDTO, boolean priceOrder) throws UpdateCartException; /** * This debugging method will print out a console-suitable representation of the current state of the order, including * the items in the order and all pricing related information for the order. * * @param order the order to debug * @param log the Log to use to print a debug-level message */ public void printOrder(Order order, Log log); /** * Invokes the extension handler of the same name to provide the ability for a module to throw an exception * and interrupt a cart operation. * * @param cart */ public void preValidateCartOperation(Order cart); /** * Invokes the extension handler of the same name to provide the ability for a module to throw an exception * and interrupt an update quantity operation. * * @param cart */ public void preValidateUpdateQuantityOperation(Order cart, OrderItemRequestDTO dto); /** * Detaches the given order from the current entity manager and then reloads a fresh version from * the database. * * @param order * @return the newly read order */ public Order reloadOrder(Order order); /** * @see OrderDao#acquireLock(Order) * @param order * @return whether or not the lock was acquired */ public boolean acquireLock(Order order); /** * @see OrderDao#releaseLock(Order) * @param order * @return whether or not the lock was released */ public boolean releaseLock(Order order); }