add to ACH batch feature from customer view page
authorjeff <jeff>
Mon, 23 Apr 2007 03:41:31 +0000 (03:41 +0000)
committerjeff <jeff>
Mon, 23 Apr 2007 03:41:31 +0000 (03:41 +0000)
FS/FS/Conf.pm
FS/FS/cust_bill.pm
FS/FS/cust_main.pm
FS/FS/pay_batch.pm
httemplate/misc/download-batch.cgi
httemplate/misc/payment.cgi
httemplate/misc/process/payment.cgi

index 8bff460..93ecf30 100644 (file)
@@ -1227,6 +1227,13 @@ httemplate/docs/config.html
   },
 
   {
+    'key'         => 'paymentforcedtobatch',
+    'section'     => 'UI',
+    'description' => 'Causes per customer payment entry to be forced to a batch processor rather than performed realtime.',
+    'type'        => 'checkbox',
+  },
+
+  {
     'key'         => 'svc_acct-notes',
     'section'     => 'UI',
     'description' => 'Extra HTML to be displayed on the Account View screen.',
index d39e6dd..877d364 100644 (file)
@@ -1434,107 +1434,9 @@ sub batch_card {
   my ($self, %options) = @_;
   my $cust_main = $self->cust_main;
 
-  my $amount = sprintf("%.2f", $cust_main->balance - $cust_main->in_transit_payments);
-  return '' unless $amount > 0;
+  $options{invnum} = $self->invnum;
   
-  if ($options{'realtime'}) {
-    return $cust_main->realtime_bop( FS::payby->payby2bop($cust_main->payby),
-                                     $amount,
-                                     %options,
-                                   );
-  }
-
-  my $oldAutoCommit = $FS::UID::AutoCommit;
-  local $FS::UID::AutoCommit = 0;
-  my $dbh = dbh;
-
-  $dbh->do("LOCK TABLE pay_batch IN SHARE ROW EXCLUSIVE MODE")
-    or return "Cannot lock pay_batch: " . $dbh->errstr;
-
-  my %pay_batch = (
-    'status' => 'O',
-    'payby'  => FS::payby->payby2payment($cust_main->payby),
-  );
-
-  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'  => $cust_main->custnum,
-  } );
-
-  my $cust_pay_batch = new FS::cust_pay_batch ( {
-    'batchnum' => $pay_batch->batchnum,
-    'invnum'   => $self->getfield('invnum'),       # is there a better value?
-                                                   # this field should be
-                                                  # removed...
-                                                  # cust_bill_pay_batch now
-    'custnum'  => $cust_main->custnum,
-    'last'     => $cust_main->getfield('last'),
-    'first'    => $cust_main->getfield('first'),
-    'address1' => $cust_main->address1,
-    'address2' => $cust_main->address2,
-    'city'     => $cust_main->city,
-    'state'    => $cust_main->state,
-    'zip'      => $cust_main->zip,
-    'country'  => $cust_main->country,
-    'payby'    => $cust_main->payby,
-    'payinfo'  => $cust_main->payinfo,
-    'exp'      => $cust_main->paydate,
-    'payname'  => $cust_main->payname,
-    'amount'   => $amount,                          # consolidating
-  } );
-  
-  $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;
-  }
-
-  my $unapplied = $cust_main->total_credited + $cust_main->total_unapplied_payments + $cust_main->in_transit_payments;
-  foreach my $cust_bill ($cust_main->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;
-  '';
+  $cust_main->batch_card(%options);
 }
 
 sub _agent_template {
index 1224c88..708f014 100644 (file)
@@ -3177,6 +3177,132 @@ sub realtime_refund_bop {
 
 }
 
+=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.
+
+=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);
+  }
+  return '' unless $amount > 0;
+  
+  my $invnum = delete $options{invnum};
+  my $payby = $options{invnum} || $self->payby;  #dubious
+
+  if ($options{'realtime'}) {
+    return $self->realtime_bop( FS::payby->payby2bop($self->payby),
+                                $amount,
+                                %options,
+                              );
+  }
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  $dbh->do("LOCK TABLE pay_batch IN SHARE ROW EXCLUSIVE MODE")
+    or return "Cannot lock pay_batch: " . $dbh->errstr;
+
+  my %pay_batch = (
+    'status' => 'O',
+    'payby'  => FS::payby->payby2payment($payby),
+  );
+
+  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 payby payinfo paydate
+               payname )) {
+    $options{$_} = '' unless exists($options{$_});
+  }
+
+  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} || $self->address1,
+    'address2' => $options{address2} || $self->address2,
+    'city'     => $options{city}     || $self->city,
+    'state'    => $options{state}    || $self->state,
+    'zip'      => $options{zip}      || $self->zip,
+    'country'  => $options{country}  || $self->country,
+    'payby'    => $options{payby}    || $self->payby,
+    'payinfo'  => $options{payinfo}  || $self->payinfo,
+    'exp'      => $options{paydate}  || $self->paydate,
+    'payname'  => $options{payname}  || $self->payname,
+    'amount'   => $amount,                         # consolidating
+  } );
+  
+  $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;
+  }
+
+  my $unapplied = $self->total_credited + $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 total_owed
 
 Returns the total owed for this customer on all invoices
@@ -4882,6 +5008,9 @@ payinfo_masked false laziness with cust_pay.pm and cust_refund.pm
 
 Birthdates rely on negative epoch values.
 
+The payby for card/check batches is broken.  With mixed batching, bad
+things will happen.
+
 =head1 SEE ALSO
 
 L<FS::Record>, L<FS::cust_pkg>, L<FS::cust_bill>, L<FS::cust_credit>
index 5a06ba6..c097534 100644 (file)
@@ -138,7 +138,7 @@ sub set_status {
   $self->replace();
 }
 
-=item import results OPTION => VALUE, ...
+=item import_results OPTION => VALUE, ...
 
 Import batch results.
 
@@ -162,6 +162,7 @@ sub import_results {
   my $formatre;      # for Fixed.+
   my @values;
   my $begin_condition;
+  my $pre_hook;
   my $end_condition;
   my $end_hook;
   my $hook;
@@ -340,7 +341,7 @@ sub import_results {
 
     @fields = (
       '',            # Name
-      'paybatchnum', # ID:  Invoice number of the transaction
+      'custnum'    , # ID:  Customer number of the transaction
       'aba',         # ABA Number for the transaction
       'payinfo',     # Bank Account Number for the transaction
       '',            # Transaction Type:  27 - debit
@@ -354,6 +355,20 @@ sub import_results {
       '';
     };
 
+    $pre_hook = sub {
+      my $hash = shift;
+      my @cust_pay_batch =    # this is dodgy, it works due to autoposting
+        qsearch('cust_pay_batch', { 'custnum' => $hash->{'custnum'}+0, 
+                                    'status'  => ''
+                                  } );
+      if ( scalar(@cust_pay_batch) == 1 ) {
+        $hash->{'paybatchnum'} = $cust_pay_batch[0]->paybatchnum;
+      }else{
+        return "can't find batch payment for customer number " .$hash->{custnum};
+      }
+      '';
+    };
+
     $hook = sub {
       my $hash = shift;
       $hash->{'_date'} = time;  # got a better one?
@@ -429,6 +444,14 @@ sub import_results {
       $hash{$field} = $value;
     }
 
+    if ( defined($pre_hook) ) {
+      my $error = &{$pre_hook}(\%hash);
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
+    }
+
     if ( &{$end_condition}(\%hash) ) {
       my $error = &{$end_hook}(\%hash, $total);
       if ( $error ) {
index da97537..26c385e 100644 (file)
@@ -99,7 +99,7 @@
 %
 %  my( $account, $aba ) = split( '@', $cust_pay_batch->payinfo );
 %  my $payname=$cust_pay_batch->payname; $payname =~ tr/",/  /; #payinfo too?
-%  my $batchline = qq!"$payname","!.$cust_pay_batch->paybatchnum.
+%  my $batchline = qq!"$payname","!.$cust_pay_batch->custnum.   #dodgy, works for autoapply
 %                  qq!","$aba","$account","27","!.$cust_pay_batch->amount.
 %                  qq!","27","0.00"!;
 %  push @batchlines, $batchline;
index 1008a21..ac10282 100644 (file)
@@ -225,6 +225,16 @@ function OLiframeContent(src, width, height, name) {
     Remember this information
   </TD>
 </TR><TR>
+% if ($conf->exists("batch-enable")) {
+  <TD COLSPAN=2>
+    <INPUT TYPE="checkbox" <% ( $conf->exists("paymentforcedtobatch") && $payby eq 'CHEK' ) ? 'CHECKED DISABLED' : '' %> NAME="batch" VALUE="1">
+    Add to current batch
+% if ($conf->exists("paymentforcedtobatch") && $payby eq 'CHEK' ) {
+    <INPUT TYPE="hidden" NAME="batch" VALUE="1">
+% }
+  </TD>
+</TR><TR>
+% }
   <TD COLSPAN=2>
     <INPUT TYPE="checkbox"<% ( ( $payby eq 'CARD' && $cust_main->payby ne 'DCRD' ) || ( $payby eq 'CHEK' && $cust_main->payby eq 'CHEK' ) ) ? ' CHECKED' : '' %> NAME="auto" VALUE="1" onClick="if (this.checked) { document.OneTrueForm.save.checked=true; }">
     Charge future payments to this <% $type{$payby} %> automatically
index 8878f52..9ac5d5d 100644 (file)
 %  die "unknown payby $payby";
 %}
 %
-%my $error = $cust_main->realtime_bop( $FS::payby::payby2bop{$payby}, $amount,
-%  'quiet'    => 1,
-%  'manual'   => 1,
-%  'payinfo'  => $payinfo,
-%  'paydate'  => "$year-$month-01",
-%  'payname'  => $payname,
-%  'paybatch' => $paybatch,
-%  'paycvv'   => $paycvv,
-%  map { $_ => $cgi->param($_) } @{$payby2fields{$payby}}
-%);
-%eidiot($error) if $error;
-%
-%$cust_main->apply_payments;
+%my $error = '';
+%if ($cgi->param('batch')) {
+%  $error = $cust_main->batch_card(
+%                                   'payby'    => $payby,
+%                                   'amount'   => $amount,
+%                                   'payinfo'  => $payinfo,
+%                                   'paydate'  => "$year-$month-01",
+%                                   'payname'  => $payname,
+%                                   map { $_ => $cgi->param($_) } 
+%                                     @{$payby2fields{$payby}}
+%                                 );
+%  eidiot($error) if $error;
+%}else{
+%  $error = $cust_main->realtime_bop( $FS::payby::payby2bop{$payby}, $amount,
+%    'quiet'    => 1,
+%    'manual'   => 1,
+%    'payinfo'  => $payinfo,
+%    'paydate'  => "$year-$month-01",
+%    'payname'  => $payname,
+%    'paybatch' => $paybatch,
+%    'paycvv'   => $paycvv,
+%    map { $_ => $cgi->param($_) } @{$payby2fields{$payby}}
+%  );
+%  eidiot($error) if $error;
+%
+%  $cust_main->apply_payments;
+%}
 %
 %if ( $cgi->param('save') ) {
 %  my $new = new FS::cust_main { $cust_main->hash };