i think it is new Pg (or... new Record.pm???) that causes this problem... before...
[freeside.git] / FS / FS / cust_bill.pm
index 4acdd85..79f85c8 100644 (file)
@@ -16,6 +16,7 @@ use FS::Misc qw( send_email send_fax generate_ps generate_pdf do_print );
 use FS::Record qw( qsearch qsearchs dbh );
 use FS::cust_main_Mixin;
 use FS::cust_main;
+use FS::cust_statement;
 use FS::cust_bill_pkg;
 use FS::cust_bill_pkg_display;
 use FS::cust_credit;
@@ -82,6 +83,8 @@ 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:
 
+Regular fields
+
 =over 4
 
 =item invnum - primary key (assigned automatically for new invoices)
@@ -93,10 +96,26 @@ L<Time::Local> and L<Date::Parse> for conversion functions.
 
 =item charged - amount of this invoice
 
+=back
+
+Deprecated
+
+=over 4
+
 =item printed - deprecated
 
+=back
+
+Specific use cases
+
+=over 4
+
 =item closed - books closed flag, empty or `Y'
 
+=item statementnum - invoice aggregation (see L<FS::cust_statement>)
+
+=item agent_invid - legacy invoice number
+
 =back
 
 =head1 METHODS
@@ -183,17 +202,16 @@ sub check {
 
   my $error =
     $self->ut_numbern('invnum')
-    || $self->ut_number('custnum')
+    || $self->ut_foreign_key('custnum', 'cust_main', 'custnum' )
     || $self->ut_numbern('_date')
     || $self->ut_money('charged')
     || $self->ut_numbern('printed')
     || $self->ut_enum('closed', [ '', 'Y' ])
+    || $self->ut_foreign_keyn('statementnum', 'cust_statement', 'statementnum' )
+    || $self->ut_numbern('agent_invid') #varchar?
   ;
   return $error if $error;
 
-  return "Unknown customer"
-    unless qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
-
   $self->_date(time) unless $self->_date;
 
   $self->printed(0) if $self->printed eq '';
@@ -201,6 +219,22 @@ sub check {
   $self->SUPER::check;
 }
 
+=item display_invnum
+
+Returns the displayed invoice number for this invoice: agent_invid if
+cust_bill-default_agent_invid is set and it has a value, invnum otherwise.
+
+=cut
+
+sub display_invnum {
+  my $self = shift;
+  if ( $conf->exists('cust_bill-default_agent_invid') && $self->agent_invid ){
+    return $self->agent_invid;
+  } else {
+    return $self->invnum;
+  }
+}
+
 =item previous
 
 Returns a list consisting of the total previous balance for this customer, 
@@ -451,7 +485,7 @@ sub cust_credited {
   ;
 }
 
-=item cust_bill_pay_pkgnum
+=item cust_bill_pay_pkgnum PKGNUM
 
 Returns all payment applications (see L<FS::cust_bill_pay>) for this invoice
 with matching pkgnum.
@@ -467,7 +501,7 @@ sub cust_bill_pay_pkgnum {
            );
 }
 
-=item cust_credited_pkgnum
+=item cust_credited_pkgnum PKGNUM
 
 Returns all applied credits (see L<FS::cust_credit_bill>) for this invoice
 with matching pkgnum.
@@ -531,12 +565,20 @@ sub owed_pkgnum {
   $balance;
 }
 
-=item apply_payments_and_credits
+=item apply_payments_and_credits [ OPTION => VALUE ... ]
+
+Applies unapplied payments and credits to this invoice.
+
+A hash of optional arguments may be passed.  Currently "manual" is supported.
+If true, a payment receipt is sent instead of a statement when
+'payment_receipt_email' configuration option is set.
+
+If there is an error, returns the error, otherwise returns false.
 
 =cut
 
 sub apply_payments_and_credits {
-  my $self = shift;
+  my( $self, %options ) = @_;
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
@@ -628,12 +670,12 @@ sub apply_payments_and_credits {
     }
     next unless $owed > 0;
 
-    warn "min ( $unapp_amount, $owed )\n";
+    warn "min ( $unapp_amount, $owed )\n" if $DEBUG;
     $app->amount( sprintf('%.2f', min( $unapp_amount, $owed ) ) );
 
     $app->invnum( $self->invnum );
 
-    my $error = $app->insert;
+    my $error = $app->insert(%options);
     if ( $error ) {
       $dbh->rollback if $oldAutoCommit;
       return "Error inserting ". $app->table. " record: $error";
@@ -794,8 +836,11 @@ sub generate_email {
       push @otherparts, build MIME::Entity
         'Type'        => 'text/csv',
         'Encoding'    => '7bit',
-        'Data'        => [ map { "$_\n" } $self->call_details ],
+        'Data'        => [ map { "$_\n" }
+                             $self->call_details('prepend_billed_number' => 1)
+                         ],
         'Disposition' => 'attachment',
+        'Filename'    => 'usage-'. $self->invnum. '.csv',
       ;
 
     }
@@ -1812,7 +1857,7 @@ sub print_generic {
 
   my( $self, %params ) = @_;
   my $today = $params{today} ? $params{today} : time;
-  warn "FS::cust_bill::print_generic called on $self with suffix $params{template}\n"
+  warn "$me print_generic called on $self with suffix $params{template}\n"
     if $DEBUG;
 
   my $format = $params{format};
@@ -2163,7 +2208,7 @@ sub print_generic {
   $invoice_data{'total_items'} = \@total_items;
   $invoice_data{'buf'} = \@buf;
   $invoice_data{'sections'} = \@sections;
-  
+
   my $previous_section = { 'description' => 'Previous Charges',
                            'subtotal'    => $other_money_char.
                                             sprintf('%.2f', $pr_total),
@@ -2336,7 +2381,7 @@ sub print_generic {
     }
   }
   $invoice_data{'taxtotal'} = sprintf('%.2f', $taxtotal);
-  
+
   push @buf,['','-----------'];
   push @buf,[( $conf->exists('disable_previous_balance') 
                ? 'Total Charges'
@@ -2411,7 +2456,7 @@ sub print_generic {
     foreach my $credit ( $self->_items_credits('trim_len'=>32) ) {
       push @buf, [ $credit->{'description'}, $money_char.$credit->{'amount'} ];
     }
-  
+
     # payments
     my $paymenttotal = 0;
     foreach my $payment ( $self->_items_payments ) {
@@ -2920,8 +2965,6 @@ sub _items_cust_bill_pkg {
 
       my $type = $display->type;
 
-      my $cust_pkg = $cust_bill_pkg->cust_pkg;
-
       my $desc = $cust_bill_pkg->desc;
       $desc = substr($desc, 0, 50). '...'
         if $format eq 'latex' && length($desc) > 50;
@@ -2933,6 +2976,8 @@ sub _items_cust_bill_pkg {
 
       if ( $cust_bill_pkg->pkgnum > 0 ) {
 
+        my $cust_pkg = $cust_bill_pkg->cust_pkg;
+
         if ( $cust_bill_pkg->setup != 0 && (!$type || $type eq 'S') ) {
 
           my $description = $desc;
@@ -3129,20 +3174,36 @@ sub _items_payments {
 
 }
 
-=item call_details
+=item call_details [ OPTION => VALUE ... ]
 
 Returns an array of CSV strings representing the call details for this invoice
+The only option available is the boolean prepend_billed_number
 
 =cut
 
 sub call_details {
-  my $self = shift;
-  map { $_->details( 'format_function' => sub{ shift },
-                     'escape_function' => sub{ return() },
-                   )
-      }
-    grep { $_->pkgnum }
-    $self->cust_bill_pkg;
+  my ($self, %opt) = @_;
+
+  my $format_function = sub { shift };
+
+  if ($opt{prepend_billed_number}) {
+    $format_function = sub {
+      my $detail = shift;
+      my $row = shift;
+
+      $row->amount ? $row->phonenum. ",". $detail : '"Billed number",'. $detail;
+      
+    };
+  }
+
+  my @details = map { $_->details( 'format_function' => $format_function,
+                                   'escape_function' => sub{ return() },
+                                 )
+                    }
+                  grep { $_->pkgnum }
+                  $self->cust_bill_pkg;
+  my $header = $details[0];
+  ( $header, grep { $_ ne $header } @details );
 }