one-way check batches, #17623
[freeside.git] / FS / FS / cust_pay_batch.pm
index 171ec9f..9f2e9dd 100644 (file)
@@ -204,6 +204,35 @@ sub cust_main {
   qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
 }
 
+=item expmmyy
+
+Returns the credit card expiration date in MMYY format.  If this is a 
+CHEK payment, returns an empty string.
+
+=cut
+
+sub expmmyy {
+  my $self = shift;
+  if ( $self->payby eq 'CARD' ) {
+    $self->get('exp') =~ /^(\d{4})-(\d{2})-(\d{2})$/;
+    return sprintf('%02u%02u', $2, ($1 % 100));
+  }
+  else {
+    return '';
+  }
+}
+
+=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?
@@ -276,6 +305,8 @@ sub approve {
   my $paybatchnum = $new->paybatchnum;
   my $old = qsearchs('cust_pay_batch', { paybatchnum => $paybatchnum })
     or return "paybatchnum $paybatchnum not found";
+  # leave these restrictions in place until TD EFT is converted over
+  # to B::BP
   return "paybatchnum $paybatchnum already resolved ('".$old->status."')" 
     if $old->status;
   $new->status('Approved');
@@ -291,6 +322,7 @@ sub approve {
       'paid'      => $new->paid,
       '_date'     => $new->_date,
       'usernum'   => $new->usernum,
+      'batchnum'  => $new->batchnum,
     } );
   $error = $cust_pay->insert;
   if ( $error ) {
@@ -300,26 +332,32 @@ 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 $conf = new FS::Conf;
+  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";
   if ( $old->status ) {
     # Handle the case where payments are rejected after the batch has been 
-    # approved.  Only if manual approval is enabled.
-    if ( $conf->exists('batch-manual_approval') 
-        and lc($old->status) eq 'approved' ) {
+    # 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,
@@ -329,7 +367,7 @@ sub decline {
         # should never happen...
         return "failed to revoke paybatchnum $paybatchnum, payment not found";
       }
-      $cust_pay->void('Returned payment');
+      $cust_pay->void($reason);
     }
     else {
       # normal case: refuse to do anything
@@ -358,6 +396,62 @@ sub decline {
   return;
 }
 
+=item request_item [ OPTIONS ]
+
+Returns a L<Business::BatchPayment::Item> object for this batch payment
+entry.  This can be submitted to a processor.
+
+OPTIONS can be a list of key/values to append to the attributes.  The most
+useful case of this is "process_date" to set a processing date based on the
+date the batch is being submitted.
+
+=cut
+
+sub request_item {
+  local $@;
+  my $self = shift;
+
+  eval "use Business::BatchPayment;";
+  die "couldn't load Business::BatchPayment: $@" if $@;
+
+  my $cust_main = $self->cust_main;
+  my $location = $cust_main->bill_location;
+  my $pay_batch = $self->pay_batch;
+
+  my %payment;
+  $payment{payment_type} = FS::payby->payby2bop( $pay_batch->payby );
+  if ( $payment{payment_type} eq 'CC' ) {
+    $payment{card_number} = $self->payinfo,
+    $payment{expiration}  = $self->expmmyy,
+  } elsif ( $payment{payment_type} eq 'ECHECK' ) {
+    $self->payinfo =~ /(\d+)@(\d+)/; # or else what?
+    $payment{account_number} = $1;
+    $payment{routing_code} = $2;
+    $payment{account_type} = $cust_main->paytype;
+    # XXX what if this isn't their regular payment method?
+  } else {
+    die "unsupported BatchPayment method: ".$pay_batch->payby;
+  }
+
+  Business::BatchPayment->create(Item =>
+    # required
+    action      => 'payment',
+    tid         => $self->paybatchnum,
+    amount      => $self->amount,
+
+    # customer info
+    customer_id => $self->custnum,
+    first_name  => $cust_main->first,
+    last_name   => $cust_main->last,
+    company     => $cust_main->company,
+    address     => $location->address1,
+    ( map { $_ => $location->$_ } qw(address2 city state country zip) ),
+    
+    invoice_number  => $self->invnum,
+    %payment,
+  );
+}
+
 =back
 
 =head1 BUGS