Source code: com/pjsofts/eurobudget/beans/Account.java
1 /*
2 * Compte.java
3 *
4 * Created on 10 janvier 2002, 11:02
5 */
6
7 package com.pjsofts.eurobudget.beans;
8
9 import com.pjsofts.eurobudget.EBConstants;
10 import java.io.Serializable;
11 import java.util.*;
12
13 /**
14 * Account, Bean
15 * Compte courant bancaire
16 * Try to keep the minimum of methods.
17 * All convenient methods should be written as AccountLib static methods.
18 * (As we save it as bean, try to minimize change and size)
19 * @author PJ
20 */
21 public class Account extends Object implements java.lang.Comparable, Serializable {
22 /** serialization trick to be compatible with older implementation ,interoperability */
23 private static final long serialVersionUID = 4486226926471298634L;
24 /** resource for i18n */
25 private static final transient ResourceBundle i18n = EBConstants.i18n;
26
27 /** compte cloturé (can't add anymore txn) */
28 public static final int FLAG_ENDED = 1;
29 public static final int FLAG_FAVORITE = 2;
30 public static final int FLAG_TVA = 3;
31 public static final int FLAG_O1 = 4;
32 public static final int FLAG_O2 = 5;
33 public static final int FLAG_O3 = 6;
34 public static final int FLAG_O4 = 7;
35 public static final int FLAG_O5 = 8;
36 public static final int FLAG_O6 = 9;
37
38 // mandatory ///////////
39 /** @serial */
40 private String name;
41 /** @serial */
42 private Bank bank;
43 /** @serial */
44 private Currency ccy = Currency.getInstance(EBConstants.EBLOCALE); //euro only ??
45
46 /**
47 * List of Transactions can't be null
48 * ??? Sort per Date in chronological order, cause
49 * 1)normal view 2)allow to compute sum on range of date
50 * -)when saved/exported on file, the sort is not reneeded
51 * -)allow to compute faster the balande for one specific day
52 * Collections.sort(txns,Comparator); binarySearch==> easy even with List
53 * @serial
54 */
55 private List txns = new ArrayList();
56
57 /**
58 * solde initial du compte
59 * @serial
60 */
61 private double initialAmount=0d;
62
63 /** @serial */
64 private double minAmount = Double.MIN_VALUE;
65 /** @serial */
66 private double maxAmount = Double.MAX_VALUE;
67
68 // optionnal
69 /** Identification internationale
70 * @serial
71 */
72 private String iban;
73 /**
74 * Reference bancaire
75 * @serial
76 */
77 private String refs;
78
79 /** Titulaire du compte */
80 //private Entity owner;
81
82 /**
83 * Holds value of property id.
84 * @serial
85 */
86 private String id;
87
88 /** Holds value of property creationDate.
89 * @serial
90 */
91 private Date creationDate;
92 /** derniere modification
93 * @serial
94 */
95 private Date lastModificationDate;
96 /** dernier rapprochement
97 * @serial
98 */
99 private Date lastBalancedDate;
100
101 /** Flags ... for future
102 * @serial
103 */
104 private BitSet flags = new BitSet();
105
106 /** Group of account
107 * @serial
108 */
109 private AccountGroup accountGroup = AccountGroup.AG_USUAL;
110 /** comment
111 * @serial
112 */
113 private String comment = null;
114
115 //////// NOT BEAN PROPERTIES ////////////
116 /** to compute , not always up to date */
117 /** Final total */
118 private transient double total=0d;
119 /** Final Credit total */
120 private transient double ctotal=0d;
121 /** Final Debit total */
122 private transient double dtotal=0d;
123 /** Today total */
124 private transient double dayTotal=0d;
125 /** Today credit total */
126 private transient double creditDayTotal=0d;
127 /** Today debit total */
128 private transient double debitDayTotal=0d;
129
130
131 //private boolean sumsInvalid = false;
132
133 public Account(){
134 }
135
136 public Account(String id, String name, Bank bank, Date start) {
137 this();
138 setId(id);
139 setName(name);
140 setBank(bank);
141 setCreationDate(start);
142 }
143
144 /** update total variable
145 * total = big total
146 * dtotal = debit total
147 * ctotal = credit total
148 * dayTotal = big total until this date
149 * @param date until date included (for dayTotal) or null means all txns.
150 */
151 public void updateTotals(Date date) {
152 this.total = getInitialAmount();
153 this.ctotal = 0d;
154 this.dtotal = 0d;
155 this.dayTotal = 0d;
156 this.creditDayTotal= 0d;
157 this.debitDayTotal = 0d;
158 if ( txns != null ) {
159 Transaction t ;
160 // could use some boolean and start big total only after day total,
161 // but I think it's a too small optimization
162 for (int i=0; i< txns.size() ;i++) {
163 t = (Transaction)txns.get(i);
164 total += t.getRealAmount();
165 if ( t.getRealAmount() >= 0) {
166 ctotal += t.getAmount();
167 } else {
168 dtotal += t.getAmount();
169 }
170 if ( date != null && date.after(t.getDate()) ) {
171 dayTotal += t.getRealAmount();
172 if ( t.getRealAmount() >= 0) {
173 creditDayTotal += t.getRealAmount();
174 } else {
175 debitDayTotal += t.getRealAmount();
176 }
177 }
178 }
179 }
180 }
181
182
183 /** update to now time */
184 public void updateLastModificationDate(){
185 setLastModificationDate(new Date());
186 }
187
188 /**
189 * Getter for property txns.
190 * @return a read/only list ?? Value of property txns. can't be null
191 * To change data use given method (hence keep order) or respect order
192 */
193 public List getTxns() {
194 return txns;
195 //return Collections.unmodifiableList(txns); //this crash the xml serialization
196 }
197
198 /**
199 * Setter for property txns.
200 * automatically update total, but when change are made to the list, need to call manually udpateTotals
201 * @param txns New value of property txns. ArrayList better (or Random Access)
202 *
203 */
204 public void setTxns(List txns) {
205 //first sort per date
206 Collections.sort(txns);//no need of Comparator Txn is Comparable already
207 this.txns = txns;
208 updateTotals(new Date());
209 updateLastModificationDate();
210 }
211
212 /** in right place in the list
213 * warning date may be null !! (virement)
214 * different of addTransaction because it manages virement
215 */
216 public int addTransactionAndRelated(Transaction t){
217 if ( t instanceof Virement ) {
218 return addVirement((Virement)t);
219 } else {
220 return addTransaction(t);
221 }
222 }
223
224 /** in right place in the list
225 * warning date may be null !! (virement)
226 * do nothing special for virement (use addVirement or addTransactionAndRelated instead)
227 */
228 public int addTransaction(Transaction t){
229 int index = Collections.binarySearch(this.txns,t);//Comparator ??
230 if ( index >= 0 ) {
231 //it is not already there ! just got the same date
232 this.txns.add(index,t);
233 } else {//index = -insertionpoint -1
234 index = -index -1;
235 this.txns.add(index,t);
236 }
237 updateLastModificationDate();
238 return index;
239 }
240
241 /**
242 * in right place in the list
243 * warning date may be null !! (virement)
244 * special for virement insert also the related ...
245 * @param v virement, related may be null, warning this could be also a RelatedVirement
246 * RelatedVirement could be copied or cut like original virement ??
247 * @return index of given transaction in this account's list
248 */
249 public int addVirement(Virement v){
250 int index = -1;
251 Virement related = v.getRelatedVirement();
252 if ( related == null ) {
253 if ( v instanceof RelatedVirement )
254 related = new Virement();//creates a related automatticaly
255 else
256 related = new RelatedVirement();
257 v.setRelatedVirement(related);
258 }
259 if ( v instanceof RelatedVirement ) {
260 related.setSourceAccount(v.getTargetAccount());
261 v.getTargetAccount().addTransaction(related);//add the virement to its account
262 index = related.setTargetAccount(this);//will add v to current account
263 } else {
264 // v is a real Virement
265 v.setSourceAccount(this);
266 index =this.addTransaction(v);
267 v.setTargetAccount(v.getTargetAccount());//add the related to right account
268 }
269 return index;
270 }
271
272 /** remove the transaction from the list of this account,
273 * (do nothing special on virement)
274 */
275 public void removeTransaction(Transaction t) {
276 if ( t == null ) return;
277 boolean removed = this.txns.remove(t);// if false , throw new exception ??
278 //sumsInvalid = false;
279 updateLastModificationDate();
280 }
281
282 /** @param index of the transaction in the list */
283 // public void removeTransaction(int index) {
284 // if ( index < 0 ) throw new IndexOutOfBoundsException("Index:"+index);
285 // Transaction t = (Transaction)this.txns.get(index);
286 // removeTransaction(t);
287 // //sumsInvalid = false;
288 // }
289
290 /** same as removeTransaction but remove also the related */
291 public void removeVirement(Virement v) {
292 removeTransaction(v);
293 Virement related = v.getRelatedVirement();
294 if ( related != null ) {
295 related.setRelatedVirement(null); //mark the related as already removed
296 related.getSourceAccount().removeTransaction(related);
297 }
298 }
299
300 /** remove transaction and related (means if virement)
301 * if a virement remove also the related txn
302 */
303 public void removeTransactionAndRelated(int index) {
304 if ( index < 0 ) throw new IllegalArgumentException(i18n.getString("error_index_<_0"));
305 Transaction t = (Transaction)this.txns.get(index);
306 if ( t instanceof Virement ) {
307 removeVirement((Virement)t);
308 } else {
309 removeTransaction(t);
310 }
311 }
312
313 /**
314 * used just before removing the account for example
315 * could be called removeAllTxnWithRelated
316 */
317 public void removeAllTxnWithRelated() {
318 // don't use iterator as it produces ConcurrentModificationException
319 List txns = this.txns;
320 for (Iterator it = txns.iterator(); it.hasNext() ;) {
321 Transaction t = (Transaction)it.next();
322 if ( t instanceof Virement ) {
323 Virement v = (Virement)t;
324 Virement related = v.getRelatedVirement();
325 if ( related != null ) {
326 related.setRelatedVirement(null); //mark the related as already removed
327 if ( related.getSourceAccount() != null
328 && related.getSourceAccount() != this ) {
329 related.getSourceAccount().removeTransaction(related);
330 }
331 }
332 it.remove();
333 }
334 }
335 updateLastModificationDate();
336 }
337
338 /**
339 * to call whenever a transaction change its date and want to keep the list ordered
340 * Automatically managed related for Virement
341 * @param index current place in the list for the txn
342 * @return new place in the list for the transaction
343 */
344 public int updateTransaction(int index){
345 if ( index < 0 ) throw new IllegalArgumentException(i18n.getString("error_index_<_0"));
346 Transaction t = (Transaction)this.txns.get(index);
347 return updateTransaction(t);
348 }
349
350 /**
351 * to call whenever a transaction change its date and want to keep the list ordered
352 * Automatically managed related synch for Virement
353 * @return new place in the list for the transaction
354 */
355 public int updateTransaction(Transaction t){
356 removeTransaction(t);
357 int newindex = addTransaction(t);
358 if ( t instanceof Virement ) { //assume we don't call updateTransaction on relatedVirement as they are r/o
359 Virement v = (Virement)t;
360 Virement related = v.getRelatedVirement();
361 // same as call to updateTransaction(related)
362 related.getSourceAccount().removeTransaction(related);
363 related.getSourceAccount().addTransaction(related);
364 }
365 updateLastModificationDate();
366 return newindex;
367 }
368
369 /** @return true if this key could define this bean */
370 public boolean isEqual(String key) {
371 return key.equalsIgnoreCase(getName());
372 }
373
374 /** Getter for property bank.
375 * @return Value of property bank.
376 */
377 public com.pjsofts.eurobudget.beans.Bank getBank() {
378 return bank;
379 }
380
381 /** Setter for property bank.
382 * @param bank New value of property bank.
383 */
384 public void setBank(com.pjsofts.eurobudget.beans.Bank bank) {
385 this.bank = bank;
386 updateLastModificationDate();
387 }
388
389 /** Getter for property ccy.
390 * @return Value of property ccy.
391 */
392 public Currency getCcy() {
393 return ccy;
394 }
395
396 /** Setter for property ccy.
397 * @param ccy New value of property ccy.
398 */
399 public void setCcy(Currency ccy) {
400 this.ccy = ccy;
401 updateLastModificationDate();
402 }
403
404 /** Getter for property id.
405 * @return Value of property id.
406 */
407 public java.lang.String getId() {
408 return id;
409 }
410
411 /** Setter for property id.
412 * @param id New value of property id.
413 */
414 public void setId(java.lang.String id) {
415 this.id = id;
416 updateLastModificationDate();
417 }
418
419 /** Getter for property name.
420 * @return Value of property name.
421 */
422 public java.lang.String getName() {
423 return name;
424 }
425
426 /** Setter for property name.
427 * @param name New value of property name.
428 */
429 public void setName(java.lang.String name) {
430 this.name = name;
431 updateLastModificationDate();
432 }
433
434 /** Getter for property total.
435 * warning: need to call updateTotal before ...
436 * @return Value of property total.
437 */
438 public double getTotal() {
439 return total;
440 }
441
442 // /** Setter for property total.
443 // * @param total New value of property total.
444 // */
445 // public void setTotal(double total) {
446 // this.total = total;
447 // }
448
449 /** Getter for property creationDate.
450 * @return Value of property creationDate.
451 */
452 public Date getCreationDate() {
453 return this.creationDate;
454 }
455
456 /** Setter for property creationDate.
457 * @param creationDate New value of property creationDate.
458 */
459 public void setCreationDate(Date creationDate) {
460 this.creationDate = creationDate;
461 updateLastModificationDate();
462 }
463
464 /** Getter for property iban.
465 * @return Value of property iban.
466 */
467 public java.lang.String getIban() {
468 return iban;
469 }
470
471 /** Setter for property iban.
472 * @param iban New value of property iban.
473 */
474 public void setIban(java.lang.String iban) {
475 this.iban = iban;
476 updateLastModificationDate();
477 }
478
479 /** Getter for property refs.
480 * @return Value of property refs.
481 */
482 public java.lang.String getRefs() {
483 return refs;
484 }
485
486 /** Setter for property refs.
487 * @param refs New value of property refs.
488 */
489 public void setRefs(java.lang.String refs) {
490 this.refs = refs;
491 updateLastModificationDate();
492 }
493
494
495 public String toString() {
496 String retValue;
497 retValue = getName();//super.toString();
498 return retValue;
499 }
500
501 /** Getter for property initialAmount.
502 * @return Value of property initialAmount.
503 */
504 public double getInitialAmount() {
505 return initialAmount;
506 }
507
508 /** Setter for property initialAmount.
509 * @param initialAmount New value of property initialAmount.
510 */
511 public void setInitialAmount(double initialAmount) {
512 this.initialAmount = initialAmount;
513 updateLastModificationDate();
514 }
515
516 /** Getter for property ctotal.
517 * @return Value of property ctotal.
518 */
519 public double getCtotal() {
520 return ctotal;
521 }
522
523 public double getCreditDayTotal() {
524 return creditDayTotal;
525 }
526 public double getDebitDayTotal() {
527 return debitDayTotal;
528 }
529
530 // /** Setter for property ctotal.
531 // * @param ctotal New value of property ctotal.
532 // */
533 // public void setCtotal(double ctotal) {
534 // this.ctotal = ctotal;
535 // }
536
537 /** Getter for property dtotal.
538 * @return Value of property dtotal.
539 */
540 public double getDtotal() {
541 return dtotal;
542 }
543
544 /** Getter for property dtotal.
545 * @return Value of property dtotal.
546 */
547 public double getDayTotal() {
548 return dayTotal;
549 }
550
551 /** Getter for property minAmount.
552 * @return Value of property minAmount.
553 */
554 public double getMinAmount() {
555 return minAmount;
556 }
557
558 /** Setter for property minAmount.
559 * @param minAmount New value of property minAmount.
560 */
561 public void setMinAmount(double minAmount) {
562 this.minAmount = minAmount;
563 updateLastModificationDate();
564 }
565
566 /** Getter for property maxAmount.
567 * @return Value of property maxAmount.
568 */
569 public double getMaxAmount() {
570 return maxAmount;
571 }
572
573 /** Setter for property maxAmount.
574 * @param maxAmount New value of property maxAmount.
575 */
576 public void setMaxAmount(double maxAmount) {
577 this.maxAmount = maxAmount;
578 updateLastModificationDate();
579 }
580
581 /** Getter for property flags.
582 * @return Value of property flags.
583 * Warning: do no modify this object !
584 */
585 public BitSet getFlags() {
586 return flags; // or clone() ??
587 }
588
589 /** don't use with flag none */
590 public boolean isFlagSet(int flag) {
591 // assume flag always > 0
592 assert flag >= 0;
593 return flags.get(flag);
594 }
595
596 /** convenient
597 * see FLAG_xxx to get possible flag values
598 */
599 public void setFlag(int flag, boolean value) {
600 flags.set(flag,value);
601 updateLastModificationDate();
602 }
603
604 /** Setter for property flags.
605 * @param flags New value of property flags.
606 */
607 public void setFlags(BitSet flags) {
608 this.flags = flags;
609 updateLastModificationDate();
610 }
611
612 /** Getter for property lastModificationDate.
613 * @return Value of property lastModificationDate.
614 */
615 public Date getLastModificationDate() {
616 return lastModificationDate;
617 }
618
619 /** Setter for property lastModificationDate.
620 * @param lastModificationDate New value of property lastModificationDate.
621 */
622 public void setLastModificationDate(Date lastModificationDate) {
623 this.lastModificationDate = lastModificationDate;
624 }
625
626 /** Getter for property lastBalancedDate.
627 * @return Value of property lastBalancedDate.
628 */
629 public Date getLastBalancedDate() {
630 return lastBalancedDate;
631 }
632
633 /** Setter for property lastBalancedDate.
634 * @param lastBalancedDate New value of property lastBalancedDate.
635 */
636 public void setLastBalancedDate(Date lastBalancedDate) {
637 this.lastBalancedDate = lastBalancedDate;
638 }
639
640 /** Getter for property accountGroup.
641 * @return Value of property accountGroup.
642 */
643 public com.pjsofts.eurobudget.beans.AccountGroup getAccountGroup() {
644 return accountGroup;
645 }
646
647 /** Setter for property accountGroup.
648 * @param accountGroup New value of property accountGroup.
649 */
650 public void setAccountGroup(com.pjsofts.eurobudget.beans.AccountGroup accountGroup) {
651 this.accountGroup = accountGroup;
652 updateLastModificationDate();
653 }
654
655 /**
656 * Compares this object with the specified object for order. Returns a
657 * negative integer, zero, or a positive integer as this object is less
658 * than, equal to, or greater than the specified object.<p>
659 *
660 * In the foregoing description, the notation
661 * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
662 * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
663 * <tt>0</tt>, or <tt>1</tt> according to whether the value of <i>expression</i>
664 * is negative, zero or positive.
665 *
666 * The implementor must ensure <tt>sgn(x.compareTo(y)) ==
667 * -sgn(y.compareTo(x))</tt> for all <tt>x</tt> and <tt>y</tt>. (This
668 * implies that <tt>x.compareTo(y)</tt> must throw an exception iff
669 * <tt>y.compareTo(x)</tt> throws an exception.)<p>
670 *
671 * The implementor must also ensure that the relation is transitive:
672 * <tt>(x.compareTo(y)>0 && y.compareTo(z)>0)</tt> implies
673 * <tt>x.compareTo(z)>0</tt>.<p>
674 *
675 * Finally, the implementer must ensure that <tt>x.compareTo(y)==0</tt>
676 * implies that <tt>sgn(x.compareTo(z)) == sgn(y.compareTo(z))</tt>, for
677 * all <tt>z</tt>.<p>
678 *
679 * It is strongly recommended, but <i>not</i> strictly required that
680 * <tt>(x.compareTo(y)==0) == (x.equals(y))</tt>. Generally speaking, any
681 * class that implements the <tt>Comparable</tt> interface and violates
682 * this condition should clearly indicate this fact. The recommended
683 * language is "Note: this class has a natural ordering that is
684 * inconsistent with equals."
685 *
686 * @param o the Object to be compared.
687 * @return a negative integer, zero, or a positive integer as this object
688 * is less than, equal to, or greater than the specified object.
689 *
690 * @throws ClassCastException if the specified object's type prevents it
691 * from being compared to this Object.
692 */
693 public int compareTo(Object o) {
694 if ( o instanceof Account ) {
695 Account obj = (Account)o;
696 if ( obj == null || obj.getName() == null )
697 return 1;
698 if ( this.getName() == null )
699 return -1;
700 return this.getName().compareToIgnoreCase(obj.getName());
701 } else {
702 throw new java.lang.IllegalArgumentException(i18n.getString("error_Compare_only_to_another_Account"));
703 }
704 }
705
706 /** */
707 public boolean contains(Transaction t) {
708 if ( t == null || this.txns == null ) return false;
709 return this.txns.contains(t);
710 }
711
712 /** Getter for property comment.
713 * @return Value of property comment.
714 */
715 public String getComment() {
716 return this.comment;
717 }
718
719 /** Setter for property comment.
720 * @param comment New value of property comment.
721 */
722 public void setComment(String comment) {
723 this.comment = comment;
724 }
725
726 }
727
728
729