summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Prykop <jonathan@freeside.biz>2015-11-13 01:12:37 -0600
committerJonathan Prykop <jonathan@freeside.biz>2015-11-16 19:36:44 -0600
commit831946cfe0fed362f6639d848714728ee5e40cf8 (patch)
tree4be8912f9c9f8b2c50afdf319160a531db97d4a2
parentdc831165b7d7f7b68b7d84a214dd01557492a101 (diff)
RT#17480: Freeside Cancel Reason
-rw-r--r--FS/FS/reason.pm74
-rw-r--r--httemplate/browse/reason.html22
-rw-r--r--httemplate/browse/reason_type.html21
-rw-r--r--httemplate/search/elements/checkbox-foot.html9
4 files changed, 123 insertions, 3 deletions
diff --git a/FS/FS/reason.pm b/FS/FS/reason.pm
index 6f4bf62..e62bf34 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 8af88a9..bdbcf37 100644
--- a/httemplate/browse/reason.html
+++ b/httemplate/browse/reason.html
@@ -18,6 +18,8 @@
'fields' => \@fields,
'links' => \@links,
'align' => $align,
+ 'html_form' => qq!<FORM ACTION="${p}misc/reason_merge.html" METHOD="POST">!,
+ '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.<BR><BR>".
+my $html_init = include('/elements/init_overlib.html').
+ucfirst($classname). " reasons $classpurpose.<BR><BR>".
qq!<A HREF="${p}edit/reason.html?class=$class">!.
"<I>Add a $classname reason</I></A><BR><BR>";
@@ -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!<INPUT TYPE="checkbox" NAME="reasonnum" VALUE="$reasonnum">!;
+};
+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,
+) . '</FORM>';
</%init>
diff --git a/httemplate/browse/reason_type.html b/httemplate/browse/reason_type.html
index 0cb6e7a..e5f42e8 100644
--- a/httemplate/browse/reason_type.html
+++ b/httemplate/browse/reason_type.html
@@ -21,6 +21,8 @@
'',
],
'disable_total' => 1,
+ 'html_form' => qq!<FORM ACTION="${p}misc/reason_merge.html" METHOD="POST">!,
+ 'html_foot' => $html_foot,
&>
<%init>
@@ -44,7 +46,8 @@ my $html_init = 'Reasons: ' .
} keys (%FS::reason_type::class_name)
);
-$html_init .= '<BR><P>' .
+$html_init .= include('/elements/init_overlib.html').
+ '<BR><P>' .
$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!<INPUT TYPE="checkbox" NAME="reasonnum" VALUE="! . $_->reasonnum . 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,
+) . '</FORM>';
+
</%init>
diff --git a/httemplate/search/elements/checkbox-foot.html b/httemplate/search/elements/checkbox-foot.html
index c470094..ae8b794 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';
}