/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
Cyclos is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Cyclos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package nl.strohalm.cyclos.dao.accounts.transactions;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import nl.strohalm.cyclos.dao.BaseDAOImpl;
import nl.strohalm.cyclos.entities.Relationship;
import nl.strohalm.cyclos.entities.accounts.AccountOwner;
import nl.strohalm.cyclos.entities.accounts.AccountType;
import nl.strohalm.cyclos.entities.accounts.MemberGroupAccountSettings;
import nl.strohalm.cyclos.entities.accounts.SystemAccountOwner;
import nl.strohalm.cyclos.entities.accounts.transactions.AuthorizationLevel.Authorizer;
import nl.strohalm.cyclos.entities.accounts.transactions.TransferType;
import nl.strohalm.cyclos.entities.accounts.transactions.TransferTypeQuery;
import nl.strohalm.cyclos.entities.exceptions.EntityNotFoundException;
import nl.strohalm.cyclos.entities.groups.AdminGroup;
import nl.strohalm.cyclos.entities.groups.Group;
import nl.strohalm.cyclos.entities.members.Element;
import nl.strohalm.cyclos.entities.members.Member;
import nl.strohalm.cyclos.services.transactions.TransactionContext;
import nl.strohalm.cyclos.utils.hibernate.HibernateHelper;
import org.apache.commons.collections.CollectionUtils;
/**
* Implementation class for transfer type DAO
* @author rafael
*/
public class TransferTypeDAOImpl extends BaseDAOImpl<TransferType> implements TransferTypeDAO {
public TransferTypeDAOImpl() {
super(TransferType.class);
}
@Override
public int delete(final boolean flush, final Long... ids) {
// We must remove the many-to-many inverse relationships manually
int rows = 0;
for (final Long id : ids) {
try {
final TransferType transferType = load(id, TransferType.Relationships.GROUPS, TransferType.Relationships.GROUPS_AS_MEMBER);
for (final Group group : transferType.getGroups()) {
group.getTransferTypes().remove(transferType);
}
for (final Group group : transferType.getGroupsAsMember()) {
group.getTransferTypes().remove(transferType);
}
// Ensure the initial credit relationship is removed
bulkUpdate("update " + MemberGroupAccountSettings.class.getName() + " set initialCreditTransferType=null where (initialCredit is null or initialCredit = 0) and initialCreditTransferType=:tt", Collections.singletonMap("tt", transferType));
getHibernateTemplate().delete(transferType);
getHibernateTemplate().flush();
rows++;
} catch (final EntityNotFoundException e) {
// Ignore
}
}
return rows;
}
@Override
public List<TransferType> search(final TransferTypeQuery query) {
final Map<String, Object> namedParameters = new HashMap<String, Object>();
namedParameters.put("system", AccountType.Nature.SYSTEM.getValue());
final Set<Relationship> fetch = query.getFetch();
final StringBuilder hql = HibernateHelper.getInitialQuery(getEntityType(), "tt", fetch);
HibernateHelper.addLikeParameterToQuery(hql, namedParameters, "tt.description", query.getDescription());
HibernateHelper.addLikeParameterToQuery(hql, namedParameters, "tt.name", query.getName());
// Context
final TransactionContext context = query.getContext();
if (context != null && context != TransactionContext.ANY) {
switch (context) {
case PAYMENT:
hql.append(" and tt.loan.type is null and tt.context.payment=true ");
break;
case SELF_PAYMENT:
hql.append(" and tt.loan.type is null and tt.context.selfPayment=true ");
break;
case LOAN:
hql.append(" and tt.loan.type is not null and tt.context.payment=true ");
break;
case AUTOMATIC:
hql.append(" and tt.loan.type is null ");
break;
case AUTOMATIC_LOAN:
hql.append(" and tt.loan.type is not null ");
break;
}
}
// Channel
if (query.getChannel() != null) {
hql.append(" and exists (select c.id from Channel c where c in elements(tt.channels) and c.internalName = :channel) ");
namedParameters.put("channel", query.getChannel());
}
// Currency
if (query.getCurrency() != null) {
hql.append(" and tt.from.currency = :currency");
namedParameters.put("currency", query.getCurrency());
}
// By another element
if (query.getBy() != null) {
final Element by = getFetchDao().fetch(query.getBy(), Element.Relationships.GROUP);
final Group group = by.getGroup();
hql.append(" and exists (select amtt.id from " + group.getClass().getName() + " g join g.transferTypesAsMember amtt where g = :byGroup and amtt = tt)");
namedParameters.put("byGroup", group);
}
final AccountOwner fromOwner = query.getFromOwner();
if (fromOwner != null) {
if (fromOwner instanceof SystemAccountOwner) {
// SystemAccountOwner is the same as SYSTEM nature, so, set the nature to handle it later
query.setFromNature(AccountType.Nature.SYSTEM);
} else {
// Member is the same as setting the group
final Member member = getFetchDao().fetch((Member) fromOwner, Element.Relationships.GROUP);
query.setFromGroups(Collections.singleton(member.getMemberGroup()));
}
}
final AccountOwner toOwner = query.getToOwner();
if (toOwner != null) {
if (toOwner instanceof SystemAccountOwner) {
// SystemAccountOwner is the same as SYSTEM nature, so, set the nature to handle it later
query.setToNature(AccountType.Nature.SYSTEM);
} else {
// Member is the same as setting the group, except that it may be to a fixed member
final Member member = getFetchDao().fetch((Member) toOwner, Element.Relationships.GROUP);
query.setToGroups(Collections.singleton(member.getMemberGroup()));
hql.append(" and (tt.fixedDestinationMember = :toMember or tt.fixedDestinationMember is null) ");
namedParameters.put("toMember", member);
}
}
final AccountOwner fromOrToOwner = query.getFromOrToOwner();
if (fromOrToOwner != null) {
if (fromOrToOwner instanceof SystemAccountOwner) {
// SystemAccountOwner is the same as SYSTEM nature, so, set the nature to handle it later
query.setFromOrToNature(AccountType.Nature.SYSTEM);
} else {
// Member is the same as setting the group
final Member member = getFetchDao().fetch((Member) fromOrToOwner, Element.Relationships.GROUP);
query.setFromOrToGroups(Collections.singleton(member.getMemberGroup()));
}
}
// Groups
if (CollectionUtils.isNotEmpty(query.getFromGroups())) {
hql.append(" and exists (select mgas.id from MemberGroupAccountSettings mgas where mgas.group in (:fromGroups) and mgas.accountType = tt.from) ");
namedParameters.put("fromGroups", query.getFromGroups());
}
if (CollectionUtils.isNotEmpty(query.getToGroups())) {
hql.append(" and exists (select mgas.id from MemberGroupAccountSettings mgas where mgas.group in (:toGroups) and mgas.accountType = tt.to) ");
namedParameters.put("toGroups", query.getToGroups());
}
if (CollectionUtils.isNotEmpty(query.getFromOrToGroups())) {
hql.append(" and exists (select mgas.id from MemberGroupAccountSettings mgas where mgas.group in (:fromOrToGroups) and (mgas.accountType = tt.from or mgas.accountType = tt.to)) ");
namedParameters.put("fromOrToGroups", query.getFromOrToGroups());
}
// Nature
if (query.getFromNature() != null) {
hql.append(" and tt.from.class = :fromNature");
namedParameters.put("fromNature", query.getFromNature().getValue());
}
if (query.getToNature() != null) {
hql.append(" and tt.to.class = :toNature");
namedParameters.put("toNature", query.getToNature().getValue());
}
if (query.getFromOrToNature() != null) {
hql.append(" and (tt.from.class = :fromOrToNature or tt.to.class = :fromOrToNature)");
namedParameters.put("fromOrToNature", query.getFromOrToNature().getValue());
}
// LimitType
if (query.getFromLimitType() != null) {
if (query.getFromLimitType().equals(AccountType.LimitType.UNLIMITED)) {
hql.append(" and tt.from.account.creditLimit is null");
} else {
hql.append(" and tt.from.account.creditLimit is not null");
}
}
if (query.getToLimitType() != null) {
if (query.getToLimitType().equals(AccountType.LimitType.UNLIMITED)) {
hql.append(" and tt.to.account.creditLimit is null");
} else {
hql.append(" and tt.to.account.creditLimit is not null");
}
}
// Account types
HibernateHelper.addInParameterToQuery(hql, namedParameters, "tt.from", query.getFromAccountTypes());
HibernateHelper.addInParameterToQuery(hql, namedParameters, "tt.to", query.getToAccountTypes());
final Collection<? extends AccountType> accountTypes = query.getFromOrToAccountTypes();
if (accountTypes != null && !accountTypes.isEmpty()) {
hql.append(" and (tt.to in (:fromOrToAT) or tt.from in (:fromOrToAT))");
namedParameters.put("fromOrToAT", accountTypes);
}
// Group
if (query.getGroup() != null) {
hql.append(" and :group in elements(tt.groups)");
namedParameters.put("group", query.getGroup());
}
// Flags
if (query.isPriority()) {
hql.append(" and tt.priority = true ");
}
if (query.isConciliable()) {
hql.append(" and tt.conciliable = true ");
}
if (query.isAuthorizable()) {
hql.append(" and tt.requiresAuthorization = true");
// Test the authorizers
final Collection<Authorizer> authorizers = query.getAuthorizers();
if (CollectionUtils.isNotEmpty(authorizers)) {
final AdminGroup authorizerGroup = query.getAuthorizerGroup();
namedParameters.put("authorizerGroup", authorizerGroup);
hql.append(" and (1<>1"); // This first condition is false, to not interfere on the OR conditions below
for (final Authorizer authorizer : authorizers) {
final String name = "authorizer_" + authorizer.ordinal();
hql.append(" or exists (select l.id from AuthorizationLevel l where l.transferType = tt and l.authorizer = :" + name);
// It may also have an admin group for authorizations
if (authorizerGroup != null) {
hql.append(" and :authorizerGroup in elements(l.adminGroups)");
}
hql.append(")");
namedParameters.put(name, authorizer);
}
hql.append(")");
}
}
if (query.isSchedulable()) {
hql.append(" and tt.allowsScheduledPayments = true");
}
if (CollectionUtils.isNotEmpty(query.getPossibleTransferTypes())) {
hql.append(" and tt in (:_possible)");
namedParameters.put("_possible", query.getPossibleTransferTypes());
}
HibernateHelper.appendOrder(hql, "tt.name");
return list(query, hql.toString(), namedParameters);
}
}