/*
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.Currency;
import nl.strohalm.cyclos.entities.accounts.SystemAccountOwner;
import nl.strohalm.cyclos.entities.accounts.transactions.Invoice;
import nl.strohalm.cyclos.entities.accounts.transactions.InvoiceQuery;
import nl.strohalm.cyclos.entities.accounts.transactions.InvoiceQuery.Direction;
import nl.strohalm.cyclos.entities.accounts.transactions.InvoiceSummaryDTO;
import nl.strohalm.cyclos.entities.accounts.transactions.Payment;
import nl.strohalm.cyclos.entities.accounts.transactions.PaymentFilter;
import nl.strohalm.cyclos.entities.accounts.transactions.Transfer;
import nl.strohalm.cyclos.entities.exceptions.EntityNotFoundException;
import nl.strohalm.cyclos.entities.groups.MemberGroup;
import nl.strohalm.cyclos.entities.reports.InvoiceSummaryType;
import nl.strohalm.cyclos.services.transactions.TransactionSummaryVO;
import nl.strohalm.cyclos.utils.Period;
import nl.strohalm.cyclos.utils.hibernate.HibernateHelper;
import org.apache.commons.collections.CollectionUtils;
/**
* Implementation class for invoice DAO
* @author rafael
*/
public class InvoiceDAOImpl extends BaseDAOImpl<Invoice> implements InvoiceDAO {
public InvoiceDAOImpl() {
super(Invoice.class);
}
public TransactionSummaryVO getSummary(final InvoiceSummaryDTO dto) {
final Direction direction = dto.getDirection();
final AccountOwner owner = dto.getOwner();
final AccountOwner relatedOwner = dto.getRelatedOwner();
PaymentFilter filter = dto.getFilter();
final Period period = dto.getPeriod();
final Invoice.Status status = dto.getStatus();
final HashMap<String, Object> namedParameters = new HashMap<String, Object>();
final StringBuilder hql = new StringBuilder("select new " + TransactionSummaryVO.class.getName() + "(count(*), sum(e.amount)) from " + getEntityType().getName() + " e ");
hql.append(" where e." + (direction == Direction.INCOMING ? "to" : "from") + "Member" + (owner instanceof SystemAccountOwner ? " is null " : " = :owner"));
namedParameters.put("owner", owner);
if (dto.getCurrency() != null) {
hql.append(" and (exists (select tt.id from TransferType tt where tt = e.transferType and tt.from.currency = :currency) or exists (select at.id from AccountType at where at = e.destinationAccountType and at.currency = :currency))");
namedParameters.put("currency", dto.getCurrency());
}
if (dto.isFromMemberToMember()) {
hql.append(" and e." + (direction == Direction.INCOMING ? "from" : "to") + "Member is not null");
} else if (relatedOwner != null) {
hql.append(" and e." + (direction == Direction.INCOMING ? "from" : "to") + "Member" + (relatedOwner instanceof SystemAccountOwner ? " is null " : " = :relatedOwner"));
namedParameters.put("relatedOwner", relatedOwner);
}
if (CollectionUtils.isNotEmpty(dto.getTypes())) {
hql.append(" and ( ");
hql.append(" e.destinationAccountType in (:types) or ");
hql.append(" exists(select i.id from Invoice i where i.transferType.from in (:types) and i = e) or ");
hql.append(" exists(select i.id from Invoice i where i.transferType.to in (:types) and i = e) ");
hql.append(" ) ");
namedParameters.put("types", dto.getTypes());
}
if (status != null) {
hql.append(" and e.status = :status ");
namedParameters.put("status", status);
}
HibernateHelper.addPeriodParameterToQuery(hql, namedParameters, "e.date", period);
if (filter != null) {
filter = getFetchDao().fetch(filter, PaymentFilter.Relationships.TRANSFER_TYPES);
HibernateHelper.addInParameterToQuery(hql, namedParameters, "e.transferType", filter.getTransferTypes());
}
return uniqueResult(hql.toString(), namedParameters);
}
public TransactionSummaryVO getSummaryByType(final Currency currency, final InvoiceSummaryType invoiceSummaryType, final Collection<MemberGroup> memberGroups) {
final Map<String, Object> namedParameters = new HashMap<String, Object>();
String fromMember = " is not null ";
String toMember = " is not null ";
switch (invoiceSummaryType) {
case SYSTEM_INCOMING:
toMember = " is null ";
break;
case SYSTEM_OUTGOING:
fromMember = " is null ";
break;
}
final StringBuilder hql = new StringBuilder("select new " + TransactionSummaryVO.class.getName() + "(count(*), sum(i.amount)) from Invoice i ");
hql.append(" where i.fromMember " + fromMember + " and i.toMember " + toMember);
hql.append(" and (exists (select tt.id from TransferType tt where tt = i.transferType and tt.from.currency = :currency) or exists (select at.id from AccountType at where at = i.destinationAccountType and at.currency = :currency))");
namedParameters.put("currency", currency);
if (memberGroups != null && !memberGroups.isEmpty()) {
switch (invoiceSummaryType) {
case SYSTEM_INCOMING:
hql.append(" and i.fromMember.group in (:memberGroups) ");
break;
case SYSTEM_OUTGOING:
hql.append(" and i.toMember.group in (:memberGroups) ");
break;
case MEMBER:
hql.append(" and (i.fromMember.group in (:memberGroups) or i.toMember.group in (:memberGroups)) ");
break;
}
namedParameters.put("memberGroups", memberGroups);
}
namedParameters.put("status", Invoice.Status.OPEN);
hql.append(" and i.status = :status");
return uniqueResult(hql.toString(), namedParameters);
}
public Invoice loadByPayment(final Payment payment, final Relationship... fetch) throws EntityNotFoundException {
String property;
if (payment instanceof Transfer) {
property = "transfer";
} else {
property = "scheduledPayment";
}
final Map<String, ?> params = Collections.singletonMap("payment", payment);
final Invoice invoice = uniqueResult("from Invoice i where i." + property + " = :payment", params);
if (invoice == null) {
throw new EntityNotFoundException(getEntityType());
}
return getFetchDao().fetch(invoice, fetch);
}
public List<Invoice> search(final InvoiceQuery query) {
final Map<String, Object> namedParameters = new HashMap<String, Object>();
final Set<Relationship> fetch = query.getFetch();
final StringBuilder hql = new StringBuilder("select i from " + getEntityType().getName() + " i");
hql.append(" left join i.fromMember fm");
hql.append(" left join fm.group fmg");
hql.append(" left join i.toMember tm");
hql.append(" left join tm.group tmg");
HibernateHelper.appendJoinFetch(hql, getEntityType(), "i", fetch);
hql.append(" where 1 = 1");
HibernateHelper.addLikeParameterToQuery(hql, namedParameters, "i.description", query.getDescription());
HibernateHelper.addParameterToQuery(hql, namedParameters, "i.status", query.getStatus());
HibernateHelper.addParameterToQuery(hql, namedParameters, "i.transferType", query.getTransferType());
HibernateHelper.addParameterToQuery(hql, namedParameters, "i.transfer.transactionNumber", query.getTransactionNumber());
HibernateHelper.addPeriodParameterToQuery(hql, namedParameters, "i.date", query.getPeriod());
// With payments scheduled for inside the period
if (query.getPaymentPeriod() != null) {
hql.append(" and exists (select ip.id from InvoicePayment ip where ip.invoice = i");
HibernateHelper.addPeriodParameterToQuery(hql, namedParameters, "ip.date", query.getPaymentPeriod());
hql.append(" ) ");
}
final boolean isIncoming = query.getDirection() == Direction.INCOMING;
final String owner = (isIncoming) ? "to" : "from";
final String related = (isIncoming) ? "from" : "to";
if (query.getOwner() != null) {
if (query.getOwner() instanceof SystemAccountOwner) {
hql.append(" and i." + owner + "Member is null ");
} else {
HibernateHelper.addParameterToQuery(hql, namedParameters, "i." + owner + "Member", query.getOwner());
}
}
if (query.getRelatedOwner() != null) {
if (query.getRelatedOwner() instanceof SystemAccountOwner) {
hql.append(" and i." + related + "Member is null ");
} else {
HibernateHelper.addParameterToQuery(hql, namedParameters, "i." + related + "Member", query.getRelatedOwner());
}
}
if (query.getGroups() != null && !query.getGroups().isEmpty()) {
hql.append(" and (fmg in (:groups) or tmg in (:groups)) ");
namedParameters.put("groups", query.getGroups());
}
// Operated by
if (query.getBy() != null) {
hql.append(" and (i.performedBy = :by or i.sentBy = :by)");
namedParameters.put("by", query.getBy());
}
HibernateHelper.appendOrder(hql, "i.date desc");
return list(query, hql.toString(), namedParameters);
}
}