5 use FS::UID qw(adminsuidsetup);
6 use FS::Record qw( qsearch );
7 use FS::part_bill_event;
9 use FS::cust_bill_event;
12 my $user = shift or die &usage;
13 adminsuidsetup($user);
17 'fee_percent' => 'NOTYET', #XXX need fee_percent action
18 'suspend' => 'suspend',
19 'suspend-if-balance' => 'suspend', #"if balance" becomes the balance cond
20 'suspend-if-pkgpart' => 'suspend_if_pkgpart',
21 'suspend-unless-pkgpart' => 'suspend_unless_pkgpart',
23 'addpost' => 'addpost',
24 'comp' => 'NOTYET', #XXX or N/A or something
25 'credit' => 'writeoff',
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',
31 'send' => 'cust_bill_send',
32 'send_email' => 'cust_bill_email',
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',
40 'collect' => 'collect',
44 foreach my $part_bill_event (
46 'table' => 'part_bill_event',
50 print $part_bill_event->event;
52 my $action = $plan2action{ $part_bill_event->plan };
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";
58 } elsif ( ! $action ) {
59 warn "not migrating part_bill_event.eventpart ".$part_bill_event->eventpart.
60 "; unknown plan ". $part_bill_event->plan;
64 my %plandata = map { /^(\w+) (.*)$/; ($1, $2); }
65 split(/\n/, $part_bill_event->plandata);
67 #XXX may need to fudge some other plandata2option names
70 my $honor_dundate = 0;
72 if ( $part_bill_event->plan eq 'suspend-if-balance' ) {
73 $balanceover = delete $plandata{'balanceover'};
74 $honor_dundate = ( (delete $plandata{'balance_honor_dundate'}) =~ /1/ );
77 my $part_event = new FS::part_event {
78 'event' => $part_bill_event->event,
79 'eventtable' => 'cust_bill',
80 'check_freq' => $part_bill_event->freq || '1d',
81 'weight' => $part_bill_event->weight,
83 'disabled' => $part_bill_event->disabled,
86 my $error = $part_event->insert(\%plandata);
87 die "error inserting part_event: $error\n" if $error;
89 print ' '. $part_event->eventpart;
91 my $once = new FS::part_event_condition {
92 'eventpart' => $part_event->eventpart,
93 'conditionname' => 'once'
95 $error = $once->insert;
98 my $balance = new FS::part_event_condition {
99 'eventpart' => $part_event->eventpart,
100 'conditionname' => 'balance'
102 $error = $balance->insert( 'balance' => $balanceover );
103 die $error if $error;
105 my $cust_bill_owed = new FS::part_event_condition {
106 'eventpart' => $part_event->eventpart,
107 'conditionname' => 'cust_bill_owed'
109 $error = $cust_bill_owed->insert( 'owed' => 0 );
110 die $error if $error;
112 my $payby = new FS::part_event_condition {
113 'eventpart' => $part_event->eventpart,
114 'conditionname' => 'payby'
116 $error = $payby->insert( 'payby' => { $part_bill_event->payby => 1 } );
117 die $error if $error;
119 if ( $part_bill_event->seconds ) {
121 my $age = new FS::part_event_condition {
122 'eventpart' => $part_event->eventpart,
123 'conditionname' => 'cust_bill_age'
125 $error = $age->insert( 'age' => ($part_bill_event->seconds/86400 ).'d' );
126 die $error if $error;
130 if ( $honor_dundate ) {
131 my $dundate = new FS::part_event_condition {
132 'eventpart' => $part_event->eventpart,
133 'conditionname' => 'dundate'
135 $error = $dundate->insert();
136 die $error if $error;
139 #my $derror = $part_bill_event->delete;
140 #die "error removing part_bill_event: $derror\n" if $derror;
142 foreach my $cust_bill_event (
144 'table' => 'cust_bill_event',
145 'hashref' => { 'eventpart' => $part_bill_event->eventpart, },
149 my $cust_event = new FS::cust_event {
150 'eventpart' => $part_event->eventpart,
151 'tablenum' => $cust_bill_event->invnum,
152 '_date' => $cust_bill_event->_date,
153 'status' => $cust_bill_event->status,
154 'statustext' => $cust_bill_event->statustext,
157 my $cerror = $cust_event->insert;
158 #die "error inserting cust_event: $cerror\n" if $cerror;
159 warn "error inserting cust_event: $cerror\n" if $cerror;
161 #my $dcerror = $cust_bill_event->delete;
162 #die "error removing cust_bill_event: $dcerror\n" if $dcerror;
173 die "Usage:\n freeside-migrate-events user\n";
178 freeside-migrate-events - Migrates 1.7/1.8-style invoice events to
179 1.9/2.0-style billing events
183 freeside-migrate-events
187 Migrates events from L<FS::part_bill_event> to L<FS::part_event> and friends,
188 and from L<FS::cust_bill_event> records to L<FS::cust_event>
192 Doesn't migrate any action options yet.
194 Doesn't translate option names that changed.
196 Doesn't migrate reasons.
198 Doesn't delete the old events (which is not a big deal, since the new code
209 #part_bill_event part_event
214 #payby part_event_condition.conditionname = payby
215 #eventcode PARSE_WITH_REGEX (probably can just get from plandata)
216 #seconds part_event_condition.conditionname = cust_bill_age
217 #plandata PARSE_WITH_REGEX (along with eventcode, yuck)
218 #reason part_event_option.optionname = reason
222 #these might help parse existing eventcode
224 $c =~ /^\s*\$cust_main\->(suspend|cancel|invoicing_list_addpost|bill|collect)\(\);\s*("";)?\s*$/
226 or $c =~ /^\s*\$cust_bill\->(comp|realtime_(card|ach|lec)|batch_card|send)\((%options)*\);\s*$/
228 or $c =~ /^\s*\$cust_bill\->send(_if_newest)?\(\'[\w\-\s]+\'\s*(,\s*(\d+|\[\s*\d+(,\s*\d+)*\s*\])\s*,\s*'[\w\@\.\-\+]*'\s*)?\);\s*$/
230 # or $c =~ /^\s*\$cust_main\->apply_payments; \$cust_main->apply_credits; "";\s*$/
231 or $c =~ /^\s*\$cust_main\->apply_payments_and_credits; "";\s*$/
233 or $c =~ /^\s*\$cust_main\->charge\( \s*\d*\.?\d*\s*,\s*\'[\w \!\@\#\$\%\&\(\)\-\+\;\:\"\,\.\?\/]*\'\s*\);\s*$/
235 or $c =~ /^\s*\$cust_main\->suspend_(if|unless)_pkgpart\([\d\,\s]*\);\s*$/
237 or $c =~ /^\s*\$cust_bill\->cust_suspend_if_balance_over\([\d\.\s]*\);\s*$/
241 return "illegal eventcode: $c";