/* * Copyright (C) 2011 4th Line GmbH, Switzerland * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.fourthline.konto.server.dao; import org.hibernate.Query; import org.hibernate.transform.ResultTransformer; import org.fourthline.konto.shared.entity.Account; import org.fourthline.konto.shared.entity.AccountGroup; import org.fourthline.konto.shared.entity.AccountGroupLink; import org.fourthline.konto.shared.AccountType; import org.fourthline.konto.shared.query.AccountsQueryCriteria; import org.fourthline.konto.shared.entity.AssetAccount; import org.fourthline.konto.shared.entity.BankAccount; import org.fourthline.konto.shared.entity.ExpenseAccount; import org.fourthline.konto.shared.entity.IncomeAccount; import org.fourthline.konto.shared.entity.LiabilityAccount; import org.fourthline.konto.shared.entity.MonetaryUnit; import java.util.ArrayList; import java.util.List; /** * @author Christian Bauer */ public class AccountDAO extends HibernateDAO { protected String getAccountEntity(AccountType type) { if (type == null) return "Account"; switch (type) { case Asset: return AssetAccount.class.getSimpleName(); case BankAccount: return BankAccount.class.getSimpleName(); case Liability: return LiabilityAccount.class.getSimpleName(); case Income: return IncomeAccount.class.getSimpleName(); case Expense: return ExpenseAccount.class.getSimpleName(); } return null; } public List<AccountGroup> getAccountGroups(AccountType type, String name) { return getAccountGroups(type, name, false); } public List<AccountGroup> getAccountGroups(AccountType type, String name, boolean exactName) { StringBuilder sb = new StringBuilder(); sb.append("select distinct(ag)"); sb.append(" from ").append(getAccountEntity(type.getRootType())).append(" a,"); sb.append(" AccountGroupLink agl,"); sb.append(" AccountGroup ag"); sb.append(" where agl.accountId = a.id and agl.accountGroupId = ag.id"); if (name != null) { if (exactName) { sb.append(" and ag.name = :name"); } else { sb.append(" and lower(ag.name) like :name"); } } sb.append(" order by ag.name asc"); Query q = getCurrentSession().createQuery(sb.toString()); if (name != null) { if (exactName) { q.setString("name", name); } else { q.setString("name", name.toLowerCase() + "%"); } } return q.list(); } public Account getAccount(Long id) { List<Account> accounts = getAccounts(id); return accounts.size() == 1 ? accounts.get(0) : null; } public List<Account> getAccounts(Long... ids) { if (ids == null) return null; StringBuilder sb = new StringBuilder(); sb.append("select a, mu from Account a, MonetaryUnit mu"); sb.append(" where mu.id = a.monetaryUnitId and a.id in (:ids) order by a.id asc"); Query q = getCurrentSession().createQuery(sb.toString()); q.setParameterList("ids", ids); q.setResultTransformer(new ResultTransformer() { @Override public Object transformTuple(Object[] objects, String[] strings) { Account account = (Account) objects[0]; account.setMonetaryUnit((MonetaryUnit) objects[1]); return account; } @Override public List transformList(List list) { return list; } }); return q.list(); } public List<Account> getAccounts(AccountsQueryCriteria criteria) { StringBuilder sb = new StringBuilder(); sb.append("select a, mu from "); sb.append(getAccountEntity(criteria.getType())).append(" a, "); sb.append("MonetaryUnit mu"); sb.append(" where mu.id = a.monetaryUnitId"); // TODO: SQL IN clause, need to split huge lists of identifiers if (!criteria.isListOfIdentifiersEmpty()) { sb.append(" and a.id in(:ids)"); } else if (criteria.getStringFilter() != null) { sb.append(" and (lower(a.name) like :nameFilter"); sb.append(" or lower(a.groupName) like :nameFilter)"); } sb.append(" order by "); if (criteria.getOrderBy() != null && !criteria.getOrderBy().equals(Account.Property.name)) { if (criteria.getOrderBy().equals(Account.Property.groupName)) { sb.append(" lower(a.groupName)"); sb.append(criteria.isSortAscending() ? " asc" : " desc"); sb.append(" , lower(a.name)"); sb.append(criteria.isSortAscending() ? " asc" : " desc"); } } else { sb.append(" lower(a.name)"); sb.append(criteria.isSortAscending() ? " asc" : " desc"); } Query q = getCurrentSession().createQuery(sb.toString()); if (!criteria.isListOfIdentifiersEmpty()) { q.setParameterList("ids", criteria.getListOfIdentifiers()); } else if (criteria.getStringFilter() != null) { q.setString( "nameFilter", (criteria.isSubstringQuery() ? "%" : "") + criteria.getStringFilter().toLowerCase() + "%" ); } if (criteria.getMaxResults() != null) { q.setMaxResults(criteria.getMaxResults()); } q.setResultTransformer(new ResultTransformer() { @Override public Object transformTuple(Object[] objects, String[] strings) { Account account = (Account) objects[0]; account.setMonetaryUnit((MonetaryUnit) objects[1]); return account; } @Override public List transformList(List list) { return list; } }); return q.list(); } public Long persist(Account account) { getCurrentSession().saveOrUpdate(account); // Remove all existing links between groups and this account getCurrentSession().createQuery( "delete from AccountGroupLink acl where acl.accountId = :id" ).setLong("id", account.getId()).executeUpdate(); if (account.getGroupName() != null) { // Account is in a group, try to find it by name or create it List<AccountGroup> groups = getAccountGroups(account.getType(), account.getGroupName(), true); AccountGroup group = groups.size() == 1 ? groups.get(0) : new AccountGroup(account.getGroupName()); if (group.getId() == null) { // New group getCurrentSession().save(group); } // Save link between account and group getCurrentSession().save( new AccountGroupLink(account.getId(), group.getId()) ); } // Clean up any groups that have no accounts removeEmptyAccountGroups(); return account.getId(); } public void delete(Account account) { getCurrentSession().delete(account); removeEmptyAccountGroups(); } protected void removeEmptyAccountGroups() { getCurrentSession().createQuery( "delete from AccountGroup ag where not ag.id in " + "(select distinct(agl.accountGroupId) from AccountGroupLink agl)" ).executeUpdate(); } }