summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlevinse <levinse>2010-12-10 06:02:53 +0000
committerlevinse <levinse>2010-12-10 06:02:53 +0000
commit457da870c23db87fbbc29d7c667a73f41422dd71 (patch)
treeea61844254e2338dc20cc85e1cbc30b006b731a3
parent6568e7bb436d6ac4ae2ec984446e8fc4a999f0af (diff)
implement customer note classes, RT9995
-rw-r--r--FS/FS.pm2
-rw-r--r--FS/FS/Conf.pm12
-rw-r--r--FS/FS/Mason.pm1
-rw-r--r--FS/FS/Schema.pm12
-rw-r--r--FS/FS/cust_main.pm7
-rw-r--r--FS/FS/cust_main_note.pm34
-rw-r--r--FS/FS/cust_note_class.pm105
-rw-r--r--FS/MANIFEST2
-rw-r--r--FS/t/cust_note_class.t5
-rw-r--r--httemplate/browse/cust_note_class.html34
-rwxr-xr-xhttemplate/edit/cust_main_note.cgi19
-rw-r--r--httemplate/edit/cust_note_class.html6
-rw-r--r--httemplate/edit/elements/class_Common.html8
-rwxr-xr-xhttemplate/edit/process/cust_main_note.cgi4
-rw-r--r--httemplate/edit/process/cust_note_class.html11
-rw-r--r--httemplate/elements/menu.html3
-rwxr-xr-xhttemplate/view/cust_main.cgi2
-rwxr-xr-xhttemplate/view/cust_main/notes.html102
18 files changed, 346 insertions, 23 deletions
diff --git a/FS/FS.pm b/FS/FS.pm
index 2b86b61..8e78639 100644
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -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 bcebdf6..ebeebb2 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 3b46d77..9b010e8 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 48363ce..70aab43 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 03e8cc6..03154ad 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 0a203a8..06da096 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 0000000..0cb9677
--- /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 edf8673..f6d6602 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 0000000..03fa0d2
--- /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 0000000..f5d450b
--- /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 439c844..c4ec071 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 &nbsp;
+ <% 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 \/>|&nbsp;/, $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 0000000..111190b
--- /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 b5f4939..e6334fe 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 f904c59..227297e 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 0000000..09dc818
--- /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 46f9a0c..acbaf41 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 0f9c1e2..df875f9 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 1283b19..2378380 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">&nbsp;</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">&nbsp;</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 %>">
&nbsp;<% $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: &nbsp;
+% 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