add ability to select specific package defs. and package status to package report...
authorivan <ivan>
Mon, 19 Jun 2006 08:05:28 +0000 (08:05 +0000)
committerivan <ivan>
Mon, 19 Jun 2006 08:05:28 +0000 (08:05 +0000)
15 files changed:
FS/FS/Conf.pm
FS/FS/ConfDefaults.pm [new file with mode: 0644]
FS/FS/UI/Web.pm
FS/FS/cust_main_Mixin.pm
FS/FS/cust_pkg.pm
httemplate/config/config.cgi
httemplate/elements/menu.html
httemplate/elements/select-cust-fields.html [new file with mode: 0644]
httemplate/elements/select-cust_pkg-status.html [new file with mode: 0644]
httemplate/elements/tr-select-cust-fields.html [new file with mode: 0644]
httemplate/elements/tr-select-cust_pkg-status.html [new file with mode: 0644]
httemplate/graph/cust_bill_pkg.cgi
httemplate/search/cust_pkg_report.cgi [deleted file]
httemplate/search/report_cust_pkg.html [new file with mode: 0755]
httemplate/view/cust_main/contacts.html

index e7b9fa5..57c18e6 100644 (file)
@@ -4,6 +4,7 @@ use vars qw($default_dir @config_items $DEBUG );
 use IO::File;
 use File::Basename;
 use FS::ConfItem;
+use FS::ConfDefaults;
 
 $DEBUG = 0;
 
@@ -1619,18 +1620,9 @@ httemplate/docs/config.html
   {
     'key'         => 'cust-fields',
     'section'     => 'UI',
-    'description' => 'Which customer fields to display on reports',
+    'description' => 'Which customer fields to display on reports by default',
     'type'        => 'select',
-    'select_enum' => [
-      'Customer: Last, First</b> or</i> Company (Last, First)</b>',
-      'Cust# | Customer: custnum | Last, First or Company (Last, First)',
-      'Name | Company: Last, First | Company',
-      'Cust# | Name | Company: custnum | Last, First | Company',
-      '(bill) Customer | (service) Customer: Last, First or Company (Last, First) | (same for service address if present)',
-      'Cust# | (bill) Customer | (service) Customer:  custnum | Last, First or Company (Last, First) | (same for service address if present)',
-      '(bill) Name | (bill) Company | (service) Name | (service) Company: Last, First | Company | (same for service address if present)',
-      'Cust# | (bill) Name | (bill) Company | (service) Name | (service) Company: custnum | Last, First | Company | (same for service address if present)',
-    ],
+    'select_hash' => [ FS::ConfDefaults->cust_fields_avail() ],
   },
 
   {
@@ -1709,6 +1701,21 @@ httemplate/docs/config.html
     'type'        => 'checkbox',
   },
 
+  {
+    'key'         => 'batch-default_format',
+    'section'     => 'billing',
+    'description' => 'Default format for batches.',
+    'type'        => 'select',
+    'select_enum' => [ 'csv-td_canada_trust-merchant_pc_batch', 'BoM' ]
+  },
+
+  {
+    'key'         => 'batchconfig-BoM',
+    'section'     => 'billing',
+    'description' => 'Configuration for Bank of Montreal batching, seven lines: 1. Origin ID, 2. Datacenter, 3. Typecode, 4. Short name, 5. Long name, 6. Bank, 7. Bank account',
+    'type'        => 'textarea',
+  },
+
 );
 
 1;
diff --git a/FS/FS/ConfDefaults.pm b/FS/FS/ConfDefaults.pm
new file mode 100644 (file)
index 0000000..b9cbcfb
--- /dev/null
@@ -0,0 +1,68 @@
+package FS::ConfDefaults;
+
+=head1 NAME
+
+FS::ConfDefaults - Freeside configuration default and available values
+
+=head1 SYNOPSIS
+
+  use FS::ConfDefaults;
+
+  @avail_cust_fields = FS::ConfDefaults->cust_fields_avail();
+
+=head1 DESCRIPTION
+
+Just a small class to keep config default and available values
+
+=head1 METHODS
+
+=over 4
+
+=item cust_fields_avail
+
+Returns a list, suitable for assigning to a hash, of available values and
+labels for customer fields values.
+
+=cut
+
+# XXX should use msgcat for "Day phone" and "Night phone", but how?
+sub cust_fields_avail { (
+
+  'Customer' =>
+    'Last, First or Company (Last, First)',
+  'Cust# | Customer' =>
+    'custnum | Last, First or Company (Last, First)',
+
+  'Name | Company' =>
+    'Last, First | Company',
+  'Cust# | Name | Company' =>
+    'custnum | Last, First | Company',
+
+  '(bill) Customer | (service) Customer' =>
+    'Last, First or Company (Last, First) | (same for service contact if present)',
+  'Cust# | (bill) Customer | (service) Customer' =>
+    'custnum | Last, First or Company (Last, First) | (same for service contact if present)',
+
+  '(bill) Name | (bill) Company | (service) Name | (service) Company' =>
+    'Last, First | Company | (same for service address if present)',
+  'Cust# | (bill) Name | (bill) Company | (service) Name | (service) Company' =>
+    'custnum | Last, First | Company | (same for service address if present)',
+
+  'Cust# | Name | Company | Address 1 | Address 2 | City | State | Zip | Country | Day phone | Night phone | Invoicing email(s)' => 
+    'custnum | Last, First | Company | (all address fields ) | Day phone | Night phone | Invoicing email(s)',
+
+); }
+
+=back
+
+=head1 BUGS
+
+Not yet.
+
+=head1 SEE ALSO
+
+L<FS::Conf>
+
+=cut
+
+1;
index 10ddbf3..080ac6e 100644 (file)
@@ -8,6 +8,8 @@ use FS::Record qw(dbdef);
 #use FS::UI
 #@ISA = qw( FS::UI );
 
+$DEBUG = 0;
+
 use Date::Parse;
 sub parse_beginning_ending {
   my($cgi) = @_;
@@ -31,73 +33,116 @@ sub parse_beginning_ending {
 }
 
 ###
-# cust_main report methods
+# cust_main report subroutines
 ###
 
-=item cust_header
 
-Returns an array of customer information headers according to the
-B<cust-fields> configuration setting.
+=item cust_header [ CUST_FIELDS_VALUE ]
+
+Returns an array of customer information headers according to the supplied
+customer fields value, or if no value is supplied, the B<cust-fields>
+configuration value.
 
 =cut
 
 use vars qw( @cust_fields );
 
-sub cust_sql_fields {
-  my @fields = qw( last first company );
-  push @fields, map "ship_$_", @fields
-    if dbdef->table('cust_main')->column('ship_last');
-  map "cust_main.$_", @fields;
-}
-
 sub cust_header {
 
   warn "FS::svc_Common::cust_header called"
     if $DEBUG;
 
-  my $conf = new FS::Conf;
-
   my %header2method = (
-    'Customer'           => 'name',
-    'Cust#'              => 'custnum',
-    'Name'               => 'contact',
-    'Company'            => 'company',
-    '(bill) Customer'    => 'name',
-    '(service) Customer' => 'ship_name',
-    '(bill) Name'        => 'contact',
-    '(service) Name'     => 'ship_contact',
-    '(bill) Company'     => 'company',
-    '(service) Company'  => 'ship_company',
+    'Customer'                 => 'name',
+    'Cust#'                    => 'custnum',
+    'Name'                     => 'contact',
+    'Company'                  => 'company',
+    '(bill) Customer'          => 'name',
+    '(service) Customer'       => 'ship_name',
+    '(bill) Name'              => 'contact',
+    '(service) Name'           => 'ship_contact',
+    '(bill) Company'           => 'company',
+    '(service) Company'        => 'ship_company',
+    'Address 1'                => 'address1',
+    'Address 2'                => 'address2',
+    'City'                     => 'city',
+    'State'                    => 'state',
+    'Zip'                      => 'zip',
+    'Country'                  => 'country_full',
+    'Day phone'                => 'daytime', # XXX should use msgcat, but how?
+    'Night phone'              => 'night',   # XXX should use msgcat, but how?
+    'Invoicing email(s)'       => 'invoicing_list_emailonly',
   );
 
+  my $cust_fields;
   my @cust_header;
-  if (    $conf->exists('cust-fields')
-       && $conf->config('cust-fields') =~ /^([\w \|\#\(\)]+):/
-     )
-  {
-    warn "  found cust-fields configuration value"
-      if $DEBUG;
+  if ( @_ && $_[0] ) {
 
-    my $cust_fields = $1;
-     @cust_header = split(/ \| /, $cust_fields);
-     @cust_fields = map { $header2method{$_} } @cust_header;
-  } else { 
-    warn "  no cust-fields configuration value found; using default 'Customer'"
+    warn "  using supplied cust-fields override".
+          " (ignoring cust-fields config file)"
       if $DEBUG;
-    @cust_header = ( 'Customer' );
-    @cust_fields = ( 'name' );
+    $cust_fields = shift;
+
+  } else {
+
+    my $conf = new FS::Conf;
+    if (    $conf->exists('cust-fields')
+         && $conf->config('cust-fields') =~ /^([\w \|\#\(\)]+):?/
+       )
+    {
+      warn "  found cust-fields configuration value"
+        if $DEBUG;
+      $cust_fields = $1;
+    } else { 
+      warn "  no cust-fields configuration value found; using default 'Customer'"
+        if $DEBUG;
+      $cust_fields = 'Customer';
+    }
+  
   }
 
+  @cust_header = split(/ \| /, $cust_fields);
+  @cust_fields = map { $header2method{$_} } @cust_header;
+
   #my $svc_x = shift;
   @cust_header;
 }
 
-=item cust_fields
+=item cust_sql_fields [ CUST_FIELDS_VALUE ]
+
+Returns a list of fields for the SELECT portion of an SQL query.
+
+As with L<the cust_header subroutine|/cust_header>, the fields returned are
+defined by the supplied customer fields setting, or if no customer fields
+setting is supplied, the <B>cust-fields</B> configuration value. 
+
+=cut
+
+sub cust_sql_fields {
+
+  my @fields = qw( last first company );
+  push @fields, map "ship_$_", @fields;
+  push @fields, 'country';
+
+  cust_header(@_);
+  #inefficientish, but tiny lists and only run once per page
+  push @fields,
+    grep { my $field = $_; grep { $_ eq $field } @cust_fields }
+         qw( address1 address2 city state zip daytime night );
+
+  map "cust_main.$_", @fields;
+}
+
+=item cust_fields SVC_OBJECT [ CUST_FIELDS_VALUE ]
 
 Given a svc_ object that contains fields from cust_main (say, from a
 JOINed search.  See httemplate/search/svc_* for examples), returns an array
-of customer information according to the <B>cust-fields</B> configuration
-setting, or "(unlinked)" if this service is not linked to a customer.
+of customer information, or "(unlinked)" if this service is not linked to a
+customer.
+
+As with L<the cust_header subroutine|/cust_header>, the fields returned are
+defined by the supplied customer fields setting, or if no customer fields
+setting is supplied, the <B>cust-fields</B> configuration value. 
 
 =cut
 
@@ -107,7 +152,8 @@ sub cust_fields {
        "(cust_fields: @cust_fields)"
     if $DEBUG > 1;
 
-  cust_header() unless @cust_fields;
+  #cust_header(@_) unless @cust_fields; #now need to cache to keep cust_fields
+  #                                     #override incase we were passed as a sub
 
   my $seen_unlinked = 0;
   map { 
index a114c5a..aa4143d 100644 (file)
@@ -89,6 +89,50 @@ sub ship_contact {
     : $self->cust_unlinked_msg;
 }
 
+=item country_full
+
+Given an object that contains fields from cust_main (say, from a JOINed
+search; see httemplate/search/ for examples), returns the equivalent of the
+FS::cust_main I<country_full> method, or "(unlinked)" if this object is not
+linked to a customer.
+
+=cut
+
+sub country_full {
+  my $self = shift;
+  $self->cust_linked
+    ? FS::cust_main::country_full($self)
+    : $self->cust_unlinked_msg;
+}
+
+=item invoicing_list_emailonly
+
+Given an object that contains fields from cust_main (say, from a JOINed
+search; see httemplate/search/ for examples), returns the equivalent of the
+FS::cust_main I<country_full> method, or "(unlinked)" if this object is not
+linked to a customer.
+
+=cut
+
+sub invoicing_list_emailonly {
+  my $self = shift;
+  warn "invoicing_list_email only called on $self, ".
+       "custnum ". $self->custnum. "\n";
+  $self->cust_linked
+    ? FS::cust_main::invoicing_list_emailonly($self)
+    : $self->cust_unlinked_msg;
+}
+
+#read-only
+sub invoicing_list {
+  my $self = shift;
+  $self->cust_linked
+    ? FS::cust_main::invoicing_list($self)
+    : ();
+}
+
+=cut
+
 =back
 
 =head1 BUGS
index 783cc73..ed9f2cb 100644 (file)
@@ -2,6 +2,7 @@ package FS::cust_pkg;
 
 use strict;
 use vars qw(@ISA $disable_agentcheck @SVCDB_CANCEL_SEQ $DEBUG);
+use Tie::IxHash;
 use FS::UID qw( getotaker dbh );
 use FS::Misc qw( send_email );
 use FS::Record qw( qsearch qsearchs );
@@ -824,26 +825,45 @@ Returns a short status string for this package, currently:
 sub status {
   my $self = shift;
 
+  my $freq = length($self->freq) ? $self->freq : $self->part_pkg->freq;
+
   return 'cancelled' if $self->get('cancel');
   return 'suspended' if $self->susp;
   return 'not yet billed' unless $self->setup;
-  return 'one-time charge' if $self->part_pkg->freq =~ /^(0|$)/;
+  return 'one-time charge' if $freq =~ /^(0|$)/;
   return 'active';
 }
 
-=item statuscolor
+=item statuses
 
-Returns a hex triplet color string for this package's status.
+Class method that returns the list of possible status strings for pacakges
+(see L<the status method|/status>).  For example:
+
+  @statuses = FS::cust_pkg->statuses();
 
 =cut
 
-my %statuscolor = (
+tie my %statuscolor, 'Tie::IxHash', 
   'not yet billed'  => '000000',
   'one-time charge' => '000000',
   'active'          => '00CC00',
   'suspended'       => 'FF9900',
   'cancelled'       => 'FF0000',
-);
+;
+
+sub statuses {
+  my $self = shift; #could be class...
+  grep { $_ !~ /^(not yet billed)$/ } #this is a dumb status anyway
+                                      # mayble split btw one-time vs. recur
+    keys %statuscolor;
+}
+
+=item statuscolor
+
+Returns a hex triplet color string for this package's status.
+
+=cut
+
 sub statuscolor {
   my $self = shift;
   $statuscolor{$self->status};
@@ -1163,7 +1183,7 @@ sub reexport {
 
 =back
 
-=head1 CLASS METHOD
+=head1 CLASS METHODS
 
 =over 4
 
@@ -1178,6 +1198,17 @@ sub recurring_sql { "
              where cust_pkg.pkgpart = part_pkg.pkgpart )
 "; }
 
+=item onetime_sql
+
+Returns an SQL expression identifying one-time packages.
+
+=cut
+
+sub onetime_sql { "
+  '0' = ( select freq from part_pkg
+            where cust_pkg.pkgpart = part_pkg.pkgpart )
+"; }
+
 =item active_sql
 
 Returns an SQL expression identifying active packages.
@@ -1190,6 +1221,19 @@ sub active_sql { "
   AND ( cust_pkg.susp   IS NULL OR cust_pkg.susp   = 0 )
 "; }
 
+=item inactive_sql
+
+Returns an SQL expression identifying inactive packages (one-time packages
+that are otherwise unsuspended/uncancelled).
+
+=cut
+
+sub inactive_sql { "
+  ". $_[0]->onetime_sql(). "
+  AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )
+  AND ( cust_pkg.susp   IS NULL OR cust_pkg.susp   = 0 )
+"; }
+
 =item susp_sql
 =item suspended_sql
 
@@ -1198,11 +1242,13 @@ Returns an SQL expression identifying suspended packages.
 =cut
 
 sub suspended_sql { susp_sql(@_); }
-sub susp_sql { "
-  ". $_[0]->recurring_sql(). "
-  AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 )
-  AND cust_pkg.susp IS NOT NULL AND cust_pkg.susp != 0
-"; }
+sub susp_sql {
+  #$_[0]->recurring_sql(). ' AND '.
+  "
+        ( cust_pkg.cancel IS     NULL  OR cust_pkg.cancel = 0 )
+    AND   cust_pkg.susp   IS NOT NULL AND cust_pkg.susp  != 0
+  ";
+}
 
 =item cancel_sql
 =item cancelled_sql
@@ -1212,10 +1258,10 @@ Returns an SQL exprression identifying cancelled packages.
 =cut
 
 sub cancelled_sql { cancel_sql(@_); }
-sub cancel_sql { "
-  ". $_[0]->recurring_sql(). "
-  AND cust_pkg.cancel IS NOT NULL AND cust_pkg.cancel != 0
-"; }
+sub cancel_sql { 
+  #$_[0]->recurring_sql(). ' AND '.
+  "cust_pkg.cancel IS NOT NULL AND cust_pkg.cancel != 0";
+}
 
 =head1 SUBROUTINES
 
index 21f79a9..6008c0e 100644 (file)
@@ -55,25 +55,65 @@ function SafeOnsubmit() {
              #warn $i->key unless defined($type);
         %>
           <% if ( $type eq '' ) { %>
-            <font color="#ff0000">no type</font>
+
+               <font color="#ff0000">no type</font>
+
           <% } elsif ( $type eq 'textarea' ) { %>
-            <textarea name="<%= $i->key. $n %>" rows=5><%= "\n". join("\n", $conf->config($i->key) ) %></textarea>
+
+               <textarea name="<%= $i->key. $n %>" rows=5><%= "\n". join("\n", $conf->config($i->key) ) %></textarea>
+
           <% } elsif ( $type eq 'checkbox' ) { %>
-            <input name="<%= $i->key. $n %>" type="checkbox" value="1"<%= $conf->exists($i->key) ? ' CHECKED' : '' %>>
+
+               <input name="<%= $i->key. $n %>" type="checkbox" value="1"<%= $conf->exists($i->key) ? ' CHECKED' : '' %>>
+
           <% } elsif ( $type eq 'text' )  { %>
-            <input name="<%= $i->key. $n %>" type="<%= $type %>" value="<%= $conf->exists($i->key) ? $conf->config($i->key) : '' %>">
+
+               <input name="<%= $i->key. $n %>" type="<%= $type %>" value="<%= $conf->exists($i->key) ? $conf->config($i->key) : '' %>">
+
           <% } elsif ( $type eq 'select' || $type eq 'selectmultiple' )  { %>
-            <select name="<%= $i->key. $n %>" <%= $type eq 'selectmultiple' ? 'MULTIPLE' : '' %>>
-              <% my %saw;
-                 foreach my $value ( "", @{$i->select_enum} ) {
-                    local($^W)=0; next if $saw{$value}++; %>
-                <option value="<%= $value %>"<%= $value eq $conf->config($i->key) || ( $type eq 'selectmultiple' && grep { $_ eq $value } $conf->config($i->key) ) ? ' SELECTED' : '' %>><%= $value %>
-              <% } %>
-              <% if ( $conf->exists($i->key) && $conf->config($i->key) && ! grep { $conf->config($i->key) eq $_ } @{$i->select_enum}) { %>
-                <option value=<%= $conf->config($i->key) %> SELECTED><%= $conf->config($i->key) %>
+          
+               <select name="<%= $i->key. $n %>" <%= $type eq 'selectmultiple' ? 'MULTIPLE' : '' %>>
+               <% 
+                  my %hash = ();
+                  if ( $i->select_enum ) {
+                    tie %hash, 'Tie::IxHash',
+                      '' => '', map { $_ => $_ } @{ $i->select_enum };
+                  } elsif ( $i->select_hash ) {
+                    if ( ref($i->select_hash) eq 'ARRAY' ) {
+                      tie %hash, 'Tie::IxHash',
+                        '' => '', @{ $i->select_hash };
+                    } else {
+                      tie %hash, 'Tie::IxHash',
+                        '' => '', %{ $i->select_hash };
+                    }
+                  } else {
+                    %hash = ( '' => 'WARNING: neither select_enum nor select_hash specified in Conf.pm for configuration option "'. $i->key. '"' );
+                  }
+
+                  my %saw = ();
+                  foreach my $value ( keys %hash ) {
+                    local($^W)=0; next if $saw{$value}++;
+                    my $label = $hash{$value};
+               %>
+
+                    <option value="<%= $value %>"<%= $value eq $conf->config($i->key) || ( $type eq 'selectmultiple' && grep { $_ eq $value } $conf->config($i->key) ) ? ' SELECTED' : '' %>><%= $label %>
+
+               <% } %>
+
+              <% my $curvalue = $conf->config($i->key);
+                 if ( $conf->exists($i->key) && $curvalue
+                      && ! grep { $curvalue eq $_ } @{$i->select_enum}
+                    ) {
+              %>
+              
+                   <option value="<%= $conf->config($i->key) %>" SELECTED><%= exists( $hash{ $conf->config($i->key) } ) ? $hash{ $conf->config($i->key) } : $conf->config($i->key) %>
+
               <% } %>
+
             </select>
+
           <% } elsif ( $type eq 'select-sub' ) { %>
+
             <select name="<%= $i->key. $n %>">
               <option value="">
               <% my %options = &{$i->options_sub};
@@ -88,7 +128,9 @@ function SafeOnsubmit() {
                 <option value=<%= $conf->config($i->key) %> SELECTED><%= $conf->config($i->key) %>: <%= &{ $i->option_sub }( $conf->config($i->key) ) %>
               <% } %>
             </select>
-          <% } elsif ( $type eq 'editlist' )  { %>
+
+          <% } elsif ( $type eq 'editlist' ) { %>
+
             <script>
               function doremove<%= $i->key. $n %>() {
                 fromObject = document.OneTrueForm.<%= $i->key. $n %>;
@@ -167,9 +209,13 @@ function SafeOnsubmit() {
             <% } %>
             <td><input type="button" value="add" onClick="doadd<%= $i->key. $n %>(this.form)"></td>
             </tr></table>
+
           <% } else { %>
+
             <font color="#ff0000">unknown type <%= $type %></font>
+
           <% } %>
+
         <% $n++; } %>
       </td>
       <td><a name="<%= $i->key %>">
index c09fcee..8da197f 100644 (file)
@@ -85,7 +85,7 @@
     'All customer packages' => [ $fsurl.'search/cust_pkg.cgi?pkgnum', 'List all customer packages', ],
     'Suspended customer packages' => [ $fsurl.'search/cust_pkg.cgi?magic=suspended', 'List suspended packages' ],
     'Customer packages with unconfigured services' => [ $fsurl.'search/cust_pkg.cgi?APKG_pkgnum', 'List packages which have provisionable services' ],
-    'By next bill date' => [ $fsurl.'search/cust_pkg_report.cgi', 'Search packages by next bill date' ],
+    'Advanced package reports' => [ $fsurl.'search/report_cust_pkg.html', 'by agent, date range, status, package definition' ],
   ;
 
   tie my %report_financial, 'Tie::IxHash', 
 
        if ( ref($url_or_submenu) ) {
 
-         warn $item;
+         #warn $item;
 
          my( $subhtml, $submenuname ) = submenu($url_or_submenu, $item);
 
diff --git a/httemplate/elements/select-cust-fields.html b/httemplate/elements/select-cust-fields.html
new file mode 100644 (file)
index 0000000..4d47fbe
--- /dev/null
@@ -0,0 +1,23 @@
+<%
+  my( $cust_fields, %opt ) = @_;
+
+  use FS::ConfDefaults;
+  $opt{'avail_fields'} ||= [ FS::ConfDefaults->cust_fields_avail() ];
+
+  tie my %hash, 'Tie::IxHash', @{ $opt{'avail_fields'} };
+
+%>
+
+<SELECT NAME="cust_fields">
+
+  <OPTION VALUE="">(configured default)
+
+  <% 
+     foreach my $value ( keys %hash ) { %>
+
+       <OPTION VALUE="<%= $value %>"><%= $hash{$value} %>
+
+  <% } %>
+
+</SELECT>
+
diff --git a/httemplate/elements/select-cust_pkg-status.html b/httemplate/elements/select-cust_pkg-status.html
new file mode 100644 (file)
index 0000000..5da93fe
--- /dev/null
@@ -0,0 +1,19 @@
+<%
+  my( $status, %opt ) = @_;
+
+  $opt{'statuses'} ||= [ FS::cust_pkg->statuses() ]; # { disabled=>'' } )
+
+%>
+
+<SELECT NAME="status">
+
+  <OPTION VALUE="">all
+
+  <% foreach my $status ( @{ $opt{'statuses'} } ) { %>
+
+       <OPTION VALUE="<%= $status %>"><%= $status %>
+
+  <% } %>
+
+</SELECT>
+
diff --git a/httemplate/elements/tr-select-cust-fields.html b/httemplate/elements/tr-select-cust-fields.html
new file mode 100644 (file)
index 0000000..ca37e42
--- /dev/null
@@ -0,0 +1,14 @@
+<%
+  my( $cust_fields, %opt ) = @_;
+
+  use FS::ConfDefaults;
+  $opt{'avail_fields'} ||= [ FS::ConfDefaults->cust_fields_avail() ];
+
+%>
+
+<TR>
+  <TD ALIGN="right"><%= $opt{'label'} || 'Customer fields' %></TD>
+  <TD>
+    <%= include( '/elements/select-cust-fields.html', $cust_fields, %opt ) %>
+  </TD>
+</TR>
diff --git a/httemplate/elements/tr-select-cust_pkg-status.html b/httemplate/elements/tr-select-cust_pkg-status.html
new file mode 100644 (file)
index 0000000..1776851
--- /dev/null
@@ -0,0 +1,13 @@
+<%
+  my( $status, %opt ) = @_;
+
+  $opt{'statuses'} ||= [ FS::cust_pkg->statuses() ]; # { disabled=>'' } )
+
+%>
+
+<TR>
+  <TD ALIGN="right"><%= $opt{'label'} || 'Status' %></TD>
+  <TD>
+    <%= include( '/elements/select-cust_pkg-status.html', $status, %opt ) %>
+  </TD>
+</TR>
index cb82255..acd39b0 100644 (file)
@@ -18,6 +18,7 @@ if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
 }
 my $title = $sel_agent ? $sel_agent->agent.' ' : '';
 
+#false lazinessish w/search/cust_pkg.cgi
 my $classnum = 0;
 my @pkg_class = ();
 if ( $cgi->param('classnum') =~ /^(\d*)$/ ) {
@@ -34,6 +35,7 @@ if ( $cgi->param('classnum') =~ /^(\d*)$/ ) {
     push @pkg_class, '(empty class)';
   }
 }
+#eslaf
 
 my $hue = 0;
 #my $hue_increment = 170;
diff --git a/httemplate/search/cust_pkg_report.cgi b/httemplate/search/cust_pkg_report.cgi
deleted file mode 100755 (executable)
index d9aada5..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<%= include('/elements/header.html', 'Packages' ) %>
-
-<FORM ACTION="cust_pkg.cgi" METHOD="GET">
-<INPUT TYPE="hidden" NAME="magic" VALUE="bill">
-
-Return packages with next bill date:
-<BR><BR>
-
-  <TABLE>
-    <%= include( '/elements/tr-input-beginning_ending.html' ) %>
-    <%= include( '/elements/tr-select-agent.html',
-                   $cgi->param('agentnum'),
-               )
-    %>
-  </TABLE>
-
-<BR>
-<INPUT TYPE="submit" VALUE="Get Report">
-
-</FORM>
-
-<%= include('/elements/footer.html') %>
diff --git a/httemplate/search/report_cust_pkg.html b/httemplate/search/report_cust_pkg.html
new file mode 100755 (executable)
index 0000000..98e9121
--- /dev/null
@@ -0,0 +1,47 @@
+<%= include('/elements/header.html', 'Package Report' ) %>
+
+<FORM ACTION="cust_pkg.cgi" METHOD="GET">
+<INPUT TYPE="hidden" NAME="magic" VALUE="bill">
+
+  <TABLE BGCOLOR="#cccccc" CELLSPACING=0>
+
+    <TR>
+      <TH BGCOLOR="#e8e8e8" COLSPAN=2 ALIGN="left"><FONT SIZE="+1">Search options</FONT></TH>
+    </TR>
+    <%= include( '/elements/tr-select-agent.html',
+                   $cgi->param('agentnum'),
+               )
+    %>
+    <%= include( '/elements/tr-select-cust_pkg-status.html' ) %>
+    <%= include( '/elements/tr-select-pkg_class.html', '',
+                   'pre_options' => [ '0' => 'all' ],
+                   'empty_label' => '(empty class)',
+               )
+    %>
+    <% #include( '/elements/tr-selectmultiple-part_pkg.html' ) %>
+    <TR>
+      <TD ALIGN="right" VALIGN="center">Next bill date</TD>
+      <TD>
+        <TABLE>
+          <%= include( '/elements/tr-input-beginning_ending.html' ) %>
+        </TABLE>
+      </TD>
+    </TR>
+    
+    <TR>
+      <TH BGCOLOR="#e8e8e8" COLSPAN=2>&nbsp;</TH>
+    </TR>
+
+    <TR>
+      <TH BGCOLOR="#e8e8e8" COLSPAN=2 ALIGN="left"><FONT SIZE="+1">Display options</FONT></TH>
+    </TR>
+    <%= include( '/elements/tr-select-cust-fields.html' ) %>
+    
+  </TABLE>
+
+<BR>
+<INPUT TYPE="submit" VALUE="Get Report">
+
+</FORM>
+
+<%= include('/elements/footer.html') %>
index 7aba118..4837155 100644 (file)
@@ -114,7 +114,7 @@ Service address
 </TR>
 <TR>
   <TD ALIGN="right">Country</TD>
-  <TD BGCOLOR="#ffffff"><%= $cust_main->get("${pre}country") %></TD>
+  <TD BGCOLOR="#ffffff"><%= code2country( $cust_main->get("${pre}country") ) %></TD>
 </TR>
 <TR>
   <TD ALIGN="right"><%= $daytime_label %></TD>