RT# 77470 - added reason option to advanced package report with suspended status...
authorChristopher Burger <burgerc@freeside.biz>
Mon, 13 Nov 2017 17:45:15 +0000 (12:45 -0500)
committerChristopher Burger <burgerc@freeside.biz>
Mon, 13 Nov 2017 17:45:15 +0000 (12:45 -0500)
FS/FS/cust_pkg/Search.pm
httemplate/elements/tr-select-reason.html
httemplate/elements/tr-td-label.html
httemplate/misc/bulk_suspend_pkg.cgi [new file with mode: 0644]
httemplate/misc/bulk_unsuspend_pkg.cgi [new file with mode: 0644]
httemplate/misc/process/bulk_suspend_pkg.cgi [new file with mode: 0644]
httemplate/misc/process/bulk_unsuspend_pkg.cgi [new file with mode: 0644]
httemplate/search/cust_pkg.cgi
httemplate/search/report_cust_pkg.html

index 311dbdb..3e1ca82 100644 (file)
@@ -627,6 +627,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  ) '.
@@ -634,6 +636,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'} ) {
index 9a43022..6f126d3 100755 (executable)
@@ -5,16 +5,22 @@ Example:
   include( '/elements/tr-select-reason.html',
 
     #required 
-    'field'         => 'reasonnum',
-    'reason_class'  => 'C', # one of those in %FS::reason_type::class_name
+    '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)
@@ -67,8 +73,9 @@ Example:
 </SCRIPT>
 
 %# 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',
@@ -76,16 +83,17 @@ Example:
   'label_callback'  => sub { my $reason = shift;
                              $reason->type . ' : ' .  $reason->reason },
   '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 <fieldset>, 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 ) {
 <TR id="<% $id %>_new_fields">
   <TD COLSPAN=2>
     <TABLE CLASS="inv" STYLE="text-align: left">
@@ -184,6 +192,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'} ) {
@@ -194,6 +204,8 @@ $init_reason ||= $opt{'curr_value'};
 my $id = $opt{'id'} || $name;
 $id =~ s/\./_/g; # for edit/part_event
 
+my $label_id = $opt{'label_id'} || '';
+
 my $add_access_right = $FS::reason_type::class_add_access_right{$class}
   or die "unknown class: $class";
 
@@ -206,8 +218,12 @@ my @reasons = qsearch({
   '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' );
 }
 
index 1d96cf3..80dddaa 100644 (file)
@@ -6,7 +6,7 @@ Note that this puts the 'label' argument into the document verbatim, with no
 escaping or localization.
 
 </%doc>
-<TR>
+<TR id="<% $opt{'id'} %>_row" <% $row_style %>>
 
   <TH ALIGN  = "right"
       VALIGN = "<% $opt{'valign'} || 'top' %>"
@@ -22,6 +22,8 @@ my $style = 'padding-top: 3px';
 $style .= '; '. $opt{'cell_style'}
   if $opt{'cell_style'};
 
+my $row_style = 'style="visibility:collapse;"' if $opt{'hide_onload'};
+
 my $required = $opt{'required'} ? '<font color="#ff0000">*</font>&nbsp;' : '';
 
 </%init>
diff --git a/httemplate/misc/bulk_suspend_pkg.cgi b/httemplate/misc/bulk_suspend_pkg.cgi
new file mode 100644 (file)
index 0000000..e41ea2b
--- /dev/null
@@ -0,0 +1,94 @@
+<% include('/elements/header-popup.html', "Suspend Packages") %>
+
+% if ( $cgi->param('error') ) {
+  <FONT SIZE="+1" COLOR="#ff0000">Error: <% $cgi->param('error') %></FONT>
+  <BR><BR>
+% }
+
+<FORM ACTION="<% $p %>misc/process/bulk_suspend_pkg.cgi" METHOD=POST>
+
+%# some false laziness w/search/cust_pkg.cgi
+
+<INPUT TYPE="hidden" NAME="query" VALUE="<% $cgi->keywords |h %>">
+% 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
+% ) {
+  <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $cgi->param($param) |h %>">
+% }
+%
+% for my $param (qw( censustract censustract2 ) ) {
+%   next unless grep { $_ eq $param } $cgi->param;
+  <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $cgi->param($param) |h %>">
+% }
+%
+% for my $param (qw( pkgpart classnum refnum towernum )) {
+%   foreach my $value ($cgi->param($param)) {
+      <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $value |h %>">
+%   }
+% }
+%
+% foreach my $field (qw( setup last_bill bill adjourn susp expire contract_end change_date cancel active )) {
+% 
+  <INPUT TYPE="hidden" NAME="<% $field %>_null" VALUE="<% $cgi->param("${field}_null") |h %>">
+  <INPUT TYPE="hidden" NAME="<% $field %>_begin" VALUE="<% $cgi->param("${field}_begin") |h %>">
+  <INPUT TYPE="hidden" NAME="<% $field %>_beginning" VALUE="<% $cgi->param("${field}_beginning") |h %>">
+  <INPUT TYPE="hidden" NAME="<% $field %>_end" VALUE="<% $cgi->param("${field}_end") |h %>">
+  <INPUT TYPE="hidden" NAME="<% $field %>_ending" VALUE="<% $cgi->param("${field}_ending") |h %>">
+% }
+
+<% 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,
+  } &>
+% }
+
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="Suspend Packages">
+
+</FORM>
+</BODY>
+</HTML>
+
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages');
+
+#use Date::Parse qw(str2time);
+#<table style="background-color: #cccccc; border-spacing: 2; width: 100%">
+
+my $conf = new FS::Conf;
+my $date_format = $conf->config('date_format') || '%m/%d/%Y';
+
+my $date = time;
+
+</%init>
\ 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 (file)
index 0000000..8fbc418
--- /dev/null
@@ -0,0 +1,66 @@
+<% include('/elements/header-popup.html', "Unsuspend Packages") %>
+
+% if ( $cgi->param('error') ) {
+  <FONT SIZE="+1" COLOR="#ff0000">Error: <% $cgi->param('error') %></FONT>
+  <BR><BR>
+% }
+
+<FORM ACTION="<% $p %>misc/process/bulk_unsuspend_pkg.cgi" METHOD=POST>
+
+%# some false laziness w/search/cust_pkg.cgi
+
+<INPUT TYPE="hidden" NAME="query" VALUE="<% $cgi->keywords |h %>">
+% 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
+% ) {
+  <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $cgi->param($param) |h %>">
+% }
+%
+% for my $param (qw( censustract censustract2 ) ) {
+%   next unless grep { $_ eq $param } $cgi->param;
+  <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $cgi->param($param) |h %>">
+% }
+%
+% for my $param (qw( pkgpart classnum refnum towernum )) {
+%   foreach my $value ($cgi->param($param)) {
+      <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $value |h %>">
+%   }
+% }
+%
+% foreach my $field (qw( setup last_bill bill adjourn susp expire contract_end change_date cancel active )) {
+% 
+  <INPUT TYPE="hidden" NAME="<% $field %>_null" VALUE="<% $cgi->param("${field}_null") |h %>">
+  <INPUT TYPE="hidden" NAME="<% $field %>_begin" VALUE="<% $cgi->param("${field}_begin") |h %>">
+  <INPUT TYPE="hidden" NAME="<% $field %>_beginning" VALUE="<% $cgi->param("${field}_beginning") |h %>">
+  <INPUT TYPE="hidden" NAME="<% $field %>_end" VALUE="<% $cgi->param("${field}_end") |h %>">
+  <INPUT TYPE="hidden" NAME="<% $field %>_ending" VALUE="<% $cgi->param("${field}_ending") |h %>">
+% }
+
+<% ntable('#cccccc') %>
+
+  <TR>
+    <TD><INPUT TYPE="checkbox" NAME="confirm"></TD>
+    <TD>Confirm Unsuspend Packages</TD>
+  </TR>
+
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="Unsuspend Packages">
+
+</FORM>
+</BODY>
+</HTML>
+
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Bulk change customer packages');
+
+</%init>
diff --git a/httemplate/misc/process/bulk_suspend_pkg.cgi b/httemplate/misc/process/bulk_suspend_pkg.cgi
new file mode 100644 (file)
index 0000000..2ac9c21
--- /dev/null
@@ -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
+</%init>
\ 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 (file)
index 0000000..13389f4
--- /dev/null
@@ -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
+</%init>
\ No newline at end of file
index 2459c44..3eb0332 100755 (executable)
@@ -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,
              ). '<BR>';
 
+    $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,
+             ). '<BR>' 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,
+             ). '<BR>' 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'),
index 5e8c429..981c546 100755 (executable)
                   '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' ],
+    &>
+
     <SCRIPT TYPE="text/javascript">
   
       function status_changed(what) {
 
+        if (what.options[what.selectedIndex].value == 'suspended') {
+          document.getElementById('reasonnum_row').style.visibility = 'visible';
+        }
+        else {
+          document.getElementById('reasonnum_row').style.visibility = 'collapse';
+        }
+
 %       foreach my $status ( '', FS::cust_pkg->statuses() ) {
 
           if ( what.options[what.selectedIndex].value == '<% $status %>' ) {