summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FS/FS/Conf.pm7
-rw-r--r--FS/FS/Schema.pm6
-rw-r--r--FS/FS/cust_bill.pm104
-rw-r--r--FS/FS/cust_bill_ApplicationCommon.pm4
-rw-r--r--FS/FS/cust_bill_pay.pm2
-rw-r--r--FS/FS/cust_credit.pm6
-rw-r--r--FS/FS/cust_credit_bill.pm2
-rw-r--r--FS/FS/cust_main.pm179
-rw-r--r--FS/FS/cust_pay.pm50
-rw-r--r--FS/FS/cust_pay_pending.pm6
-rw-r--r--FS/FS/cust_pay_void.pm38
-rw-r--r--FS/FS/cust_pkg.pm57
-rwxr-xr-xhttemplate/edit/cust_credit.cgi13
-rwxr-xr-xhttemplate/edit/cust_pay.cgi14
-rwxr-xr-xhttemplate/edit/process/cust_pay.cgi4
-rw-r--r--httemplate/elements/select-cust_pkg-balances.html30
-rw-r--r--httemplate/elements/tr-select-cust_pkg-balances.html31
-rwxr-xr-xhttemplate/view/cust_bill.cgi1
-rwxr-xr-xhttemplate/view/cust_main/packages.html3
-rw-r--r--httemplate/view/cust_main/packages/status.html43
-rw-r--r--httemplate/view/cust_main/payment_history.html13
-rw-r--r--httemplate/view/cust_main/payment_history/credit.html14
-rw-r--r--httemplate/view/cust_main/payment_history/payment.html14
-rw-r--r--httemplate/view/cust_main/payment_history/voided_payment.html5
-rw-r--r--httemplate/view/cust_pay.html9
25 files changed, 586 insertions, 69 deletions
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index 40fbaf6..c335c01 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -3009,6 +3009,13 @@ worry that config_items is freeside-specific and icky.
'type' => 'checkbox',
},
+ {
+ 'key' => 'pkg-balances',
+ 'section' => 'billing',
+ 'description' => 'Enable experimental package balances. Not recommended for general use.',
+ 'type' => 'checkbox',
+ },
+
{ key => "apacheroot", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
{ key => "apachemachine", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
{ key => "apachemachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 649e0aa..15adba3 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -598,6 +598,7 @@ sub tables_hashref {
'reasonnum', 'int', 'NULL', '', '', '',
'addlinfo', 'text', 'NULL', '', '', '',
'closed', 'char', 'NULL', 1, '', '',
+ 'pkgnum', 'int', 'NULL', '', '', '', #desired pkgnum for pkg-balances
],
'primary_key' => 'crednum',
'unique' => [],
@@ -611,6 +612,7 @@ sub tables_hashref {
'invnum', 'int', '', '', '', '',
'_date', @date_type, '', '',
'amount', @money_type, '', '',
+ 'pkgnum', 'int', 'NULL', '', '', '', #desired pkgnum for pkg-balances
],
'primary_key' => 'creditbillnum',
'unique' => [],
@@ -941,6 +943,7 @@ sub tables_hashref {
#'paybatch', 'varchar', 'NULL', $char_d, '', '', #for auditing purposes.
'payunique', 'varchar', 'NULL', $char_d, '', '', #separate paybatch "unique" functions from current usage
+ 'pkgnum', 'int', 'NULL', '', '', '', #desired pkgnum for pkg-balances
'status', 'varchar', '', $char_d, '', '',
'session_id', 'varchar', 'NULL', $char_d, '', '', #only need 32
'statustext', 'text', 'NULL', '', '', '',
@@ -970,6 +973,7 @@ sub tables_hashref {
'paybatch', 'varchar', 'NULL', $char_d, '', '', #for auditing purposes.
'payunique', 'varchar', 'NULL', $char_d, '', '', #separate paybatch "unique" functions from current usage
'closed', 'char', 'NULL', 1, '', '',
+ 'pkgnum', 'int', 'NULL', '', '', '', #desired pkgnum for pkg-balances
],
'primary_key' => 'paynum',
#i guess not now, with cust_pay_pending, if we actually make it here, we _do_ want to record it# 'unique' => [ [ 'payunique' ] ],
@@ -989,6 +993,7 @@ sub tables_hashref {
'paymask', 'varchar', 'NULL', $char_d, '', '',
'paybatch', 'varchar', 'NULL', $char_d, '', '', #for auditing purposes.
'closed', 'char', 'NULL', 1, '', '',
+ 'pkgnum', 'int', 'NULL', '', '', '', #desired pkgnum for pkg-balances
'void_date', @date_type, '', '',
'reason', 'varchar', 'NULL', $char_d, '', '',
'otaker', 'varchar', '', 32, '', '',
@@ -1005,6 +1010,7 @@ sub tables_hashref {
'paynum', 'int', '', '', '', '',
'amount', @money_type, '', '',
'_date', @date_type, '', '',
+ 'pkgnum', 'int', 'NULL', '', '', '', #desired pkgnum for pkg-balances
],
'primary_key' => 'billpaynum',
'unique' => [],
diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm
index 4e28af3..4acdd85 100644
--- a/FS/FS/cust_bill.pm
+++ b/FS/FS/cust_bill.pm
@@ -235,6 +235,25 @@ sub cust_bill_pkg {
);
}
+=item cust_bill_pkg_pkgnum PKGNUM
+
+Returns the line items (see L<FS::cust_bill_pkg>) for this invoice and
+specified pkgnum.
+
+=cut
+
+sub cust_bill_pkg_pkgnum {
+ my( $self, $pkgnum ) = @_;
+ qsearch(
+ { 'table' => 'cust_bill_pkg',
+ 'hashref' => { 'invnum' => $self->invnum,
+ 'pkgnum' => $pkgnum,
+ },
+ 'order_by' => 'ORDER BY billpkgnum',
+ }
+ );
+}
+
=item cust_pkg
Returns the packages (see L<FS::cust_pkg>) corresponding to the line items for
@@ -432,6 +451,38 @@ sub cust_credited {
;
}
+=item cust_bill_pay_pkgnum
+
+Returns all payment applications (see L<FS::cust_bill_pay>) for this invoice
+with matching pkgnum.
+
+=cut
+
+sub cust_bill_pay_pkgnum {
+ my( $self, $pkgnum ) = @_;
+ sort { $a->_date <=> $b->_date }
+ qsearch( 'cust_bill_pay', { 'invnum' => $self->invnum,
+ 'pkgnum' => $pkgnum,
+ }
+ );
+}
+
+=item cust_credited_pkgnum
+
+Returns all applied credits (see L<FS::cust_credit_bill>) for this invoice
+with matching pkgnum.
+
+=cut
+
+sub cust_credited_pkgnum {
+ my( $self, $pkgnum ) = @_;
+ sort { $a->_date <=> $b->_date }
+ qsearch( 'cust_credit_bill', { 'invnum' => $self->invnum,
+ 'pkgnum' => $pkgnum,
+ }
+ );
+}
+
=item tax
Returns the tax amount (see L<FS::cust_bill_pkg>) for this invoice.
@@ -465,6 +516,21 @@ sub owed {
$balance;
}
+sub owed_pkgnum {
+ my( $self, $pkgnum ) = @_;
+
+ #my $balance = $self->charged;
+ my $balance = 0;
+ $balance += $_->setup + $_->recur for $self->cust_bill_pkg_pkgnum($pkgnum);
+
+ $balance -= $_->amount for $self->cust_bill_pay_pkgnum($pkgnum);
+ $balance -= $_->amount for $self->cust_credited_pkgnum($pkgnum);
+
+ $balance = sprintf( "%.2f", $balance);
+ $balance =~ s/^\-0\.00$/0.00/; #yay ieee fp
+ $balance;
+}
+
=item apply_payments_and_credits
=cut
@@ -488,6 +554,13 @@ sub apply_payments_and_credits {
my @payments = grep { $_->unapplied > 0 } $self->cust_main->cust_pay;
my @credits = grep { $_->credited > 0 } $self->cust_main->cust_credit;
+ if ( $conf->exists('pkg-balances') ) {
+ # limit @payments & @credits to those w/ a pkgnum grepped from $self
+ my %pkgnums = map { $_ => 1 } map $_->pkgnum, $self->cust_bill_pkg;
+ @payments = grep { ! $_->pkgnum || $pkgnums{$_->pkgnum} } @payments;
+ @credits = grep { ! $_->pkgnum || $pkgnums{$_->pkgnum} } @credits;
+ }
+
while ( $self->owed > 0 and ( @payments || @credits ) ) {
my $app = '';
@@ -525,28 +598,39 @@ sub apply_payments_and_credits {
die "guru meditation #12 and 35";
}
+ my $unapp_amount;
if ( $app eq 'pay' ) {
my $payment = shift @payments;
-
- $app = new FS::cust_bill_pay {
- 'paynum' => $payment->paynum,
- 'amount' => sprintf('%.2f', min( $payment->unapplied, $self->owed ) ),
- };
+ $unapp_amount = $payment->unapplied;
+ $app = new FS::cust_bill_pay { 'paynum' => $payment->paynum };
+ $app->pkgnum( $payment->pkgnum )
+ if $conf->exists('pkg-balances') && $payment->pkgnum;
} elsif ( $app eq 'credit' ) {
my $credit = shift @credits;
-
- $app = new FS::cust_credit_bill {
- 'crednum' => $credit->crednum,
- 'amount' => sprintf('%.2f', min( $credit->credited, $self->owed ) ),
- };
+ $unapp_amount = $credit->credited;
+ $app = new FS::cust_credit_bill { 'crednum' => $credit->crednum };
+ $app->pkgnum( $credit->pkgnum )
+ if $conf->exists('pkg-balances') && $credit->pkgnum;
} else {
die "guru meditation #12 and 35";
}
+ my $owed;
+ if ( $conf->exists('pkg-balances') && $app->pkgnum ) {
+ warn "owed_pkgnum ". $app->pkgnum;
+ $owed = $self->owed_pkgnum($app->pkgnum);
+ } else {
+ $owed = $self->owed;
+ }
+ next unless $owed > 0;
+
+ warn "min ( $unapp_amount, $owed )\n";
+ $app->amount( sprintf('%.2f', min( $unapp_amount, $owed ) ) );
+
$app->invnum( $self->invnum );
my $error = $app->insert;
diff --git a/FS/FS/cust_bill_ApplicationCommon.pm b/FS/FS/cust_bill_ApplicationCommon.pm
index af7e087..ec694ca 100644
--- a/FS/FS/cust_bill_ApplicationCommon.pm
+++ b/FS/FS/cust_bill_ApplicationCommon.pm
@@ -115,6 +115,8 @@ sub apply_to_lineitems {
my @apply = ();
+ my $conf = new FS::Conf;
+
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
local $SIG{QUIT} = 'IGNORE';
@@ -127,6 +129,8 @@ sub apply_to_lineitems {
my $dbh = dbh;
my @open = $self->cust_bill->open_cust_bill_pkg; #FOR UPDATE...?
+ @open = grep { $_->pkgnum == $self->pkgnum } @open
+ if $conf->exists('pkg-balances') && $self->pkgnum;
warn "$me ". scalar(@open). " open line items for invoice ".
$self->cust_bill->invnum. ": ". join(', ', @open). "\n"
if $DEBUG;
diff --git a/FS/FS/cust_bill_pay.pm b/FS/FS/cust_bill_pay.pm
index b7ba2b7..e1b02ae 100644
--- a/FS/FS/cust_bill_pay.pm
+++ b/FS/FS/cust_bill_pay.pm
@@ -7,6 +7,7 @@ use FS::cust_main_Mixin;
use FS::cust_bill_ApplicationCommon;
use FS::cust_bill;
use FS::cust_pay;
+use FS::cust_pkg;
@ISA = qw( FS::cust_main_Mixin FS::cust_bill_ApplicationCommon );
@@ -121,6 +122,7 @@ sub check {
|| $self->ut_foreign_key('invnum', 'cust_bill', 'invnum' )
|| $self->ut_numbern('_date')
|| $self->ut_money('amount')
+ || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum')
;
return $error if $error;
diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm
index 47a8119..6c3effa 100644
--- a/FS/FS/cust_credit.pm
+++ b/FS/FS/cust_credit.pm
@@ -8,6 +8,7 @@ use FS::Misc qw(send_email);
use FS::Record qw( qsearch qsearchs dbdef );
use FS::cust_main_Mixin;
use FS::cust_main;
+use FS::cust_pkg;
use FS::cust_refund;
use FS::cust_credit_bill;
use FS::part_pkg;
@@ -95,6 +96,10 @@ Text
Books closed flag, empty or `Y'
+=item pkgnum
+
+Desired pkgnum when using experimental package balances.
+
=back
=head1 METHODS
@@ -295,6 +300,7 @@ sub check {
|| $self->ut_foreign_key('reasonnum', 'reason', 'reasonnum')
|| $self->ut_textn('addlinfo')
|| $self->ut_enum('closed', [ '', 'Y' ])
+ || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum')
;
return $error if $error;
diff --git a/FS/FS/cust_credit_bill.pm b/FS/FS/cust_credit_bill.pm
index 375c885..900a5c0 100644
--- a/FS/FS/cust_credit_bill.pm
+++ b/FS/FS/cust_credit_bill.pm
@@ -8,6 +8,7 @@ use FS::cust_main_Mixin;
use FS::cust_bill_ApplicationCommon;
use FS::cust_bill;
use FS::cust_credit;
+use FS::cust_pkg;
@ISA = qw( FS::cust_main_Mixin FS::cust_bill_ApplicationCommon );
@@ -122,6 +123,7 @@ sub check {
|| $self->ut_foreign_key('invnum', 'cust_bill', 'invnum' )
|| $self->ut_numbern('_date')
|| $self->ut_money('amount')
+ || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum')
;
return $error if $error;
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index f6ac186..9c13174 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -6110,32 +6110,52 @@ sub apply_credits {
@invoices = sort { $b->_date <=> $a->_date } @invoices
if defined($opt{'order'}) && $opt{'order'} eq 'newest';
+ if ( $conf->exists('pkg-balances') ) {
+ # limit @credits to those w/ a pkgnum grepped from $self
+ my %pkgnums = ();
+ foreach my $i (@invoices) {
+ foreach my $li ( $i->cust_bill_pkg ) {
+ $pkgnums{$li->pkgnum} = 1;
+ }
+ }
+ @credits = grep { ! $_->pkgnum || $pkgnums{$_->pkgnum} } @credits;
+ }
+
my $credit;
+
foreach my $cust_bill ( @invoices ) {
- my $amount;
if ( !defined($credit) || $credit->credited == 0) {
$credit = pop @credits or last;
}
- if ($cust_bill->owed >= $credit->credited) {
- $amount=$credit->credited;
- }else{
- $amount=$cust_bill->owed;
+ my $owed;
+ if ( $conf->exists('pkg-balances') && $credit->pkgnum ) {
+ $owed = $cust_bill->owed_pkgnum($credit->pkgnum);
+ } else {
+ $owed = $cust_bill->owed;
+ }
+ unless ( $owed > 0 ) {
+ push @credits, $credit;
+ next;
}
+
+ my $amount = min( $credit->credited, $owed );
my $cust_credit_bill = new FS::cust_credit_bill ( {
'crednum' => $credit->crednum,
'invnum' => $cust_bill->invnum,
'amount' => $amount,
} );
+ $cust_credit_bill->pkgnum( $credit->pkgnum )
+ if $conf->exists('pkg-balances') && $credit->pkgnum;
my $error = $cust_credit_bill->insert;
if ( $error ) {
$dbh->rollback or die $dbh->errstr if $oldAutoCommit;
die $error;
}
- redo if ($cust_bill->owed > 0);
+ redo if ($cust_bill->owed > 0) && ! $conf->exists('pkg-balances');
}
@@ -6183,33 +6203,52 @@ sub apply_payments {
grep { $_->owed > 0 }
$self->cust_bill;
+ if ( $conf->exists('pkg-balances') ) {
+ # limit @payments to those w/ a pkgnum grepped from $self
+ my %pkgnums = ();
+ foreach my $i (@invoices) {
+ foreach my $li ( $i->cust_bill_pkg ) {
+ $pkgnums{$li->pkgnum} = 1;
+ }
+ }
+ @payments = grep { ! $_->pkgnum || $pkgnums{$_->pkgnum} } @payments;
+ }
+
my $payment;
foreach my $cust_bill ( @invoices ) {
- my $amount;
if ( !defined($payment) || $payment->unapplied == 0 ) {
$payment = pop @payments or last;
}
- if ( $cust_bill->owed >= $payment->unapplied ) {
- $amount = $payment->unapplied;
+ my $owed;
+ if ( $conf->exists('pkg-balances') && $payment->pkgnum ) {
+ $owed = $cust_bill->owed_pkgnum($payment->pkgnum);
} else {
- $amount = $cust_bill->owed;
+ $owed = $cust_bill->owed;
}
+ unless ( $owed > 0 ) {
+ push @payments, $payment;
+ next;
+ }
+
+ my $amount = min( $payment->unapplied, $owed );
my $cust_bill_pay = new FS::cust_bill_pay ( {
'paynum' => $payment->paynum,
'invnum' => $cust_bill->invnum,
'amount' => $amount,
} );
+ $cust_bill_pay->pkgnum( $payment->pkgnum )
+ if $conf->exists('pkg-balances') && $payment->pkgnum;
my $error = $cust_bill_pay->insert;
if ( $error ) {
$dbh->rollback or die $dbh->errstr if $oldAutoCommit;
die $error;
}
- redo if ( $cust_bill->owed > 0);
+ redo if ( $cust_bill->owed > 0) && ! $conf->exists('pkg-balances');
}
@@ -6270,6 +6309,41 @@ sub total_owed_date {
}
+=item total_owed_pkgnum PKGNUM
+
+Returns the total owed on all invoices for this customer's specific package
+when using experimental package balances (see L<FS::cust_bill/owed_pkgnum>).
+
+=cut
+
+sub total_owed_pkgnum {
+ my( $self, $pkgnum ) = @_;
+ $self->total_owed_date_pkgnum(2145859200, $pkgnum); #12/31/2037
+}
+
+=item total_owed_date_pkgnum TIME PKGNUM
+
+Returns the total owed for this customer's specific package when using
+experimental package balances on all invoices with date earlier than
+TIME. TIME is specified as a UNIX timestamp; see L<perlfunc/"time">). Also
+see L<Time::Local> and L<Date::Parse> for conversion functions.
+
+=cut
+
+sub total_owed_date_pkgnum {
+ my( $self, $time, $pkgnum ) = @_;
+
+ my $total_bill = 0;
+ foreach my $cust_bill (
+ grep { $_->_date <= $time }
+ qsearch('cust_bill', { 'custnum' => $self->custnum, } )
+ ) {
+ $total_bill += $cust_bill->owed_pkgnum($pkgnum);
+ }
+ sprintf( "%.2f", $total_bill );
+
+}
+
=item total_paid
Returns the total amount of all payments.
@@ -6306,6 +6380,21 @@ sub total_unapplied_credits {
sprintf( "%.2f", $total_credit );
}
+=item total_unapplied_credits_pkgnum PKGNUM
+
+Returns the total outstanding credit (see L<FS::cust_credit>) for this
+customer. See L<FS::cust_credit/credited>.
+
+=cut
+
+sub total_unapplied_credits_pkgnum {
+ my( $self, $pkgnum ) = @_;
+ my $total_credit = 0;
+ $total_credit += $_->credited foreach $self->cust_credit_pkgnum($pkgnum);
+ sprintf( "%.2f", $total_credit );
+}
+
+
=item total_unapplied_payments
Returns the total unapplied payments (see L<FS::cust_pay>) for this customer.
@@ -6320,6 +6409,22 @@ sub total_unapplied_payments {
sprintf( "%.2f", $total_unapplied );
}
+=item total_unapplied_payments_pkgnum PKGNUM
+
+Returns the total unapplied payments (see L<FS::cust_pay>) for this customer's
+specific package when using experimental package balances. See
+L<FS::cust_pay/unapplied>.
+
+=cut
+
+sub total_unapplied_payments_pkgnum {
+ my( $self, $pkgnum ) = @_;
+ my $total_unapplied = 0;
+ $total_unapplied += $_->unapplied foreach $self->cust_pay_pkgnum($pkgnum);
+ sprintf( "%.2f", $total_unapplied );
+}
+
+
=item total_unapplied_refunds
Returns the total unrefunded refunds (see L<FS::cust_refund>) for this
@@ -6372,6 +6477,26 @@ sub balance_date {
);
}
+=item balance_pkgnum PKGNUM
+
+Returns the balance for this customer's specific package when using
+experimental package balances (total_owed plus total_unrefunded, minus
+total_unapplied_credits minus total_unapplied_payments)
+
+=cut
+
+sub balance_pkgnum {
+ my( $self, $pkgnum ) = @_;
+
+ sprintf( "%.2f",
+ $self->total_owed_pkgnum($pkgnum)
+# n/a - refunds aren't part of pkg-balances since they don't apply to invoices
+# + $self->total_unapplied_refunds_pkgnum($pkgnum)
+ - $self->total_unapplied_credits_pkgnum($pkgnum)
+ - $self->total_unapplied_payments_pkgnum($pkgnum)
+ );
+}
+
=item in_transit_payments
Returns the total of requests for payments for this customer pending in
@@ -7001,6 +7126,22 @@ sub cust_credit {
qsearch( 'cust_credit', { 'custnum' => $self->custnum } )
}
+=item cust_credit_pkgnum
+
+Returns all the credits (see L<FS::cust_credit>) for this customer's specific
+package when using experimental package balances.
+
+=cut
+
+sub cust_credit_pkgnum {
+ my( $self, $pkgnum ) = @_;
+ sort { $a->_date <=> $b->_date }
+ qsearch( 'cust_credit', { 'custnum' => $self->custnum,
+ 'pkgnum' => $pkgnum,
+ }
+ );
+}
+
=item cust_pay
Returns all the payments (see L<FS::cust_pay>) for this customer.
@@ -7013,6 +7154,22 @@ sub cust_pay {
qsearch( 'cust_pay', { 'custnum' => $self->custnum } )
}
+=item cust_pay_pkgnum
+
+Returns all the payments (see L<FS::cust_pay>) for this customer's specific
+package when using experimental package balances.
+
+=cut
+
+sub cust_pay_pkgnum {
+ my( $self, $pkgnum ) = @_;
+ sort { $a->_date <=> $b->_date }
+ qsearch( 'cust_pay', { 'custnum' => $self->custnum,
+ 'pkgnum' => $pkgnum,
+ }
+ );
+}
+
=item cust_pay_void
Returns all voided payments (see L<FS::cust_pay_void>) for this customer.
diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm
index 4ff2919..e1e6df2 100644
--- a/FS/FS/cust_pay.pm
+++ b/FS/FS/cust_pay.pm
@@ -17,6 +17,7 @@ use FS::cust_bill;
use FS::cust_bill_pay;
use FS::cust_pay_refund;
use FS::cust_main;
+use FS::cust_pkg;
use FS::cust_pay_void;
@ISA = qw( FS::payinfo_transaction_Mixin FS::cust_main_Mixin FS::Record );
@@ -62,28 +63,54 @@ currently supported:
=over 4
-=item paynum - primary key (assigned automatically for new payments)
+=item paynum
-=item custnum - customer (see L<FS::cust_main>)
+primary key (assigned automatically for new payments)
-=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
+=item custnum
+
+customer (see L<FS::cust_main>)
+
+=item _date
+
+specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
L<Time::Local> and L<Date::Parse> for conversion functions.
-=item paid - Amount of this payment
+=item paid
+
+Amount of this payment
+
+=item otaker
+
+order taker (assigned automatically, see L<FS::UID>)
+
+=item payby
+
+Payment Type (See L<FS::payinfo_Mixin> for valid payby values)
+
+=item payinfo
+
+Payment Information (See L<FS::payinfo_Mixin> for data format)
+
+=item paymask
+
+Masked payinfo (See L<FS::payinfo_Mixin> for how this works)
+
+=item paybatch
-=item otaker - order taker (assigned automatically, see L<FS::UID>)
+text field for tracking card processing or other batch grouping
-=item payby - Payment Type (See L<FS::payinfo_Mixin> for valid payby values)
+=item payunique
-=item payinfo - Payment Information (See L<FS::payinfo_Mixin> for data format)
+Optional unique identifer to prevent duplicate transactions.
-=item paymask - Masked payinfo (See L<FS::payinfo_Mixin> for how this works)
+=item closed
-=item paybatch - text field for tracking card processing or other batch grouping
+books closed flag, empty or `Y'
-=item payunique - Optional unique identifer to prevent duplicate transactions.
+=item pkgnum
-=item closed - books closed flag, empty or `Y'
+Desired pkgnum when using experimental package balances.
=back
@@ -417,6 +444,7 @@ sub check {
|| $self->ut_textn('paybatch')
|| $self->ut_textn('payunique')
|| $self->ut_enum('closed', [ '', 'Y' ])
+ || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum')
|| $self->payinfo_check()
;
return $error if $error;
diff --git a/FS/FS/cust_pay_pending.pm b/FS/FS/cust_pay_pending.pm
index fba19ea..f48e1a8 100644
--- a/FS/FS/cust_pay_pending.pm
+++ b/FS/FS/cust_pay_pending.pm
@@ -6,6 +6,7 @@ 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::payinfo_transaction_Mixin FS::cust_main_Mixin FS::Record );
@@ -77,6 +78,10 @@ Expiration date
Unique identifer to prevent duplicate transactions.
+=item pkgnum
+
+Desired pkgnum when using experimental package balances.
+
=item status
Pending transaction status, one of the following:
@@ -193,6 +198,7 @@ sub check {
#|| $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;
diff --git a/FS/FS/cust_pay_void.pm b/FS/FS/cust_pay_void.pm
index de05f71..86fbbe5 100644
--- a/FS/FS/cust_pay_void.pm
+++ b/FS/FS/cust_pay_void.pm
@@ -9,6 +9,7 @@ use FS::cust_pay;
#use FS::cust_bill_pay;
#use FS::cust_pay_refund;
#use FS::cust_main;
+use FS::cust_pkg;
@ISA = qw( FS::Record FS::payinfo_Mixin );
@@ -40,24 +41,44 @@ are currently supported:
=over 4
-=item paynum - primary key (assigned automatically for new payments)
+=item paynum
-=item custnum - customer (see L<FS::cust_main>)
+primary key (assigned automatically for new payments)
-=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 - `CARD' (credit cards), `CHEK' (electronic check/ACH),
+=item payby
+
+`CARD' (credit cards), `CHEK' (electronic check/ACH),
`LECB' (phone bill billing), `BILL' (billing), `CASH' (cash),
`WEST' (Western Union), `MCRD' (Manual credit card), or `COMP' (free)
-=item payinfo - card number, check #, or comp issuer (4-8 lowercase alphanumerics; think username), respectively
+=item payinfo
+
+card number, check #, or comp issuer (4-8 lowercase alphanumerics; think username), respectively
+
+=item paybatch
+
+text field for tracking card processing
+
+=item closed
+
+books closed flag, empty or `Y'
-=item paybatch - text field for tracking card processing
+=item pkgnum
-=item closed - books closed flag, empty or `Y'
+Desired pkgnum when using experimental package balances.
=item void_date
@@ -156,6 +177,7 @@ sub check {
|| $self->ut_number('_date')
|| $self->ut_textn('paybatch')
|| $self->ut_enum('closed', [ '', 'Y' ])
+ || $self->ut_foreign_keyn('pkgnum', 'cust_pkg', 'pkgnum')
|| $self->ut_numbern('void_date')
|| $self->ut_textn('reason')
;
diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm
index 00a0301..4724514 100644
--- a/FS/FS/cust_pkg.pm
+++ b/FS/FS/cust_pkg.pm
@@ -1750,6 +1750,63 @@ sub statuscolor {
$statuscolor{$self->status};
}
+=item pkg_label
+
+Returns a label for this package. (Currently "pkgnum: pkg - comment" or
+"pkg-comment" depending on user preference).
+
+=cut
+
+sub pkg_label {
+ my $self = shift;
+ my $label = $self->part_pkg->pkg_comment( 'nopkgpart' => 1 );
+ $label = $self->pkgnum. ": $label"
+ if $FS::CurrentUser::CurrentUser->option('show_pkgnum');
+ $label;
+}
+
+=item pkg_label_long
+
+Returns a long label for this package, adding the primary service's label to
+pkg_label.
+
+=cut
+
+sub pkg_label_long {
+ my $self = shift;
+ my $label = $self->pkg_label;
+ my $cust_svc = $self->primary_cust_svc;
+ $label .= ' ('. ($cust_svc->label)[1]. ')' if $cust_svc;
+ $label;
+}
+
+=item primary_cust_svc
+
+Returns a primary service (as FS::cust_svc object) if one can be identified.
+
+=cut
+
+#for labeling purposes - might not 100% match up with part_pkg->svcpart's idea
+
+sub primary_cust_svc {
+ my $self = shift;
+
+ my @cust_svc = $self->cust_svc;
+
+ return '' unless @cust_svc; #no serivces - irrelevant then
+
+ return $cust_svc[0] if scalar(@cust_svc) == 1; #always return a single service
+
+ # primary service as specified in the package definition
+ # or exactly one service definition with quantity one
+ my $svcpart = $self->part_pkg->svcpart;
+ @cust_svc = grep { $_->svcpart == $svcpart } @cust_svc;
+ return $cust_svc[0] if scalar(@cust_svc) == 1;
+
+ #couldn't identify one thing..
+ return '';
+}
+
=item labels
Returns a list of lists, calling the label method for all services
diff --git a/httemplate/edit/cust_credit.cgi b/httemplate/edit/cust_credit.cgi
index c9ca31f..c6b2bcb 100755
--- a/httemplate/edit/cust_credit.cgi
+++ b/httemplate/edit/cust_credit.cgi
@@ -40,6 +40,16 @@ Credit
<TD><SELECT NAME="apply"><OPTION VALUE="yes" SELECTED>yes<OPTION>no</SELECT></TD>
</TR>
+% if ( $conf->exists('pkg-balances') ) {
+ <% include('/elements/tr-select-cust_pkg-balances.html',
+ 'custnum' => $custnum,
+ 'cgi' => $cgi
+ )
+ %>
+% } else {
+ <INPUT TYPE="hidden" NAME="pkgnum" VALUE="">
+% }
+
</TABLE>
<BR>
@@ -65,4 +75,7 @@ my $_date = time;
my $otaker = getotaker;
my $p1 = popurl(1);
+my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+ or die "unknown custnum $custnum\n";
+
</%init>
diff --git a/httemplate/edit/cust_pay.cgi b/httemplate/edit/cust_pay.cgi
index 3c28774..4dff06d 100755
--- a/httemplate/edit/cust_pay.cgi
+++ b/httemplate/edit/cust_pay.cgi
@@ -72,6 +72,16 @@ Payment
% }
</TR>
+% if ( $conf->exists('pkg-balances') ) {
+ <% include('/elements/tr-select-cust_pkg-balances.html',
+ 'custnum' => $custnum,
+ 'cgi' => $cgi
+ )
+ %>
+% } else {
+ <INPUT TYPE="hidden" NAME="pkgnum" VALUE="">
+% }
+
</TABLE>
<BR>
@@ -95,7 +105,7 @@ my $money_char = $conf->config('money_char') || '$';
die "access denied"
unless $FS::CurrentUser::CurrentUser->access_right('Post payment');
-my($link, $linknum, $paid, $payby, $payinfo, $_date);
+my($link, $linknum, $paid, $payby, $payinfo, $_date, $pkgnum);
if ( $cgi->param('error') ) {
$link = $cgi->param('link');
$linknum = $cgi->param('linknum');
@@ -131,7 +141,7 @@ if ( $link eq 'invnum' ) {
my $cust_bill = qsearchs('cust_bill', { 'invnum' => $linknum } )
or die "unknown invnum $linknum";
$custnum = $cust_bill->custnum;
-} elsif ( $link eq 'custnum' ) {
+} elsif ( $link eq 'custnum' || $link eq 'popup' ) {
$custnum = $linknum;
}
diff --git a/httemplate/edit/process/cust_pay.cgi b/httemplate/edit/process/cust_pay.cgi
index 647f6fc..f8ac8b1 100755
--- a/httemplate/edit/process/cust_pay.cgi
+++ b/httemplate/edit/process/cust_pay.cgi
@@ -46,7 +46,9 @@ my $new = new FS::cust_pay ( {
_date => $_date,
map {
$_, scalar($cgi->param($_));
- } qw(paid payby payinfo paybatch)
+ } qw( paid payby payinfo paybatch
+ pkgnum
+ )
#} fields('cust_pay')
} );
diff --git a/httemplate/elements/select-cust_pkg-balances.html b/httemplate/elements/select-cust_pkg-balances.html
new file mode 100644
index 0000000..d41bd03
--- /dev/null
+++ b/httemplate/elements/select-cust_pkg-balances.html
@@ -0,0 +1,30 @@
+<SELECT NAME="pkgnum">
+ <OPTION VALUE="">(any)
+% foreach my $cust_pkg (@cust_pkg) {
+% my $sel = ( $cgi->param('pkgnum') == $cust_pkg->pkgnum ) ? 'SELECTED' : '';
+ <OPTION <% $sel %> VALUE="<% $cust_pkg->pkgnum %>"><% $cust_pkg->pkg_label_long |h %>
+% }
+</SELECT>
+<%init>
+
+my %opt = @_;
+
+my @cust_pkg;
+if ( $opt{'cust_pkg'} ) {
+
+ @cust_pkg = @{ $opt{'cust_pkg'} };
+
+} else {
+
+ my $custnum = $opt{'custnum'};
+
+ my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+ or die "unknown custnum $custnum\n";
+
+ @cust_pkg =
+ grep { ! $_->get('cancel') || $cust_main->balance_pkgnum($_->pkgnum) }
+ $cust_main->all_pkgs;
+
+}
+
+</%init>
diff --git a/httemplate/elements/tr-select-cust_pkg-balances.html b/httemplate/elements/tr-select-cust_pkg-balances.html
new file mode 100644
index 0000000..89dc5d4
--- /dev/null
+++ b/httemplate/elements/tr-select-cust_pkg-balances.html
@@ -0,0 +1,31 @@
+% if ( scalar(@cust_pkg) == 0 ) {
+ <INPUT TYPE="hidden" NAME="pkgnum" VALUE="">
+% } elsif ( scalar(@cust_pkg) == 1 ) {
+ <INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $cust_pkg[0]->pkgnum %>">
+% } else {
+ <TR>
+ <TD ALIGN="right">For package</TD>
+ <TD COLSPAN=2>
+ <% include('select-cust_pkg-balances.html',
+ 'cust_pkg' => \@cust_pkg,
+ 'cgi' => $opt{'cgi'},
+ )
+ %>
+ </TD>
+ </TR>
+
+% }
+
+<%init>
+my %opt = @_;
+
+my $custnum = $opt{'custnum'};
+
+my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } )
+ or die "unknown custnum $custnum\n";
+
+my @cust_pkg =
+ grep { ! $_->get('cancel') || $cust_main->balance_pkgnum($_->pkgnum) }
+ $cust_main->all_pkgs;
+
+</%init>
diff --git a/httemplate/view/cust_bill.cgi b/httemplate/view/cust_bill.cgi
index 450c74e..2673e82 100755
--- a/httemplate/view/cust_bill.cgi
+++ b/httemplate/view/cust_bill.cgi
@@ -6,6 +6,7 @@
% if ( $cust_bill->owed > 0
% && scalar( grep $payby{$_}, qw(BILL CASH WEST MCRD) )
% && $FS::CurrentUser::CurrentUser->access_right('Post payment')
+% && ! $conf->exists('pkg-balances')
% )
% {
% my $s = 0;
diff --git a/httemplate/view/cust_main/packages.html b/httemplate/view/cust_main/packages.html
index 428794b..8fbefae 100755
--- a/httemplate/view/cust_main/packages.html
+++ b/httemplate/view/cust_main/packages.html
@@ -138,6 +138,9 @@ my %conf_opt = (
#for status.html
'cust_pkg-show_autosuspend' => $conf->exists('cust_pkg-show_autosuspend'),
+ #for status.html pkg-balances
+ 'pkg-balances' => $conf->exists('pkg-balances'),
+ 'money_char' => ( $conf->config('money_char') || '$' ),
#for location.html
'countrydefault' => $countrydefault,
diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html
index 6daff50..f3b2faa 100644
--- a/httemplate/view/cust_main/packages/status.html
+++ b/httemplate/view/cust_main/packages/status.html
@@ -8,15 +8,16 @@
<% pkg_status_row($cust_pkg, 'Cancelled', 'cancel', 'color'=>'FF0000', %opt ) %>
- <% pkg_status_row_colspan(
+ <% pkg_status_row_colspan( $cust_pkg,
( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
'align'=>'right', 'color'=>'ff0000', 'size'=>'-2', 'colspan'=>$colspan,
+ %opt
)
%>
% unless ( $cust_pkg->get('setup') ) {
- <% pkg_status_row_colspan('Never billed', '', 'colspan'=>$colspan, ) %>
+ <% pkg_status_row_colspan( $cust_pkg, 'Never billed', '', 'colspan'=>$colspan, %opt, ) %>
% } else {
@@ -34,14 +35,15 @@
<% pkg_status_row( $cust_pkg, 'Suspended', 'susp', 'color'=>'FF9900', %opt ) %>
- <% pkg_status_row_colspan(
+ <% pkg_status_row_colspan( $cust_pkg,
( $cpr ? $cpr->reasontext. ' by '. $cpr->otaker : '' ), '',
'align'=>'right', 'color'=>'FF9900', 'size'=>'-2', 'colspan'=>$colspan,
+ %opt,
)
%>
% unless ( $cust_pkg->get('setup') ) {
- <% pkg_status_row_colspan('Never billed', '', 'colspan'=>$colspan ) %>
+ <% pkg_status_row_colspan( $cust_pkg, 'Never billed', '', 'colspan'=>$colspan, %opt ) %>
% } else {
<% pkg_status_row($cust_pkg, 'Setup', 'setup', %opt ) %>
% }
@@ -70,7 +72,7 @@
%
% unless ( $part_pkg->freq ) {
- <% pkg_status_row_colspan('Not&nbsp;yet&nbsp;billed&nbsp;(one-time&nbsp;charge)', '', 'colspan'=>$colspan, ) %>
+ <% pkg_status_row_colspan( $cust_pkg, 'Not&nbsp;yet&nbsp;billed&nbsp;(one-time&nbsp;charge)', '', 'colspan'=>$colspan, %opt ) %>
<% pkg_status_row_if($cust_pkg, 'Start billing', 'start_date', %opt) %>
@@ -86,7 +88,7 @@
% } else {
- <% pkg_status_row_colspan("Not&nbsp;yet&nbsp;billed&nbsp;($billed_or_prepaid&nbsp;". myfreq($part_pkg). ')', '', 'colspan'=>$colspan ) %>
+ <% pkg_status_row_colspan($cust_pkg, "Not&nbsp;yet&nbsp;billed&nbsp;($billed_or_prepaid&nbsp;". myfreq($part_pkg). ')', '', 'colspan'=>$colspan, %opt ) %>
<% pkg_status_row_if($cust_pkg, 'Start billing', 'start_date', %opt) %>
@@ -96,7 +98,7 @@
%
% unless ( $part_pkg->freq ) {
- <% pkg_status_row_colspan('One-time&nbsp;charge', '', 'colspan'=>$colspan, ) %>
+ <% pkg_status_row_colspan($cust_pkg, 'One-time&nbsp;charge', '', 'colspan'=>$colspan, %opt ) %>
<% pkg_status_row($cust_pkg, 'Billed', 'setup', %opt) %>
@@ -104,18 +106,20 @@
%
% if (scalar($cust_pkg->overlimit)) {
- <% pkg_status_row_colspan(
+ <% pkg_status_row_colspan( $cust_pkg,
'Overlimit',
$billed_or_prepaid. '&nbsp;'. myfreq($part_pkg),
'color'=>'FFD000', 'colspan'=>$colspan,
+ %opt
)
%>
% } else {
- <% pkg_status_row_colspan(
+ <% pkg_status_row_colspan( $cust_pkg,
'Active',
$billed_or_prepaid. '&nbsp;'. myfreq($part_pkg),
'color'=>'00CC00', 'colspan'=>$colspan,
+ %opt
)
%>
% }
@@ -169,7 +173,6 @@
</TABLE>
</TD>
-
<%init>
my %opt = @_;
@@ -218,8 +221,15 @@ sub pkg_status_row {
$html .= qq(<FONT COLOR="#$color"><B>) if length($color);
$html .= qq($title&nbsp;);
$html .= qq(</B></FONT>) if length($color);
+
+ if ( $opt{'pkg_balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge
+ $html .= ' (Balance:&nbsp;<B>'. $opt{'money_char'}.
+ $cust_pkg->cust_main->balance_pkgnum($cust_pkg->pkgnum).
+ '</B>)';
+ }
+
$html .= qq(</TD>);
- $html .= pkg_datestr($cust_pkg, $field, %opt).'</TR>';
+ $html .= pkg_datestr($cust_pkg, $field, %opt). '</TR>';
$html;
}
@@ -253,7 +263,7 @@ sub pkg_status_row_changed {
my $part_pkg = $old->part_pkg;
my $label = 'Changed from '. $cust_pkg->change_pkgnum. ': '.
$part_pkg->pkg_comment(nopartpkg => 1);
- $html .= pkg_status_row_colspan( $label, '',
+ $html .= pkg_status_row_colspan( $cust_pkg, $label, '',
'size' => '-1',
'align' => 'right',
'colspan' => $opt{'colspan'},
@@ -264,7 +274,7 @@ sub pkg_status_row_changed {
}
sub pkg_status_row_colspan {
- my($title, $addl, %opt) = @_;
+ my($cust_pkg, $title, $addl, %opt) = @_;
my $colspan = $opt{'colspan'};
@@ -279,6 +289,13 @@ sub pkg_status_row_colspan {
$html .= qq(</B>) if $color && !$size;
$html .= qq(</FONT>) if length($color) || $size;
$html .= ",&nbsp;$addl" if length($addl);
+
+ if ( $opt{'pkg-balances'} && ! $cust_pkg->{_printed_balance}++ ) { #kludge
+ $html .= ' (Balance:&nbsp;<B>'. $opt{'money_char'}.
+ $cust_pkg->cust_main->balance_pkgnum($cust_pkg->pkgnum).
+ '</B>)';
+ }
+
$html .= qq(</TD></TR>);
$html;
diff --git a/httemplate/view/cust_main/payment_history.html b/httemplate/view/cust_main/payment_history.html
index 1711e14..8adc954 100644
--- a/httemplate/view/cust_main/payment_history.html
+++ b/httemplate/view/cust_main/payment_history.html
@@ -374,13 +374,16 @@ my %status = (
#get payment history
my @history = ();
-my %opt =
+my %opt = (
( map { $_ => scalar($conf->config($_)) }
qw( card_refund-days )
),
( map { $_ => $conf->exists($_) }
- qw( deletepayments deleterefunds )
- );
+ qw( deletepayments deleterefunds pkg-balances )
+ )
+);
+
+warn Dumper(\%opt);
#invoices
foreach my $cust_bill ($cust_main->cust_bill) {
@@ -405,7 +408,7 @@ foreach my $cust_pay ($cust_main->cust_pay) {
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),
+ 'desc' => include('payment_history/voided_payment.html', $cust_pay_void, %opt ),
'void_payment' => $cust_pay_void->paid,
};
@@ -415,7 +418,7 @@ foreach my $cust_pay_void ($cust_main->cust_pay_void) {
foreach my $cust_credit ($cust_main->cust_credit) {
push @history, {
'date' => $cust_credit->_date,
- 'desc' => include('payment_history/credit.html', $cust_credit),
+ 'desc' => include('payment_history/credit.html', $cust_credit, %opt ),
'credit' => $cust_credit->amount,
};
diff --git a/httemplate/view/cust_main/payment_history/credit.html b/httemplate/view/cust_main/payment_history/credit.html
index 2deb275..058c6f5 100644
--- a/httemplate/view/cust_main/payment_history/credit.html
+++ b/httemplate/view/cust_main/payment_history/credit.html
@@ -9,7 +9,13 @@ 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 ) = ( '', '', '', '', '' );
+my $desc = '';
+if ( $opt{'pkg-balances'} && $cust_credit->pkgnum ) {
+ my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_credit->pkgnum } );
+ $desc .= ' for '. $cust_pkg->pkg_label_long;
+}
+
+my( $pre, $post, $apply, $ext ) = ( '', '', '', '' );
if ( scalar(@cust_credit_bill) == 0
&& scalar(@cust_credit_refund) == 0 ) {
#completely unapplied
@@ -45,15 +51,15 @@ if ( scalar(@cust_credit_bill) == 0
&& scalar(@cust_credit_refund) == 0
&& $cust_credit->credited == 0 ) {
#applied to one invoice, the usual situation
- $desc = ' '. $cust_credit_bill[0]->applied_to_invoice;
+ $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);
+ $desc .= ' refunded on '. time2str("%D", $cust_credit_refund[0]->_date);
} else {
#complicated
- $desc = '<BR>';
+ $desc .= '<BR>';
foreach my $app ( sort { $a->_date <=> $b->_date }
( @cust_credit_bill, @cust_credit_refund ) ) {
if ( $app->isa('FS::cust_credit_bill') ) {
diff --git a/httemplate/view/cust_main/payment_history/payment.html b/httemplate/view/cust_main/payment_history/payment.html
index 2e24b17..a4a349b 100644
--- a/httemplate/view/cust_main/payment_history/payment.html
+++ b/httemplate/view/cust_main/payment_history/payment.html
@@ -32,7 +32,13 @@ $payby =~ s/^MCRD$/Manual credit card/;
$payby =~ s/^BILL$//;
my $info = $payby ? "($payby$payinfo)" : '';
-my( $pre, $post, $desc, $apply, $ext ) = ( '', '', '', '', '' );
+my $desc = '';
+if ( $opt{'pkg-balances'} && $cust_pay->pkgnum ) {
+ my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_pay->pkgnum } );
+ $desc .= ' for '. $cust_pkg->pkg_label_long;
+}
+
+my( $pre, $post, $apply, $ext ) = ( '', '', '', '' );
if ( scalar(@cust_bill_pay) == 0
&& scalar(@cust_pay_refund) == 0 ) {
#completely unapplied
@@ -68,15 +74,15 @@ if ( scalar(@cust_bill_pay) == 0
&& scalar(@cust_pay_refund) == 0
&& $cust_pay->unapplied == 0 ) {
#applied to one invoice, the usual situation
- $desc = ' '. $cust_bill_pay[0]->applied_to_invoice;
+ $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);
+ $desc .= ' refunded on '. time2str("%D", $cust_pay_refund[0]->_date);
} else {
#complicated
- $desc = '<BR>';
+ $desc .= '<BR>';
foreach my $app ( sort { $a->_date <=> $b->_date }
( @cust_bill_pay, @cust_pay_refund ) ) {
if ( $app->isa('FS::cust_bill_pay') ) {
diff --git a/httemplate/view/cust_main/payment_history/voided_payment.html b/httemplate/view/cust_main/payment_history/voided_payment.html
index 9cbc47b..08469db 100644
--- a/httemplate/view/cust_main/payment_history/voided_payment.html
+++ b/httemplate/view/cust_main/payment_history/voided_payment.html
@@ -18,6 +18,11 @@ $payby =~ s/^BILL$//;
$payby =~ s/^(CARD|COMP)$/$1 /;
my $info = $payby ? " ($payby$payinfo)" : '';
+if ( $opt{'pkg-balances'} && $cust_pay_void->pkgnum ) {
+ my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_pay_void->pkgnum } );
+ $info .= ' for '. $cust_pkg->pkg_label_long;
+}
+
my $unvoid = '';
if ( $cust_pay_void->closed !~ /^Y/i
&& $curuser->access_right('Unvoid')
diff --git a/httemplate/view/cust_pay.html b/httemplate/view/cust_pay.html
index a5c99ac..2f23d9e 100644
--- a/httemplate/view/cust_pay.html
+++ b/httemplate/view/cust_pay.html
@@ -93,6 +93,15 @@
% }
+% if ( $conf->exists('pkg-balances') && $cust_pay->pkgnum ) {
+% my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $cust_pay->pkgnum } );
+ <TR>
+ <TD ALIGN="right">For package</TD>
+ <TD BGCOLOR="#FFFFFF"><B><% $cust_pkg->pkg_label_long %></B></TD>
+ </TR>
+
+% }
+
</TABLE>
% if ( $link eq 'print' ) {