From 1a033848671cad2cbe7687b37fc718b3b2a68b83 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 22 Apr 2006 00:58:40 +0000 Subject: [PATCH] start of package class web UI (add/edit package classes, package class selection in package def edit) --- FS/FS/part_pkg.pm | 34 ++ htetc/handler.pl | 1 + httemplate/browse/elements/browse.html | 6 + httemplate/browse/generic.cgi | 46 --- httemplate/{search => browse}/inventory_class.html | 2 +- httemplate/browse/part_pkg.cgi | 373 ++++++++++++--------- httemplate/browse/pkg_class.html | 26 ++ httemplate/browse/rate.cgi | 59 ++-- httemplate/edit/elements/edit.html | 6 +- httemplate/edit/inventory_class.html | 1 + httemplate/edit/part_pkg.cgi | 9 +- httemplate/edit/pkg_class.html | 10 + httemplate/edit/process/elements/process.html | 6 +- httemplate/edit/process/inventory_class.html | 3 +- httemplate/edit/process/pkg_class.html | 5 + httemplate/elements/select-agent.html | 32 +- httemplate/elements/select-pkg_class.html | 16 + httemplate/elements/select-table.html | 45 +++ httemplate/elements/tr-select-pkg_class.html | 29 ++ httemplate/index.html | 4 +- httemplate/search/cust_pkg.cgi | 8 +- httemplate/search/elements/search.html | 57 +++- 22 files changed, 505 insertions(+), 273 deletions(-) create mode 100644 httemplate/browse/elements/browse.html delete mode 100644 httemplate/browse/generic.cgi rename httemplate/{search => browse}/inventory_class.html (99%) create mode 100644 httemplate/browse/pkg_class.html create mode 100644 httemplate/edit/pkg_class.html create mode 100644 httemplate/edit/process/pkg_class.html create mode 100644 httemplate/elements/select-pkg_class.html create mode 100644 httemplate/elements/select-table.html create mode 100644 httemplate/elements/tr-select-pkg_class.html diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm index 30a97227e..05dc59913 100644 --- a/FS/FS/part_pkg.pm +++ b/FS/FS/part_pkg.pm @@ -12,6 +12,7 @@ use FS::cust_pkg; use FS::agent_type; use FS::type_pkgs; use FS::part_pkg_option; +use FS::pkg_class; @ISA = qw( FS::Record ); # FS::option_Common ); # this can use option_Common # when all the plandata bs is @@ -58,6 +59,8 @@ inherits from FS::Record. The following fields are currently supported: =item comment - Text name of this package definition (non-customer-viewable) +=item classnum - Optional package class (see L) + =item promo_code - Promotional code =item setup - Setup fee expression (deprecated) @@ -455,6 +458,37 @@ sub check { ''; } +=item pkg_class + +Returns the package class, as an FS::pkg_class object, or the empty string +if there is no package class. + +=cut + +sub pkg_class { + my $self = shift; + if ( $self->classnum ) { + qsearchs('pkg_class', { 'classnum' => $self->classnum } ); + } else { + return ''; + } +} + +=item classname + +Returns the package class name, or the empty string if there is no package +class. + +=cut + +sub classname { + my $self = shift; + my $pkg_class = $self->pkg_class; + $pkg_class + ? $pkg_class->classname + : ''; +} + =item pkg_svc Returns all FS::pkg_svc objects (see L) for this package diff --git a/htetc/handler.pl b/htetc/handler.pl index 008b0b5f9..dcbe72733 100644 --- a/htetc/handler.pl +++ b/htetc/handler.pl @@ -176,6 +176,7 @@ sub handler use FS::cdr; use FS::inventory_class; use FS::inventory_item; + use FS::pkg_class; if ( %%%RT_ENABLED%%% ) { eval ' diff --git a/httemplate/browse/elements/browse.html b/httemplate/browse/elements/browse.html new file mode 100644 index 000000000..6d146d356 --- /dev/null +++ b/httemplate/browse/elements/browse.html @@ -0,0 +1,6 @@ +<%= include( '/search/elements/search.html', + @_, + 'disable_download' => 1, + 'disable_nonefound' => 1, + ) +%> diff --git a/httemplate/browse/generic.cgi b/httemplate/browse/generic.cgi deleted file mode 100644 index 9ac0f2391..000000000 --- a/httemplate/browse/generic.cgi +++ /dev/null @@ -1,46 +0,0 @@ -<% - -use FS::Record qw(qsearch dbdef); -use DBIx::DBSchema; -use DBIx::DBSchema::Table; - -my $error; -my $p2 = popurl(2); -my ($table) = $cgi->keywords; -my $dbdef = dbdef or die "Cannot fetch dbdef!"; -my $dbdef_table = $dbdef->table($table) or die "Cannot fetch schema for $table"; - -my $pkey = $dbdef_table->primary_key or die "Cannot fetch pkey for $table"; -print header("Browse $table", menubar('Main Menu' => $p)); - -my @rec = qsearch($table, {}); -my @col = $dbdef_table->columns; - -if ($cgi->param('error')) { %> - Error: <%=$cgi->param('error')%> -

-<% } -%> -Add a new <%=$table%>

- -<%=table()%> - -<% foreach (grep { $_ ne $pkey } @col) { - %><%=$_%> - <% } %> - -<% foreach $rec (sort {$a->getfield($pkey) cmp $b->getfield($pkey) } @rec) { - %> - - - - <%=$rec->getfield($pkey)%> <% - foreach $col (grep { $_ ne $pkey } @col) { %> - <%=$rec->getfield($col)%> <% } %> - - -<% } %> - - - - diff --git a/httemplate/search/inventory_class.html b/httemplate/browse/inventory_class.html similarity index 99% rename from httemplate/search/inventory_class.html rename to httemplate/browse/inventory_class.html index 37735f3c9..6da3c9e3c 100644 --- a/httemplate/search/inventory_class.html +++ b/httemplate/browse/inventory_class.html @@ -21,7 +21,7 @@ my %inv_action_link = ( my $link = [ "${p}edit/inventory_class.html?", 'classnum' ]; -%><%= include( 'elements/search.html', +%><%= include( 'elements/browse.html', 'title' => 'Inventory Classes', 'name' => 'inventory classes', 'menubar' => [ 'Add a new inventory class' => diff --git a/httemplate/browse/part_pkg.cgi b/httemplate/browse/part_pkg.cgi index e6454639f..0afa54750 100755 --- a/httemplate/browse/part_pkg.cgi +++ b/httemplate/browse/part_pkg.cgi @@ -1,169 +1,236 @@ - <% -my %search; -if ( $cgi->param('showdisabled') ) { - %search = (); -} else { +my %search = (); +my $search = ''; +unless ( $cgi->param('showdisabled') ) { %search = ( 'disabled' => '' ); + $search = "( disabled = '' OR disabled IS NULL )"; } -my @part_pkg = qsearch('part_pkg', \%search ); -my $total = scalar(@part_pkg); - -my $sortby; -my %num_active_cust_pkg = (); -my( $suspended_sth, $canceled_sth ) = ( '', '' ); +my $select = '*'; +my $orderby = 'pkgpart'; if ( $cgi->param('active') ) { - my $active_sth = dbh->prepare( - 'SELECT COUNT(*) FROM cust_pkg WHERE pkgpart = ?'. - ' AND ( cancel IS NULL OR cancel = 0 )'. - ' AND ( susp IS NULL OR susp = 0 )' - ) or die dbh->errstr; - foreach my $part_pkg ( @part_pkg ) { - $active_sth->execute($part_pkg->pkgpart) or die $active_sth->errstr; - $num_active_cust_pkg{$part_pkg->pkgpart} = - $active_sth->fetchrow_arrayref->[0]; - } - $sortby = sub { - $num_active_cust_pkg{$b->pkgpart} <=> $num_active_cust_pkg{$a->pkgpart}; - }; - - $suspended_sth = dbh->prepare( - 'SELECT COUNT(*) FROM cust_pkg WHERE pkgpart = ?'. - ' AND ( cancel IS NULL OR cancel = 0 )'. - ' AND susp IS NOT NULL AND susp != 0' - ) or die dbh->errstr; - - $canceled_sth = dbh->prepare( - 'SELECT COUNT(*) FROM cust_pkg WHERE pkgpart = ?'. - ' AND cancel IS NOT NULL AND cancel != 0' - ) or die dbh->errstr; -} else { - $sortby = sub { $a->pkgpart <=> $b->pkgpart; }; + $orderby = 'num_active'; + + $select = " + + *, + + ( SELECT COUNT(*) FROM cust_pkg WHERE cust_pkg.pkgpart = part_pkg.pkgpart + AND ( cancel IS NULL OR cancel = 0 ) + AND ( susp IS NULL OR susp = 0 ) + ) AS num_active, + + ( SELECT COUNT(*) FROM cust_pkg WHERE cust_pkg.pkgpart = part_pkg.pkgpart + AND ( cancel IS NULL OR cancel = 0 ) + AND susp IS NOT NULL AND susp != 0 + ) AS num_suspended, + + ( SELECT COUNT(*) FROM cust_pkg WHERE cust_pkg.pkgpart = part_pkg.pkgpart + AND cancel IS NOT NULL AND cancel != 0 + ) AS num_cancelled + + "; + } my $conf = new FS::Conf; my $taxclasses = $conf->exists('enable_taxclasses'); -%> -<%= include("/elements/header.html","Package Definition Listing",menubar( 'Main Menu' => $p )) %> -<% unless ( $cgi->param('active') ) { %> - One or more service definitions are grouped together into a package - definition and given pricing information. Customers purchase packages - rather than purchase services directly.

- Add a new package definition -

-<% } %> - -<%= $total %> package definitions -<% if ( $cgi->param('showdisabled') ) { $cgi->param('showdisabled', 0); %> - ( hide disabled packages ) -<% } else { $cgi->param('showdisabled', 1); %> - ( show disabled packages ) -<% } %> - -<% my $colspan = $cgi->param('showdisabled') ? 2 : 3; %> - -<%= &table() %> - - >Package - Comment -<% if ( $cgi->param('active') ) { %> - Customer
packages
-<% } %> - Freq. -<% if ( $taxclasses ) { %> - Taxclass -<% } %> - Plan - Data - Service - Quan. -<% if ( dbdef->table('pkg_svc')->column('primary_svc') ) { %> - Primary -<% } %> - - +my $html_init; +unless ( $cgi->param('active') ) { + $html_init = qq! + One or more service definitions are grouped together into a package + definition and given pricing information. Customers purchase packages + rather than purchase services directly.

+ Add a new package definition +

+ !; +} -<% -foreach my $part_pkg ( sort $sortby @part_pkg ) { - my @pkg_svc = $part_pkg->pkg_svc; - my($rowspan)=scalar(@pkg_svc); - my $plandata; - if ( $part_pkg->plan ) { - $plandata = $part_pkg->plandata; - $plandata =~ s/^(\w+)=/$1 /mg; - $plandata =~ s/\n/
/g; - } else { - $part_pkg->plan('(legacy)'); - $plandata = "Setup ". $part_pkg->setup. - "
Recur ". $part_pkg->recur; - } -%> - - ><%= $part_pkg->pkgpart %> - -<% unless ( $cgi->param('showdisabled') ) { %> - > - <% if ( $part_pkg->disabled ) { %> - DISABLED - <% } %> - -<% } %> - - ><%= $part_pkg->pkg %> - ><%= $part_pkg->comment %> - -<% if ( $cgi->param('active') ) { %> - > - <%= $num_active_cust_pkg{$part_pkg->pkgpart} %> active
- - <% $suspended_sth->execute( $part_pkg->pkgpart ) - or die $suspended_sth->errstr; - my $num_suspended = $suspended_sth->fetchrow_arrayref->[0]; - %> - <%= $num_suspended %> suspended
- - <% $canceled_sth->execute( $part_pkg->pkgpart ) - or die $canceled_sth->errstr; - my $num_canceled = $canceled_sth->fetchrow_arrayref->[0]; - %> - <%= $num_canceled %> canceled - -<% } %> - - ><%= $part_pkg->freq_pretty %> - -<% if ( $taxclasses ) { %> - ><%= $part_pkg->taxclass || ' ' %> -<% } %> - - ><%= $part_pkg->plan %> - ><%= $plandata %> +my $posttotal; +if ( $cgi->param('showdisabled') ) { + $cgi->param('showdisabled', 0); + $posttotal = '( hide disabled packages )'; +} else { + $cgi->param('showdisabled', 1); + $posttotal = '( show disabled packages )'; +} -<% - my($n)=""; - foreach my $pkg_svc ( @pkg_svc ) { - my($svcpart)=$pkg_svc->getfield('svcpart'); - my($part_svc) = qsearchs('part_svc',{'svcpart'=> $svcpart }); - print $n,qq!!, - $part_svc->getfield('svc'),"", - $pkg_svc->getfield('quantity'),""; - if ( dbdef->table('pkg_svc')->column('primary_svc') ) { - print ''; - print 'PRIMARY' if $pkg_svc->primary_svc =~ /^Y/i; - print ''; - } - print "\n"; - $n=""; - } -%> +# ------ + +my $link = [ $p.'edit/part_pkg.cgi?', 'pkgpart' ]; + +my @header = ( '#', 'Package', 'Comment' ); +my @fields = ( 'pkgpart', 'pkg', 'comment' ); +my $align = 'rll'; +my @links = ( $link, $link, '' ); +my @style = ( '', '', '' ); + +unless ( $cgi->param('showdisabled') ) { #its been reversed already + push @header, 'Status'; + push @fields, sub { shift->disabled + ? 'DISABLED' + : 'Active' + }; + push @links, ''; + $align .= 'c'; + push @style, 'b'; +} + +unless ( 0 ) { #already showing only one class or something? + push @header, 'Class'; + push @fields, sub { shift->classname || '(none)'; }; + $align .= 'l'; +} + +if ( $cgi->param('active') ) { + push @header, 'Customer
packages'; + my %col = ( + 'active' => '00CC00', + 'suspended' => 'FF9900', + 'cancelled' => 'FF0000', + ); + my $cust_pkg_link = $p. 'search/cust_pkg.cgi?pkgpart='; + push @fields, sub { my $part_pkg = shift; + [ + map { + [ + { + 'data' => ''. + $part_pkg->get("num_$_"). + '', + 'align' => 'right', + }, + { + 'data' => $_, + 'align' => 'left', + 'link' => ( $part_pkg->get("num_$_") + ? $cust_pkg_link. + $part_pkg->pkgpart. + ";magic=$_" + : '' + ), + }, + ], + } (qw( active suspended cancelled )) + ]; }; + $align .= 'r'; +} - -<% } %> +push @header, 'Frequency'; +push @fields, sub { shift->freq_pretty; }; +$align .= 'l'; - - - +if ( $taxclasses ) { + push @header, 'Taxclass'; + push @fields, sub { shift->taxclass() || ' '; }; + $align .= 'l'; +} + +push @header, 'Plan', + 'Data', + 'Services'; + #'Service', 'Quan', 'Primary'; + +push @fields, sub { shift->plan || '(legacy)' }, + + sub { + my $part_pkg = shift; + if ( $part_pkg->plan ) { + + [ map { + /^(\w+)=(.*)$/; #or something; + [ + { 'data' => $1, + 'align' => 'right', + }, + { 'data' => $2, + 'align' => 'left', + }, + ]; + } + split(/\n/, $part_pkg->plandata) + ]; + + } else { + + [ map { [ + { 'data' => uc($_), + 'align' => 'right', + }, + { + 'data' => $part_pkg->$_(), + 'align' => 'left', + }, + ]; + } + (qw(setup recur)) + ]; + + } + + }, + + sub { + my $part_pkg = shift; + + [ map { + my $pkg_svc = $_; + my $part_svc = $pkg_svc->part_svc; + my $svc = $part_svc->svc; + if ( $pkg_svc->primary_svc =~ /^Y/i ) { + $svc = "$svc (PRIMARY)"; + } + $svc =~ s/ +/ /g; + + [ + { + 'data' => ''. $pkg_svc->quantity. '', + 'align' => 'right' + }, + { + 'data' => $svc, + 'align' => 'left', + 'link' => $p. 'edit/part_svc.cgi?'. + $part_svc->svcpart, + }, + ]; + } + sort { $b->primary_svc =~ /^Y/i + <=> $a->primary_svc =~ /^Y/i + } + $part_pkg->pkg_svc + + ]; + + }; + +$align .= 'lrl'; #rr'; + +# -------- + +my $count_query = 'SELECT COUNT(*) FROM part_pkg'; +$count_query .= " WHERE $search" + if $search; + +%><%= include( 'elements/browse.html', + 'title' => 'Package Definitions', + 'menubar' => [ 'Main Menu' => $p ], + 'html_init' => $html_init, + 'html_posttotal' => $posttotal, + 'name' => 'package definitions', + 'query' => { 'select' => $select, + 'table' => 'part_pkg', + 'hashref' => \%search, + 'extra_sql' => "ORDER BY $orderby", + }, + 'count_query' => $count_query, + 'header' => \@header, + 'fields' => \@fields, + 'links' => \@links, + 'align' => $align, + 'style' => \@style, + ) +%> diff --git a/httemplate/browse/pkg_class.html b/httemplate/browse/pkg_class.html new file mode 100644 index 000000000..d4f8f02a9 --- /dev/null +++ b/httemplate/browse/pkg_class.html @@ -0,0 +1,26 @@ +<% + +my $html_init = + 'Package classes define groups of packages, for reporting and '. + 'convenience purposes.

'. + qq!Add a package class

!; + +my $count_query = 'SELECT COUNT(*) FROM pkg_class'; + +my $link = [ $p.'edit/pkg_class.html?', 'classnum' ]; + +%><%= include( 'elements/browse.html', + 'title' => 'Package classes', + 'menubar' => [ 'Main menu' => $p, ], + 'html_init' => $html_init, + 'name' => 'package classes', + 'query' => { 'table' => 'pkg_class', + 'hashref' => {}, + 'extra_sql' => 'ORDER BY classnum', + }, + 'count_query' => $count_query, + 'header' => [ '#', 'Class', ], + 'fields' => [ 'classnum', 'classname' ], + 'links' => [ $link, $link ], + ) +%> diff --git a/httemplate/browse/rate.cgi b/httemplate/browse/rate.cgi index 4718b7147..c4ae2f081 100644 --- a/httemplate/browse/rate.cgi +++ b/httemplate/browse/rate.cgi @@ -1,34 +1,33 @@ - -<%= include("/elements/header.html","Rate plan listing", menubar( 'Main Menu' => "$p#sysadmin" )) %> -Rate plans, regions and prefixes for VoIP and call billing.

-Add a rate plan -| Add a region -

- +<% -<%= table() %> - - Rate plan - +my $html_init = + 'Rate plans, regions and prefixes for VoIP and call billing.

'. + qq!Add a rate plan!. + qq! | Add a region!. + '

+ '; -<% foreach my $rate ( sort { - $a->getfield('ratenum') <=> $b->getfield('ratenum') - } qsearch('rate',{}) ) { -%> - - <%= $rate->ratenum %> - <%= $rate->ratename %> - - -<% } %> +my $count_query = 'SELECT COUNT(*) FROM rate'; - - - +my $link = [ $p.'edit/rate.cgi?', 'ratenum' ]; - +%><%= include( 'elements/browse.html', + 'title' => 'Rate plans', + 'menubar' => [ 'Main menu' => $p, ], + 'html_init' => $html_init, + 'name' => 'rate plans', + 'query' => { 'table' => 'rate', + 'hashref' => {}, + 'extra_sql' => 'ORDER BY ratenum', + }, + 'count_query' => $count_query, + 'header' => [ '#', 'Rate plan', ], + 'fields' => [ 'ratenum', 'ratename' ], + 'links' => [ $link, $link ], + ) +%> diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html index ce6e2dbb1..5486b4b00 100644 --- a/httemplate/edit/elements/edit.html +++ b/httemplate/edit/elements/edit.html @@ -15,6 +15,8 @@ # ] # # 'menubar' => '', #menubar arrayref + # + # 'viewall_dir' => '', #'search' or 'browse', defaults to 'search' my(%opt) = @_; @@ -55,7 +57,9 @@ } else { @menubar = ( 'Main menu' => $p, #eventually get rid of this when the ACL/UI update is done - "View all $opt{'name'}s" => "${p}search/$table.html", #eventually use Lingua::bs to pluralize + #eventually use Lingua::bs to pluralize + "View all $opt{'name'}s" => $p. ( $opt{'viewall_dir'} || 'search' ). + "/$table.html", ); } diff --git a/httemplate/edit/inventory_class.html b/httemplate/edit/inventory_class.html index 5dde2e595..8c5ae4770 100644 --- a/httemplate/edit/inventory_class.html +++ b/httemplate/edit/inventory_class.html @@ -5,5 +5,6 @@ 'classnum' => 'Class number', 'classname' => 'Class name', }, + 'viewall_dir' => 'browse', ) %> diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index 158c6e2ff..462d5161f 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -84,6 +84,7 @@ Package information + <%= include( '/elements/tr-select-pkg_class.html', $part_pkg->classnum ) %> Promotional code @@ -146,8 +147,8 @@ $thead .= 'Service'; %> -<%= itable('', 4, 1) %>

Services included +<%= itable('', 4, 1) %> <%= $thead %> <% @@ -194,14 +195,14 @@ foreach my $part_svc ( @part_svc ) { - <% $count++; - foreach ( 1 .. $columns-1 ) { + <% foreach ( 1 .. $columns-1 ) { if ( $count == int( $_ * scalar(@part_svc) / $columns ) ) { %> <%= $thead %> <% } } + $count++; %> <% } %> @@ -224,7 +225,7 @@ my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } tie my %options, 'Tie::IxHash', map { $_=>$plans{$_}->{'name'} } keys %plans; -my @form_select = (); +my @form_select = ('classnum'); if ( $conf->exists('enable_taxclasses') ) { push @form_select, 'taxclass'; } else { diff --git a/httemplate/edit/pkg_class.html b/httemplate/edit/pkg_class.html new file mode 100644 index 000000000..b077f6fa9 --- /dev/null +++ b/httemplate/edit/pkg_class.html @@ -0,0 +1,10 @@ +<%= include( 'elements/edit.html', + 'name' => 'Package Class', + 'table' => 'pkg_class', + 'labels' => { + 'classnum' => 'Class number', + 'classname' => 'Class name', + }, + 'viewall_dir' => 'browse', + ) +%> diff --git a/httemplate/edit/process/elements/process.html b/httemplate/edit/process/elements/process.html index 52c876720..83ff6f728 100644 --- a/httemplate/edit/process/elements/process.html +++ b/httemplate/edit/process/elements/process.html @@ -5,6 +5,7 @@ # 'table' => # #? 'primary_key' => #required when the dbdef doesn't know...??? # #? 'fields' => [] + # 'viewall_dir' => '', #'search' or 'browse', defaults to 'search' my(%opt) = @_; @@ -40,7 +41,10 @@ $cgi->param('error', $error); print $cgi->redirect(popurl(2). "$table.html?". $cgi->query_string ); } else { - print $cgi->redirect(popurl(3). "search/$table.html"); + print $cgi->redirect( popurl(3). + ( $opt{'viewall_dir'} || 'search' ). + "/$table.html" + ); } %> diff --git a/httemplate/edit/process/inventory_class.html b/httemplate/edit/process/inventory_class.html index e30e74e7b..ab9efef48 100644 --- a/httemplate/edit/process/inventory_class.html +++ b/httemplate/edit/process/inventory_class.html @@ -1,4 +1,5 @@ <%= include( 'elements/process.html', - 'table' => 'inventory_class', + 'table' => 'inventory_class', + 'viewall_dir' => 'browse', ) %> diff --git a/httemplate/edit/process/pkg_class.html b/httemplate/edit/process/pkg_class.html new file mode 100644 index 000000000..48e2b8009 --- /dev/null +++ b/httemplate/edit/process/pkg_class.html @@ -0,0 +1,5 @@ +<%= include( 'elements/process.html', + 'table' => 'pkg_class', + 'viewall_dir' => 'browse', + ) +%> diff --git a/httemplate/elements/select-agent.html b/httemplate/elements/select-agent.html index c2a5e4bde..aa480a54b 100644 --- a/httemplate/elements/select-agent.html +++ b/httemplate/elements/select-agent.html @@ -1,24 +1,16 @@ <% my( $agentnum, %opt ) = @_; - my @agents; - if ( $opt{'agents'} ) { - @agents = @{ $opt{'agents'} }; - } else { - @agents = qsearch( 'agent', { disabled=>'' } ); - } - + my %select_opt = (); + $select_opt{'records'} = $opt{'agents'} + if $opt{'agents'}; + +%><%= include( '/elements/select-table.html', + 'table' => 'agent', + 'name_col' => 'agent', + 'value' => $agentnum, + 'empty_label' => 'all', + 'hashref' => { 'disabled' => '' }, + %select_opt, + ) %> - - - diff --git a/httemplate/elements/select-pkg_class.html b/httemplate/elements/select-pkg_class.html new file mode 100644 index 000000000..5486e0877 --- /dev/null +++ b/httemplate/elements/select-pkg_class.html @@ -0,0 +1,16 @@ +<% + my( $classnum, %opt ) = @_; + + my %select_opt = (); + $select_opt{'records'} = $opt{'pkg_class'} + if $opt{'pkg_class'}; + +%><%= include( '/elements/select-table.html', + 'table' => 'pkg_class', + 'name_col' => 'classname', + 'value' => $classnum, + 'empty_label' => '(none)', + #'hashref' => { 'disabled' => '' }, + #%select_opt, + ) +%> diff --git a/httemplate/elements/select-table.html b/httemplate/elements/select-table.html new file mode 100644 index 000000000..10cc8b995 --- /dev/null +++ b/httemplate/elements/select-table.html @@ -0,0 +1,45 @@ +<% + + ##required + # 'table' => 'table_name', + # 'name_col' => 'name_column', + # + ##strongly recommended (you want your forms to be "sticky" on errors, right?) + # 'value' => 'current_value', + # + ##opt + # 'empty_label' => '', #better specify it though, the default might change + # 'hashref' => {}, + # 'records' => \@records, #instead of hashref + + my( %opt ) = @_; + + my $key = dbdef->table($opt{'table'})->primary_key; #? $opt{'primary_key'} || + + my $name_col = $opt{'name_col'}; + + my @records = (); + if ( $opt{'records'} ) { + @records = @{ $opt{'records'} }; + } else { + @records = qsearch( $opt{'table'}, ( $opt{'hashref'} || {} ) ); + } + +%> + + + diff --git a/httemplate/elements/tr-select-pkg_class.html b/httemplate/elements/tr-select-pkg_class.html new file mode 100644 index 000000000..de10885c8 --- /dev/null +++ b/httemplate/elements/tr-select-pkg_class.html @@ -0,0 +1,29 @@ +<% + my( $classnum, %opt ) = @_; + + my @pkg_class; + if ( $opt{'pkg_class'} ) { + @pkg_class = @{ $opt{'pkg_class'} }; + } else { + @pkg_class = qsearch( 'pkg_class', {} ); # { disabled=>'' } ); + } + +%> + +<% if ( scalar(@pkg_class) == 0 ) { %> + + + +<% } else { %> + + + <%= $opt{'label'} || 'Package class' %> + + <%= include( '/elements/select-pkg_class.html', $classnum, + 'pkg_class' => \@pkg_class, + ) + %> + + + +<% } %> diff --git a/httemplate/index.html b/httemplate/index.html index a1c3caf39..6cd667d8a 100644 --- a/httemplate/index.html +++ b/httemplate/index.html @@ -186,7 +186,7 @@ - One or more services are grouped together into a package and given pricing information. Customers purchase packages, not services. -
  • View/Edit package classes +
  • View/Edit package classes - Package classes define groups of packages, for reporting and convenience purposes. @@ -234,6 +234,8 @@ - Locally defined fields
  • View/Edit message catalog - Change error messages and other customizable labels. +
  • View/Edit inventory classes and inventory + - Setup inventory classes and stock inventory.
    diff --git a/httemplate/search/cust_pkg.cgi b/httemplate/search/cust_pkg.cgi index 5da4d82fb..a2fb89c12 100755 --- a/httemplate/search/cust_pkg.cgi +++ b/httemplate/search/cust_pkg.cgi @@ -19,8 +19,10 @@ if ( $cgi->param('magic') && $cgi->param('magic') eq 'bill' ) { my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi); push @where, - "bill >= $beginning ", - "bill <= $ending", + #"bill >= $beginning ", + #"bill <= $ending", + "CASE WHEN bill IS NULL THEN 0 ELSE bill END >= $beginning ", + "CASE WHEN bill IS NULL THEN 0 ELSE bill END <= $ending", '( cancel IS NULL OR cancel = 0 )'; } else { @@ -141,7 +143,7 @@ sub time_or_blank { 'name' => 'packages', 'query' => $sql_query, 'count_query' => $count_query, - 'redirect' => $link, + #'redirect' => $link, 'header' => [ '#', 'Package', 'Status', diff --git a/httemplate/search/elements/search.html b/httemplate/search/elements/search.html index 7f7243588..6cf574164 100644 --- a/httemplate/search/elements/search.html +++ b/httemplate/search/elements/search.html @@ -8,8 +8,12 @@ # 'name' => 'items', #name for the records returned # # # some HTML callbacks... - # 'menubar' => '', #menubar arrayref - # 'html_init' => '', #after the header/menubar and before the pager + # 'menubar' => '', #menubar arrayref + # 'html_init' => '', #after the header/menubar and before the pager + # 'html_foot' => '', #at the bottom + # 'html_posttotal' => '', #at the bottom + # # (these three can be strings or coderefs) + # # # #literal SQL query string or qsearch hashref, required # 'query' => { @@ -39,6 +43,10 @@ # # (if not specified the database column names will be used) # 'header' => [ '#', 'Item' ], # + # 'disable_download' => '', # set true to hide the CSV/Excel download links + # 'disable_nonefound' => '', # set true to disable the "No matching Xs found" + # # message + # # #listref - each item is a literal column name (or method) or coderef # #if not specified all columns will be shown # 'fields' => [ @@ -286,7 +294,13 @@ include( '/elements/menubar.html', @menubar ) ) %> - <%= defined($opt{'html_init'}) ? $opt{'html_init'} : '' %> + <%= defined($opt{'html_init'}) + ? ( ref($opt{'html_init'}) + ? &{$opt{'html_init'}}() + : $opt{'html_init'} + ) + : '' + %> <% my $pager = include ( '/elements/pager.html', 'offset' => $offset, 'num_rows' => scalar(@$rows), @@ -295,26 +309,38 @@ ); %> <% unless ( $total ) { %> - No matching <%= $opt{'name'} %> found.
    + <% unless ( $opt{'disable_nonefound'} ) { %> + No matching <%= $opt{'name'} %> found.
    + <% } %> <% } else { %> - + <% unless ( $opt{'disable_download'} ) { %> + + <% } %>
    - <%= $total %> total <%= $opt{'name'} %>
    + <%= $total %> total <%= $opt{'name'} %> + <%= defined($opt{'html_posttotal'}) + ? ( ref($opt{'html_posttotal'}) + ? &{$opt{'html_posttotal'}}() + : $opt{'html_posttotal'} + ) + : '' + %> +
    <% if ( $opt{'count_addl'} ) { %> <% my $n=0; foreach my $count ( @{$opt{'count_addl'}} ) { %> <%= sprintf( $count, $count_arrayref->[++$n] ) %>
    <% } %> <% } %>
    - <% $cgi->param('_type', "$xlsname.xls" ); %> - Download full results
    - as Excel spreadsheet
    - <% $cgi->param('_type', 'csv'); %> - as CSV file -
    + <% $cgi->param('_type', "$xlsname.xls" ); %> + Download full results
    + as Excel spreadsheet
    + <% $cgi->param('_type', 'csv'); %> + as CSV file +
    @@ -471,6 +497,13 @@
    <% } %> + <%= defined($opt{'html_foot'}) + ? ( ref($opt{'html_foot'}) + ? &{$opt{'html_foot'}}() + : $opt{'html_foot'} + ) + : '' + %> <%= include( '/elements/footer.html' ) %> <% } %> <% } %> -- 2.11.0