All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.broadleafcommerce.core.order.service.FulfillmentGroupServiceImpl Maven / Gradle / Ivy

There is a newer version: 3.1.15-GA
Show newest version
/*
 * Copyright 2008-2013 the original author or authors.
 *
 * 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.
 */

package org.broadleafcommerce.core.order.service;

import org.broadleafcommerce.core.order.dao.FulfillmentGroupDao;
import org.broadleafcommerce.core.order.dao.FulfillmentGroupItemDao;
import org.broadleafcommerce.core.order.domain.BundleOrderItem;
import org.broadleafcommerce.core.order.domain.DiscreteOrderItem;
import org.broadleafcommerce.core.order.domain.FulfillmentGroup;
import org.broadleafcommerce.core.order.domain.FulfillmentGroupFee;
import org.broadleafcommerce.core.order.domain.FulfillmentGroupItem;
import org.broadleafcommerce.core.order.domain.FulfillmentOption;
import org.broadleafcommerce.core.order.domain.Order;
import org.broadleafcommerce.core.order.domain.OrderItem;
import org.broadleafcommerce.core.order.domain.OrderMultishipOption;
import org.broadleafcommerce.core.order.service.call.FulfillmentGroupItemRequest;
import org.broadleafcommerce.core.order.service.call.FulfillmentGroupRequest;
import org.broadleafcommerce.core.order.service.type.FulfillmentGroupStatusType;
import org.broadleafcommerce.core.pricing.service.exception.PricingException;
import org.broadleafcommerce.profile.core.domain.Address;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;

@Service("blFulfillmentGroupService")
public class FulfillmentGroupServiceImpl implements FulfillmentGroupService {

    @Resource(name="blFulfillmentGroupDao")
    protected FulfillmentGroupDao fulfillmentGroupDao;
    
    @Resource(name = "blFulfillmentGroupItemDao")
    protected FulfillmentGroupItemDao fulfillmentGroupItemDao;
    
    @Resource(name = "blOrderService")
    protected OrderService orderService;
    
    @Resource(name = "blOrderMultishipOptionService")
    protected OrderMultishipOptionService orderMultishipOptionService;

    @Override
    @Transactional("blTransactionManager")
    public FulfillmentGroup save(FulfillmentGroup fulfillmentGroup) {
        if (fulfillmentGroup.getSequence() == null) {
            fulfillmentGroup.setSequence(
                    fulfillmentGroupDao.readNextFulfillmentGroupSequnceForOrder(
                            fulfillmentGroup.getOrder()));
        }

        return fulfillmentGroupDao.save(fulfillmentGroup);
    }

    @Override
    public FulfillmentGroup createEmptyFulfillmentGroup() {
        return fulfillmentGroupDao.create();
    }

    @Override
    public FulfillmentGroup findFulfillmentGroupById(Long fulfillmentGroupId) {
        return fulfillmentGroupDao.readFulfillmentGroupById(fulfillmentGroupId);
    }

    @Override
    @Transactional("blTransactionManager")
    public void delete(FulfillmentGroup fulfillmentGroup) {
        fulfillmentGroupDao.delete(fulfillmentGroup);
    }

    @Override
    @Transactional("blTransactionManager")
    public FulfillmentGroup addFulfillmentGroupToOrder(FulfillmentGroupRequest fulfillmentGroupRequest, boolean priceOrder) throws PricingException {
        FulfillmentGroup fg = fulfillmentGroupDao.create();
        fg.setAddress(fulfillmentGroupRequest.getAddress());
        fg.setOrder(fulfillmentGroupRequest.getOrder());
        fg.setPhone(fulfillmentGroupRequest.getPhone());
        fg.setFulfillmentOption(fulfillmentGroupRequest.getOption());

        for (int i = 0; i < fulfillmentGroupRequest.getFulfillmentGroupItemRequests().size(); i++) {
            FulfillmentGroupItemRequest request = fulfillmentGroupRequest.getFulfillmentGroupItemRequests().get(i);
            request.setFulfillmentGroup(fg);
            request.setOrder(fulfillmentGroupRequest.getOrder());
            
            boolean shouldPriceOrder = (priceOrder && (i == (fulfillmentGroupRequest.getFulfillmentGroupItemRequests().size() - 1)));
            fg = addItemToFulfillmentGroup(request, shouldPriceOrder);
        }

        return fg;
    }

    @Override
    @Transactional("blTransactionManager")
    public FulfillmentGroup addItemToFulfillmentGroup(FulfillmentGroupItemRequest fulfillmentGroupItemRequest, boolean priceOrder) throws PricingException {
        Order order = fulfillmentGroupItemRequest.getOrder();
        OrderItem item = fulfillmentGroupItemRequest.getOrderItem();
        FulfillmentGroup fulfillmentGroup = fulfillmentGroupItemRequest.getFulfillmentGroup();
        
        if (order == null) {
            if (item.getOrder() != null) {
                order = item.getOrder();
            } else {
                throw new IllegalArgumentException("Order must not be null");
            }
        }
        
        // 1) Find the order item's existing fulfillment group, if any
        for (FulfillmentGroup fg : order.getFulfillmentGroups()) {
            Iterator itr = fg.getFulfillmentGroupItems().iterator();
            while (itr.hasNext()) {
                FulfillmentGroupItem fgItem = itr.next();
                if (fgItem.getOrderItem().equals(item)) {
                    // 2) remove item from it's existing fulfillment group
                    itr.remove();
                    fulfillmentGroupItemDao.delete(fgItem);
                }
            }
        }

        if (fulfillmentGroup == null || fulfillmentGroup.getId() == null) {
            // API user is trying to add an item to a fulfillment group not created
            fulfillmentGroup = fulfillmentGroupDao.create();
            FulfillmentGroupRequest fgRequest = new FulfillmentGroupRequest();
            fgRequest.setOrder(order);
            fulfillmentGroup = addFulfillmentGroupToOrder(fgRequest, false);
            fulfillmentGroup = save(fulfillmentGroup);
            order.getFulfillmentGroups().add(fulfillmentGroup);
        }

        FulfillmentGroupItem fgi = createFulfillmentGroupItemFromOrderItem(item, fulfillmentGroup, fulfillmentGroupItemRequest.getQuantity());
        fgi = fulfillmentGroupItemDao.save(fgi);

        // 3) add the item to the new fulfillment group
        fulfillmentGroup.addFulfillmentGroupItem(fgi);
        order = orderService.save(order, priceOrder);

        return fulfillmentGroup;
    }
    
    @Override
    @Transactional("blTransactionManager")
    public void removeOrderItemFromFullfillmentGroups(Order order, OrderItem orderItem) {
        List fulfillmentGroups = order.getFulfillmentGroups();
        for (FulfillmentGroup fulfillmentGroup : fulfillmentGroups) {
            Iterator itr = fulfillmentGroup.getFulfillmentGroupItems().iterator();
            while (itr.hasNext()) {
                FulfillmentGroupItem fulfillmentGroupItem = itr.next();
                if (fulfillmentGroupItem.getOrderItem().equals(orderItem)) {
                    itr.remove();
                    fulfillmentGroupItemDao.delete(fulfillmentGroupItem);
                } else if (orderItem instanceof BundleOrderItem) {
                    BundleOrderItem bundleOrderItem = (BundleOrderItem) orderItem;
                    for (DiscreteOrderItem discreteOrderItem : bundleOrderItem.getDiscreteOrderItems()) {
                        if (fulfillmentGroupItem.getOrderItem().equals(discreteOrderItem)){
                            itr.remove();
                            fulfillmentGroupItemDao.delete(fulfillmentGroupItem);
                            break;
                        }
                    }
                }
            }
        }
    }
    
    @Override
    @Transactional("blTransactionManager")
    public Order collapseToOneFulfillmentGroup(Order order, boolean priceOrder) throws PricingException {
        if (order.getFulfillmentGroups() == null || order.getFulfillmentGroups().size() < 2) {
            return order;
        }
        
        // Get the default (first) fulfillment group to collapse the others into
        ListIterator fgIter = order.getFulfillmentGroups().listIterator();
        FulfillmentGroup collapsedFg = fgIter.next();
        
        // Build out a map representing the default fgs items keyed by OrderItem id
        Map fgOrderItemMap = new HashMap();
        for (FulfillmentGroupItem fgi : collapsedFg.getFulfillmentGroupItems()) {
            fgOrderItemMap.put(fgi.getOrderItem().getId(), fgi);
        }
        
        // For all non default fgs, collapse the items into the default fg
        while (fgIter.hasNext()) {
            FulfillmentGroup fg = fgIter.next();
            ListIterator fgItemIter = fg.getFulfillmentGroupItems().listIterator();
            while (fgItemIter.hasNext()) {
                FulfillmentGroupItem fgi = fgItemIter.next();
                
                Long orderItemId = fgi.getOrderItem().getId();
                FulfillmentGroupItem matchingFgi = fgOrderItemMap.get(orderItemId);
                
                if (matchingFgi == null) {
                    matchingFgi = fulfillmentGroupItemDao.create();
                    matchingFgi.setFulfillmentGroup(collapsedFg);
                    matchingFgi.setOrderItem(fgi.getOrderItem());
                    matchingFgi.setQuantity(fgi.getQuantity());
                    matchingFgi = fulfillmentGroupItemDao.save(matchingFgi);
                    collapsedFg.getFulfillmentGroupItems().add(matchingFgi);
                    fgOrderItemMap.put(orderItemId, matchingFgi);
                } else {
                    matchingFgi.setQuantity(matchingFgi.getQuantity() + fgi.getQuantity());
                }
                
                fulfillmentGroupItemDao.delete(fgi);
                fgItemIter.remove();
            }
            fulfillmentGroupDao.delete(fg);
            fgIter.remove();
        }
        
        return orderService.save(order, priceOrder);
    }
    
    @Override
    @Transactional("blTransactionManager")
    public Order matchFulfillmentGroupsToMultishipOptions(Order order, boolean priceOrder) throws PricingException {
        List multishipOptions =  orderMultishipOptionService.findOrderMultishipOptions(order.getId());
        
        // Build map of fulfillmentGroupItemId --> FulfillmentGroupItem.quantity
        // Also build map of addressId:fulfillmentOptionId --> FulfillmentGroup
        Map fgItemQuantityMap = new HashMap();
        Map multishipGroups = new HashMap();
        for (FulfillmentGroup fg : order.getFulfillmentGroups()) {
            String key = getKey(fg.getAddress(), fg.getFulfillmentOption());
            multishipGroups.put(key, fg);
            
            for (FulfillmentGroupItem fgi : fg.getFulfillmentGroupItems()) {
                fgItemQuantityMap.put(fgi.getId(), fgi.getQuantity());
            }
        }
        
        for (OrderMultishipOption option : multishipOptions) {
            String key = getKey(option.getAddress(), option.getFulfillmentOption());
            FulfillmentGroup fg = multishipGroups.get(key);
            
            // Get or create a fulfillment group that matches this OrderMultishipOption destination
            if (fg == null) {
                FulfillmentGroupRequest fgr = new FulfillmentGroupRequest();
                
                fgr.setOrder(order);
                
                if (option.getAddress() != null) {
                    fgr.setAddress(option.getAddress());
                }
                
                if (option.getFulfillmentOption() != null) {
                    fgr.setOption(option.getFulfillmentOption());
                }
                
                fg = addFulfillmentGroupToOrder(fgr, false);
                fg = save(fg);
                order.getFulfillmentGroups().add(fg);
            }
            
            // See if there is a fulfillment group item that matches this OrderMultishipOption
            // OrderItem request
            FulfillmentGroupItem fulfillmentGroupItem = null;
            for (FulfillmentGroupItem fgi : fg.getFulfillmentGroupItems()) {
                if (fgi.getOrderItem().getId().equals(option.getOrderItem().getId())) {
                    fulfillmentGroupItem = fgi;
                }
            }
            
            // If there is no matching fulfillment group item, create a new one with quantity 1
            if (fulfillmentGroupItem == null) {
                fulfillmentGroupItem = fulfillmentGroupItemDao.create();
                fulfillmentGroupItem.setFulfillmentGroup(fg);
                fulfillmentGroupItem.setOrderItem(option.getOrderItem());
                fulfillmentGroupItem.setQuantity(1);
                fulfillmentGroupItem = fulfillmentGroupItemDao.save(fulfillmentGroupItem);
                fg.getFulfillmentGroupItems().add(fulfillmentGroupItem);
            } else {
                // There are three potential scenarios where a fulfillment group item exists:
                //   1: It has been previously created and exists in the database and
                //      has an id. This means it's in the fgItemQuantityMap. If there is 
                //      remaining quantity in that map, we will decrement it for future
                //      usage. If the quantity is 0 in the map, that means that we have more
                //      items than we did before, and we must simply increment the quantity.
                //      (qty == 0 or qty is not null)
                //   2: It was created in this request but has been saved to the database because
                //      it is a brand new fulfillment group and so it has an id. 
                //      However, it does not have an entry in the fgItemQuantityMap,
                //      so we can simply increment the quantity.
                //      (qty == null)
                //   3: It was created in this request and has not yet been saved to the database.
                //      This is because it was a previously existing fulfillment group that has new
                //      items. Therefore, we simply increment the quantity.
                //      (fulfillmentGroupItem.getId() == null)
                if (fulfillmentGroupItem.getId() != null) {
                    Integer qty = fgItemQuantityMap.get(fulfillmentGroupItem.getId());
                    if (qty == null || qty == 0) {
                        fulfillmentGroupItem.setQuantity(fulfillmentGroupItem.getQuantity() + 1);
                    } else {
                        qty -= 1;
                        fgItemQuantityMap.put(fulfillmentGroupItem.getId(), qty);
                    }
                } else {
                    fulfillmentGroupItem.setQuantity(fulfillmentGroupItem.getQuantity() + 1);
                }
            }
            
            multishipGroups.put(key, fg);
        }
        
        // Go through all of the items in the fgItemQuantityMap. For all items that have a
        // zero quantity, we don't need to do anything because we've already matched them
        // to the newly requested OrderMultishipOption. For items that have a non-zero quantity,
        // there are two possible scenarios:
        //   1: The quantity remaining matches exactly the quantity of a fulfillmentGroupItem.
        //      In this case, we can simply remove the fulfillmentGroupItem.
        //   2: The quantity in the map is greater than what we've found. This means that we
        //      need to subtract the remaining old quantity from the new quantity.
        // Furthermore, delete the empty fulfillment groups.
        for (Entry entry : fgItemQuantityMap.entrySet()) {
            if (entry.getValue() > 0) {
                FulfillmentGroupItem fgi = fulfillmentGroupItemDao.readFulfillmentGroupItemById(entry.getKey());
                if (fgi.getQuantity() == entry.getValue()) {
                    FulfillmentGroup fg = fgi.getFulfillmentGroup();
                    fg.getFulfillmentGroupItems().remove(fgi);
                    fulfillmentGroupItemDao.delete(fgi);
                    if (fg.getFulfillmentGroupItems().size() == 0) {
                        order.getFulfillmentGroups().remove(fg);
                        fulfillmentGroupDao.delete(fg);
                    }
                } else { 
                    fgi.setQuantity(fgi.getQuantity() - entry.getValue());
                    fulfillmentGroupItemDao.save(fgi);
                }
            }
        }

        return orderService.save(order, priceOrder);
    }
    
    protected String getKey(Address address, FulfillmentOption option) {
        Long addressKey = (address == null) ? -1 : address.getId();
        Long fulfillmentOptionKey = (option == null) ? -1 : option.getId();
        return addressKey + ":" + fulfillmentOptionKey;
    }
    
    protected FulfillmentGroupItem createFulfillmentGroupItemFromOrderItem(OrderItem orderItem, FulfillmentGroup fulfillmentGroup, int quantity) {
        FulfillmentGroupItem fgi = fulfillmentGroupItemDao.create();
        fgi.setFulfillmentGroup(fulfillmentGroup);
        fgi.setOrderItem(orderItem);
        fgi.setQuantity(quantity);
        return fgi;
    }

    @Override
    @Transactional("blTransactionManager")
    public Order removeAllFulfillmentGroupsFromOrder(Order order, boolean priceOrder) throws PricingException {
        if (order.getFulfillmentGroups() != null) {
            for (Iterator iterator = order.getFulfillmentGroups().iterator(); iterator.hasNext();) {
                FulfillmentGroup fulfillmentGroup = iterator.next();
                iterator.remove();
                fulfillmentGroupDao.delete(fulfillmentGroup);
            }
            order = orderService.save(order, priceOrder);
        }
        return order;
    }

    @Override
    public FulfillmentGroupFee createFulfillmentGroupFee() {
        return fulfillmentGroupDao.createFulfillmentGroupFee();
    }
    
    @Override
    public List findUnfulfilledFulfillmentGroups(int start,
            int maxResults) {
        return fulfillmentGroupDao.readUnfulfilledFulfillmentGroups(start, maxResults);
    }

    @Override
    public List findPartiallyFulfilledFulfillmentGroups(
            int start, int maxResults) {
        return fulfillmentGroupDao.readPartiallyFulfilledFulfillmentGroups(start, maxResults);
    }

    @Override
    public List findUnprocessedFulfillmentGroups(int start,
            int maxResults) {
        return fulfillmentGroupDao.readUnprocessedFulfillmentGroups(start, maxResults);
    }

    @Override
    public List findFulfillmentGroupsByStatus(
            FulfillmentGroupStatusType status, int start, int maxResults,
            boolean ascending) {
        return fulfillmentGroupDao.readFulfillmentGroupsByStatus(status, start, maxResults, ascending);
    }

    @Override
    public List findFulfillmentGroupsByStatus(
            FulfillmentGroupStatusType status, int start, int maxResults) {
        return fulfillmentGroupDao.readFulfillmentGroupsByStatus(status, start, maxResults);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy