add ability to search on a date range of invoice events and then reprint or reemail...
authorivan <ivan>
Thu, 2 Jun 2005 09:29:56 +0000 (09:29 +0000)
committerivan <ivan>
Thu, 2 Jun 2005 09:29:56 +0000 (09:29 +0000)
21 files changed:
FS/FS/UI/Web.pm
FS/FS/cust_bill.pm
FS/FS/cust_bill_event.pm
FS/FS/part_bill_event.pm
FS/FS/part_pkg.pm
FS/bin/freeside-queued
htetc/global.asa
htetc/handler.pl
httemplate/elements/progress-init.html
httemplate/elements/progress-popup.html
httemplate/index.html
httemplate/misc/email-invoice.cgi
httemplate/misc/email_invoices.cgi [new file with mode: 0644]
httemplate/misc/fax-invoice.cgi
httemplate/misc/fax_invoices.cgi [new file with mode: 0644]
httemplate/misc/print-invoice.cgi
httemplate/misc/print_invoices.cgi [new file with mode: 0644]
httemplate/search/cust_bill_event.cgi
httemplate/search/cust_bill_event.html
httemplate/search/elements/search.html
httemplate/view/cust_bill.cgi

index 46e904b..e701141 100644 (file)
@@ -4,6 +4,19 @@ package FS::UI::Web;
 #use FS::UI
 #@ISA = qw( FS::UI );
 
+use Date::Parse;
+sub parse_beginning_ending {
+  my($cgi) = @_;
+
+  $cgi->param('beginning') =~ /^([ 0-9\-\/]{0,10})$/;
+  my $beginning = str2time($1) || 0;
+
+  #need an option to turn off the + 86399 ???
+  $cgi->param('ending') =~ /^([ 0-9\-\/]{0,10})$/;
+  my $ending =  ( $1 ? str2time($1) : 4294880896 ) + 86399;
+
+  ( $beginning, $ending );
+}
 
 # begin JSRPC code...
 
index 2c25c6f..888687e 100644 (file)
@@ -20,6 +20,9 @@ use FS::cust_pkg;
 use FS::cust_credit_bill;
 use FS::cust_pay_batch;
 use FS::cust_bill_event;
+use FS::part_pkg;
+use FS::cust_bill_pay;
+use FS::part_bill_event;
 
 @ISA = qw( FS::Record );
 
@@ -557,63 +560,121 @@ sub send {
   my $self = shift;
   my $template = scalar(@_) ? shift : '';
   return 'N/A' if scalar(@_) && $_[0] && $self->cust_main->agentnum != shift;
+
   my $invoice_from =
     scalar(@_)
       ? shift
       : ( $self->_agent_invoice_from || $conf->config('invoice_from') );
 
-  #my @print_text = $self->print_text('', $template);
   my @invoicing_list = $self->cust_main->invoicing_list;
 
-  if ( grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list or !@invoicing_list  ) {
-    #email
+  $self->send_email($template, $invoice_from)
+    if grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list or !@invoicing_list;
 
-    #better to notify this person than silence
-    @invoicing_list = ($invoice_from) unless @invoicing_list;
+  $self->send_print($template)
+    if grep { $_ eq 'POST' } @invoicing_list; #postal
 
-    my $error = send_email(
-      $self->generate_email(
-        'from'       => $invoice_from,
-        'to'         => [ grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list ],
-        #'print_text' => [ @print_text ],
-        'template'   => $template,
-      )
-    );
-    die "can't email invoice: $error\n" if $error;
-    #die "$error\n" if $error;
+  $self->send_fax($template)
+    if grep { $_ eq 'FAX' } @invoicing_list; #fax
 
-  }
+  '';
 
-  if ( grep { $_ =~ /^(POST|FAX)$/ } @invoicing_list ) {
-    my $lpr_data;
-    if ($conf->config('invoice_latex')) {
-      $lpr_data = [ $self->print_ps('', $template) ];
-    } else {
-      $lpr_data = [ $self->print_text('', $template) ];
-    }
+}
 
-    if ( grep { $_ eq 'POST' } @invoicing_list ) { #postal
-      my $lpr = $conf->config('lpr');
-      open(LPR, "|$lpr")
-        or die "Can't open pipe to $lpr: $!\n";
-      print LPR @{$lpr_data};
-      close LPR
-        or die $! ? "Error closing $lpr: $!\n"
-                  : "Exit status $? from $lpr\n";
-    }
+=item email [ TEMPLATENAME  [ , INVOICE_FROM ] ] 
 
-    if ( grep { $_ eq 'FAX' } @invoicing_list ) { #fax
-      die 'FAX invoice destination not supported with plain text invoices.'
-        unless $conf->exists('invoice_latex');
-      my $dialstring = $self->cust_main->getfield('fax');
-      #Check $dialstring?
-      my $error = send_fax(docdata => $lpr_data, dialstring => $dialstring);
-      die $error if $error;
-    }
+Emails this invoice.
 
-  }
+TEMPLATENAME, if specified, is the name of a suffix for alternate invoices.
 
-  '';
+INVOICE_FROM, if specified, overrides the default email invoice From: address.
+
+=cut
+
+sub email {
+  my $self = shift;
+  my $template = scalar(@_) ? shift : '';
+  my $invoice_from =
+    scalar(@_)
+      ? shift
+      : ( $self->_agent_invoice_from || $conf->config('invoice_from') );
+
+  my @invoicing_list = grep { $_ !~ /^(POST|FAX)$/ } 
+                            $self->cust_main->invoicing_list;
+
+  #better to notify this person than silence
+  @invoicing_list = ($invoice_from) unless @invoicing_list;
+
+  my $error = send_email(
+    $self->generate_email(
+      'from'       => $invoice_from,
+      'to'         => [ grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list ],
+      'template'   => $template,
+    )
+  );
+  die "can't email invoice: $error\n" if $error;
+  #die "$error\n" if $error;
+
+}
+
+=item lpr_data [ TEMPLATENAME ]
+
+Returns the postscript or plaintext for this invoice.
+
+TEMPLATENAME, if specified, is the name of a suffix for alternate invoices.
+
+=cut
+
+sub lpr_data {
+  my( $self, $template) = @_;
+  $conf->exists('invoice_latex')
+    ? [ $self->print_ps('', $template) ]
+    : [ $self->print_text('', $template) ];
+}
+
+=item print [ TEMPLATENAME ]
+
+Prints this invoice.
+
+TEMPLATENAME, if specified, is the name of a suffix for alternate invoices.
+
+=cut
+
+sub print {
+  my $self = shift;
+  my $template = scalar(@_) ? shift : '';
+
+  my $lpr = $conf->config('lpr');
+  open(LPR, "|$lpr")
+    or die "Can't open pipe to $lpr: $!\n";
+  print LPR @{ $self->lpr_data($template) };
+  close LPR
+    or die $! ? "Error closing $lpr: $!\n"
+              : "Exit status $? from $lpr\n";
+}
+
+=item fax [ TEMPLATENAME ] 
+
+Faxes this invoice.
+
+TEMPLATENAME, if specified, is the name of a suffix for alternate invoices.
+
+=cut
+
+sub fax {
+  my $self = shift;
+  my $template = scalar(@_) ? shift : '';
+
+  die 'FAX invoice destination not (yet?) supported with plain text invoices.'
+    unless $conf->exists('invoice_latex');
+
+  my $dialstring = $self->cust_main->getfield('fax');
+  #Check $dialstring?
+
+  my $error = send_fax( 'docdata'    => $self->lpr_data($template),
+                        'dialstring' => $dialstring,
+                      );
+  die $error if $error;
 
 }
 
@@ -1024,7 +1085,7 @@ sub print_text {
     ( grep { ! $_->pkgnum } $self->cust_bill_pkg ),  #then taxes
   ) {
 
-    if ( $cust_bill_pkg->pkgnum ) {
+    if ( $cust_bill_pkg->pkgnum > 0 ) {
 
       my $cust_pkg = qsearchs('cust_pkg', { pkgnum =>$cust_bill_pkg->pkgnum } );
       my $part_pkg = qsearchs('part_pkg', { pkgpart=>$cust_pkg->pkgpart } );
@@ -1919,7 +1980,7 @@ sub _items_cust_bill_pkg {
   my @b = ();
   foreach my $cust_bill_pkg ( @$cust_bill_pkg ) {
 
-    if ( $cust_bill_pkg->pkgnum ) {
+    if ( $cust_bill_pkg->pkgnum > 0 ) {
 
       my $cust_pkg = qsearchs('cust_pkg', { pkgnum =>$cust_bill_pkg->pkgnum } );
       my $part_pkg = qsearchs('part_pkg', { pkgpart=>$cust_pkg->pkgpart } );
index ddd6762..7b98139 100644 (file)
@@ -1,13 +1,15 @@
 package FS::cust_bill_event;
 
 use strict;
-use vars qw( @ISA );
+use vars qw( @ISA $DEBUG );
 use FS::Record qw( qsearch qsearchs );
 use FS::cust_bill;
 use FS::part_bill_event;
 
 @ISA = qw(FS::Record);
 
+$DEBUG = 0;
+
 =head1 NAME
 
 FS::cust_bill_event - Object methods for cust_bill_event records
@@ -165,6 +167,98 @@ sub retry {
 
 =back
 
+=head1 SUBROUTINES
+
+=over 4
+
+=item reprint
+
+=cut
+
+sub process_reprint {
+  process_re_X('print', @_);
+}
+
+=item reemail
+
+=cut
+
+sub process_reemail {
+  process_re_X('email', @_);
+}
+
+=item refax
+
+=cut
+
+sub process_refax {
+  process_re_X('fax', @_);
+}
+
+use Storable qw(thaw);
+use Data::Dumper;
+use MIME::Base64;
+sub process_re_X {
+  my( $method, $job ) = ( shift, shift );
+
+  my $param = thaw(decode_base64(shift));
+  warn Dumper($param) if $DEBUG;
+
+  re_X(
+    $method,
+    $param->{'beginning'},
+    $param->{'ending'},
+    $param->{'failed'},
+    $job,
+  );
+
+}
+
+sub re_X {
+  my($method, $beginning, $ending, $failed, $job) = @_;
+
+  my $where = " WHERE plan LIKE 'send%'".
+              "   AND cust_bill_event._date >= $beginning".
+              "   AND cust_bill_event._date <= $ending";
+  $where .= " AND statustext != '' AND statustext IS NOT NULL"
+    if $failed;
+
+  my $from = 'LEFT JOIN part_bill_event USING ( eventpart )';
+
+  my @cust_bill_event = qsearch( 'cust_bill_event', {}, '', $where, '', $from );
+
+  my( $num, $last, $min_sec ) = (0, time, 5); #progresbar foo
+  foreach my $cust_bill_event ( @cust_bill_event ) {
+
+    $cust_bill_event->cust_bill->$method(
+      $cust_bill_event->part_bill_event->templatename
+    );
+
+    if ( $job ) { #progressbar foo
+      $num++;
+      if ( time - $min_sec > $last ) {
+        my $error = $job->update_statustext(
+          int( 100 * $num / scalar(@cust_bill_event) )
+        );
+        die $error if $error;
+        $last = time;
+      }
+    }
+
+  }
+
+  #this doesn't work, but it would be nice
+  #if ( $job ) { #progressbar foo
+  #  my $error = $job->update_statustext(
+  #    scalar(@cust_bill_event). " invoices re-${method}ed"
+  #  );
+  #  die $error if $error;
+  #}
+
+}
+
+=back
+
 =head1 BUGS
 
 Far too early in the morning.
index b7c8b6a..0d03ebf 100644 (file)
@@ -171,11 +171,32 @@ sub check {
   $self->SUPER::check;
 }
 
+=item templatename
+
+Returns the alternate invoice template name, if any, or false if there is
+no alternate template for this invoice event.
+
+=cut
+
+sub templatename {
+  my $self = shift;
+  if (    $self->plan     =~ /^send_(alternate|agent)$/
+       && $self->plandata =~ /^(agent_)?templatename (.*)$/m
+     )
+  {
+    $2;
+  } else {
+    '';
+  }
+}
+
+
 =back
 
 =head1 BUGS
 
-Alas.
+The whole "eventcode" idea is bunk.  This should be refactored with subclasses
+like part_pkg/ and part_export/
 
 =head1 SEE ALSO
 
index bf040c8..f9b36e2 100644 (file)
@@ -2,7 +2,7 @@ package FS::part_pkg;
 
 use strict;
 use vars qw( @ISA %freq %plans $DEBUG );
-use Carp qw(carp cluck);
+use Carp qw(carp cluck confess);
 use Tie::IxHash;
 use FS::Conf;
 use FS::Record qw( qsearch qsearchs dbh dbdef );
@@ -643,9 +643,15 @@ on how to create new price plans, but until then, see L</NEW PLAN CLASSES>.
 sub _rebless {
   my $self = shift;
   my $plan = $self->plan;
+  unless ( $plan ) {
+    confess "no price plan found for pkgpart ". $self->pkgpart. "\n"
+      if $DEBUG;
+    return $self;
+  }
   my $class = ref($self). "::$plan";
+  warn "reblessing $self into $class" if $DEBUG;
   eval "use $class;";
-  #die $@ if $@;
+  die $@ if $@;
   bless($self, $class) unless $@;
   $self;
 }
@@ -697,6 +703,7 @@ sub calc_cancel { 0; }
 
 my %info;
 foreach my $INC ( @INC ) {
+  warn "globbing $INC/FS/part_pkg/*.pm\n" if $DEBUG;
   foreach my $file ( glob("$INC/FS/part_pkg/*.pm") ) {
     warn "attempting to load plan info from $file\n" if $DEBUG;
     $file =~ /\/(\w+)\.pm$/ or do {
index b9ef09c..3a0a9b4 100644 (file)
@@ -186,7 +186,7 @@ while (1) {
     }
 
     my $eval = "&". $ljob->job. '(@args);';
-    warn "running $eval";
+    warn 'running "&'. $ljob->job. '('. join(', ', @args). ")\n" if $DEBUG;
     eval $eval; #throw away return value?  suppose so
     if ( $@ ) {
       warn "job $eval failed";
index 3781f94..39ec898 100644 (file)
@@ -12,6 +12,7 @@ use Date::Parse;
 use Time::Local;
 use Time::Duration;
 use Tie::IxHash;
+use URI::Escape;
 use HTML::Entities;
 use IO::Handle;
 use IO::File;
index b44e3f2..ad671d6 100644 (file)
@@ -95,6 +95,7 @@ sub handler
       use Time::Local;
       use Time::Duration;
       use Tie::IxHash;
+      use URI::Escape;
       use HTML::Entities;
       use IO::Handle;
       use IO::File;
index 41feaac..a8268c1 100644 (file)
@@ -1,6 +1,14 @@
 <%
-  my( $formname, $fields, $action, $success_url, $key ) = @_;
+  my( $formname, $fields, $action, $url_or_message, $key ) = @_;
   $key = '' unless defined $key;
+
+  my $url_or_message_link;
+  if ( ref($url_or_message) ) { #its a message or something
+    $url_or_message_link =
+      'message='. uri_escape( $url_or_message->{'message'} )
+  } else {
+    $url_or_message_link = "url=$url_or_message";
+  }
 %>
 
 <SCRIPT TYPE="text/javascript" SRC="../elements/jsrsClient.js"></SCRIPT>
@@ -52,7 +60,7 @@ function <%=$key%>process () {
 
 function <%=$key%>myCallback( jobnum ) {
 
-  overlib( OLiframeContent('<%=$p%>elements/progress-popup.html?jobnum=' + jobnum + ';url=<%=$success_url%>;formname=<%=$formname%>' , 432, 136, 'progress_popup'), CAPTION, 'Please wait...', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', CLOSECLICK, MIDX, 0, MIDY, 0 );
+  overlib( OLiframeContent('<%=$p%>elements/progress-popup.html?jobnum=' + jobnum + ';<%=$url_or_message_link%>;formname=<%=$formname%>' , 432, 136, 'progress_popup'), CAPTION, 'Please wait...', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', CLOSECLICK, MIDX, 0, MIDY, 0 );
 
 }
 
index d180c17..20bb5fc 100644 (file)
@@ -1,6 +1,7 @@
 <%
   my $jobnum = $cgi->param('jobnum');
   my $url = $cgi->param('url');
+  my $message = $cgi->param('message');
   my $formname = scalar($cgi->param('formname'));
 %>
 <HTML>
@@ -29,7 +30,17 @@ function updateStatus( status_statustext ) {
     bar1.update;
     jsrsExecute( '<%=$p%>elements/jsrsServer.html', updateStatus, 'job_status', '<%= $jobnum %>' );
   } else if ( status.indexOf('complete') > -1 ) {
+<% if ( $message ) { %>
+    document.getElementById("progress_message").innerHTML = "<%= $message %>";
+    document.getElementById("progress_bar").innerHTML = '';
+    document.getElementById("progress_percent").innerHTML = '<INPUT TYPE="button" VALUE="OK" onClick="parent.nd(1);">';
+    document.getElementById("progress_jobnum").innerHTML = '';
+    parent.document.<%=$formname%>.submit.disabled=false;
+<% } elsif ( $url ) { %>
     window.top.location.href = '<%= $url %>';
+<% } else { %>
+    alert('job done but no url or message specified');
+<% } %>
   } else if ( status.indexOf('error') > -1 ) {
     document.getElementById("progress_message").innerHTML = '<FONT SIZE="+1" COLOR="#FF0000">Error: ' + statustext + '</FONT>';
     document.getElementById("progress_bar").innerHTML = '';
index 90a14b1..d70c32a 100644 (file)
       <BR><A HREF="browse/cust_pay_batch.cgi">View pending credit card batch</A>      <BR><BR><A HREF="search/cust_pkg_report.cgi">Packages (by next bill date range)</A>
       <BR><BR>Invoice reports
             <UL>
-              <LI><a href="search/cust_bill_event.html">Invoice event errors (failed credit cards, processor or printer problems, etc.)</a>
               <LI>open invoices (<A HREF="search/cust_bill.html?OPEN_invnum">by invoice number</A>) (<A HREF="search/cust_bill.html?OPEN_date">by date</A>) (<A HREF="search/cust_bill.html?OPEN_custnum">by customer number</A>)
               <LI>15 day open invoices (<A HREF="search/cust_bill.html?OPEN15_invnum">by invoice number</A>) (<A HREF="search/cust_bill.html?OPEN15_date">by date</A>) (<A HREF="search/cust_bill.html?OPEN15_custnum">by customer number</A>)
               <LI>30 day open invoices (<A HREF="search/cust_bill.html?OPEN30_invnum">by invoice number</A>) (<A HREF="search/cust_bill.html?OPEN30_date">by date</A>) (<A HREF="search/cust_bill.html?OPEN30_custnum">by customer number</A>)
               <LI>120 day open invoices (<A HREF="search/cust_bill.html?OPEN120_invnum">by invoice number</A>) (<A HREF="search/cust_bill.html?OPEN120_date">by date</A>) (<A HREF="search/cust_bill.html?OPEN120_custnum">by customer number</A>)
               <LI>all invoices (<A HREF="search/cust_bill.html?invnum">by invoice number</A>) (<A HREF="search/cust_bill.html?date">by date</A>) (<A HREF="search/cust_bill.html?custnum">by customer number</A>)
             </UL>
+      Invoice event reports
+            <UL>
+              <LI><a href="search/cust_bill_event.html">All invoice events for a date range</a>
+              <LI><a href="search/cust_bill_event.html?failed=1">Invoice event errors for a date range (failed credit cards, processor or printer problems, etc.)</a>
+            </UL>
       <A HREF="search/report_cust_pay.html">Payment report (by type and/or date range)</A>
       <BR><BR><A HREF="search/report_cust_credit.html">Credit report (by employee and/or date range)</A>
       <BR><BR><A HREF="graph/money_time.cgi">Sales, Credits and Receipts Summary</A>
index 34afa90..ad9ba1a 100755 (executable)
@@ -1,7 +1,5 @@
 <%
 
-my $conf = new FS::Conf;
-
 #untaint invnum
 my($query) = $cgi->keywords;
 $query =~ /^((.+)-)?(\d+)$/;
@@ -10,16 +8,10 @@ my $invnum = $3;
 my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum});
 die "Can't find invoice!\n" unless $cust_bill;
 
-my $error = send_email(
-  $cust_bill->generate_email(
-    'from'     => 
-      ( $cust_bill->_agent_invoice_from || $conf->config('invoice_from') ),
-    'template' => $template,
-  )
-);
-eidiot($error) if $error;
+$cust_bill->email($template); 
 
 my $custnum = $cust_bill->getfield('custnum');
+
 print $cgi->redirect("${p}view/cust_main.cgi?$custnum");
 
 %>
diff --git a/httemplate/misc/email_invoices.cgi b/httemplate/misc/email_invoices.cgi
new file mode 100644 (file)
index 0000000..12d58d6
--- /dev/null
@@ -0,0 +1,6 @@
+<%
+
+my $server = new FS::UI::Web::JSRPC 'FS::cust_bill_event::process_reemail';
+$server->process;
+
+%>
index d490b8e..94fee2c 100755 (executable)
@@ -1,8 +1,5 @@
 <%
 
-my $conf = new FS::Conf;
-my $lpr = $conf->config('lpr');
-
 #untaint invnum
 my($query) = $cgi->keywords;
 $query =~ /^((.+)-)?(\d+)$/;
@@ -11,12 +8,7 @@ my $invnum = $3;
 my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum});
 die "Can't find invoice!\n" unless $cust_bill;
 
-my $error = &FS::Misc::send_fax(
-  dialstring => $cust_bill->cust_main->getfield('fax'),
-  docdata       => [ $cust_bill->print_ps('', $template) ],
-);
-
-die $error if $error;
+$cust_bill->fax($template);
 
 my $custnum = $cust_bill->getfield('custnum');
 
diff --git a/httemplate/misc/fax_invoices.cgi b/httemplate/misc/fax_invoices.cgi
new file mode 100644 (file)
index 0000000..a8ded05
--- /dev/null
@@ -0,0 +1,6 @@
+<%
+
+my $server = new FS::UI::Web::JSRPC 'FS::cust_bill_event::process_refax';
+$server->process;
+
+%>
index 5eeef34..6a4c2d7 100755 (executable)
@@ -1,8 +1,5 @@
 <%
 
-my $conf = new FS::Conf;
-my $lpr = $conf->config('lpr');
-
 #untaint invnum
 my($query) = $cgi->keywords;
 $query =~ /^((.+)-)?(\d+)$/;
@@ -11,17 +8,7 @@ my $invnum = $3;
 my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum});
 die "Can't find invoice!\n" unless $cust_bill;
 
-        open(LPR,"|$lpr") or die "Can't open $lpr: $!";
-
-        if ( $conf->exists('invoice_latex') ) {
-          print LPR $cust_bill->print_ps('', $template); #( date )
-        } else {
-          print LPR $cust_bill->print_text('', $template); #( date )
-        }
-
-        close LPR
-          or die $! ? "Error closing $lpr: $!"
-                       : "Exit status $? from $lpr";
+$cust_bill->print($template);
 
 my $custnum = $cust_bill->getfield('custnum');
 
diff --git a/httemplate/misc/print_invoices.cgi b/httemplate/misc/print_invoices.cgi
new file mode 100644 (file)
index 0000000..c6a7885
--- /dev/null
@@ -0,0 +1,6 @@
+<%
+
+my $server = new FS::UI::Web::JSRPC 'FS::cust_bill_event::process_reprint';
+$server->process;
+
+%>
index 7c2b3a2..253aa78 100644 (file)
-<!-- mason kludge -->
 <%
 
-#false laziness with view/cust_bill.cgi
+my $title = $cgi->param('failed') ? 'Failed invoice events' : 'Invoice events';
 
-$cgi->param('beginning') =~ /^([ 0-9\-\/]{0,10})$/;
-my $beginning = str2time($1) || 0;
+my($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
 
-$cgi->param('ending') =~ /^([ 0-9\-\/]{0,10})$/;
-my $ending =  ( $1 ? str2time($1) : 4294880896 ) + 86399;
+##tie my %hash, 'Tie::DxHash', 
+#my %hash = (
+#      _date => { op=> '>=', value=>$beginning },
+## i wish...
+##      _date => { op=> '<=', value=>$ending },
+#);
+#$hash{'statustext'} = { op=> '!=', value=>'' }
+#  if $cgi->param('failed');
 
-my @cust_bill_event =
-  sort { $a->_date <=> $b->_date }
-    qsearch('cust_bill_event', {
-      _date => { op=> '>=', value=>$beginning },
-      statustext => { op=> '!=', value=>'' },
-# i wish...
-#      _date => { op=> '<=', value=>$ending },
-    }, '', "AND _date <= $ending");
+my $where = " WHERE cust_bill_event._date >= $beginning".
+            "   AND cust_bill_event._date <= $ending";
+$where .= " AND statustext != '' AND statustext IS NOT NULL"
+  if $cgi->param('failed');
+
+my $sql_query = {
+  'table'     => 'cust_bill_event',
+  #'hashref'   => \%hash,
+  'hashref'   => {}, 
+  'select'    => join(', ',
+                   'cust_bill_event.*',
+                   'part_bill_event.event',
+                   'cust_bill.custnum',
+                   'cust_bill._date AS cust_bill_date',
+                   map "cust_main.$_", qw(last first company)
+
+                 ),
+  'extra_sql' => "$where ORDER BY _date ASC",
+  'addl_from' => 'LEFT JOIN part_bill_event USING ( eventpart ) '.
+                 'LEFT JOIN cust_bill       USING ( invnum    ) '.
+                 'LEFT JOIN cust_main       USING ( custnum   ) ',
+};
+
+my $count_sql = "select count(*) from cust_bill_event $where";
+
+my $conf = new FS::Conf;
+
+my $failed = $cgi->param('failed');
+
+my $html_init = join("\n", map {
+  ( my $action = $_ ) =~ s/_$//;
+  include('/elements/progress-init.html',
+            $_.'form',
+            [ 'action', 'beginning', 'ending', 'failed' ],
+            "../misc/${_}invoices.cgi",
+            { 'message' => "Invoices re-${action}ed" }, #would be nice to show the number of them, but...
+            $_, #key
+         ),
+  qq!<FORM NAME="${_}form">!,
+  qq!<INPUT TYPE="hidden" NAME="action" VALUE="$_">!, #not used though
+  qq!<INPUT TYPE="hidden" NAME="beginning" VALUE="$beginning">!,
+  qq!<INPUT TYPE="hidden" NAME="ending"    VALUE="$ending">!,
+  qq!<INPUT TYPE="hidden" NAME="failed"    VALUE="$failed">!,
+  qq!</FORM>!
+} qw( print_ email_ fax_ ) );
+
+my $menubar =  [
+                 'Main menu' => $p,
+                 'Re-print these events' =>
+                   "javascript:print_process()",
+                 'Re-email these events' =>
+                   "javascript:email_process()",
+               ];
+
+push @$menubar, 'Re-fax these events' =>
+                  "javascript:fax_process()"
+  if $conf->exists('hylafax');
+
+%><%= include( 'elements/search.html',
+                 'title'       => $title,
+                 'html_init'   => $html_init,
+                 'menubar'     => $menubar,
+                 'name'        => 'billing events',
+                 'query'       => $sql_query,
+                 'count_query' => $count_sql,
+                 'header'      => [ qw( Event Date Status ),
+                                    #'Inv #', 'Inv Date', 'Cust #',
+                                    'Invoice', 'Cust #',
+                                  ],
+                 'fields' => [
+                               'event',
+                               sub { time2str("%b %d %Y %T", $_[0]->_date) },
+                               sub { 
+                                     #my $cust_bill_event = shift;
+                                     my $status = $_[0]->status;
+                                     $status .= ': '.$_[0]->statustext
+                                       if $_[0]->statustext;
+                                     $status;
+                                   },
+                               sub {
+                                     #my $cust_bill_event = shift;
+                                     'Invoice #'. $_[0]->invnum.
+                                     ' ('.
+                                       time2str("%D", $_[0]->cust_bill_date).
+                                     ')';
+                                   },
+                               sub { FS::cust_main::name($_[0]) },
 
-%>
 
-<%= header('Failed billing events') %>
-
-<%= table() %>
-<TR>
-  <TH>Event</TH>
-  <TH>Date</TH>
-  <TH>Status</TH>
-  <TH>Invoice</TH>
-  <TH>(bill) name</TH>
-  <TH>company</TH>
-<% if ( defined dbdef->table('cust_main')->column('ship_last') ) { %>
-  <TH>(service) name</TH>
-  <TH>company</TH>
-<% } %>
-</TR>
-
-<% foreach my $cust_bill_event ( @cust_bill_event ) {
-   my $status = $cust_bill_event->status;
-   $status .= ': '.$cust_bill_event->statustext if $cust_bill_event->statustext;
-   my $cust_bill = $cust_bill_event->cust_bill;
-   my $cust_main = $cust_bill->cust_main;
-   my $invlink = "${p}view/cust_bill.cgi?". $cust_bill->invnum;
-   my $custlink = "${p}view/cust_main.cgi?". $cust_main->custnum;
+                             ],
+                 'links' => [
+                              '',
+                              '',
+                              '',
+                              sub {
+                                my $part_bill_event = shift;
+                                my $template = $part_bill_event->templatename;
+                                $template .= '-' if $template;
+                                [ "${p}view/cust_bill.cgi?$template", 'invnum'];
+                              },
+                              [ "${p}view/cust_main.cgi?", 'custnum' ],
+                              [ "${p}view/cust_main.cgi?", 'custnum' ],
+                            ],
+             )
 %>
-<TR>
-  <TD><%= $cust_bill_event->part_bill_event->event %></TD>
-  <TD><%= time2str("%a %b %e %T %Y", $cust_bill_event->_date) %></TD>
-  <TD><%= $status %></TD>
-  <TD><A HREF="<%=$invlink%>">Invoice #<%= $cust_bill->invnum %> (<%= time2str("%D", $cust_bill->_date ) %>)</A></TD>
-  <TD><A HREF="<%=$custlink%>"><%= $cust_main->last. ', '. $cust_main->first %></A></TD>
-  <TD><A HREF="<%=$custlink%>"><%= $cust_main->company %></A></TD>
-  <% if ( defined dbdef->table('cust_main')->column('ship_last') ) { %>
-    <TD><A HREF="<%=$custlink%>"><%= $cust_main->ship_last. ', '. $cust_main->ship_first %></A></TD>
-    <TD><A HREF="<%=$custlink%>"><%= $cust_main->ship_company %></A></TD>
-  <% } %>
-</TR>
-<% } %>
-</TABLE>
-
-</BODY></HTML>
index 6de2709..cebb303 100755 (executable)
@@ -1,14 +1,19 @@
-<HTML>
-  <HEAD>
-    <TITLE>Invoice event errors</TITLE>
+<%= include(
+      '/elements/header.html',
+      ( $cgi->param('failed') ? 'Failed invoice events' : 'invoice events' ),
+      include('/elements/menubar.html',
+                'Main menu' => $p, # popurl(2),
+             ),
+
+    )
+%>
     <LINK REL="stylesheet" TYPE="text/css" HREF="../elements/calendar-win2k-2.css" TITLE="win2k-2">
     <SCRIPT TYPE="text/javascript" SRC="../elements/calendar_stripped.js"></SCRIPT>
     <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-en.js"></SCRIPT>
     <SCRIPT TYPE="text/javascript" SRC="../elements/calendar-setup.js"></SCRIPT>
-  </HEAD>
-  <BODY BGCOLOR="#e8e8e8">
-    <H1>Invoice event errors</H1>
+
     <FORM ACTION="cust_bill_event.cgi" METHOD="GET">
+    <INPUT TYPE="hidden" NAME="failed" VALUE="<%= $cgi->param('failed') %>">
     <TABLE>
       <!--<TR>
         <TD ALIGN="right">Customer type</TD>
@@ -51,4 +56,3 @@
     </FORM>
   </BODY>
 </HTML>
-
index 529f48f..47d6194 100644 (file)
                  include( '/elements/menubar.html', @menubar )
              )
   %>
+  <%= defined($opt{'html_init'}) ? $opt{'html_init'} : '' %>
   <% my $pager = include ( '/elements/pager.html',
                              'offset'     => $offset,
                              'num_rows'   => scalar(@$rows),
index 38c57ec..d149cf1 100755 (executable)
@@ -67,11 +67,8 @@ my $link = $templatename ? "$templatename-$invnum" : $invnum;
     <TR>
       <TD><%= $part_bill_event->event %>
   
-        <% if (
-          $part_bill_event->plan eq 'send_alternate'
-          && $part_bill_event->plandata =~ /^(agent_)?templatename (.*)$/m
-        ) {
-          my $alt_templatename = $2;
+        <% if ( $part_bill_event->templatename ) {
+          my $alt_templatename = $part_bill_event->templatename;
           my $alt_link = "$alt_templatename-$invnum";
         %>
           ( <A HREF="<%= $p %>view/cust_bill.cgi?<%= $alt_link %>">view</A>