From: Mark Wells Date: Wed, 10 Oct 2012 19:24:09 +0000 (-0700) Subject: HTML templates for printable form letters, #17349 X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=963b977d201a71e85781bcbf6732795728e9fc0f HTML templates for printable form letters, #17349 --- diff --git a/FS/FS/Misc.pm b/FS/FS/Misc.pm index 297e39fbc..a1c15fdf8 100644 --- a/FS/FS/Misc.pm +++ b/FS/FS/Misc.pm @@ -799,7 +799,7 @@ sub _pslatex { } -=item print ARRAYREF +=item do_print ARRAYREF Sends the lines in ARRAYREF to the printer. diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 6ad4b742d..fb1f1d69b 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1349,6 +1349,7 @@ sub tables_hashref { 'tagname', 'varchar', '', $char_d, '', '', 'tagdesc', 'varchar', 'NULL', $char_d, '', '', 'tagcolor', 'varchar', 'NULL', 6, '', '', + 'by_default', 'char', 'NULL', 1, '', '', 'disabled', 'char', 'NULL', 1, '', '', ], 'primary_key' => 'tagnum', diff --git a/FS/FS/msg_template.pm b/FS/FS/msg_template.pm index cac7fe572..e38346a66 100644 --- a/FS/FS/msg_template.pm +++ b/FS/FS/msg_template.pm @@ -16,6 +16,9 @@ use Date::Format qw( time2str ); use HTML::Entities qw( decode_entities encode_entities ) ; use HTML::FormatText; use HTML::TreeBuilder; + +use File::Temp; +use IPC::Run qw(run); use vars qw( $DEBUG $conf ); FS::UID->install_callback( sub { $conf = new FS::Conf; } ); @@ -273,8 +276,8 @@ A hash reference of additional substitutions sub prepare { my( $self, %opt ) = @_; - my $cust_main = $opt{'cust_main'}; - my $object = $opt{'object'}; + my $cust_main = $opt{'cust_main'} or die 'cust_main required'; + my $object = $opt{'object'} or die 'object required'; # localization my $locale = $cust_main->locale || ''; @@ -435,9 +438,65 @@ sub send { send_email(generate_email($self->prepare(@_))); } +=item render OPTION => VALUE ... + +Fills in the template and renders it to a PDF document. Returns the +name of the PDF file. + +Options are as for 'prepare', but 'from' and 'to' are meaningless. + +=cut + +# will also have options to set paper size, margins, etc. + +sub render { + my $self = shift; + eval "use PDF::WebKit"; + die $@ if $@; + my %opt = @_; + my %hash = $self->prepare(%opt); + my $html = $hash{'html_body'}; + + my $tmp = 'msg'.$self->msgnum.'-'.time2str('%Y%m%d', time).'-XXXXXXXX'; + my $dir = "$FS::UID::cache_dir/cache.$FS::UID::datasrc"; + + # Graphics/stylesheets should probably go in /var/www on the Freeside + # machine. + my $kit = PDF::WebKit->new(\$html); #%options + # hack to use our wrapper script + $kit->configure(sub { shift->wkhtmltopdf('freeside-wkhtmltopdf') }); + my $fh = File::Temp->new( + TEMPLATE => $tmp, + DIR => $dir, + UNLINK => 0, + SUFFIX => '.pdf' + ); + + print $fh $kit->to_pdf; + close $fh; + return $fh->filename; +} + +=item print OPTIONS + +Render a PDF and send it to the printer. OPTIONS are as for 'render'. + +=cut + +sub print { + my $file = render(@_); + my @lpr = $conf->config('lpr'); + run ([@lpr, '-r'], '<', $file) + or die "lpr error:\n$?\n"; +} + + # helper sub for package dates my $ymd = sub { $_[0] ? time2str('%Y-%m-%d', $_[0]) : '' }; +# helper sub for money amounts +my $money = sub { ($conf->money_char || '$') . sprintf('%.2f', $_[0] || 0) }; + # helper sub for usage-related messages my $usage_warning = sub { my $svc = shift; @@ -483,6 +542,7 @@ sub substitutions { signupdate dundate packages recurdates ), + [ invoicing_email => sub { shift->invoicing_list_emailonly_scalar } ], #compatibility: obsolete ship_ fields - use the non-ship versions map ( { my $field = $_; @@ -520,6 +580,8 @@ sub substitutions { labels_short ), [ pkg => sub { shift->part_pkg->pkg } ], + [ pkg_category => sub { shift->part_pkg->categoryname } ], + [ pkg_class => sub { shift->part_pkg->classname } ], [ cancel => sub { shift->getfield('cancel') } ], # grrr... [ start_ymd => sub { $ymd->(shift->getfield('start_date')) } ], [ setup_ymd => sub { $ymd->(shift->getfield('setup')) } ], @@ -529,6 +591,13 @@ sub substitutions { [ susp_ymd => sub { $ymd->(shift->getfield('susp')) } ], [ expire_ymd => sub { $ymd->(shift->getfield('expire')) } ], [ cancel_ymd => sub { $ymd->(shift->getfield('cancel')) } ], + + # not necessarily correct for non-flat packages + [ setup_fee => sub { shift->part_pkg->option('setup_fee') } ], + [ recur_fee => sub { shift->part_pkg->option('recur_fee') } ], + + [ freq_pretty => sub { shift->part_pkg->freq_pretty } ], + ], 'cust_bill' => [qw( invnum diff --git a/FS/FS/part_event/Action/letter.pm b/FS/FS/part_event/Action/letter.pm new file mode 100644 index 000000000..57b7b7783 --- /dev/null +++ b/FS/FS/part_event/Action/letter.pm @@ -0,0 +1,47 @@ +package FS::part_event::Action::letter; + +use strict; +use base qw( FS::part_event::Action ); +use FS::Record qw( qsearchs ); +use FS::msg_template; + +sub description { 'Print a form letter to the customer' } + +#sub eventtable_hashref { +# { 'cust_main' => 1, +# 'cust_bill' => 1, +# 'cust_pkg' => 1, +# }; +#} + +sub option_fields { + ( + 'msgnum' => { 'label' => 'Template', + 'type' => 'select-table', + 'table' => 'msg_template', + 'name_col' => 'msgname', + 'disable_empty' => 1, + }, + ); +} + +sub default_weight { 56; } #? + +sub do_action { + my( $self, $object ) = @_; + + my $cust_main = $self->cust_main($object); + + my $msgnum = $self->option('msgnum'); + + my $msg_template = qsearchs('msg_template', { 'msgnum' => $msgnum } ) + or die "Template $msgnum not found"; + + $msg_template->print( + 'cust_main' => $cust_main, + 'object' => $object, + ); + +} + +1; diff --git a/FS/FS/part_tag.pm b/FS/FS/part_tag.pm index 0229e3aaa..ed3192969 100644 --- a/FS/FS/part_tag.pm +++ b/FS/FS/part_tag.pm @@ -30,22 +30,17 @@ FS::Record. The following fields are currently supported: =over 4 -=item tagnum +=item tagnum - primary key -primary key +=item tagname - tag name -=item tagname +=item tagdesc - description (can be longer than name) -tagname +=item tagcolor - HTML-style color to display this tag -=item tagdesc - -tagdesc - -=item tagcolor - -tagcolor +=item by_default - 'Y' to enable this tag on new customers +=item disabled =back @@ -111,6 +106,7 @@ sub check { || $self->ut_text('tagname') || $self->ut_textn('tagdesc') || $self->ut_textn('tagcolor') + || $self->ut_enum('by_default', [ '', 'Y' ] ) || $self->ut_enum('disabled', [ '', 'Y' ] ) ; return $error if $error; @@ -120,6 +116,21 @@ sub check { =back +=head1 CLASS METHODS + +=over 4 + +=item default_tags + +Returns the tagnums of all tags that have 'by_default' enabled. + +=cut + +sub default_tags { + my $class = shift; + map { $_->tagnum } qsearch('part_tag', { disabled => '', by_default => 'Y' }); +} + =head1 BUGS =head1 SEE ALSO diff --git a/FS/bin/freeside-wkhtmltopdf b/FS/bin/freeside-wkhtmltopdf new file mode 100755 index 000000000..c6c5531a5 --- /dev/null +++ b/FS/bin/freeside-wkhtmltopdf @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ $DISPLAY ] ; then + wkhtmltopdf $@ +else + xvfb-run -- wkhtmltopdf $@ +fi diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index e3e812f19..2628b4e01 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -315,6 +315,8 @@ if ( $cgi->param('error') ) { $stateid = ''; $payinfo = ''; + $cgi->param('tagnum', FS::part_tag->default_tags); + if ( $cgi->param('qualnum') =~ /^(\d+)$/ ) { my $qualnum = $1; my $qual = qsearchs('qual', { 'qualnum' => $qualnum } ) diff --git a/httemplate/edit/part_tag.html b/httemplate/edit/part_tag.html index 2caeb27a0..5712560c1 100644 --- a/httemplate/edit/part_tag.html +++ b/httemplate/edit/part_tag.html @@ -5,12 +5,14 @@ { field=>'tagname', type=>'text', size=>10 }, { field=>'disabled', type=>'checkbox', value=>'Y' }, { field=>'tagdesc', type=>'text', size=>60 }, + { field=>'by_default', type=>'checkbox', value=>'Y' }, $tagcolor, ], 'labels' => { 'tagnum' => 'Tag #', 'tagname' => 'Tag', 'tagdesc' => 'Message', 'tagcolor' => 'Highlight Color', + 'by_default' => 'On by default', 'disabled' => 'Disabled', }, 'viewall_dir' => 'browse', diff --git a/httemplate/edit/process/msg_template.html b/httemplate/edit/process/msg_template.html index b19f5c542..e146adf76 100644 --- a/httemplate/edit/process/msg_template.html +++ b/httemplate/edit/process/msg_template.html @@ -29,6 +29,8 @@ sub args_callback { # no validation of these; they can contain just about anything $content{'subject'} = $cgi->param('subject') || ''; $content{'body'} = $cgi->param('body') || ''; + $object->subject(''); + $object->body(''); return %content; } diff --git a/httemplate/elements/tr-select-cust_tag.html b/httemplate/elements/tr-select-cust_tag.html index 5312644ef..76b1b715d 100644 --- a/httemplate/elements/tr-select-cust_tag.html +++ b/httemplate/elements/tr-select-cust_tag.html @@ -28,7 +28,7 @@ my $cgi = $opt{'cgi'}; my $is_report = $opt{'is_report'}; my @curr_tagnum = (); -if ( $cgi && $cgi->param('error') ) { +if ( $cgi && $cgi->param('tagnum') ) { @curr_tagnum = $cgi->param('tagnum'); } elsif ( $opt{'custnum'} ) { @curr_tagnum = map $_->tagnum,