package com.salesmanager.core.business.services.catalog.product;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import javax.inject.Inject;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.salesmanager.core.business.exception.ServiceException;
import com.salesmanager.core.business.repositories.catalog.product.ProductRepository;
import com.salesmanager.core.business.services.catalog.category.CategoryService;
import com.salesmanager.core.business.services.catalog.product.attribute.ProductAttributeService;
import com.salesmanager.core.business.services.catalog.product.attribute.ProductOptionService;
import com.salesmanager.core.business.services.catalog.product.attribute.ProductOptionValueService;
import com.salesmanager.core.business.services.catalog.product.availability.ProductAvailabilityService;
import com.salesmanager.core.business.services.catalog.product.image.ProductImageService;
import com.salesmanager.core.business.services.catalog.product.price.ProductPriceService;
import com.salesmanager.core.business.services.catalog.product.relationship.ProductRelationshipService;
import com.salesmanager.core.business.services.catalog.product.review.ProductReviewService;
import com.salesmanager.core.business.services.common.generic.SalesManagerEntityServiceImpl;
import com.salesmanager.core.business.services.search.SearchService;
import com.salesmanager.core.business.utils.CatalogServiceHelper;
import com.salesmanager.core.business.utils.CoreConfiguration;
import com.salesmanager.core.model.catalog.category.Category;
import com.salesmanager.core.model.catalog.product.Product;
import com.salesmanager.core.model.catalog.product.ProductCriteria;
import com.salesmanager.core.model.catalog.product.ProductList;
import com.salesmanager.core.model.catalog.product.description.ProductDescription;
import com.salesmanager.core.model.catalog.product.image.ProductImage;
import com.salesmanager.core.model.catalog.product.relationship.ProductRelationship;
import com.salesmanager.core.model.catalog.product.review.ProductReview;
import com.salesmanager.core.model.content.FileContentType;
import com.salesmanager.core.model.content.ImageContentFile;
import com.salesmanager.core.model.merchant.MerchantStore;
import com.salesmanager.core.model.reference.language.Language;
import com.salesmanager.core.model.tax.taxclass.TaxClass;
@Service("productService")
public class ProductServiceImpl extends SalesManagerEntityServiceImpl<Long, Product> implements ProductService {
private static final Logger LOGGER = LoggerFactory.getLogger(ProductServiceImpl.class);
ProductRepository productRepository;
@Inject
CategoryService categoryService;
@Inject
ProductAvailabilityService productAvailabilityService;
@Inject
ProductPriceService productPriceService;
@Inject
ProductOptionService productOptionService;
@Inject
ProductOptionValueService productOptionValueService;
@Inject
ProductAttributeService productAttributeService;
@Inject
ProductRelationshipService productRelationshipService;
@Inject
SearchService searchService;
@Inject
ProductImageService productImageService;
@Inject
CoreConfiguration configuration;
@Inject
ProductReviewService productReviewService;
@Inject
public ProductServiceImpl(ProductRepository productRepository) {
super(productRepository);
this.productRepository = productRepository;
}
@Override
public void addProductDescription(Product product, ProductDescription description)
throws ServiceException {
if(product.getDescriptions()==null) {
product.setDescriptions(new HashSet<ProductDescription>());
}
product.getDescriptions().add(description);
description.setProduct(product);
update(product);
searchService.index(product.getMerchantStore(), product);
}
@Override
public List<Product> getProducts(List<Long> categoryIds) throws ServiceException {
@SuppressWarnings({ "unchecked", "rawtypes" })
Set ids = new HashSet(categoryIds);
return productRepository.getProductsListByCategories(ids);
}
public Product getById(Long productId) {
return productRepository.getById(productId);
}
@Override
public List<Product> getProducts(List<Long> categoryIds, Language language) throws ServiceException {
@SuppressWarnings({ "unchecked", "rawtypes" })
Set<Long> ids = new HashSet(categoryIds);
return productRepository.getProductsListByCategories(ids, language);
}
@Override
public ProductDescription getProductDescription(Product product, Language language) {
for (ProductDescription description : product.getDescriptions()) {
if (description.getLanguage().equals(language)) {
return description;
}
}
return null;
}
@Override
public Product getBySeUrl(MerchantStore store, String seUrl, Locale locale) {
return productRepository.getByFriendlyUrl(store, seUrl, locale);
}
@Override
public Product getProductForLocale(long productId, Language language, Locale locale)
throws ServiceException {
Product product = productRepository.getProductForLocale(productId, language, locale);
CatalogServiceHelper.setToAvailability(product, locale);
CatalogServiceHelper.setToLanguage(product, language.getId());
return product;
}
@Override
public List<Product> getProductsForLocale(Category category,
Language language, Locale locale) throws ServiceException {
if(category==null) {
throw new ServiceException("The category is null");
}
//Get the category list
StringBuilder lineage = new StringBuilder().append(category.getLineage()).append(category.getId()).append("/");
List<Category> categories = categoryService.listByLineage(category.getMerchantStore(),lineage.toString());
Set<Long> categoryIds = new HashSet<Long>();
for(Category c : categories) {
categoryIds.add(c.getId());
}
categoryIds.add(category.getId());
//Get products
List<Product> products = productRepository.getProductsForLocale(category.getMerchantStore(), categoryIds, language, locale);
//Filter availability
return products;
}
@Override
public ProductList listByStore(MerchantStore store,
Language language, ProductCriteria criteria) {
return productRepository.listByStore(store, language, criteria);
}
@Override
public List<Product> listByStore(MerchantStore store) {
return productRepository.listByStore(store);
}
@Override
public List<Product> listByTaxClass(TaxClass taxClass) {
return productRepository.listByTaxClass(taxClass);
}
@Override
public Product getByCode(String productCode, Language language) {
return productRepository.getByCode(productCode, language);
}
@Override
public void delete(Product product) throws ServiceException {
LOGGER.debug("Deleting product");
Validate.notNull(product, "Product cannot be null");
Validate.notNull(product.getMerchantStore(), "MerchantStore cannot be null in product");
product = this.getById(product.getId());//Prevents detached entity error
product.setCategories(null);
Set<ProductImage> images = product.getImages();
for(ProductImage image : images) {
productImageService.removeProductImage(image);
}
product.setImages(null);
//delete reviews
List<ProductReview> reviews = productReviewService.getByProductNoCustomers(product);
for(ProductReview review : reviews) {
productReviewService.delete(review);
}
//related - featured
List<ProductRelationship> relationships = productRelationshipService.listByProduct(product);
for(ProductRelationship relationship : relationships) {
productRelationshipService.delete(relationship);
}
super.delete(product);
searchService.deleteIndex(product.getMerchantStore(), product);
}
@Override
public void create(Product product) throws ServiceException {
this.saveOrUpdate(product);
searchService.index(product.getMerchantStore(), product);
}
@Override
public void update(Product product) throws ServiceException {
this.saveOrUpdate(product);
searchService.index(product.getMerchantStore(), product);
}
private void saveOrUpdate(Product product) throws ServiceException {
LOGGER.debug("Save or update product ");
Validate.notNull(product,"product cannot be null");
Validate.notNull(product.getAvailabilities(),"product must have at least one availability");
Validate.notEmpty(product.getAvailabilities(),"product must have at least one availability");
//List of original images
Set<ProductImage> originalProductImages = null;
if(product.getId()!=null && product.getId()>0) {
originalProductImages = product.getImages();
}
/** save product first **/
super.save(product);
/**
* Image creation needs extra service to save the file in the CMS
*/
List<Long> newImageIds = new ArrayList<Long>();
Set<ProductImage> images = product.getImages();
try {
if(images!=null && images.size()>0) {
for(ProductImage image : images) {
if(image.getImage()!=null && (image.getId()==null || image.getId()==0L)) {
image.setProduct(product);
InputStream inputStream = image.getImage();
ImageContentFile cmsContentImage = new ImageContentFile();
cmsContentImage.setFileName( image.getProductImage() );
cmsContentImage.setFile( inputStream );
cmsContentImage.setFileContentType(FileContentType.PRODUCT);
productImageService.addProductImage(product, image, cmsContentImage);
newImageIds.add(image.getId());
} else {
productImageService.save(image);
newImageIds.add(image.getId());
}
}
}
//cleanup old images
if(originalProductImages!=null) {
for(ProductImage image : originalProductImages) {
if(!newImageIds.contains(image.getId())) {
productImageService.delete(image);
}
}
}
} catch(Exception e) {
LOGGER.error("Cannot save images " + e.getMessage());
}
}
}