diff options
author | levinse <levinse> | 2010-12-10 06:02:53 +0000 |
---|---|---|
committer | levinse <levinse> | 2010-12-10 06:02:53 +0000 |
commit | 457da870c23db87fbbc29d7c667a73f41422dd71 (patch) | |
tree | ea61844254e2338dc20cc85e1cbc30b006b731a3 | |
parent | 6568e7bb436d6ac4ae2ec984446e8fc4a999f0af (diff) |
implement customer note classes, RT9995
-rw-r--r-- | FS/FS.pm | 2 | ||||
-rw-r--r-- | FS/FS/Conf.pm | 12 | ||||
-rw-r--r-- | FS/FS/Mason.pm | 1 | ||||
-rw-r--r-- | FS/FS/Schema.pm | 12 | ||||
-rw-r--r-- | FS/FS/cust_main.pm | 7 | ||||
-rw-r--r-- | FS/FS/cust_main_note.pm | 34 | ||||
-rw-r--r-- | FS/FS/cust_note_class.pm | 105 | ||||
-rw-r--r-- | FS/MANIFEST | 2 | ||||
-rw-r--r-- | FS/t/cust_note_class.t | 5 | ||||
-rw-r--r-- | httemplate/browse/cust_note_class.html | 34 | ||||
-rwxr-xr-x | httemplate/edit/cust_main_note.cgi | 19 | ||||
-rw-r--r-- | httemplate/edit/cust_note_class.html | 6 | ||||
-rw-r--r-- | httemplate/edit/elements/class_Common.html | 8 | ||||
-rwxr-xr-x | httemplate/edit/process/cust_main_note.cgi | 4 | ||||
-rw-r--r-- | httemplate/edit/process/cust_note_class.html | 11 | ||||
-rw-r--r-- | httemplate/elements/menu.html | 3 | ||||
-rwxr-xr-x | httemplate/view/cust_main.cgi | 2 | ||||
-rwxr-xr-x | httemplate/view/cust_main/notes.html | 102 |
18 files changed, 346 insertions, 23 deletions
@@ -302,6 +302,8 @@ L<FS::cust_main_exemption> - Customer tax exemption class L<FS::cust_main_note> - Customer note class +L<FS::cust_note_class> - Customer note classification class + L<FS::banned_pay> - Banned payment information class L<FS::cust_bill> - Invoice class diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index bcebdf6de..ebeebb261 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -4090,6 +4090,18 @@ and customer address. Include units.', 'description' => 'Enable the alternate address format (location type, number, and kind) on qualifications', 'type' => 'checkbox', }, + + { + 'key' => 'note-classes', + 'section' => 'UI', + 'description' => 'Use customer note classes', + 'type' => 'select', + 'select_hash' => [ + 0 => 'Disabled', + 1 => 'Enabled', + 2 => 'Enabled, with tabs', + ], + }, { key => "apacheroot", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" }, { key => "apachemachine", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" }, diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index 3b46d77bc..9b010e8d6 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -263,6 +263,7 @@ if ( -e $addl_handler_use_file ) { use FS::qual_option; use FS::dsl_note; use FS::part_pkg_vendor; + use FS::cust_note_class; # Sammath Naur if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 48363ce31..70aab4315 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -932,6 +932,7 @@ sub tables_hashref { 'columns' => [ 'notenum', 'serial', '', '', '', '', 'custnum', 'int', '', '', '', '', + 'classnum', 'int', 'NULL', '', '', '', '_date', @date_type, '', '', 'otaker', 'varchar', 'NULL', 32, '', '', 'usernum', 'int', 'NULL', '', '', '', @@ -941,6 +942,17 @@ sub tables_hashref { 'unique' => [], 'index' => [ [ 'custnum' ], [ '_date' ], [ 'usernum' ], ], }, + + 'cust_note_class' => { + 'columns' => [ + 'classnum', 'serial', '', '', '', '', + 'classname', 'varchar', '', $char_d, '', '', + 'disabled', 'char', 'NULL', 1, '', '', + ], + 'primary_key' => 'classnum', + 'unique' => [], + 'index' => [ ['disabled'] ], + }, 'cust_category' => { 'columns' => [ diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 03e8cc647..03154adc3 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -2209,12 +2209,13 @@ Returns all notes (see L<FS::cust_main_note>) for this customer. =cut sub notes { - my $self = shift; - #order by? + my($self,$orderby_classnum) = (shift,shift); + my $orderby = "_DATE DESC"; + $orderby = "CLASSNUM ASC, $orderby" if $orderby_classnum; qsearch( 'cust_main_note', { 'custnum' => $self->custnum }, '', - 'ORDER BY _DATE DESC' + "ORDER BY $orderby", ); } diff --git a/FS/FS/cust_main_note.pm b/FS/FS/cust_main_note.pm index 0a203a8f4..06da0965a 100644 --- a/FS/FS/cust_main_note.pm +++ b/FS/FS/cust_main_note.pm @@ -4,6 +4,7 @@ use strict; use base qw( FS::otaker_Mixin FS::Record ); use Carp; use FS::Record qw( qsearch qsearchs ); +use FS::cust_note_class; =head1 NAME @@ -38,6 +39,8 @@ primary key =item custnum +=item classnum + =item _date =item usernum @@ -106,6 +109,7 @@ sub check { my $error = $self->ut_numbern('notenum') || $self->ut_number('custnum') + || $self->ut_foreign_keyn('classnum', 'cust_note_class', 'classnum') || $self->ut_numbern('_date') || $self->ut_textn('otaker') || $self->ut_anything('comments') @@ -115,6 +119,36 @@ sub check { $self->SUPER::check; } +=item cust_note_class + +Returns the customer note class, as an FS::cust_note_class object, or the empty +string if there is no note class. + +=cut + +sub cust_note_class { + my $self = shift; + if ( $self->classnum ) { + qsearchs('cust_note_class', { 'classnum' => $self->classnum } ); + } else { + return ''; + } +} + +=item classname + +Returns the customer note class name, or the empty string if there is no +customer note class. + +=cut + +sub classname { + my $self = shift; + my $cust_note_class = $self->cust_note_class; + $cust_note_class ? $cust_note_class->classname : ''; +} + + #false laziness w/otaker_Mixin & cust_attachment sub otaker { my $self = shift; diff --git a/FS/FS/cust_note_class.pm b/FS/FS/cust_note_class.pm new file mode 100644 index 000000000..0cb967754 --- /dev/null +++ b/FS/FS/cust_note_class.pm @@ -0,0 +1,105 @@ +package FS::cust_note_class; + +use strict; +use base qw( FS::class_Common ); +use FS::cust_main_note; + +=head1 NAME + +FS::cust_note_class - Object methods for cust_note_class records + +=head1 SYNOPSIS + + use FS::cust_note_class; + + $record = new FS::cust_note_class \%hash; + $record = new FS::cust_note_class { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::cust_note_class object represents a customer note class. Every customer +note (see L<FS::cust_main_note) has, optionally, a note class. This class +inherits from FS::class_Common. The following fields are currently supported: + +=over 4 + +=item classnum + +primary key + +=item classname + +classname + +=item disabled + +disabled + + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new customer note class. To add the note class to the database, +see L<"insert">. + +Note that this stores the hash reference, not a distinct copy of the hash it +points to. You can ask the object for a copy with the I<hash> method. + +=cut + +sub table { 'cust_note_class'; } +sub _target_table { 'cust_main_note'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=cut + +=item delete + +Delete this record from the database. + +=cut + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error, otherwise returns false. + +=cut + +=item check + +Checks all fields to make sure this is a valid note class. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +=back + +=head1 BUGS + +=head1 SEE ALSO + +L<FS::cust_main_note>, L<FS::Record>, schema.html from the base documentation. + +=cut + +1; + diff --git a/FS/MANIFEST b/FS/MANIFEST index edf8673c0..f6d660228 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -550,3 +550,5 @@ FS/dsl_note.pm t/dsl_note.t FS/part_pkg_vendor.pm t/part_pkg_vendor.t +FS/cust_note_class.pm +t/cust_note_class.t diff --git a/FS/t/cust_note_class.t b/FS/t/cust_note_class.t new file mode 100644 index 000000000..03fa0d2b9 --- /dev/null +++ b/FS/t/cust_note_class.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::cust_note_class; +$loaded=1; +print "ok 1\n"; diff --git a/httemplate/browse/cust_note_class.html b/httemplate/browse/cust_note_class.html new file mode 100644 index 000000000..f5d450b9f --- /dev/null +++ b/httemplate/browse/cust_note_class.html @@ -0,0 +1,34 @@ +<% include( 'elements/browse.html', + 'title' => 'Customer note classes', + 'html_init' => $html_init, + 'name' => 'customer note classes', + 'disableable' => 1, + 'disabled_statuspos' => 2, + 'query' => { 'table' => 'cust_note_class', + 'hashref' => {}, + 'order_by' => 'ORDER BY classnum', + }, + 'count_query' => $count_query, + 'header' => $header, + 'fields' => $fields, + 'links' => $links, + ) +%> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +my $html_init = + 'Customer note classes define groups of notes for reporting.<BR><BR>'. + qq!<A HREF="${p}edit/cust_note_class.html"><I>Add a customer note class</I></A><BR><BR>!; + +my $count_query = 'SELECT COUNT(*) FROM cust_note_class'; + +my $link = [ $p.'edit/cust_note_class.html?', 'classnum' ]; + +my $header = [ '#', 'Class' ]; +my $fields = [ 'classnum', 'classname' ]; +my $links = [ $link, $link ]; + +</%init> diff --git a/httemplate/edit/cust_main_note.cgi b/httemplate/edit/cust_main_note.cgi index 439c84414..c4ec071b8 100755 --- a/httemplate/edit/cust_main_note.cgi +++ b/httemplate/edit/cust_main_note.cgi @@ -6,6 +6,18 @@ <INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>"> <INPUT TYPE="hidden" NAME="notenum" VALUE="<% $notenum %>"> +% if ($conf->exists('note-classes') && $conf->config('note-classes') > 0) { + Class + <% include( '/elements/select-table.html', + 'table' => 'cust_note_class', + 'name_col' => 'classname', + 'curr_value' => $classnum, + 'empty_label' => '(none)', + 'hashref' => { 'disabled' => '' }, + ) %> + <BR> +% } + % if( $FS::CurrentUser::CurrentUser->option('disable_html_editor') ) { <TEXTAREA NAME="comment_plain" ROWS="12" COLS="60"><% join '', split /<br \/>| /, $comment @@ -25,21 +37,26 @@ <%init> +my $conf = new FS::Conf; + my $comment; my $notenum = ''; +my $classnum; if ( $cgi->param('error') ) { $comment = $cgi->param('comment'); + $classnum = $cgi->param('classnum'); } elsif ( $cgi->param('notenum') =~ /^(\d+)$/ ) { $notenum = $1; die "illegal query ". $cgi->keywords unless $notenum; my $note = qsearchs('cust_main_note', { 'notenum' => $notenum }); die "no such note: ". $notenum unless $note; $comment = $note->comments; + $classnum = $note->classnum; } $comment =~ s/\r//g; # remove weird line breaks to protect FCKeditor -$cgi->param('custnum') =~ /^(\d+)$/ or die "illeagl custnum"; +$cgi->param('custnum') =~ /^(\d+)$/ or die "illegal custnum"; my $custnum = $1; my $action = $notenum ? 'Edit' : 'Add'; diff --git a/httemplate/edit/cust_note_class.html b/httemplate/edit/cust_note_class.html new file mode 100644 index 000000000..111190b71 --- /dev/null +++ b/httemplate/edit/cust_note_class.html @@ -0,0 +1,6 @@ +<% include( 'elements/class_Common.html', + 'name' => 'Customer Note Class', + 'table' => 'cust_note_class', + 'nocat' => 1, + ) +%> diff --git a/httemplate/edit/elements/class_Common.html b/httemplate/edit/elements/class_Common.html index b5f493991..e6334fe23 100644 --- a/httemplate/edit/elements/class_Common.html +++ b/httemplate/edit/elements/class_Common.html @@ -26,7 +26,11 @@ die "access denied" my %opt = @_; my $table = $opt{'table'}; -( my $category_table = $table ) =~ s/class/category/ or die; -my @category = qsearch($category_table, { 'disabled' => '' }); +my @category; +unless ( $opt{'nocat'} ) { + ( my $category_table = $table ) =~ s/class/category/ or die; + @category = qsearch($category_table, { 'disabled' => '' }); +} + </%init> diff --git a/httemplate/edit/process/cust_main_note.cgi b/httemplate/edit/process/cust_main_note.cgi index f904c5968..227297eef 100755 --- a/httemplate/edit/process/cust_main_note.cgi +++ b/httemplate/edit/process/cust_main_note.cgi @@ -18,6 +18,9 @@ $cgi->param('notenum') =~ /^(\d*)$/ or die "Illegal notenum: ". $cgi->param('notenum'); my $notenum = $1; +$cgi->param('classnum') =~ /^(\d*)$/; +my $classnum = $1; + my $comment = $cgi->param('comment_html') || join("<br />\n", split "(?:\r|\n)+", $cgi->param('comment_plain') @@ -26,6 +29,7 @@ my $comment = $cgi->param('comment_html') || my $new = new FS::cust_main_note ( { notenum => $notenum, custnum => $custnum, + classnum => $classnum ? $classnum : undef, _date => time, usernum => $FS::CurrentUser::CurrentUser->usernum, comments => $comment, diff --git a/httemplate/edit/process/cust_note_class.html b/httemplate/edit/process/cust_note_class.html new file mode 100644 index 000000000..09dc818db --- /dev/null +++ b/httemplate/edit/process/cust_note_class.html @@ -0,0 +1,11 @@ +<% include( 'elements/process.html', + 'table' => 'cust_note_class', + 'viewall_dir' => 'browse', + ) +%> +<%init> + +die "access denied" + unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); + +</%init> diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index 46f9a0ca6..acbaf41bd 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -424,6 +424,9 @@ tie my %config_cust, 'Tie::IxHash', 'Customer classes' => [ $fsurl.'browse/cust_class.html', 'Customer classes define groups of customers for reporting.' ], 'Customer categories' => [ $fsurl.'browse/cust_category.html', 'Customer categories define groups of customer classes.' ], ; + +$config_cust{'Customer note classes'} = [ $fsurl.'browse/cust_note_class.html', 'Customer note classes define groups of notes for reporting.' ] + if ($conf->exists('note-classes') && $conf->config('note-classes') > 0); tie my %config_agent, 'Tie::IxHash', 'Agent types' => [ $fsurl.'browse/agent_type.cgi', 'Agent types define groups of package definitions that you can then assign to particular agents' ], diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index 0f9c1e250..df875f939 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -146,7 +146,7 @@ Comments <BR><BR> % } <A NAME="notes"> -% my $notecount = scalar($cust_main->notes()); +% my $notecount = scalar($cust_main->notes(0)); % if ( ! $conf->exists('cust_main-disable_notes') || $notecount) { % unless ( $view eq 'notes' && $cust_main->comments !~ /[^\s\n\r]/ ) { diff --git a/httemplate/view/cust_main/notes.html b/httemplate/view/cust_main/notes.html index 1283b19da..237838029 100755 --- a/httemplate/view/cust_main/notes.html +++ b/httemplate/view/cust_main/notes.html @@ -1,24 +1,43 @@ % if ( scalar(@notes) ) { - <% include('/elements/init_overlib.html') %> - - <% include("/elements/table-grid.html") %> +<SCRIPT TYPE="text/javascript"> + + function display_notes_classnum(classnum){ + document.getElementById('notes_'+classnum).style.display = 'block'; + document.getElementById('notes_tablink_'+classnum).style.fontWeight = 'bold'; + + var divs = document.getElementsByTagName("div"); + var i; + for(i=0; i < divs.length; i++){ + var d = divs[i]; + if(d.id.length > 6 && d.id.substring(0,6) == 'notes_') { + if(divs[i].id != 'notes_'+classnum) { + divs[i].style.display = 'none'; + } + } + } + + var as = document.getElementsByTagName("a"); + for(i=0; i < as.length; i++){ + var a = as[i]; + if(a.id.length > 14 && a.id.substring(0,14) == 'notes_tablink_') { + if(as[i].id != 'notes_tablink_'+classnum) { + as[i].style.fontWeight = 'normal'; + } + } + } + } + +</SCRIPT> - <TR> - <TH CLASS="grid" BGCOLOR="#cccccc">Date</TH> -% if ( $conf->exists('cust_main_note-display_times') ) { - <TH CLASS="grid" BGCOLOR="#cccccc">Time</TH> -% } - <TH CLASS="grid" BGCOLOR="#cccccc">Person</TH> - <TH CLASS="grid" BGCOLOR="#cccccc">Note</TH> -% if ($curuser->access_right('Edit customer note') ) { - <TH CLASS="grid" BGCOLOR="#cccccc"> </TH> -% } - </TR> + <% include('/elements/init_overlib.html') %> % my $bgcolor1 = '#eeeeee'; % my $bgcolor2 = '#ffffff'; % my $bgcolor = ''; +% my $last_classnum = -1; +% my $skipheader = 0; +% my %classes = (); % % foreach my $note (@notes) { % @@ -46,12 +65,50 @@ % if ($curuser->access_right('Edit customer note') ) { % $edit = qq! <A HREF="javascript:void(0);" $clickjs>(edit)</A>!; % } +% +% if ( $last_classnum != $note->classnum && !$skipheader ) { +% my $tmp_classnum = $note->classnum ? $note->classnum : 0; +% $classes{$tmp_classnum} = $note->classname ne '' ? $note->classname +% : 'Other'; +% if ( $last_classnum != -1 ) { + </TABLE> + </DIV> +% } +% my $display = ($tmp_classnum == 0 || !$conf->exists('note-classes') +% || $conf->config('note-classes') < 2) +% ? 'block' : 'none'; + <DIV id="notes_<% $tmp_classnum %>" + style="display:<% $display %>" + > + <% include("/elements/table-grid.html") %> + <TR> + <TH CLASS="grid" BGCOLOR="#cccccc">Date</TH> +% if ( $conf->exists('cust_main_note-display_times') ) { + <TH CLASS="grid" BGCOLOR="#cccccc">Time</TH> +% } + <TH CLASS="grid" BGCOLOR="#cccccc">Person</TH> +% if ($conf->exists('note-classes') && $conf->config('note-classes') == 1) { + <TH CLASS="grid" BGCOLOR="#cccccc">Class</TH> +% } + <TH CLASS="grid" BGCOLOR="#cccccc">Note</TH> +% if ($curuser->access_right('Edit customer note') ) { + <TH CLASS="grid" BGCOLOR="#cccccc"> </TH> +% } + </TR> +% $skipheader = (!$conf->exists('note-classes') || $conf->config('note-classes') < 2); +% $last_classnum = $note->classnum; +% } <TR> <% note_datestr($note,$conf,$bgcolor) %> <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> <% $note->usernum ? $note->access_user->name : $note->otaker %> </TD> +% if ($conf->exists('note-classes') && $conf->config('note-classes') == 1) { + <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> + <% $note->classname %> + </TD> +% } <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> <% $note->comments | defang %> </TD> @@ -63,6 +120,19 @@ % } #end display notes </TABLE> +</DIV> + +% if ( $conf->exists('note-classes') && $conf->config('note-classes') == 2 ) { +% my($classnum,$classname); +Show notes of class: +% foreach my $classnum ( sort { $b <=> $a } (keys %classes) ) { + <A id="notes_tablink_<% $classnum %>" + HREF="javascript:display_notes_classnum(<% $classnum %>)" + style="font-weight: <% $classnum == 0 ? 'bold' : 'normal' %>" + ><% $classes{$classnum} %></A> +% } + <BR> +% } % } <%init> @@ -77,9 +147,9 @@ my(%opt) = @_; my $custnum = $opt{'custnum'}; my $cust_main = qsearchs('cust_main', {'custnum' => $custnum} ); -die "Custimer not found!" unless $cust_main; +die "Customer not found!" unless $cust_main; -my (@notes) = $cust_main->notes(); +my (@notes) = $cust_main->notes($conf->exists('note-classes') && $conf->config('note-classes') == 2); #subroutines |