From 49e08fcef54f4c4a3463d91f1cfcb69f121b2c5a Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Sun, 30 Dec 2012 15:35:43 -0800 Subject: [PATCH] generate E911 charges in IPifony download, #18333 --- FS/bin/freeside-ipifony-download | 133 ++++++++++++++++++++++++++++++--------- 1 file changed, 104 insertions(+), 29 deletions(-) diff --git a/FS/bin/freeside-ipifony-download b/FS/bin/freeside-ipifony-download index 64905e193..837cc3329 100644 --- a/FS/bin/freeside-ipifony-download +++ b/FS/bin/freeside-ipifony-download @@ -12,7 +12,18 @@ use FS::Conf; use Text::CSV; my %opt; -getopts('va:P:C:T:', \%opt); +getopts('va:P:C:e:', \%opt); + +# Product codes that are subject to flat rate E911 charges. For these +# products, the'quantity' field represents the number of lines. +my @E911_CODES = ( 'V-HPBX', 'V-TRUNK' ); + +# Map TAXNONVOICE/TAXVOICE to Freeside taxclass names +my %TAXCLASSES = ( + 'TAXNONVOICE' => 'Other', + 'TAXVOICE' => 'VoIP', +); + #$Net::SFTP::Foreign::debug = -1; sub HELP_MESSAGE { ' @@ -22,7 +33,7 @@ sub HELP_MESSAGE { ' [ -a archivedir ] [ -P port ] [ -C category ] - [ -T taxclass ] + [ -e pkgpart ] freesideuser sftpuser@hostname[:path] ' } @@ -30,12 +41,14 @@ my @fields = ( 'custnum', 'date_desc', 'quantity', - 'amount', + 'unit_price', 'classname', + 'taxclass', ); my $user = shift or die &HELP_MESSAGE; -adminsuidsetup $user; +my $dbh = adminsuidsetup $user; +$FS::UID::AutoCommit = 0; # for statistics my $num_charges = 0; @@ -51,6 +64,16 @@ if ( $opt{a} ) { unless -w $opt{a}; } +my $e911_part_pkg; +if ( $opt{e} ) { + $e911_part_pkg = FS::part_pkg->by_key($opt{e}) + or die "E911 pkgpart $opt{e} not found.\n"; + + if ( $e911_part_pkg->base_recur > 0 or $e911_part_pkg->freq ) { + die "E911 pkgpart $opt{e} must be a one-time charge.\n"; + } +} + my $categorynum = ''; if ( $opt{C} ) { # find this category (don't auto-create it, it should exist already) @@ -61,8 +84,6 @@ if ( $opt{C} ) { $categorynum = $category->categorynum; } -my $taxclass = $opt{T} || ''; - #my $tmpdir = File::Temp->newdir(); my $tmpdir = tempdir( CLEANUP => 1 ); #DIR=>somewhere? @@ -88,7 +109,7 @@ my $sftp = Net::SFTP::Foreign->new( port => $port, # for now we don't support passwords. use authorized_keys. timeout => 30, - more => ($opt{v} ? '-v' : ''), + #more => ($opt{v} ? '-v' : ''), ); die "failed to connect to '$sftpuser\@$host'\n(".$sftp->error.")\n" if $sftp->error; @@ -100,6 +121,12 @@ if (!@$files) { print STDERR "No charge files found.\n" if $opt{v}; exit(-1); } + +my %cust_main; # cache +my %e911_qty; # custnum => sum of E911-subject quantity + +my %is_e911 = map {$_ => 1} @E911_CODES; + FILE: foreach my $filename (@$files) { print STDERR "Retrieving $filename\n" if $opt{v}; $sftp->get("$filename", "$tmpdir/$filename"); @@ -133,7 +160,7 @@ FILE: foreach my $filename (@$files) { open my $fh, "<$tmpdir/$filename"; my $header = <$fh>; - if ($header !~ /^cust_id/) { + if ($header !~ /^"cust_id"/) { warn "warning: $filename has incorrect header row:\n$header\n"; # but try anyway } @@ -145,7 +172,8 @@ FILE: foreach my $filename (@$files) { next FILE; }; @hash{@fields} = $csv->fields(); - my $cust_main = FS::cust_main->by_key($hash{custnum}); + my $cust_main = + $cust_main{$hash{custnum}} ||= FS::cust_main->by_key($hash{custnum}); if (!$cust_main) { warn "customer #$hash{custnum} not found\n"; next; @@ -153,13 +181,14 @@ FILE: foreach my $filename (@$files) { print STDERR "Found customer #$hash{custnum}: ".$cust_main->name."\n" if $opt{v}; + my $amount = sprintf('%.2f',$hash{quantity} * $hash{unit_price}); # construct arguments for $cust_main->charge - my %opt = ( - amount => $hash{amount}, + my %charge_opt = ( + amount => $amount, quantity => $hash{quantity}, start_date => $cust_main->next_bill_date, pkg => $hash{date_desc}, - taxclass => $taxclass, + taxclass => $TAXCLASSES{ $hash{taxclass} }, ); if (my $classname = $hash{classname}) { if (!exists($classnum_of{$classname}) ) { @@ -182,11 +211,11 @@ FILE: foreach my $filename (@$files) { $classnum_of{$classname} = $pkg_class->classnum; } - $opt{classnum} = $classnum_of{$classname}; + $charge_opt{classnum} = $classnum_of{$classname}; } - print STDERR " Charging $hash{amount}\n" + print STDERR " Charging $hash{unit_price} * $hash{quantity}\n" if $opt{v}; - my $error = $cust_main->charge(\%opt); + my $error = $cust_main->charge(\%charge_opt); if ($error) { warn "Error creating charge: $error" if $error; $num_errors++; @@ -194,48 +223,94 @@ FILE: foreach my $filename (@$files) { $num_charges++; $sum_charges += $hash{amount}; } + + if ( $opt{e} and $is_e911{$hash{classname}} ) { + $e911_qty{$hash{custnum}} ||= 0; + $e911_qty{$hash{custnum}} += $hash{quantity}; + } } #while $line close $fh; } #FILE +# Order E911 packages +my $num_e911 = 0; +my $num_lines = 0; +foreach my $custnum ( keys (%e911_qty) ) { + my $cust_main = $cust_main{$custnum}; + my $quantity = $e911_qty{$custnum}; + next if $quantity == 0; + my $cust_pkg = FS::cust_pkg->new({ + pkgpart => $opt{e}, + custnum => $custnum, + start_date => $cust_main->next_bill_date, + quantity => $quantity, + }); + my $error = $cust_main->order_pkg({ cust_pkg => $cust_pkg }); + if ( $error ) { + warn "Error creating e911 charge for customer $custnum: $error\n"; + $num_errors++; + } else { + $num_e911++; + $num_lines += $quantity; + } +} + +$dbh->commit; + if ($opt{v}) { print STDERR " Finished! Processed files: @$files Created charges: $num_charges Sum of charges: \$".sprintf('%0.2f', $sum_charges)." + E911 charges: $num_e911 + E911 lines: $num_lines Errors: $num_errors "; } =head1 NAME -freeside-eftca-download - Retrieve payment batch responses from EFT Canada. +freeside-ipifony-download - Download and import invoice items from IPifony. =head1 SYNOPSIS - freeside-eftca-download [ -v ] [ -a archivedir ] user + freeside-ipifony-download + [ -v ] + [ -a archivedir ] + [ -P port ] + [ -C category ] + [ -T taxclass ] + [ -e pkgpart ] + freesideuser sftpuser@hostname[:path] -=head1 DESCRIPTION +=head1 REQUIRED PARAMETERS -Command line tool to download returned payment reports from the EFT Canada -gateway and void the returned payments. Uses the login and password from -'batchconfig-eft_canada'. +I: the Freeside user to run as. --v: Be verbose. +I: the SFTP user to connect as. The 'freeside' system user should +have an authorization key to connect as that user. --a directory: Archive response files in the provided directory. +I: the SFTP server. + +=head1 OPTIONAL PARAMETERS + +-v: Be verbose. -user: freeside username +-a I: Save a copy of the downloaded file to I. -=head1 BUGS +-P I: Connect to that TCP port. -You need to manually SFTP to ftp.eftcanada.com from the freeside account -and accept their key before running this script. +-C I: The name of a package category to use when creating package +classes. -=head1 SEE ALSO +-e I: The pkgpart (L) to use for E911 charges. A +package of this type will be ordered for each invoice that has E911-subject +line items. The 'quantity' field on this package will be set to the total +quantity of those line items. -L +The E911 package must be a one-time package (flat rate, no frequency, no +recurring fee) with setup fee equal to the fee per line. =cut -- 2.11.0