add cust_credit_bill relating multiple invoices to credits
[freeside.git] / FS / FS / cust_bill.pm
index 2df92f7..4c1617f 100644 (file)
@@ -1,7 +1,7 @@
 package FS::cust_bill;
 
 use strict;
 package FS::cust_bill;
 
 use strict;
-use vars qw( @ISA $conf $invoice_template );
+use vars qw( @ISA $conf $invoice_template $money_char );
 use vars qw( $invoice_lines @buf ); #yuck
 use Date::Format;
 use Text::Template;
 use vars qw( $invoice_lines @buf ); #yuck
 use Date::Format;
 use Text::Template;
@@ -11,12 +11,17 @@ use FS::cust_bill_pkg;
 use FS::cust_credit;
 use FS::cust_pay;
 use FS::cust_pkg;
 use FS::cust_credit;
 use FS::cust_pay;
 use FS::cust_pkg;
+use FS::cust_credit_bill;
 
 @ISA = qw( FS::Record );
 
 #ask FS::UID to run this stuff for us later
 $FS::UID::callback{'FS::cust_bill'} = sub { 
 
 @ISA = qw( FS::Record );
 
 #ask FS::UID to run this stuff for us later
 $FS::UID::callback{'FS::cust_bill'} = sub { 
+
   $conf = new FS::Conf;
   $conf = new FS::Conf;
+
+  $money_char = $conf->config('money_char') || '$';  
+
   my @invoice_template = $conf->config('invoice_template')
     or die "cannot load config file invoice_template";
   $invoice_lines = 0;
   my @invoice_template = $conf->config('invoice_template')
     or die "cannot load config file invoice_template";
   $invoice_lines = 0;
@@ -60,13 +65,17 @@ FS::cust_bill - Object methods for cust_bill records
 
   @cust_pay_objects = $cust_bill->cust_pay;
 
 
   @cust_pay_objects = $cust_bill->cust_pay;
 
+  $tax_amount = $record->tax;
+
   @lines = $cust_bill->print_text;
   @lines = $cust_bill->print_text $time;
 
 =head1 DESCRIPTION
 
   @lines = $cust_bill->print_text;
   @lines = $cust_bill->print_text $time;
 
 =head1 DESCRIPTION
 
-An FS::cust_bill object represents an invoice.  FS::cust_bill inherits from
-FS::Record.  The following fields are currently supported:
+An FS::cust_bill object represents an invoice; a declaration that a customer
+owes you money.  The specific charges are itemized as B<cust_bill_pkg> records
+(see L<FS::cust_bill_pkg>).  FS::cust_bill inherits from FS::Record.  The
+following fields are currently supported:
 
 =over 4
 
 
 =over 4
 
@@ -79,9 +88,6 @@ L<Time::Local> and L<Date::Parse> for conversion functions.
 
 =item charged - amount of this invoice
 
 
 =item charged - amount of this invoice
 
-=item owed - amount still outstanding on this invoice, which is charged minus
-all payments (see L<FS::cust_pay>).
-
 =item printed - how many times this invoice has been printed automatically
 (see L<FS::cust_main/"collect">).
 
 =item printed - how many times this invoice has been printed automatically
 (see L<FS::cust_main/"collect">).
 
@@ -106,21 +112,6 @@ sub table { 'cust_bill'; }
 Adds this invoice to the database ("Posts" the invoice).  If there is an error,
 returns the error, otherwise returns false.
 
 Adds this invoice to the database ("Posts" the invoice).  If there is an error,
 returns the error, otherwise returns false.
 
-When adding new invoices, owed must be charged (or null, in which case it is
-automatically set to charged).
-
-=cut
-
-sub insert {
-  my $self = shift;
-
-  $self->owed( $self->charged ) if $self->owed eq '';
-  return "owed != charged!"
-    unless $self->owed == $self->charged;
-
-  $self->SUPER::insert;
-}
-
 =item delete
 
 Currently unimplemented.  I don't remove invoices because there would then be
 =item delete
 
 Currently unimplemented.  I don't remove invoices because there would then be
@@ -137,9 +128,8 @@ sub delete {
 Replaces the OLD_RECORD with this one in the database.  If there is an error,
 returns the error, otherwise returns false.
 
 Replaces the OLD_RECORD with this one in the database.  If there is an error,
 returns the error, otherwise returns false.
 
-Only owed and printed may be changed.  Owed is normally updated by creating and
-inserting a payment (see L<FS::cust_pay>).  Printed is normally updated by
-calling the collect method of a customer object (see L<FS::cust_main>).
+Only printed may be changed.  printed is normally updated by calling the
+collect method of a customer object (see L<FS::cust_main>).
 
 =cut
 
 
 =cut
 
@@ -149,7 +139,6 @@ sub replace {
   #return "Can't change _date!" unless $old->_date eq $new->_date;
   return "Can't change _date!" unless $old->_date == $new->_date;
   return "Can't change charged!" unless $old->charged == $new->charged;
   #return "Can't change _date!" unless $old->_date eq $new->_date;
   return "Can't change _date!" unless $old->_date == $new->_date;
   return "Can't change charged!" unless $old->charged == $new->charged;
-  return "(New) owed can't be > (new) charged!" if $new->owed > $new->charged;
 
   $new->SUPER::replace($old);
 }
 
   $new->SUPER::replace($old);
 }
@@ -170,7 +159,6 @@ sub check {
     || $self->ut_number('custnum')
     || $self->ut_numbern('_date')
     || $self->ut_money('charged')
     || $self->ut_number('custnum')
     || $self->ut_numbern('_date')
     || $self->ut_money('charged')
-    || $self->ut_money('owed')
     || $self->ut_numbern('printed')
   ;
   return $error if $error;
     || $self->ut_numbern('printed')
   ;
   return $error if $error;
@@ -217,15 +205,15 @@ sub cust_bill_pkg {
 =item cust_credit
 
 Returns a list consisting of the total previous credited (see
 =item cust_credit
 
 Returns a list consisting of the total previous credited (see
-L<FS::cust_credit>) for this customer, followed by the previous outstanding
-credits (FS::cust_credit objects).
+L<FS::cust_credit>) and unapplied for this customer, followed by the previous
+outstanding credits (FS::cust_credit objects).
 
 =cut
 
 sub cust_credit {
   my $self = shift;
   my $total = 0;
 
 =cut
 
 sub cust_credit {
   my $self = shift;
   my $total = 0;
-  my @cust_credit = sort { $a->_date <=> $b->date }
+  my @cust_credit = sort { $a->_date <=> $b->_date }
     grep { $_->credited != 0 && $_->_date < $self->_date }
       qsearch('cust_credit', { 'custnum' => $self->custnum } )
   ;
     grep { $_->credited != 0 && $_->_date < $self->_date }
       qsearch('cust_credit', { 'custnum' => $self->custnum } )
   ;
@@ -241,11 +229,55 @@ Returns all payments (see L<FS::cust_pay>) for this invoice.
 
 sub cust_pay {
   my $self = shift;
 
 sub cust_pay {
   my $self = shift;
-  sort { $a->_date <=> $b->date }
+  sort { $a->_date <=> $b->_date }
     qsearch( 'cust_pay', { 'invnum' => $self->invnum } )
   ;
 }
 
     qsearch( 'cust_pay', { 'invnum' => $self->invnum } )
   ;
 }
 
+=item cust_credited
+
+Returns all applied credits (see L<FS::cust_credit_bill>) for this invoice.
+
+=cut
+
+sub cust_credited {
+  my $self = shift;
+  sort { $a->_date <=> $b->_date }
+    qsearch( 'cust_credit_bill', { 'invnum' => $self->invnum } )
+  ;
+}
+
+=item tax
+
+Returns the tax amount (see L<FS::cust_bill_pkg>) for this invoice.
+
+=cut
+
+sub tax {
+  my $self = shift;
+  my $total = 0;
+  my @taxlines = qsearch( 'cust_bill_pkg', { 'invnum' => $self->invnum ,
+                                             'pkgnum' => 0 } );
+  foreach (@taxlines) { $total += $_->setup; }
+  $total;
+}
+
+=item owed
+
+Returns the amount owed (still outstanding) on this invoice, which is charged
+minus all payments (see L<FS::cust_pay>) and applied credits
+(see L<FS::cust_credit_bill>).
+
+=cut
+
+sub owed {
+  my $self = shift;
+  my $balance = $self->charged;
+  $balance -= $_->paid foreach ( $self->cust_pay );
+  $balance -= $_->amount foreach ( $self->cust_credited );
+  $balance = sprintf( "%.2f", $balance);
+}
+
 =item print_text [TIME];
 
 Returns an text invoice, as a list of lines.
 =item print_text [TIME];
 
 Returns an text invoice, as a list of lines.
@@ -281,12 +313,13 @@ sub print_text {
     push @buf, [
       "Previous Balance, Invoice #". $_->invnum. 
                  " (". time2str("%x",$_->_date). ")",
     push @buf, [
       "Previous Balance, Invoice #". $_->invnum. 
                  " (". time2str("%x",$_->_date). ")",
-      '$'. sprintf("%10.2f",$_->owed)
+      $money_char. sprintf("%10.2f",$_->owed)
     ];
   }
   if (@pr_cust_bill) {
     push @buf,['','-----------'];
     ];
   }
   if (@pr_cust_bill) {
     push @buf,['','-----------'];
-    push @buf,['Total Previous Balance','$' . sprintf("%10.2f",$pr_total ) ];
+    push @buf,[ 'Total Previous Balance',
+                $money_char. sprintf("%10.2f",$pr_total ) ];
     push @buf,['',''];
   }
 
     push @buf,['',''];
   }
 
@@ -300,7 +333,7 @@ sub print_text {
       my($pkg)=$part_pkg->pkg;
 
       if ( $_->setup != 0 ) {
       my($pkg)=$part_pkg->pkg;
 
       if ( $_->setup != 0 ) {
-        push @buf, [ "$pkg Setup",'$' . sprintf("%10.2f",$_->setup) ];
+        push @buf, [ "$pkg Setup", $money_char. sprintf("%10.2f",$_->setup) ];
         push @buf,
           map { [ "  ". $_->[0]. ": ". $_->[1], '' ] } $cust_pkg->labels;
       }
         push @buf,
           map { [ "  ". $_->[0]. ": ". $_->[1], '' ] } $cust_pkg->labels;
       }
@@ -309,33 +342,39 @@ sub print_text {
         push @buf, [
           "$pkg (" . time2str("%x",$_->sdate) . " - " .
                                 time2str("%x",$_->edate) . ")",
         push @buf, [
           "$pkg (" . time2str("%x",$_->sdate) . " - " .
                                 time2str("%x",$_->edate) . ")",
-          '$' . sprintf("%10.2f",$_->recur)
+          $money_char. sprintf("%10.2f",$_->recur)
         ];
         push @buf,
           map { [ "  ". $_->[0]. ": ". $_->[1], '' ] } $cust_pkg->labels;
       }
 
     } else { #pkgnum Tax
         ];
         push @buf,
           map { [ "  ". $_->[0]. ": ". $_->[1], '' ] } $cust_pkg->labels;
       }
 
     } else { #pkgnum Tax
-      push @buf,["Tax",'$' . sprintf("%10.2f",$_->setup) ] 
+      push @buf,["Tax", $money_char. sprintf("%10.2f",$_->setup) ] 
         if $_->setup != 0;
     }
   }
 
   push @buf,['','-----------'];
   push @buf,['Total New Charges',
         if $_->setup != 0;
     }
   }
 
   push @buf,['','-----------'];
   push @buf,['Total New Charges',
-             '$' . sprintf("%10.2f",$self->charged) ];
+             $money_char. sprintf("%10.2f",$self->charged) ];
   push @buf,['',''];
 
   push @buf,['','-----------'];
   push @buf,['Total Charges',
   push @buf,['',''];
 
   push @buf,['','-----------'];
   push @buf,['Total Charges',
-             '$' . sprintf("%10.2f",$self->charged + $pr_total) ];
+             $money_char. sprintf("%10.2f",$self->charged + $pr_total) ];
   push @buf,['',''];
 
   #credits
   push @buf,['',''];
 
   #credits
+  foreach ( $self->cust_credited ) {
+    push @buf,[
+      "Credit #". $_->crednum. " (" . time2str("%x",$_->_date) .")",
+      $money_char. sprintf("%10.2f",$_->amount)
+    ];
+  }
   foreach ( @cr_cust_credit ) {
     push @buf,[
       "Credit #". $_->crednum. " (" . time2str("%x",$_->_date) .")",
   foreach ( @cr_cust_credit ) {
     push @buf,[
       "Credit #". $_->crednum. " (" . time2str("%x",$_->_date) .")",
-      '$' . sprintf("%10.2f",$_->credited)
+      $money_char. sprintf("%10.2f",$_->credited)
     ];
   }
 
     ];
   }
 
@@ -343,13 +382,13 @@ sub print_text {
   foreach ( $self->cust_pay ) {
     push @buf,[
       "Payment received ". time2str("%x",$_->_date ),
   foreach ( $self->cust_pay ) {
     push @buf,[
       "Payment received ". time2str("%x",$_->_date ),
-      '$' . sprintf("%10.2f",$_->paid )
+      $money_char. sprintf("%10.2f",$_->paid )
     ];
   }
 
   #balance due
   push @buf,['','-----------'];
     ];
   }
 
   #balance due
   push @buf,['','-----------'];
-  push @buf,['Balance Due','$' 
+  push @buf,['Balance Due', $money_char
     sprintf("%10.2f",$self->owed + $pr_total - $cr_total ) ];
 
   #setup template variables
     sprintf("%10.2f",$self->owed + $pr_total - $cr_total ) ];
 
   #setup template variables
@@ -424,7 +463,7 @@ sub print_text {
 
 =head1 VERSION
 
 
 =head1 VERSION
 
-$Id: cust_bill.pm,v 1.3 2000-09-20 10:35:21 ivan Exp $
+$Id: cust_bill.pm,v 1.9 2001-09-01 21:52:19 jeff Exp $
 
 =head1 BUGS
 
 
 =head1 BUGS