Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / httemplate / search / elements / cust_main_dayranges.html
index b3f1a2e..951eff2 100644 (file)
@@ -2,39 +2,38 @@
 
 Example:
 
-  include( 'elements/cust_main_dayranges.html',
+  <& elements/cust_main_dayranges.html,
                  'title'       => 'Accounts Receivable Aging Summary',
                  'range_sub'   => $mysub,
-         )
+                 'email_link'  => 1,  #adds an action column with an email link if true
+  &>
 
   my $mysub = sub {
     my( $start, $end ) = @_;
 
     "SQL EXPRESSION BASED ON $start AND $end";
+    # where $start and $end are unix timestamps
   };
 
 </%doc>
-<% include( 'search.html',
+<& search.html,
                  'name'        => 'customers',
                  'query'       => $sql_query,
                  'count_query' => $count_sql,
-                 'header'      => [ 
-                                    FS::UI::Web::cust_header(),
-                                    @pay_head,
+                 'header'      => [
+                                    @act_head,
+                                    @cust_header,
                                     '0-30',
                                     '30-60',
                                     '60-90',
                                     '90+',
-                                    'Total',
+                                    emt('Total'),
+                                    @pay_head,
                                   ],
                  'footer'      => [
+                                    @act_blank,
                                     'Total',
-                                    ( map '',
-                                          ( 1 .. 
-                                            scalar(FS::UI::Web::cust_header()-1)
-                                          ), @pay_labels
-                                    ),
-                                    
+                                    ( map '',( 1 .. $#cust_header ),),
                                     sprintf( $money_char.'%.2f',
                                              $row->{'rangecol_0_30'} ),
                                     sprintf( $money_char.'%.2f',
@@ -43,58 +42,71 @@ Example:
                                              $row->{'rangecol_60_90'} ),
                                     sprintf( $money_char.'%.2f',
                                              $row->{'rangecol_90_0'} ),
-                                    sprintf( '<b>'. $money_char.'%.2f'. '</b>',
+                                    sprintf( '<b>'.$money_char.'%.2f</b>',
                                              $row->{'rangecol_0_0'} ),
+                                    ('') x @pay_labels,
                                   ],
                  'fields'      => [
+                                    @act_fields,
                                     FS::UI::Web::cust_fields_subs(),
-                                    @pay_labels,
                                     format_rangecol('0_30'),
                                     format_rangecol('30_60'),
                                     format_rangecol('60_90'),
                                     format_rangecol('90_0'),
                                     format_rangecol('0_0'),
+                                    @pay_labels,
                                   ],
                  'links'       => [
+                                    @act_blank,
                                     ( map { $_ ne 'Cust. Status' ? $clink : '' }
-                                          FS::UI::Web::cust_header()
+                                          @cust_header
                                     ),
-                                    @pay_links,
                                     '',
                                     '',
                                     '',
                                     '',
                                     '',
+                                    @pay_links,
                                   ],
-                 #'align'       => 'rlccrrrrr',
-                 'align'       => FS::UI::Web::cust_aligns(). 
-                                  ('c' x @pay_labels).
-                                   'rrrrr',
-                 #'size'        => [ '', '', '-1', '-1', '', '', '', '',  '', ],
-                 #'style'       => [ '', '',  'b',  'b', '', '', '', '', 'b', ],
-                 'size'        => [ ( map '', FS::UI::Web::cust_header() ),
-                                    ( map '', @pay_labels ),
+                 'align'       => $act_align.
+                                  FS::UI::Web::cust_aligns(). 
+                                   'rrrrr'.
+                                  ('c' x @pay_labels),
+                 'size'        => [ 
+                                    @act_blank,
+                                    ( map '', @cust_header ),
                                     #'-1', '', '', '', '',  '', ],
-                                    '', '', '', '', '',  '', ],
-                 'style'       => [ FS::UI::Web::cust_styles(),
+                                    '', '', '', '', '',
                                     ( map '', @pay_labels ),
+                                  ],
+                 'style'       => [ 
+                                    @act_blank,
+                                    FS::UI::Web::cust_styles(),
                                     #'b', '', '', '', '', 'b', ],
-                                    '', '', '', '', 'b', ],
+                                    '', '', '', '', 'b', 
+                                    ( map '', @pay_labels ),
+                                    ],
+                 'xls_format'  => [ 
+                                    @act_blank,
+                                    (map '', FS::UI::Web::cust_styles),
+                                    '', '', '', '', { bold => 1 },
+                                  ],
                  'color'       => [
+                                    @act_blank,
                                     FS::UI::Web::cust_colors(),
-                                    ( map '', @pay_labels ),
-                                    '',
                                     '',
                                     '',
                                     '',
                                     '',
                                     '',
+                                    ( map '', @pay_labels ),
                                   ],
+                 'html_foot'   => $html_foot,
                %opt,
-             )
-%>
+&>
 <%init>
 
+my @cust_header = FS::UI::Web::cust_header($cgi->param('cust_fields'));
 my %opt = @_;
 
 #actually need to auto-generate other things too for a passed-in ranges to work
@@ -108,14 +120,14 @@ my $ranges = $opt{'ranges'} ? delete($opt{'ranges'}) : [
 
 my $range_sub = delete($opt{'range_sub'}); #or die
 
-my $offset = 0;
+my $as_of;
 if($cgi->param('as_of')) {
-  $offset = int((time - parse_datetime($cgi->param('as_of'))) / 86400);
-  $opt{'title'} .= ' ('.$cgi->param('as_of').')' if $offset > 0;
+  $as_of = parse_datetime($cgi->param('as_of')) || '';
+  $opt{'title'} .= ' ('.$cgi->param('as_of').')' if $as_of;
 }
 
-#my $range_cols = join(',', map &{$range_sub}( @$_ ), @ranges );
-my $range_cols = join(',', map call_range_sub($range_sub, @$_, 'offset' => $offset ), @$ranges );
+my $range_cols = join(',', 
+  map call_range_sub($range_sub, @$_, 'as_of' => $as_of ), @$ranges );
 
 my $select_count_pkgs = FS::cust_main->select_count_pkgs_sql;
 
@@ -141,8 +153,12 @@ unless ( $cgi->param('all_customers') ) {
     $days = $1;
   }
 
+  # If this is set, allow cust_main records with nonzero balances
+  my $negative = $cgi->param('negative') || 0;
+
   push @where,
-    call_range_sub($range_sub, $days + $offset, 0, 'no_as'=>1). ' > 0'; # != 0';
+    call_range_sub($range_sub, $days, 0, 'as_of' => $as_of, 'no_as'=>1). 
+    ($negative ? ' != 0' : ' > 0');
 }
 
 if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
@@ -155,10 +171,18 @@ if ( $cgi->param('agentnum') =~ /^(\d+)$/ ) {
 #prospect active inactive suspended cancelled
 if ( grep { $cgi->param('status') eq $_ } FS::cust_main->statuses() ) {
   my $method = $cgi->param('status'). '_sql';
-  #push @where, $class->$method();
   push @where, FS::cust_main->$method();
 }
 
+# cust_classnum (false laziness w/prepaid_income.html, elements/cust_pay_or_refund.html, cust_bill_pay.html, cust_bill_pkg.html, cust_bill_pkg_referral.html, unearned_detail.html, cust_credit.html, cust_credit_refund.html, cust_main::Search::search_sql)
+if ( grep { $_ eq 'cust_classnum' } $cgi->param ) {
+  my @classnums = grep /^\d*$/, $cgi->param('cust_classnum');
+  push @where, 'COALESCE( cust_main.classnum, 0) IN ( '.
+                   join(',', map { $_ || '0' } @classnums ).
+               ' )'
+    if @classnums;
+}
+
 #here is the agent virtualization
 push @where, $FS::CurrentUser::CurrentUser->agentnums_sql;
 
@@ -169,10 +193,11 @@ my $count_sql = "select count(*) from cust_main $where";
 
 my $sql_query = {
   'table'     => 'cust_main',
+  'addl_from' => FS::UI::Web::join_cust_main('cust_main'),
   'hashref'   => {},
   'select'    => join(',',
                    #'cust_main.*',
-                   'custnum',
+                   'cust_main.custnum',
                    $range_cols,
                    $packages_cols,
                    FS::UI::Web::cust_sql_fields(),
@@ -184,7 +209,9 @@ my $sql_query = {
 
 my $total_sql =
   "SELECT ".
-      join(',', map call_range_sub( $range_sub, @$_, 'offset' => $offset, 'sum'=>1 ), @$ranges).
+      join(',', 
+        map call_range_sub( $range_sub, @$_, 'as_of' => $as_of, 'sum'=>1 ), 
+        @$ranges).
     " FROM cust_main $where";
 
 my $total_sth = dbh->prepare($total_sql) or die dbh->errstr;
@@ -193,18 +220,59 @@ my $row = $total_sth->fetchrow_hashref();
 
 my $clink = [ "${p}view/cust_main.cgi?", 'custnum' ];
 
-my (@pay_head, @pay_labels, @pay_links);
+my (@payby, @pay_head, @pay_labels, @pay_links);
 
-if($opt{'payment_links'} && $curuser->access_right('Process payment')) {
-  @pay_head = ({ label => 'Process', nodownload => 1, colspan => 2 },
-                { nodownload => 1 });
+my %payby = map {$_ => 1} $conf->config('payby');
+if(%payby) {
+  push @payby, 'CARD' if ($payby{'CARD'} or $payby{'DCRD'});
+  push @payby, 'CHEK' if ($payby{'CHEK'} or $payby{'DCHK'});
+}
+else {
+  @payby = ('CARD','CHEK')
+}
 
-  @pay_labels = (map { my ($payby,$label) = @$_; 
-                        sub {($payby eq $_[0]->payby) ? "<b>$label</b>" : $label}
-                     } ([CARD => 'Card'], [CHEK => 'ACH']) );
+if($opt{'payment_links'} && $curuser->access_right('Process payment') && @payby) {
+  my %label = ( CARD => 'Card',
+                CHEK => 'E-Check' );
+  push @pay_head, ({nodownload => 1}) foreach @payby;
+  $pay_head[0] = { label => 'Process',
+                   nodownload => 1,
+                   colspan => scalar(@payby) };
+
+  @pay_labels = (map { my $payby = $_; 
+                       my $label = $label{$payby};
+                       sub {($payby eq $_[0]->payby) ? "<b>".emt("$label (on file)")."</b>" : emt($label)}
+                     } @payby );
 
   @pay_links = (map { [ "${p}misc/payment.cgi?payby=$_;custnum=", 'custnum' ] }
-                         'CARD', 'CHEK' );
+                         @payby );
+}
+
+my (@act_head, @act_blank, @act_fields, $act_align, $html_foot);
+if (delete($opt{'email_checkboxes'})) {
+  my $email_link = q!var url = toCGIString(); !;
+  $email_link   .= q/if (!url) { alert('No customers selected'); return false; }; /;
+  $email_link   .= q!url = '!;
+  $email_link   .= "${p}misc/email-customers.html?table=cust_main";
+  $email_link   .= q!' + url + '&popup=1&url=javascript%3Awindow.top.location.reload%28%29%3B'; !;
+  $email_link   .= include('/elements/popup_link_onclick.html',
+    'js_action' => 'url',
+    'actionlabel' => 'Send Customer Email',
+    'width' => '900',
+    'height' => '500',
+  );
+  $html_foot = include('checkbox-foot.html',
+    label   => 'Email selected customers',
+    onclick => $email_link,
+  );
+  push @act_fields, sub { 
+    my $row = shift;
+    my $custnum = $row->custnum;
+    qq!<input type="checkbox" name="custnum" value="$custnum">!;
+  };
+  $act_align = 'l';
+  push @act_head, {nodownload => 1};
+  push @act_blank, '';
 }
 
 </%init>
@@ -231,11 +299,26 @@ my $money_char = $conf->config('money_char') || '$';
 # )
 
 sub call_range_sub {
-  my($range_sub, $start, $end, %opt) = @_;
-
-  my $as = $opt{'no_as'} ? '' : " AS rangecol_${start}_$end";
-
-  my $sql = &{$range_sub}( $start, $end, $opt{'offset'} ); #%opt?
+  my($range_sub, $startdays, $enddays, %opt) = @_;
+
+  my $as = $opt{'no_as'} ? '' : " AS rangecol_${startdays}_$enddays";
+
+  my $as_of = $opt{'as_of'} || time;
+  my $cutoff = DateTime->from_epoch(epoch => $as_of, time_zone => 'local');
+  $cutoff->truncate(to => 'day'); # local midnight on the report day
+  $cutoff->add(days => 1); # the day after that
+  $cutoff->subtract(seconds => 1); # the last second of the report day
+
+  my $start = $cutoff->clone;
+  $start->subtract(days => $startdays);
+  my $end = $cutoff->clone;
+  $end->subtract(days => $enddays);
+
+  #warn "cutoff ".$cutoff->epoch.", range $startdays-$enddays (".$start->epoch . '-' . ($enddays ? $end->epoch : '').")\n";
+  my $sql = &{$range_sub}( $start->epoch, 
+                           $enddays ? $end->epoch : '', 
+                           $cutoff->epoch ); #%opt?
 
   $sql = "SUM($sql)" if $opt{'sum'};