FECRepositoryImpl.java

package com.tradecloud.repository.impl;

import com.tradecloud.domain.base.utils.DateRange;
import com.tradecloud.domain.base.utils.DateUtils;
import com.tradecloud.domain.base.utils.LocaleDateRange;
import com.tradecloud.domain.infrastructure.persistence.CriteriaBuilder;
import com.tradecloud.domain.model.ForexGroup;
import com.tradecloud.domain.model.LinkedType;
import com.tradecloud.domain.model.Money;
import com.tradecloud.domain.model.fec.*;
import com.tradecloud.domain.model.organisationalunit.OrganisationalUnit;
import com.tradecloud.domain.treasury.TreasuryBank;
import com.tradecloud.dto.treasury.DefaultDTO;
import com.tradecloud.dto.treasury.FECSearchDTO;
import com.tradecloud.repository.FECRepository;
import com.tradecloud.repository.GeneralRepository;
import com.tradecloud.repository.SearchMetaParams;
import com.tradecloud.repository.base.impl.RepositoryBaseImpl;
import com.tradecloud.repository.staticdata.StaticDataRepository;
import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.joda.time.LocalDate;
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.util.*;

@Repository(value = "fecRepository")
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
public class FECRepositoryImpl extends RepositoryBaseImpl<IFEC, Object> implements FECRepository {

    private static final Logger log = Logger.getLogger(FECRepositoryImpl.class);

    @Autowired
    private GeneralRepository generalRepository;

    @Autowired
    private StaticDataRepository staticDataRepository;

    @Override
    public void store(IFEC fec) {
        save(fec);
    }

    @Override
    public List<IFEC> findAll(String sortBy) {
        if (sortBy == null) {
            return findAll();
        }

        return getSessionCustom().createQuery("from FEC order by :sortBy").setParameter("sortBy", sortBy).list();
    }

    @Override
    public List<IFEC> findAll() {
        return getSessionCustom().createQuery("from FEC").list();
    }

    @Override
    public IFEC find(Long id) {
        return (IFEC) getSessionCustom().createQuery("from FEC where id = :id").setParameter("id", id).uniqueResult();
    }

    @Override
    public List<IFEC> findAllMatching(List<OrganisationalUnit> organisationalUnits, Currency currency, FECStatusType fecStatus, DateRange dateRange,
                                      ForexGroup forexGroup,TreasuryBank bank) {
        Date maturityDateFrom = dateRange.getFrom();
        Date maturityDateTo = dateRange.getTo();
        LocalDate ldMaturityDateFrom = maturityDateFrom != null ? new LocalDate(maturityDateFrom.getTime()) : null;
        LocalDate ldMaturityDateTo = maturityDateTo != null ? new LocalDate(maturityDateTo.getTime()) : null;

        DetachedCriteria criteria = DetachedCriteria.forClass(IFEC.class);

        if (ldMaturityDateFrom != null) {
            criteria.add(Restrictions.ge("maturityDate", ldMaturityDateFrom));
        }

        if (ldMaturityDateTo != null) {
            criteria.add(Restrictions.le("maturityDate", ldMaturityDateTo));
        }

        if (currency != null) {
            criteria.add(Restrictions.eq("amount.currency", currency));
        }
        if (organisationalUnits != null && !organisationalUnits.isEmpty()) {
            criteria.add(Restrictions.in("organisationalUnit", organisationalUnits));
        }
        if (forexGroup != null) {
            criteria.add(Restrictions.eq("forexGroup", forexGroup));
        }
        if(bank!=null){
            criteria.add(Restrictions.eq("bankDetails.treasuryBank", bank));
        }

        return (List<IFEC>) findByCriteria(criteria);
    }

    @Override
    public List<IFEC> findAllMatching(OrganisationalUnit organisationalUnit, LocaleDateRange maturityDateRange,
                                      Money dealAmount, ForexGroup forexGroup,
                                      String sortBy, boolean includeFECsWithOrgUnitALL) {
        log.debug("Query for FECs. OrganisationalUnit '" + organisationalUnit + maturityDateRange + " amount '" + dealAmount + "', sort '" +
                sortBy + "'");
        String queryString = buildQueryString(sortBy, includeFECsWithOrgUnitALL);
        Query query = getSessionCustom().createQuery(queryString);
        if (!includeFECsWithOrgUnitALL) {
            query.setParameter("organisationalUnit", organisationalUnit);
        }
        query.setParameter("maturityDateMin", maturityDateRange.getFrom()).
                setParameter("maturityDateMax", maturityDateRange.getTo()).
                setParameter("dealAmountCurrency", dealAmount.getCurrency()).
                setParameter("forexGroup", forexGroup);
        return query.list();
    }

    private String buildQueryString(String sortBy, boolean includeFECsWithOrgUnitALL) {
        String includeFecsWithOrgUnitALL = includeFECsWithOrgUnitALL ? " " : "organisationalUnit = :organisationalUnit and ";
        return "from FEC where " + includeFecsWithOrgUnitALL + " maturityDate >= :maturityDateMin and maturityDate <= :maturityDateMax" +
                " and unlinkedAmount.currency = :dealAmountCurrency  and trunc(unlinkedAmount.value,2) >0.00 and forexGroup = :forexGroup order by "
                + sortBy;
    }

    @Override
    public IFEC findByBankReference(BankReference bankReference) {
        Query query = getSessionCustom().createQuery("from FEC where upper(bankReference.reference) = :bankReference");
        query.setParameter("bankReference", bankReference.getReference().toUpperCase());
        return (IFEC) query.uniqueResult();
    }

    @Deprecated
    @Override
    public List<IFEC> findAllByBankReference(BankReference bankReference) {
        Query query = getSessionCustom().createQuery("from FEC where upper(bankReference.reference) like upper(:bankReference)");
        query.setParameter("bankReference", bankReference.getReference().toUpperCase());
        return query.list();
    }

    public List<IFEC> findByQuery(String query) {
        return getSessionCustom().createQuery(query).list();
    }

    private DetachedCriteria getDetachedCriteria(BankReference bankReference, InternalReference internalReference, LocalDate maturityDateFrom,
                                                 LocalDate maturityDateTo, LocalDate dealDateFrom, LocalDate dealDateTo, TreasuryBank treasuryBank,
                                                 String bankDealer, Currency amountCurrency, FECStatusType fecStatusType, LinkedType linkedType,
                                                 SortBy sortBy, boolean mustIncludeMaturedFECs, OrganisationalUnit organisationalUnit,
                                                 ForexGroup forexGroup, FECTransactionType fecTransactionType,String parentFecId) {
        DetachedCriteria criteria = DetachedCriteria.forClass(FEC.class);
//        criteria.createAlias("bankDetails","bank");
        if (bankReference != null) {
            criteria.add(Restrictions.ilike("bankReference.reference", "%" + bankReference.getReference() + "%"));
        }

        if (internalReference != null) {
            criteria.add(Restrictions.ilike("internalReference.reference", "%" + internalReference.getReference() + "%"));
        }
        if (treasuryBank != null) {
            criteria.add(Restrictions.eq("bankDetails.treasuryBank", treasuryBank ));
        }
        if (bankDealer != null) {
            criteria.add(Restrictions.ilike("bankDetails.dealer", "%" + bankDealer + "%"));
        }
        if (amountCurrency != null) {
            criteria.add(Restrictions.eq("amount.currency", amountCurrency));
        }
        if (organisationalUnit != null) {
            criteria.add(Restrictions.eq("organisationalUnit", organisationalUnit));
        }
        if (forexGroup != null) {
            criteria.add(Restrictions.eq("forexGroup", forexGroup));
        }

        if(parentFecId!=null){
            criteria.add(Restrictions.sqlRestriction("parent_fec::TEXT ilike '%" + parentFecId + "%'"));
        }

        if (fecStatusType != null) {
            if (!mustIncludeMaturedFECs) {
                switch (fecStatusType) {
                    case ESTABLISHED:
                        criteria.add(Restrictions.eq("confirmed", false));
                        break;
                    case CONFIRMED:
                        criteria.add(Restrictions.eq("confirmed", true));
                        criteria.add(Restrictions.gt("maturityDate", new LocalDate()));
                        break;
                    case MATURED:
                        criteria.add(Restrictions.gt("maturityDate", new LocalDate()));
                        criteria.add(Restrictions.lt("maturityDate", new LocalDate()));
                        break;
                }

            } else {
                switch (fecStatusType) {
                    case ESTABLISHED:
                        criteria.add(Restrictions.eq("confirmed", false));
                        break;
                    case CONFIRMED:
                        criteria.add(Restrictions.eq("confirmed", true));
                        break;
                    case MATURED:
                        criteria.add(Restrictions.lt("maturityDate", new LocalDate()));
                        criteria.add(Restrictions.eq("confirmed", true));
                        break;
                }
            }
        } else {
            if (!mustIncludeMaturedFECs) {
                criteria.add(Restrictions.not(Restrictions.and(Restrictions.lt("maturityDate", new LocalDate()), Restrictions.eq("confirmed",
                        true))));
            }
        }

        if (linkedType != null) {
            switch (linkedType) {
                case FULLY_LINKED:
                    criteria.add(Restrictions.sqlRestriction("round(unlinked_amount_value,2)=0.0")) ;
                    break;
                case NOT_FULLY_LINKED:
                    criteria.add(Restrictions.sqlRestriction("round(unlinked_amount_value,2)<>0.0"));
                    break;
            }
        }

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

        if (sortBy != null) {
            criteria.addOrder(Property.forName(sortBy.getPropertyName()).asc());
            //This will resolve paging issue when two records have the same sortBy date.
            criteria.addOrder(Property.forName("created").asc());
        }
        criteria = criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);

        CriteriaBuilder.addDateRangeCriteria(criteria, "dealDate", dealDateFrom, dealDateTo);
        CriteriaBuilder.addDateRangeCriteria(criteria, "maturityDate", maturityDateFrom, maturityDateTo);
        return criteria;
    }

    @Override
    public List<IFEC> findSurrenderFEC(Long originalFECId) {
        DetachedCriteria criteria = DetachedCriteria.forClass(SurrenderFEC.class);
        criteria.add(Restrictions.eq("parent.id", originalFECId));
        return (List<IFEC>) findByCriteria(criteria);
    }

    @Override
    public long count(FECSearchDTO search) {
        SortBy sortBy = null;
        DetachedCriteria detachedCriteria = getDetachedCriteria(search, sortBy);
        return getExecutableCriteriaCount(detachedCriteria);
    }

    @Override
    public List<IFEC> search(FECSearchDTO search) {
        SortBy sortBy = search.getSortBy();
        DetachedCriteria detachedCriteria = getDetachedCriteria(search, sortBy);
        SearchMetaParams searchMetaParams = search.isSelectAll() ? null : search.getSearchMetaParams();
        return getExecutableCriteriaList(detachedCriteria, searchMetaParams);
    }

    private DetachedCriteria getDetachedCriteria(FECSearchDTO search, SortBy sortBy) {
        LocalDate maturityDateFrom = DateUtils.toLocalDate(search.getMaturityDate().getFrom());
        LocalDate maturityDateTo = DateUtils.toLocalDate(search.getMaturityDate().getTo());
        LocalDate dealDateFrom = DateUtils.toLocalDate(search.getDealDate().getFrom());
        LocalDate dealDateTo = DateUtils.toLocalDate(search.getDealDate().getTo());
        DefaultDTO organisationalUnit1 = search.getOrganisationalUnit();
        OrganisationalUnit organisationalUnit = organisationalUnit1 != null ?
                generalRepository.retrieve(OrganisationalUnit.class, organisationalUnit1.getId()) : null;
        DefaultDTO forexGroup1 = search.getForexGroup();
        ForexGroup forexGroup = forexGroup1 != null ? generalRepository.retrieve(ForexGroup.class, forexGroup1.getId()) : null;
        BankReference bankReference = search.getBankReference() != null ? BankReference.valueOf(search.getBankReference()) : null;
        InternalReference internalReference = search.getInternalReference() != null ? InternalReference.valueOf(search.getInternalReference()) : null;
        Currency currency = search.getCurrency() != null ? Currency.getInstance(search.getCurrency().getCode()) : null;
        TreasuryBank treasuryBank= search.getTreasuryBank()!=null?  staticDataRepository.findByCode(search.getTreasuryBank().getCode(),
                TreasuryBank.class):null;
        return getDetachedCriteria(bankReference, internalReference, maturityDateFrom, maturityDateTo, dealDateFrom,
                dealDateTo, treasuryBank, search.getDealer(), currency, search.getStatus(), search.getLinked(), sortBy,
                search.isIncludeMaturedFec(), organisationalUnit, forexGroup, search.getFecTransactionType(),search.getParentFecId());
    }

    @Override
    public List<FEC> find(Set<Long> fecIds) {
        if (fecIds == null || fecIds.isEmpty()) {
            return Collections.emptyList();
        }
        List<FEC> fecs = getSessionCustom()
                .createQuery("from FEC d where d.id in (:ids)", FEC.class)
                .setParameter("ids", fecIds)
                .list();
         return fecs;
    }
}