generate E911 charges in IPifony download, #18333
authorMark Wells <mark@freeside.biz>
Sun, 30 Dec 2012 23:35:43 +0000 (15:35 -0800)
committerMark Wells <mark@freeside.biz>
Sun, 30 Dec 2012 23:35:43 +0000 (15:35 -0800)
FS/bin/freeside-ipifony-download

index 64905e1..837cc33 100644 (file)
@@ -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<freesideuser>: the Freeside user to run as.
 
--v: Be verbose.
+I<sftpuser>: 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<hostname>: the SFTP server.
+
+=head1 OPTIONAL PARAMETERS
+
+-v: Be verbose.
 
-user: freeside username
+-a I<archivedir>: Save a copy of the downloaded file to I<archivedir>.
 
-=head1 BUGS
+-P I<port>: 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<category>: The name of a package category to use when creating package
+classes.
 
-=head1 SEE ALSO
+-e I<pkgpart>: The pkgpart (L<FS::part_pkg>) 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<FS::pay_batch>
+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