Merge branch 'master' of git.freeside.biz:/home/git/freeside
authorIvan Kohler <ivan@freeside.biz>
Tue, 3 Nov 2015 17:00:21 +0000 (09:00 -0800)
committerIvan Kohler <ivan@freeside.biz>
Tue, 3 Nov 2015 17:00:21 +0000 (09:00 -0800)
16 files changed:
FS/FS/ClientAPI/MyAccount.pm
FS/FS/ClientAPI/Signup.pm
FS/FS/Template_Mixin.pm
FS/FS/cdr/amcom.pm
FS/FS/cust_svc.pm
FS/FS/log_context.pm
FS/FS/msg_template/InitialData.pm
FS/FS/part_pkg/discount_Mixin.pm
FS/FS/svc_Common.pm
FS/FS/svc_circuit.pm
FS/bin/freeside-paymentech-download
FS/bin/freeside-paymentech-upload
httemplate/elements/standardize_locations.js
httemplate/elements/tr-cust_svc.html
httemplate/misc/confirm-address_standardize.html
httemplate/search/report_tax-xls.cgi

index 89c70f7..f272cd4 100644 (file)
@@ -2521,8 +2521,8 @@ sub _do_bop_realtime {
 
         #this used to apply a credit, but now we can void invoices...
         foreach my $cust_bill (@cust_bill) {
-          my $voiderror = $cust_bill->void();
-          warn "Error voiding cust bill after decline: $voiderror";
+          my $voiderror = $cust_bill->void('automatic payment failed');
+          warn "Error voiding cust bill after decline: $voiderror" if $voiderror;
         }
 
       }
index bc69a5f..5d719c4 100644 (file)
@@ -830,8 +830,8 @@ sub new_customer {
 
       #this used to apply a credit, but now we can void invoices...
       foreach my $cust_bill (@cust_bill) {
-        my $voiderror = $cust_bill->void();
-        warn "Error voiding cust bill after decline: $voiderror";
+        my $voiderror = $cust_bill->void('automatic payment failed');
+        warn "Error voiding cust bill after decline: $voiderror" if $voiderror;
       }
 
       #should check list for errors...
index ffaef97..e02aa1f 100644 (file)
@@ -712,6 +712,8 @@ sub print_generic {
       # "balance_date_range" unfortunately is unsuitable for this, since it
       # cares about application dates.  We want to know the sum of all 
       # _top-level transactions_ dated before the last invoice.
+      #
+      # still do this for the "Previous Balance" line of the summary block
       my @sql =
         map "$_ WHERE _date <= ? AND custnum = ?", (
           "SELECT      COALESCE( SUM(charged), 0 ) FROM cust_bill",
@@ -744,19 +746,31 @@ sub print_generic {
       # longer stored in the database)
       $invoice_data{'true_previous_balance'} = $last_bill_balance;
 
-      # the change in balance from immediately after that invoice
-      # to immediately before this one
-      my $before_this_bill_balance = 0;
+      # Now, get all applications of credits/payments dated on or after the
+      # previous bill, to invoices before the current bill. (The
+      # credit/payment date restriction prevents these from intersecting
+      # the "Previous Balance" set.)
+      # These are "adjustments". The past due balance will be shown as
+      # Previous Balance - Adjustments.
+      my $adjustments = 0;
+      @sql = map {
+        "SELECT COALESCE(SUM(y.amount),0) FROM $_ JOIN cust_bill USING (invnum)
+         WHERE cust_bill._date < ?
+           AND x._date >= ?
+           AND cust_bill.custnum = ?"
+        } "cust_credit AS x JOIN cust_credit_bill y USING (crednum)",
+          "cust_pay    AS x JOIN cust_bill_pay    y USING (paynum)"
+      ;
       foreach (@sql) {
         my $delta = FS::Record->scalar_sql(
           $_,
-          $self->_date - 1,
+          $self->_date,
+          $last_bill->_date,
           $self->custnum,
         );
-        $before_this_bill_balance += $delta;
+        $adjustments += $delta;
       }
-      $invoice_data{'balance_adjustments'} =
-        sprintf("%.2f", $last_bill_balance - $before_this_bill_balance);
+      $invoice_data{'balance_adjustments'} = sprintf("%.2f", $adjustments);
 
       warn sprintf("BALANCE ADJUSTMENTS: %.2f\n\n",
                    $invoice_data{'balance_adjustments'}
index fee81f7..697a682 100644 (file)
@@ -2,9 +2,9 @@ package FS::cdr::amcom;
 
 use strict;
 use base qw( FS::cdr );
-use vars qw( %info );
+use vars qw( %info %cdrtypes);
 use DateTime;
-use FS::Record qw( qsearchs );
+use FS::Record qw( qsearch );
 use FS::cdr_type;
 
 my ($tmp_mday, $tmp_mon, $tmp_year);
@@ -16,6 +16,12 @@ my ($tmp_mday, $tmp_mon, $tmp_year);
   'type'          => 'csv',
   'sep_char'      => ',',
   'disabled'      => 0,
+  'header_buffer' => sub {
+
+       %cdrtypes = ( map { $_->cdrtypename => $_->cdrtypenum }
+                             qsearch('cdr_type', {})
+            );
+    },
 
   #listref of what to do with each field from the CDR, in order
   'import_fields' => [
@@ -37,9 +43,7 @@ my ($tmp_mday, $tmp_mon, $tmp_year);
     sub {         # 5. Call Category (LOCAL, NATIONAL, FREECALL, MOBILE)
       my ($cdr, $data) = @_;
       $data ||= 'none';
-
-      my $cdr_type = qsearchs('cdr_type', { 'cdrtypename' => $data } );
-      $cdr->set('cdrtypenum', $cdr_type->cdrtypenum) if $cdr_type;
+      $cdr->cdrtypenum($cdrtypes{$data} || '');
       $cdr->set('dcontext', $data);  
     },
     sub {         # 6. Start Date (DDMMYYYY
index 974af67..376ef02 100644 (file)
@@ -1205,9 +1205,10 @@ sub smart_search_param {
   my @or = 
       map { my $table = $_;
             my $search_sql = "FS::$table"->search_sql($string);
+            my $addl_from = "FS::$table"->search_sql_addl_from();
 
             "SELECT $table.svcnum AS svcnum, '$table' AS svcdb ".
-            "FROM $table WHERE $search_sql";
+            "FROM $table $addl_from WHERE $search_sql";
           }
       FS::part_svc->svc_tables;
 
index bd14247..ff34717 100644 (file)
@@ -18,6 +18,8 @@ my @contexts = ( qw(
   queue
   upgrade
   upgrade_taxable_billpkgnum
+  freeside-paymentech-upload
+  freeside-paymentech-download
 ) );
 
 =head1 NAME
index dbb9f40..baf145d 100644 (file)
@@ -22,6 +22,23 @@ If you did not request this password reset, you may safely ignore and delete thi
 END
                       ],
     },
+    { msgname   => 'Refund receipt',
+      msgclass  => 'email',
+      mime_type => 'text/html',
+      _conf        => 'refund_receipt_msgnum',
+      _insert_args => [ subject => '{ $company_name } refund receipt',
+                        body    => <<'END',
+Dear {$first} {$last},<BR>
+<BR>
+The following refund has been applied to your account.<BR>
+<BR>
+Refund ID: {$refundnum}<BR>
+Date:      {$date}<BR>
+Amount:    {$refund}<BR>
+
+END
+                      ],
+    },
   ];
 }
 
index dcca343..4c86753 100644 (file)
@@ -4,6 +4,7 @@ use strict;
 use vars qw( %info );
 use Time::Local qw( timelocal );
 use List::Util  qw( min );
+use FS::Record qw( qsearchs );
 use FS::cust_pkg;
 use FS::cust_bill_pkg_discount;
 
index 355c383..35415a2 100644 (file)
@@ -1349,6 +1349,9 @@ sub search_sql {
   #my( $class, $string ) = @_;
   '1 = 0'; #false
 }
+sub search_sql_addl_from {
+  '';
+}
 
 =item search HASHREF
 
index f705c68..408bd79 100644 (file)
@@ -218,6 +218,20 @@ sub label {
   $self->get('circuit_id');
 }
 
+sub search_sql {
+  my ($class, $string) = @_;
+  my @where = ();
+  push @where, 'LOWER(svc_circuit.circuit_id) = \''.lc($string).'\'';
+  push @where, 'LOWER(circuit_provider.provider) = \''.lc($string).'\'';
+  push @where, 'LOWER(circuit_type.typename) = \''.lc($string).'\'';
+  '(' . join(' OR ', @where) . ')';
+}
+
+sub search_sql_addl_from {
+  'LEFT JOIN circuit_provider USING ( providernum ) '.
+  'LEFT JOIN circuit_type USING ( typenum )';
+}
+
 =back
 
 =head1 SEE ALSO
index 16ac3c2..1b2f951 100755 (executable)
@@ -11,11 +11,20 @@ use FS::Record qw(qsearch qsearchs);
 use FS::pay_batch;
 use FS::cust_pay_batch;
 use FS::Conf;
+use FS::Log;
 
 use vars qw( $opt_t $opt_v $opt_a );
 getopts('vta:');
 
 #$Net::SFTP::Foreign::debug = -1;
+
+sub log_and_die {
+  my $message = shift;
+  my $log = FS::Log->new('freeside-paymenttech-download');
+  $log->error($message);
+  die $message; 
+}
+
 sub usage { "
   Usage:
       freeside-paymentech-download [ -v ] [ -t ] [ -a archivedir ] user\n
@@ -25,13 +34,13 @@ my $user = shift or die &usage;
 adminsuidsetup $user;
 
 if ( $opt_a ) {
-  die "no such directory: $opt_a\n"
+  log_and_die("no such directory: $opt_a\n")
     unless -d $opt_a;
-  die "archive directory $opt_a is not writable by the freeside user\n"
+  log_and_die("archive directory $opt_a is not writable by the freeside user\n")
     unless -w $opt_a;
 }
 
-my $unzip_check = `which unzip` or die "can't find unzip executable\n";
+my $unzip_check = `which unzip` or log_and_die("can't find unzip executable\n");
 
 #my $tmpdir = File::Temp->newdir();
 my $tmpdir = tempdir( CLEANUP => 1 ); #DIR=>somewhere?
@@ -39,22 +48,31 @@ my $tmpdir = tempdir( CLEANUP => 1 ); #DIR=>somewhere?
 my $conf = new FS::Conf;
 my @batchconf = $conf->config('batchconfig-paymentech');
 # BIN, terminalID, merchantID, username, password
-my $username = $batchconf[3] or die "no Paymentech batch username configured\n";
-my $password = $batchconf[4] or die "no Paymentech batch password configured\n";
+my $username = $batchconf[3] or log_and_die("no Paymentech batch username configured\n");
+my $password = $batchconf[4] or log_and_die("no Paymentech batch password configured\n");
 
 my $host = ($opt_t ? 'orbitalbatchvar.paymentech.net'
                    : 'orbitalbatch.paymentech.net');
 print STDERR "Connecting to $username\@$host...\n" if $opt_v;
 
-my $sftp = Net::SFTP::Foreign->new( host => $host,
-                                    user => $username,
-                                    password => $password,
-                                    timeout => 30,
-                                    );
-die "failed to connect to '$username\@$host'\n(".$sftp->error.")\n" if $sftp->error;
+my $sftp;
+my $ssh_retry      = 25;   # number of times to try connection, needs to be >= 1
+my $ssh_retry_wait = 60*5; # seconds to wait between tries
+while ($ssh_retry > 0) {
+  $sftp = Net::SFTP::Foreign->new( host => $host,
+                                   user => $username,
+                                   password => $password,
+                                   timeout => 30,
+                                 );
+  last unless $sftp->error;
+  $ssh_retry -= 1;
+  sleep($ssh_retry_wait) if $ssh_retry > 0;
+}
+
+log_and_die("failed to connect to '$username\@$host'\n(".$sftp->error.")\n") if $sftp->error;
 
 my @files = map { $_->{filename} } @{ $sftp->ls('.', wanted => qr/_resp\.zip$/) };
-die "no response files found\n" if !@files;
+log_and_die("no response files found\n") if !@files;
 
 BATCH: foreach my $filename (@files) {
 
index 609019e..a6e6a5d 100755 (executable)
@@ -11,12 +11,20 @@ use FS::Record qw(qsearch qsearchs);
 use FS::pay_batch;
 use FS::cust_pay_batch;
 use FS::Conf;
+use FS::Log;
 
 use vars qw( $opt_a $opt_t $opt_v $opt_p );
 getopts('avtp:');
 
 #$Net::SFTP::Foreign::debug = -1;
 
+sub log_and_die {
+  my $message = shift;
+  my $log = FS::Log->new('freeside-paymenttech-upload');
+  $log->error($message);
+  die $message; 
+}
+
 sub usage { "
   Usage:
     freeside-paymentech-upload [ -v ] [ -t ] user batchnum
@@ -26,7 +34,7 @@ sub usage { "
 my $user = shift or die &usage;
 adminsuidsetup $user;
 
-my $zip_check = `which zip` or die "can't find zip executable\n";
+my $zip_check = `which zip` or log_and_die("can't find zip executable\n");
 
 my @batches; 
 
@@ -34,21 +42,21 @@ if($opt_a) {
   my %criteria = (status => 'O');
   $criteria{'payby'} = uc($opt_p) if $opt_p;
   @batches = qsearch('pay_batch', \%criteria);
-  die "No open batches found".($opt_p ? " of type '$opt_p'" : '').".\n" 
+  log_and_die("No open batches found".($opt_p ? " of type '$opt_p'" : '').".\n")
     if !@batches;
 }
 else {
   my $batchnum = shift;
-  die &usage if !$batchnum;
+  log_and_die("batchnum not passed\n".&usage) if !$batchnum;
   @batches = qsearchs('pay_batch', { batchnum => $batchnum } );
-  die "Can't find payment batch '$batchnum'\n" if !@batches;
+  log_and_die("Can't find payment batch '$batchnum'\n") if !@batches;
 }
 
 my $conf = new FS::Conf;
 my @batchconf = $conf->config('batchconfig-paymentech');
 # BIN, terminalID, merchantID, username, password
-my $username = $batchconf[3] or die "no Paymentech batch username configured\n";
-my $password = $batchconf[4] or die "no Paymentech batch password configured\n";
+my $username = $batchconf[3] or log_and_die("no Paymentech batch username configured\n");
+my $password = $batchconf[4] or log_and_die("no Paymentech batch password configured\n");
 
 #my $tmpdir = File::Temp->newdir();
 my $tmpdir = tempdir( CLEANUP => 1 ); #DIR=>somewhere?
@@ -61,7 +69,7 @@ foreach my $pay_batch (@batches) {
   print STDERR "Exporting batch $batchnum to $filename...\n" if $opt_v;
   my $text = $pay_batch->export_batch(format => 'paymentech');
   $text =~ s!<fileID>FILEID</fileID>!<fileID>$filename</fileID>! 
-    or die "couldn't find FILEID tag\n";
+    or log_and_die("couldn't find FILEID tag\n");
   open OUT, ">$tmpdir/$filename.xml";
   print OUT $text;
   close OUT;
@@ -69,7 +77,7 @@ foreach my $pay_batch (@batches) {
   system('zip', '-P', $password, '-q', '-j',
            "$tmpdir/$filename.zip", "$tmpdir/$filename.xml");
 
-  die "failed to create zip file\n" if (! -f "$tmpdir/$filename.zip" );
+  log_and_die("failed to create zip file\n") if (! -f "$tmpdir/$filename.zip" );
   push @filenames, $filename;
 }
 
@@ -77,17 +85,26 @@ my $host = ($opt_t ? 'orbitalbatchvar.paymentech.net'
                    : 'orbitalbatch.paymentech.net');
 print STDERR "Connecting to $username\@$host...\n" if $opt_v;
 
-my $sftp = Net::SFTP::Foreign->new( host => $host,
-                                    user => $username,
-                                    password => $password,
-                                    timeout => 30,
-                                    );
-die "failed to connect to '$username\@$host'\n(".$sftp->error.")\n" 
+my $sftp;
+my $ssh_retry      = 25;   # number of times to try connection, needs to be >= 1
+my $ssh_retry_wait = 60*5; # seconds to wait between tries
+while ($ssh_retry > 0) {
+  $sftp = Net::SFTP::Foreign->new( host => $host,
+                                   user => $username,
+                                   password => $password,
+                                   timeout => 30,
+                                 );
+  last unless $sftp->error;
+  $ssh_retry -= 1;
+  sleep($ssh_retry_wait) if $ssh_retry > 0;
+}
+
+log_and_die("failed to connect to '$username\@$host'\n(".$sftp->error.")\n")
     if $sftp->error;
 
 foreach my $filename (@filenames) {
   $sftp->put("$tmpdir/$filename.zip", "$filename.zip")
-    or die "failed to upload file (".$sftp->error.")\n";
+    or log_and_die("failed to upload file (".$sftp->error.")\n");
 }
 
 print STDERR "Finished!\n" if $opt_v;
index 1a01daa..b824fb2 100644 (file)
@@ -129,7 +129,7 @@ function confirm_standardize(arg) {
         function() {
           overlib( OLresponseAJAX, CAPTION, 'Address standardization', STICKY, 
             AUTOSTATUSCAP, CLOSETEXT, '', MIDX, 0, MIDY, 0, DRAGGABLE, WIDTH, 
-            576, HEIGHT, 268, BGCOLOR, '#333399', CGCOLOR, '#333399', 
+            650, HEIGHT, 368, BGCOLOR, '#333399', CGCOLOR, '#333399', 
             TEXTSIZE, 3 );
         }, 0);
 
@@ -141,10 +141,15 @@ function replace_address() {
   var newaddr = returned['new'];
 
   var cf = document.<% $formname %>;
+  var crf = document.forms['confirm_replace_form'];
 %  foreach my $pre (@prefixes) {
   var clean = newaddr['<% $pre %>addr_clean'] == 'Y';
+  var replace = true; // auto_standardize_address won't load the form, so just do it
+  if ( crf && crf['<% $pre %>replace'] ) {
+    replace = crf['<% $pre %>replace'].value == 'Y';
+  }
   var error = newaddr['<% $pre %>error'];
-  if ( clean ) {
+  if ( clean && replace ) {
 %   foreach my $field (qw(address1 address2 state zip addr_clean ),($conf->exists('cust_main-no_city_in_address') ? () : 'city')) {
     cf.elements['<% $pre %><% $field %>'].value = newaddr['<% $pre %><% $field %>'];
 %   } #foreach $field
@@ -154,7 +159,12 @@ function replace_address() {
       cf.elements['<% $pre %>longitude'].value = newaddr['<% $pre %>longitude'];
     }
 %   if ( $withcensus ) {
-    if ( clean && newaddr['<% $pre %>censustract'] ) {
+    var census_replace = true;
+    if ( crf && crf['census_replace'] ) {
+      census_replace = crf['census_replace'].value == 'Y';
+    }
+
+    if ( clean && census_replace && newaddr['<% $pre %>censustract'] ) {
       cf.elements['<% $pre %>censustract'].value = newaddr['<% $pre %>censustract'];
     }
 %   } #if $withcensus
index 03de3ba..2d1a9e6 100644 (file)
@@ -38,6 +38,10 @@ Usage:
       <% FS::UI::Web::svc_label_link($m, $part_svc, $cust_svc) %>
 %   }
     </B>
+%   if ($part_svc->svcdb eq 'svc_circuit') {
+      <BR>Provider:&nbsp;<% $svc_x->circuit_provider->provider %>
+      <BR>Type:&nbsp;<% $svc_x->circuit_type->typename %>
+%   }
 %   if ( $opt{after_svc_callback} ) {
       <% &{ $opt{after_svc_callback} }( $cust_svc ) %>
 %   }
index 2eae011..0a05c70 100644 (file)
@@ -1,8 +1,15 @@
 <STYLE type="text/css">
-th { line-height: 150% }
+th { line-height: 150%;
+  width: 45%;
+}
+.td_radio {
+  width: 5%;
+  vertical-align: middle;
+  text-align: center;
+}
 </STYLE>
 <CENTER><BR><B>
-% if ( $new{bill_error} or $new{ship_error} ) {
+% if ( $is_error ) {
 Address standardization error
 % }
 % else {
@@ -10,24 +17,26 @@ Confirm address standardization
 % }
 
 </B><BR><BR>
+<FORM ID="confirm_replace_form">
 <TABLE WIDTH="100%">
-% my @prefixes = ('');
-% if ( $old{same} ) {
-%   @prefixes = ('bill_');
-% } elsif ( $old{billship} ) {
-%   @prefixes = ('bill_', 'ship_');
-% }
 % for my $pre (@prefixes) {
 %   my $name = $pre eq 'bill_' ? 'billing' : 'service';
+%   my $rows = 5;
 %   if ( $new{$pre.'error'} ) {
   <TR>
-    <TH>Entered <%$name%> address</TH>
+    <TD ROWSPAN=<% $rows %> CLASS="td_radio">
+        <INPUT TYPE="radio" NAME="<% $pre %>replace" VALUE="" CHECKED="Y">
+    </TD>
+    <TH>Entered <%$name%> address
+    </TH>
+    <TH></TH>
+    <TD CLASS="td_radio"></TD>
   </TR>
-%     if ( $old{$pre.'company'} ) {
   <TR>
+%     if ( $old{$pre.'company'} ) {
     <TD><% $old{$pre.'company'} %></TD>
-  </TR>
 %     }
+  </TR>
   <TR>
     <TD><% $old{$pre.'address1'} %></TD>
     <TD ROWSPAN=3><FONT COLOR="#ff0000"><B><% $new{$pre.'error'} %></B></FONT></TD>
@@ -39,9 +48,16 @@ Confirm address standardization
     <TD><% $old{$pre.'city'} %>, <% $old{$pre.'state'} %>  <% $old{$pre.'zip'} %></TD>
   </TR>
 %   } else { # not an error
+%     $rows++ if !$new{$pre.'addr_clean'};
   <TR>
+    <TD ROWSPAN=<% $rows %> CLASS="td_radio">
+      <INPUT TYPE="radio" NAME="<% $pre %>replace" VALUE="">
+    </TD>
     <TH>Entered <%$name%> address</TH>
     <TH>Standardized <%$name%> address</TH>
+    <TD ROWSPAN=<% $rows %> CLASS="td_radio">
+      <INPUT TYPE="radio" NAME="<% $pre %>replace" VALUE="Y" CHECKED="Y">
+    </TD>
   </TR>
 %   if ( !$new{$pre.'addr_clean'} ) {
   <TR>
@@ -75,11 +91,16 @@ Confirm address standardization
 %# only do this part if address standardization provided a censustract
 % my $pre = $old{same} ? 'bill_' : 'ship_';
 % my $censustract = $new{$pre.'censustract'};
-% my $census_error = $new{$pre.'census_error'};
 % if ( $censustract ) {
   <TR>
+    <TD ROWSPAN=2 CLASS="td_radio">
+      <INPUT TYPE="radio" NAME="census_replace" VALUE="" <% $census_error ? 'CHECKED="Y"' : '' %>>
+    </TD>
     <TH>Entered census tract</TH>
     <TH>Calculated census tract</TH>
+    <TD ROWSPAN=2 CLASS="td_radio">
+      <INPUT TYPE="radio" NAME="census_replace" VALUE="Y" <% $census_error ? '' : 'CHECKED="Y"' %>>
+    </TD>
   </TR>
   <TR>
     <TD><% $old{$pre.'censustract'} %></TD>
@@ -93,35 +114,21 @@ Confirm address standardization
   </TR>
 % } #if censustract
 
-% if ( grep {$new{$_.'error'}} @prefixes ) {
   <TR>
+    <TD> </TD>
     <TD ALIGN="center">
-    <BUTTON TYPE="button" STYLE="width:205px" onclick="confirm_manual_address();">
-      <IMG SRC="<%$p%>images/error.png" ALT=""> Use entered <%$addresses%>
+    <BUTTON TYPE="button" STYLE="width:205px" onclick="replace_address();">
+      <IMG SRC="<%$p%>images/<% $is_error ? 'error.png' : 'tick.png' %>"
+           ALT=""> Use selected <%$addresses%>
     </BUTTON></TD>
     <TD ALIGN="center">
     <BUTTON TYPE="button" STYLE="width:205px" onclick="submit_abort();">
       <IMG SRC="<%$p%>images/cross.png" ALT=""> Cancel submission
     </BUTTON></TD>
+    <TD> </TD>
   </TR>
-% } else {
-  <TR>
-    <TD ALIGN="center">
-    <BUTTON TYPE="button" STYLE="width:205px" onclick="confirm_manual_address();">
-      <IMG SRC="<%$p%>images/error.png" ALT=""> Use entered <%$addresses%>
-    </BUTTON></TD>
-    <TD ALIGN="center">
-    <BUTTON TYPE="button" STYLE="width:205px" onclick="replace_address();">
-      <IMG SRC="<%$p%>images/tick.png" ALT=""> Use standardized <%$addresses%>
-    </BUTTON></TD>
-  </TR>
-  <TR ALIGN="center"><TD COLSPAN=2>
-    <BUTTON TYPE="button" STYLE="width:205px" onclick="submit_abort();">
-      <IMG SRC="<%$p%>images/cross.png" ALT=""> Cancel submission
-    </BUTTON>
-  </TD></TR>
 </TABLE>
-% } # !error
+</FORM>
 <%init>
 
 # slightly weird interface...
@@ -132,4 +139,14 @@ my %new = %{ $q->{new} };
 
 my $addresses = $old{billship} ? 'addresses' : 'address';
 
+my @prefixes = ('');
+if ( $old{same} ) {
+  @prefixes = ('bill_');
+} elsif ( $old{billship} ) {
+  @prefixes = ('bill_', 'ship_');
+}
+
+my $census_error = $new{'census_error'};
+my $is_error = $census_error || grep { $new{$_.'error'} } @prefixes;
+
 </%init>
index 9b02457..07fcf7c 100755 (executable)
@@ -207,11 +207,11 @@ foreach my $row (@rows) {
   $x++;
   $ws->write_string($y, $x, " \N{U+2212} ", $f->{bigmath}); # MINUS SIGN
   $x++;
-  $ws->write($y, $x, $row->{credit} || 0, $f->{currency});
+  $ws->write($y, $x, $row->{tax_credited} || 0, $f->{currency});
   $x++;
   $ws->write_string($y, $x, " = ", $f->{bigmath});
   $x++;
-  $ws->write($y, $x, $row->{tax} - $row->{credit}, $f->{currency});
+  $ws->write($y, $x, $row->{tax} - $row->{tax_credited}, $f->{currency});
   $x++;
   $ws->write($y, $x, $row->{tax_paid} || 0, $f->{currency});