<& /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', ], 'system_log' => [ '$logmessage' => 'Log entry message', '$loglevel' => 'Log entry level', '$logcontext' => 'Log entry context', ], ); 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', 'system_log' => 'System log 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; }