1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package net.sf.emarket.account.service;
22
23 import java.sql.Timestamp;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.Comparator;
27 import java.util.Date;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Set;
33
34 import net.sf.emarket.account.domain.Account;
35 import net.sf.emarket.account.domain.AcctPosition;
36 import net.sf.emarket.account.domain.AcctPositionSummary;
37 import net.sf.emarket.account.domain.AcctPositionTransfer;
38 import net.sf.emarket.account.domain.AcctValue;
39 import net.sf.emarket.account.domain.CashBalance;
40 import net.sf.emarket.account.domain.CashTransfer;
41 import net.sf.emarket.account.repository.IAccountDao;
42 import net.sf.emarket.account.repository.IAccountPositionDao;
43 import net.sf.emarket.account.repository.IAcctPositionTransferDao;
44 import net.sf.emarket.account.repository.ICashBalanceDao;
45 import net.sf.emarket.account.repository.ICashTransferDao;
46 import net.sf.emarket.quote.domain.Quote;
47 import net.sf.emarket.quote.service.IQuoteManagerService;
48 import net.sf.emarket.quote.service.SymbolsCannotBeEmptyException;
49 import net.sf.emarket.user.domain.User;
50 import net.sf.emarket.user.service.IUserManagerService;
51 import net.sf.emarket.user.service.UserNotFoundException;
52
53 import org.springframework.beans.factory.annotation.Autowired;
54 import org.springframework.dao.EmptyResultDataAccessException;
55 import org.springframework.transaction.annotation.Propagation;
56 import org.springframework.transaction.annotation.Transactional;
57
58
59
60 public class AccountManagerServiceImpl implements IAccountManagerService {
61
62 private static final long serialVersionUID = -5752914821716454464L;
63
64
65 private IAccountDao accountDao;
66 private IAccountPositionDao accountPositionDao;
67 private IAcctPositionTransferDao acctPositionTransferDao;
68 private ICashBalanceDao cashBalanceDao;
69 private ICashTransferDao cashTransferDao;
70
71 private IQuoteManagerService quoteMgr;
72 private IUserManagerService userMgr;
73
74 @Autowired
75 public void setAccountDao( IAccountDao dao){
76 accountDao = dao;
77 }
78
79 @Autowired
80 public void setAccountPositionDao( IAccountPositionDao dao){
81 accountPositionDao = dao;
82 }
83
84 @Autowired
85 public void setAcctPositionTransferDao( IAcctPositionTransferDao dao){
86 acctPositionTransferDao = dao;
87 }
88
89 @Autowired
90 public void setCashBalanceDao( ICashBalanceDao dao){
91 cashBalanceDao = dao;
92 }
93
94 @Autowired
95 public void setCashTransferDao( ICashTransferDao dao){
96 cashTransferDao = dao;
97 }
98
99 @Autowired
100 public void setQuoteManager( IQuoteManagerService mgr ){
101 quoteMgr = mgr;
102 }
103
104 @Autowired
105 public void setUserManager( IUserManagerService mgr ){
106 userMgr = mgr;
107 }
108
109 public void addAccount(Account account) {
110
111 long acctId = accountDao.generateAccountId();
112 account.setAcctId( Long.toString(acctId) );
113 account.setStatus(Account.STATUS_ACTIVE);
114
115 accountDao.addAccount(account);
116 }
117
118 public int deleteAccountById(String acctId) {
119 return accountDao.deleteAccountById(acctId);
120 }
121
122 public Account getAccountById(String acctId) {
123 return accountDao.getAccountById(acctId);
124 }
125
126 public List<Account> getAccountsForUser(User user) {
127 return accountDao.getAccountsForUser(user) ;
128 }
129
130 public List<Account> getAccountsOfType( String acctType ){
131 return accountDao.getAccountsOfType(acctType);
132 }
133
134 public int updateAccount(Account account) {
135 return accountDao.updateAccount(account);
136 }
137
138 public CashBalance getCashBalance(Account account) {
139
140 CashBalance balance = new CashBalance();
141
142 try{
143 balance = cashBalanceDao.getCashBalance(account);
144 }catch( EmptyResultDataAccessException ere){
145 balance.setAmount(0l);
146 }
147
148 return balance;
149 }
150
151 @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
152 public void tranferCash(CashTransfer transfer) throws NotEnoughCashException, NotValidAccountException {
153
154
155 CashBalance senderBalance = cashBalanceDao.getCashBalance(transfer.getSenderAcctId());
156 if( senderBalance.getAmount() < transfer.getAmount() ){
157 String message = "Account "+ transfer.getSenderAcctId() + " does not have cash to transfer";
158 throw new NotEnoughCashException( message );
159 }
160
161
162 Account receiverAccount = accountDao.getAccountById(transfer.getReceiverAcctId());
163
164 if( receiverAccount != null &&
165 ( receiverAccount.getStatus().equals( Account.STATUS_INACTIVE) ||
166 receiverAccount.getStatus().equals( Account.STATUS_DISABLED) )
167 ){
168
169 String message = "Receiver account "+ transfer.getReceiverAcctId() + " is not a valid account";
170 throw new NotValidAccountException(message);
171 }
172
173
174 float remaining = senderBalance.getAmount() - transfer.getAmount();
175 senderBalance.setAmount(remaining);
176 senderBalance.setAcctId(transfer.getSenderAcctId());
177 cashBalanceDao.updateCashBalance(senderBalance);
178
179
180 CashBalance receiverBalance = new CashBalance();
181 boolean insertFlag = false;
182
183 try{
184 receiverBalance = cashBalanceDao.getCashBalance(transfer.getReceiverAcctId());
185 }catch(EmptyResultDataAccessException ere){
186 insertFlag = true;
187 receiverBalance.setAmount(0f);
188 }
189
190 float addition = receiverBalance.getAmount() + transfer.getAmount();
191 receiverBalance.setAmount(addition);
192 receiverBalance.setAcctId(transfer.getReceiverAcctId());
193
194
195 if( insertFlag ){
196 cashBalanceDao.addCashBalance(receiverBalance);
197 }else{
198 cashBalanceDao.updateCashBalance(receiverBalance);
199 }
200
201
202 long transferId = cashTransferDao.generateTransferId();
203 transfer.setTransferId(transferId);
204
205 Date date = new Date();
206 Timestamp createdTime = new Timestamp( date.getTime());
207 transfer.setCreatedTime(createdTime);
208
209
210 transfer.setTransferStatus(CashTransfer.STATUS_COMPLETED);
211 cashTransferDao.addCashTransfer(transfer);
212 }
213
214 @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
215 public void transferPosition( AcctPositionTransfer transfer ) throws NotEnoughPositionsException, NotValidAccountException{
216
217
218 List<AcctPosition> positions = accountPositionDao.getAccountPositions(transfer.getSenderAcctId(), transfer.getSymbol());
219 int totalQuantity = 0;
220
221 for( AcctPosition position : positions ){
222 totalQuantity += position.getQuantity();
223 }
224
225 if( totalQuantity < transfer.getQuantity() ){
226
227 String message = "Account: "+ transfer.getSenderAcctId() +" does not have "+
228 transfer.getQuantity() + " positions of "+ transfer.getSymbol();
229
230 throw new NotEnoughPositionsException(message );
231 }
232
233
234 Account receiverAccount = accountDao.getAccountById(transfer.getReceiverAcctId());
235
236 if( receiverAccount != null &&
237 ( receiverAccount.getStatus().equals( Account.STATUS_INACTIVE) ||
238 receiverAccount.getStatus().equals( Account.STATUS_DISABLED) )
239 ){
240 String message = "Receiver account "+ transfer.getReceiverAcctId() + " is not a valid account";
241 throw new NotValidAccountException(message);
242 }
243
244
245
246 int remaining = transfer.getQuantity();
247 for( AcctPosition senderPosition : positions){
248
249 if( senderPosition.getQuantity() <= remaining ){
250 remaining -= senderPosition.getQuantity();
251 accountPositionDao.deleteAccountPosition(senderPosition);
252 }else if( senderPosition.getQuantity() > remaining ){
253 long updateQuantity = senderPosition.getQuantity() - remaining;
254 remaining =0;
255 senderPosition.setQuantity(updateQuantity);
256 accountPositionDao.updateAccountPosition(senderPosition);
257 }
258
259 if( remaining == 0){
260 break;
261 }else if( remaining < 0){
262
263
264 }
265 }
266
267
268 AcctPosition receiverPosition = new AcctPosition();
269 receiverPosition.setAcctId(transfer.getReceiverAcctId());
270 receiverPosition.setQuantity(transfer.getQuantity());
271 receiverPosition.setSymbol(transfer.getSymbol());
272 receiverPosition.setPurchasePrice( transfer.getPrice());
273
274
275 float totalPrice = receiverPosition.getPurchasePrice() * receiverPosition.getQuantity();
276
277 receiverPosition.setTotalPrice(totalPrice);
278
279 long posId = accountPositionDao.generateAcctPositionId();
280 receiverPosition.setId(posId);
281
282 accountPositionDao.addAccountPosition(receiverPosition);
283
284
285
286 long transferId = acctPositionTransferDao.generateTransferId();
287 transfer.setTransferId(transferId);
288
289 Date date = new Date();
290 Timestamp createdTime = new Timestamp( date.getTime());
291 transfer.setCreatedTime(createdTime);
292
293
294 transfer.setTransferStatus(CashTransfer.STATUS_COMPLETED);
295 acctPositionTransferDao.addAcctPositionTransfer( transfer);
296
297 }
298
299 @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
300 public AcctPosition addAccountPosition(AcctPosition position) {
301 long acctPosId = accountPositionDao.generateAcctPositionId();
302 position.setId(acctPosId);
303 return accountPositionDao.addAccountPosition(position);
304 }
305
306 @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
307 public void deleteAccountPosition(AcctPosition position) {
308 accountPositionDao.deleteAccountPosition(position);
309 }
310
311 public AcctPosition getAccountPosition(long acctPositionId) {
312 return accountPositionDao.getAccountPosition(acctPositionId);
313 }
314
315 public List<AcctPosition> getAccountPositions(String acctId) {
316 return accountPositionDao.getAccountPositions(acctId);
317 }
318
319 public List<AcctPosition> getAccountPositions(String acctId, String symbol) {
320 return accountPositionDao.getAccountPositions(acctId, symbol);
321 }
322
323 public float getTotalValueOfPositions(String acctId) {
324
325 List<AcctPosition> positions = getAccountPositions( acctId );
326
327 List<String> symbols = new ArrayList<String>();
328 for( AcctPosition pos : positions){
329 symbols.add( pos.getSymbol());
330 }
331
332 float total = 0f;
333 List<Quote> quotes;
334
335 try {
336
337 quotes = quoteMgr.getQuotes(symbols);
338
339
340 for( AcctPosition pos : positions ){
341 String symbol = pos.getSymbol();
342 Quote quote=null;
343 for( Quote q : quotes ){
344 if( q.getSymbol().equals(symbol)){
345 quote = q;
346 break;
347 }
348 }
349
350 if( quote != null ){
351 float value = pos.getQuantity() * quote.getLastPrice();
352 total += value;
353 }
354 }
355
356 } catch (SymbolsCannotBeEmptyException e) {
357 e.printStackTrace();
358 }
359
360
361
362 return total;
363 }
364
365 @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
366 public AcctPosition updateAccountPosition(AcctPosition position) {
367 return accountPositionDao.updateAccountPosition(position);
368 }
369
370 public List<AcctPositionSummary> getAccountPositionsSummary(String acctId) {
371
372 List<AcctPosition> positions = getAccountPositions( acctId );
373
374 List<String> symbols = new ArrayList<String>();
375 for( AcctPosition pos : positions){
376 symbols.add( pos.getSymbol());
377 }
378
379 float total = 0f;
380 List<Quote> quotes;
381
382 List<AcctPositionSummary> acctSummaries = new ArrayList<AcctPositionSummary>();
383
384 try {
385
386 quotes = quoteMgr.getQuotes(symbols);
387
388
389 for( Quote q : quotes ){
390
391 String symbol = q.getSymbol();
392 int totalShares = 0;
393 float totalPrice = 0;
394 float totalCurrentPrice =0;
395
396
397 for( AcctPosition pos : positions ){
398 if( !q.getSymbol().equals(pos.getSymbol())){
399 continue;
400 }
401
402 totalShares += pos.getQuantity();
403 totalPrice += pos.getQuantity() * pos.getPurchasePrice();
404 totalCurrentPrice += pos.getQuantity() * q.getLastPrice();
405 }
406
407 AcctPositionSummary acctPos = new AcctPositionSummary();
408
409 acctPos.setAcctId(acctId);
410 acctPos.setSymbol(symbol);
411 acctPos.setQuantity(totalShares);
412 float avgPurchasePrice = totalPrice / totalShares;
413 acctPos.setAveragePurchasePrice(avgPurchasePrice);
414 acctPos.setTotalPurchasePrice(totalPrice);
415
416 acctPos.setCurrentPrice(q.getLastPrice());
417 acctPos.setCurrentValue(totalCurrentPrice);
418
419 acctSummaries.add(acctPos);
420
421 }
422
423
424 } catch (SymbolsCannotBeEmptyException e) {
425 e.printStackTrace();
426 }
427
428 return acctSummaries;
429 }
430
431 public List<AcctValue> getTopAccounts(int count) {
432
433
434 List<Account> accounts = getAccountsOfType( Account.TYPE_CASH);
435
436
437 List<AcctValue> acctValues = new ArrayList<AcctValue>();
438 for( Account acct : accounts ){
439
440 float totalValue = getTotalValueOfPositions( acct.getAcctId());
441
442 AcctValue v = new AcctValue();
443 v.setAccount(acct);
444 v.setValue( new Float(totalValue) );
445 acctValues.add(v);
446 }
447
448
449 for( AcctValue value : acctValues ){
450 CashBalance balance = getCashBalance( value.getAccount() );
451 float total = value.getValue() + balance.getAmount();
452 value.setValue(total);
453 }
454
455
456 Collections.sort(acctValues, new Comparator<AcctValue>(){
457 public int compare(AcctValue o1, AcctValue o2) {
458 int diff = (int) (o1.getValue() - o2.getValue());
459 return (-diff);
460 }
461 });
462
463
464 int sortcount =0;
465 if( count <= acctValues.size()){
466 sortcount = count;
467 }else{
468 sortcount = acctValues.size();
469 }
470
471
472 List<AcctValue> sortedList = new ArrayList<AcctValue>(sortcount);
473 for( int i=0; i<sortcount; i++ ){
474 AcctValue acctValue = acctValues.get(i);
475 try {
476 User user = userMgr.getUserById( acctValue.getAccount().getId() );
477 acctValue.setUser(user);
478 sortedList.add(acctValue);
479 } catch (UserNotFoundException e) {
480 e.printStackTrace();
481 }
482 }
483
484 return sortedList;
485 }
486
487 private Map<String,Float> sortMapByValue(Map<String,Float> map){
488
489 List<CustomEntry> list = new ArrayList<CustomEntry>();
490 Set<Map.Entry<String,Float>> entrySet = map.entrySet();
491 Iterator<Map.Entry<String,Float>> iterator = entrySet.iterator();
492
493 while (iterator.hasNext()) {
494 Map.Entry<String,Float> entry = iterator.next();
495 CustomEntry customEntry = new CustomEntry(entry);
496 list.add(customEntry);
497 }
498
499 Collections.sort(list);
500
501
502 Map<String,Float> sortedMap = new HashMap<String,Float>();
503 for(CustomEntry entry : list ){
504 Map.Entry<String,Float> mEntry = entry.getEntry();
505 sortedMap.put(mEntry.getKey(), mEntry.getValue());
506 }
507
508 return sortedMap;
509 }
510
511 public class CustomEntry implements Comparable{
512 private Map.Entry<String,Float> entry;
513
514 public CustomEntry(Map.Entry<String,Float> entry) {
515 this.entry = entry;
516 }
517
518 public Map.Entry<String,Float> getEntry() {
519 return this.entry;
520 }
521
522 public int compareTo(CustomEntry anotherEntry) {
523 Float thisFloatVal = this.getEntry().getValue();
524 float thisVal = thisFloatVal.floatValue();
525 Float anotherFloatVal = anotherEntry.getEntry().getValue();
526 float anotherVal = anotherFloatVal.floatValue();
527 return (thisVal > anotherVal ? 1 : (thisVal==anotherVal ? 0 : -1));
528 }
529
530 public int compareTo(Object o) {
531 return compareTo((CustomEntry)o);
532 }
533
534 }
535 }