correctly allow re-editing of config options with " in them
[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 $cust_bill_owed = new FS::part_event_condition {
98     'eventpart'     => $part_event->eventpart,
99     'conditionname' => 'cust_bill_owed'
100   };
101   $error = $cust_bill_owed->insert( 'owed' => 0 );
102   die $error if $error;
103
104   my $payby = new FS::part_event_condition {
105     'eventpart'     => $part_event->eventpart,
106     'conditionname' => 'payby'
107   };
108   $error = $payby->insert( 'payby' => { $part_bill_event->payby => 1 } );
109   die $error if $error;
110
111   if ( $part_bill_event->seconds ) {
112
113     my $age = new FS::part_event_condition { 
114       'eventpart'     => $part_event->eventpart,
115       'conditionname' => 'cust_bill_age'
116     };
117     $error = $age->insert( 'age' => ($part_bill_event->seconds/86400 ).'d' );
118     die $error if $error;
119
120   }
121   
122   #my $derror = $part_bill_event->delete;
123   #die "error removing part_bill_event: $derror\n" if $derror;
124
125   foreach my $cust_bill_event (
126     qsearch({
127       'table'     => 'cust_bill_event',
128       'hashref'   => { 'eventpart' => $part_bill_event->eventpart, },
129     })
130   ) {
131
132     my $cust_event = new FS::cust_event {
133       'eventpart'  => $part_event->eventpart,
134       'tablenum'   => $cust_bill_event->invnum,
135       '_date'      => $cust_bill_event->_date,
136       'status'     => $cust_bill_event->status,
137       'statustext' => $cust_bill_event->statustext,
138     };
139
140     my $cerror = $cust_event->insert;
141     #die "error inserting cust_event: $cerror\n" if $cerror;
142     warn "error inserting cust_event: $cerror\n" if $cerror;
143   
144     #my $dcerror = $cust_bill_event->delete;
145     #die "error removing cust_bill_event: $dcerror\n" if $dcerror;
146
147     print ".";
148
149   }
150
151   print "\n";
152
153 }
154
155 sub usage {
156   die "Usage:\n  freeside-migrate-events user\n"; 
157 }
158
159 =head1 NAME
160
161 freeside-migrate-events - Migrates 1.7/1.8-style invoice events to
162                           1.9/2.0-style billing events
163
164 =head1 SYNOPSIS
165
166   freeside-migrate-events
167
168 =head1 DESCRIPTION
169
170 Migrates events from L<FS::part_bill_event> to L<FS::part_event> and friends,
171 and from L<FS::cust_bill_event> records to L<FS::cust_event>
172
173 =head1 BUGS
174
175 Doesn't migrate any action options yet.
176
177 Doesn't translate option names that changed.
178
179 Doesn't migrate reasons.
180
181 Doesn't delete the old events (which is not a big deal, since the new code
182 won't run them...)
183
184 =head1 SEE ALSO
185
186 =cut
187
188 1;
189
190 __END__
191
192 #part_bill_event      part_event
193 #
194 #eventpart            n/a
195 #event                event
196 #freq                 check_freq
197 #payby                part_event_condition.conditionname = payby
198 #eventcode            PARSE_WITH_REGEX (probably can just get from plandata)
199 #seconds              part_event_condition.conditionname = cust_bill_age
200 #plandata             PARSE_WITH_REGEX (along with eventcode, yuck)
201 #reason               part_event_option.optionname = reason
202 #disabled             disabled
203 #
204
205     #these might help parse existing eventcode
206
207     $c =~ /^\s*\$cust_main\->(suspend|cancel|invoicing_list_addpost|bill|collect)\(\);\s*("";)?\s*$/
208
209       or $c =~ /^\s*\$cust_bill\->(comp|realtime_(card|ach|lec)|batch_card|send)\((%options)*\);\s*$/
210
211       or $c =~ /^\s*\$cust_bill\->send(_if_newest)?\(\'[\w\-\s]+\'\s*(,\s*(\d+|\[\s*\d+(,\s*\d+)*\s*\])\s*,\s*'[\w\@\.\-\+]*'\s*)?\);\s*$/
212
213 #      or $c =~ /^\s*\$cust_main\->apply_payments; \$cust_main->apply_credits; "";\s*$/
214       or $c =~ /^\s*\$cust_main\->apply_payments_and_credits; "";\s*$/
215
216       or $c =~ /^\s*\$cust_main\->charge\( \s*\d*\.?\d*\s*,\s*\'[\w \!\@\#\$\%\&\(\)\-\+\;\:\"\,\.\?\/]*\'\s*\);\s*$/
217
218       or $c =~ /^\s*\$cust_main\->suspend_(if|unless)_pkgpart\([\d\,\s]*\);\s*$/
219
220       or $c =~ /^\s*\$cust_bill\->cust_suspend_if_balance_over\([\d\.\s]*\);\s*$/
221
222       or do {
223         #log
224         return "illegal eventcode: $c";
225       };
226
227   }
228
229