CostDefinitionRepositoryImpl.java

package com.tradecloud.repository.impl;

import com.tradecloud.domain.base.utils.ObjectUtil;
import com.tradecloud.domain.common.Incoterm;
import com.tradecloud.domain.costing.*;
import com.tradecloud.domain.infrastructure.persistence.CriteriaBuilder;
import com.tradecloud.domain.model.organisationalunit.OrganisationalUnit;
import com.tradecloud.domain.place.Country;
import com.tradecloud.domain.supplier.Supplier;
import com.tradecloud.dto.costing.CostDefinitionSearch;
import com.tradecloud.repository.CostDefinitionRepository;
import com.tradecloud.repository.GeneralRepository;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.hibernate.query.NativeQuery;
import org.springframework.beans.factory.annotation.Autowired;
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.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

/**
 * Default implementation of the {@link CostDefinitionRepository} interface.
 */
@Repository(value = "costDefinitionRepository")
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
public class CostDefinitionRepositoryImpl extends RepositoryBaseImplNoSearch<CostDefinition> implements CostDefinitionRepository {

    private static final long serialVersionUID = 1L;

    @Autowired
    private GeneralRepository generalRepository;

    @Override
    public CostDefinition findByOrgUnitIncotermAndContext(CostDefinitionSearch search) {
        //search.setIgnoreActive(false);
        return findBy(search);
    }

    public void setGeneralRepository(GeneralRepository generalRepository) {
        this.generalRepository = generalRepository;
    }

    @Override
    public CostDefinition findByOrgUnitIncotermAndContextIgnoreActive(CostDefinitionSearch search) {
        search.setIgnoreActive(true);
        return findByOrgUnitIncotermAndContext(search);
    }

    private CostDefinition findBy(CostDefinitionSearch search) {
        validateNotNull(search.getIncoterm(), "Incoterm");
        validateNotNull(search.getCostingContextType(), "CostingContextType");
        CostDefinition costDefinition = getByCountry(search);

        if (costDefinition != null) {
            return costDefinition;
        }
        List<CostDefinition> list = findCostableCostDefinitions(search);
        //default to no shippingmoade
        if (list.isEmpty()) {
            search.setShippingMode(null);
            list = findCostableCostDefinitions(search);
        }

        if (list != null && !list.isEmpty())
            return list.stream().findFirst().orElse(null);

        costDefinition = retryWithParentOrg(search, null);
        if (costDefinition != null)
            return costDefinition;

        //default to no orgunit
        if (list.isEmpty()) {
            search.setOrganisationalUnit(null);
            list = findCostableCostDefinitions(search);
        }

        return list.stream().findFirst().orElse(null);
    }

    private CostDefinition getByCountry(CostDefinitionSearch search) {
        CostDefinition costDefinition = null;
        Country country = null;
        if (search.getSupplier() != null && search.getSupplier().getPhysicalAddress() != null) {
            search.setSupplier(generalRepository.retrieve(Supplier.class, search.getSupplier().getId()));
            country = search.getSupplier().getPhysicalAddress().getCountry();
        }

        if (country != null) {
            if (search.getOrganisationalUnit() != null) {
                search.setOrganisationalUnit(generalRepository.retrieve(OrganisationalUnit.class, search.getOrganisationalUnit().getId()));
            }

            StringBuilder query = new StringBuilder("select c.id from costdefinition c ");
            query.append("left join countrygroup on c.countrygroup_id = countrygroup.id left join ");
            query.append(" countrygroup_country on countrygroup.id = countrygroup_country.countrygroup_id where ");
            if (search.getOrganisationalUnit() != null) {
                query.append("organisationalunit_id=:organisationalUnit");
            } else {
                query.append("organisationalunit_id is null");
            }
            query.append(" and incoterm_code =:incoterm and ");
            query.append(" costablecostdefinition = :costableCostDefinition and costingcontexttype= :costingContextType and ");
            query.append(" countrygroup_country.countries_code = :country");
            SQLQuery sqlQuery = getCurrentSession().createSQLQuery(query.toString());
            sqlQuery.setParameter("costingContextType", search.getCostingContextType().name());
            sqlQuery.setParameter("country", country.getCode());
            sqlQuery.setParameter("incoterm", search.getIncoterm().getCode());

            if (search.getOrganisationalUnit() != null) {
                sqlQuery.setParameter("organisationalUnit", search.getOrganisationalUnit().getId());
            }
            sqlQuery.setParameter("costableCostDefinition", search.isIgnoreActive());
            BigInteger id = (BigInteger) sqlQuery.uniqueResult();
            if (id != null) {
                costDefinition = retrieve(id.longValue());
            }
            costDefinition = retryWithParentOrg(search, costDefinition);
            return costDefinition;
        }
        return costDefinition;
    }

    private CostDefinition retryWithParentOrg(CostDefinitionSearch search, CostDefinition costDefinition) {
        if (costDefinition == null && search.getOrganisationalUnit() != null) {
            OrganisationalUnit parent = search.getOrganisationalUnit().getParent();
            // if an org was specified in the search, don't ever search with a null org
            if (parent == null) {
                costDefinition = null;
            } else {
                search.setOrganisationalUnit(parent);
                costDefinition = findByOrgUnitIncotermAndContext(search);
            }
        }
        return costDefinition;
    }

    @Override
    public CostDefinition findByIncotermAndContext(Incoterm incoterm, CostingContextType costingContextType) {
        validateNotNull(incoterm, "Incoterm");
        validateNotNull(costingContextType, "CostingContextType");
        return runNamedQuery("costDefinition.byIncotermAndContext", new String[]{"incoterm", "costingContextType"},
                new Object[]{incoterm, costingContextType});
    }

    @Override
    public CostDefinition findByIncoterm(Incoterm incoterm) {
        List<CostDefinition> list = (List<CostDefinition>) findByNamedQueryAndNamedParam("costDefinition.byIncoterm", "incoterm", incoterm);
        return ObjectUtil.first(list);
    }

    @Override
    public List<CostDefinition> findByOrgUnit(OrganisationalUnit organisationalUnit) {
        List<CostDefinition> list = (List<CostDefinition>) findByNamedQueryAndNamedParam("costDefinition.byOrgUnit",
                "organisationalUnit", organisationalUnit);
        return list;
    }

    @Override
    public List<CostDefinition> findAllWithIncotermAndNullOrgUnit() {
        @SuppressWarnings("unchecked") List<CostDefinition> list = (List<CostDefinition>) getNamedQuery("costDefinition" +
                ".allWithIncotermAndNullOrgUnit");
        return list;
    }

    @Override
    public CostableCostDefinition findCostableCostDefinition(Costable costable) {
        Criteria searchCriteria = getSessionCustom().createCriteria(CostableCostDefinition.class);

        if (costable.getCostableCostDefinition() == null)
            return null;

        searchCriteria.add(Restrictions.eq("id", costable.getCostableCostDefinition().getId()));

        CostableCostDefinition costableCostDefinition = (CostableCostDefinition) searchCriteria.uniqueResult();

        if (costableCostDefinition != null) {
            Hibernate.initialize(costableCostDefinition.getCostLines());
            return costableCostDefinition;
        }
        return null;
    }

    @Override
    public List<CostDefinition> findAllNonCostableCostDefinitionsByOrg(List<CostDefinition> costDefinitions) {
        List<CostDefinition> matchedCostDefinitions = new ArrayList<CostDefinition>();

        //Allows all costdefinitions that are not linked to an org unit to be shown to all users
        //for (CostDefinition costDefinition : costDefinitions) {
        //  if (costDefinition.getOrganisationalUnit() == null ) {
        //    matchedCostDefinitions.add(costDefinition);
        //}
        //}

        //Check if user is a holdingcompany tier user
        Boolean holdingUser = false;
        for (OrganisationalUnit userOrg : getUserOrganisationalUnits()) {
            if (userOrg.getTier().equals("HoldingCompany")) {
                holdingUser = true;
            }
        }
        //skip filtering if user is holdingtier
        if (holdingUser = true) {
            for (CostDefinition costDefinition : costDefinitions) {
                matchedCostDefinitions.add(costDefinition);
            }
        } else {
            for (OrganisationalUnit userOrg : getUserOrganisationalUnits()) {
                for (CostDefinition costDefinition : costDefinitions) {
                    if (userOrg.equals(costDefinition.getOrganisationalUnit())) {
                        matchedCostDefinitions.add(costDefinition);
                    }
                }
            }
        }

        return matchedCostDefinitions;
    }

    @Override
    public List<CostDefinition> findAllNonCostableCostDefinitions() {
        DetachedCriteria criteria = DetachedCriteria.forClass(CostDefinition.class);
        CriteriaBuilder.addEqRestriction(criteria, "costableCostDefinition", false);

        return criteria.getExecutableCriteria(getSessionCustom()).list();
    }

    private CostDefinition runNamedQuery(String namedQuery, String[] paramNames, Object[] paramValues) {
        List<CostDefinition> list = (List<CostDefinition>) findByNamedQueryAndNamedParam(namedQuery, paramNames, paramValues);
        return ObjectUtil.first(list);
    }

    @Override
    public List<CostDefinition> findAll() {
        return (List<CostDefinition>) getNamedQuery("costDefinition.allActive");
    }

    @Override
    public List<CostDefinition> findAllIgnoreActive() {
        return (List<CostDefinition>) getNamedQuery("costDefinition.all");
    }

    @Override
    public List<OrganisationalUnit> findAllOrganisationalUnits(Incoterm incoterm) {
        ObjectUtil.validateNotNull(incoterm, "Incoterm");

        StringBuilder sql = new StringBuilder("select orgs from CostDefinition cd join cd.organisationalUnit as orgs");
        sql.append(" where cd.incoterm = :incoterm and cd.active = 't' ");
        sql.append("and cd.costingContextType = :ctx" + " and cd.costableCostDefinition = 'f'");

        Query query = getSessionCustom().createQuery(sql.toString());
        query.setParameter("incoterm", incoterm);
        query.setParameter("ctx", CostingContextType.IMPORT);
        return query.list();
    }

    @Override
    public List<CostableCostDefinition> findCostableCostDefinitions(List<Costable> costables) {
        List<CostableCostDefinition> costableCostDefinitions = new ArrayList<CostableCostDefinition>();
        for (Costable costable : costables)
            costableCostDefinitions.add(costable.getCostableCostDefinition());

        return costableCostDefinitions;
    }

    @Override
    public CostableCostDefinition findCostableCostDefinitionById(Long id) {
        return (CostableCostDefinition) getCurrentSession().load(CostableCostDefinition.class, id);
    }

    @Override
    public boolean isCostDefinitionUnique(CostDefinitionSearch search) {

        StringBuilder queryString = new StringBuilder("select count(i.id) from CostDefinition i where i.incoterm =:incoterm and ");
        queryString.append("i.costingContextType =:costingContextType ");

        if (search.getOrganisationalUnit() != null) {
            queryString.append("and i.organisationalUnit =:organisationalUnit ");
        }
        if (search.getShippingMode() != null) {
            queryString.append("and i.shippingMode =:shippingMode ");
        } else {
            queryString.append("and i.shippingMode = null ");
        }
        if (search.getMultiModalShippingMode() != null) {
            queryString.append("and i.multiModalShippingMode =:multiModalShippingMode ");
        } else {
            queryString.append("and i.multiModalShippingMode = null ");
        }

        if (search.getCountryGroup() != null) {
            queryString.append("and i.countryGroup =:countryGroup ");
        } else {
            queryString.append("and i.countryGroup is null ");
        }
        Query query = getSessionCustom().createQuery(queryString.toString());
        query.setParameter("incoterm", search.getIncoterm());
        query.setParameter("costingContextType", search.getCostingContextType());
        if (search.getOrganisationalUnit() != null) {
            query.setParameter("organisationalUnit", search.getOrganisationalUnit());
        }
        if (search.getCountryGroup() != null) {
            query.setParameter("countryGroup", search.getCountryGroup());
        }
        if (search.getShippingMode() != null) {
            query.setParameter("shippingMode", search.getShippingMode());
        }
        if (search.getMultiModalShippingMode() != null) {
            query.setParameter("multiModalShippingMode", search.getMultiModalShippingMode());
        }

        Long result = (Long) query.uniqueResult();
        return result == 0;
    }

    @Override
    public List<CostLine> findAllCustomsWorkSheetCostLine() {
        String sql = "select distinct c from CostDefinition cd join cd.costLines c  where  cd.costableCostDefinition='f'" +
                " and c.customsWorksheet = 't'";
        Query query = getSessionCustom().createQuery(sql);
        return query.list();
    }

    @Override
    public void detach(Object obj) {
        getCurrentSession().detach(obj);
    }

    @Override
    public List<CostDefinition> findCostableCostDefinitions(CostDefinitionSearch search) {

        String table = search.isCostableCostDefinition() ? "costablecostdefinition" : "costdefinition";
        String alias = !search.isCostableCostDefinition() ? "cd" : "c1";
        String join = search.isCostableCostDefinition() ? " left join costdefinition c1 on cd.id = c1.id " : "";
        StringBuilder queryString = new StringBuilder("select cd.*");

        if (search.isCostableCostDefinition())
            queryString.append(", c1.*");

        queryString.append(", 0 AS clazz_ from ");
        queryString.append(table + " cd ");
        queryString.append(join + "where\n");

        boolean preParm = false;
        if (search.getIncoterm() != null) {
            queryString.append(alias + ".incoterm_code = :incoterm\n");
            preParm = true;
        }

        if (search.getShippingMode() != null) {
            if (preParm) queryString.append(" and\n");
            queryString.append(alias + ".shippingMode = :shippingMode");
            preParm = true;
        }

        if (search.getMultiModalShippingMode() != null) {
            if (preParm) queryString.append(" and\n");
            queryString.append(alias + ".multiModalShippingMode = :multiModalShippingMode");
            preParm = true;
        }

        if (search.getCostingContextType() != null) {
            if (preParm) queryString.append(" and\n");
            queryString.append(alias + ".costingcontexttype = :costingContextType");
            preParm = true;
        }

        if (search.getCountryGroup() != null) {
            if (preParm) queryString.append(" and\n");
            queryString.append(alias + ".countrygroup_id = :countrygroup_id");
            preParm = true;
        }

        if (search.getOrganisationalUnit() != null && search.getOrganisationalUnit().getId()!=null) {
            if (preParm) queryString.append(" and\n");
            queryString.append("(").append(alias).append(".organisationalunit_id = :organisationalunit_id)");
            preParm = true;
        } else {
            if (preParm) queryString.append(" and\n");
            queryString.append("(").append(alias).append(".organisationalunit_id IS NULL)");
            preParm = true;
        }

        if (!search.isIgnoreActive()) {
            if (preParm)
                queryString.append(" and\n");
            queryString.append(alias + ".active = 't'\n");
        }
        if (preParm)
            queryString.append(" and\n");
        queryString.append(alias + ".costableCostDefinition = :costableCostDefinition\n");

        NativeQuery nativeQuery = (NativeQuery) getCurrentSession()
                .createNativeQuery(queryString.toString(), search.isCostableCostDefinition() ? CostableCostDefinition.class : CostDefinition.class);
        nativeQuery.addEntity(search.isCostableCostDefinition() ? CostableCostDefinition.class : CostDefinition.class);
        nativeQuery.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

        if (search.getIncoterm() != null) {
            nativeQuery.setParameter("incoterm", search.getIncoterm().getCode());
        }
        if (search.getShippingMode() != null) {
            nativeQuery.setParameter("shippingMode", search.getShippingMode().name());
        }
        if (search.getMultiModalShippingMode() != null) {
            nativeQuery.setParameter("multiModalShippingMode", search.getMultiModalShippingMode().name());
        }
        if (search.getCostingContextType() != null) {
            nativeQuery.setParameter("costingContextType", search.getCostingContextType().name());
        }
        if (search.getCountryGroup() != null) {
            nativeQuery.setParameter("countrygroup_id", search.getCountryGroup().getId());
        }
        if (search.getOrganisationalUnit() != null && search.getOrganisationalUnit().getId()!=null) {
            nativeQuery.setParameter("organisationalunit_id", search.getOrganisationalUnit().getId());
        }
        nativeQuery.setParameter("costableCostDefinition", search.isCostableCostDefinition());

        return nativeQuery.getResultList();
    }

}