add progressbar to service definition add - duplicate checking can take a while,...
authorivan <ivan>
Thu, 24 Feb 2005 14:24:07 +0000 (14:24 +0000)
committerivan <ivan>
Thu, 24 Feb 2005 14:24:07 +0000 (14:24 +0000)
FS/FS/UI/Web.pm
FS/FS/export_svc.pm
FS/FS/part_svc.pm
FS/FS/rate.pm
FS/FS/svc_acct.pm
httemplate/edit/part_svc.cgi
httemplate/edit/process/part_svc.cgi [new file with mode: 0755]
httemplate/elements/progress-init.html
httemplate/elements/progress-popup.html

index 18c2dfe..46e904b 100644 (file)
@@ -36,9 +36,27 @@ sub new {
 sub start_job {
   my $self = shift;
 
-  my %param = @_;
+  warn "FS::UI::Web::start_job: ". join(', ', @_) if $DEBUG;
+#  my %param = @_;
+  my %param = ();
+  while ( @_ ) {
+    my( $field, $value ) = splice(@_, 0, 2);
+    unless ( exists( $param{$field} ) ) {
+      $param{$field} = $value;
+    } elsif ( ! ref($param{$field}) ) {
+      $param{$field} = [ $param{$field}, $value ];
+    } else {
+      push @{$param{$field}}, $value;
+    }
+  }
   warn "FS::UI::Web::start_job\n".
-       join('', map "  $_ => $param{$_}\n", keys %param )
+       join('', map {
+                      if ( ref($param{$_}) ) {
+                        "  $_ => [ ". join(', ', @{$param{$_}}). " ]\n";
+                      } else {
+                        "  $_ => $param{$_}\n";
+                      }
+                    } keys %param )
     if $DEBUG;
 
   #first get the CGI params shipped off to a job ASAP so an id can be returned
index d1153c0..b196d6c 100644 (file)
@@ -60,16 +60,21 @@ points to.  You can ask the object for a copy with the I<hash> method.
 
 sub table { 'export_svc'; }
 
-=item insert
+=item insert [ JOB, OFFSET, MULTIPLIER ]
 
 Adds this record to the database.  If there is an error, returns the error,
 otherwise returns false.
 
+TODOC: JOB, OFFSET, MULTIPLIER
+
 =cut
 
 sub insert {
   my $self = shift;
-  my $error;
+  my( $job, $offset, $mult ) = ( '', 0, 100);
+  $job = shift if @_;
+  $offset = shift if @_;
+  $mult = shift if @_;
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
@@ -82,7 +87,7 @@ sub insert {
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
-  $error = $self->check;
+  my $error = $self->check;
   return $error if $error;
 
   #check for duplicates!
@@ -126,11 +131,40 @@ sub insert {
     warn "WARNING: No duplicate checking done on merge of $svcdb exports";
   }
 
+  my $done = 0;
+  my $percheck = $mult / scalar(@checks);
   foreach my $check ( @checks ) {
+
+    if ( $job ) {
+      $error = $job->update_statustext(int( $offset + ($done+.33) *$percheck ));
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
+    }
+
     my @current_svc = $self->part_export->svc_x;
     #warn "current: ". scalar(@current_svc). " $current_svc[0]\n";
+
+    if ( $job ) {
+      $error = $job->update_statustext(int( $offset + ($done+.67) *$percheck ));
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
+    }
+
     my @new_svc = $self->part_svc->svc_x;
     #warn "new: ". scalar(@new_svc). " $new_svc[0]\n";
+
+    if ( $job ) {
+      $error = $job->update_statustext(int( $offset + ($done+1) *$percheck ));
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
+    }
+
     my $method = $check->{'method'};
     my %cur_svc = map { $_->$method() => $_ } @current_svc;
     my @dup_svc = grep { $cur_svc{$_->$method()} } @new_svc;
@@ -165,6 +199,8 @@ sub insert {
              ": ". join(', ', sort $sortby map { $_->$method() } @diff_customer_svc )
              ;
     }
+
+    $done++;
   }
 
   #end of duplicate check, whew
index e7f205d..e94c803 100644 (file)
@@ -1,7 +1,7 @@
 package FS::part_svc;
 
 use strict;
-use vars qw( @ISA );
+use vars qw( @ISA $DEBUG );
 use FS::Record qw( qsearch qsearchs fields dbh );
 use FS::part_svc_column;
 use FS::part_export;
@@ -10,6 +10,8 @@ use FS::cust_svc;
 
 @ISA = qw(FS::Record);
 
+$DEBUG = 1;
+
 =head1 NAME
 
 FS::part_svc - Object methods for part_svc objects
@@ -64,7 +66,7 @@ database, see L<"insert">.
 
 sub table { 'part_svc'; }
 
-=item insert [ EXTRA_FIELDS_ARRAYREF [ , EXPORTNUMS_HASHREF ] ] 
+=item insert [ EXTRA_FIELDS_ARRAYREF [ , EXPORTNUMS_HASHREF [ , JOB ] ] ] 
 
 Adds this service definition to the database.  If there is an error, returns
 the error, otherwise returns false.
@@ -87,6 +89,8 @@ EXTRA_FIELDS_ARRAYREF also.
 If EXPORTNUMS_HASHREF is specified (keys are exportnums and values are
 boolean), the appopriate export_svc records will be inserted.
 
+TODOC: JOB
+
 =cut
 
 sub insert {
@@ -98,6 +102,8 @@ sub insert {
     my $exportnums = shift;
     @exportnums = grep $exportnums->{$_}, keys %$exportnums;
   }
+  my $job = '';
+  $job = shift if @_;
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
@@ -156,13 +162,14 @@ sub insert {
   }
 
   # add export_svc records
-
+  my $slice = 100/scalar(@exportnums) if @exportnums;
+  my $done = 0;
   foreach my $exportnum ( @exportnums ) {
     my $export_svc = new FS::export_svc ( {
       'exportnum' => $exportnum,
       'svcpart'   => $self->svcpart,
     } );
-    $error = $export_svc->insert;
+    $error = $export_svc->insert($job, $slice*$done++, $slice);
     if ( $error ) {
       $dbh->rollback if $oldAutoCommit;
       return $error;
@@ -185,7 +192,7 @@ sub delete {
 # check & make sure the svcpart isn't in cust_svc or pkg_svc (in any packages)?
 }
 
-=item replace OLD_RECORD [ '1.3-COMPAT' [ , EXTRA_FIELDS_ARRAYREF [ , EXPORTNUMS_HASHREF ] ] ]
+=item replace OLD_RECORD [ '1.3-COMPAT' [ , EXTRA_FIELDS_ARRAYREF [ , EXPORTNUMS_HASHREF [ , JOB ] ] ] ]
 
 Replaces OLD_RECORD with this one in the database.  If there is an error,
 returns the error, otherwise returns false.
@@ -194,10 +201,26 @@ TODOC: 1.3-COMPAT
 
 TODOC: EXTRA_FIELDS_ARRAYREF (same as insert method)
 
+TODOC: JOB
+
 =cut
 
 sub replace {
   my ( $new, $old ) = ( shift, shift );
+  my $compat = '';
+  my @fields = ();
+  my $exportnums;
+  my $job = '';
+  if ( @_ && $_[0] eq '1.3-COMPAT' ) {
+    shift;
+    $compat = '1.3';
+    @fields = @{shift(@_)} if @_;
+    $exportnums = @_ ? shift : '';
+    $job = shift if @_;
+  } else {
+    return 'non-1.3-COMPAT interface not yet written';
+    #not yet implemented
+  }
 
   return "Can't change svcdb for an existing service definition!"
     unless $old->svcdb eq $new->svcdb;
@@ -219,11 +242,7 @@ sub replace {
     return $error;
   }
 
-  if ( @_ && $_[0] eq '1.3-COMPAT' ) {
-    shift;
-    my @fields = ();
-    @fields = @{shift(@_)} if @_;
-    my $exportnums = @_ ? shift : '';
+  if ( $compat eq '1.3' ) {
 
    # maintain part_svc_column records
 
@@ -264,6 +283,7 @@ sub replace {
     if ( $exportnums ) {
 
       #false laziness w/ edit/process/agent_type.cgi
+      my @new_export_svc = ();
       foreach my $part_export ( qsearch('part_export', {}) ) {
         my $exportnum = $part_export->exportnum;
         my $hashref = {
@@ -279,14 +299,26 @@ sub replace {
             return $error;
           }
         } elsif ( ! $export_svc && $exportnums->{$exportnum} ) {
-          $export_svc = new FS::export_svc ( $hashref );
-          $error = $export_svc->insert;
+          push @new_export_svc, new FS::export_svc ( $hashref );
+        }
+
+      }
+
+      my $slice = 100/scalar(@new_export_svc) if @new_export_svc;
+      my $done = 0;
+      foreach my $export_svc (@new_export_svc) {
+        $error = $export_svc->insert($job, $slice*$done++, $slice);
+        if ( $error ) {
+          $dbh->rollback if $oldAutoCommit;
+          return $error;
+        }
+        if ( $job ) {
+          $error = $job->update_statustext( int( $slice * $done ) );
           if ( $error ) {
             $dbh->rollback if $oldAutoCommit;
             return $error;
           }
         }
-        
       }
 
     }
@@ -397,6 +429,70 @@ sub svc_x {
 
 =back
 
+=head1 SUBROUTINES
+
+=over 4
+
+=item process
+
+Experimental job-queue processor for web interface adds/edits
+
+=cut
+
+use Storable qw(thaw);
+use Data::Dumper;
+use MIME::Base64;
+sub process {
+  my $job = shift;
+
+  my $param = thaw(decode_base64(shift));
+  warn Dumper($param) if $DEBUG;
+
+  my $old = qsearchs('part_svc', { 'svcpart' => $param->{'svcpart'} }) 
+    if $param->{'svcpart'};
+
+  $param->{'svc_acct__usergroup'} =
+    ref($param->{'svc_acct__usergroup'})
+      ? join(',', @{$param->{'svc_acct__usergroup'}} )
+      : '';
+  
+  my $new = new FS::part_svc ( {
+    map {
+      $_ => $param->{$_};
+  #  } qw(svcpart svc svcdb)
+    } ( fields('part_svc'),
+        map { my $svcdb = $_;
+              my @fields = fields($svcdb);
+              push @fields, 'usergroup' if $svcdb eq 'svc_acct'; #kludge
+              map { ( $svcdb.'__'.$_, $svcdb.'__'.$_.'_flag' )  } @fields;
+            } grep defined( $FS::Record::dbdef->table($_) ),
+                   qw( svc_acct svc_domain svc_forward svc_www svc_broadband )
+      )
+  } );
+  
+  my %exportnums =
+    map { $_->exportnum => ( $param->{'exportnum'.$_->exportnum} || '') }
+        qsearch('part_export', {} );
+
+  my $error;
+  if ( $param->{'svcpart'} ) {
+    $error = $new->replace( $old,
+                            '1.3-COMPAT',
+                            [ 'usergroup' ],
+                            \%exportnums,
+                            $job
+                          );
+  } else {
+    $error = $new->insert( [ 'usergroup' ],
+                           \%exportnums,
+                           $job,
+                         );
+    $param->{'svcpart'} = $new->getfield('svcpart');
+  }
+
+  die $error if $error;
+}
+
 =head1 BUGS
 
 Delete is unimplemented.
index 1cc2152..f19ebf0 100644 (file)
@@ -2,8 +2,6 @@ package FS::rate;
 
 use strict;
 use vars qw( @ISA $DEBUG );
-use Storable qw(thaw);
-use Data::Dumper;
 use FS::Record qw( qsearch qsearchs dbh fields );
 use FS::rate_detail;
 
@@ -309,6 +307,8 @@ Experimental job-queue processor for web interface adds/edits
 
 =cut
 
+use Storable qw(thaw);
+use Data::Dumper;
 use MIME::Base64;
 sub process {
   my $job = shift;
index 157a2e8..35596e3 100644 (file)
@@ -1414,7 +1414,7 @@ sub radius_usergroup_selector {
 END
 
   foreach my $group ( @all_groups ) {
-    $html .= '<OPTION';
+    $html .= qq(<OPTION VALUE="$group");
     if ( $sel_groups{$group} ) {
       $html .= ' SELECTED';
       $sel_groups{$group} = 0;
@@ -1422,7 +1422,7 @@ END
     $html .= ">$group</OPTION>\n";
   }
   foreach my $group ( grep { $sel_groups{$_} } keys %sel_groups ) {
-    $html .= "<OPTION SELECTED>$group</OPTION>\n";
+    $html .= qq(<OPTION VALUE="$group" SELECTED>$group</OPTION>\n);
   };
   $html .= '</SELECT>';
 
index befd9b2..bc38c34 100755 (executable)
@@ -1,52 +1,7 @@
 <%
 my $part_svc;
 my $clone = '';
-my $error = '';
-if ( $cgi->param('magic') eq 'process' ) {
-
-  my $svcpart = $cgi->param('svcpart');
-  my $old = qsearchs('part_svc', { 'svcpart' => $svcpart }) if $svcpart;
-  
-  $cgi->param( 'svc_acct__usergroup',
-               join(',', $cgi->param('svc_acct__usergroup') ) );
-  
-  my $new = new FS::part_svc ( {
-    map {
-      $_, scalar($cgi->param($_));
-  #  } qw(svcpart svc svcdb)
-    } ( fields('part_svc'),
-        map { my $svcdb = $_;
-              my @fields = fields($svcdb);
-              push @fields, 'usergroup' if $svcdb eq 'svc_acct'; #kludge
-              map { ( $svcdb.'__'.$_, $svcdb.'__'.$_.'_flag' )  } @fields;
-            } grep defined( $FS::Record::dbdef->table($_) ),
-                   qw( svc_acct svc_domain svc_forward svc_www svc_broadband )
-      )
-  } );
-  
-  my %exportnums =
-    map { $_->exportnum => ( $cgi->param('exportnum'.$_->exportnum) || '') }
-        qsearch('part_export', {} );
-
-  if ( $svcpart ) {
-    $error = $new->replace($old, '1.3-COMPAT', [ 'usergroup' ], \%exportnums );
-  } else {
-    $error = $new->insert( [ 'usergroup' ], \%exportnums );
-    $svcpart = $new->getfield('svcpart');
-  }
-
-  unless ( $error ) { #no error, redirect
-    #print $cgi->redirect(popurl(3)."browse/part_svc.cgi");
-    print $cgi->redirect("${p}browse/part_svc.cgi");
-    myexit;
-  }
-
-  $part_svc = $new; #??
-  #$part_svc = new FS::part_svc ( {
-  #  map { $_, scalar($cgi->param($_)) } fields('part_svc')
-  #} );
-
-} elsif ( $cgi->param('clone') && $cgi->param('clone') =~ /^(\d+)$/ ) {#clone
+if ( $cgi->param('clone') && $cgi->param('clone') =~ /^(\d+)$/ ) {#clone
   #$cgi->param('clone') =~ /^(\d+)$/ or die "malformed query: $query";
   $part_svc = qsearchs('part_svc', { 'svcpart'=>$1 } )
     or die "unknown svcpart: $1";
@@ -76,17 +31,12 @@ my $hashref = $part_svc->hashref;
            )
 %>
 
-<% if ( $error ) { %>
-<FONT SIZE="+1" COLOR="#ff0000">Error: <%= $error %></FONT>
-<% } %>
-
 <FORM NAME="dummy">
 
       Service Part #<%= $part_svc->svcpart ? $part_svc->svcpart : "(NEW)" %>
 <BR><BR>
 Service  <INPUT TYPE="text" NAME="svc" VALUE="<%= $hashref->{svc} %>"><BR>
 Disable new orders <INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<%= $hashref->{disabled} eq 'Y' ? ' CHECKED' : '' %>><BR>
-<INPUT TYPE="hidden" NAME="magic" VALUE="process">
 <INPUT TYPE="hidden" NAME="svcpart" VALUE="<%= $hashref->{svcpart} %>">
 <BR>
 Services are items you offer to your customers.
@@ -213,10 +163,11 @@ my %defs = (
     'form_name'      => 'dummy',
     #'form_action'    => 'process/part_svc.cgi',
     'form_action'    => 'part_svc.cgi', #self
-    'form_text'      => [ qw( magic svc svcpart ) ],
+    'form_text'      => [ qw( svc svcpart ) ],
     'form_checkbox'  => [ 'disabled' ],
     'layer_callback' => sub {
       my $layer = shift;
+      
       my $html = qq!<INPUT TYPE="hidden" NAME="svcdb" VALUE="$layer">!;
 
       my $columns = 3;
@@ -250,12 +201,8 @@ my %defs = (
       $part_svc->svcpart($clone) if $clone; #haha, undone below
       foreach my $field (@fields) {
         my $part_svc_column = $part_svc->part_svc_column($field);
-        my $value = $error
-                      ? $cgi->param("${layer}__${field}")
-                      : $part_svc_column->columnvalue;
-        my $flag = $error
-                     ? $cgi->param("${layer}__${field}_flag")
-                     : $part_svc_column->columnflag;
+        my $value = $part_svc_column->columnvalue;
+        my $flag = $part_svc_column->columnflag;
         my $def = $defs{$layer}{$field};
         my $desc = ref($def) ? $def->{desc} : $def;
         
@@ -317,8 +264,20 @@ my %defs = (
       $part_svc->svcpart('') if $clone; #undone
       $html .= "</TABLE>";
 
-      $html .= '<BR><INPUT TYPE="submit" VALUE="'.
-               ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '">';
+      $html .= include('/elements/progress-init.html',
+                         $layer, #form name
+                         [ qw(svc svcpart disabled exportnum), @fields ],
+                         'process/part_svc.cgi',
+                         $p.'browse/part_svc.cgi',
+                         $layer,
+                      );
+      $html .= '<BR><INPUT NAME="submit" TYPE="button" VALUE="'.
+               ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '" '.
+               ' onClick="document.'. "$layer.submit.disabled=true; ".
+               "fixup(document.$layer); $layer". 'process();">';
+
+      #$html .= '<BR><INPUT TYPE="submit" VALUE="'.
+      #         ($hashref->{svcpart} ? 'Apply changes' : 'Add service'). '">';
 
       $html;
 
diff --git a/httemplate/edit/process/part_svc.cgi b/httemplate/edit/process/part_svc.cgi
new file mode 100755 (executable)
index 0000000..664e521
--- /dev/null
@@ -0,0 +1,4 @@
+<%
+my $server = new FS::UI::Web::JSRPC 'FS::part_svc::process';
+$server->process;
+%>
index 7edb831..41feaac 100644 (file)
@@ -1,44 +1,58 @@
-<% my( $formname, $fields, $action, $success_url ) = @_; %>
+<%
+  my( $formname, $fields, $action, $success_url, $key ) = @_;
+  $key = '' unless defined $key;
+%>
 
 <SCRIPT TYPE="text/javascript" SRC="../elements/jsrsClient.js"></SCRIPT>
 <SCRIPT TYPE="text/javascript" SRC="../elements/overlibmws.js"></SCRIPT>
 <SCRIPT TYPE="text/javascript">
 function OLiframeContent(src, width, height, name) {
   return ('<iframe src="'+src+'" width="'+width+'" height="'+height+'"'
-   +(name?' name="'+name+'" id="'+name+'"':'')+' scrolling="no">'
+   +(name?' name="'+name+'" id="'+name+'"':'')+' scrolling="auto">'
    +'<div>[iframe not supported]</div></iframe>');
 }
 
-function process () {
+function <%=$key%>process () {
 
-  document.OneTrueForm.submit.disabled=true;
+  document.<%=$formname%>.submit.disabled=true;
 
-  overlib( 'Submitting job to server...', WIDTH, 420, HEIGHT, 128, CAPTION, 'Please wait...', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', CLOSECLICK, MIDX, 0, MIDY, 0 );
+  overlib( 'Submitting job to server...', WIDTH, 432, HEIGHT, 136, CAPTION, 'Please wait...', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', CLOSECLICK, MIDX, 0, MIDY, 0 );
 
   var Hash = new Array();
   var x = 0;
   var fieldName;
-  for (var i = 0; i<document.OneTrueForm.elements.length; i++) {
-    fieldName = document.OneTrueForm.elements[i].name;
-//            (fieldName.indexOf('rate') > -1)
-//         || (fieldName.indexOf('min_') > -1) 
-//        || (fieldName.indexOf('sec_') > -1) 
-    if ( <%= join(' || ', map { "(fieldName.indexOf('$_') > -1)" } @$fields ) %>
+  for (var i = 0; i<document.<%=$formname%>.elements.length; i++) {
+    field  = document.<%=$formname%>.elements[i];
+    if ( <%= join(' || ', map { "(field.name.indexOf('$_') > -1)" } @$fields ) %>
        )
     {
-        Hash[x++] = fieldName;
-        Hash[x++] = document.OneTrueForm.elements[i].value;
+        if ( field.type == 'select-multiple' ) {
+          for (var j=0; j < field.options.length; j++) {
+            if ( field.options[j].selected ) {
+              Hash[x++] = field.name;
+              Hash[x++] = field.options[j].value;
+            }
+          }
+        } else if (    ( field.type != 'radio'  && field.type != 'checkbox' )
+                    || ( ( field.type == 'radio' || field.type == 'checkbox' )
+                         && document.<%=$formname%>.elements[i].checked
+                       )
+                  )
+        {
+          Hash[x++] = field.name;
+          Hash[x++] = field.value;
+        }
     }
   }
 
   jsrsPOST = true;
-  jsrsExecute( '<%= $action %>', myCallback, 'start_job', Hash );
+  jsrsExecute( '<%= $action %>', <%=$key%>myCallback, 'start_job', Hash );
 
 }
 
-function myCallback( jobnum ) {
+function <%=$key%>myCallback( jobnum ) {
 
-  overlib( OLiframeContent('<%=$p%>elements/progress-popup.html?jobnum=' + jobnum + ';url=<%=$success_url%>' , 420, 128, 'progress_popup'), CAPTION, 'Please wait...', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', CLOSECLICK, MIDX, 0, MIDY, 0 );
+  overlib( OLiframeContent('<%=$p%>elements/progress-popup.html?jobnum=' + jobnum + ';url=<%=$success_url%>;formname=<%=$formname%>' , 432, 136, 'progress_popup'), CAPTION, 'Please wait...', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', CLOSECLICK, MIDX, 0, MIDY, 0 );
 
 }
 
index 0881a96..d180c17 100644 (file)
@@ -1,6 +1,7 @@
 <%
-  my( $jobnum ) = $cgi->param('jobnum');
-  my( $url ) = $cgi->param('url');
+  my $jobnum = $cgi->param('jobnum');
+  my $url = $cgi->param('url');
+  my $formname = scalar($cgi->param('formname'));
 %>
 <HTML>
   <HEAD>
@@ -34,7 +35,7 @@ function updateStatus( status_statustext ) {
     document.getElementById("progress_bar").innerHTML = '';
     document.getElementById("progress_percent").innerHTML = '<INPUT TYPE="button" VALUE="OK" onClick="parent.nd(1);">';
     document.getElementById("progress_jobnum").innerHTML = '';
-    parent.document.OneTrueForm.submit.disabled=false;
+    parent.document.<%=$formname%>.submit.disabled=false;
   } else {
     alert('XXX unknown status returned from server: ' + status);
   }