[freeside-commits] branch master updated. f228534e7bc57e615657d6a8b9c09069f34f914e

Christopher Burger burgerc at freeside.biz
Thu Nov 16 12:00:52 PST 2017


The branch, master has been updated
       via  f228534e7bc57e615657d6a8b9c09069f34f914e (commit)
       via  679da2cb45e49797636f722abc52d41ee273ba00 (commit)
       via  483528c704363ae7d0318a9651a8416ff07e946d (commit)
       via  2554b11e48a7ec4567bf89f9a48f7a83ec925eea (commit)
      from  8036d190629e546818b7418938b4e8fcda3f16a8 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit f228534e7bc57e615657d6a8b9c09069f34f914e
Merge: 679da2cb4 8036d1906
Author: Christopher Burger <burgerc at freeside.biz>
Date:   Wed Nov 15 22:27:47 2017 -0500

    Merge branch 'master' of ssh://git.freeside.biz/home/git/freeside


commit 679da2cb45e49797636f722abc52d41ee273ba00
Author: Christopher Burger <burgerc at freeside.biz>
Date:   Wed Nov 15 16:00:26 2017 -0500

    RT# 77470 - Fixed error with select reason drop down box, not working when no pre_options listed

diff --git a/httemplate/elements/tr-select-reason.html b/httemplate/elements/tr-select-reason.html
index 6f126d327..a4e0c033e 100755
--- a/httemplate/elements/tr-select-reason.html
+++ b/httemplate/elements/tr-select-reason.html
@@ -220,7 +220,7 @@ my @reasons = qsearch({
 
 
 my @pre_options = ( 0 => 'Select reason...' );
- at pre_options = @{ $opt{'pre_options'} if $opt{'pre_options'} };
+ at pre_options = @{ $opt{'pre_options'} } if $opt{'pre_options'};
 
 my @post_options;
 if ( $curuser->access_right($add_access_right) && !$hide_addnew ) {

commit 483528c704363ae7d0318a9651a8416ff07e946d
Author: Christopher Burger <burgerc at freeside.biz>
Date:   Wed Nov 15 14:04:22 2017 -0500

    RT# 29295 - added package_list and package_status to backend API.  Also added two new test files in bin to test new apis

diff --git a/FS/FS/API.pm b/FS/FS/API.pm
index 17587443b..75948a3e3 100644
--- a/FS/FS/API.pm
+++ b/FS/FS/API.pm
@@ -650,6 +650,102 @@ sub location_info {
   return \%return;
 }
 
+=item list_customer_packages OPTION => VALUE, ...
+
+Lists all customer packages.
+
+=over
+
+=item secret
+
+API Secret
+
+=item custnum
+
+Customer Number
+
+=back
+
+Example:
+
+  my $result = FS::API->list_packages(
+    'secret'  => 'sharingiscaring',
+    'custnum'  => custnum,
+  );
+
+  if ( $result->{'error'} ) {
+    die $result->{'error'};
+  } else {
+    # list packages returns an array of hashes for packages ordered by custnum and pkgnum.
+    print Dumper($result->{'pkgs'});
+  }
+
+=cut
+
+sub list_customer_packages {
+  my( $class, %opt ) = @_;
+  return _shared_secret_error() unless _check_shared_secret($opt{secret});
+
+  my $sql_query = FS::cust_pkg->search({ 'custnum' => $opt{custnum}, });
+
+  $sql_query->{order_by} = 'ORDER BY custnum, pkgnum';
+
+  my @packages = qsearch($sql_query)
+    or return { 'error' => 'No packages' };
+
+  my $return = {
+    'packages'       => [ map $_->hashref, @packages ],
+  };
+
+  $return;
+}
+
+=item package_status OPTION => VALUE, ...
+
+Get package status.
+
+=over
+
+=item secret
+
+API Secret
+
+=item pkgnum
+
+Package Number
+
+=back
+
+Example:
+
+  my $result = FS::API->package_status(
+    'secret'  => 'sharingiscaring',
+    'pkgnum'  => pkgnum,
+  );
+
+  if ( $result->{'error'} ) {
+    die $result->{'error'};
+  } else {
+    # package status returns a hash with the status for a package.
+    print Dumper($result->{'status'});
+  }
+
+=cut
+
+sub package_status {
+  my( $class, %opt ) = @_;
+  return _shared_secret_error() unless _check_shared_secret($opt{secret});
+
+  my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $opt{pkgnum} } )
+    or return { 'error' => 'No packages' };
+
+  my $return = {
+    'status' => $cust_pkg->status,
+  };
+
+  $return;
+}
+
 =item order_package OPTION => VALUE, ...
 
 Orders a new customer package.  Takes a list of keys and values as paramaters
diff --git a/bin/xmlrpc-customer_package-status.pl b/bin/xmlrpc-customer_package-status.pl
new file mode 100644
index 000000000..589c42af4
--- /dev/null
+++ b/bin/xmlrpc-customer_package-status.pl
@@ -0,0 +1,27 @@
+#!/usr/bin/perl
+
+## example
+# perl xmlrpc-customer_package-status.pl <pkgnum>
+##  
+
+use strict;
+use Frontier::Client;
+use Data::Dumper;
+
+my $uri = new URI 'http://localhost:8008/';
+
+my $server = new Frontier::Client ( 'url' => $uri );
+
+my $result = $server->call(
+  'FS.API.package_status',
+    'secret'  => 'MySecretCode',
+    'pkgnum' => $ARGV[0],
+);
+
+die $result->{'error'} if $result->{'error'};
+
+print $result->{status};
+
+print "\nAll Done\n";
+
+exit;
\ No newline at end of file
diff --git a/bin/xmlrpc-customer_packages-list.pl b/bin/xmlrpc-customer_packages-list.pl
new file mode 100644
index 000000000..745d30fbd
--- /dev/null
+++ b/bin/xmlrpc-customer_packages-list.pl
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+
+## example
+# perl xmlrpc-customer_packages-list.pl <custnum>
+##  
+
+use strict;
+use Frontier::Client;
+use Data::Dumper;
+
+my $uri = new URI 'http://localhost:8008/';
+
+my $server = new Frontier::Client ( 'url' => $uri );
+
+my $result = $server->call(
+  'FS.API.list_customer_packages',
+    'secret'  => 'MySecretCode',
+    'custnum' => $ARGV[0],
+);
+
+die $result->{'error'} if $result->{'error'};
+
+my @packages = @{$result->{packages}};
+
+print Dumper(@packages);
+
+print "\n total: " . scalar @packages;
+
+print "\nAll Done\n";
+
+exit;
\ No newline at end of file

commit 2554b11e48a7ec4567bf89f9a48f7a83ec925eea
Author: Christopher Burger <burgerc at freeside.biz>
Date:   Mon Nov 13 12:45:15 2017 -0500

    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.

diff --git a/FS/FS/cust_pkg/Search.pm b/FS/FS/cust_pkg/Search.pm
index 311dbdbe1..3e1ca820e 100644
--- a/FS/FS/cust_pkg/Search.pm
+++ b/FS/FS/cust_pkg/Search.pm
@@ -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'} ) {
diff --git a/httemplate/elements/tr-select-reason.html b/httemplate/elements/tr-select-reason.html
index 9a430222c..6f126d327 100755
--- a/httemplate/elements/tr-select-reason.html
+++ b/httemplate/elements/tr-select-reason.html
@@ -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...' );
+ at 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 1d96cf307..80dddaa47 100644
--- a/httemplate/elements/tr-td-label.html
+++ b/httemplate/elements/tr-td-label.html
@@ -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> ' : '';
 
 </%init>
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') ) {
+  <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
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') ) {
+  <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
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
+</%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
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
+</%init>
\ 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,
              ). '<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'),
diff --git a/httemplate/search/report_cust_pkg.html b/httemplate/search/report_cust_pkg.html
index 5e8c429ec..981c54607 100755
--- a/httemplate/search/report_cust_pkg.html
+++ b/httemplate/search/report_cust_pkg.html
@@ -65,10 +65,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' ],
+    &>
+
     <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 %>' ) {

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/API.pm                                       |  96 +++++++++++++++++++
 FS/FS/cust_pkg/Search.pm                           |   6 ++
 ...s-list.pl => xmlrpc-customer_package-status.pl} |   9 +-
 ...es-list.pl => xmlrpc-customer_packages-list.pl} |  13 ++-
 httemplate/elements/tr-select-reason.html          |  32 +++++--
 httemplate/elements/tr-td-label.html               |   4 +-
 ...pkg_increment_bill.cgi => bulk_suspend_pkg.cgi} |  48 ++++++++--
 ...g_increment_bill.cgi => bulk_unsuspend_pkg.cgi} |  14 +--
 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, 425 insertions(+), 31 deletions(-)
 copy bin/{xmlrpc-advertising_sources-list.pl => xmlrpc-customer_package-status.pl} (67%)
 mode change 100755 => 100644
 copy bin/{xmlrpc-advertising_sources-list.pl => xmlrpc-customer_packages-list.pl} (56%)
 mode change 100755 => 100644
 copy httemplate/misc/{bulk_pkg_increment_bill.cgi => bulk_suspend_pkg.cgi} (59%)
 mode change 100755 => 100644
 copy httemplate/misc/{bulk_pkg_increment_bill.cgi => bulk_unsuspend_pkg.cgi} (82%)
 mode change 100755 => 100644
 create mode 100644 httemplate/misc/process/bulk_suspend_pkg.cgi
 create mode 100644 httemplate/misc/process/bulk_unsuspend_pkg.cgi




More information about the freeside-commits mailing list