freeside-migrate-events now moves event options, whew
[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
44 foreach my $part_bill_event (
45   qsearch({
46     'table'   => 'part_bill_event',
47   })
48 ) {
49
50   print $part_bill_event->event;
51
52   my $action = $plan2action{ $part_bill_event->plan };
53
54   if ( $action eq 'NOTYET' ) {
55     warn "not migrating part_bill_event.eventpart ".$part_bill_event->eventpart.
56          "; ". $part_bill_event->plan. " plan not (yet) handled";
57     next;
58   } elsif ( ! $action ) {
59     warn "not migrating part_bill_event.eventpart ".$part_bill_event->eventpart.
60          "; unknown plan ". $part_bill_event->plan;
61     next;
62   }
63
64   my %plandata = map { /^(\w+) (.*)$/; ($1, $2); }
65                      split(/\n/, $part_bill_event->plandata);
66
67   #XXX may need to fudge some plandata2option names!!!
68
69   my $part_event = new FS::part_event {
70     'event'      => $part_bill_event->event,
71     'eventtable' => 'cust_bill',
72     'check_freq' => $part_bill_event->freq || '1d',
73     'weight'     => $part_bill_event->weight,
74     'action'     => $action,
75     'disabled'   => $part_bill_event->disabled,
76   };
77
78   my $error = $part_event->insert(\%plandata);
79   die "error inserting part_event: $error\n" if $error;
80
81   print ' '. $part_event->eventpart;
82
83   my $once = new FS::part_event_condition {
84     'eventpart'     => $part_event->eventpart,
85     'conditionname' => 'once'
86   };
87   $error = $once->insert;
88   die $error if $error;
89   
90   my $balance = new FS::part_event_condition {
91     'eventpart'     => $part_event->eventpart,
92     'conditionname' => 'balance'
93   };
94   $error = $balance->insert( 'balance' => 0 );
95   die $error if $error;
96
97   my $payby = new FS::part_event_condition {
98     'eventpart'     => $part_event->eventpart,
99     'conditionname' => 'payby'
100   };
101   $error = $payby->insert( 'payby' => { $part_bill_event->payby => 1 } );
102   die $error if $error;
103
104   if ( $part_bill_event->seconds ) {
105
106     my $age = new FS::part_event_condition { 
107       'eventpart'     => $part_event->eventpart,
108       'conditionname' => 'cust_bill_age'
109     };
110     $error = $age->insert( 'age' => ($part_bill_event->seconds/86400 ).'d' );
111     die $error if $error;
112
113   }
114   
115   #my $derror = $part_bill_event->delete;
116   #die "error removing part_bill_event: $derror\n" if $derror;
117
118   foreach my $cust_bill_event (
119     qsearch({
120       'table'     => 'cust_bill_event',
121       'hashref'   => { 'eventpart' => $part_bill_event->eventpart, },
122     })
123   ) {
124
125     my $cust_event = new FS::cust_event {
126       'eventpart'  => $part_event->eventpart,
127       'tablenum'   => $cust_bill_event->invnum,
128       '_date'      => $cust_bill_event->_date,
129       'status'     => $cust_bill_event->status,
130       'statustext' => $cust_bill_event->statustext,
131     };
132
133     my $cerror = $cust_event->insert;
134     #die "error inserting cust_event: $cerror\n" if $cerror;
135     warn "error inserting cust_event: $cerror\n" if $cerror;
136   
137     #my $dcerror = $cust_bill_event->delete;
138     #die "error removing cust_bill_event: $dcerror\n" if $dcerror;
139
140     print ".";
141
142   }
143
144   print "\n";
145
146 }
147
148 sub usage {
149   die "Usage:\n  freeside-migrate-events user\n"; 
150 }
151
152 =head1 NAME
153
154 freeside-migrate-events - Migrates 1.7/1.8-style invoice events to
155                           1.9/2.0-style billing events
156
157 =head1 SYNOPSIS
158
159   freeside-migrate-events
160
161 =head1 DESCRIPTION
162
163 Migrates events from L<FS::part_bill_event> to L<FS::part_event> and friends,
164 and from L<FS::cust_bill_event> records to L<FS::cust_event>
165
166 =head1 BUGS
167
168 Doesn't migrate any action options yet.
169
170 Doesn't translate option names that changed.
171
172 Doesn't migrate reasons.
173
174 Doesn't delete the old events (which is not a big deal, since the new code
175 won't run them...)
176
177 =head1 SEE ALSO
178
179 =cut
180
181 1;
182
183 __END__
184
185 #part_bill_event      part_event
186 #
187 #eventpart            n/a
188 #event                event
189 #freq                 check_freq
190 #payby                part_event_condition.conditionname = payby
191 #eventcode            PARSE_WITH_REGEX (probably can just get from plandata)
192 #seconds              part_event_condition.conditionname = cust_bill_age
193 #plandata             PARSE_WITH_REGEX (along with eventcode, yuck)
194 #reason               part_event_option.optionname = reason
195 #disabled             disabled
196 #
197
198     #these might help parse existing eventcode
199
200     $c =~ /^\s*\$cust_main\->(suspend|cancel|invoicing_list_addpost|bill|collect)\(\);\s*("";)?\s*$/
201
202       or $c =~ /^\s*\$cust_bill\->(comp|realtime_(card|ach|lec)|batch_card|send)\((%options)*\);\s*$/
203
204       or $c =~ /^\s*\$cust_bill\->send(_if_newest)?\(\'[\w\-\s]+\'\s*(,\s*(\d+|\[\s*\d+(,\s*\d+)*\s*\])\s*,\s*'[\w\@\.\-\+]*'\s*)?\);\s*$/
205
206 #      or $c =~ /^\s*\$cust_main\->apply_payments; \$cust_main->apply_credits; "";\s*$/
207       or $c =~ /^\s*\$cust_main\->apply_payments_and_credits; "";\s*$/
208
209       or $c =~ /^\s*\$cust_main\->charge\( \s*\d*\.?\d*\s*,\s*\'[\w \!\@\#\$\%\&\(\)\-\+\;\:\"\,\.\?\/]*\'\s*\);\s*$/
210
211       or $c =~ /^\s*\$cust_main\->suspend_(if|unless)_pkgpart\([\d\,\s]*\);\s*$/
212
213       or $c =~ /^\s*\$cust_bill\->cust_suspend_if_balance_over\([\d\.\s]*\);\s*$/
214
215       or do {
216         #log
217         return "illegal eventcode: $c";
218       };
219
220   }
221
222