package com.salesmanager.core.business.services.shoppingcart; import com.salesmanager.core.business.exception.ServiceException; import com.salesmanager.core.business.repositories.shoppingcart.ShoppingCartAttributeRepository; import com.salesmanager.core.business.repositories.shoppingcart.ShoppingCartItemRepository; import com.salesmanager.core.business.repositories.shoppingcart.ShoppingCartRepository; import com.salesmanager.core.business.services.catalog.product.PricingService; import com.salesmanager.core.business.services.catalog.product.ProductService; import com.salesmanager.core.business.services.catalog.product.attribute.ProductAttributeService; import com.salesmanager.core.business.services.common.generic.SalesManagerEntityServiceImpl; import com.salesmanager.core.model.catalog.product.Product; import com.salesmanager.core.model.catalog.product.attribute.ProductAttribute; import com.salesmanager.core.model.catalog.product.price.FinalPrice; import com.salesmanager.core.model.customer.Customer; import com.salesmanager.core.model.merchant.MerchantStore; import com.salesmanager.core.model.shipping.ShippingProduct; import com.salesmanager.core.model.shoppingcart.ShoppingCart; import com.salesmanager.core.model.shoppingcart.ShoppingCartAttributeItem; import com.salesmanager.core.model.shoppingcart.ShoppingCartItem; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.inject.Inject; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @Service("shoppingCartService") public class ShoppingCartServiceImpl extends SalesManagerEntityServiceImpl<Long, ShoppingCart> implements ShoppingCartService { private ShoppingCartRepository shoppingCartRepository; @Inject private ProductService productService; @Inject private ShoppingCartItemRepository shoppingCartItemRepository; @Inject private ShoppingCartAttributeRepository shoppingCartAttributeItemRepository; @Inject private PricingService pricingService; @Inject private ProductAttributeService productAttributeService; private static final Logger LOGGER = LoggerFactory.getLogger(ShoppingCartServiceImpl.class); @Inject public ShoppingCartServiceImpl(ShoppingCartRepository shoppingCartRepository) { super(shoppingCartRepository); this.shoppingCartRepository = shoppingCartRepository; } /** * Retrieve a {@link ShoppingCart} cart for a given customer */ @Override @Transactional public ShoppingCart getShoppingCart(final Customer customer) throws ServiceException { try { ShoppingCart shoppingCart = shoppingCartRepository.findByCustomer(customer.getId()); getPopulatedShoppingCart(shoppingCart); if (shoppingCart != null && shoppingCart.isObsolete()) { delete(shoppingCart); return null; } else { return shoppingCart; } } catch (Exception e) { throw new ServiceException(e); } } /** * Save or update a {@link ShoppingCart} for a given customer */ @Override public void saveOrUpdate(final ShoppingCart shoppingCart) throws ServiceException { if (shoppingCart.getId() == null || shoppingCart.getId().longValue() == 0) { super.create(shoppingCart); } else { super.update(shoppingCart); } } /** * Get a {@link ShoppingCart} for a given id and MerchantStore. Will update * the shopping cart prices and items based on the actual inventory. This * method will remove the shopping cart if no items are attached. */ @Override @Transactional public ShoppingCart getById(final Long id, final MerchantStore store) throws ServiceException { try { ShoppingCart shoppingCart = shoppingCartRepository.findById(store.getId(), id); if (shoppingCart == null) { return null; } getPopulatedShoppingCart(shoppingCart); if (shoppingCart.isObsolete()) { delete(shoppingCart); return null; } else { return shoppingCart; } } catch (Exception e) { throw new ServiceException(e); } } /** * Get a {@link ShoppingCart} for a given id. Will update the shopping cart * prices and items based on the actual inventory. This method will remove * the shopping cart if no items are attached. */ @Override @Transactional public ShoppingCart getById(final Long id) { try { ShoppingCart shoppingCart = shoppingCartRepository.findOne(id); if (shoppingCart == null) { return null; } getPopulatedShoppingCart(shoppingCart); if (shoppingCart.isObsolete()) { delete(shoppingCart); return null; } else { return shoppingCart; } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } /** * Get a {@link ShoppingCart} for a given code. Will update the shopping * cart prices and items based on the actual inventory. This method will * remove the shopping cart if no items are attached. */ @Override @Transactional public ShoppingCart getByCode(final String code, final MerchantStore store) throws ServiceException { try { ShoppingCart shoppingCart = shoppingCartRepository.findByCode(store.getId(), code); if (shoppingCart == null) { return null; } getPopulatedShoppingCart(shoppingCart); if (shoppingCart.isObsolete()) { delete(shoppingCart); return null; } else { return shoppingCart; } } catch (javax.persistence.NoResultException nre) { return null; } catch (RuntimeException e) { throw new ServiceException(e); } catch (Exception ee) { throw new ServiceException(ee); } catch (Throwable t) { throw new ServiceException(t); } } @Override public void deleteCart(final ShoppingCart shoppingCart) throws ServiceException { ShoppingCart cart = this.getById(shoppingCart.getId()); if (cart != null) { super.delete(cart); } } @Override @Transactional public ShoppingCart getByCustomer(final Customer customer) throws ServiceException { try { ShoppingCart shoppingCart = shoppingCartRepository.findByCustomer(customer.getId()); if (shoppingCart == null) { return null; } return getPopulatedShoppingCart(shoppingCart); } catch (Exception e) { throw new ServiceException(e); } } @Transactional(noRollbackFor = { org.springframework.dao.EmptyResultDataAccessException.class }) private ShoppingCart getPopulatedShoppingCart(final ShoppingCart shoppingCart) throws Exception { try { boolean cartIsObsolete = false; if (shoppingCart != null) { Set<ShoppingCartItem> items = shoppingCart.getLineItems(); if (items == null || items.size() == 0) { shoppingCart.setObsolete(true); return shoppingCart; } // Set<ShoppingCartItem> shoppingCartItems = new // HashSet<ShoppingCartItem>(); for (ShoppingCartItem item : items) { LOGGER.debug("Populate item " + item.getId()); getPopulatedItem(item); LOGGER.debug("Obsolete item ? " + item.isObsolete()); if (item.isObsolete()) { cartIsObsolete = true; } } // shoppingCart.setLineItems(shoppingCartItems); boolean refreshCart = false; Set<ShoppingCartItem> refreshedItems = new HashSet<ShoppingCartItem>(); for (ShoppingCartItem item : items) { /* if (!item.isObsolete()) { refreshedItems.add(item); } else { refreshCart = true; }*/ refreshedItems.add(item); } //if (refreshCart) { shoppingCart.setLineItems(refreshedItems); update(shoppingCart); //} if (cartIsObsolete) { shoppingCart.setObsolete(true); } return shoppingCart; } } catch (Exception e) { LOGGER.error(e.getMessage()); throw new ServiceException(e); } return shoppingCart; } @Override public ShoppingCartItem populateShoppingCartItem(final Product product) throws ServiceException { Validate.notNull(product, "Product should not be null"); Validate.notNull(product.getMerchantStore(), "Product.merchantStore should not be null"); ShoppingCartItem item = new ShoppingCartItem(product); // Set<ProductAttribute> productAttributes = product.getAttributes(); // Set<ShoppingCartAttributeItem> attributesList = new // HashSet<ShoppingCartAttributeItem>(); // if(!CollectionUtils.isEmpty(productAttributes)) { // for(ProductAttribute productAttribute : productAttributes) { // ShoppingCartAttributeItem attributeItem = new // ShoppingCartAttributeItem(); // attributeItem.setShoppingCartItem(item); // attributeItem.setProductAttribute(productAttribute); // attributeItem.setProductAttributeId(productAttribute.getId()); // attributesList.add(attributeItem); // } // item.setAttributes(attributesList); // } item.setProductVirtual(product.isProductVirtual()); // set item price FinalPrice price = pricingService.calculateProductPrice(product); item.setItemPrice(price.getFinalPrice()); return item; } @Transactional private void getPopulatedItem(final ShoppingCartItem item) throws Exception { Product product = null; Long productId = item.getProductId(); product = productService.getById(productId); if (product == null) { item.setObsolete(true); return; } item.setProduct(product); if (product.isProductVirtual()) { item.setProductVirtual(true); } Set<ShoppingCartAttributeItem> cartAttributes = item.getAttributes(); Set<ProductAttribute> productAttributes = product.getAttributes(); List<ProductAttribute> attributesList = new ArrayList<ProductAttribute>();//attributes maintained List<ShoppingCartAttributeItem> removeAttributesList = new ArrayList<ShoppingCartAttributeItem>();//attributes to remove //DELETE ORPHEANS MANUALLY if ( (productAttributes != null && productAttributes.size() > 0) || (cartAttributes != null && cartAttributes.size() > 0)) { for (ShoppingCartAttributeItem attribute : cartAttributes) { long attributeId = attribute.getProductAttributeId().longValue(); boolean existingAttribute = false; for (ProductAttribute productAttribute : productAttributes) { if (productAttribute.getId().longValue() == attributeId) { attribute.setProductAttribute(productAttribute); attributesList.add(productAttribute); existingAttribute = true; break; } } if(!existingAttribute) { removeAttributesList.add(attribute); } } } //cleanup orphean item if(CollectionUtils.isNotEmpty(removeAttributesList)) { for(ShoppingCartAttributeItem attr : removeAttributesList) { shoppingCartAttributeItemRepository.delete(attr); } } //cleanup detached attributes if(CollectionUtils.isEmpty(attributesList)) { item.setAttributes(null); } // set item price FinalPrice price = pricingService.calculateProductPrice(product, attributesList); item.setItemPrice(price.getFinalPrice()); item.setFinalPrice(price); BigDecimal subTotal = item.getItemPrice().multiply(new BigDecimal(item.getQuantity().intValue())); item.setSubTotal(subTotal); } @Override public List<ShippingProduct> createShippingProduct(final ShoppingCart cart) throws ServiceException { /** * Determines if products are virtual */ Set<ShoppingCartItem> items = cart.getLineItems(); List<ShippingProduct> shippingProducts = null; for (ShoppingCartItem item : items) { Product product = item.getProduct(); if (!product.isProductVirtual() && product.isProductShipeable()) { if (shippingProducts == null) { shippingProducts = new ArrayList<ShippingProduct>(); } ShippingProduct shippingProduct = new ShippingProduct(product); shippingProduct.setQuantity(item.getQuantity()); shippingProduct.setFinalPrice(item.getFinalPrice()); shippingProducts.add(shippingProduct); } } return shippingProducts; } @Override public boolean isFreeShoppingCart(final ShoppingCart cart) throws ServiceException { /** * Determines if products are free */ Set<ShoppingCartItem> items = cart.getLineItems(); for (ShoppingCartItem item : items) { Product product = item.getProduct(); FinalPrice finalPrice = pricingService.calculateProductPrice(product); if (finalPrice.getFinalPrice().longValue() > 0) { return false; } } return true; } @Override public boolean requiresShipping(final ShoppingCart cart) throws ServiceException { Validate.notNull(cart, "Shopping cart cannot be null"); Validate.notNull(cart.getLineItems(), "ShoppingCart items cannot be null"); boolean requiresShipping = false; for (ShoppingCartItem item : cart.getLineItems()) { Product product = item.getProduct(); if (product.isProductShipeable()) { requiresShipping = true; break; } } return requiresShipping; } @Override public void removeShoppingCart(final ShoppingCart cart) throws ServiceException { shoppingCartRepository.delete(cart); } @Override public ShoppingCart mergeShoppingCarts(final ShoppingCart userShoppingModel, final ShoppingCart sessionCart, final MerchantStore store) throws Exception { if (sessionCart.getCustomerId() != null && sessionCart.getCustomerId() == userShoppingModel.getCustomerId()) { LOGGER.info("Session Shopping cart belongs to same logged in user"); if (CollectionUtils.isNotEmpty(userShoppingModel.getLineItems()) && CollectionUtils.isNotEmpty(sessionCart.getLineItems())) { return userShoppingModel; } } LOGGER.info("Starting merging shopping carts"); if (CollectionUtils.isNotEmpty(sessionCart.getLineItems())) { Set<ShoppingCartItem> shoppingCartItemsSet = getShoppingCartItems(sessionCart, store, userShoppingModel); boolean duplicateFound = false; if (CollectionUtils.isNotEmpty(shoppingCartItemsSet)) { for (ShoppingCartItem sessionShoppingCartItem : shoppingCartItemsSet) { if (CollectionUtils.isNotEmpty(userShoppingModel.getLineItems())) { for (ShoppingCartItem cartItem : userShoppingModel.getLineItems()) { if (cartItem.getProduct().getId().longValue() == sessionShoppingCartItem.getProduct() .getId().longValue()) { if (CollectionUtils.isNotEmpty(cartItem.getAttributes())) { if (!duplicateFound) { LOGGER.info("Dupliate item found..updating exisitng product quantity"); cartItem.setQuantity( cartItem.getQuantity() + sessionShoppingCartItem.getQuantity()); duplicateFound = true; break; } } } } } if (!duplicateFound) { LOGGER.info("New item found..adding item to Shopping cart"); userShoppingModel.getLineItems().add(sessionShoppingCartItem); } } } } LOGGER.info("Shopping Cart merged successfully....."); saveOrUpdate(userShoppingModel); removeShoppingCart(sessionCart); return userShoppingModel; } private Set<ShoppingCartItem> getShoppingCartItems(final ShoppingCart sessionCart, final MerchantStore store, final ShoppingCart cartModel) throws Exception { Set<ShoppingCartItem> shoppingCartItemsSet = null; if (CollectionUtils.isNotEmpty(sessionCart.getLineItems())) { shoppingCartItemsSet = new HashSet<ShoppingCartItem>(); for (ShoppingCartItem shoppingCartItem : sessionCart.getLineItems()) { Product product = productService.getById(shoppingCartItem.getProductId()); if (product == null) { throw new Exception("Item with id " + shoppingCartItem.getProductId() + " does not exist"); } if (product.getMerchantStore().getId().intValue() != store.getId().intValue()) { throw new Exception("Item with id " + shoppingCartItem.getProductId() + " does not belong to merchant " + store.getId()); } ShoppingCartItem item = populateShoppingCartItem(product); item.setQuantity(shoppingCartItem.getQuantity()); item.setShoppingCart(cartModel); List<ShoppingCartAttributeItem> cartAttributes = new ArrayList<ShoppingCartAttributeItem>( shoppingCartItem.getAttributes()); if (CollectionUtils.isNotEmpty(cartAttributes)) { for (ShoppingCartAttributeItem shoppingCartAttributeItem : cartAttributes) { ProductAttribute productAttribute = productAttributeService .getById(shoppingCartAttributeItem.getId()); if (productAttribute != null && productAttribute.getProduct().getId().longValue() == product.getId().longValue()) { ShoppingCartAttributeItem attributeItem = new ShoppingCartAttributeItem(item, productAttribute); if (shoppingCartAttributeItem.getId() > 0) { attributeItem.setId(shoppingCartAttributeItem.getId()); } item.addAttributes(attributeItem); } } } shoppingCartItemsSet.add(item); } } return shoppingCartItemsSet; } @Override public boolean isFreeShoppingCart(List<ShoppingCartItem> items) throws ServiceException { ShoppingCart cart = new ShoppingCart(); Set<ShoppingCartItem> cartItems = new HashSet<ShoppingCartItem>(items); cart.setLineItems(cartItems); return this.isFreeShoppingCart(cart); } @Override public void deleteShoppingCartItem(Long id) { shoppingCartItemRepository.delete(id); } }