move account search (httemplate/search/svc_acct.cgi) to new template, cust-fields...
authorivan <ivan>
Thu, 14 Jul 2005 10:52:46 +0000 (10:52 +0000)
committerivan <ivan>
Thu, 14 Jul 2005 10:52:46 +0000 (10:52 +0000)
21 files changed:
Changes.1.5.8 [new file with mode: 0644]
FS/FS/Conf.pm
FS/FS/UI/Web.pm
FS/FS/cust_bill.pm
FS/FS/cust_bill_event.pm
FS/FS/cust_credit.pm
FS/FS/cust_main.pm
FS/FS/cust_main_Mixin.pm [new file with mode: 0644]
FS/FS/cust_pay.pm
FS/FS/svc_Common.pm
FS/MANIFEST
FS/t/cust_main_Mixin.t [new file with mode: 0644]
httemplate/search/cust_bill_event.cgi
httemplate/search/cust_credit.html
httemplate/search/cust_pay.cgi
httemplate/search/elements/search.html
httemplate/search/report_receivables.cgi
httemplate/search/svc_acct.cgi
httemplate/search/svc_domain.cgi
httemplate/search/svc_forward.cgi
httemplate/search/svc_www.cgi

diff --git a/Changes.1.5.8 b/Changes.1.5.8
new file mode 100644 (file)
index 0000000..113078b
--- /dev/null
@@ -0,0 +1,2 @@
+- move account search (httemplate/search/svc_acct.cgi) to new template
+- cust-fields configuration value to control which customer fields are shown on reports
index d78135a..78b1f61 100644 (file)
@@ -1545,6 +1545,23 @@ httemplate/docs/config.html
     'type'        => 'checkbox',
   },
 
+  {
+    'key'         => 'cust-fields',
+    'section'     => 'UI',
+    'description' => 'Which customer fields to display on reports',
+    '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)',
+    ],
+  },
+
 );
 
 1;
index e701141..716fd86 100644 (file)
@@ -1,5 +1,8 @@
 package FS::UI::Web;
 
+use FS::Conf;
+use FS::Record qw(dbdef);
+
 #use vars qw(@ISA);
 #use FS::UI
 #@ISA = qw( FS::UI );
@@ -18,7 +21,102 @@ sub parse_beginning_ending {
   ( $beginning, $ending );
 }
 
+###
+# cust_main report methods
+###
+
+=item cust_header
+
+Returns an array of customer information headers according to the
+B<cust-fields> configuration setting.
+
+=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',
+  );
+
+  my @cust_header;
+  if (    $conf->exists('cust-fields')
+       && $conf->config('cust-fields') =~ /^([\w \|\#\(\)]+):/
+     )
+  {
+    warn "  found cust-fields configuration value"
+      if $DEBUG;
+
+    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'"
+      if $DEBUG;
+    @cust_header = ( 'Customer' );
+    @cust_fields = ( 'cust_name' );
+  }
+
+  #my $svc_x = shift;
+  @cust_header;
+}
+
+=item cust_fields
+
+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.
+
+=cut
+
+sub cust_fields {
+  my $svc_x = shift;
+  warn "FS::svc_Common::cust_fields called for $svc_x ".
+       "(cust_fields: @cust_fields)"
+    if $DEBUG > 1;
+
+  cust_header() unless @cust_fields;
+
+  my $seen_unlinked = 0;
+  map { 
+    if ( $svc_x->custnum ) {
+      warn "  $svc_x -> $_"
+        if $DEBUG > 1;
+      $svc_x->$_(@_);
+    } else {
+      warn "  ($svc_x unlinked)"
+        if $DEBUG > 1;
+      $seen_unlinked++ ? '' : '(unlinked)';
+    }
+  } @cust_fields;
+}
+
+###
 # begin JSRPC code...
+###
 
 package FS::UI::Web::JSRPC;
 
index b9a99c9..d9e04de 100644 (file)
@@ -11,8 +11,9 @@ use String::ShellQuote;
 use HTML::Entities;
 use Locale::Country;
 use FS::UID qw( datasrc );
-use FS::Record qw( qsearch qsearchs );
 use FS::Misc qw( send_email send_fax );
+use FS::Record qw( qsearch qsearchs );
+use FS::cust_main_Mixin;
 use FS::cust_main;
 use FS::cust_bill_pkg;
 use FS::cust_credit;
@@ -25,7 +26,7 @@ use FS::part_pkg;
 use FS::cust_bill_pay;
 use FS::part_bill_event;
 
-@ISA = qw( FS::Record );
+@ISA = qw( FS::cust_main_Mixin FS::Record );
 
 $DEBUG = 0;
 
@@ -105,6 +106,13 @@ Invoices are normally created by calling the bill method of a customer object
 
 sub table { 'cust_bill'; }
 
+sub cust_linked { $_[0]->cust_main_custnum; } 
+sub cust_unlinked_msg {
+  my $self = shift;
+  "WARNING: can't find cust_main.custnum ". $self->custnum.
+  ' (cust_bill.invnum '. $self->invnum. ')';
+}
+
 =item insert
 
 Adds this invoice to the database ("Posts" the invoice).  If there is an error,
index 7b98139..128e5a5 100644 (file)
@@ -3,10 +3,11 @@ package FS::cust_bill_event;
 use strict;
 use vars qw( @ISA $DEBUG );
 use FS::Record qw( qsearch qsearchs );
+use FS::cust_main_Mixin;
 use FS::cust_bill;
 use FS::part_bill_event;
 
-@ISA = qw(FS::Record);
+@ISA = qw(FS::cust_main_Mixin FS::Record);
 
 $DEBUG = 0;
 
@@ -70,6 +71,13 @@ points to.  You can ask the object for a copy with the I<hash> method.
 
 sub table { 'cust_bill_event'; }
 
+sub cust_linked { $_[0]->cust_main_custnum; } 
+sub cust_unlinked_msg {
+  my $self = shift;
+  "WARNING: can't find cust_main.custnum ". $self->custnum.
+  ' (cust_bill.invnum '. $self->invnum. ')';
+}
+
 =item insert
 
 Adds this record to the database.  If there is an error, returns the error,
index 026b92e..9cc92d2 100644 (file)
@@ -4,13 +4,14 @@ use strict;
 use vars qw( @ISA $conf $unsuspendauto );
 use Date::Format;
 use FS::UID qw( dbh getotaker );
-use FS::Record qw( qsearch qsearchs );
 use FS::Misc qw(send_email);
+use FS::Record qw( qsearch qsearchs );
+use FS::cust_main_Mixin;
 use FS::cust_main;
 use FS::cust_refund;
 use FS::cust_credit_bill;
 
-@ISA = qw( FS::Record );
+@ISA = qw( FS::cust_main_Mixin FS::Record );
 
 #ask FS::UID to run this stuff for us later
 $FS::UID::callback{'FS::cust_credit'} = sub { 
@@ -75,6 +76,12 @@ Creates a new credit.  To add the credit to the database, see L<"insert">.
 =cut
 
 sub table { 'cust_credit'; }
+sub cust_linked { $_[0]->cust_main_custnum; } 
+sub cust_unlinked_msg {
+  my $self = shift;
+  "WARNING: can't find cust_main.custnum ". $self->custnum.
+  ' (cust_credit.crednum '. $self->crednum. ')';
+}
 
 =item insert
 
index 1bbf191..ab2c74a 100644 (file)
@@ -3160,11 +3160,53 @@ Returns a name string for this customer, either "Company (Last, First)" or
 
 sub name {
   my $self = shift;
-  my $name = $self->get('last'). ', '. $self->first;
+  my $name = $self->bill_contact;
   $name = $self->company. " ($name)" if $self->company;
   $name;
 }
 
+=item ship_name
+
+Returns a name string for this (service/shipping) contact, either
+"Company (Last, First)" or "Last, First".
+
+=cut
+
+sub ship_name {
+  my $self = shift;
+  if ( $self->get('ship_last') ) { 
+    my $name = $self->ship_contact;
+    $name = $self->ship_company. " ($name)" if $self->ship_company;
+    $name;
+  } else {
+    $self->name;
+  }
+}
+
+=item contact
+
+Returns this customer's full (billing) contact name only, "Last, First"
+
+=cut
+
+sub contact {
+  my $self = shift;
+  $self->get('last'). ', '. $self->first;
+}
+
+=item ship_contact
+
+Returns this customer's full (shipping) contact name only, "Last, First"
+
+=cut
+
+sub ship_contact {
+  my $self = shift;
+  $self->get('ship_last')
+    ? $self->get('ship_last'). ', '. $self->ship_first
+    : $self->bill_contact;
+}
+
 =item status
 
 Returns a status string for this customer, currently:
diff --git a/FS/FS/cust_main_Mixin.pm b/FS/FS/cust_main_Mixin.pm
new file mode 100644 (file)
index 0000000..a114c5a
--- /dev/null
@@ -0,0 +1,103 @@
+package FS::cust_main_Mixin;
+
+use strict;
+use FS::cust_main;
+
+=head1 NAME
+
+FS::cust_main_Mixin - Mixin class for records that contain fields from cust_main
+
+=head1 SYNOPSIS
+
+package FS::some_table;
+use vars qw(@ISA);
+@ISA = qw( FS::cust_main_Mixin FS::Record );
+
+=head1 DESCRIPTION
+
+This is a mixin class for records that contain fields from the cust_main table,
+for example, from a JOINed search.  See httemplate/search/ for examples.
+
+=head1 METHODS
+
+=over 4
+
+=item name
+
+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<name> method, or "(unlinked)" if this object is not linked to
+a customer.
+
+=cut
+
+sub cust_unlinked_msg { '(unlinked)'; }
+sub cust_linked { $_[0]->custnum; }
+
+sub name {
+  my $self = shift;
+  $self->cust_linked
+    ? FS::cust_main::name($self)
+    : $self->cust_unlinked_msg;
+}
+
+=item ship_name
+
+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<ship_name> method, or "(unlinked)" if this object is not
+linked to a customer.
+
+=cut
+
+sub ship_name {
+  my $self = shift;
+  $self->cust_linked
+    ? FS::cust_main::ship_name($self)
+    : $self->cust_unlinked_msg;
+}
+
+=item contact
+
+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<contact> method, or "(unlinked)" if this object is not linked
+to a customer.
+
+=cut
+
+sub contact {
+  my $self = shift;
+  $self->cust_linked
+    ? FS::cust_main::contact($self)
+    : $self->cust_unlinked_msg;
+}
+
+=item ship_contact
+
+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<ship_contact> method, or "(unlinked)" if this object is not
+linked to a customer.
+
+=cut
+
+sub ship_contact {
+  my $self = shift;
+  $self->cust_linked
+    ? FS::cust_main::ship_contact($self)
+    : $self->cust_unlinked_msg;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::cust_main>, L<FS::Record>
+
+=cut
+
+1;
+
index ccf991d..0f872a4 100644 (file)
@@ -5,15 +5,16 @@ use vars qw( @ISA $conf $unsuspendauto $ignore_noapply );
 use Date::Format;
 use Business::CreditCard;
 use Text::Template;
-use FS::Record qw( dbh qsearch qsearchs );
 use FS::Misc qw(send_email);
+use FS::Record qw( dbh qsearch qsearchs );
+use FS::cust_main_Mixin;
 use FS::cust_bill;
 use FS::cust_bill_pay;
 use FS::cust_pay_refund;
 use FS::cust_main;
 use FS::cust_pay_void;
 
-@ISA = qw( FS::Record );
+@ISA = qw( FS::cust_main_Mixin FS::Record );
 
 $ignore_noapply = 0;
 
@@ -81,6 +82,12 @@ Creates a new payment.  To add the payment to the databse, see L<"insert">.
 =cut
 
 sub table { 'cust_pay'; }
+sub cust_linked { $_[0]->cust_main_custnum; } 
+sub cust_unlinked_msg {
+  my $self = shift;
+  "WARNING: can't find cust_main.custnum ". $self->custnum.
+  ' (cust_pay.paynum '. $self->paynum. ')';
+}
 
 =item insert
 
index 80d5e21..205c330 100644 (file)
@@ -3,15 +3,16 @@ package FS::svc_Common;
 use strict;
 use vars qw( @ISA $noexport_hack $DEBUG );
 use FS::Record qw( qsearch qsearchs fields dbh );
+use FS::cust_main_Mixin;
 use FS::cust_svc;
 use FS::part_svc;
 use FS::queue;
 use FS::cust_main;
 
-@ISA = qw( FS::Record );
+@ISA = qw( FS::cust_main_Mixin FS::Record );
 
-$DEBUG = 0;
-#$DEBUG = 1;
+#$DEBUG = 0;
+$DEBUG = 1;
 
 =head1 NAME
 
@@ -547,20 +548,6 @@ sub clone_kludge_unsuspend {
   shift;
 }
 
-=item cust_name
-
-Given a svc_ object that contains fields from cust_main (say, from a
-JOINed search.  See httemplate/search/svc_* for examples), returns the 
-equivalent of "$svc_x->cust_svc->cust_pkg->name" (but much more efficient),
-or "(unlinked)" if this service is not linked to a customer.
-
-=cut
-
-sub cust_name {
-  my $svc_x = shift;
-  $svc_x->custnum ? FS::cust_main::name($svc_x) : '(unlinked)';
-}
-
 =back
 
 =head1 BUGS
index 971fe40..fa2cef0 100644 (file)
@@ -52,6 +52,7 @@ FS/cust_bill_pkg_detail.pm
 FS/cust_credit.pm
 FS/cust_credit_bill.pm
 FS/cust_main.pm
+FS/cust_main_Mixin.pm
 FS/cust_main_county.pm
 FS/cust_main_invoice.pm
 FS/cust_pay.pm
@@ -177,6 +178,7 @@ t/cust_credit.t
 t/cust_credit_bill.t
 t/cust_credit_refund.t
 t/cust_main.t
+t/cust_main_Mixin.t
 t/cust_main_county.t
 t/cust_main_invoice.t
 t/cust_pay.t
diff --git a/FS/t/cust_main_Mixin.t b/FS/t/cust_main_Mixin.t
new file mode 100644 (file)
index 0000000..c8b9291
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_main_Mixin;
+$loaded=1;
+print "ok 1\n";
index f34bb68..df4dcbf 100644 (file)
@@ -27,8 +27,8 @@ my $sql_query = {
                    'part_bill_event.event',
                    'cust_bill.custnum',
                    'cust_bill._date AS cust_bill_date',
-                   map "cust_main.$_", qw(last first company)
-
+                   'cust_main.custnum AS cust_main_custnum',
+                   FS::UI::Web::cust_sql_fields(),
                  ),
   'extra_sql' => "$where ORDER BY _date ASC",
   'addl_from' => 'LEFT JOIN part_bill_event USING ( eventpart ) '.
@@ -71,6 +71,13 @@ push @$menubar, 'Re-fax these events' =>
                   "javascript:fax_process()"
   if $conf->exists('hylafax');
 
+my $link_cust = sub {
+  my $cust_bill_event = shift;
+  $cust_bill_event->cust_main_custnum
+    ? [ "${p}view/cust_main.cgi?", 'custnum' ]
+    : '';
+};
+
 %><%= include( 'elements/search.html',
                  'title'       => $title,
                  'html_init'   => $html_init,
@@ -78,9 +85,12 @@ push @$menubar, 'Re-fax these events' =>
                  'name'        => 'billing events',
                  'query'       => $sql_query,
                  'count_query' => $count_sql,
-                 'header'      => [ qw( Event Date Status ),
+                 'header'      => [ 'Event',
+                                    'Date',
+                                    'Status',
                                     #'Inv #', 'Inv Date', 'Cust #',
-                                    'Invoice', 'Cust #',
+                                    'Invoice',
+                                    FS::UI::Web::cust_header(),
                                   ],
                  'fields' => [
                                'event',
@@ -99,9 +109,7 @@ push @$menubar, 'Re-fax these events' =>
                                        time2str("%D", $_[0]->cust_bill_date).
                                      ')';
                                    },
-                               sub { FS::cust_main::name($_[0]) },
-
-
+                               \&FS::UI::Web::cust_fields,
                              ],
                  'links' => [
                               '',
@@ -113,8 +121,7 @@ push @$menubar, 'Re-fax these events' =>
                                 $template .= '-' if $template;
                                 [ "${p}view/cust_bill.cgi?$template", 'invnum'];
                               },
-                              [ "${p}view/cust_main.cgi?", 'custnum' ],
-                              [ "${p}view/cust_main.cgi?", 'custnum' ],
+                              ( map { $link_cust } FS::UI::Web::cust_header() ),
                             ],
              )
 %>
index b978e62..4b3da60 100755 (executable)
 
    my $sql_query   = {
      'table'     => 'cust_credit',
-     'select'    => 'cust_credit.*, cust_main.last, cust_main.first, cust_main.company',
+     'select'    => join(', ',
+                      'cust_credit.*',
+                      'cust_main.custnum as cust_main_custnum',
+                      FS::UI::Web::cust_sql_fields(),
+                    ),
      'hashref'   => {},
      'extra_sql' => $where,
      'addl_from' => 'LEFT JOIN cust_main USING ( custnum )',
    };
 
-   my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ];
+     my $clink = sub {
+       my $cust_bill = shift;
+       $cust_bill->cust_main_custnum
+         ? [ "${p}view/cust_main.cgi?", 'custnum' ]
+         : '';
+     };
 
 %><%= include( 'elements/search.html',
                  'title'       => $title,
                  'count_query' => $count_query,
                  'count_addl'  => [ '$%.2f total credited', ],
                  #'redirect'    => $link,
-                 'header'      =>
-                   [ qw(Amount Date), 'Cust #', 'Contact name',
-                     qw(Company By Reason) ],
+                 'header'      => [ 'Amount',
+                                    'Date',
+                                    FS::UI::Web::cust_header(),
+                                    'By',
+                                    'Reason'
+                                  ],
                  'fields'      => [
                    #'crednum',
                    sub { sprintf('$%.2f', shift->amount ) },
                    sub { time2str('%b %d %Y', shift->_date ) },
-                   'custnum',
-                   sub { $_[0]->get('last'). ', '. $_[0]->first; },
-                   'company',
+                   \&FS::UI::Web::cust_fields,
                    'otaker',
                    'reason',
                  ],
-                 'align' => 'rrrllll',
+                 #'align' => 'rrrllll',
+                 'align' => 'rr',
                  'links' => [
                    '',
                    '',
-                   $clink,
-                   $clink,
-                   $clink,
+                   ( map { $clink } FS::UI::Web::cust_header() ),
                    '',
                    '',
                  ],
index c23653a..a680479 100755 (executable)
    
      $sql_query = {
        'table'     => 'cust_pay',
-       'select'    => 'cust_pay.*, cust_main.last, cust_main.first, cust_main.company',
+       'select'    => join(', ',
+                        'cust_pay.*',
+                        'cust_main.custnum as cust_main_custnum',
+                        FS::UI::Web::cust_sql_fields(),
+                      ),
        'hashref'   => {},
        'extra_sql' => "$search ORDER BY _date",
        'addl_from' => 'LEFT JOIN cust_main USING ( custnum )',
    
    }
 
-   my $link = [ "${p}view/cust_main.cgi?", 'custnum' ];
+   my $link = sub {
+     my $cust_pay = shift;
+     $cust_pay->cust_main_custnum
+       ? [ "${p}view/cust_main.cgi?", 'custnum' ] 
+       : '';
+   };
 
 %><%= include( 'elements/search.html',
                  'title'       => $title,
                  'query'       => $sql_query,
                  'count_query' => $count_query,
                  'count_addl'  => [ '$%.2f total paid', ],
-                 'header'      =>
-                   [ qw(Payment Amount Date), 'Cust #', 'Contact name',
-                     'Company', ],
+                 'header'      => [ 'Payment',
+                                    'Amount',
+                                    'Date',
+                                    FS::UI::Web::cust_header(),
+                                  ],
                  'fields'      => [
                    sub {
                      my $cust_pay = shift;
                        'E-check acct#'. $cust_pay->payinfo;
                      } elsif ( $cust_pay->payby eq 'BILL' ) {
                        'Check #'. $cust_pay->payinfo;
+                     } elsif ( $cust_pay->payby eq 'PREP' ) {
+                       'Prepaid card #'. $cust_pay->payinfo;
                      } else {
                        $cust_pay->payby. ' '. $cust_pay->payinfo;
                      }
                    },
                    sub { sprintf('$%.2f', shift->paid ) },
                    sub { time2str('%b %d %Y', shift->_date ) },
-                   'custnum',
-                   sub { $_[0]->get('last'). ', '. $_[0]->first; },
-                   'company',
+                   \&FS::UI::Web::cust_fields,
                  ],
-                 'align' => 'lrrrll',
+                 #'align' => 'lrrrll',
+                 'align' => 'rrr',
                  'links' => [
                    '',
                    '',
                    '',
-                   $link,
-                   $link,
-                   $link,
+                   ( map { $link } FS::UI::Web::cust_header() ),
                  ],
       )
 %>
index 47d6194..78754fe 100644 (file)
           #  }
           #}
           if ( ref($field) eq 'CODE' ) {
-            $worksheet->write($r, $c++, &{$field}($row) );
+            foreach my $value ( &{$field}($row) ) {
+              $worksheet->write($r, $c++, $value );
+            }
           } else {
             $worksheet->write($r, $c++, $row->$field() );
           }
                         my $sizes  = $opt{'size'}  ? [ @{$opt{'size'}}  ] : [];
                         my $styles = $opt{'style'} ? [ @{$opt{'style'}} ] : [];
 
-                        foreach my $field ( @{$opt{'fields'}} ) {
+                        foreach my $field (
+
+                          map {
+                                if ( ref($_) eq 'CODE' ) {
+                                  &{$_}($row);
+                                } else {
+                                  $row->$_();
+                                }
+                              }
+                          @{$opt{'fields'}}
+
+                        ) {
 
                           my $align = $aligns ? shift @$aligns : '';
                           $align = " ALIGN=$align" if $align;
                           }
 
                        %>
-                       <% if ( ref($field) eq 'CODE' ) { %>
-                         <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>"<%= $align %>><%= $font %><%= $a %><%= $s %><%= &{$field}($row) %><%= $es %><%= $a ? '</A>' : '' %><%= $font ? '</FONT>' : '' %></TD>
-                       <% } else { %>
-                         <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>"<%= $align %>><%= $font %><%= $a %><%= $s %><%= $row->$field() %><%= $es %><%= $a ? '</A>' : '' %><%= $font ? '</FONT>' : '' %></TD>
-                       <% } %>
+                       <TD CLASS="grid" BGCOLOR="<%= $bgcolor %>"<%= $align %>><%= $font %><%= $a %><%= $s %><%= $field %><%= $es %><%= $a ? '</A>' : '' %><%= $font ? '</FONT>' : '' %></TD>
                      <% } %>
                    <% } else { %>
                      <% foreach ( @$row ) { %>
index 82ce5d7..535afcc 100755 (executable)
@@ -118,14 +118,16 @@ END
   my $conf = new FS::Conf;
   my $money_char = $conf->config('money_char') || '$';
 
+  my $align = join('', map { /#/ ? 'r' : 'l' } FS::UI::Web::cust_header() ).
+             'crrrrr';
+
 %><%= include( 'elements/search.html',
                  'title'       => 'Accounts Receivable Aging Summary',
                  'name'        => 'customers',
                  'query'       => $sql_query,
                  'count_query' => $count_sql,
                  'header'      => [
-                                    '#',
-                                    'Customer',
+                                    FS::UI::Web::cust_header(),
                                     'Status', # (me)',
                                     #'Status', # (cust_main)',
                                     '0-30',
@@ -135,8 +137,12 @@ END
                                     'Total',
                                   ],
                  'footer'      => [
-                                    '',
                                     'Total',
+                                    ( map '',
+                                          ( 1 .. 
+                                            scalar(FS::UI::Web::cust_header()-1)
+                                          )
+                                    ),
                                     '',
                                     #'',
                                     sprintf( $money_char.'%.2f',
@@ -151,8 +157,7 @@ END
                                              $row->{'owed_total'} ),
                                   ],
                  'fields'      => [
-                                    'custnum',
-                                    'name',
+                                    \&FS::UI::Web::cust_fields,
                                     sub {
                                           my $row = shift;
                                           my $status = 'Cancelled';
@@ -191,14 +196,15 @@ END
                                     '',
                                   ],
                  #'align'       => 'rlccrrrrr',
-                 'align'       => 'rlcrrrrr',
+                 'align'       => $align,
                  #'size'        => [ '', '', '-1', '-1', '', '', '', '',  '', ],
                  #'style'       => [ '', '',  'b',  'b', '', '', '', '', 'b', ],
-                 'size'        => [ '', '', '-1', '', '', '', '',  '', ],
-                 'style'       => [ '', '',  'b', '', '', '', '', 'b', ],
+                 'size'        => [ ( map '', FS::UI::Web::cust_header() ),
+                                    '-1', '', '', '', '',  '', ],
+                 'style'       => [ ( map '', FS::UI::Web::cust_header() ),
+                                    'b', '', '', '', '', 'b', ],
                  'color'       => [
-                                    '',
-                                    '',
+                                    ( map '', FS::UI::Web::cust_header() ),
                                     sub {  
                                           my $row = shift;
                                           my $status = 'Cancelled';
index 1e4a03d..d4565ae 100755 (executable)
 <%
 
-my $conf = new FS::Conf;
-my $maxrecords = $conf->config('maxsearchrecordsperpage');
-
-my $orderby = ''; #removeme
-
-my $limit = '';
-$limit .= "LIMIT $maxrecords" if $maxrecords;
-
-my $offset = $cgi->param('offset') || 0;
-$limit .= " OFFSET $offset" if $offset;
-
-my $total;
+my $orderby = 'ORDER BY svcnum';
 
 my($query)=$cgi->keywords;
 $query ||= ''; #to avoid use of unitialized value errors
 
-my $unlinked = '';
+my $cjoin = '';
+my @extra_sql = ();
 if ( $query =~ /^UN_(.*)$/ ) {
   $query = $1;
-  my $empty = driver_name eq 'Pg' ? qq('') : qq("");
-  if ( driver_name eq 'mysql' ) {
-    $unlinked = "LEFT JOIN cust_svc ON cust_svc.svcnum = svc_acct.svcnum
-                 WHERE cust_svc.pkgnum IS NULL
-                    OR cust_svc.pkgnum = 0
-                    OR cust_svc.pkgnum = $empty";
-  } else {
-    $unlinked = "
-      WHERE 0 <
-        ( SELECT count(*) FROM cust_svc
-            WHERE cust_svc.svcnum = svc_acct.svcnum
-              AND ( pkgnum IS NULL OR pkgnum = 0 )
-        )
-    ";
-  }
+  $cjoin = 'LEFT JOIN cust_svc USING ( svcnum )';
+  push @extra_sql, 'pkgnum IS NULL';
 }
 
-my $tblname = driver_name eq 'mysql' ? 'svc_acct.' : '';
-my(@svc_acct, $sortby);
 if ( $query eq 'svcnum' ) {
-  $sortby=\*svcnum_sort;
-  $orderby = "ORDER BY ${tblname}svcnum";
+  #$orderby = "ORDER BY svcnum";
 } elsif ( $query eq 'username' ) {
-  $sortby=\*username_sort;
-  $orderby = "ORDER BY ${tblname}username";
+  $orderby = "ORDER BY LOWER(username)";
 } elsif ( $query eq 'uid' ) {
-  $sortby=\*uid_sort;
-  $orderby = ( $unlinked ? ' AND' : ' WHERE' ).
-             " ${tblname}uid IS NOT NULL ORDER BY ${tblname}uid";
+  $orderby = "ORDER BY uid";
+  push @extra_sql, "uid IS NOT NULL";
 } elsif ( $cgi->param('popnum') =~ /^(\d+)$/ ) {
-  $unlinked .= ( $unlinked ? 'AND' : 'WHERE' ).
-               " popnum = $1";
-  $sortby=\*username_sort;
-  $orderby = "ORDER BY ${tblname}username";
+  push @extra_sql, "popnum = $1";
+  $orderby = "ORDER BY LOWER(username)";
 } elsif ( $cgi->param('svcpart') =~ /^(\d+)$/ ) {
-  $unlinked .= ( $unlinked ? ' AND' : ' WHERE' ).
-               " $1 = ( SELECT svcpart FROM cust_svc ".
-               "        WHERE cust_svc.svcnum = svc_acct.svcnum ) ";
-  $sortby=\*uid_sort;
-  #$sortby=\*svcnum_sort;
+  $cjoin ||= 'LEFT JOIN cust_svc USING ( svcnum )';
+  push @extra_sql, "svcpart = $1";
+  $orderby = "ORDER BY uid";
+  #$orderby = "ORDER BY svcnum";
 } else {
-  $sortby=\*uid_sort;
-  @svc_acct = @{&usernamesearch};
-}
-
-
-if (    $query eq 'svcnum'
-     || $query eq 'username'
-     || $query eq 'uid'
-     || $cgi->param('popnum') =~ /^(\d+)$/
-     || $cgi->param('svcpart') =~ /^(\d+)$/
-   ) {
-
-  my $statement = "SELECT COUNT(*) FROM svc_acct $unlinked";
-  my $sth = dbh->prepare($statement)
-    or die dbh->errstr. " doing $statement";
-  $sth->execute or die "Error executing \"$statement\": ". $sth->errstr;
-
-  $total = $sth->fetchrow_arrayref->[0];
-
-  @svc_acct = qsearch('svc_acct', {}, '', "$unlinked $orderby $limit");
-
-}
-
-if ( scalar(@svc_acct) == 1 ) {
-  my($svcnum)=$svc_acct[0]->svcnum;
-  print $cgi->redirect(popurl(2). "view/svc_acct.cgi?$svcnum");  #redirect
-  #exit;
-} elsif ( scalar(@svc_acct) == 0 ) { #error
-%>
-<!-- mason kludge -->
-<%
-  idiot("Account not found");
-} else {
-%>
-<!-- mason kludge -->
-<%
-  $total ||= scalar(@svc_acct);
-
-  #begin pager
-  my $pager = '';
-  if ( $total != scalar(@svc_acct) && $maxrecords ) {
-    unless ( $offset == 0 ) {
-      $cgi->param('offset', $offset - $maxrecords);
-      $pager .= '<A HREF="'. $cgi->self_url.
-                '"><B><FONT SIZE="+1">Previous</FONT></B></A> ';
-    }
-    my $poff;
-    my $page;
-    for ( $poff = 0; $poff < $total; $poff += $maxrecords ) {
-      $page++;
-      if ( $offset == $poff ) {
-        $pager .= qq!<FONT SIZE="+2">$page</FONT> !;
-      } else {
-        $cgi->param('offset', $poff);
-        $pager .= qq!<A HREF="!. $cgi->self_url. qq!">$page</A> !;
-      }
-    }
-    unless ( $offset + $maxrecords > $total ) {
-      $cgi->param('offset', $offset + $maxrecords);
-      $pager .= '<A HREF="'. $cgi->self_url.
-                '"><B><FONT SIZE="+1">Next</FONT></B></A> ';
-    }
-  }
-  #end pager
-
-  print header("Account Search Results",menubar('Main Menu'=>popurl(2))),
-        "$total matching accounts found<BR><BR>$pager",
-        &table(), <<END;
-      <TR>
-        <TH><FONT SIZE=-1>#</FONT></TH>
-        <TH><FONT SIZE=-1>Username</FONT></TH>
-        <TH><FONT SIZE=-1>Domain</FONT></TH>
-        <TH><FONT SIZE=-1>UID</FONT></TH>
-        <TH><FONT SIZE=-1>Service</FONT></TH>
-        <TH><FONT SIZE=-1>Cust#</FONT></TH>
-        <TH><FONT SIZE=-1>(bill) name</FONT></TH>
-        <TH><FONT SIZE=-1>company</FONT></TH>
-END
-  if ( defined dbdef->table('cust_main')->column('ship_last') ) {
-    print <<END;
-        <TH><FONT SIZE=-1>(service) name</FONT></TH>
-        <TH><FONT SIZE=-1>company</FONT></TH>
-END
-  }
-  print "</TR>";
+  $orderby = "ORDER BY uid";
 
-  my(%saw,$svc_acct);
-  my $p = popurl(2);
-  foreach $svc_acct (
-    sort $sortby grep(!$saw{$_->svcnum}++, @svc_acct)
-  ) {
-    my $cust_svc = qsearchs('cust_svc', { 'svcnum' => $svc_acct->svcnum })
-      or die "No cust_svc record for svcnum ". $svc_acct->svcnum;
-    my $part_svc = qsearchs('part_svc', { 'svcpart' => $cust_svc->svcpart })
-      or die "No part_svc record for svcpart ". $cust_svc->svcpart;
-
-    my $domain;
-    my $svc_domain = qsearchs('svc_domain', { 'svcnum' => $svc_acct->domsvc });
-    if ( $svc_domain ) {
-      $domain = "<A HREF=\"${p}view/svc_domain.cgi?". $svc_domain->svcnum.
-                "\">". $svc_domain->domain. "</A>";
-    } else {
-      die "No svc_domain.svcnum record for svc_acct.domsvc: ".
-          $svc_acct->domsvc;
-    }
-    my($cust_pkg,$cust_main);
-    if ( $cust_svc->pkgnum ) {
-      $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_svc->pkgnum })
-        or die "No cust_pkg record for pkgnum ". $cust_svc->pkgnum;
-      $cust_main = qsearchs('cust_main', { 'custnum' => $cust_pkg->custnum })
-        or die "No cust_main record for custnum ". $cust_pkg->custnum;
-    }
-    my($svcnum, $username, $uid, $svc, $custnum, $last, $first, $company) = (
-      $svc_acct->svcnum,
-      $svc_acct->getfield('username'),
-      $svc_acct->getfield('uid'),
-      $part_svc->svc,
-      $cust_svc->pkgnum ? $cust_main->custnum : '',
-      $cust_svc->pkgnum ? $cust_main->getfield('last') : '',
-      $cust_svc->pkgnum ? $cust_main->getfield('first') : '',
-      $cust_svc->pkgnum ? $cust_main->company : '',
-    );
-    my($pcustnum) = $custnum
-      ? "<A HREF=\"${p}view/cust_main.cgi?$custnum\"><FONT SIZE=-1>$custnum</FONT></A>"
-      : "<I>(unlinked)</I>"
-    ;
-    my $pname = $custnum ? "<A HREF=\"${p}view/cust_main.cgi?$custnum\">$last, $first</A>" : '';
-    my $pcompany = $custnum ? "<A HREF=\"${p}view/cust_main.cgi?$custnum\">$company</A>" : '';
-    my($pship_name, $pship_company);
-    if ( defined dbdef->table('cust_main')->column('ship_last') ) {
-      my($ship_last, $ship_first, $ship_company) = (
-        $cust_svc->pkgnum ? ( $cust_main->ship_last || $last ) : '',
-        $cust_svc->pkgnum ? ( $cust_main->ship_last
-                              ? $cust_main->ship_first
-                              : $first
-                            ) : '',
-        $cust_svc->pkgnum ? ( $cust_main->ship_last
-                              ? $cust_main->ship_company
-                              : $company
-                            ) : '',
-      );
-      $pship_name = $custnum ? "<A HREF=\"${p}view/cust_main.cgi?$custnum\">$ship_last, $ship_first</A>" : '';
-      $pship_company = $custnum ? "<A HREF=\"${p}view/cust_main.cgi?$custnum\">$ship_company</A>" : '';
-    }
-    print <<END;
-    <TR>
-      <TD><A HREF="${p}view/svc_acct.cgi?$svcnum"><FONT SIZE=-1>$svcnum</FONT></A></TD>
-      <TD><A HREF="${p}view/svc_acct.cgi?$svcnum"><FONT SIZE=-1>$username</FONT></A></TD>
-      <TD><FONT SIZE=-1>$domain</FONT></TD>
-      <TD><A HREF="${p}view/svc_acct.cgi?$svcnum"><FONT SIZE=-1>$uid</FONT></A></TD>
-      <TD><FONT SIZE=-1>$svc</FONT></TH>
-      <TD><FONT SIZE=-1>$pcustnum</FONT></TH>
-      <TD><FONT SIZE=-1>$pname<FONT></TH>
-      <TD><FONT SIZE=-1>$pcompany</FONT></TH>
-END
-    if ( defined dbdef->table('cust_main')->column('ship_last') ) {
-      print <<END;
-      <TD><FONT SIZE=-1>$pship_name<FONT></TH>
-      <TD><FONT SIZE=-1>$pship_company</FONT></TH>
-END
-    }
-    print "</TR>";
-
-  }
-  print "</TABLE>$pager<BR>".
-        '</BODY></HTML>';
-
-}
-
-sub svcnum_sort {
-  $a->getfield('svcnum') <=> $b->getfield('svcnum');
-}
-
-sub username_sort {
-  $a->getfield('username') cmp $b->getfield('username');
-}
-
-sub uid_sort {
-  $a->getfield('uid') <=> $b->getfield('uid');
-}
-
-sub usernamesearch {
-
-  my @svc_acct;
+  my @username_sql;
 
   my %username_type;
   foreach ( $cgi->param('username_type') ) {
@@ -254,17 +41,13 @@ sub usernamesearch {
   $cgi->param('username') =~ /^([\w\-\.\&]+)$/; #untaint username_text
   my $username = $1;
 
-  if ( $username_type{'Exact'} || $username_type{'Fuzzy'} ) {
-    push @svc_acct, qsearch( 'svc_acct',
-                             { 'username' => { 'op'    => 'ILIKE',
-                                               'value' => $username } } );
-  }
+  push @username_sql, "username ILIKE '$username'"
+    if $username_type{'Exact'}
+    || $username_type{'Fuzzy'};
 
-  if ( $username_type{'Substring'} || $username_type{'All'} ) {
-    push @svc_acct, qsearch( 'svc_acct',
-                             { 'username' => { 'op'    => 'ILIKE',
-                                               'value' => "%$username%" } } );
-  }
+  push @username_sql, "username ILIKE '\%$username\%'"
+    if $username_type{'Substring'}
+    || $username_type{'All'};
 
   if ( $username_type{'Fuzzy'} || $username_type{'All'} ) {
     &FS::svc_acct::check_and_rebuild_fuzzyfiles;
@@ -280,15 +63,78 @@ sub usernamesearch {
     #if ($username_type{'Sound-alike'}) {
     #}
 
-    foreach ( keys %username ) {
-      push @svc_acct, qsearch('svc_acct',{'username'=>$_});
-    }
+    push @username_sql, "username = '$_'"
+      foreach (keys %username);
 
   }
 
-  #[ qsearch('svc_acct',{'username'=>$username}) ];
-  \@svc_acct;
+  push @extra_sql, '( '. join( ' OR ', @username_sql). ' )';
 
 }
 
+my $extra_sql = 
+  scalar(@extra_sql)
+    ? ' WHERE '. join(' AND ', @extra_sql )
+    : '';
+
+my $count_query = "SELECT COUNT(*) FROM svc_acct $cjoin $extra_sql";
+#if ( keys %svc_acct ) {
+#  $count_query .= ' WHERE '.
+#                    join(' AND ', map "$_ = ". dbh->quote($svc_acct{$_}),
+#                                      keys %svc_acct
+#                        );
+#}
+
+my $sql_query = {
+  'table' => 'svc_acct',
+  'hashref'   => {}, # \%svc_acct,
+  'select'    => join(', ',
+                    'svc_acct.*',
+                    'cust_main.custnum',
+                    FS::UI::Web::cust_sql_fields(),
+                  ),
+  'extra_sql' => "$extra_sql $orderby",
+  'addl_from' => 'LEFT JOIN cust_svc  USING ( svcnum  ) '.
+                 'LEFT JOIN part_svc  USING ( svcpart ) '.
+                 'LEFT JOIN cust_pkg  USING ( pkgnum  ) '.
+                 'LEFT JOIN cust_main USING ( custnum ) ',
+};
+
+my $link      = [ "${p}view/svc_acct.cgi?",   'svcnum'  ];
+my $link_cust = sub {
+  my $svc_acct = shift;
+  if ( $svc_acct->custnum ) {
+    [ "${p}view/cust_main.cgi?", 'custnum' ];
+  } else {
+    '';
+  }
+};
+
+%><%= include( 'elements/search.html',
+                 'title'       => 'Account Search Results',
+                 'name'        => 'accounts',
+                 'query'       => $sql_query,
+                 'count_query' => $count_query,
+                 'redirect'    => $link,
+                 'header'      => [ '#',
+                                    'Account',
+                                    'UID',
+                                    'Service',
+                                    FS::UI::Web::cust_header(),
+                                  ],
+                 'fields'      => [ 'svcnum',
+                                    'email',
+                                    'uid',
+                                    'svc',
+                                    \&FS::UI::Web::cust_fields,
+                                  ],
+                 'links'       => [ $link,
+                                    $link,
+                                    $link,
+                                    '',
+                                    ( map { $link_cust }
+                                          FS::UI::Web::cust_header()
+                                    ),
+                                  ],
+             )
 %>
index 06041e0..f261ea9 100755 (executable)
@@ -37,7 +37,6 @@ if ( keys %svc_domain ) {
                     join(' AND ', map "$_ = ". dbh->quote($svc_domain{$_}),
                                       keys %svc_domain
                         );
-
 }
 
 my $sql_query = {
@@ -45,12 +44,13 @@ my $sql_query = {
   'hashref'   => \%svc_domain,
   'select'    => join(', ',
                    'svc_domain.*',
-                   map "cust_main.$_", qw(custnum last first company)
+                    'cust_main.custnum',
+                    FS::UI::Web::cust_sql_fields(),
                  ),
   'extra_sql' => "$extra_sql $orderby",
-  'addl_from' => 'LEFT JOIN cust_svc  USING ( svcnum  )'.
-                 'LEFT JOIN cust_pkg  USING ( pkgnum  )'.
-                 'LEFT JOIN cust_main USING ( custnum )',
+  'addl_from' => 'LEFT JOIN cust_svc  USING ( svcnum  ) '.
+                 'LEFT JOIN cust_pkg  USING ( pkgnum  ) '.
+                 'LEFT JOIN cust_main USING ( custnum ) ',
 };
 
 my $link = [ "${p}view/svc_domain.cgi?", 'svcnum' ];
@@ -69,15 +69,17 @@ my $link_cust = sub {
                  'redirect'          => $link,
                  'header'            => [ '#',
                                           'Domain',
-                                          'Customer',
+                                          FS::UI::Web::cust_header(),
                                         ],
                  'fields'            => [ 'svcnum',
                                           'domain',
-                                          \&FS::svc_Common::cust_name,
+                                          \&FS::UI::Web::cust_fields,
                                         ],
                  'links'             => [ $link,
                                           $link,
-                                          $link_cust,
+                                          ( map { $link_cust }
+                                                FS::UI::Web::cust_header()
+                                          ),
                                         ],
               )
 %>
index 1c1c6e4..330c0ee 100755 (executable)
@@ -17,7 +17,8 @@ my $sql_query = {
   'hashref'   => {},
   'select'    => join(', ',
                    'svc_forward.*',
-                   map "cust_main.$_", qw(custnum last first company)
+                    'cust_main.custnum',
+                    FS::UI::Web::cust_sql_fields(),
                  ),
   'extra_sql' => $orderby,
   'addl_from' => 'LEFT JOIN cust_svc  USING ( svcnum  )'.
@@ -75,7 +76,7 @@ my $link_cust = sub {
   $svc_x->custnum ? [ "${p}view/cust_main.cgi?", 'custnum' ] : '';
 };
 
-%><%= include ('elements/search.html',
+%><%= include'elements/search.html',
                  'title'             => "Mail forward Search Results",
                  'name'              => 'mail forwards',
                  'query'             => $sql_query,
@@ -84,17 +85,19 @@ my $link_cust = sub {
                  'header'            => [ '#',
                                           'Mail to',
                                           'Forwards to',
-                                          'Customer',
+                                          FS::UI::Web::cust_header(),
                                         ],
                  'fields'            => [ 'svcnum',
                                           $format_src,
                                           $format_dst,
-                                          \&FS::svc_Common::cust_name,
+                                          \&FS::UI::Web::cust_fields,
                                         ],
                  'links'             => [ $link,
                                           $link_src,
                                           $link_dst,
-                                          $link_cust,
+                                          ( map { $link_cust }
+                                                FS::UI::Web::cust_header()
+                                          ),
                                         ],
-              )
+             )
 %>
index de1f5dd..ae51c61 100755 (executable)
@@ -17,7 +17,8 @@ my $sql_query = {
   'hashref'   => {},
   'select'    => join(', ',
                    'svc_www.*',
-                   map "cust_main.$_", qw(custnum last first company)
+                   'cust_main.custnum',
+                   FS::UI::Web::cust_sql_fields(),
                  ),
   'extra_sql' => $orderby,
   'addl_from' => 'LEFT JOIN cust_svc  USING ( svcnum  )'.
@@ -44,17 +45,25 @@ my $link_cust = sub {
                  'header'      => [ '#',
                                     'Zone',
                                     'User',
-                                    'Customer',
+                                    FS::UI::Web::cust_header(),
                                   ],
                  'fields'      => [ 'svcnum',
                                     sub { $_[0]->domain_record->zone },
-                                    sub { $_[0]->svc_acct->email },
-                                    \&FS::svc_Common::cust_name,
+                                    sub {
+                                          my $svc_www = shift;
+                                          my $svc_acct = $svc_www->svc_acct;
+                                          $svc_acct
+                                            ? $svc_acct->email
+                                            : '';
+                                        },
+                                    \&FS::UI::Web::cust_fields,
                                   ],
                  'links'       => [ $link,
                                     '',
                                     $ulink,
-                                    $link_cust,
+                                    ( map { $link_cust }
+                                          FS::UI::Web::cust_header()
+                                    ),
                                   ],
              )
 %>