/** * Copyright 2010 Archfirst * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.archfirst.bfoms.domain.account; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; import org.archfirst.bfoms.domain.marketdata.MarketDataService; import org.archfirst.bfoms.domain.referencedata.ReferenceDataService; import org.archfirst.bfoms.domain.security.AuthorizationException; import org.archfirst.common.money.Money; import org.archfirst.common.quantity.DecimalQuantity; import org.joda.time.DateTime; /** * BaseAccountService * * @author Naresh Bhatia */ public class BaseAccountService { // ----- Commands ----- public void changeAccountName(Long accountId, String newName) { this.findAccount(accountId).changeName(newName); } /** * Transfer cash from the specified account to the specified account. * Amount should always be positive. */ public void transferCash( String username, Money amount, Long fromAccountId, Long toAccountId) { this.transferCash( username, amount, this.findAccount(fromAccountId), this.findAccount(toAccountId)); } private void transferCash( String username, Money amount, BaseAccount fromAccount, BaseAccount toAccount) { // Check authorization on from account // TODO: This needs to be done // Check if cash is available if (!fromAccount.isCashAvailable(amount, marketDataService)) { throw new InsufficientFundsException(); } // Transfer the cash DateTime now = new DateTime(); CashTransfer fromTransfer = new CashTransfer(now, amount.negate(), toAccount); CashTransfer toTransfer = new CashTransfer(now, amount, fromAccount); baseAccountRepository.persist(fromTransfer); baseAccountRepository.persist(toTransfer); baseAccountRepository.flush(); // get object ids before adding to set fromAccount.transferCash(fromTransfer); toAccount.transferCash(toTransfer); } /** * Transfer securities from the specified account to the specified account. * Quantity should always be positive. */ public void transferSecurities( String username, String symbol, DecimalQuantity quantity, Money pricePaidPerShare, Long fromAccountId, Long toAccountId) { this.transferSecurities( username, symbol, quantity, pricePaidPerShare, this.findAccount(fromAccountId), this.findAccount(toAccountId)); } private void transferSecurities( String username, String symbol, DecimalQuantity quantity, Money pricePaidPerShare, BaseAccount fromAccount, BaseAccount toAccount) { // Check authorization on from account // TODO: This needs to be done // Check if the symbol is valid if (this.referenceDataService.lookup(symbol) == null) { throw new InvalidSymbolException(); } // Check if security is available if (!fromAccount.isSecurityAvailable(symbol, quantity)) { throw new InsufficientQuantityException(); } // Transfer the security DateTime now = new DateTime(); SecuritiesTransfer fromTransfer = new SecuritiesTransfer( now, symbol, quantity.negate(), pricePaidPerShare, toAccount); SecuritiesTransfer toTransfer = new SecuritiesTransfer( now, symbol, quantity, pricePaidPerShare, fromAccount); baseAccountRepository.persist(fromTransfer); baseAccountRepository.persist(toTransfer); baseAccountRepository.flush(); // get object ids before adding to set fromAccount.transferSecurities(fromTransfer); toAccount.transferSecurities(toTransfer); } // ----- Queries ----- public BaseAccount findAccount(Long id) { return baseAccountRepository.findAccount(id); } public List<Transaction> findTransactions(TransactionCriteria criteria) { return baseAccountRepository.findTransactions( toTransactionCriteriaInternal(criteria)); } /** * This version returns transactions for a single account, and does not * implement security checks (difficult to set up security checks for * mixed brokerage and external accounts). For a better implementation * look at BrokerageAccountService.getTransactionSummaries(). */ public List<TransactionSummary> getTransactionSummaries( String username, TransactionCriteria criteria) { // Check authorization on account // TODO: This needs to be done // Currently we are only checking if accountId is specified if (criteria.getAccountId() == null) throw new AuthorizationException(); List<Transaction> transactions = baseAccountRepository.findTransactions( toTransactionCriteriaInternal(criteria)); List<TransactionSummary> summaries = new ArrayList<TransactionSummary>(); for (Transaction transaction : transactions) { summaries.add(new TransactionSummary(transaction)); } return summaries; } private TransactionCriteriaInternal toTransactionCriteriaInternal( TransactionCriteria criteria) { List<Long> accountIds = new ArrayList<Long>(); if (criteria.getAccountId() != null) { accountIds.add(criteria.getAccountId()); } return new TransactionCriteriaInternal(criteria, accountIds); } // ----- Attributes ----- @Inject private BaseAccountRepository baseAccountRepository; @Inject private ReferenceDataService referenceDataService; @Inject private MarketDataService marketDataService; }