fix for freeside-migrate-events bug that would throw a duplicate row error instead...
[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 = $age->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     warn "error inserting cust_event: $cerror\n" if $cerror;
132   
133     #my $dcerror = $cust_bill_event->delete;
134     #die "error removing cust_bill_event: $dcerror\n" if $dcerror;
135
136     print ".";
137
138   }
139
140   print "\n";
141
142 }
143
144 sub usage {
145   die "Usage:\n  freeside-migrate-events user\n"; 
146 }
147
148 =head1 NAME
149
150 freeside-migrate-events - Migrates 1.7/1.8-style invoice events to
151                           1.9/2.0-style billing events
152
153 =head1 SYNOPSIS
154
155   freeside-migrate-events
156
157 =head1 DESCRIPTION
158
159 Migrates events from L<FS::part_bill_event> to L<FS::part_event> and friends,
160 and from L<FS::cust_bill_event> records to L<FS::cust_event>
161
162 =head1 BUGS
163
164 Doesn't migrate any action options yet.
165
166 Doesn't translate option names that changed.
167
168 Doesn't migrate reasons.
169
170 Doesn't delete the old events (which is not a big deal, since the new code
171 won't run them...)
172
173 =head1 SEE ALSO
174
175 =cut
176
177 1;
178
179 __END__
180
181 #part_bill_event      part_event
182 #
183 #eventpart            n/a
184 #event                event
185 #freq                 check_freq
186 #payby                part_event_condition.conditionname = payby
187 #eventcode            PARSE_WITH_REGEX (probably can just get from plandata)
188 #seconds              part_event_condition.conditionname = cust_bill_age
189 #plandata             PARSE_WITH_REGEX (along with eventcode, yuck)
190 #reason               part_event_option.optionname = reason
191 #disabled             disabled
192 #
193
194     #these might help parse existing eventcode
195
196     $c =~ /^\s*\$cust_main\->(suspend|cancel|invoicing_list_addpost|bill|collect)\(\);\s*("";)?\s*$/
197
198       or $c =~ /^\s*\$cust_bill\->(comp|realtime_(card|ach|lec)|batch_card|send)\((%options)*\);\s*$/
199
200       or $c =~ /^\s*\$cust_bill\->send(_if_newest)?\(\'[\w\-\s]+\'\s*(,\s*(\d+|\[\s*\d+(,\s*\d+)*\s*\])\s*,\s*'[\w\@\.\-\+]*'\s*)?\);\s*$/
201
202 #      or $c =~ /^\s*\$cust_main\->apply_payments; \$cust_main->apply_credits; "";\s*$/
203       or $c =~ /^\s*\$cust_main\->apply_payments_and_credits; "";\s*$/
204
205       or $c =~ /^\s*\$cust_main\->charge\( \s*\d*\.?\d*\s*,\s*\'[\w \!\@\#\$\%\&\(\)\-\+\;\:\"\,\.\?\/]*\'\s*\);\s*$/
206
207       or $c =~ /^\s*\$cust_main\->suspend_(if|unless)_pkgpart\([\d\,\s]*\);\s*$/
208
209       or $c =~ /^\s*\$cust_bill\->cust_suspend_if_balance_over\([\d\.\s]*\);\s*$/
210
211       or do {
212         #log
213         return "illegal eventcode: $c";
214       };
215
216   }
217
218