From ca24c5a345c866a069ac4fe58f1567dc38b79478 Mon Sep 17 00:00:00 2001 From: Jonathan Prykop Date: Fri, 13 Nov 2015 01:12:37 -0600 Subject: [PATCH] RT#17480: Freeside Cancel Reason --- FS/FS/reason.pm | 74 +++++++++++++++++++++++++++ httemplate/browse/reason.html | 22 +++++++- httemplate/browse/reason_type.html | 21 +++++++- httemplate/search/elements/checkbox-foot.html | 9 ++++ 4 files changed, 123 insertions(+), 3 deletions(-) diff --git a/FS/FS/reason.pm b/FS/FS/reason.pm index 6f4bf62d9..e62bf342b 100644 --- a/FS/FS/reason.pm +++ b/FS/FS/reason.pm @@ -155,6 +155,80 @@ sub reasontype { qsearchs( 'reason_type', { 'typenum' => shift->reason_type } ); } +=item merge + +Accepts an arrayref of reason objects, to be merged into this reason. +Reasons must all have the same reason_type class as this one. +Matching reasonnums will be replaced in the following tables: + + cust_bill_void + cust_bill_pkg_void + cust_credit + cust_credit_void + cust_pay_void + cust_pkg_reason + cust_refund + +=cut + +sub merge { + my ($self,$reasons) = @_; + return "Bad input for merge" unless ref($reasons) eq 'ARRAY'; + + my $class = $self->reasontype->class; + + 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 $error; + foreach my $reason (@$reasons) { + last if $error; + next if $reason->reasonnum eq $self->reasonnum; + $error = "Mismatched reason type class" + unless $reason->reasontype->class eq $class; + foreach my $table ( qw( + cust_bill_void + cust_bill_pkg_void + cust_credit + cust_credit_void + cust_pay_void + cust_pkg_reason + cust_refund + )) { + last if $error; + my @fields = ('reasonnum'); + push(@fields, 'void_reasonnum') if $table eq 'cust_credit_void'; + foreach my $field (@fields) { + last if $error; + foreach my $obj ( qsearch($table,{ $field => $reason->reasonnum }) ) { + last if $error; + $obj->set($field,$self->reasonnum); + $error = $obj->replace; + } + } + } + $error ||= $reason->delete; + } + + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + + ''; + +} + =back =head1 CLASS METHODS diff --git a/httemplate/browse/reason.html b/httemplate/browse/reason.html index 8af88a950..bdbcf3704 100644 --- a/httemplate/browse/reason.html +++ b/httemplate/browse/reason.html @@ -18,6 +18,8 @@ 'fields' => \@fields, 'links' => \@links, 'align' => $align, + 'html_form' => qq!
!, + 'html_foot' => $html_foot, ) %> <%init> @@ -31,7 +33,8 @@ my $class = $1; my $classname = $FS::reason_type::class_name{$class}; my $classpurpose = $FS::reason_type::class_purpose{$class}; -my $html_init = ucfirst($classname). " reasons $classpurpose.

". +my $html_init = include('/elements/init_overlib.html'). +ucfirst($classname). " reasons $classpurpose.

". qq!!. "Add a $classname reason

"; @@ -107,5 +110,22 @@ if ( $class eq 'S' ) { $align .= 'cl'; } +# reason merge handling +push @header, ''; +push @fields, sub { + my $reason = shift; + my $reasonnum = $reason->reasonnum; + qq!!; +}; +push @links, ''; +$align .= 'l'; +my $html_foot = include('/search/elements/checkbox-foot.html', + onclick => include( '/elements/popup_link_onclick.html', + js_action => q!'! . "${p}misc/reason-merge.html?" . q!' + toCGIString()!, + actionlabel => 'Merge reasons', + ), + label => 'merge selected reasons', + minboxes => 2, +) . '
'; diff --git a/httemplate/browse/reason_type.html b/httemplate/browse/reason_type.html index 0cb6e7a39..e5f42e839 100644 --- a/httemplate/browse/reason_type.html +++ b/httemplate/browse/reason_type.html @@ -21,6 +21,8 @@ '', ], 'disable_total' => 1, + 'html_form' => qq!
!, + 'html_foot' => $html_foot, &> <%init> @@ -44,7 +46,8 @@ my $html_init = 'Reasons: ' . } keys (%FS::reason_type::class_name) ); -$html_init .= '

' . +$html_init .= include('/elements/init_overlib.html'). + '

' . $classname . ' reasons ' . $FS::reason_type::class_purpose{$class} . '. Reason types allow reasons to be grouped for reporting purposes.' . @@ -64,6 +67,10 @@ my $reasons_sub = sub { 'link' => $p. "edit/reason.html?class=$class&reasonnum=". $_->reasonnum, }, + { + 'data' => q!!, + 'align' => 'right', + }, ]; } $reason_type->enabled_reasons ), @@ -73,7 +80,8 @@ my $reasons_sub = sub { 'align' => 'left', 'link' => $p. "edit/reason.html?class=$class", 'data_style' => 'i', - } + }, + { 'data' => '' }, ] ]; @@ -86,4 +94,13 @@ $count_query .= $where_clause; my $link = [ $p.'edit/reason_type.html?class='.$class.'&typenum=', 'typenum' ]; +my $html_foot = include('/search/elements/checkbox-foot.html', + onclick => include( '/elements/popup_link_onclick.html', + js_action => q!'! . "${p}misc/reason-merge.html?" . q!' + toCGIString()!, + actionlabel => 'Merge reasons', + ), + label => 'merge selected reasons', + minboxes => 2, +) . '

'; + diff --git a/httemplate/search/elements/checkbox-foot.html b/httemplate/search/elements/checkbox-foot.html index c47009425..ae8b79470 100644 --- a/httemplate/search/elements/checkbox-foot.html +++ b/httemplate/search/elements/checkbox-foot.html @@ -11,6 +11,7 @@ }, ], filter => '.name = "pkgpart"', # see below + minboxes => 2, #will remove checkboxes if there aren't at least this many ), &> @@ -67,6 +68,14 @@ for (var i = 0; i < inputs.length; i++) { } } %# avoid the need for "$areboxes" late-evaluation hackery +% if ($opt{'minboxes'}) { +if ( checkboxes.length < <% $opt{'minboxes'} %> ) { + for (i = 0; i < checkboxes.length; i++) { + checkboxes[i].parentNode.removeChild(checkboxes[i]); + } + checkboxes = []; +} +% } if ( checkboxes.length == 0 ) { document.getElementById('checkbox_footer').style.display = 'none'; } -- 2.11.0