[freeside-commits] branch FREESIDE_3_BRANCH updated. ab42a6d76c5a5905d223d214e409f0527b2c5b9e

Christopher Burger burgerc at freeside.biz
Tue Nov 6 18:05:22 PST 2018


The branch, FREESIDE_3_BRANCH has been updated
       via  ab42a6d76c5a5905d223d214e409f0527b2c5b9e (commit)
       via  f621fddd392f6bf809434ba5653acc645045e6bf (commit)
       via  959a59186f30a33d167b12e67d3c9cc4ce58a0f5 (commit)
      from  ad94da6a8b46ba0cb915a69307810c8a5bcf6749 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit ab42a6d76c5a5905d223d214e409f0527b2c5b9e
Author: Christopher Burger <burgerc at freeside.biz>
Date:   Tue Nov 6 21:04:22 2018 -0500

    RT# 76093 - added ability for processing fee to be used with batch processing. V3 change

diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index 590783b27..88dd0e54b 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -2847,6 +2847,27 @@ sub batch_card {
   if ($options{'processing-fee'} > 0) {
     my $pf_cust_pkg;
     my $processing_fee_text = 'Payment Processing Fee';
+
+    unless ( $invnum ) { # probably from a payment screen
+      # do we have any open invoices? pick earliest
+      # uses the fact that cust_main->cust_bill sorts by date ascending
+      my @open = $self->open_cust_bill;
+      $invnum = $open[0]->invnum if scalar(@open);
+    }
+
+    unless ( $invnum ) {  # still nothing? pick last closed invoice
+      # again uses fact that cust_main->cust_bill sorts by date ascending
+      my @closed = $self->cust_bill;
+      $invnum = $closed[$#closed]->invnum if scalar(@closed);
+    }
+
+    unless ( $invnum ) {
+      # XXX: unlikely case - pre-paying before any invoices generated
+      # what it should do is create a new invoice and pick it
+      warn '\PROCESS FEE AND NO INVOICES PICKED TO APPLY IT!';
+      return '';
+    }
+
     my $pf_change_error = $self->charge({
             'amount'  => $options{'processing-fee'},
             'pkg'   => $processing_fee_text,

commit f621fddd392f6bf809434ba5653acc645045e6bf
Author: Christopher Burger <burgerc at freeside.biz>
Date:   Tue Nov 6 13:57:35 2018 -0500

    RT# 76093 - added ability for processing fee to be used with batch processing.

diff --git a/FS/FS/cust_main/Billing_Batch.pm b/FS/FS/cust_main/Billing_Batch.pm
index 1ea069de4..0e713e937 100644
--- a/FS/FS/cust_main/Billing_Batch.pm
+++ b/FS/FS/cust_main/Billing_Batch.pm
@@ -170,6 +170,27 @@ sub batch_card {
   if ($options{'processing-fee'} > 0) {
     my $pf_cust_pkg;
     my $processing_fee_text = 'Payment Processing Fee';
+
+    unless ( $invnum ) { # probably from a payment screen
+      # do we have any open invoices? pick earliest
+      # uses the fact that cust_main->cust_bill sorts by date ascending
+      my @open = $self->open_cust_bill;
+      $invnum = $open[0]->invnum if scalar(@open);
+    }
+
+    unless ( $invnum ) {  # still nothing? pick last closed invoice
+      # again uses fact that cust_main->cust_bill sorts by date ascending
+      my @closed = $self->cust_bill;
+      $invnum = $closed[$#closed]->invnum if scalar(@closed);
+    }
+
+    unless ( $invnum ) {
+      # XXX: unlikely case - pre-paying before any invoices generated
+      # what it should do is create a new invoice and pick it
+      warn '\PROCESS FEE AND NO INVOICES PICKED TO APPLY IT!';
+      return '';
+    }
+
     my $pf_change_error = $self->charge({
             'amount'  => $options{'processing-fee'},
             'pkg'   => $processing_fee_text,

commit 959a59186f30a33d167b12e67d3c9cc4ce58a0f5
Author: Christopher Burger <burgerc at freeside.biz>
Date:   Mon Nov 5 17:44:50 2018 -0500

    RT# 76093 - Added ability to charge a processing fee when taking a payment on the back end
    
    Conflicts:
            FS/FS/Conf.pm
            FS/FS/cust_main/Billing_Batch.pm
            httemplate/elements/tr-amount_fee.html
            httemplate/elements/tr-select-payment_options.html
            httemplate/misc/process/payment.cgi

diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index b36f5f585..157fbb6be 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -2837,6 +2837,14 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'processing-fee',
+    'section'     => 'billing',
+    'description' => 'Fee for back end payment processing.',
+    'type'        => 'text',
+    'per_agent'   => 1,
+  },
+
+  {
     'key'         => 'payby-default',
     'section'     => 'UI',
     'description' => 'Default payment type.  HIDE disables display of billing information and sets customers to BILL.',
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index 1de1db5b1..590783b27 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -2844,6 +2844,41 @@ sub batch_card {
     die $error;
   }
 
+  if ($options{'processing-fee'} > 0) {
+    my $pf_cust_pkg;
+    my $processing_fee_text = 'Payment Processing Fee';
+    my $pf_change_error = $self->charge({
+            'amount'  => $options{'processing-fee'},
+            'pkg'   => $processing_fee_text,
+            'setuptax'  => 'Y',
+            'cust_pkg_ref' => \$pf_cust_pkg,
+    });
+
+    if($pf_change_error) {
+      warn 'Unable to add payment processing fee';
+      return '';
+    }
+
+    $pf_cust_pkg->setup(time);
+    my $pf_error = $pf_cust_pkg->replace;
+    if($pf_error) {
+      warn 'Unable to set setup time on cust_pkg for processing fee';
+      # but keep going...
+    }
+
+    my $cust_bill = qsearchs('cust_bill', { 'invnum' => $invnum });
+    unless ( $cust_bill ) {
+      warn "race condition + invoice deletion just happened";
+      return '';
+    }
+
+    my $grand_pf_error =
+      $cust_bill->add_cc_surcharge($pf_cust_pkg->pkgnum,$options{'processing-fee'});
+
+    warn "cannot add Processing fee to invoice #$invnum: $grand_pf_error"
+      if $grand_pf_error;
+  }
+
   my $unapplied =   $self->total_unapplied_credits
                   + $self->total_unapplied_payments
                   + $self->in_transit_payments;
diff --git a/FS/FS/cust_main/Billing_Batch.pm b/FS/FS/cust_main/Billing_Batch.pm
new file mode 100644
index 000000000..1ea069de4
--- /dev/null
+++ b/FS/FS/cust_main/Billing_Batch.pm
@@ -0,0 +1,283 @@
+package FS::cust_main::Billing_Batch;
+
+use strict;
+use vars qw( $conf );
+use FS::Record qw( qsearch qsearchs dbh );
+use FS::pay_batch;
+use FS::cust_pay_batch;
+use FS::cust_bill_pay_batch;
+
+install_callback FS::UID sub { 
+  $conf = new FS::Conf;
+  #yes, need it for stuff below (prolly should be cached)
+};
+
+=item batch_card OPTION => VALUE...
+
+Adds a payment for this invoice to the pending credit card batch (see
+L<FS::cust_pay_batch>), or, if the B<realtime> option is set to a true value,
+runs the payment using a realtime gateway.
+
+Options may include:
+
+B<amount>: the amount to be paid; defaults to the customer's balance minus
+any payments in transit.
+
+B<realtime>: runs this as a realtime payment instead of adding it to a 
+batch.  Deprecated.
+
+B<invnum>: sets cust_pay_batch.invnum.
+
+B<address1>, B<address2>, B<city>, B<state>, B<zip>, B<country>: sets 
+the billing address for the payment; defaults to the customer's billing
+location.
+
+B<payby>, B<payinfo>, B<paydate>, B<payname>: sets the payment method, 
+payment account, expiration date, and name; defaults to those fields 
+in cust_main.
+
+=cut
+
+sub batch_card {
+  my ($self, %options) = @_;
+
+  my $amount;
+  if (exists($options{amount})) {
+    $amount = $options{amount};
+  }else{
+    $amount = sprintf("%.2f", $self->balance - $self->in_transit_payments);
+  }
+  if ($amount <= 0) {
+    warn(sprintf("Customer balance %.2f - in transit amount %.2f is <= 0.\n",
+        $self->balance,
+        $self->in_transit_payments
+    ));
+    return;
+  }
+  
+  #my $invnum = delete $options{invnum};
+  my $invnum = $options{invnum};
+
+  #pay fields should all come from either cust_payby or options, not both
+  #  in theory, could just pass payby, and use it to select cust_payby,
+  #  but nothing currently needs that, so not implementing it now
+  die "Incomplete payment details" 
+    if  ($options{payby} || $options{payinfo} || $options{paydate} || $options{payname})
+    && !($options{payby} && $options{payinfo} && $options{paydate} && $options{payname});
+
+  #false laziness with Billing_Realtime
+  my @cust_payby = $self->cust_payby('CARD','CHEK');
+
+  # batch can't try out every one like realtime, just use first one
+  my $cust_payby = $cust_payby[0];
+
+  die "No customer payment info found"
+    unless $options{payinfo} || $cust_payby;
+                                                   
+  my $payby = $options{payby} || $cust_payby->payby;
+
+  if ($options{'realtime'}) {
+    return $self->realtime_bop( FS::payby->payby2bop($payby),
+                                $amount,
+                                %options,
+                              );
+  }
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  #this needs to handle mysql as well as Pg, like svc_acct.pm
+  #(make it into a common function if folks need to do batching with mysql)
+  $dbh->do("LOCK TABLE pay_batch IN SHARE ROW EXCLUSIVE MODE")
+    or die "Cannot lock pay_batch: " . $dbh->errstr;
+
+  my %pay_batch = (
+    'status' => 'O',
+    'payby'  => FS::payby->payby2payment($payby),
+  );
+  $pay_batch{agentnum} = $self->agentnum if $conf->exists('batch-spoolagent');
+
+  my $pay_batch = qsearchs( 'pay_batch', \%pay_batch );
+
+  unless ( $pay_batch ) {
+    $pay_batch = new FS::pay_batch \%pay_batch;
+    my $error = $pay_batch->insert;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      die "error creating new batch: $error\n";
+    }
+  }
+
+  my $old_cust_pay_batch = qsearchs('cust_pay_batch', {
+      'batchnum' => $pay_batch->batchnum,
+      'custnum'  => $self->custnum,
+  } );
+
+  foreach (qw( address1 address2 city state zip country latitude longitude
+               payby payinfo paydate payname paycode paytype ))
+  {
+    $options{$_} = '' unless exists($options{$_});
+  }
+
+  my $loc = $self->bill_location;
+
+  my $cust_pay_batch = new FS::cust_pay_batch ( {
+    'batchnum' => $pay_batch->batchnum,
+    'invnum'   => $invnum || 0,                    # is there a better value?
+                                                   # this field should be
+                                                   # removed...
+                                                   # cust_bill_pay_batch now
+    'custnum'  => $self->custnum,
+    'last'     => $self->getfield('last'),
+    'first'    => $self->getfield('first'),
+    'address1' => $options{address1} || $loc->address1,
+    'address2' => $options{address2} || $loc->address2,
+    'city'     => $options{city}     || $loc->city,
+    'state'    => $options{state}    || $loc->state,
+    'zip'      => $options{zip}      || $loc->zip,
+    'country'  => $options{country}  || $loc->country,
+    'payby'    => $options{payby}    || $cust_payby->payby,
+    'payinfo'  => $options{payinfo}  || $cust_payby->payinfo,
+    'paymask'  => ( $options{payinfo}
+                      ? FS::payinfo_Mixin->mask_payinfo( $options{payby},
+                                                         $options{payinfo} )
+                      : $cust_payby->paymask
+                  ),
+    'exp'      => $options{paydate}  || $cust_payby->paydate,
+    'payname'  => $options{payname}  || $cust_payby->payname,
+    'paytype'  => $options{paytype}  || $cust_payby->paytype,
+    'amount'   => $amount,                         # consolidating
+    'paycode'  => $options{paycode}  || '',
+  } );
+  
+  $cust_pay_batch->paybatchnum($old_cust_pay_batch->paybatchnum)
+    if $old_cust_pay_batch;
+
+  my $error;
+  if ($old_cust_pay_batch) {
+    $error = $cust_pay_batch->replace($old_cust_pay_batch)
+  } else {
+    $error = $cust_pay_batch->insert;
+  }
+
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    #die $error;
+    return $error; # e.g. "Illegal zip" ala RT#75998
+  }
+
+  if ($options{'processing-fee'} > 0) {
+    my $pf_cust_pkg;
+    my $processing_fee_text = 'Payment Processing Fee';
+    my $pf_change_error = $self->charge({
+            'amount'  => $options{'processing-fee'},
+            'pkg'   => $processing_fee_text,
+            'setuptax'  => 'Y',
+            'cust_pkg_ref' => \$pf_cust_pkg,
+    });
+
+    if($pf_change_error) {
+      warn 'Unable to add payment processing fee';
+      return '';
+    }
+
+    $pf_cust_pkg->setup(time);
+    my $pf_error = $pf_cust_pkg->replace;
+    if($pf_error) {
+      warn 'Unable to set setup time on cust_pkg for processing fee';
+      # but keep going...
+    }
+
+    my $cust_bill = qsearchs('cust_bill', { 'invnum' => $invnum });
+    unless ( $cust_bill ) {
+      warn "race condition + invoice deletion just happened";
+      return '';
+    }
+
+    my $grand_pf_error =
+      $cust_bill->add_cc_surcharge($pf_cust_pkg->pkgnum,$options{'processing-fee'});
+
+    warn "cannot add Processing fee to invoice #$invnum: $grand_pf_error"
+      if $grand_pf_error;
+  }
+
+  my $unapplied =   $self->total_unapplied_credits
+                  + $self->total_unapplied_payments
+                  + $self->in_transit_payments;
+  foreach my $cust_bill ($self->open_cust_bill) {
+    #$dbh->commit or die $dbh->errstr if $oldAutoCommit;
+    my $cust_bill_pay_batch = new FS::cust_bill_pay_batch {
+      'invnum' => $cust_bill->invnum,
+      'paybatchnum' => $cust_pay_batch->paybatchnum,
+      'amount' => $cust_bill->owed,
+      '_date' => time,
+    };
+    if ($unapplied >= $cust_bill_pay_batch->amount){
+      $unapplied -= $cust_bill_pay_batch->amount;
+      next;
+    }else{
+      $cust_bill_pay_batch->amount(sprintf ( "%.2f", 
+                                   $cust_bill_pay_batch->amount - $unapplied ));      $unapplied = 0;
+    }
+    $error = $cust_bill_pay_batch->insert;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      die $error;
+    }
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
+}
+
+=item cust_pay_batch [ OPTION => VALUE... | EXTRA_QSEARCH_PARAMS_HASHREF ]
+
+Returns all batched payments (see L<FS::cust_pay_batch>) for this customer.
+
+Optionally, a list or hashref of additional arguments to the qsearch call can
+be passed.
+
+=cut
+
+sub cust_pay_batch {
+  my $self = shift;
+  my $opt = ref($_[0]) ? shift : { @_ };
+
+  #return $self->num_cust_statement unless wantarray || keys %$opt;
+
+  $opt->{'table'} = 'cust_pay_batch';
+  $opt->{'hashref'} ||= {}; #i guess it would autovivify anyway...
+  $opt->{'hashref'}{'custnum'} = $self->custnum;
+  $opt->{'order_by'} ||= 'ORDER BY paybatchnum ASC';
+
+  map { $_ } #behavior of sort undefined in scalar context
+    sort { $a->paybatchnum <=> $b->paybatchnum }
+      qsearch($opt);
+}
+
+=item in_transit_payments
+
+Returns the total of requests for payments for this customer pending in 
+batches in transit to the bank.  See L<FS::pay_batch> and L<FS::cust_pay_batch>
+
+=cut
+
+sub in_transit_payments {
+  my $self = shift;
+  my $in_transit_payments = 0;
+  foreach my $pay_batch ( qsearch('pay_batch', {
+    'status' => 'I',
+  } ) ) {
+    foreach my $cust_pay_batch ( qsearch('cust_pay_batch', {
+      'batchnum' => $pay_batch->batchnum,
+      'custnum' => $self->custnum,
+      'status'  => '',
+    } ) ) {
+      $in_transit_payments += $cust_pay_batch->amount;
+    }
+  }
+  sprintf( "%.2f", $in_transit_payments );
+}
+
+1;
diff --git a/FS/FS/cust_main/Billing_Realtime.pm b/FS/FS/cust_main/Billing_Realtime.pm
index 611af5d08..ed5d094f5 100644
--- a/FS/FS/cust_main/Billing_Realtime.pm
+++ b/FS/FS/cust_main/Billing_Realtime.pm
@@ -374,8 +374,8 @@ sub realtime_bop {
   elsif($cc_surcharge_pct > 0 || $cc_surcharge_flat > 0) {
     # we're called not from event (i.e. from a
     # payment screen), so consider the given
-		# amount as post-surcharge
-    $cc_surcharge = $options{'amount'} - (($options{'amount'} - $cc_surcharge_flat) / ( 1 + $cc_surcharge_pct/100 )) if $options{'amount'} > 0;
+		# amount as post-surcharge-processing_fee
+    $cc_surcharge = $options{'amount'} - $options{'processing-fee'} - (($options{'amount'} - ($cc_surcharge_flat + $options{'processing-fee'})) / ( 1 + $cc_surcharge_pct/100 )) if $options{'amount'} > 0;
   }
   
   $cc_surcharge = sprintf("%.2f",$cc_surcharge) if $cc_surcharge > 0;
@@ -979,7 +979,7 @@ sub _realtime_bop_result {
       }
 
       # have a CC surcharge portion --> one-time charge
-      if ( $options{'cc_surcharge'} > 0 ) { 
+      if ( $options{'cc_surcharge'} > 0 || $options{'processing-fee'} > 0) {
 	    # XXX: this whole block needs to be in a transaction?
 
 	  my $invnum;
@@ -1000,44 +1000,83 @@ sub _realtime_bop_result {
 	  unless ( $invnum ) {
 	    # XXX: unlikely case - pre-paying before any invoices generated
 	    # what it should do is create a new invoice and pick it
-		warn 'CC SURCHARGE AND NO INVOICES PICKED TO APPLY IT!';
+		warn 'CC SURCHARGE OR PROCESS FEE AND NO INVOICES PICKED TO APPLY IT!';
 		return '';
 	  }
 
-	  my $cust_pkg;
-    my $cc_surcharge_text = 'Credit Card Surcharge';
-    $cc_surcharge_text = $conf->config('credit-card-surcharge-text', $self->agentnum) if $conf->exists('credit-card-surcharge-text', $self->agentnum);
-	  my $charge_error = $self->charge({
+    if ($options{'cc_surcharge'} > 0) {
+	    my $cust_pkg;
+      my $cc_surcharge_text = 'Credit Card Surcharge';
+      $cc_surcharge_text = $conf->config('credit-card-surcharge-text', $self->agentnum) if $conf->exists('credit-card-surcharge-text', $self->agentnum);
+	    my $charge_error = $self->charge({
 				    'amount' 	=> $options{'cc_surcharge'},
 				    'pkg' 	=> $cc_surcharge_text,
 				    'setuptax'  => 'Y',
 				    'cust_pkg_ref' => \$cust_pkg,
-				});
-	  if($charge_error) {
-		warn 'Unable to add CC surcharge cust_pkg';
-		return '';
-	  }
+			});
+
+	    if($charge_error) {
+		    warn 'Unable to add CC surcharge cust_pkg';
+		    return '';
+	    }
+
+      $cust_pkg->setup(time);
+      my $cp_error = $cust_pkg->replace;
+      if($cp_error) {
+        warn 'Unable to set setup time on cust_pkg for cc surcharge';
+        # but keep going...
+      }
 
-	  $cust_pkg->setup(time);
-	  my $cp_error = $cust_pkg->replace;
-	  if($cp_error) {
-	      warn 'Unable to set setup time on cust_pkg for cc surcharge';
-	    # but keep going...
-	  }
-				    
-	  my $cust_bill = qsearchs('cust_bill', { 'invnum' => $invnum });
-	  unless ( $cust_bill ) {
-	      warn "race condition + invoice deletion just happened";
-	      return '';
-	  }
+      my $cust_bill = qsearchs('cust_bill', { 'invnum' => $invnum });
+      unless ( $cust_bill ) {
+        warn "race condition + invoice deletion just happened";
+        return '';
+      }
 
-	  my $grand_error = 
-	    $cust_bill->add_cc_surcharge($cust_pkg->pkgnum,$options{'cc_surcharge'});
+      my $grand_error =
+        $cust_bill->add_cc_surcharge($cust_pkg->pkgnum,$options{'cc_surcharge'});
+
+      warn "cannot add CC surcharge to invoice #$invnum: $grand_error"
+        if $grand_error;
+    } # end if $options{'cc_surcharge'}
+
+    if ($options{'processing-fee'} > 0) {
+      my $pf_cust_pkg;
+      my $processing_fee_text = 'Payment Processing Fee';
+      my $pf_change_error = $self->charge({
+            'amount'  => $options{'processing-fee'},
+            'pkg'   => $processing_fee_text,
+            'setuptax'  => 'Y',
+            'cust_pkg_ref' => \$pf_cust_pkg,
+      });
+
+      if($pf_change_error) {
+        warn 'Unable to add payment processing fee';
+        return '';
+      }
+
+      $pf_cust_pkg->setup(time);
+      my $pf_error = $pf_cust_pkg->replace;
+      if($pf_error) {
+        warn 'Unable to set setup time on cust_pkg for processing fee';
+        # but keep going...
+      }
 
-	  warn "cannot add CC surcharge to invoice #$invnum: $grand_error"
-	    if $grand_error;
+      my $cust_bill = qsearchs('cust_bill', { 'invnum' => $invnum });
+      unless ( $cust_bill ) {
+        warn "race condition + invoice deletion just happened";
+        return '';
       }
 
+      my $grand_pf_error =
+        $cust_bill->add_cc_surcharge($pf_cust_pkg->pkgnum,$options{'processing-fee'});
+
+      warn "cannot add Processing fee to invoice #$invnum: $grand_pf_error"
+        if $grand_pf_error;
+    } #end if $options{'processing-fee'}
+
+      } #end if ( $options{'cc_surcharge'} > 0 || $options{'processing-fee'} > 0)
+
       return ''; #no error
 
     }
diff --git a/httemplate/elements/tr-amount_fee.html b/httemplate/elements/tr-amount_fee.html
index e3b8d7800..1cd59bbc3 100644
--- a/httemplate/elements/tr-amount_fee.html
+++ b/httemplate/elements/tr-amount_fee.html
@@ -8,7 +8,7 @@
                                 VALUE    = "<% $amount %>"
                                 SIZE     = 8
                                 STYLE    = "text-align:right;"
-%                               if ( $fee ) {
+%                               if ( $fee || $processing_fee) {
                                   onChange   = "amount_changed(this)"
                                   onKeyDown  = "amount_changed(this)"
                                   onKeyUp    = "amount_changed(this)"
@@ -32,7 +32,23 @@
     </TD>
   </TR>
 
-% if ( $fee ) {
+%        if ( $processing_fee ) {
+      <TR>
+        <TH ALIGN="right"><% mt('Processing fee') |h %></TH>
+        <TD>
+          <TABLE><TR>
+            <TD BGCOLOR="#ffffff">
+             <INPUT TYPE="checkbox" NAME="processing_fee" ID="processing_fee" VALUE="<% $processing_fee %>" onclick="<% $opt{prefix} %>process_fee_changed()">
+            </TD>
+            <TD>
+             Apply a processing fee of <% $processing_fee %> .</FONT>
+            </TD>
+          </TR></TABLE>
+        </TD>
+      </TR>
+%        }
+
+% if ($fee) {
 
     <SCRIPT TYPE="text/javascript">
 
@@ -55,6 +71,27 @@
 
 % }
 
+% if ($processing_fee) {
+
+    <SCRIPT TYPE="text/javascript">
+
+      function <% $opt{prefix} %>process_fee_changed(what) {
+
+        if (document.getElementById('processing_fee').checked == true) {
+          var amount = +document.getElementById('amount').value + +document.getElementById('processing_fee').value;
+          $('#amount').val(amount.toFixed(2));
+        }
+        else {
+          var amount = +document.getElementById('amount').value - +document.getElementById('processing_fee').value;
+          $('#amount').val(amount.toFixed(2));
+        }
+
+      }
+
+    </SCRIPT>
+
+% }
+
 <%init>
 
 my %opt = @_;
@@ -66,6 +103,7 @@ my $fee = '';
 my $fee_pkg = '';
 my $fee_display = '';
 my $fee_op = '';
+my $processing_fee = 0;
 
 if ( $opt{'process-pkgpart'}
      and ! $opt{'process-skip_first'} || $opt{'num_payments'}
@@ -97,6 +135,8 @@ if ( $amount > 0 ) {
   $amount += $opt{'surcharge_flatfee'}
     if $opt{'surcharge_flatfee'} > 0;
 
+  $processing_fee = $opt{'processing_fee'} if $opt{'processing_fee'} > 0;
+
   $amount = sprintf("%.2f", $amount);
 }
 
diff --git a/httemplate/elements/tr-select-payment_options.html b/httemplate/elements/tr-select-payment_options.html
deleted file mode 100644
index 8859b9b36..000000000
--- a/httemplate/elements/tr-select-payment_options.html
+++ /dev/null
@@ -1,99 +0,0 @@
-<%doc>
-
-Example:
-
-  include( '/elements/tr-select-payment_options.html',
-
-    #opt - most get used in /elements/tr-amount-fee
-    'custnum'              => 4,     # customer number needed for selecting invoices
-    'prefix'               => 'pre', # prefix to fields and row ID's
-    'amount'               => 1,     # payment amount
-    'process-pkgpart'      => scalar($conf->config('manual_process-pkgpart', $cust_main->agentnum)),
-    'process-display'      => scalar($conf->config('manual_process-display')),
-    'process-skip_first'   => $conf->exists('manual_process-skip_first'),
-    'num_payments'         => scalar($cust_main->cust_pay),
-    'surcharge_percentage' =>
-      ( $payby eq 'CARD'
-          ? scalar($conf->config('credit-card-surcharge-percentage', $cust_main->agentnum))
-          : 0
-      ),
-    'surcharge_flatfee' =>
-      ( $payby eq 'CARD'
-          ? scalar($conf->config('credit-card-surcharge-flatfee', $cust_main->agentnum))
-          : 0
-      ),
-  )
-
-</%doc>
-
-  <TR STYLE="display:block">
-    <TH ALIGN="right"><% mt('Payment options') |h %></TH>
-    <TD COLSPAN=7>
-     <SELECT
-  	  ID       = "<% $opt{prefix} %>payment_option"
-  	  NAME     = "<% $opt{prefix} %>payment_option"
-  	  onChange = "<% $opt{prefix} %>payment_option_changed(this)"
-  	  <% $opt{disabled} %>
-	>
-  		<OPTION VALUE="select">Select payment option</OPTION>
-  		<OPTION VALUE="<% $opt{amount} %>">Pay full balance</OPTION>
-  		<OPTION VALUE="invoice">Pay specific invoice</OPTION>
-  		<OPTION VALUE="">Pay specific amount</OPTION>
-	</SELECT>	
-    </TD>
-  </TR>
-
-  <& /elements/tr-select-invoice.html,
-       'custnum' => $opt{custnum},
-       'prefix'  => $opt{prefix},
-  &>
-
-  <& /elements/tr-amount_fee.html,
-       'row_style'  => 'STYLE="display:none;"',
-       %opt
-  &>
-
-  <SCRIPT TYPE="text/javascript">
-
-      function <% $opt{prefix} %>payment_option_changed(what) {
-
-        if ( what.value == 'select' ) {
-        	document.getElementById('payment_amount_row').style.display = 'none';
-        	document.getElementById('invoice_row').style.display = 'none';
-          document.getElementById('<% $opt{prefix} %>invoice').value = 'select';
-        	document.getElementById('amount').value = '';
-        }
-        else if ( what.value == 'invoice' ) {
-        	document.getElementById('payment_amount_row').style.display = 'none';
-        	document.getElementById('invoice_row').style.display = 'block';
-        	document.getElementById('amount').value = '';
-        }
-        else {
-        	document.getElementById('payment_amount_row').style.display = 'block';
-        	document.getElementById('invoice_row').style.display = 'none';
-          document.getElementById('<% $opt{prefix} %>invoice').value = 'select';
-        	document.getElementById('amount').value = what.value;
-        }
-
-      }
-
-      function <% $opt{prefix} %>invoice_select_changed(what) {
-
-        if ( what.value == 'select' ) {
-        	document.getElementById('payment_amount_row').style.display = 'none';
-        	document.getElementById('amount').value = '';
-        }
-        else {
-        	document.getElementById('payment_amount_row').style.display = 'block';
-        	document.getElementById('amount').value = what.value;
-        }
-
-      }
-
-</SCRIPT>
-
-<%init>
-
-my %opt = @_;
-
-</%init>
\ No newline at end of file
diff --git a/httemplate/misc/payment.cgi b/httemplate/misc/payment.cgi
index b882da061..6a1fd550b 100644
--- a/httemplate/misc/payment.cgi
+++ b/httemplate/misc/payment.cgi
@@ -27,6 +27,7 @@
              ? scalar($conf->config('credit-card-surcharge-flatfee', $cust_main->agentnum))
              : 0
          ),
+         'processing_fee' => scalar($conf->config('processing-fee', $cust_main->agentnum)),
   &>
 
 % if ( $conf->exists('part_pkg-term_discounts') ) {
diff --git a/httemplate/misc/process/payment.cgi b/httemplate/misc/process/payment.cgi
index 6163b93dd..4d4e62a32 100644
--- a/httemplate/misc/process/payment.cgi
+++ b/httemplate/misc/process/payment.cgi
@@ -32,6 +32,8 @@ my $custnum = $1;
 my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } );
 die "unknown custnum $custnum" unless $cust_main;
 
+my $processing_fee = $cgi->param('processing_fee') ? $cgi->param('processing_fee') : '';
+
 $cgi->param('amount') =~ /^\s*(\d*(\.\d\d)?)\s*$/
   or errorpage("illegal amount ". $cgi->param('amount'));
 my $amount = $1;
@@ -204,6 +206,7 @@ if ( $cgi->param('batch') ) {
                                      'payinfo'  => $payinfo,
                                      'paydate'  => "$year-$month-01",
                                      'payname'  => $payname,
+                                     'processing-fee' => $processing_fee,
                                      map { $_ => scalar($cgi->param($_)) } 
                                        @{$payby2fields{$payby}}
                                    );
@@ -225,6 +228,7 @@ if ( $cgi->param('batch') ) {
     'discount_term' => $discount_term,
     'no_auto_apply' => ($cgi->param('apply') eq 'never') ? 'Y' : '',
     'no_invnum'     => 1,
+    'processing-fee' => $processing_fee,
     map { $_ => scalar($cgi->param($_)) } @{$payby2fields{$payby}}
   );
   errorpage($error) if $error;

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/Conf.pm                                      |   8 +
 FS/FS/cust_main.pm                                 |  56 ++++
 FS/FS/cust_main/Billing_Batch.pm                   | 304 +++++++++++++++++++++
 FS/FS/cust_main/Billing_Realtime.pm                |  97 +++++--
 httemplate/elements/tr-amount_fee.html             |  44 ++-
 httemplate/elements/tr-select-payment_options.html |  99 -------
 httemplate/misc/payment.cgi                        |   1 +
 httemplate/misc/process/payment.cgi                |   4 +
 8 files changed, 483 insertions(+), 130 deletions(-)
 create mode 100644 FS/FS/cust_main/Billing_Batch.pm
 delete mode 100644 httemplate/elements/tr-select-payment_options.html




More information about the freeside-commits mailing list