changes to support eWay third-party payment, #10208
[freeside.git] / FS / FS / cust_pay_pending.pm
index 7d81754..e54690e 100644 (file)
@@ -2,13 +2,14 @@ package FS::cust_pay_pending;
 
 use strict;
 use vars qw( @ISA  @encrypted_fields );
-use FS::Record qw( qsearch qsearchs );
-use FS::payby;
-use FS::payinfo_Mixin;
+use FS::Record qw( qsearch qsearchs dbh ); #dbh for _upgrade_data
+use FS::payinfo_transaction_Mixin;
+use FS::cust_main_Mixin;
 use FS::cust_main;
+use FS::cust_pkg;
 use FS::cust_pay;
 
-@ISA = qw(FS::Record FS::payinfo_Mixin);
+@ISA = qw( FS::payinfo_transaction_Mixin FS::cust_main_Mixin FS::Record );
 
 @encrypted_fields = ('payinfo');
 
@@ -40,32 +41,88 @@ following fields are currently supported:
 
 =over 4
 
-=item paypendingnum - primary key
+=item paypendingnum
 
-=item custnum - customer (see L<FS::cust_main>)
+Primary key
 
-=item paid - Amount of this payment
+=item custnum
 
-=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">.  Also see
+Customer (see L<FS::cust_main>)
+
+=item paid
+
+Amount of this payment
+
+=item _date
+
+Specified as a UNIX timestamp; see L<perlfunc/"time">.  Also see
 L<Time::Local> and L<Date::Parse> for conversion functions.
 
-=item payby - Payment Type (See L<FS::payinfo_Mixin> for valid payby values)
+=item payby
 
-=item payinfo - Payment Information (See L<FS::payinfo_Mixin> for data format)
+Payment Type (See L<FS::payinfo_Mixin> for valid payby values)
 
-=item paymask - Masked payinfo (See L<FS::payinfo_Mixin> for how this works)
+=item payinfo
 
-=item paydate - Expiration date
+Payment Information (See L<FS::payinfo_Mixin> for data format)
 
-=item payunique - Unique identifer to prevent duplicate transactions.
+=item paymask
 
-=item status - new (acquires basic lock on payunique), pending (transaction is pending with the gateway), authorized (only used for two-stage transactions that require a separate capture step), captured/declined (transaction completed with payment gateway, not yet recorded in the database), done (transaction recorded in database)
+Masked payinfo (See L<FS::payinfo_Mixin> for how this works)
 
-=item statustext - 
+=item paydate
 
-=cut
+Expiration date
+
+=item payunique
+
+Unique identifer to prevent duplicate transactions.
+
+=item pkgnum
+
+Desired pkgnum when using experimental package balances.
+
+=item status
+
+Pending transaction status, one of the following:
+
+=over 4
+
+=item new
+
+Aquires basic lock on payunique
+
+=item pending
+
+Transaction is pending with the gateway
+
+=item authorized
+
+Only used for two-stage transactions that require a separate capture step
+
+=item captured
 
-#=item cust_balance - 
+Transaction completed with payment gateway (sucessfully), not yet recorded in
+the database
+
+=item declined
+
+Transaction completed with payment gateway (declined), not yet recorded in
+the database
+
+=item done
+
+Transaction recorded in database
+
+=back
+
+=item statustext
+
+Additional status information.
+
+=item gatewaynum
+
+L<FS::payment_gateway> id.
 
 =item paynum - 
 
@@ -139,7 +196,9 @@ sub check {
     #|| $self->ut_textn('statustext')
     || $self->ut_anything('statustext')
     #|| $self->ut_money('cust_balance')
+    || $self->ut_hexn('session_id')
     || $self->ut_foreign_keyn('paynum', 'cust_pay', 'paynum' )
+    || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum')
     || $self->payinfo_check() #payby/payinfo/paymask/paydate
   ;
   return $error if $error;
@@ -163,6 +222,111 @@ sub check {
   $self->SUPER::check;
 }
 
+=item cust_main
+
+Returns the associated L<FS::cust_main> record if any.  Otherwise returns false.
+
+=cut
+
+sub cust_main {
+  my $self = shift;
+  qsearchs('cust_main', { custnum => $self->custnum } );
+}
+
+
+#these two are kind-of false laziness w/cust_main::realtime_bop
+#(currently only used when resolving pending payments manually)
+
+=item insert_cust_pay
+
+Sets the status of this pending pament to "done" (with statustext
+"captured (manual)"), and inserts a payment record (see L<FS::cust_pay>).
+
+Currently only used when resolving pending payments manually.
+
+=cut
+
+sub insert_cust_pay {
+  my $self = shift;
+
+  my $cust_pay = new FS::cust_pay ( {
+     'custnum'  => $self->custnum,
+     'paid'     => $self->paid,
+     '_date'    => $self->_date, #better than passing '' for now
+     'payby'    => $self->payby,
+     'payinfo'  => $self->payinfo,
+     'paybatch' => $self->paybatch,
+     'paydate'  => $self->paydate,
+  } );
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  #start a transaction, insert the cust_pay and set cust_pay_pending.status to done in a single transction
+
+  my $error = $cust_pay->insert;#($options{'manual'} ? ( 'manual' => 1 ) : () );
+
+  if ( $error ) {
+    # gah.
+    $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
+    return $error;
+  }
+
+  $self->status('done');
+  $self->statustext('captured (manual)');
+  $self->paynum($cust_pay->paynum);
+  my $cpp_done_err = $self->replace;
+
+  if ( $cpp_done_err ) {
+
+    $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
+    return $cpp_done_err;
+
+  } else {
+
+    $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+    return ''; #no error
+
+  }
+
+}
+
+=item decline [ STATUSTEXT ]
+
+Sets the status of this pending payment to "done" (with statustext
+"declined (manual)" unless otherwise specified).
+
+Currently only used when resolving pending payments manually.
+
+=cut
+
+sub decline {
+  my $self = shift;
+  my $statustext = shift || "declined (manual)";
+
+  #could send decline email too?  doesn't seem useful in manual resolution
+
+  $self->status('done');
+  $self->statustext($statustext);
+  $self->replace;
+}
+
+# _upgrade_data
+#
+# Used by FS::Upgrade to migrate to a new database.
+
+sub _upgrade_data {  #class method
+  my ($class, %opts) = @_;
+
+  my $sql =
+    "DELETE FROM cust_pay_pending WHERE status = 'new' AND _date < ".(time-600);
+
+  my $sth = dbh->prepare($sql) or die dbh->errstr;
+  $sth->execute or die $sth->errstr;
+
+}
+
 =back
 
 =head1 BUGS