diff options
author | Jonathan Prykop <jonathan@freeside.biz> | 2015-02-16 13:53:20 -0600 |
---|---|---|
committer | Jonathan Prykop <jonathan@freeside.biz> | 2015-02-16 13:53:20 -0600 |
commit | 251d07aa41b6830a0a2f2a51c14fa94586d843c2 (patch) | |
tree | c53f5a96bc595b914187a4c2be0c9a3084bedb98 /FS/FS | |
parent | 4771a2fe6202aa77d8e6fda10dc2b221899f3941 (diff) |
RT#27710: Credit voiding
Diffstat (limited to 'FS/FS')
-rw-r--r-- | FS/FS/AccessRight.pm | 3 | ||||
-rw-r--r-- | FS/FS/Schema.pm | 5 | ||||
-rw-r--r-- | FS/FS/access_right.pm | 3 | ||||
-rw-r--r-- | FS/FS/cust_credit.pm | 13 | ||||
-rw-r--r-- | FS/FS/cust_credit_void.pm | 81 | ||||
-rw-r--r-- | FS/FS/reason_type.pm | 4 |
6 files changed, 103 insertions, 6 deletions
diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm index 121f83c..f395dea 100644 --- a/FS/FS/AccessRight.pm +++ b/FS/FS/AccessRight.pm @@ -221,6 +221,8 @@ tie my %rights, 'Tie::IxHash', { rightname=>'Backdate credit', desc=>'Enable credits to be posted for days other than today.' }, 'Credit line items', #NEWNEWNEW 'Apply credit', #NEWNEW + 'Void credit', #NEWER than things marked NEWNEWNEW + 'Unvoid credit', #NEWER than things marked NEWNEWNEW { rightname=>'Unapply credit', desc=>'Enable "unapplication" of unclosed credits.' }, #aka unapplycredits { rightname=>'Delete credit', desc=>'Enable deletion of unclosed credits. Be very careful! Only delete credits that were data-entry errors, not adjustments.' }, #aka. deletecredits Optionally specify one or more comma-separated email addresses to be notified when a credit is deleted. 'View refunds', @@ -233,6 +235,7 @@ tie my %rights, 'Tie::IxHash', 'Refund Echeck payment', 'Delete refund', #NEW 'Add on-the-fly credit reason', #NEW + 'Add on-the-fly void credit reason', 'Add on-the-fly refund reason', #NEW ], diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 54a4680..5333b1a 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1423,6 +1423,7 @@ sub tables_hashref { #void fields 'void_date', @date_type, '', '', 'void_reason', 'varchar', 'NULL', $char_d, '', '', + 'void_reasonnum', 'int', 'NULL', '', '', '', 'void_usernum', 'int', 'NULL', '', '', '', ], 'primary_key' => 'crednum', @@ -1458,6 +1459,10 @@ sub tables_hashref { table => 'cust_pkg', references => [ 'pkgnum' ], }, + { columns => [ 'void_reasonnum' ], + table => 'reason', + references => [ 'reasonnum' ], + }, { columns => [ 'void_usernum' ], table => 'access_user', references => [ 'usernum' ], diff --git a/FS/FS/access_right.pm b/FS/FS/access_right.pm index d5e3b8b..1ea6e49 100644 --- a/FS/FS/access_right.pm +++ b/FS/FS/access_right.pm @@ -251,6 +251,9 @@ sub _upgrade_data { # class method 'List customers' => 'List contacts', 'Backdate payment' => 'Backdate credit', 'Generate quotation' => 'Disable quotation', + 'Void credit' => 'Void credit', + 'Unvoid credit' => 'Unvoid credit', + 'Add on-the-fly void credit reason' => 'Add on-the-fly void credit reason', ); # foreach my $old_acl ( keys %onetime ) { diff --git a/FS/FS/cust_credit.pm b/FS/FS/cust_credit.pm index deebe27..76fdecb 100644 --- a/FS/FS/cust_credit.pm +++ b/FS/FS/cust_credit.pm @@ -382,13 +382,18 @@ adds a record of the voided credit to the cust_credit_void table. =cut -# yes, false laziness with cust_pay and cust_bill -# but frankly I don't have time to fix it now - sub void { my $self = shift; my $reason = shift; + unless (ref($reason) || !$reason) { + $reason = FS::reason->new_or_existing( + 'class' => 'X', + 'type' => 'Void credit', + 'reason' => $reason + ); + } + local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; local $SIG{QUIT} = 'IGNORE'; @@ -403,7 +408,7 @@ sub void { my $cust_credit_void = new FS::cust_credit_void ( { map { $_ => $self->get($_) } $self->fields } ); - $cust_credit_void->set('void_reason', $reason); + $cust_credit_void->set('void_reasonnum', $reason->reasonnum); my $error = $cust_credit_void->insert; if ( $error ) { $dbh->rollback if $oldAutoCommit; diff --git a/FS/FS/cust_credit_void.pm b/FS/FS/cust_credit_void.pm index f76f794..9c92068 100644 --- a/FS/FS/cust_credit_void.pm +++ b/FS/FS/cust_credit_void.pm @@ -1,11 +1,12 @@ package FS::cust_credit_void; -use base qw( FS::otaker_Mixin FS::cust_main_Mixin FS::Record ); +use base qw( FS::otaker_Mixin FS::cust_main_Mixin FS::reason_Mixin FS::Record ); use strict; use FS::Record qw(qsearchs); # qsearch qsearchs); use FS::CurrentUser; use FS::access_user; use FS::cust_credit; +use FS::UID qw( dbh ); =head1 NAME @@ -85,6 +86,7 @@ sub check { || $self->ut_numbern('void_date') || $self->ut_textn('void_reason') || $self->ut_foreign_keyn('void_usernum', 'access_user', 'usernum') + || $self->ut_foreign_keyn('void_reasonnum', 'reason', 'reasonnum') ; return $error if $error; @@ -96,6 +98,49 @@ sub check { $self->SUPER::check; } +=item unvoid + +"Un-void"s this credit: Deletes the voided credit from the database and adds +back (but does not re-apply) a normal credit. + +=cut + +sub unvoid { + my $self = shift; + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $cust_credit = new FS::cust_credit ( { + map { $_ => $self->get($_) } grep { $_ !~ /void/ } $self->fields + } ); + my $error = $cust_credit->insert; + + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + $error ||= $self->delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + + ''; + +} + =item cust_main Returns the parent customer object (see L<FS::cust_main>). @@ -111,6 +156,40 @@ sub void_access_user { qsearchs('access_user', { 'usernum' => $self->void_usernum } ); } +=item void_access_user_name + +Returns the voiding employee name. + +=cut + +sub void_access_user_name { + my $self = shift; + my $user = $self->void_access_user; + return unless $user; + return $user->name; +} + +=item void_reason + +Returns the text of the associated void credit reason (see L<FS::reason>) for this voided credit. + +The reason for the original credit remains accessible through the reason method. + +=cut + +sub void_reason { + my ($self, $value, %options) = @_; + my $reason_text; + if ( $self->void_reasonnum ) { + my $reason = FS::reason->by_key($self->void_reasonnum); + $reason_text = $reason->reason; + } else { # in case one of these somehow still exists + $reason_text = $self->get('void_reason'); + } + + return $reason_text; +} + =back =head1 BUGS diff --git a/FS/FS/reason_type.pm b/FS/FS/reason_type.pm index 00ac9a8..17a7167 100644 --- a/FS/FS/reason_type.pm +++ b/FS/FS/reason_type.pm @@ -11,6 +11,7 @@ our %class_name = ( 'R' => 'credit', 'S' => 'suspend', 'F' => 'refund', + 'X' => 'void credit', ); our %class_purpose = ( @@ -18,6 +19,7 @@ our %class_purpose = ( 'R' => 'explain why a customer was credited', 'S' => 'explain why a customer package was suspended', 'F' => 'explain why a customer was refunded', + 'X' => 'explain why a credit was voided', ); =head1 NAME @@ -48,7 +50,7 @@ inherits from FS::Record. The following fields are currently supported: =item typenum - primary key -=item class - currently 'C', 'R', or 'S' for cancel, credit, or suspend +=item class - currently 'C', 'R', 'S', 'F' or 'X' for cancel, credit, suspend, refund or void credit =item type - name of the type of reason |