From: Mark Wells Date: Sun, 30 Aug 2015 04:27:20 +0000 (-0700) Subject: #21564: user interface for REST client X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=9fd03716b831bd00a725a63edbe19cfe6b88aea0 #21564: user interface for REST client --- diff --git a/FS/FS/msg_template.pm b/FS/FS/msg_template.pm index 827bb9883..4c2ac4bd4 100644 --- a/FS/FS/msg_template.pm +++ b/FS/FS/msg_template.pm @@ -5,7 +5,7 @@ use strict; use vars qw( $DEBUG $conf ); use FS::Conf; -use FS::Record qw( qsearch qsearchs ); +use FS::Record qw( qsearch qsearchs dbh ); use FS::cust_msg; use FS::template_content; @@ -95,11 +95,16 @@ sub _rebless { eval "use $class;"; bless($self, $class) unless $@; - # merge in the extension fields + # merge in the extension fields (but let fields in $self override them) + # except don't ever override the extension's primary key, it's immutable if ( $self->msgnum and $self->extension_table ) { my $extension = $self->_extension; if ( $extension ) { - $self->{Hash} = { $self->hash, $extension->hash }; + my $ext_key = $extension->get($extension->primary_key); + $self->{Hash} = { $extension->hash, + $self->hash, + $extension->primary_key => $ext_key + }; } } @@ -194,6 +199,8 @@ sub replace { my $extension = $new->_extension; if ( $extension ) { + # merge changes into the extension record and replace it + $extension->{Hash} = { $extension->hash, $new->hash }; $error ||= $extension->replace; } @@ -212,7 +219,7 @@ sub replace_check { if ( $old->msgclass ) { if ( !$self->msgclass ) { $self->set('msgclass', $old->msgclass); - } else { + } elsif ( $old->msgclass ne $self->msgclass ) { return "Can't change message template class from ".$old->msgclass. " to ".$self->msgclass."."; } diff --git a/httemplate/browse/msg_template.html b/httemplate/browse/msg_template.html deleted file mode 100644 index 1646bc169..000000000 --- a/httemplate/browse/msg_template.html +++ /dev/null @@ -1,65 +0,0 @@ -<% include( 'elements/browse.html', - 'title' => 'Message templates', - 'name_singular' => 'template', - 'menubar' => \@menubar, - 'query' => { 'table' => 'msg_template', }, - 'count_query' => 'SELECT COUNT(*) FROM msg_template', - 'disableable' => 1, - 'disabled_statuspos' => (scalar(@locales) + 3), - 'agent_virt' => 1, - 'agent_null_right' => ['View global templates','Edit global templates'], - 'agent_pos' => 1, - 'header' => [ 'Name', '', map ('', @locales), '' ], - 'fields' => [ 'msgname', @locales, $disable_link_label ], - 'links' => [ $link, @locale_links, '' ], - 'link_onclicks' => [ '', map('', @locale_links), $disable_link ], - 'cell_style' => [ '', '', map ($locale_style, @locales), $locale_style ], - ) -%> -<%init> - -my $curuser = $FS::CurrentUser::CurrentUser; - -die "access denied" - unless $curuser->access_right([ 'View templates', 'View global templates', - 'Edit templates', 'Edit global templates', ]); - -my @menubar = (); -if ( $curuser->access_right(['Edit templates', 'Edit global templates']) ) { - push @menubar, 'Add a new template' => $p.'edit/msg_template.html'; -} -push @menubar, 'View template images' => $p.'browse/template_image.html'; - -my $link = [ "${p}edit/msg_template.html?msgnum=", 'msgnum' ]; - -my $locale_style = 'font-size:0.8em; padding:3px'; - -my (@locales, @locale_links); -foreach my $l ( FS::Locales->locales ) { - push @locales, sub { - exists ( $_[0]->content_locales->{$l} ) - ? +{ FS::Locales->locale_info($l) }->{'label'} - : ''; - }; - push @locale_links, sub { - my $content = $_[0]->content_locales->{$l} or return ''; - [ "${p}edit/msg_template.html?locale=$l;msgnum=", 'msgnum' ]; - }; -} - -my $disable_link = sub { - my $template = shift; - include('/elements/popup_link_onclick.html', - action => $p.'misc/disable-msg_template.cgi?msgnum=' . - $template->msgnum . - ($template->disabled ? ';enable=1' : ''), - actionlabel => 'Disable template', - ); -}; - -my $disable_link_label = sub { - my $template = shift; - $template->disabled ? '(enable)' : '(disable)' ; -}; - - diff --git a/httemplate/browse/msg_template/email.html b/httemplate/browse/msg_template/email.html new file mode 100644 index 000000000..d0ef4e3e9 --- /dev/null +++ b/httemplate/browse/msg_template/email.html @@ -0,0 +1,74 @@ +<& /browse/elements/browse.html, + 'title' => 'Message templates', + 'name_singular' => 'template', + 'menubar' => \@menubar, + 'query' => $query, + 'count_query' => $count_query, + 'disableable' => 1, + 'disabled_statuspos' => (scalar(@locales) + 3), + 'agent_virt' => 1, + 'agent_null_right' => ['View global templates','Edit global templates'], + 'agent_pos' => 1, + 'header' => [ 'Name', '', map ('', @locales), '' ], + 'fields' => [ 'msgname', @locales, $disable_link_label ], + 'links' => [ $link, @locale_links, '' ], + 'link_onclicks' => [ '', map('', @locale_links), $disable_link ], + 'cell_style' => [ '', '', map ($locale_style, @locales), $locale_style ], +&> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', ]); + +my @menubar = (); +if ( $curuser->access_right(['Edit templates', 'Edit global templates']) ) { + push @menubar, 'Add a new template' => $fsurl.'edit/msg_template/email.html'; +} +push @menubar, 'Template images' => $fsurl.'browse/template_image.html'; + +push @menubar, 'External message interfaces' => $fsurl.'browse/msg_template/http.html'; + +my $query = { + 'table' => 'msg_template', + 'select' => '*', + 'hashref' => { 'msgclass' => 'email' }, +}; + +my $count_query = "SELECT COUNT(*) FROM msg_template WHERE msgclass = 'email'"; + +my $link = [ $fsurl.'edit/msg_template/email.html?msgnum=', 'msgnum' ]; + +my $locale_style = 'font-size:0.8em; padding:3px'; + +my (@locales, @locale_links); +foreach my $l ( FS::Locales->locales ) { + push @locales, sub { + exists ( $_[0]->content_locales->{$l} ) + ? +{ FS::Locales->locale_info($l) }->{'label'} + : ''; + }; + push @locale_links, sub { + my $content = $_[0]->content_locales->{$l} or return ''; + [ $fsurl."edit/msg_template/email.html?locale=$l;msgnum=", 'msgnum' ]; + }; +} + +my $disable_link = sub { + my $template = shift; + include('/elements/popup_link_onclick.html', + action => $fsurl.'misc/disable-msg_template.cgi?msgnum=' . + $template->msgnum . + ($template->disabled ? ';enable=1' : ''), + actionlabel => 'Disable template', + ); +}; + +my $disable_link_label = sub { + my $template = shift; + $template->disabled ? '(enable)' : '(disable)' ; +}; + + diff --git a/httemplate/browse/msg_template/http.html b/httemplate/browse/msg_template/http.html new file mode 100644 index 000000000..888fda441 --- /dev/null +++ b/httemplate/browse/msg_template/http.html @@ -0,0 +1,68 @@ +<& /browse/elements/browse.html, + 'title' => 'External message interfaces', + 'name_singular' => 'interface', # what else do we call them? + 'menubar' => \@menubar, + 'query' => $query, + 'count_query' => $count_query, + 'disableable' => 1, + 'disabled_statuspos' => 4, + 'agent_virt' => 1, + 'agent_null_right' => ['View global templates','Edit global templates'], + 'agent_pos' => 1, + 'header' => [ 'Name', + # 'Agent', + 'Prepare', + 'Send', + '' ], + 'fields' => [ 'msgname', + 'prepare_url', + 'send_url', + $disable_link_label + ], + 'links' => [ $link, ], + 'link_onclicks' => [ '', '', '', $disable_link ], + 'cell_style' => [ '', '', $url_style, $url_style ], +&> +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', ]); + +my @menubar = (); +if ( $curuser->access_right(['Edit templates', 'Edit global templates']) ) { + push @menubar, 'Add a new interface' => $fsurl.'edit/msg_template/http.html'; +} +push @menubar, 'Email templates' => $fsurl.'browse/msg_template/email.html'; +push @menubar, 'Template images' => $fsurl.'browse/template_image.html'; + +my $query = { + 'table' => 'msg_template', + 'select' => '*', + 'hashref' => { 'msgclass' => 'http' }, +}; + +my $count_query = "SELECT COUNT(*) FROM msg_template WHERE msgclass = 'http'"; + +my $link = [ $fsurl.'edit/msg_template/http.html?msgnum=', 'msgnum' ]; + +my $url_style = 'font-size:0.8em; padding:3px'; # also for (disable) label + +my $disable_link = sub { + my $template = shift; + include('/elements/popup_link_onclick.html', + action => $fsurl.'misc/disable-msg_template.cgi?msgnum=' . + $template->msgnum . + ($template->disabled ? ';enable=1' : ''), + actionlabel => 'Disable template', + ); +}; + +my $disable_link_label = sub { + my $template = shift; + $template->disabled ? '(enable)' : '(disable)' ; +}; + + diff --git a/httemplate/edit/msg_template.html b/httemplate/edit/msg_template.html index df72c5b66..889b10731 100644 --- a/httemplate/edit/msg_template.html +++ b/httemplate/edit/msg_template.html @@ -1,380 +1,9 @@ -<& elements/edit.html, - 'html_init' => '$sidebar
', - 'body_etc' => $body_etc, - 'name_singular' => 'template', - 'table' => 'msg_template', - 'viewall_dir' => 'browse', - 'agent_virt' => 1, - 'agent_null' => 1, - 'agent_null_right' => [ 'View global templates', 'Edit global templates' ], - - 'fields' => \@fields, - 'labels' => { - 'msgnum' => 'Template', - 'agentnum' => 'Agent', - 'msgname' => 'Template name', - 'from_addr' => 'From: ', - 'bcc_addr' => 'Bcc: ', - 'locale' => 'Locale', - 'subject' => 'Subject: ', - 'body' => 'Message body', - }, - 'edit_callback' => \&edit_callback, - 'error_callback' => \&edit_callback, - 'html_bottom' => '', - 'html_table_bottom'=> \&html_table_bottom, - 'html_foot' => ( $no_submit ? '' : "
" ), - 'no_submit' => $no_submit, -&> <%init> -use FS::template_image; - -my $curuser = $FS::CurrentUser::CurrentUser; - -die "access denied" - unless $curuser->access_right([ 'View templates', 'View global templates', - 'Edit templates', 'Edit global templates', - ]); - -my $body_etc = ''; -$body_etc = q!onload="document.getElementById('locale').onchange()"! - if $cgi->param('locale') eq 'new'; - -my $msgnum = $cgi->param('msgnum'); -my $msg_template = $msgnum ? qsearchs('msg_template', {msgnum=>$msgnum}) : ''; - -my $no_submit = 0; -my @fields = (); -if ( $curuser->access_right('Edit global templates') - || ( $curuser->access_right('Edit templates') - && $msg_template - && $msg_template->agentnum - && $curuser->agentnums_href->{$msg_template->agentnum} - ) - ) -{ - push @fields, - { field => 'agentnum', - type => 'select-agent', - }, - { field => 'msgname', size=>60, }, - { field => 'from_addr', size=>60, }, - { field => 'bcc_addr', size=>60, }, - { type => 'tablebreak-tabs', - include_opt_callback => \&menubar_opt_callback, - }, - # template_content fields - { field => 'locale', type => 'hidden' }, - { field => 'subject', size=>60, }, - { field => 'body', - type => 'htmlarea', - width => 763, - config=> { extraPlugins => 'blockprotect' }, - }, - ; -} else { #readonly - - $no_submit = 1; - - push @fields, - { field => 'agentnum', - type => 'select-agent', - fixed => 1, - }, - { field => 'msgname', type => 'fixed', }, - { field => 'from_addr', type => 'fixed', }, - { field => 'bcc_addr', type => 'fixed', }, - { type => 'tablebreak-tabs', - include_opt_callback => \&menubar_opt_callback, - }, - # template_content fields - { field => 'locale', type => 'hidden' }, - { field => 'subject', type => 'fixed', }, - { field => 'body', - type => 'fixed', - noescape => 1, - }, - ; - +my $msgclass = 'email'; +if ( $cgi->param('msgnum') =~ /^(\d+)$/ ) { + my $msg_template = FS::msg_template->by_key($1) + or die "unknown msgnum $1"; + $msgclass = $msg_template->msgclass; } - -sub new_callback { - my ($cgi, $object, $fields_listref, $opt_hashref) = @_; - my $template_content = new FS::template_content { 'locale' => '' }; - $object->{'Hash'} = { $object->hash, $template_content->hash }; -} - -sub edit_callback { - my ($cgi, $object, $fields_listref, $opt_hashref) = @_; - $cgi->param('locale') =~ /^(\w*)$/ or die 'bad locale '.$cgi->param('locale'); - my $locale = $1; - - # fetch the content object and merge its fields - my %args = ( - 'msgnum' => $object->msgnum, - 'locale' => $locale - ); - my $template_content = qsearchs('template_content', \%args) - || new FS::template_content( { %args }); - $object->{'Hash'} = { $object->hash, $template_content->hash }; - - # set up the locale selector if this is a new content - if ( $locale eq 'new' ) { - - # make a list of available locales - my $content_locales = $object->content_locales; - my @locales = grep { !exists($content_locales->{$_}) } - FS::Conf->new->config('available-locales'); - my %labels; - foreach (@locales) { - my %info = FS::Locales->locale_info($_); - $labels{$_} = $info{'label'}; - } - unshift @locales, 'new'; - $labels{'new'} = 'Select language'; - - # insert a field def - my $i = 0; - $i++ until ( $fields_listref->[$i]->{'field'} eq 'locale' ); - my $locale_field = $fields_listref->[$i]; - - my $onchange_locale = "document.getElementById('submit').disabled = - (this.options[this.selectedIndex].value == 'new');"; - - %$locale_field = ( - field => 'locale', - type => 'select', - options => \@locales, - labels => \%labels, - curr_value => 'new', - onchange => $onchange_locale, - ); - } -} - -sub menubar_opt_callback { - my $object = shift; - # generate no tabs for new msg_templates. - my $msgnum = $object->msgnum or return; - my (@tabs, @options, %labels); - push @tabs, mt('Default'), ''; - my $display_new = 0; - my $selected = ''; - foreach my $l (FS::Locales->locales) { - if ( exists $object->content_locales->{$l} ) { - my %info = FS::Locales->locale_info($l); - push @tabs, - $info{'label'}, - ';locale='.$l; - $selected = $info{'label'} if $object->locale eq $l; - } - else { - $display_new = 1; # there is at least one unused locale left - } - } - push @tabs, mt('New'), ';locale=new' if $display_new; - $selected = mt('New') if $object->locale eq 'new'; - $selected ||= mt('Default'); - ( - 'url_base' => $p.'edit/msg_template.html?msgnum='.$msgnum, - 'selected' => $selected, - 'tabs' => \@tabs - ); -} - -my $onchange_locale = ''; - -# Create hints pane - -my %substitutions = ( - 'cust_main' => [ - '$display_custnum'=> 'Customer#', - '$agentnum' => 'Agent#', - '$agent_name' => 'Agent name', - '$payby' => 'Payment method', - '$paymask' => 'Card/account# (masked)', - '$payname' => 'Name on card/bank name', - '$paytype' => 'Account type', - '$payip' => 'IP address used to submit payment info', - '$num_ncancelled_pkgs' => '# of active packages', - '$num_cancelled_pkgs' => '# of cancelled packages', - '$num_pkgs' => '# of packages', - '$classname' => 'Customer class', - '$categoryname' => 'Customer category', - '$balance' => 'Current balance', - '$credit_limit' => 'Credit limit', - '$invoicing_list_emailonly' => 'Billing email address', - #'$cust_status' => 'Status (raw internal label)', - '$cust_status_label' => 'Status (display label)', - '$cust_statuscolor' => 'Status color code', - '$company_name' => 'Our company name', - '$company_address'=> 'Our company address', - '$company_phonenum' => 'Our phone number', - '$selfservice_server_base_url' => 'Base URL of customer self-service', - ], - 'contact' => [ # duplicate this for shipping - '$name' => 'Company and contact name', - '$name_short' => 'Company or contact name', - '$company' => 'Company name', - '$contact' => 'Contact name (last, first)', - '$contact_firstlast'=> 'Contact name (first last)', - '$first' => 'First name', - '$last' => 'Last name', - '$address1' => 'Address line 1', - '$address2' => 'Address line 2', - '$city' => 'City', - '$county' => 'County', - '$state' => 'State', - '$zip' => 'Zip', - '$country' => 'Country', - '$daytime' => 'Day phone', - '$night' => 'Night phone', - '$mobile' => 'Mobile phone', - '$fax' => 'Fax', - ], - 'service' => [ - '$ship_address1' => 'Address line 1', - '$ship_address2' => 'Address line 2', - '$ship_city' => 'City', - '$ship_county' => 'County', - '$ship_state' => 'State', - '$ship_zip' => 'Zip', - '$ship_country' => 'Country', - ], - 'cust_bill' => [ - '$invnum' => 'Invoice#', - '$_date_pretty' => 'Invoice date', - '$due_date' => 'Invoice due date (timestamp)', - '$due_date2str' => 'Invoice due date (human readable)', - ], - 'cust_pkg' => [ - '$pkgnum' => 'Package#', - '$pkg' => 'Package description', - '$pkg_label' => 'Description + comment', - '$status' => 'Status', - '$statuscolor' => 'Status color code', - '$start_ymd' => 'Start date', - '$setup_ymd' => 'Setup date', - '$last_bill_ymd' => 'Last bill date', - '$next_bill_ymd' => 'Next bill date', - '$susp_ymd' => 'Suspended on date', - '$cancel_ymd' => 'Canceled on date', - '$adjourn_ymd' => 'Adjournment date', - '$expire_ymd' => 'Expiration date', - '$labels_short' => 'Service labels', - '$location_label' => 'Service location', - ], - 'svc_acct' => [ - '$svcnum' => 'Service#', - '$username' => 'Login name', - '$password' => 'Password', - '$domain' => 'Domain name', - ], - 'svc_domain' => [ - '$svcnum' => 'Service#', - '$domain' => 'Domain name', - '$registrar' => 'Registrar name', - '$catchall' => 'Catchall email', - ], - 'svc_phone' => [ - '$svcnum' => 'Service#', - '$phonenum' => 'Phone number', - '$countrycode' => 'Country code', - '$domain' => 'Domain name' - ], - 'svc_broadband' => [ - '$svcnum' => 'Service#', - '$ip_addr' => 'IP address', - '$mac_addr' => 'MAC address', - '$speed_up' => 'Upstream speed', - '$speed_down' => 'Downstream speed', - ], - 'cust_pay' => [ - '$paynum' => 'Payment#', - '$paid' => 'Amount', - '$payby' => 'Payment method', - '$date' => 'Payment date', - '$payinfo' => 'Card/account# (masked)', - '$error' => 'Decline reason', - ], -); - -tie my %sections, 'Tie::IxHash', ( -'contact' => 'Name and contact info (billing)', -'service' => 'Service address', -'cust_main' => 'Customer status and payment info', -'cust_pkg' => 'Package fields', -'cust_bill' => 'Invoice fields', -'cust_pay' => 'Payment fields', -'svc_acct' => 'Login service fields', -'svc_domain'=> 'Domain service fields', -'svc_phone' => 'Phone service fields', -'svc_broadband' => 'Broadband service fields', -); - -my $widget = new HTML::Widgets::SelectLayers( - 'options' => \%sections, - 'form_name' => 'dummy', - 'html_between'=>'', - 'selected_layer'=>(keys(%sections))[0], - 'layer_callback' => sub { - my $section = shift; - my $html = include('/elements/table-grid.html'); - my @hints = @{ $substitutions{$section} }; - while(@hints) { - my $key = shift @hints; - $html .= qq!\n$key!; - $html .= "\n".shift(@hints).''; - } - $html .= "\n"; - return $html; - }, -); - -my $sidebar = ' - -
-Substitutions: ' -. $widget->html . -'

Click above links to insert substitution code.

-

-Enclose substitutions and other Perl expressions in braces: -
{ $name } = ExampleCo (Smith, John) -
{ time2str("%D", time) } = '.time2str("%D", time).' -

'; -$sidebar .= include('/elements/template_image-dialog.html', - 'callback' => 'insertHtml' - ); -$sidebar .= '

Insert Uploaded Image

-
-'; - -sub html_table_bottom { - my $object = shift; - $cgi->param('locale') =~ /^(\w+)$/; - my $locale = $1; - my $html; - if ( $locale and $locale ne 'new' ) { - # set up a delete link - my $msgnum = $object->msgnum; - my $url = $p."misc/delete-template_content.html?msgnum=$msgnum;locale=$1"; - my $link = qq!! . - 'Delete this template' . - ''; - $html = qq! - $link!; - } - $html; -} - +print $cgi->redirect($fsurl."edit/msg_template/$msgclass.html?".$cgi->query_string); diff --git a/httemplate/edit/msg_template/email.html b/httemplate/edit/msg_template/email.html new file mode 100644 index 000000000..dc70ef6ec --- /dev/null +++ b/httemplate/edit/msg_template/email.html @@ -0,0 +1,385 @@ +<& /edit/elements/edit.html, + 'post_url' => $fsurl.'edit/process/msg_template.html', + 'html_init' => '$sidebar
', + 'body_etc' => $body_etc, + 'name_singular' => 'template', + 'table' => 'msg_template', + 'viewall_dir' => 'browse', + 'agent_virt' => 1, + 'agent_null' => 1, + 'agent_null_right' => [ 'View global templates', 'Edit global templates' ], + + 'fields' => \@fields, + 'labels' => { + 'msgnum' => 'Template', + 'agentnum' => 'Agent', + 'msgname' => 'Template name', + 'from_addr' => 'From: ', + 'bcc_addr' => 'Bcc: ', + 'locale' => 'Locale', + 'subject' => 'Subject: ', + 'body' => 'Message body', + }, + 'edit_callback' => \&edit_callback, + 'error_callback' => \&edit_callback, + 'html_bottom' => '', + 'html_table_bottom'=> \&html_table_bottom, + 'html_foot' => ( $no_submit ? '' : "
" ), + 'no_submit' => $no_submit, +&> +<%init> +use FS::template_image; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', + ]); + +my $body_etc = ''; +$body_etc = q!onload="document.getElementById('locale').onchange()"! + if $cgi->param('locale') eq 'new'; + +my $msgnum = $cgi->param('msgnum'); +my $msg_template = $msgnum ? qsearchs('msg_template', {msgnum=>$msgnum}) : ''; + +my $no_submit = 0; +my @fields = (); +if ( $curuser->access_right('Edit global templates') + || ( $curuser->access_right('Edit templates') + && $msg_template + && $msg_template->agentnum + && $curuser->agentnums_href->{$msg_template->agentnum} + ) + ) +{ + push @fields, + { field => 'msgclass', + type => 'hidden', + value => 'email', + }, + { field => 'agentnum', + type => 'select-agent', + }, + { field => 'msgname', size=>60, }, + { field => 'from_addr', size=>60, }, + { field => 'bcc_addr', size=>60, }, + { type => 'tablebreak-tabs', + include_opt_callback => \&menubar_opt_callback, + }, + # template_content fields + { field => 'locale', type => 'hidden' }, + { field => 'subject', size=>60, }, + { field => 'body', + type => 'htmlarea', + width => 763, + config=> { extraPlugins => 'blockprotect' }, + }, + ; +} else { #readonly + + $no_submit = 1; + + push @fields, + { field => 'agentnum', + type => 'select-agent', + fixed => 1, + }, + { field => 'msgname', type => 'fixed', }, + { field => 'from_addr', type => 'fixed', }, + { field => 'bcc_addr', type => 'fixed', }, + { type => 'tablebreak-tabs', + include_opt_callback => \&menubar_opt_callback, + }, + # template_content fields + { field => 'locale', type => 'hidden' }, + { field => 'subject', type => 'fixed', }, + { field => 'body', + type => 'fixed', + noescape => 1, + }, + ; + +} + +sub new_callback { + my ($cgi, $object, $fields_listref, $opt_hashref) = @_; + my $template_content = new FS::template_content { 'locale' => '' }; + $object->{'Hash'} = { $object->hash, $template_content->hash }; +} + +sub edit_callback { + my ($cgi, $object, $fields_listref, $opt_hashref) = @_; + $cgi->param('locale') =~ /^(\w*)$/ or die 'bad locale '.$cgi->param('locale'); + my $locale = $1; + + # fetch the content object and merge its fields + my %args = ( + 'msgnum' => $object->msgnum, + 'locale' => $locale + ); + my $template_content = qsearchs('template_content', \%args) + || new FS::template_content( { %args }); + $object->{'Hash'} = { $object->hash, $template_content->hash }; + + # set up the locale selector if this is a new content + if ( $locale eq 'new' ) { + + # make a list of available locales + my $content_locales = $object->content_locales; + my @locales = grep { !exists($content_locales->{$_}) } + FS::Conf->new->config('available-locales'); + my %labels; + foreach (@locales) { + my %info = FS::Locales->locale_info($_); + $labels{$_} = $info{'label'}; + } + unshift @locales, 'new'; + $labels{'new'} = 'Select language'; + + # insert a field def + my $i = 0; + $i++ until ( $fields_listref->[$i]->{'field'} eq 'locale' ); + my $locale_field = $fields_listref->[$i]; + + my $onchange_locale = "document.getElementById('submit').disabled = + (this.options[this.selectedIndex].value == 'new');"; + + %$locale_field = ( + field => 'locale', + type => 'select', + options => \@locales, + labels => \%labels, + curr_value => 'new', + onchange => $onchange_locale, + ); + } +} + +sub menubar_opt_callback { + my $object = shift; + # generate no tabs for new msg_templates. + my $msgnum = $object->msgnum or return; + my (@tabs, @options, %labels); + push @tabs, mt('Default'), ''; + my $display_new = 0; + my $selected = ''; + foreach my $l (FS::Locales->locales) { + if ( exists $object->content_locales->{$l} ) { + my %info = FS::Locales->locale_info($l); + push @tabs, + $info{'label'}, + ';locale='.$l; + $selected = $info{'label'} if $object->locale eq $l; + } + else { + $display_new = 1; # there is at least one unused locale left + } + } + push @tabs, mt('New'), ';locale=new' if $display_new; + $selected = mt('New') if $object->locale eq 'new'; + $selected ||= mt('Default'); + ( + 'url_base' => $fsurl.'edit/msg_template.html?msgnum='.$msgnum, + 'selected' => $selected, + 'tabs' => \@tabs + ); +} + +my $onchange_locale = ''; + +# Create hints pane + +my %substitutions = ( + 'cust_main' => [ + '$display_custnum'=> 'Customer#', + '$agentnum' => 'Agent#', + '$agent_name' => 'Agent name', + '$payby' => 'Payment method', + '$paymask' => 'Card/account# (masked)', + '$payname' => 'Name on card/bank name', + '$paytype' => 'Account type', + '$payip' => 'IP address used to submit payment info', + '$num_ncancelled_pkgs' => '# of active packages', + '$num_cancelled_pkgs' => '# of cancelled packages', + '$num_pkgs' => '# of packages', + '$classname' => 'Customer class', + '$categoryname' => 'Customer category', + '$balance' => 'Current balance', + '$credit_limit' => 'Credit limit', + '$invoicing_list_emailonly' => 'Billing email address', + #'$cust_status' => 'Status (raw internal label)', + '$cust_status_label' => 'Status (display label)', + '$cust_statuscolor' => 'Status color code', + '$company_name' => 'Our company name', + '$company_address'=> 'Our company address', + '$company_phonenum' => 'Our phone number', + '$selfservice_server_base_url' => 'Base URL of customer self-service', + ], + 'contact' => [ # duplicate this for shipping + '$name' => 'Company and contact name', + '$name_short' => 'Company or contact name', + '$company' => 'Company name', + '$contact' => 'Contact name (last, first)', + '$contact_firstlast'=> 'Contact name (first last)', + '$first' => 'First name', + '$last' => 'Last name', + '$address1' => 'Address line 1', + '$address2' => 'Address line 2', + '$city' => 'City', + '$county' => 'County', + '$state' => 'State', + '$zip' => 'Zip', + '$country' => 'Country', + '$daytime' => 'Day phone', + '$night' => 'Night phone', + '$mobile' => 'Mobile phone', + '$fax' => 'Fax', + ], + 'service' => [ + '$ship_address1' => 'Address line 1', + '$ship_address2' => 'Address line 2', + '$ship_city' => 'City', + '$ship_county' => 'County', + '$ship_state' => 'State', + '$ship_zip' => 'Zip', + '$ship_country' => 'Country', + ], + 'cust_bill' => [ + '$invnum' => 'Invoice#', + '$_date_pretty' => 'Invoice date', + '$due_date' => 'Invoice due date (timestamp)', + '$due_date2str' => 'Invoice due date (human readable)', + ], + 'cust_pkg' => [ + '$pkgnum' => 'Package#', + '$pkg' => 'Package description', + '$pkg_label' => 'Description + comment', + '$status' => 'Status', + '$statuscolor' => 'Status color code', + '$start_ymd' => 'Start date', + '$setup_ymd' => 'Setup date', + '$last_bill_ymd' => 'Last bill date', + '$next_bill_ymd' => 'Next bill date', + '$susp_ymd' => 'Suspended on date', + '$cancel_ymd' => 'Canceled on date', + '$adjourn_ymd' => 'Adjournment date', + '$expire_ymd' => 'Expiration date', + '$labels_short' => 'Service labels', + '$location_label' => 'Service location', + ], + 'svc_acct' => [ + '$svcnum' => 'Service#', + '$username' => 'Login name', + '$password' => 'Password', + '$domain' => 'Domain name', + ], + 'svc_domain' => [ + '$svcnum' => 'Service#', + '$domain' => 'Domain name', + '$registrar' => 'Registrar name', + '$catchall' => 'Catchall email', + ], + 'svc_phone' => [ + '$svcnum' => 'Service#', + '$phonenum' => 'Phone number', + '$countrycode' => 'Country code', + '$domain' => 'Domain name' + ], + 'svc_broadband' => [ + '$svcnum' => 'Service#', + '$ip_addr' => 'IP address', + '$mac_addr' => 'MAC address', + '$speed_up' => 'Upstream speed', + '$speed_down' => 'Downstream speed', + ], + 'cust_pay' => [ + '$paynum' => 'Payment#', + '$paid' => 'Amount', + '$payby' => 'Payment method', + '$date' => 'Payment date', + '$payinfo' => 'Card/account# (masked)', + '$error' => 'Decline reason', + ], +); + +tie my %sections, 'Tie::IxHash', ( +'contact' => 'Name and contact info (billing)', +'service' => 'Service address', +'cust_main' => 'Customer status and payment info', +'cust_pkg' => 'Package fields', +'cust_bill' => 'Invoice fields', +'cust_pay' => 'Payment fields', +'svc_acct' => 'Login service fields', +'svc_domain'=> 'Domain service fields', +'svc_phone' => 'Phone service fields', +'svc_broadband' => 'Broadband service fields', +); + +my $widget = new HTML::Widgets::SelectLayers( + 'options' => \%sections, + 'form_name' => 'dummy', + 'html_between'=>'
', + 'selected_layer'=>(keys(%sections))[0], + 'layer_callback' => sub { + my $section = shift; + my $html = include('/elements/table-grid.html'); + my @hints = @{ $substitutions{$section} }; + while(@hints) { + my $key = shift @hints; + $html .= qq!\n$key!; + $html .= "\n".shift(@hints).''; + } + $html .= "\n"; + return $html; + }, +); + +my $sidebar = ' + +
+Substitutions: ' +. $widget->html . +'

Click above links to insert substitution code.

+

+Enclose substitutions and other Perl expressions in braces: +
{ $name } = ExampleCo (Smith, John) +
{ time2str("%D", time) } = '.time2str("%D", time).' +

'; +$sidebar .= include('/elements/template_image-dialog.html', + 'callback' => 'insertHtml' + ); +$sidebar .= '

Insert Uploaded Image

+
+'; + +sub html_table_bottom { + my $object = shift; + $cgi->param('locale') =~ /^(\w+)$/; + my $locale = $1; + my $html; + if ( $locale and $locale ne 'new' ) { + # set up a delete link + my $msgnum = $object->msgnum; + my $url = $fsurl."misc/delete-template_content.html?msgnum=$msgnum;locale=$1"; + my $link = qq!! . + 'Delete this template' . + ''; + $html = qq! + $link!; + } + $html; +} + + diff --git a/httemplate/edit/msg_template/http.html b/httemplate/edit/msg_template/http.html new file mode 100644 index 000000000..e82cc0c60 --- /dev/null +++ b/httemplate/edit/msg_template/http.html @@ -0,0 +1,82 @@ +<& /edit/elements/edit.html, + 'post_url' => $fsurl.'edit/process/msg_template.html', + 'name_singular' => 'message interface', + 'table' => 'msg_template', + 'viewall_dir' => 'browse', + 'agent_virt' => 1, + 'agent_null' => 1, + 'agent_null_right' => [ 'View global templates', 'Edit global templates' ], + + 'fields' => [], # callback takes care of this + 'new_callback' => $edit_callback, + 'edit_callback' => $edit_callback, + 'error_callback' => $edit_callback, + 'labels' => \%labels, + 'no_submit' => $no_submit, +&> +<%init> +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', + ]); + +my %labels = ( + 'msgnum' => 'Template', # it's still a template number + 'agentnum' => 'Agent', + 'msgname' => 'Interface name', + 'prepare_url' => 'Prepare URL', + 'send_url' => 'Send URL', + 'username' => 'HTTP username', + 'password' => 'HTTP password', + 'content' => 'Additional POST content', +); + +my $no_submit = 0; + +my $edit_callback = sub { + my ($cgi, $msg_template, $fields, $opt) = @_; + if ( $curuser->access_right('Edit global templates') + || ( $curuser->access_right('Edit templates') + && $msg_template + && $msg_template->agentnum + && $curuser->agentnums_href->{$msg_template->agentnum} + ) + ) { + @$fields = ( + { field => 'msgclass', + type => 'hidden', + value => 'http', + }, + { field => 'agentnum', + type => 'select-agent', + }, + { field => 'msgname', size=>60, required => 1 }, + { field => 'prepare_url', size=>60, required => 1 }, + { field => 'send_url', size=>60, required => 1 }, + { field => 'username', size=>20 }, + { field => 'password', size=>20 }, + { field => 'content', type => 'textarea' }, + ); + } else { #readonly + + $no_submit = 1; + + @$fields = ( + { field => 'agentnum', + type => 'select-agent', + fixed => 1, + }, + { field => 'msgname', type => 'fixed', }, + { field => 'prepare_url', type => 'fixed', }, + { field => 'send_url', type => 'fixed', }, + { field => 'username', type => 'fixed', }, + { field => 'password', type => 'fixed', }, + { field => 'content', type => 'fixed' }, + ); + + } +}; + + diff --git a/httemplate/edit/process/msg_template.html b/httemplate/edit/process/msg_template.html index e146adf76..d8b125ae0 100644 --- a/httemplate/edit/process/msg_template.html +++ b/httemplate/edit/process/msg_template.html @@ -1,7 +1,7 @@ <% include( 'elements/process.html', 'table' => 'msg_template', - 'viewall_dir' => 'browse', - #'popup_reload'=> 1, + 'fields' => $fields, + 'viewall_url' => "browse/msg_template/$msgclass.html", 'debug' => 0, 'precheck_callback' => \&precheck_callback, 'args_callback' => \&args_callback, @@ -11,9 +11,21 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right(['Edit templates','Edit global templates']); +my $msgclass = 'email'; +if ( $cgi->param('msgclass') =~ /^(\w+)$/ ) { + $msgclass = $1; +} + +my $fields = [ fields('msg_template') ]; +my $class = "FS::msg_template::$msgclass"; +eval "use $class;"; +if ( $class->extension_table ) { + push @$fields, fields($class->extension_table); +} + sub precheck_callback { my $cgi = shift; - # validate some fields + # validate locale field (for email-type records) $cgi->param('locale') =~ /^(\w*)$/; my $locale = $1; return mt('Language required') if $locale eq 'new'; # the user didn't choose diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index a5fb15bc2..55645cf31 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -767,7 +767,7 @@ tie my %config_nms, 'Tie::IxHash', ; tie my %config_misc, 'Tie::IxHash'; -$config_misc{'Message templates'} = [ $fsurl.'browse/msg_template.html', 'Templates for customer notices' ] +$config_misc{'Message templates'} = [ $fsurl.'browse/msg_template/email.html', 'Templates for customer notices' ] if $curuser->access_right(['View templates', 'View global templates', 'Edit templates', 'Edit global templates', ]); $config_misc{'Advertising sources'} = [ $fsurl.'browse/part_referral.html', 'Where a customer heard about your service.' ]