summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Wells <mark@freeside.biz>2015-03-19 13:43:34 -0700
committerMark Wells <mark@freeside.biz>2015-03-19 13:43:34 -0700
commite18263db61c9695eb4c139f23c79730fd7659ad6 (patch)
tree04947f96c8709dbce3e136622c6c36223f3bd194
parent5886bd773a3c1fe43abcde0beafb7fb5e1991388 (diff)
correctly void invoices with fees, #32862
-rw-r--r--FS/FS/Schema.pm59
-rw-r--r--FS/FS/TemplateItem_Mixin.pm24
-rw-r--r--FS/FS/cust_bill_pkg.pm23
-rw-r--r--FS/FS/cust_bill_pkg_fee_void.pm85
-rw-r--r--FS/FS/cust_bill_pkg_void.pm8
-rw-r--r--FS/t/cust_bill_pkg_fee_void.t5
-rwxr-xr-xhttemplate/view/cust_bill.cgi56
7 files changed, 199 insertions, 61 deletions
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 378a521..a048d3e 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -947,9 +947,9 @@ sub tables_hashref {
{ columns => [ 'eventnum' ],
table => 'cust_event',
},
- { columns => [ 'billpkgnum' ],
- table => 'cust_bill_pkg',
- },
+ #{ columns => [ 'billpkgnum' ],
+ # table => 'cust_bill_pkg',
+ #},
{ columns => [ 'feepart' ],
table => 'part_fee',
},
@@ -1078,17 +1078,31 @@ sub tables_hashref {
{ columns => [ 'billpkgnum' ],
table => 'cust_bill_pkg',
},
- { columns => [ 'base_billpkgnum' ],
- table => 'cust_bill_pkg',
- references => [ 'billpkgnum' ],
- },
- { columns => [ 'base_invnum' ],
- table => 'cust_bill',
- references => [ 'invnum' ],
+ ],
+ },
+
+ 'cust_bill_pkg_fee_void' => {
+ 'columns' => [
+ 'billpkgfeenum', 'serial', '', '', '', '',
+ 'billpkgnum', 'int', '', '', '', '',
+ 'base_invnum', 'int', '', '', '', '',
+ 'base_billpkgnum', 'int', 'NULL', '', '', '',
+ 'amount', @money_type, '', '',
+ ],
+ 'primary_key' => 'billpkgfeenum',
+ 'unique' => [],
+ 'index' => [ ['billpkgnum'],
+ ['base_invnum'],
+ ['base_billpkgnum'],
+ ],
+ 'foreign_keys' => [
+ { columns => [ 'billpkgnum' ],
+ table => 'cust_bill_pkg_void',
},
],
},
+
'cust_bill_pkg_tax_location' => {
'columns' => [
'billpkgtaxlocationnum', 'serial', '', '', '', '',
@@ -1119,10 +1133,10 @@ sub tables_hashref {
{ columns => [ 'locationnum' ],
table => 'cust_location',
},
- { columns => [ 'taxable_billpkgnum' ],
- table => 'cust_bill_pkg',
- references => [ 'billpkgnum' ],
- },
+ #{ columns => [ 'taxable_billpkgnum' ],
+ # table => 'cust_bill_pkg',
+ # references => [ 'billpkgnum' ],
+ #},
],
},
@@ -1150,10 +1164,10 @@ sub tables_hashref {
{ columns => [ 'taxratelocationnum' ],
table => 'tax_rate_location',
},
- { columns => [ 'taxable_billpkgnum' ],
- table => 'cust_bill_pkg',
- references => [ 'billpkgnum' ],
- },
+ #{ columns => [ 'taxable_billpkgnum' ],
+ # table => 'cust_bill_pkg',
+ # references => [ 'billpkgnum' ],
+ #},
],
},
@@ -1177,6 +1191,7 @@ sub tables_hashref {
'unitsetup', @money_typen, '', '',
'unitrecur', @money_typen, '', '',
'hidden', 'char', 'NULL', 1, '', '',
+ 'feepart', 'int', 'NULL', '', '', '',
#void fields
'void_date', @date_type, '', '',
'reason', 'varchar', 'NULL', $char_d, '', '',
@@ -1286,10 +1301,10 @@ sub tables_hashref {
{ columns => [ 'locationnum' ],
table => 'cust_location',
},
- { columns => [ 'taxable_billpkgnum' ],
- table => 'cust_bill_pkg_void',
- references => [ 'billpkgnum' ],
- },
+ #{ columns => [ 'taxable_billpkgnum' ],
+ # table => 'cust_bill_pkg_void',
+ # references => [ 'billpkgnum' ],
+ #},
],
},
diff --git a/FS/FS/TemplateItem_Mixin.pm b/FS/FS/TemplateItem_Mixin.pm
index 27b8f1b..dcd7ab3 100644
--- a/FS/FS/TemplateItem_Mixin.pm
+++ b/FS/FS/TemplateItem_Mixin.pm
@@ -45,7 +45,31 @@ sub part_pkg {
$part_pkg = $cust_pkg->part_pkg if $cust_pkg;
$part_pkg;
}
+}
+
+=item part_fee
+Returns the fee definition for this line item, if there is one.
+
+=cut
+
+sub part_fee {
+ my $self = shift;
+ $self->feepart
+ ? FS::part_fee->by_key($self->feepart)
+ : '';
+}
+
+=item part_X
+
+Returns L</part_pkg> or L</part_fee>, whichever is applicable (or nothing,
+if called on a tax line item).
+
+=cut
+
+sub part_X {
+ my $self = shift;
+ $self->part_pkg || $self->part_fee;
}
=item desc LOCALE
diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm
index 9b9cf92..7257a9b 100644
--- a/FS/FS/cust_bill_pkg.pm
+++ b/FS/FS/cust_bill_pkg.pm
@@ -25,6 +25,7 @@ use FS::cust_bill_pkg_discount_void;
use FS::cust_bill_pkg_tax_location_void;
use FS::cust_bill_pkg_tax_rate_location_void;
use FS::cust_tax_exempt_pkg_void;
+use FS::cust_bill_pkg_fee_void;
use FS::Cursor;
@@ -358,6 +359,7 @@ sub void {
cust_bill_pkg_tax_location
cust_bill_pkg_tax_rate_location
cust_tax_exempt_pkg
+ cust_bill_pkg_fee
)) {
foreach my $linked ( qsearch($table, { billpkgnum=>$self->billpkgnum }) ) {
@@ -417,6 +419,7 @@ sub delete {
cust_tax_exempt_pkg
cust_bill_pay_pkg
cust_credit_bill_pkg
+ cust_bill_pkg_fee
)) {
foreach my $linked ( qsearch($table, { billpkgnum=>$self->billpkgnum }) ) {
@@ -1026,26 +1029,6 @@ sub tax_location {
}
}
-=item part_X
-
-Returns the L<FS::part_pkg> or L<FS::part_fee> object that defines this
-charge. If called on a tax line, returns nothing.
-
-=cut
-
-sub part_X {
- my $self = shift;
- if ( $self->pkgpart_override ) {
- return FS::part_pkg->by_key($self->pkgpart_override);
- } elsif ( $self->pkgnum ) {
- return $self->cust_pkg->part_pkg;
- } elsif ( $self->feepart ) {
- return $self->part_fee;
- } else {
- return;
- }
-}
-
=back
=head1 CLASS METHODS
diff --git a/FS/FS/cust_bill_pkg_fee_void.pm b/FS/FS/cust_bill_pkg_fee_void.pm
new file mode 100644
index 0000000..51f5a3f
--- /dev/null
+++ b/FS/FS/cust_bill_pkg_fee_void.pm
@@ -0,0 +1,85 @@
+package FS::cust_bill_pkg_fee_void;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::cust_bill_pkg_fee - Object methods for cust_bill_pkg_fee_void records
+
+=head1 SYNOPSIS
+
+ use FS::cust_bill_pkg_fee;
+
+ $record = new FS::cust_bill_pkg_fee \%hash;
+ $record = new FS::cust_bill_pkg_fee { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_bill_pkg_fee_void object records the origin of a fee that
+appears on a voided invoice. FS::cust_bill_pkg_fee_void inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item billpkgfeenum - primary key
+
+=item billpkgnum - the billpkgnum of the fee line item
+
+=item base_invnum - the invoice number (L<FS::cust_bill>) that caused (this
+portion of) the fee to be charged.
+
+=item base_billpkgnum - the invoice line item (L<FS::cust_bill_pkg>) that
+caused (this portion of) the fee to be charged. May be null.
+
+=item amount - the fee amount
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=cut
+
+sub table { 'cust_bill_pkg_fee_void'; }
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is an error,
+returns the error, otherwise returns false. Called by the insert and replace
+methods.
+
+=cut
+
+sub check { my $self = shift;
+
+ my $error = $self->ut_numbern('billpkgfeenum')
+ || $self->ut_number('billpkgnum')
+ || $self->ut_foreign_key('base_invnum', 'cust_bill', 'invnum')
+ || $self->ut_foreign_keyn('base_billpkgnum', 'cust_bill_pkg', 'billpkgnum')
+ || $self->ut_money('amount')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check; }
+
+=back
+
+=head1 SEE ALSO
+
+L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/FS/FS/cust_bill_pkg_void.pm b/FS/FS/cust_bill_pkg_void.pm
index 8949ba7..080452e 100644
--- a/FS/FS/cust_bill_pkg_void.pm
+++ b/FS/FS/cust_bill_pkg_void.pm
@@ -8,6 +8,7 @@ use FS::cust_bill_pkg_detail;
use FS::cust_bill_pkg_display;
use FS::cust_bill_pkg_discount;
use FS::cust_bill_pkg;
+use FS::cust_bill_pkg_fee;
use FS::cust_bill_pkg_tax_location;
use FS::cust_bill_pkg_tax_rate_location;
use FS::cust_tax_exempt_pkg;
@@ -170,6 +171,7 @@ sub unvoid {
cust_bill_pkg_tax_location
cust_bill_pkg_tax_rate_location
cust_tax_exempt_pkg
+ cust_bill_pkg_fee
)) {
foreach my $voided (
@@ -239,6 +241,7 @@ sub check {
|| $self->ut_moneyn('unitsetup')
|| $self->ut_moneyn('unitrecur')
|| $self->ut_enum('hidden', [ '', 'Y' ])
+ || $self->ut_numbern('feepart')
;
return $error if $error;
@@ -258,6 +261,11 @@ sub cust_bill {
qsearchs( 'cust_bill_void', { 'invnum' => $self->invnum } );
}
+sub cust_bill_pkg_fee {
+ my $self = shift;
+ qsearch( 'cust_bill_pkg_fee_void', { 'billpkgnum' => $self->billpkgnum } );
+}
+
=back
=head1 BUGS
diff --git a/FS/t/cust_bill_pkg_fee_void.t b/FS/t/cust_bill_pkg_fee_void.t
new file mode 100644
index 0000000..a2a51dc
--- /dev/null
+++ b/FS/t/cust_bill_pkg_fee_void.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_bill_pkg_fee_void;
+$loaded=1;
+print "ok 1\n";
diff --git a/httemplate/view/cust_bill.cgi b/httemplate/view/cust_bill.cgi
index 6bc499a..f1bcf4d 100755
--- a/httemplate/view/cust_bill.cgi
+++ b/httemplate/view/cust_bill.cgi
@@ -2,26 +2,37 @@
emt("View this customer (#[_1])",$display_custnum) => "${p}view/cust_main.cgi?$custnum",
) &>
-% if ( $conf->exists('deleteinvoices')
-% && $curuser->access_right('Delete invoices' )
-% )
-% {
-
- <SCRIPT TYPE="text/javascript">
- function areyousure(href, message) {
- if (confirm(message) == true)
- window.location.href = href;
- }
- </SCRIPT>
-
- <A HREF = "javascript:areyousure(
- '<%$p%>misc/delete-cust_bill.html?<% $invnum %>',
- '<% mt('Are you sure you want to delete this invoice?') |h %>'
- )"
- TITLE = "<% mt('Delete this invoice from the database completely') |h %>"
- ><% mt('Delete this invoice') |h %></A>
- <BR><BR>
+<SCRIPT TYPE="text/javascript">
+function areyousure(href, message) {
+ if (confirm(message) == true)
+ window.location.href = href;
+}
+</SCRIPT>
+% if ( !$cust_bill->closed ) { # otherwise allow no changes
+% my $can_delete = $conf->exists('deleteinvoices')
+% && $curuser->access_right('Delete invoices');
+% my $can_void = $curuser->access_right('Void invoices');
+% if ( $can_void ) {
+ <& /elements/popup_link.html,
+ 'label' => emt('Void this invoice'),
+ 'actionlabel' => emt('Void this invoice'),
+ 'action' => $p.'misc/void-cust_bill.html?invnum='.$invnum,
+ &>
+% }
+% if ( $can_void and $can_delete ) {
+ &nbsp;|&nbsp;
+% }
+% if ( $can_delete ) {
+ <A href="" onclick="areyousure(\
+ '<%$p%>misc/delete-cust_bill.html?<% $invnum %>',\
+ <% mt('Are you sure you want to delete this invoice?') |js_string %>)"\
+ TITLE = "<% mt('Delete this invoice from the database completely') |h %>">\
+ <% emt('Delete this invoice') |h %></A>
+% }
+% if ( $can_void or $can_delete ) {
+ <BR><BR>
+% }
% }
% if ( $cust_bill->owed > 0
@@ -185,6 +196,13 @@ my $cust_bill = qsearchs({
'hashref' => { 'invnum' => $invnum },
'extra_sql' => ' AND '. $curuser->agentnums_sql,
});
+# if we're asked for a voided invnum, redirect appropriately
+if (!$cust_bill and FS::cust_bill_void->row_exists("invnum = $invnum") ) {
+ $m->clear_buffer;
+ my $url = $p.'view/cust_bill_void.html?'.$cgi->query_string;
+ $m->print( $cgi->redirect($url) );
+ $m->abort;
+}
die "Invoice #$invnum not found!" unless $cust_bill;
$cust_bill->set('mode' => $mode);