5 use FS::UID qw( adminsuidsetup dbh );
6 use FS::Record qw( qsearch );
7 use FS::part_bill_event;
9 use FS::cust_bill_event;
12 #use vars qw( $opt_m );
15 my $user = shift or die &usage;
16 adminsuidsetup($user);
20 'fee_percent' => 'NOTYET', #XXX need fee_percent action
21 'suspend' => 'suspend',
22 'suspend-if-balance' => 'suspend', #"if balance" becomes the balance cond
23 'suspend-if-pkgpart' => 'suspend_if_pkgpart',
24 'suspend-unless-pkgpart' => 'suspend_unless_pkgpart',
26 'addpost' => 'addpost',
27 'comp' => 'NOTYET', #XXX or N/A or something
28 'credit' => 'writeoff',
29 'realtime-card' => 'cust_bill_realtime_card',
30 'realtime-check' => 'cust_bill_realtime_check',
31 'realtime-lec' => 'cust_bill_realtime_lec',
32 'batch-card' => 'cust_bill_batch',
34 'send' => 'cust_bill_send',
35 'send_email' => 'cust_bill_email',
36 'send_alternate' => 'cust_bill_send_alternate',
37 'send_if_newest' => 'cust_bill_send_if_newest',
38 'send_agent' => 'cust_bill_send_agent',
39 'send_csv_ftp' => 'cust_bill_send_csv_ftp',
40 'spool_csv', => 'cust_bill_spool_csv',
43 'collect' => 'collect',
47 foreach my $part_bill_event (
49 'table' => 'part_bill_event',
53 print $part_bill_event->event;
55 my $action = $plan2action{ $part_bill_event->plan };
57 if ( $action eq 'NOTYET' ) {
58 warn "not migrating part_bill_event.eventpart ".$part_bill_event->eventpart.
59 "; ". $part_bill_event->plan. " plan not (yet) handled";
61 } elsif ( ! $action ) {
62 warn "not migrating part_bill_event.eventpart ".$part_bill_event->eventpart.
63 "; unknown plan ". $part_bill_event->plan;
67 my %plandata = map { /^(\w+) (.*)$/; ($1, $2); }
68 split(/\n/, $part_bill_event->plandata);
70 #XXX may need to fudge some other plandata2option names
73 my $honor_dundate = 0;
75 if ( $part_bill_event->plan eq 'suspend-if-balance' ) {
76 $balanceover = delete $plandata{'balanceover'};
77 $honor_dundate = ( (delete $plandata{'balance_honor_dundate'}) =~ /1/ );
80 my $part_event = new FS::part_event {
81 'event' => $part_bill_event->event,
82 'eventtable' => 'cust_bill',
83 'check_freq' => $part_bill_event->freq || '1d',
84 'weight' => $part_bill_event->weight,
86 'disabled' => $part_bill_event->disabled,
89 my $error = $part_event->insert(\%plandata);
90 die "error inserting part_event: $error\n" if $error;
92 print ' '. $part_event->eventpart;
94 my $once = new FS::part_event_condition {
95 'eventpart' => $part_event->eventpart,
96 'conditionname' => 'once'
98 $error = $once->insert;
101 my $balance = new FS::part_event_condition {
102 'eventpart' => $part_event->eventpart,
103 'conditionname' => 'balance'
105 $error = $balance->insert( 'balance' => $balanceover );
106 die $error if $error;
108 my $cust_bill_owed = new FS::part_event_condition {
109 'eventpart' => $part_event->eventpart,
110 'conditionname' => 'cust_bill_owed'
112 $error = $cust_bill_owed->insert( 'owed' => 0 );
113 die $error if $error;
115 my $payby = new FS::part_event_condition {
116 'eventpart' => $part_event->eventpart,
117 'conditionname' => 'payby'
119 $error = $payby->insert( 'payby' => { $part_bill_event->payby => 1 } );
120 die $error if $error;
122 if ( $part_bill_event->seconds ) {
124 my $age = new FS::part_event_condition {
125 'eventpart' => $part_event->eventpart,
126 'conditionname' => 'cust_bill_age'
128 $error = $age->insert( 'age' => ($part_bill_event->seconds/86400 ).'d' );
129 die $error if $error;
133 if ( $honor_dundate ) {
134 my $dundate = new FS::part_event_condition {
135 'eventpart' => $part_event->eventpart,
136 'conditionname' => 'dundate'
138 $error = $dundate->insert();
139 die $error if $error;
142 #my $derror = $part_bill_event->delete;
143 #die "error removing part_bill_event: $derror\n" if $derror;
147 my $sth = dbh->prepare('
148 INSERT INTO cust_event ( eventpart, tablenum, _date, status, statustext )
149 SELECT ? , invnum , _date, status, statustext
150 FROM cust_bill_event WHERE eventpart = ?
151 ') or die dbh->errstr;
153 $sth->execute( $part_event->eventpart, $part_bill_event->eventpart )
158 # foreach my $cust_bill_event (
160 # 'table' => 'cust_bill_event',
161 # 'hashref' => { 'eventpart' => $part_bill_event->eventpart, },
165 # my $cust_event = new FS::cust_event {
166 # 'eventpart' => $part_event->eventpart,
167 # 'tablenum' => $cust_bill_event->invnum,
168 # '_date' => $cust_bill_event->_date,
169 # 'status' => $cust_bill_event->status,
170 # 'statustext' => $cust_bill_event->statustext,
173 # my $cerror = $cust_event->insert;
174 # #die "error inserting cust_event: $cerror\n" if $cerror;
175 # warn "error inserting cust_event: $cerror\n" if $cerror;
177 # #my $dcerror = $cust_bill_event->delete;
178 # #die "error removing cust_bill_event: $dcerror\n" if $dcerror;
191 die "Usage:\n freeside-migrate-events user\n";
196 freeside-migrate-events - Migrates 1.7/1.8-style invoice events to
197 1.9/2.0-style billing events
201 freeside-migrate-events
205 Migrates events from L<FS::part_bill_event> to L<FS::part_event> and friends,
206 and from L<FS::cust_bill_event> records to L<FS::cust_event>
210 Doesn't migrate any action options yet.
212 Doesn't translate option names that changed.
214 Doesn't migrate reasons.
216 Doesn't delete the old events (which is not a big deal, since the new code
219 Can take lots of memory for large databases.
229 #part_bill_event part_event
234 #payby part_event_condition.conditionname = payby
235 #eventcode PARSE_WITH_REGEX (probably can just get from plandata)
236 #seconds part_event_condition.conditionname = cust_bill_age
237 #plandata PARSE_WITH_REGEX (along with eventcode, yuck)
238 #reason part_event_option.optionname = reason
242 #these might help parse existing eventcode
244 $c =~ /^\s*\$cust_main\->(suspend|cancel|invoicing_list_addpost|bill|collect)\(\);\s*("";)?\s*$/
246 or $c =~ /^\s*\$cust_bill\->(comp|realtime_(card|ach|lec)|batch_card|send)\((%options)*\);\s*$/
248 or $c =~ /^\s*\$cust_bill\->send(_if_newest)?\(\'[\w\-\s]+\'\s*(,\s*(\d+|\[\s*\d+(,\s*\d+)*\s*\])\s*,\s*'[\w\@\.\-\+]*'\s*)?\);\s*$/
250 # or $c =~ /^\s*\$cust_main\->apply_payments; \$cust_main->apply_credits; "";\s*$/
251 or $c =~ /^\s*\$cust_main\->apply_payments_and_credits; "";\s*$/
253 or $c =~ /^\s*\$cust_main\->charge\( \s*\d*\.?\d*\s*,\s*\'[\w \!\@\#\$\%\&\(\)\-\+\;\:\"\,\.\?\/]*\'\s*\);\s*$/
255 or $c =~ /^\s*\$cust_main\->suspend_(if|unless)_pkgpart\([\d\,\s]*\);\s*$/
257 or $c =~ /^\s*\$cust_bill\->cust_suspend_if_balance_over\([\d\.\s]*\);\s*$/
261 return "illegal eventcode: $c";