From 9fae251fc1e3069694ebaf4fae62bde844f45cff Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Wed, 11 Jun 2014 13:51:22 -0700 Subject: [PATCH] display sent mail on customer notes page, and improve sent mail log UI, #29250 --- FS/FS/cust_msg.pm | 31 +++ httemplate/search/cust_msg.html | 12 +- httemplate/view/cust_main.cgi | 70 +----- httemplate/view/cust_main/notes.html | 234 ++++++++------------- .../view/cust_main/{ => notes}/attachments.html | 6 +- httemplate/view/cust_main/notes/notes.html | 168 +++++++++++++++ httemplate/view/cust_msg.html | 86 +++++--- httemplate/view/cust_msg_part.html | 23 ++ 8 files changed, 384 insertions(+), 246 deletions(-) rename httemplate/view/cust_main/{ => notes}/attachments.html (97%) create mode 100755 httemplate/view/cust_main/notes/notes.html create mode 100644 httemplate/view/cust_msg_part.html diff --git a/FS/FS/cust_msg.pm b/FS/FS/cust_msg.pm index 8d57a54ac..72f64b9c5 100644 --- a/FS/FS/cust_msg.pm +++ b/FS/FS/cust_msg.pm @@ -3,6 +3,7 @@ package FS::cust_msg; use strict; use base qw( FS::cust_main_Mixin FS::Record ); use FS::Record qw( qsearch qsearchs ); +use MIME::Parser; use vars qw( @statuses ); =head1 NAME @@ -149,6 +150,36 @@ sub check { $self->SUPER::check; } +=item entity + +Returns the complete message as a L. + +=item parts + +Returns a list of the MIME parts contained in the message, as L +objects. + +=cut + +sub entity { + my $self = shift; + if ( !exists($self->{entity}) ) { + my $parser = MIME::Parser->new; + my $output_dir = "$FS::UID::cache_dir/cache.$FS::UID::datasrc/mimeparts"; + mkdir($output_dir) unless -d $output_dir; + $parser->output_under($output_dir); + $self->{entity} = + $parser->parse_data( $self->header . "\n" . $self->body ); + } + $self->{entity}; +} + +sub parts { + my $self = shift; + # return only the parts with bodies, not the multipart containers + grep { $_->bodyhandle } $self->entity->parts_DFS; +} + =back =head1 SEE ALSO diff --git a/httemplate/search/cust_msg.html b/httemplate/search/cust_msg.html index 716addfd6..2b6f08e3f 100644 --- a/httemplate/search/cust_msg.html +++ b/httemplate/search/cust_msg.html @@ -1,6 +1,6 @@ <& 'elements/search.html', 'title' => $title, - 'name' => 'messages', + 'name_singular' => 'message', 'query' => $query, 'count_query' => $count_query, 'header' => [ @@ -24,6 +24,12 @@ 'status', sub { encode_entities($_[0]->error) }, ], + 'sort_fields' => [ '_date', + 'msgtype', + 'env_to', + 'status', + 'error', + ], 'align' => 'rllcl', 'links' => [ ], 'link_onclicks' => [ @@ -41,6 +47,7 @@ ], 'html_init' => $html_init, 'really_disable_download' => 1, + @_ &> <%init> #hmm... @@ -58,6 +65,9 @@ if ( $cgi->param('status') =~ /^(\w+)$/ ) { if ( $cgi->param('msgtype') =~ /^(\w+)$/ ) { push @where, "msgtype = '$1'"; } +if ( $cgi->param('custnum') =~ /^(\d+)$/ ) { + push @where, "custnum = $1"; +} my ($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi, ''); push @where, "(_date >= $beginning AND _date <= $ending)"; diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index cdea49dee..c6266ce34 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -191,79 +191,14 @@ function areyousure(href, message) { % if ( $view eq 'notes' || $view eq 'jumbo' ) { -%if ( $cust_main->comments =~ /[^\s\n\r]/ ) { -
<% mt('Comments') |h %> -<% ntable("#cccccc") %><% ntable("#cccccc",2) %> - - -
<% encode_entities($cust_main->comments) %>
- - - -

-% } - -% 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]/ ) { -
-
<% mt('Notes') |h %>
-% } - -% if ( $curuser->access_right('Add customer note') && -% ! $conf->exists('cust_main-disable_notes') -% ) { - - <& /elements/popup_link-cust_main.html, - 'label' => emt('Add customer note'), - 'action' => $p. 'edit/cust_main_note.cgi', - 'actionlabel' => emt('Enter customer note'), - 'cust_main' => $cust_main, - 'width' => 616, - 'height' => 538, #575 - &> - -% } - -
- -<& cust_main/notes.html, 'custnum' => $cust_main->custnum &> - -% } -
- -% if(! $conf->config('disable_cust_attachment') -% and $curuser->access_right('Add attachment')) { -<& /elements/popup_link-cust_main.html, - 'label' => emt('Attach file'), - 'action' => $p.'edit/cust_main_attach.cgi', - 'actionlabel' => emt('Upload file'), - 'cust_main' => $cust_main, - 'width' => 480, - 'height' => 296, -&> -% } -% if( $curuser->access_right('View attachments') ) { -<& cust_main/attachments.html, 'custnum' => $cust_main->custnum &> -% if ($cgi->param('show_deleted')) { -">(<% mt('Show active attachments') |h %>) -% } -% elsif($curuser->access_right('View deleted attachments')) { -">(<% mt('Show deleted attachments') |h %>) -% } -% } -
+<& cust_main/notes.html, 'cust_main' => $cust_main &> % } % if ( $view eq 'jumbo' ) {
% } +
% if ( $view eq 'tickets' || $view eq 'jumbo' ) { @@ -345,6 +280,7 @@ if ( $cgi->param('custnum') =~ /^(\d+)$/ ) { my($query) = $cgi->keywords; # needs parens with my, ->keywords returns array $query =~ /^(\d+)$/; $custnum = $1; + $cgi->param('custnum', $1); } my $cust_main = qsearchs( { diff --git a/httemplate/view/cust_main/notes.html b/httemplate/view/cust_main/notes.html index 2de68ff46..1cd6e0970 100755 --- a/httemplate/view/cust_main/notes.html +++ b/httemplate/view/cust_main/notes.html @@ -1,143 +1,91 @@ -% if ( scalar(@notes) ) { - - - - <& /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) { -% -% if ( $bgcolor eq $bgcolor1 ) { -% $bgcolor = $bgcolor2; -% } else { -% $bgcolor = $bgcolor1; -% } -% -% my $pop = popurl(3); -% my $notenum = $note->notenum; -% my $onclick = include( '/elements/popup_link_onclick.html', -% 'action' => popurl(2). -% 'edit/cust_main_note.cgi'. -% "?custnum=$custnum". -% ";notenum=$notenum", -% 'actionlabel' => emt('Edit customer note'), -% 'width' => 616, -% 'height' => 538, #575 -% 'frame' => 'top', -% ); -% my $clickjs = qq!onclick="$onclick"!; -% -% my $edit = ''; -% if ($curuser->access_right('Edit customer note') ) { -% my $delete_url = $fsurl.'misc/delete-note.html?'.$notenum; -% $edit = qq! (!.emt('edit').')'. -% qq! !. -% '('.emt('delete').')'; -% } -% -% if ( $last_classnum != $note->classnum && !$skipheader ) { -% my $tmp_classnum = $note->classnum ? $note->classnum : 0; -% $classes{$tmp_classnum} = $note->classname ne '' ? $note->classname -% : emt('Other'); -% if ( $last_classnum != -1 ) { - - +% # Customer comments +% if ( $cust_main->comments =~ /[^\s\n\r]/ ) { +
<% mt('Comments') |h %> +<% ntable("#cccccc") %><% ntable("#cccccc",2) %> + + +
<% encode_entities($cust_main->comments) %>
+ + + +

% } -% my $display = ($tmp_classnum == 0 || !$conf->exists('note-classes') -% || $conf->config('note-classes') < 2) -% ? 'block' : 'none'; -
- <& /elements/table-grid.html &> - - <% mt('Date') |h %> -% if ( $conf->exists('cust_main_note-display_times') ) { - <% mt('Time') |h %> -% } - <% mt('Person') |h %> -% if ($conf->exists('note-classes') && $conf->config('note-classes') == 1) { - <% mt('Class') |h %> + +% # Notes, if any + +% 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]/ ) { +

+ <% mt('Notes') |h %> +

+ % } - <% mt('Note') |h %> -% if ($curuser->access_right('Edit customer note') ) { -   + +% if ( $curuser->access_right('Add customer note') && +% ! $conf->exists('cust_main-disable_notes') +% ) { + + <& /elements/popup_link-cust_main.html, + 'label' => emt('Add customer note'), + 'action' => $p. 'edit/cust_main_note.cgi', + 'actionlabel' => emt('Enter customer note'), + 'cust_main' => $cust_main, + 'width' => 616, + 'height' => 538, #575 + &> + % } - -% $skipheader = (!$conf->exists('note-classes') || $conf->config('note-classes') < 2); -% $last_classnum = $note->classnum; +
+ +% # actually display notes +<& notes/notes.html, 'cust_main' => $cust_main &> +
+% } # end of notes + +% # Attachments +% # XXX at some point move all of this into notes/attachments.html +% if( $curuser->access_right('View attachments') ) { +% # List attachments +<& notes/attachments.html, 'cust_main' => $cust_main &> +% # "Attach file" link +% if(! $conf->config('disable_cust_attachment') +% and $curuser->access_right('Add attachment')) { +<& /elements/popup_link-cust_main.html, + 'label' => emt('Attach file'), + 'action' => $p.'edit/cust_main_attach.cgi', + 'actionlabel' => emt('Upload file'), + 'cust_main' => $cust_main, + 'width' => 480, + 'height' => 296, +&> % } - - <% note_datestr($note,$conf,$bgcolor) %> - -  <% $note->usernum ? $note->access_user->name : $note->otaker %> - -% if ($conf->exists('note-classes') && $conf->config('note-classes') == 1) { - - <% $note->classname %> - -% } - - <% $note->comments | defang %> - -% if($edit) { - <% $edit %> -% } - - -% } #end display notes - - -
- -% if ( $conf->exists('note-classes') && $conf->config('note-classes') == 2 ) { -% my($classnum,$classname); -<% mt('Show notes of class:') |h %>   -% foreach my $classnum ( sort { $b <=> $a } (keys %classes) ) { - <% $classes{$classnum} %> -% } -
+% if ($cgi->param('show_deleted')) { +">(<% mt('Show active attachments') |h %>) +% } elsif($curuser->access_right('View deleted attachments')) { +">(<% mt('Show deleted attachments') |h %>) +% } % } +
+% if ( $curuser->access_right('View email logs') +% and FS::cust_msg->count("custnum = $custnum")) { +
+% if (!$cgi->param('order_by')) { +% my $order_by = '_date'; +% $order_by .= ' DESC' if $curuser->option('history_order') eq 'newest'; +% $cgi->param('order_by', $order_by); +% } +<& /search/cust_msg.html, + nohtmlheader => 1, + html_init => mt('Mail sent to this customer: '), +&> % } <%init> @@ -148,23 +96,9 @@ my $curuser = $FS::CurrentUser::CurrentUser; my(%opt) = @_; -my $custnum = $opt{'custnum'}; - -my $cust_main = qsearchs('cust_main', {'custnum' => $custnum} ); -die "Customer not found!" unless $cust_main; - -my (@notes) = $cust_main->notes($conf->exists('note-classes') && $conf->config('note-classes') == 2); - -#subroutines +my $cust_main = $opt{'cust_main'}; +my $custnum = $cust_main->custnum; -sub note_datestr { - my($note, $conf, $bgcolor) = @_ or return ''; - my $td = qq{}; - my $format = "$td%b %o, %Y"; - $format .= "$td%l:%M%P" - if $conf->exists('cust_main_note-display_times'); - ( my $strip = time2str($format, $note->_date) ) =~ s/ (\d)/$1/g; - $strip; -} +my $view = $cgi->param('show') || $curuser->default_customer_view; diff --git a/httemplate/view/cust_main/attachments.html b/httemplate/view/cust_main/notes/attachments.html similarity index 97% rename from httemplate/view/cust_main/attachments.html rename to httemplate/view/cust_main/notes/attachments.html index d51d82645..0c16835f2 100755 --- a/httemplate/view/cust_main/attachments.html +++ b/httemplate/view/cust_main/notes/attachments.html @@ -113,10 +113,8 @@ my $curuser = $FS::CurrentUser::CurrentUser; die "access denied" if !$curuser->access_right('View attachments'); my(%opt) = @_; -my $custnum = $opt{'custnum'}; - -my $cust_main = qsearchs('cust_main', {'custnum' => $custnum} ); -die "Customer not found!" unless $cust_main; +my $cust_main = $opt{'cust_main'}; +my $custnum = $cust_main->custnum; my (@attachments) = qsearch('cust_attachment', {'custnum' => $custnum}); diff --git a/httemplate/view/cust_main/notes/notes.html b/httemplate/view/cust_main/notes/notes.html new file mode 100755 index 000000000..6a7a06a02 --- /dev/null +++ b/httemplate/view/cust_main/notes/notes.html @@ -0,0 +1,168 @@ +% if ( scalar(@notes) ) { + + + + <& /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) { +% +% if ( $bgcolor eq $bgcolor1 ) { +% $bgcolor = $bgcolor2; +% } else { +% $bgcolor = $bgcolor1; +% } +% +% my $pop = popurl(3); +% my $notenum = $note->notenum; +% my $onclick = include( '/elements/popup_link_onclick.html', +% 'action' => popurl(2). +% 'edit/cust_main_note.cgi'. +% "?custnum=$custnum". +% ";notenum=$notenum", +% 'actionlabel' => emt('Edit customer note'), +% 'width' => 616, +% 'height' => 538, #575 +% 'frame' => 'top', +% ); +% my $clickjs = qq!onclick="$onclick"!; +% +% my $edit = ''; +% if ($curuser->access_right('Edit customer note') ) { +% my $delete_url = $fsurl.'misc/delete-note.html?'.$notenum; +% $edit = qq! (!.emt('edit').')'. +% qq! !. +% '('.emt('delete').')'; +% } +% +% if ( $last_classnum != $note->classnum && !$skipheader ) { +% my $tmp_classnum = $note->classnum ? $note->classnum : 0; +% $classes{$tmp_classnum} = $note->classname ne '' ? $note->classname +% : emt('Other'); +% if ( $last_classnum != -1 ) { + + +% } +% my $display = ($tmp_classnum == 0 || !$conf->exists('note-classes') +% || $conf->config('note-classes') < 2) +% ? 'block' : 'none'; +
+ <& /elements/table-grid.html &> + + <% mt('Date') |h %> +% if ( $conf->exists('cust_main_note-display_times') ) { + <% mt('Time') |h %> +% } + <% mt('Person') |h %> +% if ($conf->exists('note-classes') && $conf->config('note-classes') == 1) { + <% mt('Class') |h %> +% } + <% mt('Note') |h %> +% if ($curuser->access_right('Edit customer note') ) { +   +% } + +% $skipheader = (!$conf->exists('note-classes') || $conf->config('note-classes') < 2); +% $last_classnum = $note->classnum; +% } + + + <% note_datestr($note,$conf,$bgcolor) %> + +  <% $note->usernum ? $note->access_user->name : $note->otaker %> + +% if ($conf->exists('note-classes') && $conf->config('note-classes') == 1) { + + <% $note->classname %> + +% } + + <% $note->comments | defang %> + +% if($edit) { + <% $edit %> +% } + + +% } #end display notes + + +
+ +% if ( $conf->exists('note-classes') && $conf->config('note-classes') == 2 ) { +% my($classnum,$classname); +<% mt('Show notes of class:') |h %>   +% foreach my $classnum ( sort { $b <=> $a } (keys %classes) ) { + <% $classes{$classnum} %> +% } +
+% } + +% } +<%init> + +use HTML::Defang; + +my $conf = new FS::Conf; +my $curuser = $FS::CurrentUser::CurrentUser; + +my(%opt) = @_; + +my $cust_main = $opt{'cust_main'}; +my $custnum = $cust_main->custnum; + +my (@notes) = $cust_main->notes($conf->exists('note-classes') && $conf->config('note-classes') == 2); + +#subroutines + +sub note_datestr { + my($note, $conf, $bgcolor) = @_ or return ''; + my $td = qq{}; + my $format = "$td%b %o, %Y"; + $format .= "$td%l:%M%P" + if $conf->exists('cust_main_note-display_times'); + ( my $strip = time2str($format, $note->_date) ) =~ s/ (\d)/$1/g; + $strip; +} + + diff --git a/httemplate/view/cust_msg.html b/httemplate/view/cust_msg.html index 67ceef799..91a08ebda 100755 --- a/httemplate/view/cust_msg.html +++ b/httemplate/view/cust_msg.html @@ -1,4 +1,16 @@ <& /elements/header-popup.html &> + + @@ -8,31 +20,35 @@ % if ( $cust_msg->error ) { % } - - +<& /elements/menubar.html, + { 'newstyle' => 1, + 'url_base' => $cgi->self_url . ';part=', + 'selected' => $selected_index, + }, + map { $partnames[$_] => $_ } (0 .. scalar(@parts) - 1), +&>
From:<% $cust_msg->env_from %>
To:<% $env_to %>
Error:<% encode_entities($cust_msg->error) %>
-
- - Header - Body -
-
- - -
+
+% if ( $selected_part->isa('MIME::Entity') ) { +% my $type = $selected_part->mime_type; +% if ( $type =~ /^text/ ) { +%#