#!/usr/bin/perl # Copyright © 2018, Bradley M. Kuhn # License: AGPL-3.0-or-later use strict; use warnings; use autodie qw(:all); use Getopt::Long; use File::Spec; use Date::Manip qw(ParseDate UnixDate); my($VERBOSE, $INTERACTIVE, $RT_CMD, $SVN_CMD, %AMOUNTS, $SHOW_AMOUNTS, $QUERY_STRING, $SUB_TOTALS); ############################################################################### sub TicketIDsReadyForPayment () { my @ticketSpecs; my $queryString = $QUERY_STRING; if (not defined $queryString or $queryString =~ /^\s*$/) { $queryString = "Status = 'ready-for-payment' and Owner = 'bkuhn' and Queue = 'outreachy-interns' and Subject like '%2019-12%'"; $queryString = "Status = 'ready-for-payment' and Owner = 'bkuhn' and Due < '2020-04-30'"; $queryString = "Status = 'ready-for-payment'"; $queryString = "Status = 'ready-for-payment' and 'CF.{payment-method}' = 'USD PayPal'"; $queryString = "Status = 'ready-for-payment'"; } print "Using $queryString\n"; open(my $rtLsFH, "-|", "$RT_CMD", "ls", "-i", $queryString); print "Running: rt ls -i Status=ready-for-payment\n" if ($VERBOSE >= 10); while (my $lsLine = <$rtLsFH>) { print "rt ls line from Ready for payment search: $lsLine" if ($VERBOSE >= 10); chomp $lsLine; next if $lsLine =~ /^\s*$/; # There are sometimes blank lines in the rt ls -i output, push(@ticketSpecs, $lsLine); # particularly with 0 results, and no empty strings go on this list } print "Done: rt ls -i Status=ready-for-payment\n" if ($VERBOSE >= 10); close $rtLsFH; return @ticketSpecs; } ############################################################################### sub FindMostRecentPaymentMethodForTicket ($) { my($ticketSpec) = @_; my $paymentMethod; $ticketSpec =~ s%^\s*ticket\s*/\s*%%; open(my $rtShowFH, "-|", "$RT_CMD", "show", '-t', 'ticket', '-f', 'CF.{payment-method}', $ticketSpec); my($ticketDataAgain, $value) = <$rtShowFH>; close $rtShowFH; chomp $value; $value =~ s/^\s*cf.\{payment-method\}\s*:\s+(.*)$/$1/i or warn "$ticketSpec: Unknown value for payment-method of \"$value\""; if (not defined $value or $value =~ /^\s*$/) { $value = "NO-CF-SET"; } if ($SHOW_AMOUNTS) { open(my $rtShowFH, "-|", "$RT_CMD", "show", '-t', 'ticket', '-f', 'CF.{payment-amount}', $ticketSpec); my($ticketDataYetAgain, $curAndAmount) = <$rtShowFH>; close $rtShowFH; chomp $curAndAmount; $curAndAmount =~ s/^\s*cf.\{payment-amount\}\s*:\s+(.*)$/$1/i; $ticketSpec =~ s%^\s*ticket\s*/\s*%%; $curAndAmount = "USD -32767.69" if not defined $curAndAmount; $curAndAmount =~ /^\s*([A-Z]{3,3})\s+([\-\d\,\.]+)\s*$/ or die "Ticket, $ticketSpec, has amount of $curAndAmount"; ($AMOUNTS{$ticketSpec}{currency}, $AMOUNTS{$ticketSpec}{amount}) = ($1, $2); $AMOUNTS{$ticketSpec}{amount} =~ s/\$//g; $AMOUNTS{$ticketSpec}{amount} =~ s/,//g; $AMOUNTS{$ticketSpec}{currency} =~ s/\s//g; } return $value; } ############################################################################### GetOptions("verbose=i" => \$VERBOSE, "interactive" => \$INTERACTIVE, 'showAmounts' => \$SHOW_AMOUNTS, 'subTotals' => \$SUB_TOTALS, "rtCommand=s" => \$RT_CMD, "svnCommand=s" => \$SVN_CMD, 'queryString=s' => \$QUERY_STRING); $SHOW_AMOUNTS = 1 if $SUB_TOTALS; $RT_CMD = '/usr/bin/rt' unless defined $RT_CMD; $SVN_CMD = '/usr/bin/svn' unless defined $SVN_CMD; $INTERACTIVE = 0 if not defined $INTERACTIVE; my @ticketSpecs = TicketIDsReadyForPayment(); if (@ticketSpecs <= 0) { print "No tickets found that are ready for payment at this time\n"; exit 0; } my %payments; print "Total tickets ready for payment is: ", scalar(@ticketSpecs), "\n\n"; foreach my $ticketSpec (@ticketSpecs) { my $paymentMethod = FindMostRecentPaymentMethodForTicket($ticketSpec); print STDERR "$ticketSpec has payment method of $paymentMethod\n" if ($VERBOSE > 6); if (not defined $paymentMethod) { warn "Cannot find payment method for ticket, $ticketSpec"; $paymentMethod = "UNKNOWN PAYMENT METHOD"; } push(@{$payments{$paymentMethod}}, $ticketSpec); } print "#" x 70, "\n"; my $overallTotalOk = 1; my %overallTotals; foreach my $paymentMethod (sort { $a cmp $b } keys %payments) { print "$paymentMethod: Count: ", scalar(@{$payments{$paymentMethod}}), "\n"; print " Tickets: ", join(" ", map { s%^\s*ticket\s*/\s*%%; $_; } @{$payments{$paymentMethod}}), "\n"; my $subTotalOk = 1; my %subTotals; if ($SUB_TOTALS) { foreach my $tix (@{$payments{$paymentMethod}}) { $tix =~ s%^\s*ticket\s*/\s*%%; my($currency, $val) = ($AMOUNTS{$tix}{currency}, $AMOUNTS{$tix}{amount}); $subTotals{$currency} = 0.00 unless defined $subTotals{$currency}; print sprintf(" %5d: %.2f %3.3s\n", $tix, $val, $currency); if (defined $val and $val =~ /^[\d\.]+$/) { $subTotals{$currency} += $val; } else { $subTotalOk = 0; } } if ($subTotalOk) { print sprintf("%30s", "SUBTOTAL for $paymentMethod\n"); foreach my $currency (keys %subTotals) { print sprintf("%30s %.2f %3.3s\n\n", " ", $subTotals{$currency}, $currency); $overallTotals{$currency} = 0.00 unless defined $overallTotals{$currency}; $overallTotals{$currency} += $subTotals{$currency}; } } else { $overallTotalOk = 0; } } } if ($SHOW_AMOUNTS and not $SUB_TOTALS) { print "Unable to find amounts for all tickets\n" if (scalar(@ticketSpecs) != scalar(keys %AMOUNTS)); foreach my $tix (sort { $a <=> $b} (keys %AMOUNTS)) { foreach my $currency (keys %overallTotals) { my $val = $AMOUNTS{$tix}{$currency}; print sprintf("%5d: %.2f %3.3d\n", $tix, $val, $currency); $overallTotals{$currency} = 0.00 unless defined $overallTotals{$currency}; if ($val =~ /^[\d\.]+$/) { $overallTotals{$currency} += $val; } else { $overallTotalOk = 0; } } } } if ($overallTotalOk and $SHOW_AMOUNTS) { print sprintf("%30s:\n", "TOTAL AMOUNT"); foreach my $currency (keys %overallTotals) { print sprintf("%30s %.2f %3.3s\n\n", " ", $overallTotals{$currency}, $currency); } } ############################################################################### # # Local variables: # compile-command: "perl -c rt-bulk-prep-pay.plx" # perl-indent-level: 2 # End: