package selector, split by package class, RT#5077
authorivan <ivan>
Sat, 28 Mar 2009 22:59:36 +0000 (22:59 +0000)
committerivan <ivan>
Sat, 28 Mar 2009 22:59:36 +0000 (22:59 +0000)
FS/FS/Conf.pm
FS/FS/part_pkg.pm
httemplate/elements/select-cust-part_pkg.html
httemplate/elements/select-cust-pkg_class.html [new file with mode: 0644]
httemplate/elements/select-part_pkg.html
httemplate/elements/select-table.html
httemplate/elements/tr-select-cust-part_pkg.html [new file with mode: 0644]
httemplate/elements/tr-selectmultiple-part_pkg.html
httemplate/misc/change_pkg.cgi
httemplate/misc/cust-part_pkg.cgi [new file with mode: 0644]
httemplate/misc/order_pkg.html

index f765fc7..b6fea54 100644 (file)
@@ -2712,6 +2712,13 @@ worry that config_items is freeside-specific and icky.
     'type'        => 'checkbox',
   },
 
+  {
+    'key'         => 'disable-cust-pkg_class',
+    'section'     => 'UI',
+    'description' => 'Disable the two-step dropdown for selecting package class and package, and return to the classic single dropdown.',
+    'type'        => 'checkbox',
+  },
+
 );
 
 1;
index 81696fc..8cf7d0c 100644 (file)
@@ -1236,9 +1236,31 @@ L<FS::type_pkgs>).
 =cut
 
 sub curuser_pkgs_sql {
-  #my($class) = shift;
+  my $class = shift;
+
+  $class->_pkgs_sql( $FS::CurrentUser::CurrentUser->agentnums );
+
+}
+
+=item agent_pkgs_sql AGENT | AGENTNUM, ...
+
+Returns an SQL fragment for searching for packages the provided agent or agents
+can use, either via part_pkg.agentnum directly, or via agent type (see
+L<FS::type_pkgs>).
+
+=cut
+
+sub agent_pkgs_sql {
+  my $class = shift;  #i'm a class method, not a sub (the question is... why??)
+  my @agentnums = map { ref($_) ? $_->agentnum : $_ } @_;
+
+  $class->_pkgs_sql(@agentnums); #is this why
+
+}
 
-  my $agentnums = join(',', $FS::CurrentUser::CurrentUser->agentnums);
+sub _pkgs_sql {
+  my( $class, @agentnums ) = @_;
+  my $agentnums = join(',', @agentnums);
 
   "
     (
index 2926629..7f91e81 100644 (file)
@@ -31,11 +31,11 @@ my( %opt ) = @_;
 my $cust_main = $opt{'cust_main'}
   or die "cust_main not specified";
 
-$opt{'extra_sql'} .=
-  ' AND ( agentnum IS NOT NULL '.
-  '         OR 0 < ( SELECT COUNT(*) FROM type_pkgs '.
-  '                    WHERE typenum = '. $cust_main->agent->typenum.
-  '                      AND type_pkgs.pkgpart = part_pkg.pkgpart )'.
-  '     )';
+$opt{'extra_sql'} .= ' AND '. FS::part_pkg->agent_pkgs_sql( $cust_main->agent );
+#  ' AND ( agentnum IS NOT NULL '.
+#  '         OR 0 < ( SELECT COUNT(*) FROM type_pkgs '.
+#  '                    WHERE typenum = '. $cust_main->agent->typenum.
+#  '                      AND type_pkgs.pkgpart = part_pkg.pkgpart )'.
+#  '     )';
 
 </%init>
diff --git a/httemplate/elements/select-cust-pkg_class.html b/httemplate/elements/select-cust-pkg_class.html
new file mode 100644 (file)
index 0000000..5c19efa
--- /dev/null
@@ -0,0 +1,12 @@
+<% include( '/elements/select-pkg_class.html',
+              'pre_options'   => [ '-1' => 'all' ], #XXX a config ?
+              #'pre_options'   => [ '-2' => 'Select package class' ],
+              'disable_empty' => 1,
+              %opt,
+          )
+%>
+<%init>
+
+my %opt = @_;
+
+</%init>
index 52b1cca..6b697ab 100644 (file)
@@ -22,17 +22,27 @@ Example:
               'name_col'       => 'pkg',
               'empty_label'    => 'Select package', #should this be the default?
               'label_callback' => sub { shift->pkg_comment },
-              'hashref'        => { 'disabled' => '' },
+              'hashref'        => \%hash,
               %opt,
           )
 %>
 <%init>
-
 my( %opt ) = @_;
 
 $opt{'records'} = delete $opt{'part_pkg'}
   if $opt{'part_pkg'};
 
+my %hash = ( 'disabled' => '' );
+
+if ( exists($opt{'classnum'}) && defined($opt{'classnum'}) ) {
+  if ( $opt{'classnum'} > 0 ) {
+    $hash{'classnum'} = $opt{'classnum'};
+  } elsif ( $opt{'classnum'} eq '' || $opt{'classnum'} == 0 ) {
+    $hash{'classnum'} = '';
+  } #else -1 or not specified, all classes, so don't set classnum
+}
+
 $opt{'extra_sql'} .= ' AND '. FS::part_pkg->curuser_pkgs_sql;
 
 </%init>
index 4efbcba..e7baaf5 100644 (file)
@@ -139,7 +139,7 @@ if ( $opt{'records'} ) {
   });
 }
 
-unless (    ! $value
+unless (    $value < 1 # !$value #ignore negatives too
          or ref($value)
          or ! exists( $opt{hashref}->{disabled} ) #??
          or grep { $value == $_->$key() } @records
diff --git a/httemplate/elements/tr-select-cust-part_pkg.html b/httemplate/elements/tr-select-cust-part_pkg.html
new file mode 100644 (file)
index 0000000..75f1f6f
--- /dev/null
@@ -0,0 +1,107 @@
+%if ( scalar(@pkg_class) > 1 && ! $conf->exists('disable-cust-pkg_class') ) {
+
+  <% include('/elements/xmlhttp.html',
+                'url'  => $p.'misc/cust-part_pkg.cgi',
+                'subs' => [ 'get_part_pkg' ],
+            )
+  %>
+
+  <SCRIPT TYPE="text/javascript">
+
+    function opt(what,value,text) {
+      var optionName = new Option(text, value, false, false);
+      var length = what.length;
+      what.options[length] = optionName;
+    }
+
+    function classnum_changed(what) {
+
+      what.form.pkgpart.disabled = 'disabled'; //disable part_pkg dropdown
+      what.form.submit.disabled = true; //disable the submit button
+
+      classnum = what.options[what.selectedIndex].value;
+
+      function update_part_pkg(part_pkg) {
+
+        // blank the current packages
+        for ( var i = what.form.pkgpart.length; i>= 0; i-- )
+          what.form.pkgpart.options[i] = null;
+
+        // add the new packages
+        opt(what.form.pkgpart, '', 'Select package');
+        var packagesArray = eval('(' + part_pkg + ')' );
+        for ( var s = 0; s < packagesArray.length; s=s+2 ) {
+          var packagesLabel = packagesArray[s+1];
+          opt(what.form.pkgpart, packagesArray[s], packagesLabel);
+        }
+
+        what.form.pkgpart.disabled = ''; //re-enable part_pkg dropdown
+
+      }
+
+      get_part_pkg( <% $cust_main->custnum %>, classnum, update_part_pkg );
+    
+    }
+
+  </SCRIPT>
+
+  <TR>
+    <TH ALIGN="right">Package Class</TH>
+    <TD COLSPAN=7>
+      <% include('/elements/select-cust-pkg_class.html',
+                   'curr_value' => $opt{'classnum'},
+                   'pkg_class'  => \@pkg_class,
+                   'onchange'   => 'classnum_changed',
+                )
+      %>
+    </TD>
+  </TR>
+
+%}
+
+<TR>
+  <TH ALIGN="right">Package</TH>
+  <TD COLSPAN=7>
+    <% include('/elements/select-cust-part_pkg.html',
+                 'curr_value' => $opt{'curr_value'}, #$pkgpart
+                 'classnum'   => $opt{'classnum'},
+                 'cust_main'  => $opt{'cust_main'},  #$cust_main
+                 'onchange'   => 'enable_order_pkg',
+              )
+    %>
+  </TD>
+</TR>
+
+<%init>
+
+my $conf = new FS::Conf;
+
+my %opt = @_;
+
+my $pre_label = $opt{'pre_label'} || '';
+$pre_label .= ' ' if length($pre_label) && $pre_label =~ /\S$/;
+
+my $cust_main = $opt{'cust_main'}
+  or die "cust_main not specified";
+
+#my @pkg_class = sort { $a->classname cmp $b->classname }
+#                     qsearch( 'pkg_class', { 'disabled' => '' } );
+
+#"normal" part_pkg agent virtualization (agentnum or type)
+my @part_pkg = qsearch({
+  'select'    => 'DISTINCT classnum',
+  'table'     => 'part_pkg',
+  'hashref'   => { 'disabled' => '' },
+  'extra_sql' =>
+    ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql( 'null'=>1 ).
+    ' AND '. FS::part_pkg->agent_pkgs_sql( $opt{'cust_main'}->agent ),
+});
+
+my @pkg_class =
+  sort { $a->classname cmp $b->classname } #should get a sort order in config
+  map  { $_->pkg_class || new FS::pkg_class { 'classnum'  => '',
+                                              'classname' => '(none)' }
+       }
+  @part_pkg;
+
+</%init>
index 455038d..d959a5b 100644 (file)
@@ -2,11 +2,10 @@
   <TD ALIGN="right"><% $opt{'label'} || 'Packages' %></TD>
   <TD>
     <% include( '/elements/select-table.html',
-                  'table'     => 'part_pkg',
-                 'name_col'  => 'pkg',
-                 'value'     => '',
-                 'empty_label' => '(none)',
-                 'element_etc' => 'multiple',
+                  'table'         => 'part_pkg',
+                 'name_col'      => 'pkg',
+                 'disable_empty' => 1,
+                 'element_etc'   => 'multiple',
                  %opt,
               )
     %>
index c4dfca2..16b7071 100755 (executable)
       <% $curuser->option('show_pkgnum') ? $cust_pkg->pkgnum.': ' : '' %><B><% $part_pkg->pkg |h %></B> - <% $part_pkg->comment |h %>
     </TD>
   </TR>
-  
-  <TR>
-    <TH ALIGN="right">New package</TH>
-    <TD COLSPAN=7>
-      <% include('/elements/select-cust-part_pkg.html',
-                   'cust_main'    => $cust_main,
-                   'element_name' => 'pkgpart',
-                   #'extra_sql'    => ' AND pkgpart != '. $cust_pkg->pkgpart,
-                   'curr_value'   => scalar($cgi->param('pkgpart')),
-                )
-      %>
-    </TD>
-  </TR>
+
+  <% include('/elements/tr-select-cust-part_pkg.html',
+               'pre_label'  => 'New',
+               'curr_value' => scalar($cgi->param('pkgpart')),
+               'classnum'   => $part_pkg->classnum,
+               'cust_main'  => $cust_main,
+               #'extra_sql'    => ' AND pkgpart != '. $cust_pkg->pkgpart,
+            )
+  %>
 
   <% include('/elements/tr-select-cust_location.html',
                'cgi'       => $cgi,
diff --git a/httemplate/misc/cust-part_pkg.cgi b/httemplate/misc/cust-part_pkg.cgi
new file mode 100644 (file)
index 0000000..a249f03
--- /dev/null
@@ -0,0 +1,29 @@
+<% objToJson( \@return ) %>
+<%init>
+
+my( $custnum, $classnum ) = $cgi->param('arg');
+
+#XXX i guess i should be agent-virtualized.  cause "packages a customer can
+#order" is such a huge deal
+my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } );
+
+my %hash = ( 'disabled' => '' );
+if ( $classnum > 0 ) {
+  $hash{'classnum'} = $classnum;
+} elsif ( $classnum eq '' || $classnum == 0 ) {
+  $hash{'classnum'} = '';
+} #else -1, all classes, so don't set classnum
+
+my @part_pkg = qsearch({
+  'table'     => 'part_pkg',
+  'hashref'   => \%hash,
+  'extra_sql' =>
+    ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql( 'null'=>1 ).
+    ' AND '. FS::part_pkg->agent_pkgs_sql( $cust_main->agent ),
+});
+
+my @return = map  { $_->pkgpart => $_->pkg_comment }
+             sort { $a->pkg_comment cmp $b->pkg_comment }
+             @part_pkg;
+
+</%init>
index 2c83351..9caa57a 100644 (file)
 <INPUT TYPE="hidden" NAME="custnum" VALUE="<% $cust_main->custnum %>">
 
 <% ntable("#cccccc", 2) %>
-<TR>
-  <TH ALIGN="right">Package</TH>
-  <TD COLSPAN=7>
-    <% include('/elements/select-cust-part_pkg.html',
-                 'curr_value' => $pkgpart,
-                 'cust_main'  => $cust_main,
-                 'onchange'   => 'enable_order_pkg',
-              )
-    %>
-  </TD>
-</TR>
+<% include('/elements/tr-select-cust-part_pkg.html',
+             'curr_value' => $pkgpart,
+             'classnum'   => -1,
+             'cust_main'  => $cust_main,
+             'onchange'   => 'enable_order_pkg',
+          )
+%>
 
 % if ( $conf->exists('pkg_referral') ) {
   <% include('/elements/tr-select-part_referral.html',