/* 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.webservices.rest; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import javax.servlet.http.HttpServletRequest; import nl.strohalm.cyclos.entities.accounts.Account; import nl.strohalm.cyclos.entities.accounts.AccountOwner; import nl.strohalm.cyclos.entities.accounts.Currency; import nl.strohalm.cyclos.entities.accounts.MemberAccount; import nl.strohalm.cyclos.entities.accounts.transactions.PaymentFilter; import nl.strohalm.cyclos.entities.accounts.transactions.PaymentFilterQuery; import nl.strohalm.cyclos.entities.accounts.transactions.PaymentFilterQuery.Context; import nl.strohalm.cyclos.entities.accounts.transactions.ScheduledPayment; import nl.strohalm.cyclos.entities.accounts.transactions.ScheduledPaymentQuery; import nl.strohalm.cyclos.entities.accounts.transactions.ScheduledPaymentQuery.SearchType; import nl.strohalm.cyclos.entities.accounts.transactions.ScheduledPaymentQuery.StatusGroup; import nl.strohalm.cyclos.entities.accounts.transactions.Transfer; import nl.strohalm.cyclos.entities.exceptions.EntityNotFoundException; import nl.strohalm.cyclos.entities.members.Contact; import nl.strohalm.cyclos.entities.members.Member; import nl.strohalm.cyclos.services.accounts.AccountDTO; import nl.strohalm.cyclos.services.accounts.AccountService; import nl.strohalm.cyclos.services.accounts.CurrencyService; import nl.strohalm.cyclos.services.elements.ContactService; import nl.strohalm.cyclos.services.elements.MemberService; import nl.strohalm.cyclos.services.transactions.PaymentService; import nl.strohalm.cyclos.services.transactions.ScheduledPaymentService; import nl.strohalm.cyclos.services.transfertypes.PaymentFilterService; import nl.strohalm.cyclos.utils.Period; import nl.strohalm.cyclos.utils.access.LoggedUser; import nl.strohalm.cyclos.utils.conversion.Transformer; import nl.strohalm.cyclos.webservices.accounts.AccountHistoryResultPage; import nl.strohalm.cyclos.webservices.accounts.ScheduledPaymentsResultPage; import nl.strohalm.cyclos.webservices.model.AccountHistoryTransferVO; import nl.strohalm.cyclos.webservices.model.AccountStatusVO; import nl.strohalm.cyclos.webservices.model.MemberAccountVO; import nl.strohalm.cyclos.webservices.model.MemberAccountWithStatusVO; import nl.strohalm.cyclos.webservices.model.PaymentFilterVO; import nl.strohalm.cyclos.webservices.model.ScheduledPaymentVO; import nl.strohalm.cyclos.webservices.model.SearchParameters; import nl.strohalm.cyclos.webservices.model.TransferDataVO; import nl.strohalm.cyclos.webservices.payments.AccountHistoryParams; import nl.strohalm.cyclos.webservices.utils.QueryHelper; import org.apache.commons.lang.StringUtils; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; /** * Controller which handles /accounts paths * * @author luis */ @Controller public class AccountsRestController extends BaseRestController { /** * Parameters for searching scheduled payments * @author luis */ public static class SearchScheduledPaymentParams extends SearchParameters { private static final long serialVersionUID = 1L; private String memberPrincipal; private Long memberId; private Calendar beginDate; private Calendar endDate; private Boolean incoming = false; private SearchScheduledPaymentStatus status; public Calendar getBeginDate() { return beginDate; } public Calendar getEndDate() { return endDate; } public boolean getIncoming() { return incoming; } public Long getMemberId() { return memberId; } public String getMemberPrincipal() { return memberPrincipal; } public SearchScheduledPaymentStatus getStatus() { return status; } public void setBeginDate(final Calendar beginDate) { this.beginDate = beginDate; } public void setEndDate(final Calendar endDate) { this.endDate = endDate; } public void setIncoming(final boolean incoming) { this.incoming = incoming; } public void setMemberId(final Long memberId) { this.memberId = memberId; } public void setMemberPrincipal(final String memberPrincipal) { this.memberPrincipal = memberPrincipal; } public void setStatus(final SearchScheduledPaymentStatus status) { this.status = status; } } public static enum SearchScheduledPaymentStatus { OPEN, CLOSED_WITHOUT_ERRORS, CLOSED_WITH_ERRORS; } private static final String CUSTOM_VALUE_PREFIX = "customValue."; private AccountService accountService; private ContactService contactService; private PaymentService paymentService; private QueryHelper queryHelper; private PaymentFilterService paymentFilterService; private ScheduledPaymentService scheduledPaymentService; private CurrencyService currencyService; private MemberService memberService; private PaymentFieldsRestController paymentFieldsRestController; @SuppressWarnings("unchecked") @RequestMapping(value = "accounts/info", method = RequestMethod.GET) @ResponseBody public List<MemberAccountWithStatusVO> getAccountsInfo() { List<MemberAccount> accounts = (List<MemberAccount>) accountService.getAccounts(LoggedUser.member()); List<MemberAccountWithStatusVO> result = new ArrayList<MemberAccountWithStatusVO>(); for (MemberAccount memberAccount : accounts) { AccountStatusVO statusVO = accountService.getCurrentAccountStatusVO(new AccountDTO(memberAccount)); MemberAccountVO accountVO = accountService.getMemberAccountVO(memberAccount.getId()); MemberAccountWithStatusVO as = new MemberAccountWithStatusVO(accountVO, statusVO); result.add(as); } return result; } /** * Returns the account status for the default account. */ @RequestMapping(value = "accounts/default/status", method = RequestMethod.GET) @ResponseBody public AccountStatusVO getDefaultStatus() { MemberAccount account = accountService.getDefaultAccount(); return accountService.getCurrentAccountStatusVO(new AccountDTO(account)); } /** * Returns the account status for the given account. */ @RequestMapping(value = "accounts/{id}/status", method = RequestMethod.GET) @ResponseBody public AccountStatusVO getStatus(@PathVariable final Long id) { MemberAccount account; try { account = accountService.load(id); } catch (Exception e) { throw new EntityNotFoundException(Account.class); } return accountService.getCurrentAccountStatusVO(new AccountDTO(account)); } /** * Returns the authenticated user's accounts */ @RequestMapping(value = "accounts", method = RequestMethod.GET) @ResponseBody @SuppressWarnings("unchecked") public List<MemberAccountVO> listAccounts() { List<MemberAccount> accounts = (List<MemberAccount>) accountService.getAccounts(LoggedUser.member()); List<MemberAccountVO> result = new ArrayList<MemberAccountVO>(accounts.size()); if (accounts != null) { for (MemberAccount memberAccount : accounts) { MemberAccountVO memberAccountVO = accountService.getMemberAccountVO(memberAccount.getId()); result.add(memberAccountVO); } } return result; } /** * Returns the available payment filters for an specific account */ @RequestMapping(value = "accounts/default/paymentFilters", method = RequestMethod.GET) @ResponseBody public List<PaymentFilterVO> listDefaultPaymentFilters() { MemberAccount account = accountService.getDefaultAccount(); return listPaymentFilters(account); } /** * Returns the available payment filters for an specific account */ @RequestMapping(value = "accounts/{id}/paymentFilters", method = RequestMethod.GET) @ResponseBody public List<PaymentFilterVO> listPaymentFilters(@PathVariable final Long id) { MemberAccount account; try { account = accountService.load(id); } catch (Exception e) { throw new EntityNotFoundException(Account.class); } return listPaymentFilters(account); } /** * Loads data for an account by id. The account must belong to the authenticated user. */ @RequestMapping(value = "accounts/{id}", method = RequestMethod.GET) @ResponseBody public MemberAccountVO loadAccount(@PathVariable final Long id) { return accountService.getMemberAccountVO(id); } /** * Attempts to load a currency by either id or symbol */ public Currency loadCurrencyByIdOrSymbol(final Long id, final String symbol) { String idOrSymbol = id == null ? symbol : id.toString(); if (StringUtils.isNotEmpty(idOrSymbol)) { return currencyService.loadBySymbolOrId(idOrSymbol); } return null; } /** * Loads data for an account by id. The account must belong to the authenticated user. */ @RequestMapping(value = "accounts/default", method = RequestMethod.GET) @ResponseBody public MemberAccountVO loadDefaultAccount() { MemberAccount account = accountService.getDefaultAccount(); return accountService.getMemberAccountVO(account.getId()); } /** * Loads a scheduled payment by id */ @RequestMapping(value = "accounts/scheduledPayment/{id}", method = RequestMethod.GET) @ResponseBody public ScheduledPaymentVO loadScheduledPayment(@PathVariable final Long id) { return scheduledPaymentService.getScheduledPaymentVO(id); } /** * Loads a transfer by id */ @RequestMapping(value = "accounts/transfer/{id}", method = RequestMethod.GET) @ResponseBody public AccountHistoryTransferVO loadTransfer(@PathVariable final Long id) { return paymentService.getAccountHistoryTransferVO(id); } /** * Loads a transfer by id and return it with the list of payment custom fields of the transfer type. */ @RequestMapping(value = "accounts/transferData/{id}", method = RequestMethod.GET) @ResponseBody public TransferDataVO loadTransferData(@PathVariable final Long id) { Transfer transfer; try { transfer = paymentService.load(id); } catch (Exception e) { throw new EntityNotFoundException(Transfer.class); } AccountHistoryTransferVO accountHistoryTransferVO = paymentService.getAccountHistoryTransferVO(id); AccountOwner relatedAccountOwner = null; if (LoggedUser.member().equals(transfer.getFromOwner())) { relatedAccountOwner = transfer.getToOwner(); } else { relatedAccountOwner = transfer.getFromOwner(); } boolean canAddRelatedMemberAsContact = false; // The related account owner can be added to the logged user's contact list if its a member and it's not already added. if (relatedAccountOwner != null && relatedAccountOwner instanceof Member && LoggedUser.member() != relatedAccountOwner) { Member m = (Member) relatedAccountOwner; Contact contact = contactService.loadIfExists(LoggedUser.member(), m); if (contact == null) { canAddRelatedMemberAsContact = true; } } return new TransferDataVO(accountHistoryTransferVO, canAddRelatedMemberAsContact); } /** * Searches for account history entries on the given account */ @RequestMapping(value = "accounts/{id}/history", method = RequestMethod.GET) @ResponseBody public AccountHistoryResultPage searchAccountHistory(@PathVariable final Long id, final AccountHistoryParams params, final HttpServletRequest request) { params.setMemberAccountId(id); return search(params, request); } /** * Searches for account history entries on the default account */ @RequestMapping(value = "accounts/default/history", method = RequestMethod.GET) @ResponseBody public AccountHistoryResultPage searchDefaultAccountHistory(final AccountHistoryParams params, final HttpServletRequest request) { params.setMemberAccountId(null); return search(params, request); } /** * Searches for scheduled payments on the default account */ @RequestMapping(value = "accounts/default/scheduledPayments", method = RequestMethod.GET) @ResponseBody public ScheduledPaymentsResultPage searchDefaultScheduledPayments(final SearchScheduledPaymentParams params) { MemberAccount account = accountService.getDefaultAccount(); return searchScheduledPayments(account, params); } /** * Searches for scheduled payments on the given account */ @RequestMapping(value = "accounts/{id}/scheduledPayments", method = RequestMethod.GET) @ResponseBody public ScheduledPaymentsResultPage searchScheduledPayments(@PathVariable final Long id, final SearchScheduledPaymentParams params) { MemberAccount account = accountService.load(id); return searchScheduledPayments(account, params); } public void setAccountService(final AccountService accountService) { this.accountService = accountService; } public void setContactService(final ContactService contactService) { this.contactService = contactService; } public void setCurrencyService(final CurrencyService currencyService) { this.currencyService = currencyService; } public void setMemberService(final MemberService memberService) { this.memberService = memberService; } public void setPaymentFieldsRestController(final PaymentFieldsRestController paymentFieldsRestController) { this.paymentFieldsRestController = paymentFieldsRestController; } public void setPaymentFilterService(final PaymentFilterService paymentFilterService) { this.paymentFilterService = paymentFilterService; } public void setPaymentService(final PaymentService paymentService) { this.paymentService = paymentService; } public void setQueryHelper(final QueryHelper queryHelper) { this.queryHelper = queryHelper; } public void setScheduledPaymentService(final ScheduledPaymentService scheduledPaymentService) { this.scheduledPaymentService = scheduledPaymentService; } private List<PaymentFilterVO> listPaymentFilters(final MemberAccount account) { PaymentFilterQuery query = new PaymentFilterQuery(); query.setContext(Context.ACCOUNT_HISTORY); query.setAccount(account); List<PaymentFilter> paymentFilters = paymentFilterService.search(query); return paymentFilterService.getPaymentFilterVOs(paymentFilters); } private AccountHistoryResultPage search(final AccountHistoryParams params, final HttpServletRequest request) { params.setCustomValues(paymentFieldsRestController.requestParametersToFieldValues(request, CUSTOM_VALUE_PREFIX)); return paymentService.getAccountHistoryResultPage(params); } private ScheduledPaymentsResultPage searchScheduledPayments(final MemberAccount account, final SearchScheduledPaymentParams params) { Member member = memberService.loadByIdOrPrincipal(params.getMemberId(), null, params.getMemberPrincipal()); // Convert the params to a TransferQuery ScheduledPaymentQuery query = new ScheduledPaymentQuery(); queryHelper.fill(params, query); query.setOwner(account.getOwner()); query.setMember(member); query.setPeriod(Period.between(params.getBeginDate(), params.getEndDate())); query.setSearchType(params.getIncoming() ? SearchType.INCOMING : SearchType.OUTGOING); if (params.getStatus() == null) { query.setStatusGroup(StatusGroup.OPEN); } else { query.setStatusGroup(StatusGroup.valueOf(params.getStatus().name())); } // Execute the search List<ScheduledPayment> scheduledPayments = scheduledPaymentService.search(query); return toScheduledResultPage(scheduledPayments); } private ScheduledPaymentsResultPage toScheduledResultPage(final List<ScheduledPayment> payments) { return queryHelper.toResultPage(ScheduledPaymentsResultPage.class, payments, new Transformer<ScheduledPayment, ScheduledPaymentVO>() { @Override public ScheduledPaymentVO transform(final ScheduledPayment scheduledPayment) { return scheduledPaymentService.getScheduledPaymentVO(scheduledPayment.getId()); } }); } }