From d65053a0357531b623d0ff715d3426301f242b2c Mon Sep 17 00:00:00 2001 From: Christopher Burger Date: Mon, 13 Nov 2017 12:45:15 -0500 Subject: [PATCH] RT# 77470 - added reason option to advanced package report with suspended status is selected. Also added links to suspend and unsuspend when status active or suspended is used. Conflicts: FS/FS/cust_pkg/Search.pm httemplate/elements/tr-select-reason.html httemplate/elements/tr-td-label.html --- FS/FS/cust_pkg.pm | 6 ++ httemplate/elements/header-popup.html | 1 + httemplate/elements/popup-topreload.html | 17 ++++ httemplate/elements/topreload.js | 6 ++ httemplate/elements/tr-select-reason.html | 35 +++++--- httemplate/elements/tr-td-label.html | 12 ++- httemplate/misc/bulk_suspend_pkg.cgi | 94 ++++++++++++++++++++++ httemplate/misc/bulk_unsuspend_pkg.cgi | 66 +++++++++++++++ httemplate/misc/process/bulk_suspend_pkg.cgi | 106 +++++++++++++++++++++++++ httemplate/misc/process/bulk_unsuspend_pkg.cgi | 91 +++++++++++++++++++++ httemplate/search/cust_pkg.cgi | 18 ++++- httemplate/search/report_cust_pkg.html | 19 +++++ 12 files changed, 460 insertions(+), 11 deletions(-) create mode 100644 httemplate/elements/popup-topreload.html create mode 100644 httemplate/elements/topreload.js create mode 100644 httemplate/misc/bulk_suspend_pkg.cgi create mode 100644 httemplate/misc/bulk_unsuspend_pkg.cgi create mode 100644 httemplate/misc/process/bulk_suspend_pkg.cgi create mode 100644 httemplate/misc/process/bulk_unsuspend_pkg.cgi diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index fa60afb45..3b746fc2d 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -5893,6 +5893,8 @@ sub search { push @where, $FS::CurrentUser::CurrentUser->agentnums_sql('table'=>'cust_main'); } + push @where, "cust_pkg_reason.reasonnum = '".$params->{reasonnum}."'" if $params->{reasonnum}; + my $extra_sql = scalar(@where) ? ' WHERE '. join(' AND ', @where) : ''; my $addl_from = 'LEFT JOIN part_pkg USING ( pkgpart ) '. @@ -5900,6 +5902,10 @@ sub search { 'LEFT JOIN cust_location USING ( locationnum ) '. FS::UI::Web::join_cust_main('cust_pkg', 'cust_pkg'); + if ($params->{reasonnum}) { + $addl_from .= 'LEFT JOIN cust_pkg_reason ON (cust_pkg_reason.pkgnum = cust_pkg.pkgnum) '; + } + my $select; my $count_query; if ( $params->{'select_zip5'} ) { diff --git a/httemplate/elements/header-popup.html b/httemplate/elements/header-popup.html index 906b1ee51..37402014b 100644 --- a/httemplate/elements/header-popup.html +++ b/httemplate/elements/header-popup.html @@ -34,6 +34,7 @@ Example: % } % } + <% $head |n %> > diff --git a/httemplate/elements/popup-topreload.html b/httemplate/elements/popup-topreload.html new file mode 100644 index 000000000..7a166f6de --- /dev/null +++ b/httemplate/elements/popup-topreload.html @@ -0,0 +1,17 @@ +<%doc> + +Example: + + <& /elements/popup-topreload, mt('Action completed') &> + + +<& /elements/header-popup.html, encode_entities($message) &> + +<& /elements/footer-popup.html &> +<%init> + +my $message = shift; + + \ No newline at end of file diff --git a/httemplate/elements/topreload.js b/httemplate/elements/topreload.js new file mode 100644 index 000000000..84faee05c --- /dev/null +++ b/httemplate/elements/topreload.js @@ -0,0 +1,6 @@ + window.topreload = function() { + if (window != window.top) { + window.top.location.reload(); + } + } + \ No newline at end of file diff --git a/httemplate/elements/tr-select-reason.html b/httemplate/elements/tr-select-reason.html index 3b9bb2299..2fe676b1f 100755 --- a/httemplate/elements/tr-select-reason.html +++ b/httemplate/elements/tr-select-reason.html @@ -5,17 +5,22 @@ Example: include( '/elements/tr-select-reason.html', #required - 'field' => 'reasonnum', - 'reason_class' => 'C', # currently 'C', 'R', 'F', 'S' or 'X' - # for cancel, credit, refund, suspend or void credit + 'field' => 'reasonnum', # field name + 'reason_class' => 'C', # one of those in %FS::reason_type::class_name + 'label' => 'Your Label', # field display label #recommended 'cgi' => $cgi, #easiest way for things to be properly "sticky" on errors #optional - 'control_button' => 'element_name', #button to be enabled when a reason is - #selected + 'control_button' => 'element_name', #button to be enabled when a reason is + #selected 'id' => 'element_id', + 'hide_add' => '1', # setting this will hide the add new reason link, + # even if the user has access to add a new reason. + 'hide_onload' => '1', # setting this will hide reason select box on page load, + # allowing for it do be displayed later. + 'pre_options' => [ 0 => 'all'], # an array of pre options. Defaults to 0 => 'select reason...' #deprecated ways to keep things "sticky" on errors # (requires duplicate code in each using file to parse cgi params) @@ -68,24 +73,28 @@ Example: %# sadly can't just use add_inline here, as we have non-text fields + <& tr-select-table.html, - 'label' => 'Reason', + 'label' => $label, 'field' => $name, 'id' => $id, 'table' => 'reason', 'records' => \@reasons, + 'label_callback' => sub { my $reason = shift; + $reason->type . ' : ' . $reason->reason }, 'name_col' => 'label', 'disable_empty' => 1, - 'pre_options' => [ 0 => 'Select reason...' ], + 'pre_options' => \@pre_options, 'post_options' => \@post_options, 'curr_value' => $init_reason, 'onchange' => $id.'_changed()', + 'hide_onload' => $opt{'hide_onload'}, &> % # "add new reason" fields % # should be a
, but that doesn't fit well into the table -% if ( $curuser->access_right($add_access_right) ) { +% if ( $curuser->access_right($add_access_right) && !$hide_addnew ) { @@ -184,6 +193,8 @@ my %opt = @_; my $name = $opt{'field'}; my $class = $opt{'reason_class'}; +my $label = $opt{'label'} ? $opt{'label'} : 'Reason'; +my $hide_addnew = $opt{'hide_addnew'} ? $opt{'hide_addnew'} : ''; my $init_reason; if ( $opt{'cgi'} ) { @@ -195,6 +206,8 @@ if ( $opt{'cgi'} ) { my $id = $opt{'id'} || $name; $id =~ s/\./_/g; # for edit/part_event +my $label_id = $opt{'label_id'} || ''; + my $add_access_right; if ($class eq 'C') { $add_access_right = 'Add on-the-fly cancel reason'; @@ -222,10 +235,14 @@ my @reasons = qsearch({ ' ON (reason.reason_type = reason_type.typenum)', 'hashref' => { disabled => '' }, 'extra_sql' => " AND reason_type.class = '$class'", + 'order_by' => ' ORDER BY type, reason', }); +my @pre_options = ( 0 => 'Select reason...' ); +@pre_options = @{ $opt{'pre_options'} if $opt{'pre_options'} }; + my @post_options; -if ( $curuser->access_right($add_access_right) ) { +if ( $curuser->access_right($add_access_right) && !$hide_addnew ) { @post_options = ( -1 => 'Add new reason' ); } diff --git a/httemplate/elements/tr-td-label.html b/httemplate/elements/tr-td-label.html index 8125541c7..542f4559c 100644 --- a/httemplate/elements/tr-td-label.html +++ b/httemplate/elements/tr-td-label.html @@ -1,4 +1,12 @@ - +<%doc> + +Actually + +Note that this puts the 'label' argument into the document verbatim, with no +escaping or localization. + + +>
$label
* ' : ''; diff --git a/httemplate/misc/bulk_suspend_pkg.cgi b/httemplate/misc/bulk_suspend_pkg.cgi new file mode 100644 index 000000000..e41ea2b1a --- /dev/null +++ b/httemplate/misc/bulk_suspend_pkg.cgi @@ -0,0 +1,94 @@ +<% include('/elements/header-popup.html', "Suspend Packages") %> + +% if ( $cgi->param('error') ) { + Error: <% $cgi->param('error') %> +

+% } + +
+ +%# some false laziness w/search/cust_pkg.cgi + + +% for my $param ( +% qw( +% agentnum cust_status cust_main_salesnum salesnum custnum magic status +% custom pkgbatch zip reasonnum +% 477part 477rownum date +% report_option +% ), +% grep { /^location_\w+$/ || /^report_option_any/ } $cgi->param +% ) { + +% } +% +% for my $param (qw( censustract censustract2 ) ) { +% next unless grep { $_ eq $param } $cgi->param; + +% } +% +% for my $param (qw( pkgpart classnum refnum towernum )) { +% foreach my $value ($cgi->param($param)) { + +% } +% } +% +% foreach my $field (qw( setup last_bill bill adjourn susp expire contract_end change_date cancel active )) { +% + "> + "> + "> + "> + "> +% } + +<% ntable('#cccccc') %> + +% my $date_init = 0; + <& /elements/tr-input-date-field.html, { + 'name' => 'suspend_date', + 'value' => $date, + 'label' => mt("Suspend package on"), + 'format' => $date_format, + } &> +% $date_init = 1; + + <& /elements/tr-select-reason.html, + field => 'suspend_reasonnum', + reason_class => 'S', + &> + +% if ( $FS::CurrentUser::CurrentUser->access_right('Unsuspend customer package')) { + + <& /elements/tr-input-date-field.html, { + 'name' => 'suspend_resume_date', + 'value' => '', + 'label' => mt('Unsuspend on'), + 'format' => $date_format, + 'noinit' => $date_init, + } &> +% } + +
+ +
+ + + + + + +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages'); + +#use Date::Parse qw(str2time); +# + +my $conf = new FS::Conf; +my $date_format = $conf->config('date_format') || '%m/%d/%Y'; + +my $date = time; + + \ No newline at end of file diff --git a/httemplate/misc/bulk_unsuspend_pkg.cgi b/httemplate/misc/bulk_unsuspend_pkg.cgi new file mode 100644 index 000000000..8fbc41841 --- /dev/null +++ b/httemplate/misc/bulk_unsuspend_pkg.cgi @@ -0,0 +1,66 @@ +<% include('/elements/header-popup.html', "Unsuspend Packages") %> + +% if ( $cgi->param('error') ) { + Error: <% $cgi->param('error') %> +

+% } + + + +%# some false laziness w/search/cust_pkg.cgi + + +% for my $param ( +% qw( +% agentnum cust_status cust_main_salesnum salesnum custnum magic status +% custom pkgbatch zip reasonnum +% 477part 477rownum date +% report_option +% ), +% grep { /^location_\w+$/ || /^report_option_any/ } $cgi->param +% ) { + +% } +% +% for my $param (qw( censustract censustract2 ) ) { +% next unless grep { $_ eq $param } $cgi->param; + +% } +% +% for my $param (qw( pkgpart classnum refnum towernum )) { +% foreach my $value ($cgi->param($param)) { + +% } +% } +% +% foreach my $field (qw( setup last_bill bill adjourn susp expire contract_end change_date cancel active )) { +% + "> + "> + "> + "> + "> +% } + +<% ntable('#cccccc') %> + + + + + + +
Confirm Unsuspend Packages
+ +
+ + + + + + +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages'); + + diff --git a/httemplate/misc/process/bulk_suspend_pkg.cgi b/httemplate/misc/process/bulk_suspend_pkg.cgi new file mode 100644 index 000000000..2ac9c212f --- /dev/null +++ b/httemplate/misc/process/bulk_suspend_pkg.cgi @@ -0,0 +1,106 @@ +% if ($error) { +<% $cgi->redirect(popurl(2)."bulk_suspend_pkg.cgi?".$cgi->query_string ) %> +% } +<% include('/elements/popup-topreload.html', "Packages Suspended") %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages'); + +my $error; + +if (!$error) { + + my %search_hash = (); + + $search_hash{'query'} = $cgi->param('query'); + + #scalars + for (qw( agentnum cust_status cust_main_salesnum salesnum custnum magic status + custom cust_fields pkgbatch zip reasonnum + 477part 477rownum date + )) + { + $search_hash{$_} = $cgi->param($_) if length($cgi->param($_)); + } + + #arrays + for my $param (qw( pkgpart classnum refnum towernum )) { + $search_hash{$param} = [ $cgi->param($param) ] + if grep { $_ eq $param } $cgi->param; + } + + #scalars that need to be passed if empty + for my $param (qw( censustract censustract2 )) { + $search_hash{$param} = $cgi->param($param) || '' + if grep { $_ eq $param } $cgi->param; + } + + #location flags (checkboxes) + my @loc = grep /^\w+$/, $cgi->param('loc'); + $search_hash{"location_$_"} = 1 foreach @loc; + + my $report_option = $cgi->param('report_option'); + $search_hash{report_option} = $report_option if $report_option; + + for my $param (grep /^report_option_any/, $cgi->param) { + $search_hash{$param} = $cgi->param($param); + } + + ### + # parse dates + ### + + #false laziness w/report_cust_pkg.html and bulk_pkg_increment_bill.cgi + my %disable = ( + 'all' => {}, + 'one-time charge' => { 'last_bill'=>1, 'bill'=>1, 'adjourn'=>1, 'susp'=>1, 'expire'=>1, 'cancel'=>1, }, + 'active' => { 'susp'=>1, 'cancel'=>1 }, + 'suspended' => { 'cancel' => 1 }, + 'cancelled' => {}, + '' => {}, + ); + + foreach my $field (qw( setup last_bill bill adjourn susp expire contract_end change_date cancel active )) { + + $search_hash{$field.'_null'} = scalar( $cgi->param($field.'_null') ); + + my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi, $field); + + next if $beginning == 0 && $ending == 4294967295 + or $disable{$cgi->param('status')}->{$field}; + + $search_hash{$field} = [ $beginning, $ending ]; + + } + + my $sql_query = FS::cust_pkg->search(\%search_hash); + $sql_query->{'select'} = 'cust_pkg.pkgnum'; + + ## set suspend info + $cgi->param('suspend_reasonnum') =~ /^(\d+)$/ or die "Illegal Reason"; + my $suspend_reasonnum = $1; + + my $suspend_date = time; + parse_datetime($cgi->param('suspend_date')) =~ /^(\d+)$/ or die "Illegal date"; + $suspend_date = $1; + + my $suspend_resume_date = ''; + (parse_datetime($cgi->param('suspend_resume_date')) =~ /^(\d+)$/ or die "Illegal resume date") if $cgi->param('suspend_resume_date'); + $suspend_resume_date = $1; + + foreach my $pkgnum (map { $_->pkgnum } qsearch($sql_query)) { + my $cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); + + $error = $cust_pkg->suspend('reason' => $suspend_reasonnum, + 'date' => $suspend_date, + 'resume_date' => $suspend_resume_date, + ); + } + +} + +$cgi->param("error", substr($error, 0, 512)); # arbitrary length believed + # suited for all supported + # browsers + \ No newline at end of file diff --git a/httemplate/misc/process/bulk_unsuspend_pkg.cgi b/httemplate/misc/process/bulk_unsuspend_pkg.cgi new file mode 100644 index 000000000..13389f43a --- /dev/null +++ b/httemplate/misc/process/bulk_unsuspend_pkg.cgi @@ -0,0 +1,91 @@ +% if ($error) { +<% $cgi->redirect(popurl(2)."bulk_unsuspend_pkg.cgi?".$cgi->query_string ) %> +% } +<% include('/elements/popup-topreload.html', "Packages Unsuspended") %> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages'); + +my $error; +$error = 'Unsuspend packages not confirmed' if !$cgi->param('confirm'); + +if (!$error) { + + my %search_hash = (); + + $search_hash{'query'} = $cgi->param('query'); + + #scalars + for (qw( agentnum cust_status cust_main_salesnum salesnum custnum magic status + custom cust_fields pkgbatch zip reasonnum + 477part 477rownum date + )) + { + $search_hash{$_} = $cgi->param($_) if length($cgi->param($_)); + } + + #arrays + for my $param (qw( pkgpart classnum refnum towernum )) { + $search_hash{$param} = [ $cgi->param($param) ] + if grep { $_ eq $param } $cgi->param; + } + + #scalars that need to be passed if empty + for my $param (qw( censustract censustract2 )) { + $search_hash{$param} = $cgi->param($param) || '' + if grep { $_ eq $param } $cgi->param; + } + + #location flags (checkboxes) + my @loc = grep /^\w+$/, $cgi->param('loc'); + $search_hash{"location_$_"} = 1 foreach @loc; + + my $report_option = $cgi->param('report_option'); + $search_hash{report_option} = $report_option if $report_option; + + for my $param (grep /^report_option_any/, $cgi->param) { + $search_hash{$param} = $cgi->param($param); + } + + ### + # parse dates + ### + + #false laziness w/report_cust_pkg.html and bulk_pkg_increment_bill.cgi + my %disable = ( + 'all' => {}, + 'one-time charge' => { 'last_bill'=>1, 'bill'=>1, 'adjourn'=>1, 'susp'=>1, 'expire'=>1, 'cancel'=>1, }, + 'active' => { 'susp'=>1, 'cancel'=>1 }, + 'suspended' => { 'cancel' => 1 }, + 'cancelled' => {}, + '' => {}, + ); + + foreach my $field (qw( setup last_bill bill adjourn susp expire contract_end change_date cancel active )) { + + $search_hash{$field.'_null'} = scalar( $cgi->param($field.'_null') ); + + my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi, $field); + + next if $beginning == 0 && $ending == 4294967295 + or $disable{$cgi->param('status')}->{$field}; + + $search_hash{$field} = [ $beginning, $ending ]; + + } + + my $sql_query = FS::cust_pkg->search(\%search_hash); + $sql_query->{'select'} = 'cust_pkg.pkgnum'; + + foreach my $pkgnum (map { $_->pkgnum } qsearch($sql_query)) { + my $cust_pkg = qsearchs('cust_pkg',{'pkgnum'=>$pkgnum}); + $error = $cust_pkg->unsuspend; + } + +} + +$cgi->param("error", substr($error, 0, 512)); # arbitrary length believed + # suited for all supported + # browsers + \ No newline at end of file diff --git a/httemplate/search/cust_pkg.cgi b/httemplate/search/cust_pkg.cgi index 2459c44b2..3eb0332d2 100755 --- a/httemplate/search/cust_pkg.cgi +++ b/httemplate/search/cust_pkg.cgi @@ -159,7 +159,7 @@ $search_hash{'query'} = $cgi->keywords; #scalars for (qw( agentnum cust_status cust_main_salesnum salesnum custnum magic status - custom cust_fields pkgbatch zip + reasonnum custom cust_fields pkgbatch zip 477part 477rownum date )) { @@ -270,6 +270,22 @@ my $html_init = sub { 'height' => 210, ). '
'; + $text .= include( '/elements/popup_link.html', + 'label' => emt('Suspend these packages'), + 'action' => "${p}misc/bulk_suspend_pkg.cgi?$query", + 'actionlabel' => emt('Suspend Packages'), + 'width' => 569, + 'height' => 210, + ). '
' if $search_hash{status} eq 'active'; + + $text .= include( '/elements/popup_link.html', + 'label' => emt('Unsuspend these packages'), + 'action' => "${p}misc/bulk_unsuspend_pkg.cgi?$query", + 'actionlabel' => emt('Unsuspend Packages'), + 'width' => 569, + 'height' => 210, + ). '
' if $search_hash{status} eq 'suspended'; + if ( $curuser->access_right('Edit customer package dates') ) { $text .= include( '/elements/popup_link.html', 'label' => emt('Increment next bill date'), diff --git a/httemplate/search/report_cust_pkg.html b/httemplate/search/report_cust_pkg.html index ed5af2481..8c910e603 100755 --- a/httemplate/search/report_cust_pkg.html +++ b/httemplate/search/report_cust_pkg.html @@ -67,10 +67,29 @@ 'onchange' => 'status_changed(this);', &> + <& /elements/tr-select-reason.html, + 'field' => 'reasonnum', + 'reason_class' => 'S', + 'label' => 'Suspended Reason', + 'label_id' => 'reasonnum_label', + 'hide_addnew' => '1', + 'hide_onload' => '1', + 'cgi' => $cgi, + 'control_button' => 'confirm_suspend_cust_button', + 'pre_options' => [ 0 => 'all' ], + &> +