/* 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.controls.invoices; import java.util.LinkedList; import java.util.List; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.servlet.http.HttpServletRequest; import nl.strohalm.cyclos.annotations.Inject; import nl.strohalm.cyclos.controls.ActionContext; import nl.strohalm.cyclos.controls.BaseQueryAction; import nl.strohalm.cyclos.entities.EntityReference; import nl.strohalm.cyclos.entities.accounts.AccountOwner; 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.TransferType; import nl.strohalm.cyclos.entities.accounts.transactions.TransferTypeQuery; import nl.strohalm.cyclos.entities.groups.AdminGroup; import nl.strohalm.cyclos.entities.members.Element; import nl.strohalm.cyclos.entities.members.Member; import nl.strohalm.cyclos.entities.members.Operator; import nl.strohalm.cyclos.entities.members.OperatorQuery; import nl.strohalm.cyclos.entities.settings.LocalSettings; import nl.strohalm.cyclos.entities.settings.events.LocalSettingsChangeListener; import nl.strohalm.cyclos.entities.settings.events.LocalSettingsEvent; import nl.strohalm.cyclos.exceptions.PermissionDeniedException; import nl.strohalm.cyclos.services.transactions.InvoiceService; import nl.strohalm.cyclos.services.transactions.TransactionContext; import nl.strohalm.cyclos.services.transfertypes.TransferTypeService; import nl.strohalm.cyclos.utils.RequestHelper; import nl.strohalm.cyclos.utils.TransformedIteratorList; import nl.strohalm.cyclos.utils.binding.BeanBinder; import nl.strohalm.cyclos.utils.binding.DataBinder; import nl.strohalm.cyclos.utils.binding.DataBinderHelper; import nl.strohalm.cyclos.utils.binding.PropertyBinder; import nl.strohalm.cyclos.utils.conversion.AccountOwnerConverter; import nl.strohalm.cyclos.utils.conversion.ReferenceConverter; import nl.strohalm.cyclos.utils.conversion.Transformer; import nl.strohalm.cyclos.utils.query.Page; import nl.strohalm.cyclos.utils.query.PageImpl; import nl.strohalm.cyclos.utils.query.QueryParameters; import nl.strohalm.cyclos.utils.validation.ValidationException; /** * Action used to retrieve the invoices of a given member * @author luis */ public class SearchInvoicesAction extends BaseQueryAction implements LocalSettingsChangeListener { public static class Entry { private Invoice invoice; private Member relatedMember; private String relatedName; public Invoice getInvoice() { return invoice; } public Member getRelatedMember() { return relatedMember; } public String getRelatedName() { return relatedName; } public void setInvoice(final Invoice invoice) { this.invoice = invoice; } public void setRelatedMember(final Member relatedMember) { this.relatedMember = relatedMember; } public void setRelatedName(final String relatedName) { this.relatedName = relatedName; } } public class TransformInvoiceInEntry implements Transformer<Invoice, Entry> { private AccountOwner owner; private LocalSettings localSettings; public TransformInvoiceInEntry(final AccountOwner owner) { this.owner = owner; localSettings = settingsService.getLocalSettings(); } @Override public Entry transform(final Invoice invoice) { final Entry entry = new Entry(); entry.setInvoice(invoice); final AccountOwner from = invoice.getFrom(); final AccountOwner to = invoice.getTo(); final AccountOwner related = owner.equals(from) ? to : from; if (related instanceof Member) { try { entry.setRelatedMember((Member) elementService.load(((Member) related).getId())); } catch (final PermissionDeniedException e) { // Ok. The logged member cannot see this member } } if (entry.getRelatedMember() == null) { if (related instanceof Member) { entry.setRelatedName(((Member) related).getUsername()); } else { entry.setRelatedName(localSettings.getApplicationUsername()); } } return entry; } } private DataBinder<InvoiceQuery> dataBinder; private InvoiceService invoiceService; private TransferTypeService transferTypeService; private ReadWriteLock lock = new ReentrantReadWriteLock(true); public DataBinder<InvoiceQuery> getDataBinder() { try { lock.readLock().lock(); if (dataBinder == null) { final LocalSettings localSettings = settingsService.getLocalSettings(); final BeanBinder<InvoiceQuery> binder = BeanBinder.instance(InvoiceQuery.class); binder.registerBinder("owner", PropertyBinder.instance(AccountOwner.class, "owner", AccountOwnerConverter.instance())); binder.registerBinder("direction", PropertyBinder.instance(InvoiceQuery.Direction.class, "direction")); binder.registerBinder("status", PropertyBinder.instance(Invoice.Status.class, "status")); binder.registerBinder("transferType", PropertyBinder.instance(TransferType.class, "transferType", ReferenceConverter.instance(TransferType.class))); binder.registerBinder("period", DataBinderHelper.periodBinder(localSettings, "period")); binder.registerBinder("relatedOwner", PropertyBinder.instance(AccountOwner.class, "relatedMemberId", AccountOwnerConverter.zeroIsSystemInstance())); binder.registerBinder("description", PropertyBinder.instance(String.class, "description")); binder.registerBinder("transactionNumber", PropertyBinder.instance(String.class, "transactionNumber")); binder.registerBinder("by", PropertyBinder.instance(Element.class, "by", ReferenceConverter.instance(Element.class))); binder.registerBinder("pageParameters", DataBinderHelper.pageBinder()); dataBinder = binder; } return dataBinder; } finally { lock.readLock().unlock(); } } public InvoiceService getInvoiceService() { return invoiceService; } public TransferTypeService getTransferTypeService() { return transferTypeService; } @Override public void onLocalSettingsUpdate(final LocalSettingsEvent event) { try { lock.writeLock().lock(); super.onLocalSettingsUpdate(event); dataBinder = null; } finally { lock.writeLock().unlock(); } } @Inject public void setInvoiceService(final InvoiceService invoiceService) { this.invoiceService = invoiceService; } @Inject public void setTransferTypeService(final TransferTypeService transferTypeService) { this.transferTypeService = transferTypeService; } @Override protected void executeQuery(final ActionContext context, final QueryParameters queryParameters) { final InvoiceQuery query = (InvoiceQuery) queryParameters; final List<Invoice> invoices = invoiceService.search(query); final TransformInvoiceInEntry transformer = new TransformInvoiceInEntry(query.getOwner()); List<Entry> entries = new TransformedIteratorList<Invoice, Entry>(transformer, invoices); if (invoices instanceof Page<?>) { final Page<Invoice> page = (Page<Invoice>) invoices; entries = new PageImpl<Entry>(queryParameters.getPageParameters(), page.getTotalCount(), new LinkedList<Entry>(entries)); } context.getRequest().setAttribute("invoices", entries); } @Override protected QueryParameters prepareForm(final ActionContext context) { final HttpServletRequest request = context.getRequest(); final SearchInvoicesForm form = context.getForm(); final InvoiceQuery query = getDataBinder().readFromString(form.getQuery()); final Element loggedElement = context.getElement(); // Set the initial parameters if (query.getOwner() == null) { final AccountOwner owner = context.getAccountOwner(); query.setOwner(owner); form.setQuery("memberId", owner instanceof Member ? ((Member) owner).getId().toString() : "0"); } if (query.getDirection() == null) { query.setDirection(InvoiceQuery.Direction.INCOMING); form.setQuery("direction", InvoiceQuery.Direction.INCOMING.name()); } if (context.isAdmin()) { AdminGroup adminGroup = context.getGroup(); adminGroup = groupService.load(adminGroup.getId(), AdminGroup.Relationships.MANAGES_GROUPS); query.setGroups(adminGroup.getManagesGroups()); form.setAdvanced(true); } // Retrieve the data we need Member member = null; boolean myInvoices = false; boolean byBroker = false; boolean byOperator = false; final AccountOwner owner = query.getOwner(); if (owner instanceof SystemAccountOwner) { if (context.isAdmin()) { myInvoices = true; } else { throw new ValidationException(); } } else { member = elementService.load(((Member) owner).getId(), Element.Relationships.USER); myInvoices = loggedElement.equals(member); byBroker = context.isBrokerOf(member); byOperator = context.isOperator() && member.equals(((Operator) loggedElement).getMember()); if (!context.isAdmin() && !myInvoices && !byBroker && !byOperator) { throw new ValidationException(); } } // Search the possible transfer types final TransferTypeQuery ttQuery = new TransferTypeQuery(); ttQuery.setContext(TransactionContext.PAYMENT); ttQuery.setFromOrToOwner(owner); if (context.isAdmin()) { AdminGroup adminGroup = context.getGroup(); adminGroup = groupService.load(adminGroup.getId(), AdminGroup.Relationships.MANAGES_GROUPS); ttQuery.setFromOrToGroups(adminGroup.getManagesGroups()); } final List<TransferType> transferTypes = transferTypeService.search(ttQuery); // Fetch the query entities if (query.getRelatedMember() instanceof EntityReference) { query.setRelatedOwner((Member) elementService.load(query.getRelatedMember().getId(), Element.Relationships.USER)); } if (query.getTransferType() instanceof EntityReference) { query.setTransferType(transferTypeService.load(query.getTransferType().getId())); } // Lists the operators when member if (context.isMember() && form.isAdvanced()) { final OperatorQuery oq = new OperatorQuery(); oq.setMember((Member) context.getElement()); final List<? extends Element> operators = elementService.search(oq); request.setAttribute("operators", operators); } // Store the request attributes request.setAttribute("myInvoices", myInvoices); request.setAttribute("member", member); request.setAttribute("byBroker", byBroker); request.setAttribute("transferTypes", transferTypes); RequestHelper.storeEnum(request, InvoiceQuery.Direction.class, "directions"); RequestHelper.storeEnum(request, Invoice.Status.class, "status"); form.setMemberId((member == null) ? 0L : member.getId()); return query; } @Override protected boolean willExecuteQuery(final ActionContext context, final QueryParameters queryParameters) throws Exception { // The query is always executed return true; } }