File Coverage

blib/lib/Palm/MaTirelire/AccountsV2.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             #
2             # Author : Maxime Soulé
3             # Created On : Wed Sep 8 14:24:17 2004
4             # Last Modified By: Maxime Soule
5             # Last Modified On: Mon May 3 14:57:49 2010
6             # Update Count : 99
7             #
8             # Copyright (C) 2005, Maxime Soulé
9             # You may distribute this file under the terms of the Artistic
10             # License, as specified in the README file.
11             #
12              
13             package Palm::MaTirelire::AccountsV2;
14              
15 1     1   2264 use strict;
  1         3  
  1         67  
16              
17 1     1   7 use Palm::BlockPack;
  1         1  
  1         23  
18              
19 1     1   6 use Palm::MaTirelire;
  1         2  
  1         7  
20 1     1   819 use Palm::StdAppInfo();
  0            
  0            
21              
22             use base qw(Palm::MaTirelire Palm::StdAppInfo);
23              
24             our $VERSION = '1.0';
25              
26             use constant UNKNOWN_MODE => ((1 << 5) - 1);
27             use constant UNKNOWN_TYPE => ((1 << 8) - 1);
28              
29             use constant MATI_DB_PREFS_VERSION => 1;
30              
31              
32             # AppInfoBlock
33             my $APPINFO_BLOCK = Palm::BlockPack->new
34             ('N' => [ 'access_code' => 0 ],
35             UInt32 => [
36             [ 'version:4' => 1 ],
37             [ 'cur_category:4' => 0 ],
38             [ 'show_all_cat:1' => 0 ],
39             [ 'remove_type:1' => 0 ],#DmRemoveRecord really deletes
40             [ 'deny_find:1' => 0 ],
41             [ 'sort_type:3' => 0 ],
42             [ 'list_date:1' => 0 ],
43             [ 'check_locked:1' => 0 ],
44             [ 'repeat_startup:1' => 0 ],
45             [ 'repeat_days:7' => 15 ],
46             [ 'reserved1:*' => 0 ],
47             ],
48             UInt32 => [
49             [ 'sum_type:4' => 0 ],
50             [ 'sum_date:5' => 1 ],
51             [ 'sum_todayplus:5' => 10 ],
52             [ 'sum_at_date:1' => 0 ],
53             [ 'accounts_sel_type:2' => 0 ],
54             [ 'accounts_currency:8' => 0 ],
55             [ 'reserved2:*' => 0 ],
56             ],
57             'n' => [ 'selected_accounts' => 0x0 ],
58             'DateType' => 'sum_',
59             );
60              
61             use constant DB_PREFS_STATS_NUM => 14;
62             my $APPINFO_BLOCK_STATS = Palm::BlockPack->new
63             ('DateType' => [ 'beg_date_' => 0 ],
64             'DateType' => [ 'end_date_' => 0 ],
65             UInt32 => [
66             [ 'menu_choice:3' => 0 ],
67             [ 'week_bounds:1' => 0 ],
68             [ 'by:4' => 0 ],
69             [ 'type_any:1' => 0 ],
70             [ 'type:8' => 0 ],
71             [ 'mode_any:1' => 0 ],
72             [ 'mode:5' => 0 ],
73             [ 'on:2' => 0 ],
74             [ 'val_date:1' => 0 ],
75             [ 'ignore_nulls:1' => 0 ],
76             [ 'type_children:1' => 0 ],
77             [ 'reserved:*' => 0 ],
78             ],
79             'n' => [ 'checked_accounts' => 0 ],
80             );
81              
82             my $APPINFO_BLOCK_END = Palm::BlockPack->new('Z*' => [ 'note' => '' ]);
83              
84             my $ACCOUNT_BLOCK = Palm::BlockPack->new
85             ('DateType' => [ 'date_' => 0 ],
86             'TimeType' => [ 'time_' => 0 ],
87              
88             '-N' => [ 'amount' => 0 ],
89              
90             UInt32 => [
91             [ 'checked:1' => 1 ],
92             [ 'marked:1' => 0 ],
93             [ 'warning:1' => 0 ],
94             [ 'stmt_num:1' => 0 ],
95             [ 'currency:8' => 0 ],
96             [ 'cheques_by_cbook:6' => 25 ],
97             [ 'num_chequebook:2'=> 0 ],
98             [ 'take_last_date:1'=> 0 ],
99             [ 'reserved:*' => 0 ],
100             ],
101             '-N' => [ 'overdraft_thresold' => 0 ],
102             '-N' => [ 'non_overdraft_thresold' => 0 ],
103              
104             '[N4]' => [ 'check_books' ],
105              
106             'Z24' => [ 'number' => '' ],
107              
108             'Z*' => [ 'note' => '' ],
109             );
110              
111             my $TRANS_BLOCK = Palm::BlockPack->new
112             ('DateType' => [ 'date_' => 'now' ],
113             'TimeType' => [ 'time_' => 'now' ],
114              
115             '-N' => [ 'amount' => 0 ],
116              
117             UInt32 => [
118             [ 'checked:1' => 0 ],
119             [ 'marked:1' => 0 ],
120             [ 'alarm:1' => 0 ],
121             [ 'mode:5' => UNKNOWN_MODE ],
122             [ 'type:8' => UNKNOWN_TYPE ],
123             'value_date:1',
124             'check_num:1',
125             'repeat:1',
126             'xfer:1',
127             'xfer_cat:1',
128             'stmt_num:1',
129             'currency:1',
130             'splits:1',
131             [ 'reserved:*' => 0 ],
132             ],
133             );
134              
135             my $TRANS_VALUEDATE_BLOCK = Palm::BlockPack->new(DateType => '');
136              
137             my $TRANS_CHECKNUM_BLOCK = Palm::BlockPack->new(N => 'check_num');
138              
139             my $TRANS_REPEAT_BLOCK = Palm::BlockPack->new
140             (UInt16 => [
141             'repeat_type:2',
142             'repeat_freq:6',
143             'reserved:*',
144             ],
145             DateType => 'end_date_',
146             );
147              
148             my $TRANS_XFER_BLOCK = Palm::BlockPack->new(N => 'xfer');
149              
150             my $TRANS_STMTNUM_BLOCK = Palm::BlockPack->new(N => 'stmt_num');
151              
152             my $TRANS_CURRENCY_BLOCK = Palm::BlockPack->new
153             ('-N' => 'currency_amount',
154             UInt32 => [
155             'currency:8',
156             'reserved:*',
157             ]);
158              
159             my $TRANS_SUBTR_BLOCK = Palm::BlockPack->new
160             (UInt16 => [
161             'num:8',
162             'reserved:*',
163             ],
164             n => 'size');
165              
166             my $TRANS_SUBTR_SUB_BLOCK = Palm::BlockPack->new
167             (
168             UInt32 => [
169             'type:8',
170             'reserved:*',
171             ],
172             '-N' => 'amount',
173             'Z*' => 'desc',
174             );
175              
176             my $TRANS_NOTE_BLOCK = Palm::BlockPack->new('Z*' => [ note => '' ]);
177              
178              
179             sub import
180             {
181             &Palm::PDB::RegisterPDBHandlers(__PACKAGE__, [ "MaT2", 'Acnt' ]);
182             }
183              
184              
185             sub new
186             {
187             my $classname = shift;
188             my $self = $classname->SUPER::new(@_);
189             # Create a generic PDB. No need to rebless it,
190             # though.
191            
192             $self->{name} = "MaTi=Default"; # Default name
193             $self->{type} = "Acnt";
194              
195             # Add the standard AppInfo block stuff
196             &Palm::StdAppInfo::seed_StdAppInfo($self->{appinfo});
197              
198             # delete the auto-created "Unfiled" category
199             $self->{appinfo}{categories}[0]{name} = undef;
200              
201             # The AppInfo block stuff
202             $APPINFO_BLOCK->init_block($self->{appinfo});
203             $self->{appinfo}{stats} = [ ({}) x DB_PREFS_STATS_NUM ];
204             foreach my $idx (0 .. DB_PREFS_STATS_NUM - 1)
205             {
206             $APPINFO_BLOCK_STATS->init_block($self->{appinfo}{stats}[$idx]);
207             }
208             $APPINFO_BLOCK_END->init_block($self->{appinfo});
209              
210             return $self;
211             }
212              
213              
214             sub ParseAppInfoBlock
215             {
216             my $self = shift;
217             my $data = shift;
218             my $appinfo = {};
219             my $std_len;
220              
221             # Get the standard parts of the AppInfo block
222             &Palm::StdAppInfo::parse_StdAppInfo($appinfo, $data);
223              
224             # Palm::StdAppInfo::parse_StdAppInfo nous laisse le reste dans
225             # $appinfo->{other}
226             $data = delete $appinfo->{other};
227             $APPINFO_BLOCK->unpack_block(\$data, $appinfo, 1);
228              
229             if ($appinfo->{version} >= MATI_DB_PREFS_VERSION)
230             {
231             foreach my $idx (0 .. DB_PREFS_STATS_NUM - 1)
232             {
233             unless (defined $appinfo->{appinfo}{stats}[$idx])
234             {
235             $appinfo->{appinfo}{stats}[$idx] = {};
236             }
237              
238             $APPINFO_BLOCK_STATS->unpack_block(\$data,
239             $appinfo->{appinfo}{stats}[$idx],
240             1);
241             }
242             }
243             # La version 0 n'avait pas encore les stats
244             else
245             {
246             $appinfo->{version} = MATI_DB_PREFS_VERSION;
247              
248             $self->{appinfo}{stats} = [ ({}) x DB_PREFS_STATS_NUM ];
249             foreach my $idx (0 .. DB_PREFS_STATS_NUM - 1)
250             {
251             $APPINFO_BLOCK_STATS->init_block($self->{appinfo}{stats}[$idx]);
252             }
253             }
254             $APPINFO_BLOCK_END->unpack_block(\$data, $appinfo);
255              
256             return $appinfo;
257             }
258              
259              
260             sub PackAppInfoBlock
261             {
262             my $self = shift;
263             my $appinfo = $self->{appinfo};
264             my $pack;
265              
266             $appinfo->{other} = $APPINFO_BLOCK->pack_block($appinfo);
267             foreach my $idx (0 .. DB_PREFS_STATS_NUM - 1)
268             {
269             $appinfo->{other} .=
270             $APPINFO_BLOCK_STATS->pack_block($appinfo->{stats}[$idx]);
271             }
272             $appinfo->{other} .=
273             $APPINFO_BLOCK_END->pack_block($appinfo);
274            
275              
276             # Pack the AppInfo block (and then append $appinfo->{other})
277             $pack = &Palm::StdAppInfo::pack_StdAppInfo($appinfo);
278              
279             return $pack;
280             }
281              
282              
283             sub new_Record
284             {
285             my $classname = shift;
286             my $retval = $classname->SUPER::new_Record(@_);
287              
288             $TRANS_BLOCK->init_block($retval);
289             $TRANS_NOTE_BLOCK->init_block($retval);
290              
291             return $retval;
292             }
293              
294              
295             sub new_AccountProperties
296             {
297             my $classname = shift;
298             my $retval = $classname->SUPER::new_Record(@_);
299              
300             $ACCOUNT_BLOCK->init_block($retval);
301            
302             return $retval;
303             }
304              
305              
306             sub findAccountPropertiesByName ($$)
307             {
308             my($self, $account_name) = @_;
309              
310             my $ref_accounts = $self->{appinfo}{categories};
311              
312             for (my $index = 0; $index < @$ref_accounts; $index++)
313             {
314             my $cur_account = $ref_accounts->[$index]{name};
315              
316             if (defined $cur_account and $cur_account eq $account_name)
317             {
318             return $self->findAccountPropertiesByIndex($index);
319             }
320             }
321              
322             return undef;
323             }
324              
325              
326             sub findAccountPropertiesByIndex ($$)
327             {
328             my($self, $account_idx) = @_;
329              
330             foreach my $rec (@{$self->{records}})
331             {
332             # Account properties
333             if ($rec->{date_day} == 0 and $rec->{date_month} == 0
334             and $rec->{date_year} == 0 and $rec->{category} == $account_idx)
335             {
336             return $rec;
337             }
338             }
339            
340             return undef;
341             }
342              
343              
344             sub ParseRecord
345             {
346             my $self = shift;
347             my %record = @_;
348              
349             delete $record{offset}; # This is useless
350             my $data = delete $record{data};
351              
352             $record{size} = length $data; # used in validRecords sub
353              
354             # !!! PROBLČME !!!
355             return \%record if $record{size} < 4;
356              
357             # Propriétés du compte
358             if (unpack('N', $data) == 0)
359             {
360             $ACCOUNT_BLOCK->unpack_block(\$data, \%record);
361             }
362             # Opération...
363             else
364             {
365             $TRANS_BLOCK->unpack_block(\$data, \%record, 1);
366              
367             # Value date
368             if (delete $record{value_date})
369             {
370             $record{value_date} = {};
371             $TRANS_VALUEDATE_BLOCK->unpack_block(\$data,$record{value_date}, 1);
372             }
373              
374             # Cheque number
375             if (delete $record{check_num})
376             {
377             $TRANS_CHECKNUM_BLOCK->unpack_block(\$data, \%record, 1);
378             }
379              
380             # Repetition
381             if (delete $record{repeat})
382             {
383             $record{repeat} = {};
384             $TRANS_REPEAT_BLOCK->unpack_block(\$data, $record{repeat}, 1);
385             }
386              
387             # Transfer
388             if (delete $record{xfer})
389             {
390             $TRANS_XFER_BLOCK->unpack_block(\$data, \%record, 1);
391             }
392             else
393             {
394             delete $record{xfer_cat};
395             }
396              
397             # Statement number
398             if (delete $record{stmt_num})
399             {
400             $TRANS_STMTNUM_BLOCK->unpack_block(\$data, \%record, 1);
401             }
402              
403             # Currency
404             if (delete $record{currency})
405             {
406             $record{currency} = {};
407             $TRANS_CURRENCY_BLOCK->unpack_block(\$data, $record{currency}, 1);
408             }
409              
410             # Sub-transactions
411             if (delete $record{splits})
412             {
413             $record{splits} = {};
414             $TRANS_SUBTR_BLOCK->unpack_block(\$data, $record{splits}, 1);
415              
416             if ($record{splits}{size} > 0)
417             {
418             my $subtrs = substr($data, 0, $record{splits}{size}, '');
419              
420             $record{splits}{list} = [];
421              
422             while (length $subtrs > 0)
423             {
424             my %subtr;
425              
426             $TRANS_SUBTR_SUB_BLOCK->unpack_block(\$subtrs, \%subtr, 1);
427              
428             # La somme des sous-op est égale ŕ la valeur
429             # absolue du montant de l'opération. Donc on
430             # corrige au chargement si le montant de
431             # l'opération est < 0
432             if ($record{amount} < 0)
433             {
434             $subtr{amount} = - $subtr{amount};
435             }
436              
437             # La description a toujours une longueur multiple de 2
438             # y compris le \0 de fin
439             substr($subtrs, 0, 1) = '' if length($subtr{desc}) % 2 == 0;
440              
441             push(@{$record{splits}{list}}, \%subtr);
442             }
443             }
444              
445             # Here we can delete the number and the size, they will be
446             # recomputed at PackRecord
447             delete @{$record{splits}}{qw(num size)};
448             }
449              
450             $TRANS_NOTE_BLOCK->unpack_block(\$data, \%record);
451             }
452              
453             return \%record;
454             }
455              
456              
457             sub PackRecord
458             {
459             my $self = shift;
460             my $record = shift;
461             my $pack;
462              
463             # Propriétés du compte
464             if ($record->{date_day} == 0)
465             {
466             $pack = $ACCOUNT_BLOCK->pack_block($record);
467             }
468             # Opération...
469             else
470             {
471             # Small check...
472             if ($record->{xfer_cat})
473             {
474             if (not defined $record->{xfer} or $record->{xfer} >= 16)
475             { delete $record->{xfer_cat} }
476             }
477              
478             $pack = $TRANS_BLOCK->pack_block($record);
479              
480             # Value date
481             if ($record->{value_date})
482             {
483             $pack .= $TRANS_VALUEDATE_BLOCK->pack_block($record->{value_date});
484             }
485              
486             # Cheque number
487             if ($record->{check_num})
488             {
489             $pack .= $TRANS_CHECKNUM_BLOCK->pack_block($record);
490             }
491              
492             # Repetition
493             if ($record->{repeat})
494             {
495             $pack .= $TRANS_REPEAT_BLOCK->pack_block($record->{repeat});
496             }
497              
498             # Transfer
499             if ($record->{xfer})
500             {
501             $pack .= $TRANS_XFER_BLOCK->pack_block($record);
502             }
503              
504             # Statement number
505             if ($record->{stmt_num})
506             {
507             $pack .= $TRANS_STMTNUM_BLOCK->pack_block($record);
508             }
509              
510             # Currency
511             if ($record->{currency})
512             {
513             $pack .= $TRANS_CURRENCY_BLOCK->pack_block($record->{currency});
514             }
515              
516             # Sub-transactions
517             if ($record->{splits})
518             {
519             my $subtrs = '';
520             foreach my $ref_subtr (@{$record->{splits}{list}})
521             {
522             # La somme des sous-op doit ętre égale ŕ la valeur
523             # absolue du montant de l'opération. Donc on corrige ŕ
524             # la sauvegarde si le montant de l'opération est < 0
525             if ($record->{amount} < 0)
526             {
527             $ref_subtr->{amount} = - $ref_subtr->{amount};
528             }
529              
530             $subtrs .= $TRANS_SUBTR_SUB_BLOCK->pack_block($ref_subtr);
531              
532             # La description a toujours une longueur multiple de 2
533             # y compris le \0 de fin
534             $subtrs .= "\0" if length($subtrs) % 2;
535             }
536              
537             $record->{splits}{num} = @{$record->{splits}{list}};
538             $record->{splits}{size} = length $subtrs;
539              
540             $pack .= $TRANS_SUBTR_BLOCK->pack_block($record->{splits});
541              
542             $pack .= $subtrs;
543              
544             # Here we can delete the number and the size, they will be
545             # recomputed the next time
546             delete @{$record->{splits}}{qw(num size)};
547             }
548              
549             $pack .= $TRANS_NOTE_BLOCK->pack_block($record);
550             }
551              
552             return $pack;
553             }
554              
555              
556             #
557             # Ŕ faire les différentes sortes de tri...
558             sub sortRecords
559             {
560             my $self = shift;
561              
562             # Sort by value date
563             if ($self->{appinfo}{sort_type} == 1)
564             {
565             @{$self->{records}} = sort
566             {
567             my($refa, $refb) = ($a, $b);
568              
569             # Account properties don't have value_date
570             if ($a->{value_date})
571             {
572             $refa = { date_day => $a->{value_date}{day},
573             date_month => $a->{value_date}{month},
574             date_year => $a->{value_date}{year},
575             time_hour => $a->{time_hour},
576             time_min => $a->{time_min},
577             };
578             }
579              
580             # Account properties don't have value_date
581             if ($b->{value_date})
582             {
583             $refb = { date_day => $b->{value_date}{day},
584             date_month => $b->{value_date}{month},
585             date_year => $b->{value_date}{year},
586             time_hour => $b->{time_hour},
587             time_min => $b->{time_min},
588             };
589             }
590              
591             # Pack date and time on an 31 bits width integer...
592              
593             # 11 bits: 30 .. 20
594             (($refa->{date_year} << 20)
595             # 4 bits: 19 .. 16
596             | ($refa->{date_month} << 16)
597             # 5 bits: 15 .. 11
598             | ($refa->{date_day} << 11)
599             # 5 bits: 10 .. 6
600             | ($refa->{time_hour} << 6)
601             # 6 bits: 5 .. 0 11 bits: 30 .. 20
602             | $refa->{time_min}) <=> (($refb->{date_year} << 20)
603             # 4 bits: 19 .. 16
604             | ($refb->{date_month} << 16)
605             # 5 bits: 15 .. 11
606             | ($refb->{date_day} << 11)
607             # 5 bits: 10 .. 6
608             | ($refb->{time_hour} << 6)
609             # 6 bits: 5 .. 0
610             | $refb->{time_min})
611             }
612             @{$self->{records}};
613             }
614             # Sort by date
615             else
616             {
617             # Force "sort by date" as there is no other sort type at this time
618             $self->{appinfo}{sort_type} = 0;
619              
620             @{$self->{records}} = sort
621             {
622             # Pack date and time on an 31 bits width integer...
623              
624             # 11 bits: 30 .. 20
625             (($a->{date_year} << 20)
626             # 4 bits: 19 .. 16
627             | ($a->{date_month} << 16)
628             # 5 bits: 15 .. 11
629             | ($a->{date_day} << 11)
630             # 5 bits: 10 .. 6
631             | ($a->{time_hour} << 6)
632             # 6 bits: 5 .. 0 11 bits: 30 .. 20
633             | $a->{time_min}) <=> (($b->{date_year} << 20)
634             # 4 bits: 19 .. 16
635             | ($b->{date_month} << 16)
636             # 5 bits: 15 .. 11
637             | ($b->{date_day} << 11)
638             # 5 bits: 10 .. 6
639             | ($b->{time_hour} << 6)
640             # 6 bits: 5 .. 0
641             | $b->{time_min})
642             }
643             @{$self->{records}};
644             }
645             }
646              
647              
648             #
649             # Returns a list (number of deleted records, number of errors corrected)
650             sub validRecords ($;$)
651             {
652             my($self, $verbose) = @_;
653              
654             # $verbose can be a reference on a filehandle
655             $verbose = \*STDOUT if $verbose && not ref $verbose;
656              
657             my $deleted_records = 0;
658             my $errors_found = 0;
659              
660             my @to_del;
661             my %ids;
662             my $index = 0;
663              
664             foreach my $rec (@{$self->{records}})
665             {
666             if ($rec->{attributes}{expunged})
667             {
668             print $verbose "Record #$index expunged => delete it really\n"
669             if $verbose;
670              
671             # No need to count these already deleted records
672             push(@to_del, $index);
673             }
674             elsif ($rec->{size} == 0)
675             {
676             print $verbose ("Record #$index (cat=$rec->{category}) "
677             . "UniqueID $rec->{id}\n"
678             . "**** empty => deleted\n")
679             if $verbose;
680              
681             push(@to_del, $index);
682             $deleted_records++;
683             }
684             else
685             {
686             $ids{$rec->{id}} = 1;
687             }
688             $index++;
689             }
690              
691             if (@to_del)
692             {
693             foreach my $idx (reverse @to_del)
694             {
695             splice @{$self->{records}}, $idx, 1;
696             }
697             }
698              
699             my %links;
700             $index = 0;
701              
702             foreach my $rec (@{$self->{records}})
703             {
704             my @err_msg;
705              
706             if ($rec->{reserved})
707             {
708             $rec->{reserved} = 0;
709             push(@err_msg, "null reserved field corrected");
710             }
711              
712             # Account properties
713             if ($rec->{date_day} == 0 and $rec->{date_month} == 0
714             and $rec->{date_year} == 0)
715             {
716             # Nothing to do here...
717             }
718             else
719             {
720             # Repeat
721             if ($rec->{repeat})
722             {
723             if ($rec->{repeat}{repeat_freq} == 0
724             or $rec->{repeat}{repeat_type} > 2)
725             {
726             push(@err_msg, "deleted repeat option");
727             delete $rec->{repeat};
728             }
729              
730             if ($rec->{repeat}{reserved} != 0)
731             {
732             $rec->{repeat}{reserved} = 0;
733             push(@err_msg, "repeat option, reserved corrected");
734             }
735             }
736              
737             # Xfer
738             if (exists $rec->{xfer})
739             {
740             my $error = 0;
741              
742             if ($rec->{xfer_cat})
743             {
744             if ($rec->{xfer} >= 16)
745             {
746             push(@err_msg, "invalid account (xfer) link");
747              
748             $error = 1;
749             }
750             }
751             else
752             {
753             if (exists $ids{$rec->{xfer}})
754             {
755             $links{$rec->{id}} = $rec->{xfer};
756             }
757             else
758             {
759             push(@err_msg, "invalid transaction (xfer) link");
760              
761             $error = 1;
762             }
763             }
764              
765             if ($error)
766             {
767             delete @$rec{qw(xfer xfer_cat)};
768             push(@err_msg, "deleted transfer option");
769             }
770             }
771              
772             # Splits
773             if (exists $rec->{splits})
774             {
775             if (not defined $rec->{splits}{list}
776             or @{$rec->{splits}{list}} == 0)
777             {
778             push(@err_msg, "deleted splits option");
779             delete $rec->{splits};
780             }
781              
782             for (my $split_idx = @{$rec->{splits}{list}}; $split_idx-- > 0;)
783             {
784             if ($rec->{splits}{list}[$split_idx]{reserved})
785             {
786             $rec->{splits}{list}[$split_idx]{reserved} = 0;
787             push(@err_msg, "split #$split_idx, reserved corrected");
788             }
789             }
790              
791             if ($rec->{splits}{reserved})
792             {
793             $rec->{splits}{reserved} = 0;
794             push(@err_msg, "splits option, reserved corrected");
795             }
796             }
797              
798             # No account (not possible ?)
799             if ($rec->{category} eq '')
800             {
801             $rec->{attributes} = { dirty => 1 };
802             push(@err_msg, "not associated to an account");
803             }
804              
805             if (@err_msg)
806             {
807             if ($verbose)
808             {
809             print $verbose
810             ("Record #$index (account=$rec->{category}) ",
811             "UniqueID $rec->{id}\n",
812             "$rec->{date_year}/$rec->{date_month}/$rec->{date_day} ",
813             "$rec->{time_hour}:$rec->{time_min} ",
814             "amount = ", $rec->{amount} / 100, "\n",
815             " ");
816              
817             print $verbose join("\n ", @err_msg), "\n";
818             }
819              
820             $rec->{attributes}{Dirty} = 1;
821              
822             $errors_found++;
823             }
824             }
825             }
826              
827             while (my($id, $link) = each %links)
828             {
829             if (not exists $links{$link})
830             {
831             print $verbose ("**** Xfer: $id => $link but $link is not linked,",
832             " corrected.\n")
833             if $verbose;
834              
835             my $rec = $self->findRecordByID($link);
836             $rec->{xfer} = $id;
837             delete $rec->{xfer_cat};
838              
839             $rec->{attributes}{Dirty} = 1;
840             }
841             elsif ($links{$link} != $id)
842             {
843             print $verbose
844             "**** Xfer: $id => $link but $link => $links{$link}\n"
845             if $verbose;
846             }
847             }
848              
849             return ($deleted_records, $errors_found);
850             }
851              
852             1;
853             __END__