=================================================================== RCS file: /cvs/RT/Invoicing/rt_invoices.pl,v retrieving revision 1.3 retrieving revision 1.5 diff -u -r1.3 -r1.5 --- RT/Invoicing/rt_invoices.pl 2011/03/21 04:19:25 1.3 +++ RT/Invoicing/rt_invoices.pl 2011/03/21 18:36:59 1.5 @@ -80,7 +80,7 @@ $end->subtract( seconds => 1 ); - $startdate = $start->clone if $startdate > $start; + $startdate = $start->clone if !$startdate || $startdate > $start; $invoice{start} ||= $start->clone; $invoice{end} = $end->clone; my %hours = ( @@ -137,12 +137,6 @@ # XXX This should be a config option qw/ open stalled resolved /; -#push @limits, -# { -# attribute => 'resolved', -# operator => '>=', -# value => '2011-03-01' -# }; if ($startdate) { push @limits, { @@ -152,21 +146,25 @@ }; } -#push @limits, { attribute => 'id', operator => '=', value => '51' }; -#push @limits, { attribute => '', operator => '', value => '' }; - my $results = $tickets->search( limits => \@limits, orderby => 'id', ); -#print Dump $ticket, $results; - my $count = $results->count; print "There are $count results that matched your query\n"; my $iterator = $results->get_iterator; while ( my $ticket = &$iterator ) { + my $invoice = find_invoice_for_ticket( \@invoices, $ticket ); + + if ( !$invoice ) { + say "No invoice found for ticket " . $ticket->id; + + # XXX should construct a "new" invoice to pop onto the list + next; + } + my %project = ( id => $ticket->id, queue => $ticket->queue, @@ -182,35 +180,6 @@ expenses => [], ); - my $invoice; -INVOICE: foreach my $i (@invoices) { - next INVOICE unless $i->{match}; - foreach my $m ( @{ $i->{match} } ) { - my $type = $m->{type}; - my $thing = join ' ', $ticket->$type; - - if ( $m->{$type} ) { - my $match = lc $m->{$type}; - next INVOICE unless lc($thing) ~~ $match; - } - elsif ( $m->{regex} ) { - next INVOICE unless $thing ~~ /\Q$m->{regex}\E/; - } - else { - warn "Invalid match!"; - next INVOICE; - } - } - $invoice = $i; - } - - if ( !$invoice ) { - say "No invoice found for ticket " . $ticket->id; - - # XXX should construct a "new" invoice to pop onto the list - next; - } - #foreach my $r ($ticket->requestors) { # $users->id( $r ); # $users->retrieve; @@ -238,49 +207,22 @@ next if $invoice->{start} && $invoice->{start} > $txn_date; next if $invoice->{end} < $txn_date; - my $hours = {}; - if ( $invoice->{hours} ) { - foreach my $h ( @{ $invoice->{hours} } ) { - next if $h->{start} && $h->{start} > $txn_date; - next if $h->{end} < $txn_date; + my $fee = make_fee( $ticket, $txn, $invoice->{rates} ); + push @{ $project{fees} }, $fee; - $hours = $h->{hours}; - last; - } - } + my $hours = hours_for_date( $invoice, $txn_date ); - my $work_time = sprintf "%.03f", $txn->time_taken / 60; - my $work_type = $txn->cf('WorkType'); - my $work_rate - = $invoice->{rates}{$work_type} - || $invoice->{rates}{default} - || 0; - my $h_type - = exists $hours->{$work_type} - ? $work_type + = exists $hours->{ $fee->{type} } + ? $fee->{type} : 'default'; - my %fee = ( - id => $txn->id, - contents => $txn->created . ' (' - . $txn->id . ')' . "\n\n" - . ( $txn->data || $ticket->subject ), - count => $work_time, - rate => $work_rate, - ); - if ( $work_type && $work_type ne 'Normal' ) { - $fee{detail} = $work_type . ' rate'; - } + next unless exists $hours->{$h_type} && $hours->{$h_type} > 0; - push @{ $project{fees} }, \%fee; - - next unless $hours->{$h_type} && $hours->{$h_type} > 0; - my $discount_time = 0; - if ( $hours->{$h_type} > $work_time ) { - $hours->{$h_type} -= $work_time; - $discount_time = $work_time; + if ( $hours->{$h_type} > $fee->{count} ) { + $hours->{$h_type} -= $fee->{count}; + $discount_time = $fee->{count}; } else { $discount_time = $hours->{$h_type}; @@ -288,9 +230,11 @@ } if ($discount_time) { - $fee{detail} = "$discount_time $work_type Hours Discounted"; - $invoice->{discount}{amount} += $discount_time * $fee{rate}; - $invoice->{discount}{hours}{$work_type} += $discount_time; + $invoice->{discount}{amount} += $discount_time * $fee->{rate}; + $invoice->{discount}{hours}{$h_type} += $discount_time; + + $h_type = '' if $h_type eq 'default'; + $fee->{detail} = "$discount_time $h_type Hours Discounted"; } #print Dump $txn; exit; @@ -368,19 +312,85 @@ return sprintf "%.02f", $amount; } +sub find_invoice_for_ticket { + my ( $invoices, $ticket ) = @_; + +INVOICE: foreach my $i ( @{$invoices} ) { + next INVOICE unless $i->{match}; + foreach my $m ( @{ $i->{match} } ) { + my $type = $m->{type}; + my $thing = join ' ', $ticket->$type; + + if ( $m->{$type} ) { + my $match = lc $m->{$type}; + next INVOICE unless lc($thing) ~~ $match; + } + elsif ( $m->{regex} ) { + next INVOICE unless $thing ~~ /\Q$m->{regex}\E/; + } + else { + warn "Invalid match!"; + next INVOICE; + } + } + return $i; + } +} + +sub make_fee { + my ( $ticket, $txn, $rates ) = @_; + + my $work_time = sprintf "%.03f", $txn->time_taken / 60; + my $work_type = $txn->cf('WorkType'); + my $work_rate = $rates->{$work_type} || $rates->{default} || 0; + + my %fee = ( + id => $txn->id, + contents => $txn->created . ' (' + . $txn->id . ')' . "\n\n" + . ( $txn->data || $ticket->subject ), + count => $work_time, + rate => $work_rate, + type => $work_type, + ); + + if ( $work_type && $work_type ne 'Normal' ) { + $fee{detail} = $work_type . ' rate'; + } + + return \%fee; +} + +sub hours_for_date { + my ( $invoice, $date ) = @_; + + my $hours = {}; + if ( $invoice->{hours} ) { + foreach my $h ( @{ $invoice->{hours} } ) { + next if $h->{start} && $h->{start} > $date; + next if $h->{end} < $date; + + $hours = $h->{hours}; + last; + } + } + return $hours; +} + package RTI::Config; use strict; use warnings; use 5.010; -use YAML::Any qw/ LoadFile /; +use YAML::Any qw/ LoadFile Dump Load /; sub new { my ( $class, $args ) = @_; my $self = { file => '', }; bless $self, $class; + my $file = $args->{file} || $self->_find_config; $self->read_config($file); @@ -412,7 +422,7 @@ if ( $c->{default} ) { foreach my $cust ( @{ $c->{customers} } ) { foreach my $k ( keys %{ $c->{default} } ) { - $cust->{$k} //= $c->{default}->{$k}; + $cust->{$k} //= Load( Dump( $c->{default}->{$k} ) ); } } } @@ -423,9 +433,7 @@ sub get { my ( $self, $key ) = @_; - - # XXX This should deep copy? not a reference would be good - return $self->{_config}->{$key}; + return Load( Dump( $self->{_config}->{$key} ) ); } package RTI::State;