event refactor, landing on HEAD!
[freeside.git] / bin / freeside-migrate-events
diff --git a/bin/freeside-migrate-events b/bin/freeside-migrate-events
new file mode 100644 (file)
index 0000000..74732b7
--- /dev/null
@@ -0,0 +1,217 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+use FS::UID qw(adminsuidsetup);
+use FS::Record qw( qsearch );
+use FS::part_bill_event;
+use FS::part_event;
+use FS::cust_bill_event;
+use FS::cust_event;
+
+my $user = shift or die &usage;
+adminsuidsetup($user);
+
+my %plan2action = (
+  'fee'                    => 'fee',
+  'fee_percent'            => 'NOTYET', #XXX need fee_percent action
+  'suspend'                => 'suspend',
+  'suspend-if-balance'     => 'NOTYET', #XXX "if balance" becomes a balance condition
+  'suspend-if-pkgpart'     => 'suspend_if_pkgpart',
+  'suspend-unless-pkgpart' => 'suspend_unless_pkgpart',
+  'cancel'                 => 'cancel',
+  'addpost'                => 'addpost',
+  'comp'                   => 'NOTYET', #XXX or N/A or something
+  'credit'                 => 'NOTYET',
+  'realtime-card'          => 'cust_bill_realtime_card',
+  'realtime-check'         => 'cust_bill_realtime_check',
+  'realtime-lec'           => 'cust_bill_realtime_lec',
+  'batch-card'             => 'cust_bill_batch',
+  #?'retriable'             =>
+  'send'                   => 'cust_bill_send',
+  'send_email'             => 'NOTYET', 
+  'send_alternate'         => 'cust_bill_send_alternate',
+  'send_if_newest'         => 'cust_bill_send_if_newest',
+  'send_agent'             => 'cust_bill_send_agent',
+  'send_csv_ftp'           => 'cust_bill_send_csv_ftp',
+  'spool_csv',             => 'cust_bill_spool_csv',
+  'bill'                   => 'bill',
+  'apply'                  => 'apply',
+  'collect'                => 'collect',
+);
+
+#XXX may need to fudge some plandata2option names!!!
+
+foreach my $part_bill_event (
+  qsearch({
+    'table'   => 'part_bill_event',
+  })
+) {
+
+  print $part_bill_event->event;
+
+  my $action = $plan2action{ $part_bill_event->plan };
+
+  if ( $action eq 'NOTYET' ) {
+    warn "not migrating part_bill_event.eventpart ".$part_bill_event->eventpart.
+         "; ". $part_bill_event->plan. " plan not (yet) handled";
+    next;
+  } elsif ( ! $action ) {
+    warn "not migrating part_bill_event.eventpart ".$part_bill_event->eventpart.
+         "; unknown plan ". $part_bill_event->plan;
+    next;
+  }
+
+  my $part_event = new FS::part_event {
+    'event'      => $part_bill_event->event,
+    'eventtable' => 'cust_bill',
+    'check_freq' => $part_bill_event->freq || '1d',
+    'weight'     => $part_bill_event->weight,
+    'action'     => $action,
+    'disabled'   => $part_bill_event->disabled,
+  };
+
+  my $error = $part_event->insert;
+  die "error inserting part_event: $error\n" if $error;
+
+  print ' '. $part_event->eventpart;
+
+  my $once = new FS::part_event_condition {
+    'eventpart'     => $part_event->eventpart,
+    'conditionname' => 'once'
+  };
+  $error = $once->insert;
+  die $error if $error;
+  
+  my $balance = new FS::part_event_condition {
+    'eventpart'     => $part_event->eventpart,
+    'conditionname' => 'balance'
+  };
+  $error = $balance->insert( 'balance' => 0 );
+  die $error if $error;
+
+  my $payby = new FS::part_event_condition {
+    'eventpart'     => $part_event->eventpart,
+    'conditionname' => 'payby'
+  };
+  $error = $payby->insert( 'payby' => { $part_bill_event->payby => 1 } );
+  die $error if $error;
+
+  if ( $part_bill_event->seconds ) {
+
+    my $age = new FS::part_event_condition { 
+      'eventpart'     => $part_event->eventpart,
+      'conditionname' => 'cust_bill_age'
+    };
+    $error = $payby->insert( 'age' => ($part_bill_event->seconds/86400 ).'d' );
+    die $error if $error;
+
+  }
+  
+  #my $derror = $part_bill_event->delete;
+  #die "error removing part_bill_event: $derror\n" if $derror;
+
+  foreach my $cust_bill_event (
+    qsearch({
+      'table'     => 'cust_bill_event',
+      'hashref'   => { 'eventpart' => $part_bill_event->eventpart, },
+    })
+  ) {
+
+    my $cust_event = new FS::cust_event {
+      'eventpart'  => $part_event->eventpart,
+      'tablenum'   => $cust_bill_event->invnum,
+      '_date'      => $cust_bill_event->_date,
+      'status'     => $cust_bill_event->status,
+      'statustext' => $cust_bill_event->statustext,
+    };
+
+    my $cerror = $cust_event->insert;
+    die "error inserting cust_event: $cerror\n" if $cerror;
+  
+    #my $dcerror = $cust_bill_event->delete;
+    #die "error removing cust_bill_event: $dcerror\n" if $dcerror;
+
+    print ".";
+
+  }
+
+  print "\n";
+
+}
+
+sub usage {
+  die "Usage:\n  freeside-migrate-events user\n"; 
+}
+
+=head1 NAME
+
+freeside-migrate-events - Migrates 1.7/1.8-style invoice events to
+                          1.9/2.0-style billing events
+
+=head1 SYNOPSIS
+
+  freeside-migrate-events
+
+=head1 DESCRIPTION
+
+Migrates events from L<FS::part_bill_event> to L<FS::part_event> and friends,
+and from L<FS::cust_bill_event> records to L<FS::cust_event>
+
+=head1 BUGS
+
+Doesn't migrate any action options yet.
+
+Doesn't translate option names that changed.
+
+Doesn't migrate reasons.
+
+Doesn't delete the old events (which is not a big deal, since the new code
+won't run them...)
+
+=head1 SEE ALSO
+
+=cut
+
+1;
+
+__END__
+
+#part_bill_event      part_event
+#
+#eventpart            n/a
+#event                event
+#freq                 check_freq
+#payby                part_event_condition.conditionname = payby
+#eventcode            PARSE_WITH_REGEX (probably can just get from plandata)
+#seconds              part_event_condition.conditionname = cust_bill_age
+#plandata             PARSE_WITH_REGEX (along with eventcode, yuck)
+#reason               part_event_option.optionname = reason
+#disabled             disabled
+#
+
+    #these might help parse existing eventcode
+
+    $c =~ /^\s*\$cust_main\->(suspend|cancel|invoicing_list_addpost|bill|collect)\(\);\s*("";)?\s*$/
+
+      or $c =~ /^\s*\$cust_bill\->(comp|realtime_(card|ach|lec)|batch_card|send)\((%options)*\);\s*$/
+
+      or $c =~ /^\s*\$cust_bill\->send(_if_newest)?\(\'[\w\-\s]+\'\s*(,\s*(\d+|\[\s*\d+(,\s*\d+)*\s*\])\s*,\s*'[\w\@\.\-\+]*'\s*)?\);\s*$/
+
+#      or $c =~ /^\s*\$cust_main\->apply_payments; \$cust_main->apply_credits; "";\s*$/
+      or $c =~ /^\s*\$cust_main\->apply_payments_and_credits; "";\s*$/
+
+      or $c =~ /^\s*\$cust_main\->charge\( \s*\d*\.?\d*\s*,\s*\'[\w \!\@\#\$\%\&\(\)\-\+\;\:\"\,\.\?\/]*\'\s*\);\s*$/
+
+      or $c =~ /^\s*\$cust_main\->suspend_(if|unless)_pkgpart\([\d\,\s]*\);\s*$/
+
+      or $c =~ /^\s*\$cust_bill\->cust_suspend_if_balance_over\([\d\.\s]*\);\s*$/
+
+      or do {
+        #log
+        return "illegal eventcode: $c";
+      };
+
+  }
+
+