From: Mitch Jackson Date: Tue, 27 Nov 2018 20:39:01 +0000 (-0500) Subject: RT# 32243 Package Bulk Edit UI Update X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=28051580bf12b079a4631647a5c0defc7f55c9dc RT# 32243 Package Bulk Edit UI Update --- diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index f29ab9fc0..d39dbbbcd 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -5614,6 +5614,8 @@ sub _X_show_zero { =item order CUSTNUM, PKGPARTS_ARYREF, [ REMOVE_PKGNUMS_ARYREF [ RETURN_CUST_PKG_ARRAYREF [ REFNUM ] ] ] +=item order \%PARAMS + Bulk cancel + order subroutine. Perhaps slightly deprecated, only used by the bulk cancel+order in the web UI and nowhere else (edit/process/cust_pkg.cgi) @@ -5638,10 +5640,25 @@ setting I to an array reference of refnums or a hash reference with refnums as keys. If no I is defined, a default FS::pkg_referral record will be created corresponding to cust_main.refnum. +LOCATIONNUM, if specified, will be set on newly created cust_pkg records + =cut sub order { - my ($custnum, $pkgparts, $remove_pkgnum, $return_cust_pkg, $refnum) = @_; + my ($custnum, $pkgparts, $remove_pkgnum, $return_cust_pkg, $refnum, + $locationnum); + + if ( ref $_[0] ) { + my $args = $_[0]; + $custnum = $args->{custnum}; + $pkgparts = $args->{pkgparts}; + $remove_pkgnum = $args->{remove_pkgnum}; + $return_cust_pkg = $args->{return_cust_pkg}; + $refnum = $args->{refnum}; + $locationnum = $args->{locationnum}; + } else { + ($custnum, $pkgparts, $remove_pkgnum, $return_cust_pkg, $refnum) = @_; + } my $conf = new FS::Conf; @@ -5685,6 +5702,8 @@ sub order { } + $hash{locationnum} = $locationnum if $locationnum; + # Create the new packages. foreach my $pkgpart (@$pkgparts) { diff --git a/httemplate/edit/cust_pkg.cgi b/httemplate/edit/cust_pkg.cgi index 7ffbb1fc0..4e4f4d2b2 100755 --- a/httemplate/edit/cust_pkg.cgi +++ b/httemplate/edit/cust_pkg.cgi @@ -1,115 +1,207 @@ -<% include('/elements/header.html', "Add/Edit Packages", '') %> +<%doc> + Bulk package Edit Page + + +<& /elements/header-cust_main.html, + view => 'packages', + cust_main => $cust_main, + include_selectize => 1, +&> <% include('/elements/error.html') %> -
- - - -%#current packages -%if (@cust_pkg) { - - Current packages - select to remove (services are moved to a new package below) - - - - - -

-% -% foreach ( @main_pkgs ) { -% my($pkgnum,$pkgpart)=( $_->getfield('pkgnum'), $_->getfield('pkgpart') ); -% my $checked = $remove_pkg{$pkgnum} ? ' CHECKED' : ''; -% -% - - - - - - - -% foreach my $supp_pkg ( @{ $supp_pkgs_of{$pkgnum} } ) { - - - - - + + + + + + +

+ + <% include( '/elements/select-cust_location.html', + cust_main => $cust_main, + addnew => 0, + onchange => 'javascript:location_changed(this);', + ) %>
+ + Bulk-edit works with one customer location at a time + +

+ +
Pkg #Package description
><% $pkgnum %>:<% $all_pkg{$pkgpart} |h %> - <% $all_comment{$pkgpart} |h %>
+ <% $all_pkg{$supp_pkg->pkgpart} |h %> - <% $all_comment{$supp_pkg->pkgpart} |h %>
+ + + + + + + +% for my $cust_pkg ( @cust_pkg ) { +% my $id = sprintf 'remove_cust_pkg[%s]', $cust_pkg->pkgnum; +% my $is_displayed = $cust_main->ship_locationnum == $cust_pkg->locationnum ? 1 : 0; + + + + + % } -% } - - -
+ Pkg # + + Current Packages
+
+ Selected packages are removed.
+ Attached services are moved to the new package selected below + +
+ + #<% $cust_pkg->pkgnum %> + +% } +
-

-% } - - -Order new packages -

- -%my $cust_main = qsearchs('cust_main',{'custnum'=>$custnum}); -%my $agent = qsearchs('agent',{'agentnum'=> $cust_main->agentnum }); -% -%my %agent_pkgs = map { ( $_->pkgpart => $all_pkg{$_->pkgpart} ) } -% ( qsearch('type_pkgs',{ typenum => $agent->typenum }), -% qsearch('part_pkg', { agentnum => $cust_main->agentnum }), -% ); -% -%my $count = 0; -%my $pkgparts = 0; - - - - - - -% -%#foreach my $type_pkgs ( qsearch('type_pkgs',{'typenum'=> $agent->typenum }) ) { -%foreach my $pkgpart ( sort { $agent_pkgs{$a} cmp $agent_pkgs{$b} } -% keys(%agent_pkgs) ) { -% $pkgparts++; -% next unless exists $pkg{$pkgpart}; #skip disabled ones -% #print qq!! if ( $count == 0 ); -% my $value = $cgi->param("pkg$pkgpart") || 0; -% - - - - - - - -% -% $count ++ ; -% #if ( $count == 2 ) { -% # print qq!\n! ; -% # $count = 0; -% #} -%} -% - - -
Qty.Package Description
- " VALUE="<% $value %>" SIZE="2" MAXLENGTH="2"> - <% $pkgpart %>:<% $pkg{$pkgpart} |h %> - <% $comment{$pkgpart} |h %>
-% unless ( $pkgparts ) { -% my $p2 = popurl(2); -% my $typenum = $agent->typenum; -% my $agent_type = qsearchs( 'agent_type', { 'typenum' => $typenum } ); -% my $atype = $agent_type->atype; -% - - - (No package definitions, - or agent type - <% $atype %> - is not allowed to purchase any packages.) -% } - - -

- -

+ + + + + + + + + + + + + + + +% for my $part_pkg ( @part_pkg_enabled ) { +% my $id = sprintf 'qty_part_pkg[%s]', $part_pkg->pkgpart; + + + + + +% } + +
+ <% include('/elements/selectize/select-multiple-pkg_class.html', + id => 'filter_pkg_class', + onchange => 'pkg_class_filter_onchange', + ) %> +
QtyClassOrder New Packages
+ + <% $part_pkg->classname || '(none)' %><% $part_pkg->pkg %>
+ + + + <% include('/elements/footer.html') %> @@ -118,53 +210,41 @@ Order new packages die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages'); -my %pkg = (); -my %comment = (); -my %all_pkg = (); -my %all_comment = (); -#foreach (qsearch('part_pkg', { 'disabled' => '' })) { -# $pkg{ $_ -> getfield('pkgpart') } = $_->getfield('pkg'); -# $comment{ $_ -> getfield('pkgpart') } = $_->getfield('comment'); -#} -foreach (qsearch('part_pkg', {} )) { - $all_pkg{ $_ -> getfield('pkgpart') } = $_->getfield('pkg'); - $all_comment{ $_ -> getfield('pkgpart') } = $_->custom_comment; - next if $_->disabled; - $pkg{ $_ -> getfield('pkgpart') } = $_->getfield('pkg'); - $comment{ $_ -> getfield('pkgpart') } = $_->custom_comment; -} +my $custnum = $cgi->param('keywords') || $cgi->param('custnum'); +$custnum =~ /^\d+$/ + or die "Invalid custnum($custnum)"; -my($custnum, %remove_pkg); -if ( $cgi->param('error') ) { - $custnum = $cgi->param('custnum'); - %remove_pkg = map { $_ => 1 } $cgi->param('remove_pkg'); -} else { - my($query) = $cgi->keywords; - $query =~ /^(\d+)$/; - $custnum = $1; - %remove_pkg = (); -} +my $cust_main = qsearchs( cust_main => { custnum => $custnum }) + or die "Invalid custnum ($custnum)"; -my $p1 = popurl(1); +my %part_pkg; +my @part_pkg_enabled; -my @cust_pkg = qsearch('cust_pkg', { 'custnum' => $custnum, 'cancel' => '' } ); -my @main_pkgs; -my %supp_pkgs_of; # main pkgnum => arrayref of cust_pkgs - - -foreach my $cust_pkg - ( sort { $all_pkg{ $a->pkgpart } cmp $all_pkg{ $b->getfield('pkgpart') } } - @cust_pkg +for my $part_pkg ( qsearch( part_pkg => {} )) { + $part_pkg{ $part_pkg->pkgpart } = $part_pkg; + push @part_pkg_enabled, $part_pkg + unless $part_pkg->disabled; +} +@part_pkg_enabled = + sort { $a->classname cmp $b->classname || $a->pkg cmp $b->pkg } + @part_pkg_enabled; + +my @cust_pkg; +my %cust_pkg_supp_of; +for my $cust_pkg ( + qsearch( + cust_pkg => { + custnum => $custnum, + cancel => '', + } ) - # XXX does not properly handle recursive supplemental links -{ +) { if ( my $main_pkgnum = $cust_pkg->main_pkgnum ) { - $supp_pkgs_of{$main_pkgnum} ||= []; - push @{ $supp_pkgs_of{$main_pkgnum} }, $cust_pkg; + $cust_pkg_supp_of{ $main_pkgnum } //= []; + push @{ $cust_pkg_supp_of{ $main_pkgnum } }, $cust_pkg; } else { - push @main_pkgs, $cust_pkg; - $supp_pkgs_of{$cust_pkg->pkgnum} ||= []; + $cust_pkg_supp_of{ $cust_pkg->pkgnum } //= []; + push @cust_pkg, $cust_pkg; } } - diff --git a/httemplate/edit/process/cust_pkg.cgi b/httemplate/edit/process/cust_pkg.cgi index c564c417e..82a9e2375 100755 --- a/httemplate/edit/process/cust_pkg.cgi +++ b/httemplate/edit/process/cust_pkg.cgi @@ -5,38 +5,61 @@ <% $cgi->redirect(popurl(3). "view/cust_main.cgi?$custnum") %> % } <%init> - +use Data::Dumper; +my $DEBUG = 0; my $curuser = $FS::CurrentUser::CurrentUser; die "access denied" unless $curuser->access_right('Bulk change customer packages'); my $error = ''; +my %param = $cgi->Vars; + +my $custnum = $param{custnum}; +$error = "Invalid custnum ($custnum)" if $custnum =~ /\D/; + +my $locationnum = $param{locationnum}; +$error = "Invalid locationnum ($locationnum)" if $locationnum =~ /\D/; + +my @remove_pkgnum = + map { $_ =~ /remove_cust_pkg\[(\d+)\]/ ? $1 : () } + keys %param; + +my @pkgparts; +for my $k ( keys %param ) { + next unless $k =~ /qty_part_pkg\[(\d+)\]/; + my $pkgpart = $1; + my $qty = $param{$k}; + $qty =~ s/(^\s+|\s+$)//g; -#untaint custnum -$cgi->param('custnum') =~ /^(\d+)$/; -my $custnum = $1; - -my @remove_pkgnums = map { - /^(\d+)$/ or die "Illegal remove_pkg value!"; - $1; -} $cgi->param('remove_pkg'); - -my( $action, $error_redirect ) = ( '', '' ); -my @pkgparts = (); - -foreach my $pkgpart ( map /^pkg(\d+)$/ ? $1 : (), $cgi->param ) { - if ( $cgi->param("pkg$pkgpart") =~ /^(\d+)$/ ) { - my $num_pkgs = $1; - while ( $num_pkgs-- ) { - push @pkgparts,$pkgpart; - } - } else { - $error = "Illegal quantity"; + warn "k($k) param{k}($param{$k}) pkgpart($pkgpart) qty($qty)\n" + if $DEBUG; + + if ( $qty =~ /\D/ ) { + $error = "Invalid quantity $qty for pkgpart $pkgpart - please use a number"; last; } + + next if $qty == 0; + + push ( @pkgparts, $pkgpart ) for ( 1..$qty ); +} + +if ( $DEBUG ) { + warn Dumper({ + custnum => $custnum, + locationnum => $locationnum, + remove_pkgnum => \@remove_pkgnum, + pkgparts => \@pkgparts, + param => \%param, + }); } -$error ||= FS::cust_pkg::order($custnum,\@pkgparts,\@remove_pkgnums); +$error ||= FS::cust_pkg::order({ + custnum => $custnum, + pkgparts => \@pkgparts, + remove_pkgnum => \@remove_pkgnum, + locationnum => $locationnum, +}); diff --git a/httemplate/elements/header-cust_main.html b/httemplate/elements/header-cust_main.html index c094f950f..f29f32567 100644 --- a/httemplate/elements/header-cust_main.html +++ b/httemplate/elements/header-cust_main.html @@ -10,12 +10,12 @@ Examples: <& /elements/header.html, { - 'title' => $title, - 'title_noescape' => $title_noescape, - #'nobr' => 1, - 'etc' => $opt{'etc'}, - } -&> + 'title' => $title, + 'title_noescape' => $title_noescape, + #'nobr' => 1, + 'etc' => $opt{'etc'}, + include_selectize => $opt{include_selectize} ? 1 : 0, +} &> % my @part_tag = $cust_main->part_tag; % if ( $conf->config('cust_tag-location') eq 'top' && @part_tag ) {