package FS::cust_pay;
use strict;
-use vars qw( @ISA $conf $unsuspendauto $smtpmachine $invoice_from );
+use vars qw( @ISA $conf $unsuspendauto );
use Date::Format;
-use Mail::Header;
-use Mail::Internet;
use Business::CreditCard;
+use Text::Template;
use FS::UID qw( dbh );
use FS::Record qw( dbh qsearch qsearchs dbh );
+use FS::Misc qw(send_email);
use FS::cust_bill;
use FS::cust_bill_pay;
+use FS::cust_pay_refund;
use FS::cust_main;
@ISA = qw( FS::Record );
#ask FS::UID to run this stuff for us later
-$FS::UID::callback{'FS::cust_pay'} = sub {
-
+FS::UID->install_callback( sub {
$conf = new FS::Conf;
$unsuspendauto = $conf->exists('unsuspendauto');
- $smtpmachine = $conf->config('smtpmachine');
- $invoice_from = $conf->config('invoice_from');
-
-};
+} );
=head1 NAME
=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 - `CARD' (credit cards), `BILL' (billing), or `COMP' (free)
+=item payby - `CARD' (credit cards), `CHEK' (electronic check/ACH),
+`LECB' (phone bill billing), `BILL' (billing), or `COMP' (free)
=item payinfo - card number, check #, or comp issuer (4-8 lowercase alphanumerics; think username), respectively
$self->custnum($cust_bill->custnum );
}
- my $cust_main = qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+ my $cust_main = $self->cust_main;
my $old_balance = $cust_main->balance;
my $error = $self->check;
}
}
- $dbh->commit or die $dbh->errstr if $oldAutoCommit;
-
#false laziness w/ cust_credit::insert
if ( $unsuspendauto && $old_balance && $cust_main->balance <= 0 ) {
my @errors = $cust_main->unsuspend;
}
#eslaf
- '';
-
-}
-
-sub upgrade_replace { #1.3.x->1.4.x
- my $self = shift;
-
- local $SIG{HUP} = 'IGNORE';
- local $SIG{INT} = 'IGNORE';
- local $SIG{QUIT} = 'IGNORE';
- local $SIG{TERM} = 'IGNORE';
- local $SIG{TSTP} = 'IGNORE';
- local $SIG{PIPE} = 'IGNORE';
-
- my $oldAutoCommit = $FS::UID::AutoCommit;
- local $FS::UID::AutoCommit = 0;
- my $dbh = dbh;
-
- my $error = $self->check;
- return $error if $error;
-
- my %new = $self->hash;
- my $new = FS::cust_pay->new(\%new);
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
- if ( $self->invnum ) {
- my $cust_bill_pay = new FS::cust_bill_pay {
- 'invnum' => $self->invnum,
- 'paynum' => $self->paynum,
- 'amount' => $self->paid,
- '_date' => $self->_date,
+ #my $cust_main = $self->cust_main;
+ if ( $conf->exists('payment_receipt_email')
+ && grep { $_ ne 'POST' } $cust_main->invoicing_list
+ ) {
+
+ my $receipt_template = new Text::Template (
+ TYPE => 'ARRAY',
+ SOURCE => [ map "$_\n", $conf->config('payment_receipt_email') ],
+ ) or do {
+ warn "can't create payment receipt template: $Text::Template::ERROR";
+ return '';
};
- $error = $cust_bill_pay->insert;
- if ( $error =~
- /total cust_bill_pay.amount and cust_credit_bill.amount .* for invnum .* greater than cust_bill.charged/ ) {
- #warn $error;
- my $cust_bill = qsearchs( 'cust_bill', { 'invnum' => $self->invnum } );
- $new->custnum($cust_bill->custnum);
- } elsif ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
- } else {
- $new->custnum($cust_bill_pay->cust_bill->custnum);
+
+ my @invoicing_list = grep { $_ ne 'POST' } $cust_main->invoicing_list;
+
+ my $error = send_email(
+ 'from' => $conf->config('invoice_from'), #??? well as good as any
+ 'to' => \@invoicing_list,
+ 'subject' => 'Payment receipt',
+ 'body' => $receipt_template->fill_in( HASH => {
+ 'date' => str2time("%a %B %o, %Y", $self->_date),
+ 'paynum' => $self->paynum,
+ 'paid' => $self->paid,
+ 'payby' => ucfirst(lc($self->payby)),
+ 'payinfo' => ( $self->payby eq 'CARD'
+ ? $self->payinfo_masked
+ : $self->payinfo ),
+ 'balance' => $cust_main->balance,
+ } ),
+ );
+ if ( $error ) {
+ warn "can't send payment receipt: $error";
}
- } else {
- die;
- }
- $error = $new->SUPER::replace($self);
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
}
- $dbh->commit or die $dbh->errstr if $oldAutoCommit;
-
'';
-
}
=item delete
if ( $conf->config('deletepayments') ne '' ) {
- my $cust_main = qsearchs('cust_main',{ 'custnum' => $self->custnum });
- #false laziness w/FS::cust_bill::send
- $ENV{MAILADDRESS} = $conf->config('invoice_from'); #??? well as good as any
- my $header = new Mail::Header ( [
- "From: $invoice_from",
- "To: ". $conf->config('deletepayments'),
- "Sender: $invoice_from",
- "Reply-To: $invoice_from",
- "Date: ". time2str("%a, %d %b %Y %X %z", time),
- "Subject: FREESIDE NOTIFICATION: Payment deleted",
- ] );
- my $message = new Mail::Internet (
- 'Header' => $header,
- 'Body' => [
+ my $cust_main = $self->cust_main;
+
+ my $error = send_email(
+ 'from' => $conf->config('invoice_from'), #??? well as good as any
+ 'to' => $conf->config('deletepayments'),
+ 'subject' => 'FREESIDE NOTIFICATION: Payment deleted',
+ 'body' => [
"This is an automatic message from your Freeside installation\n",
"informing you that the following payment has been deleted:\n",
"\n",
'paybatch: '. $self->paybatch. "\n",
],
);
- $!=0;
- $message->smtpsend( Host => $smtpmachine )
- or $message->smtpsend( Host => $smtpmachine, Debug => 1 )
- or do {
- $dbh->rollback if $oldAutoCommit;
- return "(customer # ". $self->custnum.
- ") can't send payment deletion email to ".
- $conf->config('deletepayments').
- " via server $smtpmachine with SMTP: $!";
- };
+
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't send payment deletion notification: $error";
+ }
+
}
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
$self->_date(time) unless $self->_date;
- $self->payby =~ /^(CARD|BILL|COMP)$/ or return "Illegal payby";
+ $self->payby =~ /^(CARD|CHEK|LECB|BILL|COMP)$/ or return "Illegal payby";
$self->payby($1);
#false laziness with cust_refund::check
return $error if $error;
}
- ''; #no error
-
+ $self->SUPER::check;
}
=item cust_bill_pay
;
}
+=item cust_pay_refund
+
+Returns all applications of refunds (see L<FS::cust_pay_refund>) to this
+payment.
+
+=cut
+
+sub cust_pay_refund {
+ my $self = shift;
+ sort { $a->_date <=> $b->_date }
+ qsearch( 'cust_pay_refund', { 'paynum' => $self->paynum } )
+ ;
+}
+
+
=item unapplied
Returns the amount of this payment that is still unapplied; which is
-paid minus all payment applications (see L<FS::cust_bill_pay>).
+paid minus all payment applications (see L<FS::cust_bill_pay>) and refund
+applications (see L<FS::cust_pay_refund>).
=cut
my $self = shift;
my $amount = $self->paid;
$amount -= $_->amount foreach ( $self->cust_bill_pay );
+ $amount -= $_->amount foreach ( $self->cust_pay_refund );
sprintf("%.2f", $amount );
}
-=back
+=item cust_main
+
+Returns the parent customer object (see L<FS::cust_main>).
-=head1 VERSION
+=cut
-$Id: cust_pay.pm,v 1.18 2002-03-18 19:49:10 ivan Exp $
+sub cust_main {
+ my $self = shift;
+ qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+}
+
+=item payinfo_masked
+
+Returns a "masked" payinfo field with all but the last four characters replaced
+by 'x'es. Useful for displaying credit cards.
+
+=cut
+
+sub payinfo_masked {
+ my $self = shift;
+ my $payinfo = $self->payinfo;
+ 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4));
+}
+
+=back
=head1 BUGS
-Delete and replace methods.
+Delete and replace methods. payinfo_masked false laziness with cust_main.pm
+and cust_refund.pm
=head1 SEE ALSO