SupplierRepositoryImpl.java

package com.tradecloud.repository.company;

import com.tradecloud.common.externalreference.ExternalReference;
import com.tradecloud.domain.base.utils.ObjectUtil;
import com.tradecloud.domain.common.Currency;
import com.tradecloud.domain.model.organisationalunit.OrganisationalUnit;
import com.tradecloud.domain.supplier.*;
import com.tradecloud.dto.company.SupplierSearch;
import com.tradecloud.repository.base.impl.CriteriaOperation;
import com.tradecloud.repository.base.impl.CriteriaValue;
import com.tradecloud.repository.base.impl.RepositoryBaseImpl;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 *
 */
@Repository(value = "supplierRepository")
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
public class SupplierRepositoryImpl extends RepositoryBaseImpl<AbstractSupplier, SupplierSearch> implements SupplierRepository {

    private static final long serialVersionUID = 1L;

    private static final Logger log = Logger.getLogger(SupplierRepositoryImpl.class);
    private final SimpleDateFormat DF = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public List<AbstractSupplier> search(SupplierSearch search) {

        DetachedCriteria criteria = DetachedCriteria.forClass(AbstractSupplier.class);
        criteria.addOrder(Order.asc("name"));
        addSearchRestrictions(criteria, search, AbstractSupplier.class);

        List<AbstractSupplier> supplierList = getExecutableCriteriaList(criteria, search.getSearchMetaParams(), "name", true);
        Collections.sort(supplierList, new Comparator<AbstractSupplier>() {
            @Override
            public int compare(AbstractSupplier o1, AbstractSupplier o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });

        return supplierList;
    }

    @Override
    public long countByCriteria(SupplierSearch search) {
        // Dirty f*cking hack!
        long total = 0l;
        total += countSupplier(search, IntegratedSupplier.class);
        total += countSupplier(search, Supplier.class);
        return total;
    }

    private long countSupplier(SupplierSearch search, Class clazz) {
        DetachedCriteria criteria = DetachedCriteria.forClass(clazz);
        addSearchRestrictions(criteria, search, clazz);

        long count = getExecutableCriteriaCount(criteria);
        log.debug("Count for Class:" + clazz.getSimpleName() + " is " + count);
        return count;
    }

    private void addSearchRestrictions(DetachedCriteria criteria, SupplierSearch search, Class clazz) {

        log.debug("addSearchRestrictions " + search.toString());

        // State
        if (search.getState() != null) {
            criteria.add(Restrictions.eq("state", search.getState()));
        }

        if (search.getComplete() != null) {
            // Active will be true by default in the search.
            if (CompleteType.COMPLETE.equals(search.getComplete())) {
                criteria.add(Restrictions.eq("complete", true));
            } else {
                criteria.add(Restrictions.eq("complete", false));
            }
        }

        if (search.getIntegrated() != null) {
            // Integrated will be true by default in the search.
            if (IntegratedType.INTEGRATED.equals(search.getIntegrated())) {
                criteria.add(Restrictions.eq("integrated", true));
            } else {
                criteria.add(Restrictions.eq("integrated", false));
            }
        }

        if (search.getName() != null) {
            criteria.add(Restrictions.ilike("name", LIKE + search.getName() + LIKE));
        }

        if (search.getReference() != null) {
            if (search.isUnique()) {
                criteria.add(Restrictions.eq("externalReference", search.getReference()));
            } else {
                criteria.add(Restrictions.ilike("externalReference", LIKE + search.getReference() + LIKE));
            }
        }

        if (search.getCreatedFrom() != null && search.getCreatedTo() != null) {
            criteria.add(Restrictions.between("created", search.getCreatedFrom(), search.getCreatedTo()));
        }

        if (search.getCreatedFrom() != null) {
            criteria.add(Restrictions.between("created", search.getCreatedFrom(), new Date()));
        }

        if (search.getCreatedTo() != null) {
            Calendar calendar = new GregorianCalendar(1999, 1, 1);
            Date time = calendar.getTime();
            criteria.add(Restrictions.between("created", time, search.getCreatedTo()));
        }

        if (search.getCountry() != null) {
            DetachedCriteria eventCrit = criteria.createCriteria("physicalAddress").add(Restrictions.eq("country", search.getCountry()));
            eventCrit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        }

        if (search.getCurrency() != null) {
            criteria.add(Restrictions.eq("currency", search.getCurrency()));
        }

        if (search.getTypes() != null && !search.getTypes().isEmpty()) {
            criteria.add(Restrictions.in("type", search.getTypes()));
        } else {
            criteria.add(Restrictions.eq("type", AbstractSupplier.Type.FULL));
        }

        if (search.getShippingMode() != null) {
            criteria.add(Restrictions.eq("shippingMode", search.getShippingMode()));
        }
        if (search.getShippingMode() != null) {
            criteria.add(Restrictions.eq("shippingMode", search.getShippingMode()));
        }

        Set<OrganisationalUnit> organisationalUnits = Collections.EMPTY_SET;
        if (search.isFilteredByUserOrg()) {
            organisationalUnits = getUserOrganisationalUnits();
        } else if (search.getOrganisationalUnit() != null) {
            organisationalUnits = Collections.singleton(search.getOrganisationalUnit());
        }

        if (search.getShowUnlinked() != null && search.getShowUnlinked().equalsIgnoreCase("NO") && !organisationalUnits.isEmpty()) {
            String orgIdsAsString = getOrgIdsAsString(organisationalUnits);
            StringBuilder builder = new StringBuilder(" ((select count(*) from organisationalunitsupplier where supplier_id = {alias}.id " +
                    "and organisationalunit_id in (" + orgIdsAsString + "))>0 ");
            String orgIdsAsCode = getOrgIdsAsCode(organisationalUnits);
            builder.append(" OR (select count(*)  from integratedsupplier_organisationalunitcodes where integratedsupplier_id = {alias}.id  and " +
                    " organisationalunitcodes in (" + orgIdsAsCode + "))>0 ");
//            if (search.isShowUnlinked()!=null && search.isShowUnlinked()) {
//                builder.append(" or (select count(*) from organisationalunitsupplier where supplier_id = {alias}.id )=0 ");
//            }
            builder.append(")");

            criteria.add(Restrictions.sqlRestriction(builder.toString()));
        } else if (search.getShowUnlinked() != null && search.getShowUnlinked().equalsIgnoreCase("NO")) {
            StringBuilder builder = new StringBuilder();
            if (clazz.getName().equals(Supplier.class.getName())) {
                builder.append(" (select count(*) from organisationalunitsupplier where supplier_id = {alias}.id  )>0 ");
            } else if (clazz.getName().equals(IntegratedSupplier.class.getName())) {
                builder.append("(select count(*)  from integratedsupplier_organisationalunitcodes where integratedsupplier_id = {alias}.id  )>0 ");
            } else {
                builder.append(" ((select count(*) from organisationalunitsupplier where supplier_id = {alias}.id  )>0 ");
                builder.append(" OR (select count(*)  from integratedsupplier_organisationalunitcodes where integratedsupplier_id ={alias}.id )>0) ");
            }
            criteria.add(Restrictions.sqlRestriction(builder.toString()));
        } else if (search.getShowUnlinked() != null && search.getShowUnlinked().equalsIgnoreCase("YES")) {
            StringBuilder builder = new StringBuilder(" ");
            if (clazz.getName().equals(Supplier.class.getName())) {
                builder.append(" (select count(*) from organisationalunitsupplier where supplier_id = {alias}.id  )=0");
            } else if (clazz.getName().equals(IntegratedSupplier.class.getName())) {
                builder.append("  (select count(*) from integratedsupplier_organisationalunitcodes where integratedsupplier_id = {alias}.id  )=0");
            } else {
                builder.append(" ((select count(*) from organisationalunitsupplier where supplier_id = {alias}.id )=0");
                builder.append(" AND  (select count(*) from integratedsupplier_organisationalunitcodes " +
                        "where integratedsupplier_id = {alias}.id )=0) ");
            }
            criteria.add(Restrictions.sqlRestriction(builder.toString()));
        }
//        criteria.add(Restrictions.sqlRestriction("x"));
    }

    /**
     * A convenience method that maps each search field from {@code ProductSearch} to the corresponding value from the search.
     *
     * @param search The {@code ProductSearch} whose names and values will create the map
     * @return A map of search field-name to field-value
     */
    @Override
    protected Collection<CriteriaValue> mapFieldsToValues(SupplierSearch search) {
        log.debug("mapFieldsToValues " + search.toString());
        Collection<CriteriaValue> fields = new LinkedHashSet<CriteriaValue>();
        fields.add(new CriteriaValue(CriteriaOperation.EQUALS, "name", search.getName()));
        fields.add(new CriteriaValue(CriteriaOperation.EQUALS, "externalReference", search.getReference()));
        fields.add(new CriteriaValue(CriteriaOperation.EQUALS, "state", search.getState()));
        fields.add(new CriteriaValue(CriteriaOperation.EQUALS, "currency", search.getCurrency()));
        fields.add(new CriteriaValue(CriteriaOperation.GREATER_THAN, "created", search.getCreatedFrom()));
        fields.add(new CriteriaValue(CriteriaOperation.LESS_THAN, "created", search.getCreatedTo()));
        if (search.getIntegrated() != null) {
            fields.add(new CriteriaValue(CriteriaOperation.EQUALS, "integrated", search.getIntegrated().equals(IntegratedType.INTEGRATED)));
        }
        if (search.getComplete() != null) {
            fields.add(new CriteriaValue(CriteriaOperation.EQUALS, "complete", search.getComplete().equals(CompleteType.COMPLETE)));
        }
        return fields;
    }

    @Override
    public List<Supplier> findSuppliers() {
        return (List<Supplier>) loadAll(Supplier.class);
    }

    @Override
    public List<IntegratedSupplier> findIntegratedSuppliers() {
        return (List<IntegratedSupplier>) loadAll(IntegratedSupplier.class);
    }

    @Override
    public AbstractSupplier findByIdWithEvents(long supplierId) {
        List<AbstractSupplier> suppliers = (List<AbstractSupplier>) findByNamedQueryAndNamedParam("findIntegratedSupplierByIdWithEventsLoaded",
                "id", supplierId);
        return ObjectUtil.first(suppliers);
    }

    @Override
    public Supplier findByName(String name) {
        @SuppressWarnings("unchecked") Supplier result = (Supplier) getSessionCustom().createCriteria(Supplier.class).add(Restrictions.eq("name",
                name)).uniqueResult();
        return result;
    }

    @Override
    public List<Supplier> findByNameList(String name) {
        return getSessionCustom().createCriteria(Supplier.class).add(Restrictions.eq("name", name)).list();
    }

    @Override
    public List<Supplier> findSuppliersUpdatedCreated(SupplierSearch search) {
        Calendar c = Calendar.getInstance();
        c.setTime(search.getCreatedTo());
        c.add(Calendar.DATE, 1);
        Date toDate = c.getTime();
        String query = "from Supplier s where s.created between \'" + DF.format(search.getCreatedFrom()) + "\'"
                + " and  \'" + DF.format(toDate) + "\' "
                + " or s.updated between \'" + DF.format(search.getUpdatedFrom()) + "\' "
                + " and \'" + DF.format(toDate) + "\'";
        //log.debug("QUERY:  " + query);
        List<Supplier> list = (List<Supplier>) getSessionCustom().createQuery(query).list();

        return list;
    }

    @Override
    public List<AbstractSupplier> searchForIntegration(SupplierSearch search) {
        DetachedCriteria criteria = DetachedCriteria.forClass(AbstractSupplier.class);
        criteria.addOrder(Order.asc("name"));
        //criteria.addOrder(Order.asc("id"));

        // search.getSearchMetaParams().setOrderBy("id");
        addSearchRestrictionsForIntegration(criteria, search);

        List<AbstractSupplier> supplierList = getExecutableCriteriaList(criteria, search.getSearchMetaParams(), "name",
                true);
        Collections.sort(supplierList, new Comparator<AbstractSupplier>() {
            @Override
            public int compare(AbstractSupplier o1, AbstractSupplier o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });

        return supplierList;
    }

    private void addSearchRestrictionsForIntegration(DetachedCriteria criteria, SupplierSearch search) {

        log.debug("addSearchRestrictions " + search.toString());

        // State
        if (search.getState() != null) {
            criteria.add(Restrictions.eq("state", search.getState()));
        }

        if (search.getComplete() != null) {
            // Active will be true by default in the search.
            if (CompleteType.COMPLETE.equals(search.getComplete())) {
                criteria.add(Restrictions.eq("complete", true));
            } else {
                criteria.add(Restrictions.eq("complete", false));
            }
        }

        if (search.getIntegrated() != null) {
            // Integrated will be true by default in the search.
            if (IntegratedType.INTEGRATED.equals(search.getIntegrated())) {
                criteria.add(Restrictions.eq("integrated", true));
            } else {
                criteria.add(Restrictions.eq("integrated", false));
            }
        }

        if (search.getName() != null) {
            criteria.add(Restrictions.ilike("name", LIKE + search.getName() + LIKE));
        }

        if (search.getReference() != null) {
            criteria.add(Restrictions.eq("externalReference", search.getReference()));
        }

        if (search.getCreatedFrom() != null && search.getCreatedTo() != null) {
            criteria.add(Restrictions.between("created", search.getCreatedFrom(), search.getCreatedTo()));
        }

        if (search.getCountry() != null) {
            DetachedCriteria eventCrit = criteria.createCriteria("physicalAddress").add(Restrictions.eq("country", search.getCountry()));
            eventCrit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        }

        if (search.getCurrency() != null) {
            criteria.add(Restrictions.eq("currency", search.getCurrency()));
        }
    }

    @Override
    public List<AbstractSupplier> supplierReportSearch(SupplierSearch search) {

        DetachedCriteria criteria = DetachedCriteria.forClass(AbstractSupplier.class);
        criteria.addOrder(Order.asc("name"));
        addSearchRestrictions(criteria, search, AbstractSupplier.class);

        List<AbstractSupplier> supplierList = getExecutableCriteriaList(criteria, search.getSearchMetaParams(), "name", true);
        return supplierList;
    }

    @Override
    public Set<Currency> getAllowedCurrencies(Long id) {
        final List list = getSessionCustom().createQuery("select s.allowedCurrencies from Supplier s where s.id=:supplier_id")
                .setParameter("supplier_id", id).list();
        return CollectionUtils.isNotEmpty(list) ? new HashSet<>(list) : new HashSet<>();
    }

    @Override
    public void save(AbstractSupplier company) {
        validatePBExternalReferences(company.getClass(), company.getExternalReferences(), null);
        super.save2(company);
    }

    @Override
    public Serializable save2(AbstractSupplier company) {
        validatePBExternalReferences(company.getClass(), company.getExternalReferences(), null);
        return super.save2(company);
    }

    @Override
    public void update(AbstractSupplier company) {
        validatePBExternalReferences(company.getClass(), company.getExternalReferences(), company.getId());
        super.update(company);
    }

    public void delete(Supplier supplier) {
        try {
            super.delete(supplier);
        } catch (ConstraintViolationException e) {
            throw new RuntimeException("Supplier " + supplier.toString() + " cannot be delete");
        }
    }

    @Override
    public AbstractSupplier retrieve(ExternalReference externalReference) {
        AbstractSupplier t = getT(externalReference, Supplier.class.getSimpleName());
        if (t == null) {
            return getT(externalReference, IntegratedSupplier.class.getSimpleName());
        }
        return t;
    }

    @Override
    public List<Supplier> findAllNotIn(Set<Long> collect) {
        if(!collect.isEmpty()) {
            return getSessionCustom().createQuery("select s from Supplier s where s.id not in (:supplier_ids) ")
                    .setParameterList("supplier_ids", collect).list();
        }else{
            return getSessionCustom().createQuery("select s from Supplier s")
                    .list();
        }
    }
}