event refactor, landing on HEAD!
[freeside.git] / bin / freeside-migrate-events
1 #!/usr/bin/perl -w
2
3 use strict;
4
5 use FS::UID qw(adminsuidsetup);
6 use FS::Record qw( qsearch );
7 use FS::part_bill_event;
8 use FS::part_event;
9 use FS::cust_bill_event;
10 use FS::cust_event;
11
12 my $user = shift or die &usage;
13 adminsuidsetup($user);
14
15 my %plan2action = (
16   'fee'                    => 'fee',
17   'fee_percent'            => 'NOTYET', #XXX need fee_percent action
18   'suspend'                => 'suspend',
19   'suspend-if-balance'     => 'NOTYET', #XXX "if balance" becomes a balance condition
20   'suspend-if-pkgpart'     => 'suspend_if_pkgpart',
21   'suspend-unless-pkgpart' => 'suspend_unless_pkgpart',
22   'cancel'                 => 'cancel',
23   'addpost'                => 'addpost',
24   'comp'                   => 'NOTYET', #XXX or N/A or something
25   'credit'                 => 'NOTYET',
26   'realtime-card'          => 'cust_bill_realtime_card',
27   'realtime-check'         => 'cust_bill_realtime_check',
28   'realtime-lec'           => 'cust_bill_realtime_lec',
29   'batch-card'             => 'cust_bill_batch',
30   #?'retriable'             =>
31   'send'                   => 'cust_bill_send',
32   'send_email'             => 'NOTYET', 
33   'send_alternate'         => 'cust_bill_send_alternate',
34   'send_if_newest'         => 'cust_bill_send_if_newest',
35   'send_agent'             => 'cust_bill_send_agent',
36   'send_csv_ftp'           => 'cust_bill_send_csv_ftp',
37   'spool_csv',             => 'cust_bill_spool_csv',
38   'bill'                   => 'bill',
39   'apply'                  => 'apply',
40   'collect'                => 'collect',
41 );
42
43 #XXX may need to fudge some plandata2option names!!!
44
45 foreach my $part_bill_event (
46   qsearch({
47     'table'   => 'part_bill_event',
48   })
49 ) {
50
51   print $part_bill_event->event;
52
53   my $action = $plan2action{ $part_bill_event->plan };
54
55   if ( $action eq 'NOTYET' ) {
56     warn "not migrating part_bill_event.eventpart ".$part_bill_event->eventpart.
57          "; ". $part_bill_event->plan. " plan not (yet) handled";
58     next;
59   } elsif ( ! $action ) {
60     warn "not migrating part_bill_event.eventpart ".$part_bill_event->eventpart.
61          "; unknown plan ". $part_bill_event->plan;
62     next;
63   }
64
65   my $part_event = new FS::part_event {
66     'event'      => $part_bill_event->event,
67     'eventtable' => 'cust_bill',
68     'check_freq' => $part_bill_event->freq || '1d',
69     'weight'     => $part_bill_event->weight,
70     'action'     => $action,
71     'disabled'   => $part_bill_event->disabled,
72   };
73
74   my $error = $part_event->insert;
75   die "error inserting part_event: $error\n" if $error;
76
77   print ' '. $part_event->eventpart;
78
79   my $once = new FS::part_event_condition {
80     'eventpart'     => $part_event->eventpart,
81     'conditionname' => 'once'
82   };
83   $error = $once->insert;
84   die $error if $error;
85   
86   my $balance = new FS::part_event_condition {
87     'eventpart'     => $part_event->eventpart,
88     'conditionname' => 'balance'
89   };
90   $error = $balance->insert( 'balance' => 0 );
91   die $error if $error;
92
93   my $payby = new FS::part_event_condition {
94     'eventpart'     => $part_event->eventpart,
95     'conditionname' => 'payby'
96   };
97   $error = $payby->insert( 'payby' => { $part_bill_event->payby => 1 } );
98   die $error if $error;
99
100   if ( $part_bill_event->seconds ) {
101
102     my $age = new FS::part_event_condition { 
103       'eventpart'     => $part_event->eventpart,
104       'conditionname' => 'cust_bill_age'
105     };
106     $error = $payby->insert( 'age' => ($part_bill_event->seconds/86400 ).'d' );
107     die $error if $error;
108
109   }
110   
111   #my $derror = $part_bill_event->delete;
112   #die "error removing part_bill_event: $derror\n" if $derror;
113
114   foreach my $cust_bill_event (
115     qsearch({
116       'table'     => 'cust_bill_event',
117       'hashref'   => { 'eventpart' => $part_bill_event->eventpart, },
118     })
119   ) {
120
121     my $cust_event = new FS::cust_event {
122       'eventpart'  => $part_event->eventpart,
123       'tablenum'   => $cust_bill_event->invnum,
124       '_date'      => $cust_bill_event->_date,
125       'status'     => $cust_bill_event->status,
126       'statustext' => $cust_bill_event->statustext,
127     };
128
129     my $cerror = $cust_event->insert;
130     die "error inserting cust_event: $cerror\n" if $cerror;
131   
132     #my $dcerror = $cust_bill_event->delete;
133     #die "error removing cust_bill_event: $dcerror\n" if $dcerror;
134
135     print ".";
136
137   }
138
139   print "\n";
140
141 }
142
143 sub usage {
144   die "Usage:\n  freeside-migrate-events user\n"; 
145 }
146
147 =head1 NAME
148
149 freeside-migrate-events - Migrates 1.7/1.8-style invoice events to
150                           1.9/2.0-style billing events
151
152 =head1 SYNOPSIS
153
154   freeside-migrate-events
155
156 =head1 DESCRIPTION
157
158 Migrates events from L<FS::part_bill_event> to L<FS::part_event> and friends,
159 and from L<FS::cust_bill_event> records to L<FS::cust_event>
160
161 =head1 BUGS
162
163 Doesn't migrate any action options yet.
164
165 Doesn't translate option names that changed.
166
167 Doesn't migrate reasons.
168
169 Doesn't delete the old events (which is not a big deal, since the new code
170 won't run them...)
171
172 =head1 SEE ALSO
173
174 =cut
175
176 1;
177
178 __END__
179
180 #part_bill_event      part_event
181 #
182 #eventpart            n/a
183 #event                event
184 #freq                 check_freq
185 #payby                part_event_condition.conditionname = payby
186 #eventcode            PARSE_WITH_REGEX (probably can just get from plandata)
187 #seconds              part_event_condition.conditionname = cust_bill_age
188 #plandata             PARSE_WITH_REGEX (along with eventcode, yuck)
189 #reason               part_event_option.optionname = reason
190 #disabled             disabled
191 #
192
193     #these might help parse existing eventcode
194
195     $c =~ /^\s*\$cust_main\->(suspend|cancel|invoicing_list_addpost|bill|collect)\(\);\s*("";)?\s*$/
196
197       or $c =~ /^\s*\$cust_bill\->(comp|realtime_(card|ach|lec)|batch_card|send)\((%options)*\);\s*$/
198
199       or $c =~ /^\s*\$cust_bill\->send(_if_newest)?\(\'[\w\-\s]+\'\s*(,\s*(\d+|\[\s*\d+(,\s*\d+)*\s*\])\s*,\s*'[\w\@\.\-\+]*'\s*)?\);\s*$/
200
201 #      or $c =~ /^\s*\$cust_main\->apply_payments; \$cust_main->apply_credits; "";\s*$/
202       or $c =~ /^\s*\$cust_main\->apply_payments_and_credits; "";\s*$/
203
204       or $c =~ /^\s*\$cust_main\->charge\( \s*\d*\.?\d*\s*,\s*\'[\w \!\@\#\$\%\&\(\)\-\+\;\:\"\,\.\?\/]*\'\s*\);\s*$/
205
206       or $c =~ /^\s*\$cust_main\->suspend_(if|unless)_pkgpart\([\d\,\s]*\);\s*$/
207
208       or $c =~ /^\s*\$cust_bill\->cust_suspend_if_balance_over\([\d\.\s]*\);\s*$/
209
210       or do {
211         #log
212         return "illegal eventcode: $c";
213       };
214
215   }
216
217