=================================================================== RCS file: /cvs/RT/Invoicing/rt_invoices.pl,v retrieving revision 1.45 retrieving revision 1.50 diff -u -r1.45 -r1.50 --- RT/Invoicing/rt_invoices.pl 2011/12/31 02:14:32 1.45 +++ RT/Invoicing/rt_invoices.pl 2013/06/20 05:36:06 1.50 @@ -1,5 +1,5 @@ #!/usr/bin/perl -# $AFresh1: rt_invoices.pl,v 1.44 2011/12/30 05:01:41 andrew Exp $ +# $AFresh1: rt_invoices.pl,v 1.49 2013/02/05 03:41:58 andrew Exp $ ######################################################################## # Copyright (c) 2011 Andrew Fresh # @@ -28,6 +28,8 @@ use File::Path; use DateTime; +use List::Util qw/ sum /; + use lib './lib'; # XXX This is fragile, there are better ways use RTI::Config; use RTI::State; @@ -135,8 +137,10 @@ if ( my $unpaid_invoices = $state->unpaid_invoices() ) { foreach my $custid ( keys %{$unpaid_invoices} ) { - my %project = ( title => 'Unpaid Invoices', fees => [], ); + my %project + = ( title => 'Unpaid Invoices', fees => [], no_total => 1 ); my $past_due = 0; + my $unpaid = 0; my $cust; foreach ( @{$customers} ) { @@ -147,39 +151,74 @@ } $cust ||= fake_customer($custid); - foreach my $id ( sort { $a <=> $b } - keys %{ $unpaid_invoices->{$custid} } ) + foreach my $id ( + sort { $a <=> $b } + keys %{ $unpaid_invoices->{$custid} } + ) { my $unpaid = $state->get_invoice($id); my $invdate = ymd_to_DateTime( $unpaid->{invdate} ); - next - if $cust->{duedate} - && DateTime->compare( $invdate, $cust->{duedate} ) > 0; + my $content + = sprintf( "Invoice %06d from %s", $id, $invdate->ymd ); + if ( $cust->{duedate} && $invdate < $cust->{duedate}) { + $content = "PAST DUE: $content"; + $past_due += $unpaid_invoices->{$custid}->{$id}; + } + else { + $unpaid += $unpaid_invoices->{$custid}->{$id}; + } - $past_due += $unpaid_invoices->{$custid}->{$id}; push @{ $project{fees} }, { - id => $id, - contents => - sprintf( "Invoice %06d from %s", $id, $invdate->ymd ), - count => 1, - rate => $unpaid_invoices->{$custid}->{$id}, + id => $id, + contents => $content, + count => 1, + rate => $unpaid_invoices->{$custid}->{$id}, }; } if ($past_due) { - $cust->{invoice} ||= make_invoice(); + $cust->{invoice} ||= make_invoice($cust); $cust->{invoice}->{past_due} = $past_due; - $cust->{invoice}->{total_due} - = $cust->{invoice}->{total} + $past_due; + $cust->{invoice}->{unpaid} = $unpaid; unshift @{ $cust->{invoice}->{projects} }, \%project; } } } +if ( my $credits = $state->credits ) { + foreach my $custid ( keys %{$credits} ) { + + my $cust; + foreach ( @{$customers} ) { + if ( $_->{id} eq $custid ) { + $cust = $_; + last; + } + } + + next unless $cust; + next unless $cust->{invoice}; + next unless $credits->{$custid} < 0; + + $cust->{invoice}->{credit} = $credits->{$custid}; + + unshift @{ $cust->{invoice}->{projects} }, { + title => 'Credits', + no_total => 1, + fees => [ + { contents => 'Available Credit', + count => 1, + rate => -$credits->{$custid}, + } + ], + }; + } +} + foreach my $cust ( @{$customers} ) { my $invoice = $cust->{invoice}; next unless $invoice && $invoice->{projects} && @{ $invoice->{projects} }; @@ -201,6 +240,8 @@ $subtotal += round( $expense->{amount} ); } $project->{total} = $subtotal; + + next if $project->{no_total}; $invoice->{total} += $subtotal; } @{ $invoice->{transactions} } = sort { $a <=> $b } keys %transactions; @@ -219,6 +260,11 @@ $invoice->{total} -= round( $invoice->{discount}{amount} ); } + if ($invoice->{past_due}) { + $invoice->{total_due} + = sum( @{ $invoice }{ qw/ total past_due unpaid / } ); + } + next unless $invoice->{total} > 0 || $invoice->{total_due}; $invoice->{info} = $config->get('info'); @@ -330,8 +376,10 @@ sub make_invoice { my ($cust) = @_; - my %invoice - = ( end => $cust->{billend}->clone->subtract( seconds => 1 ) ); + my %invoice = ( + end => $cust->{billend}->clone->subtract( seconds => 1 ), + total => 0, + ); $invoice{start} = $cust->{startinvoicedate}->clone if $cust->{startinvoicedate}; @@ -490,7 +538,7 @@ # XXX Only need $ticket for the alternate subject my $work_time = sprintf "%.03f", $txn->time_taken / 60; - my $work_type = $txn->cf('WorkType'); + my $work_type = $txn->cf('WorkType') || ''; if ( $work_type =~ s/\s*Onsite//i ) {