[freeside-commits] freeside/FS/FS Conf.pm, 1.324.2.13, 1.324.2.14 Record.pm, 1.196.2.3, 1.196.2.4 cust_bill.pm, 1.263.2.11, 1.263.2.12 cust_location.pm, 1.2, 1.2.4.1 cust_main.pm, 1.464.2.12, 1.464.2.13 cust_pkg.pm, 1.139.2.5, 1.139.2.6

Jeff Finucane,420,, jeff at wavetail.420.am
Wed Dec 16 07:07:40 PST 2009


Update of /home/cvs/cvsroot/freeside/FS/FS
In directory wavetail.420.am:/tmp/cvs-serv20469/FS/FS

Modified Files:
      Tag: FREESIDE_1_9_BRANCH
	Conf.pm Record.pm cust_bill.pm cust_location.pm cust_main.pm 
	cust_pkg.pm 
Log Message:
group invoice line items by location, show location address on invoice, option for due date rather than invoice date on prior unpaid invoice line items, and option for aging on invoice (#6418, #5235, #4648)

Index: Conf.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Conf.pm,v
retrieving revision 1.324.2.13
retrieving revision 1.324.2.14
diff -u -d -r1.324.2.13 -r1.324.2.14
--- Conf.pm	14 Dec 2009 07:10:55 -0000	1.324.2.13
+++ Conf.pm	16 Dec 2009 15:07:37 -0000	1.324.2.14
@@ -1029,6 +1029,20 @@
   },
 
   { 
+    'key'         => 'invoice_show_prior_due_date',
+    'section'     => 'billing',
+    'description' => 'Show previous invoice due dates when showing prior balances.  Default is to show invoice date.',
+    'type'        => 'checkbox',
+  },
+
+  { 
+    'key'         => 'invoice_include_aging',
+    'section'     => 'billing',
+    'description' => 'Show an aging line after the prior balance section.  Only valud when invoice_sections is enabled.',
+    'type'        => 'checkbox',
+  },
+
+  { 
     'key'         => 'invoice_sections',
     'section'     => 'billing',
     'description' => 'Split invoice into sections and label according to package category when enabled.',

Index: cust_main.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_main.pm,v
retrieving revision 1.464.2.12
retrieving revision 1.464.2.13
diff -u -d -r1.464.2.12 -r1.464.2.13
--- cust_main.pm	10 Dec 2009 23:03:24 -0000	1.464.2.12
+++ cust_main.pm	16 Dec 2009 15:07:38 -0000	1.464.2.13
@@ -1953,6 +1953,28 @@
   qsearch('cust_location', { 'custnum' => $self->custnum } );
 }
 
+=item location_label_short
+
+Returns the short label of the service location (see analog in L<FS::cust_location>) for this customer.
+
+=cut
+
+# false laziness with FS::cust_location::line_short
+
+sub location_label_short {
+  my $self = shift;
+  my $cydefault = FS::conf->new->config('countrydefault') || 'US';
+
+  my $line =       $self->address1;
+  #$line   .= ', '. $self->address2              if $self->address2;
+  $line   .= ', '. $self->city;
+  $line   .= ', '. $self->state                 if $self->state;
+  $line   .= '  '. $self->zip                   if $self->zip;
+  $line   .= '  '. code2country($self->country) if $self->country ne $cydefault;
+
+  $line;
+}
+
 =item ncancelled_pkgs [ EXTRA_QSEARCH_PARAMS_HASHREF ]
 
 Returns all non-cancelled packages (see L<FS::cust_pkg>) for this customer.
@@ -2014,6 +2036,9 @@
 # This should be generalized to use config options to determine order.
 sub sort_packages {
   
+  my $locationsort = $a->locationnum <=> $b->locationnum;
+  return $locationsort if $locationsort;
+
   if ( $a->get('cancel') xor $b->get('cancel') ) {
     return -1 if $b->get('cancel');
     return  1 if $a->get('cancel');
@@ -6742,6 +6767,36 @@
   );
 }
 
+=item balance_date_range START_TIME [ END_TIME [ OPTION => VALUE ... ] ]
+
+Returns the balance for this customer, only considering invoices with date
+earlier than START_TIME, and optionally not later than END_TIME
+(total_owed_date minus total_unapplied_credits minus total_unapplied_payments).
+
+Times are specified as SQL fragments or numeric
+UNIX timestamps; see L<perlfunc/"time">).  Also see L<Time::Local> and
+L<Date::Parse> for conversion functions.  The empty string can be passed
+to disable that time constraint completely.
+
+Available options are:
+
+=over 4
+
+=item unapplied_date
+
+set to true to disregard unapplied credits, payments and refunds outside the specified time period - by default the time period restriction only applies to invoices (useful for reporting, probably a bad idea for event triggering)
+
+=back
+
+=cut
+
+sub balance_date_range {
+  my $self = shift;
+  my $sql = 'SELECT SUM('. $self->balance_date_sql(@_).
+            ') FROM cust_main WHERE custnum='. $self->custnum;
+  sprintf( "%.2f", $self->scalar_sql($sql) );
+}
+
 =item balance_pkgnum PKGNUM
 
 Returns the balance for this customer's specific package when using

Index: cust_location.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_location.pm,v
retrieving revision 1.2
retrieving revision 1.2.4.1
diff -u -d -r1.2 -r1.2.4.1
--- cust_location.pm	9 Jan 2009 04:06:26 -0000	1.2
+++ cust_location.pm	16 Dec 2009 15:07:38 -0000	1.2.4.1
@@ -179,6 +179,39 @@
   $line;
 }
 
+=item line_short
+
+Returns this location on one line in a shortened form
+
+=cut
+
+# configurable?
+
+sub line_short {
+  my $self = shift;
+  my $cydefault = FS::conf->new->config('countrydefault') || 'US';
+
+  my $line =       $self->address1;
+  #$line   .= ', '. $self->address2              if $self->address2;
+  $line   .= ', '. $self->city;
+  $line   .= ', '. $self->state                 if $self->state;
+  $line   .= '  '. $self->zip                   if $self->zip;
+  $line   .= '  '. code2country($self->country) if $self->country ne $cydefault;
+
+  $line;
+}
+
+=item location_label_short
+
+Synonym for line_short
+
+=cut
+
+sub location_label_short {
+  my $self = shift;
+  $self->line_short;
+}
+
 =back
 
 =head1 BUGS

Index: cust_pkg.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_pkg.pm,v
retrieving revision 1.139.2.5
retrieving revision 1.139.2.6
diff -u -d -r1.139.2.5 -r1.139.2.6
--- cust_pkg.pm	4 Dec 2009 04:40:44 -0000	1.139.2.5
+++ cust_pkg.pm	16 Dec 2009 15:07:38 -0000	1.139.2.6
@@ -1945,6 +1945,18 @@
   $self->cust_location || $self->cust_main;
 }
 
+=item location_label_short
+
+Returns the short label of the location object (see L<FS::cust_location>).
+
+=cut
+
+sub location_label_short {
+  my $self = shift;
+  my $object = $self->cust_location_or_main;
+  $object->location_label_short;
+}
+
 =item seconds_since TIMESTAMP
 
 Returns the number of seconds all accounts (see L<FS::svc_acct>) in this

Index: cust_bill.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/cust_bill.pm,v
retrieving revision 1.263.2.11
retrieving revision 1.263.2.12
diff -u -d -r1.263.2.11 -r1.263.2.12
--- cust_bill.pm	5 Dec 2009 23:36:26 -0000	1.263.2.11
+++ cust_bill.pm	16 Dec 2009 15:07:38 -0000	1.263.2.12
@@ -1,7 +1,7 @@
 package FS::cust_bill;
 
 use strict;
-use vars qw( @ISA $DEBUG $me $conf $money_char );
+use vars qw( @ISA $DEBUG $me $conf $money_char $date_format );
 use vars qw( $invoice_lines @buf ); #yuck
 use Fcntl qw(:flock); #for spool_csv
 use List::Util qw(min max);
@@ -44,6 +44,7 @@
 FS::UID->install_callback( sub { 
   $conf = new FS::Conf;
   $money_char = $conf->config('money_char') || '$';  
+  $date_format = $conf->config('date_format') || '%x';  
 } );
 
 =head1 NAME
@@ -2459,6 +2460,11 @@
                                             sprintf('%.2f', $pr_total),
                            'summarized'  => $summarypage ? 'Y' : '',
                          };
+  $previous_section->{posttotal} = '0 / 30 / 60/ 90 days overdue '. 
+    join(' / ', map { $cust_main->balance_date_range(@$_) }
+                $self->_prior_month30s
+        )
+    if $conf->exists('invoice_include_aging');
 
   my $taxtotal = 0;
   my $tax_section = { 'description' => 'Taxes, Surcharges, and Fees',
@@ -2572,6 +2578,7 @@
                  );
     }
 
+    my $multilocation = scalar($cust_main->cust_location); #too expensive?
     my %options = ();
     $options{'section'} = $section if $multisection;
     $options{'format'} = $format;
@@ -2581,6 +2588,7 @@
     $options{'summary_page'} = $summarypage;
     $options{'skip_usage'} =
       scalar(@$extra_sections) && !grep{$section == $_} @$extra_sections;
+    $options{'multilocation'} = $multilocation;
 
     foreach my $line_item ( $self->_items_pkg(%options) ) {
       my $detail = {
@@ -2927,6 +2935,22 @@
   }
 }
 
+# helper routine for generating date ranges
+sub _prior_month30s {
+  my $self = shift;
+  my @ranges = (
+   [ 1,       2592000 ], # 0-30 days ago
+   [ 2592000, 5184000 ], # 30-60 days ago
+   [ 5184000, 7776000 ], # 60-90 days ago
+   [ 7776000, 0       ], # 90+   days ago
+  );
+
+  map { [ $_->[0] ? $self->_date - $_->[0] - 1 : '',
+          $_->[1] ? $self->_date - $_->[1] - 1 : '',
+      ] }
+  @ranges;
+}
+
 =item print_ps HASHREF | [ TIME [ , TEMPLATE ] ]
 
 Returns an postscript invoice, as a scalar.
@@ -3797,9 +3821,13 @@
   my( $pr_total, @pr_cust_bill ) = $self->previous; #previous balance
   my @b = ();
   foreach ( @pr_cust_bill ) {
+    my $date = $conf->exists('invoice_show_prior_due_date')
+               ? 'due '. $_->due_date2str($date_format)
+               : time2str('%x', $_->_date); # date_format here, too,
+                                            # but fix _items_cust_bill_pkg,
+                                            # header, others?
     push @b, {
-      'description' => 'Previous Balance, Invoice #'. $_->invnum. 
-                       ' ('. time2str('%x',$_->_date). ')',
+      'description' => 'Previous Balance, Invoice #'. $_->invnum. " ($date)",
       #'pkgpart'     => 'N/A',
       'pkgnum'      => 'N/A',
       'amount'      => sprintf("%.2f", $_->owed),
@@ -3875,6 +3903,7 @@
   my $unsquelched = $opt{unsquelched} || '';
   my $section = $opt{section}->{description} if $opt{section};
   my $summary_page = $opt{summary_page} || '';
+  my $multilocation = $opt{multilocation} || '';
 
   my @b = ();
   my ($s, $r, $u) = ( undef, undef, undef );
@@ -3922,10 +3951,15 @@
           $description .= ' Setup' if $cust_bill_pkg->recur != 0;
 
           my @d = ();
-          push @d, map &{$escape_function}($_),
-                       $cust_pkg->h_labels_short($self->_date)
-            unless $cust_pkg->part_pkg->hide_svc_detail
-                || $cust_bill_pkg->hidden;
+          unless ( $cust_pkg->part_pkg->hide_svc_detail
+                || $cust_bill_pkg->hidden )
+          {
+            push @d, map &{$escape_function}($_),
+                         $cust_pkg->h_labels_short($self->_date);
+            push @d, map &{$escape_function}($_),
+                         $cust_pkg->location_label_short
+              if $multilocation;
+          }
           push @d, $cust_bill_pkg->details(%details_opt)
             if $cust_bill_pkg->recur == 0;
 
@@ -3969,14 +4003,20 @@
           my $prev = $cust_bill_pkg->previous_cust_bill_pkg;
           push @dates, $prev->sdate if $prev;
 
-          push @d, map &{$escape_function}($_),
-                       $cust_pkg->h_labels_short(@dates)
-                                                 #$cust_bill_pkg->edate,
-                                                 #$cust_bill_pkg->sdate)
-            unless $cust_pkg->part_pkg->hide_svc_detail
+          unless ( $cust_pkg->part_pkg->hide_svc_detail
                 || $cust_bill_pkg->itemdesc
                 || $cust_bill_pkg->hidden
-                || $is_summary && $type && $type eq 'U';
+                || $is_summary && $type && $type eq 'U' )
+          {
+            push @d, map &{$escape_function}($_),
+                         $cust_pkg->h_labels_short(@dates)
+                                                   #$cust_bill_pkg->edate,
+                                                   #$cust_bill_pkg->sdate)
+            ;
+            push @d, map &{$escape_function}($_),
+                         $cust_pkg->location_label_short
+              if $multilocation;
+          }
 
           push @d, $cust_bill_pkg->details(%details_opt)
             unless ($is_summary || $type && $type eq 'R');

Index: Record.pm
===================================================================
RCS file: /home/cvs/cvsroot/freeside/FS/FS/Record.pm,v
retrieving revision 1.196.2.3
retrieving revision 1.196.2.4
diff -u -d -r1.196.2.3 -r1.196.2.4
--- Record.pm	3 Dec 2009 07:37:55 -0000	1.196.2.3
+++ Record.pm	16 Dec 2009 15:07:38 -0000	1.196.2.4
@@ -2764,6 +2764,25 @@
   $h ? $h->history_date : '';
 }
 
+=item scalar_sql SQL
+
+A class method with a propensity for becoming an instance method.  This
+method executes the sql statement represented by SQL and returns a scalar
+representing the result.  Don't ask for rows -- you get the first column
+of the first row.  Don't give me bogus SQL or I'll die on you.
+
+Returns an empty string in the event of no rows.
+
+=cut
+
+sub scalar_sql {
+  my($self, $sql ) = ( shift, shift );
+  my $sth = dbh->prepare($sql) or die dbh->errstr;
+  $sth->execute
+    or die "Unexpected error executing statement $sql: ". $sth->errstr;
+  $sth->fetchrow_arrayref->[0] || '';
+}
+
 =back
 
 =head1 SUBROUTINES



More information about the freeside-commits mailing list