bulk checkin from working on the road:
[freeside.git] / FS / FS / part_export.pm
index 444e86a..a43c384 100644 (file)
@@ -22,7 +22,7 @@ FS::part_export - Object methods for part_export records
   ($new_record, $options) = $template_recored->clone( $svcpart );
 
   $error = $record->insert( { 'option' => 'value' } );
-  $error = $record->insert( \$options );
+  $error = $record->insert( \%options );
 
   $error = $new_record->replace($old_record);
 
@@ -102,6 +102,7 @@ created (see L<FS::part_export_option>).
 #false laziness w/queue.pm
 sub insert {
   my $self = shift;
+  my $options = shift;
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
   local $SIG{QUIT} = 'IGNORE';
@@ -119,7 +120,6 @@ sub insert {
     return $error;
   }
 
-  my $options = shift;
   foreach my $optionname ( keys %{$options} ) {
     my $part_export_option = new FS::part_export_option ( {
       'exportnum'   => $self->exportnum,
@@ -191,6 +191,8 @@ created or modified (see L<FS::part_export_option>).
 
 sub replace {
   my $self = shift;
+  my $old = shift;
+  my $options = shift;
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
   local $SIG{QUIT} = 'IGNORE';
@@ -202,13 +204,12 @@ sub replace {
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
-  my $error = $self->SUPER::replace;
+  my $error = $self->SUPER::replace($old);
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
   }
 
-  my $options = shift;
   foreach my $optionname ( keys %{$options} ) {
     my $old = qsearchs( 'part_export_option', {
         'exportnum'   => $self->exportnum,
@@ -219,6 +220,7 @@ sub replace {
         'optionname'  => $optionname,
         'optionvalue' => $options->{$optionname},
     } );
+    $new->optionnum($old->optionnum) if $old;
     my $error = $old ? $new->replace($old) : $new->insert;
     if ( $error ) {
       $dbh->rollback if $oldAutoCommit;
@@ -226,6 +228,17 @@ sub replace {
     }
   }
 
+  #remove extraneous old options
+  foreach my $opt (
+    grep { !exists $options->{$_->optionname} } $old->part_export_option
+  ) {
+    my $error = $opt->delete;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
 
   '';
@@ -244,6 +257,7 @@ sub check {
   my $self = shift;
   my $error = 
     $self->ut_numbern('exportnum')
+    || $self->ut_domain('machine')
     || $self->ut_number('svcpart')
     || $self->ut_alpha('exporttype')
   ;
@@ -277,6 +291,9 @@ sub part_svc {
 
 =item part_export_option
 
+Returns all options as FS::part_export_option objects (see
+L<FS::part_export_option>).
+
 =cut
 
 sub part_export_option {
@@ -286,6 +303,8 @@ sub part_export_option {
 
 =item options 
 
+Returns a list of option names and values suitable for assigning to a hash.
+
 =cut
 
 sub options {
@@ -293,7 +312,9 @@ sub options {
   map { $_->optionname => $_->optionvalue } $self->part_export_option;
 }
 
-=item option
+=item option OPTIONNAME
+
+Returns the option value for the given name, or the empty string.
 
 =cut
 
@@ -309,19 +330,23 @@ sub option {
 
 =item rebless
 
+Reblesses the object into the FS::part_export::EXPORTTYPE class, where
+EXPORTTYPE is the object's I<exporttype> field.  There should be better docs
+on how to create new exports (and they should live in their own files and be
+autoloaded-on-demand), but until then, see L</NEW EXPORT CLASSES>.
+
 =cut
 
 sub rebless {
   my $self = shift;
   my $exporttype = $self->exporttype;
-  my $class = ref($self);
-  bless($self, $class."::$exporttype");
+  my $class = ref($self). "::$exporttype";
+  eval "use $class;";
+  bless($self, $class);
 }
 
 =item export_insert SVC_OBJECT
 
-Calls the appropriate export_I<exporttype> for this object's exporttype.
-
 =cut
 
 sub export_insert {
@@ -339,7 +364,7 @@ sub export_insert {
 #  $self->$method(@_);
 #}
 
-=item export_replace
+=item export_replace NEW OLD
 
 =cut
 
@@ -359,271 +384,34 @@ sub export_delete {
   $self->_export_delete(@_);
 }
 
-=back
-
-#infostreet
-
-package FS::part_export::infostreet;
-use vars qw(@ISA);
-@ISA = qw(FS::part_export);
-
-sub _export_insert {
-  my( $self, $svc_acct ) = (shift, shift);
-  $self->infostreet_queue( $svc_acct->svcnum,
-    'createUser', $svc_acct->username, $svc_acct->password );
-}
-
-sub _export_replace {
-  my( $self, $new, $old ) = (shift, shift, shift);
-  return "can't change username with InfoStreet"
-    if $old->username ne $new->username;
-  return '' unless $old->_password ne $new->_password;
-  $self->infostreet_queue( $new->svcnum,
-    'passwd', $new->username, $new->password );
-}
-
-sub _export_delete {
-  my( $self, $svc_acct ) = (shift, shift);
-  $self->infostreet_queue( $svc_acct->svcnum,
-    'purgeAccount,releaseUsername', $svc_acct->username );
-}
-
-sub infostreet_queue {
-  my( $self, $svcnum, $method ) = (shift, shift, shift);
-  my $queue = new FS::queue {
-    'svcnum' => $svcnum,
-    'job'    => 'FS::part_export::infostreet::infostreet_command',
-  };
-  $queue->insert(
-    $self->option('url'),
-    $self->option('login'),
-    $self->option('password'),
-    $self->option('groupID'),
-    $method,
-    @_,
-  );
-}
-
-sub infostreet_command { #subroutine, not method
-  my($url, $username, $password, $groupID, $method, @args) = @_;
-
-  #quelle hack
-  if ( $method =~ /,/ ) {
-    foreach my $part ( split(/,\s*/, $method) ) {
-      infostreet_command($url, $username, $password, $groupID, $part, @args);
-    }
-    return;
-  }
-
-  eval "use Frontier::Client;";
-
-  my $conn = Frontier::Client->new( url => $url );
-  my $key_result = $conn->call( 'authenticate', $username, $password, $groupID);
-  my %key_result = _infostreet_parse($key_result);
-  die $key_result{error} unless $key_result{success};
-  my $key = $key_result{data};
-
-  my $result = $conn->call($opt{method}, $key, @{$opt{args}});
-  my %result = _infostreet_parse($result);
-  die $result{error} unless $result{success};
-
-}
-
-sub _infostreet_parse { #subroutine, not method
-  my $arg = shift;
-  map {
-    my $value = $arg->{$_};
-    #warn ref($value);
-    $value = $value->value()
-      if ref($value) && $value->isa('Frontier::RPC2::DataType');
-    $_=>$value;
-  } keys %$arg;
-}
-
-#sqlradius
-
-package FS::part_export::sqlradius;
-use vars qw(@ISA);
-@ISA = qw(FS::part_export);
-
+#fallbacks providing useful error messages intead of infinite loops
 sub _export_insert {
-  my($self, $svc_acct) = (shift, shift);
-  $self->sqlradius_queue( $svc_acct->svcnum, 'insert',
-    'reply', $svc_acct->username, $svc_acct->radius_reply );
-  $self->sqlradius_queue( $svc_acct->svcnum, 'insert',
-    'check', $svc_acct->username, $svc_acct->radius_check );
+  my $self = shift;
+  return "_export_insert: unknown export type ". $self->exporttype;
 }
 
 sub _export_replace {
-  my( $self, $new, $old ) = (shift, shift, shift);
-
-  #return "can't (yet) change username with sqlradius"
-  #  if $old->username ne $new->username;
-  if ( $old->username ne $new->username ) {
-    my $error = $self->sqlradius_queue( $new->svcnum, 'rename',
-      $new->username, $old->username );
-    return $error if $error;
-  }
-
-  foreach my $table (qw(reply check)) {
-    my $method = "radius_$table";
-    my %new = $new->$method;
-    my %old = $old->$method;
-    if ( grep { !exists $old{$_} #new attributes
-                || $new{$n} ne $old{$n} #changed
-              } keys %new
-    ) {
-      my $error = $self->sqlradius_queue( $new->svcnum, 'insert'
-        $table, $new->username, %new );
-      return $error if $error;
-    }
-
-    my @del = grep { !exists $new{$_} } keys %old;
-    my $error = $self->sqlradius_queue( $new->svcnum, 'sqlradius_attrib_delete',
-      $table, $new->username, @del );
-    return $error if $error;
-  }
-
-  '';
+  my $self = shift;
+  return "_export_replace: unknown export type ". $self->exporttype;
 }
 
 sub _export_delete {
-  my( $self, $svc_something ) = (shift, shift);
-  $self->sqlradius_queue( $svc_acct->svcnum, 'delete',
-    $svc_something->username );
-}
-
-sub sqlradius_queue {
-  my( $self, $svcnum, $method ) = (shift, shift, shift);
-  my $queue = new FS::queue {
-    'svcnum' => $svcnum,
-    'job'    => "FS::part_export::sqlradius::sqlradius_$method",
-  };
-  $queue->insert(
-    $self->option('datasrc'),
-    $self->option('username'),
-    $self->option('password'),
-    @_,
-  );
-}
-
-sub sqlradius_insert { #subroutine, not method
-  my $dbh = sqlradius_connect(shift, shift, shift);
-  my( $replycheck, $username, %attributes ) = @_;
-
-  foreach my $attribute ( keys %attributes ) {
-    my $u_sth = $dbh->prepare(
-      "UPDATE rad$replycheck SET Value = ? WHERE UserName = ? AND Attribute = ?"    ) or die $dbh->errstr;
-    my $i_sth = $dbh->prepare(
-      "INSERT INTO rad$replycheck ( id, UserName, Attribute, Value ) ".
-        "VALUES ( ?, ?, ?, ? )" )
-      or die $dbh->errstr;
-    $u_sth->execute($attributes{$attribute}, $username, $attribute) > 0
-      or $i_sth->execute( '', $username, $attribute, $attributes{$attribute} )
-        or die "can't insert into rad$replycheck table: ". $i_sth->errstr;
-  }
-  $dbh->disconnect;
-}
-
-sub sqlradius_rename { #subroutine, not method
-  my $dbh = sqlradius_connect(shift, shift, shift);
-  my($new_username, $old_username) = @_;
-  foreach my $table (qw(radreply radcheck)) {
-    my $sth = $dbh->prepare("UPDATE $table SET Username = ? WHERE UserName = ?")
-      or die $dbh->errstr;
-    $sth->execute($new_username, $old_username)
-      or die "can't update $table: ". $sth->errstr;
-  }
-  $dbh->disconnect;
-}
-
-sub sqlradius_attrib_delete { #subroutine, not method
-  my $dbh = sqlradius_connect(shift, shift, shift);
-  my( $replycheck, $username, @attrib ) = @_;
-
-  foreach my $attribute ( @attrib ) {
-    my $sth = $dbh->prepare(
-        "DELETE FROM $table WHERE UserName = ? AND Attribute = ?" )
-      or die $dbh->errstr;
-    $sth->execute($username,$attribute)
-      or die "can't delete from $table table: ". $sth->errstr;
-  }
-  $dbh->disconnect;
-}
-
-sub sqlradius_delete { #subroutine, not method
-  my $dbh = sqlradius_connect(shift, shift, shift);
-  my $username = shift;
-
-  foreach my $table (qw( radcheck radreply )) {
-    my $sth = $dbh->prepare( "DELETE FROM $table WHERE UserName = ?" );
-    $sth->execute($username)
-      or die "can't delete from $table table: ". $sth->errstr;
-  }
-  $dbh->disconnect;
-}
-
-sub sqlradius_connect {
-  #my($datasrc, $username, $password) = @_;
-  #DBI->connect($datasrc, $username, $password) or die $DBI::errstr;
-  DBI->connect(@_) or die $DBI::errstr;
-}
-
-=head1 NOTES
-
-Writing a new export class:
-
-#myexport
-
-package FS::part_export::myexport;
-use vars qw(@ISA);
-@ISA = qw(FS::part_export);
-
-sub _export_insert {
-  my($self, $svc_something) = (shift, shift);
-  $self->myexport_queue( $svc_acct->svcnum, 'insert',
-    $svc_something->username, $svc_something->password );
-}
-
-sub _export_replace {
-  my( $self, $new, $old ) = (shift, shift, shift);
-  #return "can't change username with myexport"
-  #  if $old->username ne $new->username;
-  #return '' unless $old->_password ne $new->_password;
-  $self->myexport_queue( $new->svcnum,
-    'replace', $new->username, $new->password );
+  my $self = shift;
+  return "_export_delete: unknown export type ". $self->exporttype;
 }
 
-sub _export_delete {
-  my( $self, $svc_something ) = (shift, shift);
-  $self->myexport_queue( $svc_acct->svcnum,
-    'delete', $svc_something->username );
-}
+=back
 
-#a good idea to queue anything that could fail or take any time
-sub myexport_queue {
-  my( $self, $svcnum, $method ) = (shift, shift, shift);
-  my $queue = new FS::queue {
-    'svcnum' => $svcnum,
-    'job'    => "FS::part_export::myexport::myexport_$method",
-  };
-  $queue->insert( @_ );
-}
+=head1 NEW EXPORT CLASSES
 
-sub myexport_insert { #subroutine, not method
-}
-sub myexport_replace { #subroutine, not method
-}
-sub myexport_delete { #subroutine, not method
-}
+Should be added to httemplate/edit/part_export.cgi and a module should
+be FS/FS/part_export/ (an example may be found in eg/export_template.pm)
 
 =head1 BUGS
 
 Probably.
 
-Hmm, export code has wound up in here.  Move those sub-classes out into their
-own files, at least.  Also hmm... cust_export class (not necessarily a
-database table...) ... ?
+Hmm... cust_export class (not necessarily a database table...) ... ?
 
 =head1 SEE ALSO