RT# 76093 - Added ability to charge a processing fee when taking a payment on the...
authorChristopher Burger <burgerc@freeside.biz>
Mon, 5 Nov 2018 22:44:50 +0000 (17:44 -0500)
committerChristopher Burger <burgerc@freeside.biz>
Mon, 5 Nov 2018 22:44:50 +0000 (17:44 -0500)
FS/FS/Conf.pm
FS/FS/cust_main/Billing_Batch.pm
FS/FS/cust_main/Billing_Realtime.pm
httemplate/elements/tr-amount_fee.html
httemplate/elements/tr-select-payment_options.html
httemplate/misc/payment.cgi
httemplate/misc/process/payment.cgi

index aed054a..d5b72fa 100644 (file)
@@ -2654,6 +2654,14 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'processing-fee',
+    'section'     => 'payments',
+    'description' => 'Fee for back end payment processing.',
+    'type'        => 'text',
+    'per_agent'   => 1,
+  },
+
+  {
     'key'         => 'banned_pay-pad',
     'section'     => 'credit_cards',
     'description' => 'Padding for encrypted storage of banned credit card hashes.  If you already have new-style SHA512 entries in the banned_pay table, do not change as this will invalidate the old entries.',
index 70dc288..1ea069d 100644 (file)
@@ -167,6 +167,41 @@ sub batch_card {
     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;
index 714a2e6..b29408b 100644 (file)
@@ -474,8 +474,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;
@@ -1061,7 +1061,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;
@@ -1082,44 +1082,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'});
+
+      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 '';
+      }
 
-         my $grand_error = 
-           $cust_bill->add_cc_surcharge($cust_pkg->pkgnum,$options{'cc_surcharge'});
+      $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
 
     }
index a84fef6..94795de 100644 (file)
@@ -8,7 +8,7 @@
                                 VALUE    = "<% $amount %>"
                                 SIZE     = 8
                                 STYLE    = "text-align:right;"
-%                               if ( $fee || $surcharge_percentage || $surcharge_flatfee ) {
+%                               if ( $fee || $surcharge_percentage || $surcharge_flatfee || $processing_fee) {
                                   onChange   = "amount_changed(this)"
                                   onKeyDown  = "amount_changed(this)"
                                   onKeyUp    = "amount_changed(this)"
     </TD>
   </TR>
 
-% if ($fee || $surcharge_percentage || $surcharge_flatfee ) {
+%        if ( $processing_fee ) {
+      <TR>
+        <TH ALIGN="right"><% mt('Apply 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 ID="ajax_processingfee_cell" BGCOLOR="#dddddd" STYLE="border:1px solid blue">
+             <FONT SIZE="+1">A processing fee of <% $processing_fee %> is being applied to this transaction.</FONT>
+            </TD>
+          </TR></TABLE>
+        </TD>
+      </TR>
+%        }
+
+% if ($fee || $surcharge_percentage || $surcharge_flatfee || $processing_fee) {
 
     <SCRIPT TYPE="text/javascript">
 
 
 % if ( $surcharge_percentage || $surcharge_flatfee ) {
         var surcharge_cell = document.getElementById('ajax_surcharge_cell');
+        var amount = what.value;
+        if (document.getElementById('processing_fee').checked == true) {
+          amount = (what.value - <% $processing_fee %>);
+        }
         var surcharge = ((what.value - <% $surcharge_flatfee %>) * <% $surcharge_percentage %>) + <% $surcharge_flatfee %>;
         surcharge_cell.innerHTML = '<FONT SIZE="+1">A credit card surcharge of ' + surcharge.toFixed(2) + ' is included in this payment</FONT>';
 % }
@@ -82,6 +102,7 @@ my $fee_op = '';
 my $surcharge = '';
 my $surcharge_percentage = 0;
 my $surcharge_flatfee = 0;
+my $processing_fee = 0;
 
 if ( $opt{'process-pkgpart'}
      and ! $opt{'process-skip_first'} || $opt{'num_payments'}
@@ -115,6 +136,7 @@ if ( $amount ) {
   $surcharge_flatfee = $opt{'surcharge_flatfee'} if $opt{'surcharge_flatfee'} > 0;
   $surcharge = $amount * $surcharge_percentage if $surcharge_percentage > 0;
   $surcharge += $surcharge_flatfee if ( $surcharge_flatfee > 0 && $amount > 0 );
+  $processing_fee = $opt{'processing_fee'} if $opt{'processing_fee'} > 0;
 
   $amount += $surcharge;
 
index f86f3ed..c5b84e7 100644 (file)
@@ -22,6 +22,7 @@ Example:
           ? scalar($conf->config('credit-card-surcharge-flatfee', $cust_main->agentnum))
           : 0
       ),
+    'processing_fee' => scalar($conf->config('processing-fee', $cust_main->agentnum)),
   )
 
 </%doc>
@@ -59,6 +60,7 @@ Example:
 
       $('#payment_option_row').<% $payment_option_row %>();
       $('#payment_amount_row').<% $payment_amount_row %>();
+      $('#ajax_processingfee_cell').hide();
 
       if($('#payment_amount_row').is(':visible')) {
         var surcharge;
@@ -76,11 +78,21 @@ Example:
       function <% $opt{prefix} %>payment_option_changed(what) {
 
         var surcharge;
+        var processingFee = 0;
+        var pfElement = document.getElementById('processing_fee');
+
         if (document.getElementById('surcharge_percentage') || document.getElementById('surcharge_flatfee')) {
           surcharge = (+what.value * +document.getElementById('surcharge_percentage').value) + +document.getElementById('surcharge_flatfee').value;
         }
         else { surcharge = 0; }
-        var amount = +what.value + +surcharge;
+
+        if (pfElement != null) {
+          if (pfElement.checked == true) {
+           processingFee = +pfElement.value;
+          }
+        }
+
+        var amount = +what.value + +surcharge + +processingFee;
         document.getElementById('amount').disabled = true;
 
         if ( what.value == 'select' ) {
@@ -131,12 +143,21 @@ Example:
       function <% $opt{prefix} %>invoice_select_changed(what) {
 
         var surcharge;
+        var processingFee = 0;
+        var pfElement = document.getElementById('processing_fee');
         var invdue = document.getElementById("<% $opt{prefix} %>inv" + what.value);
         if (document.getElementById('surcharge_percentage') || document.getElementById('surcharge_flatfee')) {
           surcharge = (+invdue.value * +document.getElementById('surcharge_percentage').value) + +document.getElementById('surcharge_flatfee').value;
         }
         else { surcharge = 0; }
-        var amount = +invdue.value + +surcharge;
+
+        if (pfElement != null) {
+          if (pfElement.checked == true) {
+           processingFee = +pfElement.value;
+          }
+        }
+
+        var amount = +invdue.value + +surcharge + +processingFee;
 
         if ( what.value == 'select' ) {
           $('#payment_amount_row').hide();
@@ -154,6 +175,21 @@ Example:
 
       }
 
+      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));
+          $('#ajax_processingfee_cell').show();
+        }
+        else {
+          var amount = +document.getElementById('amount').value - +document.getElementById('processing_fee').value;
+          $('#amount').val(amount.toFixed(2));
+          $('#ajax_processingfee_cell').hide();
+        }
+
+      }
+
 </SCRIPT>
 
 <%init>
index 77f5acd..7911a5d 100644 (file)
@@ -29,6 +29,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') ) {
index 7747bcb..56bcfd8 100644 (file)
@@ -41,6 +41,8 @@ my $cust_main = qsearchs({
 
 my $invoice = ($cgi->param('invoice') =~ /^(\d+)$/) ? $cgi->param('invoice') : '';
 
+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;
@@ -233,6 +235,7 @@ if ( $cgi->param('batch') ) {
                                      'paydate'  => $paydate,
                                      'payname'  => $payname,
                                      'invnum'   => $invoice,
+                                     'processing-fee' => $processing_fee,
                                      map { $_ => scalar($cgi->param($_)) } 
                                        @{$payby2fields{$payby}}
                                    );
@@ -256,6 +259,7 @@ if ( $cgi->param('batch') ) {
     'no_auto_apply' => ($cgi->param('apply') eq 'never') ? 'Y' : '',
     'no_invnum'     => 1,
     'invnum'        => $invoice,
+    'processing-fee' => $processing_fee,
     map { $_ => scalar($cgi->param($_)) } @{$payby2fields{$payby}}
   );
   errorpage($error) if $error;