omit from history
[freeside.git] / FS / FS / cust_pay_batch.pm
index 9fa1459..20e88a0 100644 (file)
@@ -9,13 +9,16 @@ use FS::payinfo_Mixin;
 use FS::cust_main;
 use FS::cust_bill;
 
-@ISA = qw( FS::payinfo_Mixin FS::Record );
+@ISA = qw( FS::payinfo_Mixin FS::cust_main_Mixin FS::Record );
 
 # 1 is mostly method/subroutine entry and options
 # 2 traces progress of some operations
 # 3 is even more information including possibly sensitive data
 $DEBUG = 0;
 
+#@encrypted_fields = ('payinfo');
+sub nohistory_fields { ('payinfo'); }
+
 =head1 NAME
 
 FS::cust_pay_batch - Object methods for batch cards
@@ -80,7 +83,9 @@ following fields are currently supported:
 
 =item country 
 
-=item status
+=item status - 'Approved' or 'Declined'
+
+=item error_message - the error returned by the gateway if any
 
 =back
 
@@ -204,6 +209,17 @@ sub cust_main {
   qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
 }
 
+=item pay_batch
+
+Returns the payment batch this payment belongs to (L<FS::pay_batch).
+
+=cut
+
+sub pay_batch {
+  my $self = shift;
+  FS::pay_batch->by_key($self->batchnum);
+}
+
 #you know what, screw this in the new world of events.  we should be able to
 #get the event defs to retry (remove once.pm condition, add every.pm) without
 #mucking about with statuses of previous cust_event records.  right?
@@ -290,6 +306,8 @@ sub approve {
       'payinfo'   => $new->payinfo || $old->payinfo,
       'paid'      => $new->paid,
       '_date'     => $new->_date,
+      'usernum'   => $new->usernum,
+      'batchnum'  => $new->batchnum,
     } );
   $error = $cust_pay->insert;
   if ( $error ) {
@@ -299,22 +317,55 @@ sub approve {
   return;
 }
 
-=item decline
+=item decline [ REASON ]
 
 Decline this payment.  This will replace the existing record with the 
 same paybatchnum, set its status to 'Declined', and run collection events
 as appropriate.  This should only be called from the batch import process.
+
+REASON is a string description of the decline reason, defaulting to 
+'Returned payment'.
 
 =cut
+
 sub decline {
   my $new = shift;
+  my $reason = shift || 'Returned payment';
+  #my $conf = new FS::Conf;
+
   my $paybatchnum = $new->paybatchnum;
   my $old = qsearchs('cust_pay_batch', { paybatchnum => $paybatchnum })
     or return "paybatchnum $paybatchnum not found";
-  return "paybatchnum $paybatchnum already resolved ('".$old->status."')" 
-    if $old->status;
+  if ( $old->status ) {
+    # Handle the case where payments are rejected after the batch has been 
+    # approved.  FS::pay_batch::import_results won't allow results to be 
+    # imported to a closed batch unless batch-manual_approval is enabled, 
+    # so we don't check it here.
+#    if ( $conf->exists('batch-manual_approval') and
+    if ( lc($old->status) eq 'approved' ) {
+      # Void the payment
+      my $cust_pay = qsearchs('cust_pay', { 
+          custnum  => $new->custnum,
+          batchnum => $new->batchnum
+        });
+      # pre-3.0 style
+      $cust_pay ||= qsearchs('cust_pay', { 
+          custnum  => $new->custnum,
+          paybatch => $new->batchnum
+        });
+      if ( !$cust_pay ) {
+        # should never happen...
+        return "failed to revoke paybatchnum $paybatchnum, payment not found";
+      }
+      $cust_pay->void($reason);
+    }
+    else {
+      # normal case: refuse to do anything
+      return "paybatchnum $paybatchnum already resolved ('".$old->status."')";
+    }
+  } # !$old->status
   $new->status('Declined');
+  $new->error_message($reason);
   my $error = $new->replace($old);
   if ( $error ) {
     return "error updating status of paybatchnum $paybatchnum: $error\n";