refactor payment history slightly, add refund receipts, have "unapplied" refunds...
authorivan <ivan>
Sun, 1 Jun 2008 22:48:15 +0000 (22:48 +0000)
committerivan <ivan>
Sun, 1 Jun 2008 22:48:15 +0000 (22:48 +0000)
12 files changed:
FS/FS/cust_pay.pm
FS/FS/cust_refund.pm
FS/FS/payinfo_Mixin.pm
FS/FS/payinfo_transaction_Mixin.pm [new file with mode: 0644]
httemplate/search/elements/cust_pay_or_refund.html
httemplate/view/cust_main/payment_history.html
httemplate/view/cust_main/payment_history/credit.html [new file with mode: 0644]
httemplate/view/cust_main/payment_history/invoice.html [new file with mode: 0644]
httemplate/view/cust_main/payment_history/payment.html [new file with mode: 0644]
httemplate/view/cust_main/payment_history/refund.html [new file with mode: 0644]
httemplate/view/cust_main/payment_history/voided_payment.html [new file with mode: 0644]
httemplate/view/cust_refund.html [new file with mode: 0644]

index 03e355f..1568870 100644 (file)
@@ -12,14 +12,14 @@ use FS::Misc qw( send_email );
 use FS::Record qw( dbh qsearch qsearchs );
 use FS::payby;
 use FS::cust_main_Mixin;
-use FS::payinfo_Mixin;
+use FS::payinfo_transaction_Mixin;
 use FS::cust_bill;
 use FS::cust_bill_pay;
 use FS::cust_pay_refund;
 use FS::cust_main;
 use FS::cust_pay_void;
 
-@ISA = qw( FS::Record FS::cust_main_Mixin FS::payinfo_Mixin );
+@ISA = qw( FS::payinfo_transaction_Mixin FS::cust_main_Mixin FS::Record );
 
 $DEBUG = 0;
 
@@ -550,90 +550,6 @@ sub unrefunded {
   sprintf("%.2f", $amount );
 }
 
-
-=item cust_main
-
-Returns the parent customer object (see L<FS::cust_main>).
-
-=cut
-
-sub cust_main {
-  my $self = shift;
-  qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
-}
-
-=item payby_name
-
-Returns a name for the payby field.
-
-=cut
-
-sub payby_name {
-  my $self = shift;
-  if ( $self->payby eq 'BILL' ) { #kludge
-    'Check';
-  } else {
-    FS::payby->shortname( $self->payby );
-  }
-}
-
-=item gatewaynum
-
-Returns a gatewaynum for the processing gateway.
-
-=item processor
-
-Returns a name for the processing gateway.
-
-=item authorization
-
-Returns a name for the processing gateway.
-
-=item order_number
-
-Returns a name for the processing gateway.
-
-=cut
-
-sub gatewaynum    { shift->_parse_paybatch->{'gatewaynum'}; }
-sub processor     { shift->_parse_paybatch->{'processor'}; }
-sub authorization { shift->_parse_paybatch->{'authorization'}; }
-sub order_number  { shift->_parse_paybatch->{'order_number'}; }
-
-#sucks that this stuff is in paybatch like this in the first place,
-#but at least other code can start to use new field names
-#(code nicked from FS::cust_main::realtime_refund_bop)
-sub _parse_paybatch {
-  my $self = shift;
-
-  $self->paybatch =~ /^((\d+)\-)?(\w+):\s*([\w\-\/ ]*)(:([\w\-]+))?$/
-    or return {};
-              #"Can't parse paybatch for paynum $options{'paynum'}: ".
-              #  $cust_pay->paybatch;
-
-  my( $gatewaynum, $processor, $auth, $order_number ) = ( $2, $3, $4, $6 );
-
-  if ( $gatewaynum ) { #gateway for the payment to be refunded
-
-    my $payment_gateway =
-      qsearchs('payment_gateway', { 'gatewaynum' => $gatewaynum } );
-
-    die "payment gateway $gatewaynum not found" #?
-      unless $payment_gateway;
-
-    $processor = $payment_gateway->gateway_module;
-
-  }
-
-  {
-    'gatewaynum'    => $gatewaynum,
-    'processor'     => $processor,
-    'authorization' => $auth,
-    'order_number'  => $order_number,
-  };
-
-}
-
 =back
 
 =head1 CLASS METHODS
index e075e3e..abc131e 100644 (file)
@@ -3,15 +3,16 @@ package FS::cust_refund;
 use strict;
 use vars qw( @ISA @encrypted_fields );
 use Business::CreditCard;
-use FS::Record qw( qsearch qsearchs dbh );
 use FS::UID qw(getotaker);
+use FS::Record qw( qsearch qsearchs dbh );
+use FS::cust_main_Mixin;
+use FS::payinfo_transaction_Mixin;
 use FS::cust_credit;
 use FS::cust_credit_refund;
 use FS::cust_pay_refund;
 use FS::cust_main;
-use FS::payinfo_Mixin;
 
-@ISA = qw( FS::payinfo_Mixin FS::cust_main_Mixin FS::Record );
+@ISA = qw( FS::payinfo_transaction_Mixin FS::cust_main_Mixin FS::Record );
 
 @encrypted_fields = ('payinfo');
 
index fb56371..99cca6a 100644 (file)
@@ -271,6 +271,8 @@ sub payby_payinfo_pretty {
   }
 }
 
+=back
+
 =head1 BUGS
 
 Future items?
diff --git a/FS/FS/payinfo_transaction_Mixin.pm b/FS/FS/payinfo_transaction_Mixin.pm
new file mode 100644 (file)
index 0000000..a6a2c99
--- /dev/null
@@ -0,0 +1,122 @@
+package FS::payinfo_transaction_Mixin;
+
+use strict;
+use vars qw( @ISA );
+use FS::payby;
+use FS::payinfo_Mixin;
+
+@ISA = qw( FS::payinfo_Mixin );
+
+=head1 NAME
+
+FS::payinfo_transaction_Mixin - Mixin class for records in tables that represent transactions.
+
+=head1 SYNOPSIS
+
+package FS::some_table;
+use vars qw(@ISA);
+@ISA = qw( FS::payinfo_transaction_Mixin FS::Record );
+
+=head1 DESCRIPTION
+
+This is a mixin class for records that represent transactions: that contain
+payinfo and paybatch.  Currently FS::cust_pay and FS::cust_refund
+
+=head1 METHODS
+
+=over 4
+
+
+=item cust_main
+
+Returns the parent customer object (see L<FS::cust_main>).
+
+=cut
+
+sub cust_main {
+  my $self = shift;
+  qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
+}
+
+=item payby_name
+
+Returns a name for the payby field.
+
+=cut
+
+sub payby_name {
+  my $self = shift;
+  if ( $self->payby eq 'BILL' ) { #kludge
+    'Check';
+  } else {
+    FS::payby->shortname( $self->payby );
+  }
+}
+
+=item gatewaynum
+
+Returns a gatewaynum for the processing gateway.
+
+=item processor
+
+Returns a name for the processing gateway.
+
+=item authorization
+
+Returns a name for the processing gateway.
+
+=item order_number
+
+Returns a name for the processing gateway.
+
+=cut
+
+sub gatewaynum    { shift->_parse_paybatch->{'gatewaynum'}; }
+sub processor     { shift->_parse_paybatch->{'processor'}; }
+sub authorization { shift->_parse_paybatch->{'authorization'}; }
+sub order_number  { shift->_parse_paybatch->{'order_number'}; }
+
+#sucks that this stuff is in paybatch like this in the first place,
+#but at least other code can start to use new field names
+#(code nicked from FS::cust_main::realtime_refund_bop)
+sub _parse_paybatch {
+  my $self = shift;
+
+  $self->paybatch =~ /^((\d+)\-)?(\w+):\s*([\w\-\/ ]*)(:([\w\-]+))?$/
+    or return {};
+              #"Can't parse paybatch for paynum $options{'paynum'}: ".
+              #  $cust_pay->paybatch;
+
+  my( $gatewaynum, $processor, $auth, $order_number ) = ( $2, $3, $4, $6 );
+
+  if ( $gatewaynum ) { #gateway for the payment to be refunded
+
+    my $payment_gateway =
+      qsearchs('payment_gateway', { 'gatewaynum' => $gatewaynum } );
+
+    die "payment gateway $gatewaynum not found" #?
+      unless $payment_gateway;
+
+    $processor = $payment_gateway->gateway_module;
+
+  }
+
+  {
+    'gatewaynum'    => $gatewaynum,
+    'processor'     => $processor,
+    'authorization' => $auth,
+    'order_number'  => $order_number,
+  };
+
+}
+
+
+
+
+=back
+
+=head1 SEE ALSO
+
+L<FS::payinfo_Mixin>
+
+=back
index cd1e19d..9457ae2 100755 (executable)
@@ -242,10 +242,9 @@ if ( $cgi->param('magic') ) {
 }
 
 my $link = '';
-if ( $thing eq 'pay' ) { #XXX no refund receipts yet
-  $link = [ "${p}view/cust_pay.html?paynum=", 'paynum' ]
-    if $FS::CurrentUser::CurrentUser->access_right('View invoices'); #XXX for now
-    #later# if $FS::CurrentUser::CurrentUser->access_right('View customer payments');
+if ( $FS::CurrentUser::CurrentUser->access_right('View invoices') #XXX for now
+     || $FS::CurrentUser::CurrentUser->access_right('View customer payments') ){
+  $link = [ "${p}view/cust_$thing.html?${thing}num=", $thing.'num' ]
 }
 
 my $cust_link = sub {
index 582fc8d..750e59d 100644 (file)
   <BR>
 % } 
 
-%#get payment history
-%my @history = ();
-%
-%#invoices
-%foreach my $cust_bill ($cust_main->cust_bill) {
-%  my $pre = ( $cust_bill->owed > 0 )
-%              ? '<B><FONT SIZE="+1" COLOR="#FF0000">Open '
-%              : '';
-%  my $post = ( $cust_bill->owed > 0 ) ? '</FONT></B>' : '';
-%  my $invnum = $cust_bill->invnum;
-%  my $link = $curuser->access_right('View invoices')
-%               ? qq!<A HREF="${p}view/cust_bill.cgi?$invnum">!
-%               : '';
-%  my $events = '';
-%  if ( $cust_bill->num_cust_event
-%       && (    $curuser->access_right('Billing event reports')
-%            || $curuser->access_right('View customer billing events')
-%          )
-%     ) {
-%    $events =
-%      qq!<BR><FONT SIZE="-1"><A HREF="${p}search/cust_event.html?invnum=!.
-%      $cust_bill->invnum. '">(&nbsp;View invoice events&nbsp;)</A></FONT>';
-%  }
-%  push @history, {
-%    'date'   => $cust_bill->_date,
-%    'desc'   => $link. $pre.
-%                "Invoice #$invnum (Balance \$". $cust_bill->owed. ')'.
-%                $post. ( $link ? '</A>' : '' ). $events,
-%    'charge' => $cust_bill->charged,
-%  };
-%}
-%
-%#payments (some false laziness w/credits)
-%foreach my $cust_pay ($cust_main->cust_pay) {
-%
-%  my $payby = $cust_pay->payby;
-%
-%  my $payinfo;
-%  if ( $payby eq 'CARD' ) {
-%    $payinfo = $cust_pay->paymask;
-%  } elsif ( $payby eq 'CHEK' ) {
-%    my( $account, $aba ) = split('@', $cust_pay->paymask );
-%    $payinfo = "ABA $aba, Acct #$account";
-%  } else {
-%    $payinfo = $cust_pay->payinfo;
-%  }
-%  my @cust_bill_pay = $cust_pay->cust_bill_pay;
-%  my @cust_pay_refund = $cust_pay->cust_pay_refund;
-%
-%  my $target = "$payby$payinfo";
-%  $payby =~ s/^BILL$/Check #/ if $payinfo;
-%  $payby =~ s/^CHEK$/Electronic check /;
-%  $payby =~ s/^PREP$/Prepaid card /;
-%  $payby =~ s/^CARD$/Credit card #/; 
-%  $payby =~ s/^COMP$/Complimentary by /; 
-%  $payby =~ s/^CASH$/Cash/;
-%  $payby =~ s/^WEST$/Western Union/;
-%  $payby =~ s/^MCRD$/Manual credit card/;
-%  $payby =~ s/^BILL$//;
-%  my $info = $payby ? "($payby$payinfo)" : '';
-%
-%  my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
-%  if (    scalar(@cust_bill_pay)   == 0
-%       && scalar(@cust_pay_refund) == 0 ) {
-%    #completely unapplied
-%    $pre = '<B><FONT COLOR="#FF0000">Unapplied ';
-%    $post = '</FONT></B>';
-%    if ( $curuser->access_right('Apply payment') ) {
-%      $apply = ' ('. include( '/elements/popup_link.html',
-%                                'label'       => 'apply',
-%                                'action'      => "${p}edit/cust_bill_pay.cgi?".
-%                                                 $cust_pay->paynum,
-%                                'actionlabel' => 'Apply payment',
-%                                'width'       => 392,
-%                                #default# 'height' => 336,
-%                            ).
-%                ')';
-%    }
-%  } elsif (    scalar(@cust_bill_pay)   == 1
-%            && scalar(@cust_pay_refund) == 0
-%            && $cust_pay->unapplied == 0     ) {
-%    #applied to one invoice, the usual situation
-%    $desc = ' '. $cust_bill_pay[0]->applied_to_invoice;
-%  } elsif (    scalar(@cust_bill_pay)   == 0
-%            && scalar(@cust_pay_refund) == 1
-%            && $cust_pay->unapplied == 0     ) {
-%    #applied to one refund
-%    $desc = ' refunded on '. time2str("%D", $cust_pay_refund[0]->_date);
-%  } else {
-%    #complicated
-%    $desc = '<BR>';
-%    foreach my $app ( sort { $a->_date <=> $b->_date }
-%                           ( @cust_bill_pay, @cust_pay_refund ) ) {
-%      if ( $app->isa('FS::cust_bill_pay') ) {
-%        $desc .= '&nbsp;&nbsp;'.
-%                 '$'. $app->amount.
-%                 ' '. $app->applied_to_invoice.
-%                 '<BR>';
-%                 #' on '. time2str("%D", $cust_bill_pay->_date).
-%      } elsif ( $app->isa('FS::cust_pay_refund') ) {
-%        $desc .= '&nbsp;&nbsp;'.
-%                 '$'. $app->amount.
-%                 ' refunded on '. time2str("%D", $app->_date).
-%                 '<BR>';
-%      } else {
-%        die "$app is not a FS::cust_bill_pay or FS::cust_pay_refund";
-%      }
-%    }
-%    if ( $cust_pay->unapplied > 0 ) {
-%      $desc .= '&nbsp;&nbsp;'.
-%               '<B><FONT COLOR="#FF0000">$'.
-%               $cust_pay->unapplied. ' unapplied</FONT></B>';
-%      if ( $curuser->access_right('Apply payment') ) {
-%        $desc = ' ('. include( '/elements/popup_link.html',
-%                                 'label'      => 'apply',
-%                                 'action'     => "${p}edit/cust_bill_pay.cgi?".
-%                                                 $cust_pay->paynum,
-%                                 'actionlabel' => 'Apply payment',
-%                                 'width'      => 392,
-%                                 #default# 'height' => 336,
-%                            ).
-%                ')';
-%      }
-%      $desc .= '<BR>';
-%    }
-%  }
-%
-%  my $view =
-%    ' ('. include('/elements/popup_link.html',
-%                    'label'     => 'view receipt',
-%                    'action'    => "${p}view/cust_pay.html?link=popup;paynum=".
-%                                    $cust_pay->paynum,
-%                    'actionlabel' => 'Payment Receipt',
-%                 ).
-%     ')';
-%
-%  my $refund = '';
-%  my $refund_days = $conf->config('card_refund-days') || 120;
-%  if (    $cust_pay->closed !~ /^Y/i
-%       && $cust_pay->payby =~ /^(CARD|CHEK)$/
-%       && time-$cust_pay->_date < $refund_days*86400
-%       && $cust_pay->unrefunded > 0
-%       && $curuser->access_right('Refund payment')
-%  ) {
-%    $refund = qq! (<A HREF="${p}edit/cust_refund.cgi?payby=$1;!.
-%              qq!paynum=!. $cust_pay->paynum. '"'.
-%              qq! TITLE="Send a refund for this payment to the payment gateway"!.
-%              qq!>refund</A>)!;
-%  }
-%
-%  my $void = '';
-%  if (    $cust_pay->closed !~ /^Y/i
-%       && (    ( $cust_pay->payby eq 'CARD'
-%                 && $curuser->access_right('Credit card void')
-%               )
-%            || ( $cust_pay->payby eq 'CHEK'
-%                 && $curuser->access_right('Echeck void')
-%               )
-%            || ( $cust_pay->payby !~ /^(CARD|CHEK)$/
-%                 && $curuser->access_right('Regular void')
-%               )
-%          )
-%     )
-%  {
-%    $void = qq! (<A HREF="javascript:areyousure('!.
-%            qq!${p}misc/void-cust_pay.cgi?!. $cust_pay->paynum.
-%            qq!', 'Are you sure you want to void this payment?')"!.
-%            qq! TITLE="Void this payment from the database!.
-%              ( $cust_pay->payby =~ /^(CARD|CHEK)$/
-%                ? ' (do not send anything to the payment gateway)'
-%                : '' 
-%              ). '"'.
-%            qq!>void</A>)!;
-%  }
-%
-%  my $delete = '';
-%  if ( $cust_pay->closed !~ /^Y/i
-%       && $conf->exists('deletepayments')
-%       && $curuser->access_right('Delete payment')
-%     )
-%  {
-%    $delete = qq! (<A HREF="javascript:areyousure('!.
-%              qq!${p}misc/delete-cust_pay.cgi?!. $cust_pay->paynum.
-%              qq!', 'Are you sure you want to delete this payment?')"!.
-%              qq! TITLE="Delete this payment from the database completely - not recommended"!.
-%              qq!>delete</A>)!;
-%  }
-%
-%  my $unapply = '';
-%  if (    $cust_pay->closed !~ /^Y/i
-%       && scalar(@cust_bill_pay)           
-%       && $curuser->access_right('Unapply payment')
-%     )
-%  {
-%    $unapply = qq! (<A HREF="javascript:areyousure('!.
-%               qq!${p}misc/unapply-cust_pay.cgi?!. $cust_pay->paynum.
-%               qq!', 'Are you sure you want to unapply this payment?')"!.
-%               qq! TITLE="Keep this payment, but dissociate it from the invoices it is currently applied against"!.
-%               qq!>unapply</A>)!;
-%  }
-%
-%  my $otaker = $cust_pay->otaker;
-%  $otaker = '<i>auto billing</i>'          if $otaker eq 'fs_daily';
-%  $otaker = '<i>customer self-service</i>' if $otaker eq 'fs_selfservice';
-%
-%  push @history, {
-%    'date'    => $cust_pay->_date,
-%    'desc'    => $pre. "Payment$post by $otaker $info$desc".
-%                 "$view$apply$refund$void$delete$unapply",
-%    'payment' => $cust_pay->paid,
-%    'target'  => $target,
-%  };
-%}
-%
-%#voided payments
-%foreach my $cust_pay_void ($cust_main->cust_pay_void) {
-%
-%  my $payby = $cust_pay_void->payby;
-%  my $payinfo = $payby eq 'CARD'
-%                  ? $cust_pay_void->paymask
-%                  : $cust_pay_void->payinfo;
-%
-%  $payby =~ s/^BILL$/Check #/ if $payinfo;
-%  $payby =~ s/^CHEK$/Electronic check /;
-%  $payby =~ s/^BILL$//;
-%  $payby =~ s/^(CARD|COMP)$/$1 /;
-%  my $info = $payby ? " ($payby$payinfo)" : '';
-%
-%  my $unvoid = '';
-%  if ( $cust_pay_void->closed !~ /^Y/i
-%       && $curuser->access_right('Unvoid')
-%     )
-%  {
-%    $unvoid = qq! (<A HREF="javascript:areyousure('!.
-%              qq!${p}misc/unvoid-cust_pay_void.cgi?!. $cust_pay_void->paynum.
-%              qq!', 'Are you sure you want to unvoid this payment?')"!.
-%              qq! TITLE="Unvoid this payment from the database!.
-%                ( $cust_pay_void->payby =~ /^(CARD|CHEK)$/
-%                  ? ' (do not send anything to the payment gateway)'
-%                  : '' 
-%                ). '"'.
-%              qq!>unvoid</A>)!;
-%  }
-%
-%  push @history, {
-%    'date'   => $cust_pay_void->_date,
-%    'desc'   => "<DEL>Payment $info</DEL> <I>voided ".
-%                time2str("%D", $cust_pay_void->void_date).
-%                " by ". $cust_pay_void->otaker. '</i>'. $unvoid,
-%    'void_payment' => $cust_pay_void->paid,
-%  };
-%
-%}
-%
-%#credits (some false laziness w/payments)
-%foreach my $cust_credit ($cust_main->cust_credit) {
-%
-%  my @cust_credit_bill = $cust_credit->cust_credit_bill;
-%  my @cust_credit_refund = $cust_credit->cust_credit_refund;
-%
-%  my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
-%  if (    scalar(@cust_credit_bill)   == 0
-%       && scalar(@cust_credit_refund) == 0 ) {
-%    #completely unapplied
-%    $pre = '<B><FONT COLOR="#FF0000">Unapplied ';
-%    $post = '</FONT></B>';
-%    if ( $curuser->access_right('Apply credit') ) {
-%      $apply = ' ('. include( '/elements/popup_link.html',
-%                                'label'    => 'apply',
-%                                'action'   => "${p}edit/cust_credit_bill.cgi?".
-%                                              $cust_credit->crednum,
-%                                'actionlabel' => 'Apply credit',
-%                                'width'    => 392,
-%                                #default# 'height' => 336,
-%                            ).
-%                ')';
-%    }
-%  } elsif (    scalar(@cust_credit_bill)   == 1
-%            && scalar(@cust_credit_refund) == 0
-%            && $cust_credit->credited == 0      ) {
-%    #applied to one invoice, the usual situation
-%    $desc = ' '. $cust_credit_bill[0]->applied_to_invoice;
-%  } elsif (    scalar(@cust_credit_bill)   == 0
-%            && scalar(@cust_credit_refund) == 1
-%            && $cust_credit->credited == 0      ) {
-%    #applied to one refund
-%    $desc = ' refunded on '.  time2str("%D", $cust_credit_refund[0]->_date);
-%  } else {
-%    #complicated
-%    $desc = '<BR>';
-%    foreach my $app ( sort { $a->_date <=> $b->_date }
-%                           ( @cust_credit_bill, @cust_credit_refund ) ) {
-%      if ( $app->isa('FS::cust_credit_bill') ) {
-%        $desc .= '&nbsp;&nbsp;'.
-%                 '$'. $app->amount.
-%                 ' '. $app->applied_to_invoice.
-%                 '<BR>';
-%                 #' on '. time2str("%D", $app->_date).
-%      } elsif ( $app->isa('FS::cust_credit_refund') ) {
-%        $desc .= '&nbsp;&nbsp;'.
-%                 '$'. $app->amount.
-%                 ' refunded on '. time2str("%D", $app->_date).
-%                 '<BR>';
-%      } else {
-%        die "$app is not a FS::cust_credit_bill or a FS::cust_credit_refund";
-%      }
-%    }
-%    if ( $cust_credit->credited > 0 ) {
-%      $desc .= '&nbsp;&nbsp;<B><FONT COLOR="#FF0000">$'.
-%               $cust_credit->credited. ' unapplied</FONT></B>';
-%      if ( $curuser->access_right('Apply credit') ) {
-%        $desc = ' ('. include( '/elements/popup_link.html',
-%                                'label'       => 'apply',
-%                                'action'      => "${p}edit/cust_credit_bill.cgi?".
-%                                                 $cust_credit->crednum,
-%                                'actionlabel' => 'Apply credit',
-%                                'width'       => 392,
-%                                #default# 'height' => 336,
-%                            ).
-%                ')';
-%      }
-%      $desc .= '<BR>';
-%    }
-%  }
-%#
-%  my $delete = '';
-%  if ( $cust_credit->closed !~ /^Y/i
-%
-%       #s'pose deleting a credit isn't bad like deleting a payment
-%       # and this needs to be generally available until we have credit voiding..
-%       #&& $conf->exists('deletecredits')
-%
-%       && $curuser->access_right('Delete credit')
-%     )
-%  {
-%    $delete = qq! (<A HREF="javascript:areyousure('!.
-%              qq!${p}misc/delete-cust_credit.cgi?!. $cust_credit->crednum.
-%              qq!', 'Are you sure you want to delete this credit?')">!.
-%              qq!delete</A>)!;
-%  }
-%  
-%  my $unapply = '';
-%  if (    $cust_credit->closed !~ /^Y/i
-%       && scalar(@cust_credit_bill)
-%       && $curuser->access_right('Unapply credit')
-%     )
-%  {
-%    $unapply = qq! (<A HREF="javascript:areyousure('!.
-%               qq!${p}misc/unapply-cust_credit.cgi?!. $cust_credit->crednum.
-%               qq!', 'Are you sure you want to unapply this credit?')">!.
-%               qq!unapply</A>)!;
-%  }
-%  
-%  push @history, {
-%    'date'   => $cust_credit->_date,
-%    'desc'   => $pre. "Credit$post by ". $cust_credit->otaker.
-%                ( $cust_credit->reason
-%                  ? ' ('. $cust_credit->reason. ')'
-%                  : ''
-%              ).
-%                "$desc$apply$delete$unapply",
-%    'credit' => $cust_credit->amount,
-%  };
-%
-%}
-%
-%#refunds
-%foreach my $cust_refund ($cust_main->cust_refund) {
-%
-%  my $payby = $cust_refund->payby;
-%  my $payinfo = $payby eq 'CARD'
-%                  ? $cust_refund->paymask
-%                  : $cust_refund->payinfo;
-%
-%  $payby =~ s/^BILL$/Check #/ if $payinfo;
-%  $payby =~ s/^CHEK$/Electronic check /;
-%  $payby =~ s/^(CARD|COMP)$/$1 /;
-%
-%  my $delete = '';
-%  if ( $cust_refund->closed !~ /^Y/i
-%       && $conf->exists('deleterefunds')
-%       && $curuser->access_right('Delete refund')
-%     )
-%  {
-%    $delete = qq! (<A HREF="javascript:areyousure('!.
-%              qq!${p}misc/delete-cust_refund.cgi?!. $cust_refund->refundnum.
-%              qq!', 'Are you sure you want to delete this refund?')"!.
-%              qq! TITLE="Delete this refund from the database completely - not recommended"!.
-%              qq!>delete</A>)!;
-%  }
-%
-%  push @history, {
-%    'date'   => $cust_refund->_date,
-%    'desc'   => "Refund ($payby$payinfo) by ". $cust_refund->otaker. "<BR>".
-%                $delete,
-%    'refund' => $cust_refund->refund,
-%  };
-%
-%}
-%
-%
-
 
 <% include("/elements/table-grid.html") %>
 % my $bgcolor1 = '#eeeeee';
@@ -681,4 +279,56 @@ my %status = (
   'All'        => '',
 );
 
+#get payment history
+my @history = ();
+
+#invoices
+foreach my $cust_bill ($cust_main->cust_bill) {
+  push @history, {
+    'date'   => $cust_bill->_date,
+    'desc'   => include('payment_history/invoice.html', $cust_bill),
+    'charge' => $cust_bill->charged,
+  };
+}
+
+#payments (some false laziness w/credits)
+foreach my $cust_pay ($cust_main->cust_pay) {
+  push @history, {
+    'date'    => $cust_pay->_date,
+    'desc'    => include('payment_history/payment.html', $cust_pay),
+    'payment' => $cust_pay->paid,
+    #'target'  => $target, #XXX
+  };
+}
+
+#voided payments
+foreach my $cust_pay_void ($cust_main->cust_pay_void) {
+  push @history, {
+    'date'   => $cust_pay_void->_date,
+    'desc'   => include('payment_history/voided_payment.html', $cust_pay_void),
+    'void_payment' => $cust_pay_void->paid,
+  };
+
+}
+
+#credits (some false laziness w/payments)
+foreach my $cust_credit ($cust_main->cust_credit) {
+  push @history, {
+    'date'   => $cust_credit->_date,
+    'desc'   => include('payment_history/credit.html', $cust_credit),
+    'credit' => $cust_credit->amount,
+  };
+
+}
+
+#refunds
+foreach my $cust_refund ($cust_main->cust_refund) {
+  push @history, {
+    'date'   => $cust_refund->_date,
+    'desc'   => include('payment_history/refund.html', $cust_refund),
+    'refund' => $cust_refund->refund,
+  };
+
+}
+
 </%init>
diff --git a/httemplate/view/cust_main/payment_history/credit.html b/httemplate/view/cust_main/payment_history/credit.html
new file mode 100644 (file)
index 0000000..bf76945
--- /dev/null
@@ -0,0 +1,110 @@
+<% $pre %>Credit<% $post %>
+by <% $cust_credit->otaker %><% "$reason$desc$apply$delete$unapply" %>
+<%init>
+
+my( $cust_credit, %opt ) = @_;
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+my @cust_credit_bill = $cust_credit->cust_credit_bill;
+my @cust_credit_refund = $cust_credit->cust_credit_refund;
+
+my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
+if (    scalar(@cust_credit_bill)   == 0
+     && scalar(@cust_credit_refund) == 0 ) {
+  #completely unapplied
+  $pre = '<B><FONT COLOR="#FF0000">Unapplied ';
+  $post = '</FONT></B>';
+  if ( $curuser->access_right('Apply credit') ) {
+    $apply = ' ('. include( '/elements/popup_link.html',
+                              'label'    => 'apply',
+                              'action'   => "${p}edit/cust_credit_bill.cgi?".
+                                            $cust_credit->crednum,
+                              'actionlabel' => 'Apply credit',
+                              'width'    => 392,
+                              #default# 'height' => 336,
+                          ).
+              ')';
+  }
+} elsif (    scalar(@cust_credit_bill)   == 1
+          && scalar(@cust_credit_refund) == 0
+          && $cust_credit->credited == 0      ) {
+  #applied to one invoice, the usual situation
+  $desc = ' '. $cust_credit_bill[0]->applied_to_invoice;
+} elsif (    scalar(@cust_credit_bill)   == 0
+          && scalar(@cust_credit_refund) == 1
+          && $cust_credit->credited == 0      ) {
+  #applied to one refund
+  $desc = ' refunded on '.  time2str("%D", $cust_credit_refund[0]->_date);
+} else {
+  #complicated
+  $desc = '<BR>';
+  foreach my $app ( sort { $a->_date <=> $b->_date }
+                         ( @cust_credit_bill, @cust_credit_refund ) ) {
+    if ( $app->isa('FS::cust_credit_bill') ) {
+      $desc .= '&nbsp;&nbsp;'.
+               '$'. $app->amount.
+               ' '. $app->applied_to_invoice.
+               '<BR>';
+               #' on '. time2str("%D", $app->_date).
+    } elsif ( $app->isa('FS::cust_credit_refund') ) {
+      $desc .= '&nbsp;&nbsp;'.
+               '$'. $app->amount.
+               ' refunded on '. time2str("%D", $app->_date).
+               '<BR>';
+    } else {
+      die "$app is not a FS::cust_credit_bill or a FS::cust_credit_refund";
+    }
+  }
+  if ( $cust_credit->credited > 0 ) {
+    $desc .= '&nbsp;&nbsp;<B><FONT COLOR="#FF0000">$'.
+             $cust_credit->credited. ' unapplied</FONT></B>';
+    if ( $curuser->access_right('Apply credit') ) {
+      $desc = ' ('. include( '/elements/popup_link.html',
+                              'label'       => 'apply',
+                              'action'      => "${p}edit/cust_credit_bill.cgi?".
+                                               $cust_credit->crednum,
+                              'actionlabel' => 'Apply credit',
+                              'width'       => 392,
+                              #default# 'height' => 336,
+                          ).
+              ')';
+    }
+    $desc .= '<BR>';
+  }
+}
+#
+my $delete = '';
+if ( $cust_credit->closed !~ /^Y/i
+
+     #s'pose deleting a credit isn't bad like deleting a payment
+     # and this needs to be generally available until we have credit voiding..
+     #&& $conf->exists('deletecredits')
+
+     && $curuser->access_right('Delete credit')
+   )
+{
+  $delete = qq! (<A HREF="javascript:areyousure('!.
+            qq!${p}misc/delete-cust_credit.cgi?!. $cust_credit->crednum.
+            qq!', 'Are you sure you want to delete this credit?')">!.
+            qq!delete</A>)!;
+}
+
+my $unapply = '';
+if (    $cust_credit->closed !~ /^Y/i
+     && scalar(@cust_credit_bill)
+     && $curuser->access_right('Unapply credit')
+   )
+{
+  $unapply = qq! (<A HREF="javascript:areyousure('!.
+             qq!${p}misc/unapply-cust_credit.cgi?!. $cust_credit->crednum.
+             qq!', 'Are you sure you want to unapply this credit?')">!.
+             qq!unapply</A>)!;
+}
+
+my $reason = $cust_credit->reason
+               ? ' ('. $cust_credit->reason. ')'
+               : '';
+
+</%init>
+
diff --git a/httemplate/view/cust_main/payment_history/invoice.html b/httemplate/view/cust_main/payment_history/invoice.html
new file mode 100644 (file)
index 0000000..39c6739
--- /dev/null
@@ -0,0 +1,34 @@
+<% $link %><% $pre %>Invoice #<% $invnum %>
+(Balance $ <% $cust_bill->owed %>)<% $post %><% $link ? '</A>' : '' %><% $events %>
+<%init>
+
+my( $cust_bill, %opt ) = @_;
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+my($pre, $post) = ('', '');
+if ( $cust_bill->owed > 0 ) {
+  $pre = '<B><FONT SIZE="+1" COLOR="#FF0000">Open ';
+  $post = '</FONT></B>';
+}
+
+my $invnum = $cust_bill->invnum;
+
+my $link = $curuser->access_right('View invoices')
+             ? qq!<A HREF="${p}view/cust_bill.cgi?$invnum">!
+             : '';
+
+my $events = '';
+#1.9
+if ( $cust_bill->num_cust_event
+     && (    $curuser->access_right('Billing event reports')
+          || $curuser->access_right('View customer billing events')
+        )
+   ) {
+  $events =
+    qq!<BR><FONT SIZE="-1"><A HREF="${p}search/cust_event.html?invnum=!.
+    $cust_bill->invnum. '">(&nbsp;View invoice events&nbsp;)</A></FONT>';
+}
+#
+
+</%init>
diff --git a/httemplate/view/cust_main/payment_history/payment.html b/httemplate/view/cust_main/payment_history/payment.html
new file mode 100644 (file)
index 0000000..96fca7f
--- /dev/null
@@ -0,0 +1,180 @@
+<% $pre %>Payment<% $post %> by <% $otaker %>
+<% "$info$desc$view$apply$refund$void$delete$unapply" %>
+<%init>
+
+my( $cust_pay, %opt ) = @_;
+
+my $conf = new FS::Conf;
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+my $payby = $cust_pay->payby;
+
+my $payinfo;
+if ( $payby eq 'CARD' ) {
+  $payinfo = $cust_pay->paymask;
+} elsif ( $payby eq 'CHEK' ) {
+  my( $account, $aba ) = split('@', $cust_pay->paymask );
+  $payinfo = "ABA $aba, Acct #$account";
+} else {
+  $payinfo = $cust_pay->payinfo;
+}
+my @cust_bill_pay = $cust_pay->cust_bill_pay;
+my @cust_pay_refund = $cust_pay->cust_pay_refund;
+
+my $target = "$payby$payinfo";
+$payby =~ s/^BILL$/Check #/ if $payinfo;
+$payby =~ s/^CHEK$/Electronic check /;
+$payby =~ s/^PREP$/Prepaid card /;
+$payby =~ s/^CARD$/Credit card #/; 
+$payby =~ s/^COMP$/Complimentary by /; 
+$payby =~ s/^CASH$/Cash/;
+$payby =~ s/^WEST$/Western Union/;
+$payby =~ s/^MCRD$/Manual credit card/;
+$payby =~ s/^BILL$//;
+my $info = $payby ? "($payby$payinfo)" : '';
+
+my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
+if (    scalar(@cust_bill_pay)   == 0
+     && scalar(@cust_pay_refund) == 0 ) {
+  #completely unapplied
+  $pre = '<B><FONT COLOR="#FF0000">Unapplied ';
+  $post = '</FONT></B>';
+  if ( $curuser->access_right('Apply payment') ) {
+    $apply = ' ('. include( '/elements/popup_link.html',
+                              'label'       => 'apply',
+                              'action'      => "${p}edit/cust_bill_pay.cgi?".
+                                               $cust_pay->paynum,
+                              'actionlabel' => 'Apply payment',
+                              'width'       => 392,
+                              #default# 'height' => 336,
+                          ).
+              ')';
+  }
+} elsif (    scalar(@cust_bill_pay)   == 1
+          && scalar(@cust_pay_refund) == 0
+          && $cust_pay->unapplied == 0     ) {
+  #applied to one invoice, the usual situation
+  $desc = ' '. $cust_bill_pay[0]->applied_to_invoice;
+} elsif (    scalar(@cust_bill_pay)   == 0
+          && scalar(@cust_pay_refund) == 1
+          && $cust_pay->unapplied == 0     ) {
+  #applied to one refund
+  $desc = ' refunded on '. time2str("%D", $cust_pay_refund[0]->_date);
+} else {
+  #complicated
+  $desc = '<BR>';
+  foreach my $app ( sort { $a->_date <=> $b->_date }
+                         ( @cust_bill_pay, @cust_pay_refund ) ) {
+    if ( $app->isa('FS::cust_bill_pay') ) {
+      $desc .= '&nbsp;&nbsp;'.
+               '$'. $app->amount.
+               ' '. $app->applied_to_invoice.
+               '<BR>';
+               #' on '. time2str("%D", $cust_bill_pay->_date).
+    } elsif ( $app->isa('FS::cust_pay_refund') ) {
+      $desc .= '&nbsp;&nbsp;'.
+               '$'. $app->amount.
+               ' refunded on '. time2str("%D", $app->_date).
+               '<BR>';
+    } else {
+      die "$app is not a FS::cust_bill_pay or FS::cust_pay_refund";
+    }
+  }
+  if ( $cust_pay->unapplied > 0 ) {
+    $desc .= '&nbsp;&nbsp;'.
+             '<B><FONT COLOR="#FF0000">$'.
+             $cust_pay->unapplied. ' unapplied</FONT></B>';
+    if ( $curuser->access_right('Apply payment') ) {
+      $desc = ' ('. include( '/elements/popup_link.html',
+                               'label'      => 'apply',
+                               'action'     => "${p}edit/cust_bill_pay.cgi?".
+                                               $cust_pay->paynum,
+                               'actionlabel' => 'Apply payment',
+                               'width'      => 392,
+                               #default# 'height' => 336,
+                          ).
+              ')';
+    }
+    $desc .= '<BR>';
+  }
+}
+
+my $view =
+  ' ('. include('/elements/popup_link.html',
+                  'label'     => 'view receipt',
+                  'action'    => "${p}view/cust_pay.html?link=popup;paynum=".
+                                  $cust_pay->paynum,
+                  'actionlabel' => 'Payment Receipt',
+               ).
+   ')';
+
+my $refund = '';
+my $refund_days = $conf->config('card_refund-days') || 120;
+if (    $cust_pay->closed !~ /^Y/i
+     && $cust_pay->payby =~ /^(CARD|CHEK)$/
+     && time-$cust_pay->_date < $refund_days*86400
+     && $cust_pay->unrefunded > 0
+     && $curuser->access_right('Refund payment')
+) {
+  $refund = qq! (<A HREF="${p}edit/cust_refund.cgi?payby=$1;!.
+            qq!paynum=!. $cust_pay->paynum. '"'.
+            qq! TITLE="Send a refund for this payment to the payment gateway"!.
+            qq!>refund</A>)!;
+}
+
+my $void = '';
+if (    $cust_pay->closed !~ /^Y/i
+     && (    ( $cust_pay->payby eq 'CARD'
+               && $curuser->access_right('Credit card void')
+             )
+          || ( $cust_pay->payby eq 'CHEK'
+               && $curuser->access_right('Echeck void')
+             )
+          || ( $cust_pay->payby !~ /^(CARD|CHEK)$/
+               && $curuser->access_right('Regular void')
+             )
+        )
+   )
+{
+  $void = qq! (<A HREF="javascript:areyousure('!.
+          qq!${p}misc/void-cust_pay.cgi?!. $cust_pay->paynum.
+          qq!', 'Are you sure you want to void this payment?')"!.
+          qq! TITLE="Void this payment from the database!.
+            ( $cust_pay->payby =~ /^(CARD|CHEK)$/
+              ? ' (do not send anything to the payment gateway)'
+              : '' 
+            ). '"'.
+          qq!>void</A>)!;
+}
+
+my $delete = '';
+if ( $cust_pay->closed !~ /^Y/i
+     && $conf->exists('deletepayments')
+     && $curuser->access_right('Delete payment')
+   )
+{
+  $delete = qq! (<A HREF="javascript:areyousure('!.
+            qq!${p}misc/delete-cust_pay.cgi?!. $cust_pay->paynum.
+            qq!', 'Are you sure you want to delete this payment?')"!.
+            qq! TITLE="Delete this payment from the database completely - not recommended"!.
+            qq!>delete</A>)!;
+}
+
+my $unapply = '';
+if (    $cust_pay->closed !~ /^Y/i
+     && scalar(@cust_bill_pay)           
+     && $curuser->access_right('Unapply payment')
+   )
+{
+  $unapply = qq! (<A HREF="javascript:areyousure('!.
+             qq!${p}misc/unapply-cust_pay.cgi?!. $cust_pay->paynum.
+             qq!', 'Are you sure you want to unapply this payment?')"!.
+             qq! TITLE="Keep this payment, but dissociate it from the invoices it is currently applied against"!.
+             qq!>unapply</A>)!;
+}
+
+my $otaker = $cust_pay->otaker;
+$otaker = '<i>auto billing</i>'          if $otaker eq 'fs_daily';
+$otaker = '<i>customer self-service</i>' if $otaker eq 'fs_selfservice';
+
+</%init>
diff --git a/httemplate/view/cust_main/payment_history/refund.html b/httemplate/view/cust_main/payment_history/refund.html
new file mode 100644 (file)
index 0000000..5f9bca3
--- /dev/null
@@ -0,0 +1,50 @@
+<% $pre %>Refund<% $post %>
+(<% $payby. $payinfo %>)
+by <% $cust_refund->otaker %><% $view %><% $delete %>
+<%init>
+
+my( $cust_refund, %opt ) = @_;
+
+my $conf = new FS::Conf;
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+my $payby = $cust_refund->payby;
+my $payinfo = $payby eq 'CARD'
+                ? $cust_refund->paymask
+                : $cust_refund->payinfo;
+
+$payby =~ s/^BILL$/Check #/ if $payinfo;
+$payby =~ s/^CHEK$/Electronic check /;
+$payby =~ s/^(CARD|COMP)$/$1 /;
+
+my($pre, $post) = ('', '');
+if ( $cust_refund->unapplied > 0 ) {
+  $pre = '<B><FONT COLOR="#FF0000">Unapplied ';
+  $post = '</FONT></B>';
+}
+
+my $view =
+  ' ('. include('/elements/popup_link.html',
+                  'label'     => 'view receipt',
+                  'action'    => "${p}view/cust_refund.html?link=popup;".
+                                 'refundnum='. $cust_refund->refundnum,
+                  'actionlabel' => 'Payment Receipt',
+               ).
+   ')';
+
+
+my $delete = '';
+if ( $cust_refund->closed !~ /^Y/i
+     && $conf->exists('deleterefunds')
+     && $curuser->access_right('Delete refund')
+   )
+{
+  $delete = qq! (<A HREF="javascript:areyousure('!.
+            qq!${p}misc/delete-cust_refund.cgi?!. $cust_refund->refundnum.
+            qq!', 'Are you sure you want to delete this refund?')"!.
+            qq! TITLE="Delete this refund from the database completely - not recommended"!.
+            qq!>delete</A>)!;
+}
+
+</%init>
+
diff --git a/httemplate/view/cust_main/payment_history/voided_payment.html b/httemplate/view/cust_main/payment_history/voided_payment.html
new file mode 100644 (file)
index 0000000..9cbc47b
--- /dev/null
@@ -0,0 +1,37 @@
+<DEL>Payment <% $info %></DEL>
+<I>voided <% time2str("%D", $cust_pay_void->void_date) %>
+by <% $cust_pay_void->otaker %></I><% $unvoid %>
+<%init>
+
+my( $cust_pay_void, %opt ) = @_;
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+my $payby = $cust_pay_void->payby;
+my $payinfo = $payby eq 'CARD'
+                ? $cust_pay_void->paymask
+                : $cust_pay_void->payinfo;
+
+$payby =~ s/^BILL$/Check #/ if $payinfo;
+$payby =~ s/^CHEK$/Electronic check /;
+$payby =~ s/^BILL$//;
+$payby =~ s/^(CARD|COMP)$/$1 /;
+my $info = $payby ? " ($payby$payinfo)" : '';
+
+my $unvoid = '';
+if ( $cust_pay_void->closed !~ /^Y/i
+     && $curuser->access_right('Unvoid')
+   )
+{
+  $unvoid = qq! (<A HREF="javascript:areyousure('!.
+            qq!${p}misc/unvoid-cust_pay_void.cgi?!. $cust_pay_void->paynum.
+            qq!', 'Are you sure you want to unvoid this payment?')"!.
+            qq! TITLE="Unvoid this payment from the database!.
+              ( $cust_pay_void->payby =~ /^(CARD|CHEK)$/
+                ? ' (do not send anything to the payment gateway)'
+                : '' 
+              ). '"'.
+            qq!>unvoid</A>)!;
+}
+
+</%init>
diff --git a/httemplate/view/cust_refund.html b/httemplate/view/cust_refund.html
new file mode 100644 (file)
index 0000000..40f6ab6
--- /dev/null
@@ -0,0 +1,141 @@
+% if ( $link eq 'popup' ) { 
+
+  <% include('/elements/header-popup.html', "Refund Receipt" ) %>
+
+  <CENTER><A HREF="javascript:self.parent.location = '<% $pr_link %>'">Print</A></CENTER><BR>
+
+% } elsif ( $link eq 'print' ) { 
+
+  <% include('/elements/header-popup.html', "Refund Receipt" ) %>
+  
+% #it would be nice if the menubar could be hidden for print, but better to
+% # have it available than not, otherwise the user winds up at a dead end
+  <% menubar(
+       "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+     )
+  %>
+  <BR><BR>
+
+% } else { 
+
+  <% include('/elements/header.html', "Refund Receipt", menubar(
+       "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum",
+       'Print receipt' => $pr_link,
+     ))
+  %>
+
+% }
+
+% unless ($link eq 'popup' ) {
+  <% include('/elements/small_custview.html',
+               $custnum,
+               scalar($conf->config('countrydefault')),
+               1, #no balance
+            )
+  %>
+  <BR><BR>
+% } 
+
+<% ntable("#cccccc", 2) %>
+
+<TR>
+  <TD ALIGN="right">Refund#</TD>
+  <TD BGCOLOR="#FFFFFF"><B><% $cust_refund->refundnum %></B></TD>
+</TR>
+
+<TR>
+  <TD ALIGN="right">Date</TD>
+  <TD BGCOLOR="#FFFFFF"><B><% time2str"%a&nbsp;%b&nbsp;%o,&nbsp;%Y&nbsp;%r", $cust_refund->_date %></B></TD>
+</TR>
+
+<TR>
+  <TD ALIGN="right">Amount</TD>
+  <TD BGCOLOR="#FFFFFF"><B><% $money_char. $cust_refund->refund %></B></TD>
+</TR>
+
+<TR>
+  <TD ALIGN="right">Reason</TD>
+  <TD BGCOLOR="#FFFFFF"><B><% $cust_refund->reason %></B></TD>
+</TR>
+
+<TR>
+  <TD ALIGN="right">Refund method</TD>
+  <TD BGCOLOR="#FFFFFF"><B><% $cust_refund->payby_name %> #<% $cust_refund->paymask %></B></TD>
+</TR>
+
+% if ( $cust_refund->payby =~ /^(CARD|CHEK|LECB)$/ && $cust_refund->paybatch ) { 
+
+    <TR>
+      <TD ALIGN="right">Processor</TD>
+      <TD BGCOLOR="#FFFFFF"><B><% $cust_refund->processor %></B></TD>
+    </TR>
+
+    <TR>
+      <TD ALIGN="right">Authorization#</TD>
+      <TD BGCOLOR="#FFFFFF"><B><% $cust_refund->authorization %></B></TD>
+    </TR>
+
+%   if ( $cust_refund->order_number ) {
+      <TR>
+        <TD ALIGN="right">Order#</TD>
+        <TD BGCOLOR="#FFFFFF"><B><% $cust_refund->order_number %></B></TD>
+      </TR>
+%   }
+
+% }
+
+</TABLE>
+
+% if ( $link eq 'print' ) {
+
+  <SCRIPT TYPE="text/javascript">
+    window.print();
+  </SCRIPT>
+
+% }
+
+% if ( $link =~ /^(popup|print)$/ ) { 
+    </BODY>
+  </HTML>
+% } else {
+  <% include('/elements/footer.html') %>
+% }
+
+<%init>
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+die "access denied"
+  unless $curuser->access_right('View invoices') #remove this in 1.9 EVENTUALLY
+      || $curuser->access_right('View customer payments');
+      #'View customer refunds' ???
+
+
+$cgi->param('refundnum') =~ /^(\d+)$/ or die "no refundnum";
+my $refundnum = $1;
+
+my $link = '';
+if ( $cgi->param('link') =~ /^(\w+)$/ ) {
+  $link = $1;
+}
+
+my $cust_refund = qsearchs({
+  'select'    => 'cust_refund.*',
+  'table'     => 'cust_refund',
+  'addl_from' => 'LEFT JOIN cust_main USING ( custnum )',
+  'hashref'   => { 'refundnum' => $refundnum },
+  'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql,
+});
+die "Refund #$refundnum not found!" unless $cust_refund;
+
+my $pr_link = "${p}view/cust_refund.html?link=print;refundnum=$refundnum";
+
+my $custnum = $cust_refund->custnum;
+
+my $conf = new FS::Conf;
+
+my $money_char = $conf->config('money_char') || '$';
+
+tie my %payby, 'Tie::IxHash', FS::payby->payby2longname;
+
+</%init>