+ @errors;
+
+}
+
+=item cust_bill_pay
+
+Returns all applications to invoices (see L<FS::cust_bill_pay>) for this
+payment.
+
+=cut
+
+sub cust_bill_pay {
+ my $self = shift;
+ sort { $a->_date <=> $b->_date
+ || $a->invnum <=> $b->invnum }
+ qsearch( 'cust_bill_pay', { 'paynum' => $self->paynum } )
+ ;
+}
+
+=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>) and refund
+applications (see L<FS::cust_pay_refund>).
+
+=cut
+
+sub unapplied {
+ my $self = shift;
+ my $amount = $self->paid;
+ $amount -= $_->amount foreach ( $self->cust_bill_pay );
+ $amount -= $_->amount foreach ( $self->cust_pay_refund );
+ sprintf("%.2f", $amount );
+}
+
+=item unrefunded
+
+Returns the amount of this payment that has not been refuned; which is
+paid minus all refund applications (see L<FS::cust_pay_refund>).
+
+=cut
+
+sub unrefunded {
+ my $self = shift;
+ my $amount = $self->paid;
+ $amount -= $_->amount foreach ( $self->cust_pay_refund );
+ 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;
+ 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,
+ };