package FS::Conf;
-use vars qw($base_dir @config_items @base_items @card_types $DEBUG);
+use strict;
+use vars qw( $base_dir @config_items @base_items @card_types $DEBUG
+ $conf_cache $conf_cache_enabled
+ );
use Carp;
use IO::File;
use File::Basename;
use Locale::Currency;
use FS::ConfItem;
use FS::ConfDefaults;
-use FS::Conf_compat17;
use FS::Locales;
use FS::payby;
use FS::conf;
use FS::Record qw(qsearch qsearchs);
-use FS::UID qw(dbh datasrc use_confcompat);
+use FS::UID qw(dbh datasrc);
use FS::Misc::Invoicing qw( spool_formats );
$base_dir = '%%%FREESIDE_CONF%%%';
$DEBUG = 0;
+$conf_cache_enabled = 0;
+
=head1 NAME
FS::Conf - Freeside configuration values
=cut
-sub _usecompat {
- my ($self, $method) = (shift, shift);
- carp "NO CONFIGURATION RECORDS FOUND -- USING COMPATIBILITY MODE"
- if use_confcompat;
- my $compat = new FS::Conf_compat17 ("$base_dir/conf." . datasrc);
- $compat->$method(@_);
-}
-
sub _config {
my($self,$name,$agentnum,$agentonly)=@_;
my $hashref = { 'name' => $name };
local $FS::Record::conf = undef; # XXX evil hack prevents recursion
+ $conf_cache = undef unless $conf_cache_enabled; # use cache only when it is
+ # safe to do so
my $cv;
my @a = (
($agentnum || ()),
foreach my $a (@a) {
$hashref->{agentnum} = $a;
foreach my $l (@l) {
- $hashref->{locale} = $l;
- $cv = FS::Record::qsearchs('conf', $hashref);
- return $cv if $cv;
+ my $key = join(':',$name, $a, $l);
+ if (! exists $conf_cache->{$key}){
+ $hashref->{locale} = $l;
+ # $conf_cache is reset in FS::UID during myconnect, so the cache is
+ # reset per connection
+ $conf_cache->{$key} = FS::Record::qsearchs('conf', $hashref);
+ }
+ return $conf_cache->{$key} if $conf_cache->{$key};
}
}
return undef;
sub config {
my $self = shift;
- return $self->_usecompat('config', @_) if use_confcompat;
carp "FS::Conf->config(". join(', ', @_). ") called"
if $DEBUG > 1;
sub config_binary {
my $self = shift;
- return $self->_usecompat('config_binary', @_) if use_confcompat;
my $cv = $self->_config(@_) or return;
length($cv->value) ? decode_base64($cv->value) : '';
sub exists {
my $self = shift;
- return $self->_usecompat('exists', @_) if use_confcompat;
#my($name, $agentnum)=@_;
sub config_bool {
my $self = shift;
- return $self->_usecompat('exists', @_) if use_confcompat;
my($name,$agentnum,$agentonly) = @_;
# these to fall back to standard values
sub config_orbase {
my $self = shift;
- return $self->_usecompat('config_orbase', @_) if use_confcompat;
my( $name, $suffix ) = @_;
if ( $self->exists("${name}_$suffix") ) {
sub key_orbase {
my $self = shift;
- #no compat for this...return $self->_usecompat('config_orbase', @_) if use_confcompat;
my( $name, $suffix ) = @_;
if ( $self->exists("${name}_$suffix") ) {
sub touch {
my $self = shift;
- return $self->_usecompat('touch', @_) if use_confcompat;
my($name, $agentnum) = @_;
#unless ( $self->exists($name, $agentnum) ) {
sub set {
my $self = shift;
- return $self->_usecompat('set', @_) if use_confcompat;
my($name, $value, $agentnum) = @_;
$value =~ /^(.*)$/s;
$error = $new->insert;
}
+ if (! $error) {
+ # clean the object cache
+ my $key = join(':',$name, $agentnum, $self->{locale});
+ $conf_cache->{ $key } = $new;
+ }
+
die "error setting configuration value: $error \n"
if $error;
sub set_binary {
my $self = shift;
- return if use_confcompat;
my($name, $value, $agentnum)=@_;
$self->set($name, encode_base64($value), $agentnum);
sub delete {
my $self = shift;
- return $self->_usecompat('delete', @_) if use_confcompat;
my($name, $agentnum) = @_;
if ( my $cv = FS::Record::qsearchs('conf', {name => $name, agentnum => $agentnum, locale => $self->{locale}}) ) {
sub delete_bool {
my $self = shift;
- return $self->_usecompat('delete', @_) if use_confcompat;
my($name, $agentnum) = @_;
sub import_config_item {
my ($self,$item,$dir) = @_;
my $key = $item->key;
- if ( -e "$dir/$key" && ! use_confcompat ) {
+ if ( -e "$dir/$key" ) {
warn "Inserting $key\n" if $DEBUG;
local $/;
my $value = readline(new IO::File "$dir/$key");
}else{
$self->set($key, $value);
}
- }else {
- warn "Not inserting $key\n" if $DEBUG;
- }
-}
-
-=item verify_config_item CONFITEM DIR
-
- Compares the item specified by the CONFITEM (see L<FS::ConfItem>) in
-the database to the legacy file value in DIR.
-
-=cut
-
-sub verify_config_item {
- return '' if use_confcompat;
- my ($self,$item,$dir) = @_;
- my $key = $item->key;
- my $type = $item->type;
-
- my $compat = new FS::Conf_compat17 $dir;
- my $error = '';
-
- $error .= "$key fails existential comparison; "
- if $self->exists($key) xor $compat->exists($key);
-
- if ( $type !~ /^(binary|image)$/ ) {
-
- {
- no warnings;
- $error .= "$key fails scalar comparison; "
- unless scalar($self->config($key)) eq scalar($compat->config($key));
- }
-
- my (@new) = $self->config($key);
- my (@old) = $compat->config($key);
- unless ( scalar(@new) == scalar(@old)) {
- $error .= "$key fails list comparison; ";
- }else{
- my $r=1;
- foreach (@old) { $r=0 if ($_ cmp shift(@new)); }
- $error .= "$key fails list comparison; "
- unless $r;
- }
-
} else {
-
- no warnings 'uninitialized';
- $error .= "$key fails binary comparison; "
- unless scalar($self->config_binary($key)) eq scalar($compat->config_binary($key));
-
+ warn "Not inserting $key\n" if $DEBUG;
}
-
-#remove deprecated config on our own terms, not freeside-upgrade's
-# if ($error =~ /existential comparison/ && $item->section eq 'deprecated') {
-# my $proto;
-# for ( @config_items ) { $proto = $_; last if $proto->key eq $key; }
-# unless ($proto->key eq $key) {
-# warn "removed config item $error\n" if $DEBUG;
-# $error = '';
-# }
-# }
-
- $error;
}
#item _orbase_items OPTIONS
sub config_items {
my $self = shift;
- return $self->_usecompat('config_items', @_) if use_confcompat;
( @config_items, $self->_orbase_items(@_) );
}
sub init_config {
my $dir = shift;
- {
- local $FS::UID::use_confcompat = 0;
- my $conf = new FS::Conf;
- foreach my $item ( $conf->config_items(dir => $dir) ) {
- $conf->import_config_item($item, $dir);
- my $error = $conf->verify_config_item($item, $dir);
- return $error if $error;
- }
-
- my $compat = new FS::Conf_compat17 $dir;
- foreach my $item ( $compat->config_items ) {
- my $error = $conf->verify_config_item($item, $dir);
- return $error if $error;
- }
+ my $conf = new FS::Conf;
+ foreach my $item ( $conf->config_items(dir => $dir) ) {
+ $conf->import_config_item($item, $dir);
}
- $FS::UID::use_confcompat = 0;
''; #success
}
invoice_latexsmallfooter
invoice_latexnotes
invoice_latexcoupon
+invoice_latexwatermark
invoice_html
invoice_htmlreturnaddress
invoice_htmlfooter
invoice_htmlnotes
+invoice_htmlwatermark
logo.png
logo.eps
);
},
);
+my %invoice_mode_options = (
+ 'type' => 'select-sub',
+ 'options_sub' => sub {
+ my @modes = qsearch({
+ 'table' => 'invoice_mode',
+ 'extra_sql' => ' WHERE '.
+ $FS::CurrentUser::CurrentUser->agentnums_sql(null => 1),
+ });
+ map { $_->modenum, $_->modename } @modes;
+ },
+ 'option_sub' => sub {
+ my $mode = FS::invoice_mode->by_key(shift);
+ $mode ? $mode->modename : '',
+ },
+ 'per_agent' => 1,
+);
+
my @cdr_formats = (
'' => '',
'default' => 'Default',
}
}
+my $validate_email = sub { $_[0] =~
+ /^[^@]+\@[[:alnum:]-]+(\.[[:alnum:]-]+)+$/
+ ? '' : 'Invalid email address';
+ };
+
#Billing (81 items)
#Invoicing (50 items)
#UI (69 items)
@config_items = map { new FS::ConfItem $_ } (
- {
- 'key' => 'address',
- 'section' => 'deprecated',
- 'description' => 'This configuration option is no longer used. See <a href="#invoice_template">invoice_template</a> instead.',
- 'type' => 'text',
- },
-
{
'key' => 'event_log_level',
'section' => 'notification',
'select_enum' => [ '', qw( USD AUD CAD DKK EUR GBP ILS JPY NZD ) ],
},
+ {
+ 'key' => 'business-onlinepayment-verification',
+ 'section' => 'billing',
+ 'description' => 'Run a $1 authorization (followed by a void) to verify new credit card information.',
+ 'type' => 'checkbox',
+ },
+
{
'key' => 'currency',
'section' => 'billing',
'per_locale' => 1,
},
- {
- 'key' => 'deleteinvoices',
- 'section' => 'UI',
- 'description' => 'Enable invoices deletions. Be very careful! Deleting an invoice will remove all traces that the invoice ever existed! Normally, you would void or apply a credit against the invoice instead.',
- 'type' => 'checkbox',
- },
-
- {
- 'key' => 'deletecredits',
- #not actually deprecated yet
- #'section' => 'deprecated',
- #'description' => '<B>DEPRECATED</B>, now controlled by ACLs. Used to enable deletion of unclosed credits. Be very careful! Only delete credits that were data-entry errors, not adjustments. Optionally specify one or more comma-separated email addresses to be notified when a credit is deleted.',
- 'section' => '',
- 'description' => 'One or more comma-separated email addresses to be notified when a credit is deleted.',
- 'type' => [qw( checkbox text )],
- },
-
{
'key' => 'deleterefunds',
'section' => 'billing',
'type' => 'checkbox',
},
- {
- 'key' => 'unapplypayments',
- 'section' => 'deprecated',
- 'description' => '<B>DEPRECATED</B>, now controlled by ACLs. Used to enable "unapplication" of unclosed payments.',
- 'type' => 'checkbox',
- },
-
- {
- 'key' => 'unapplycredits',
- 'section' => 'deprecated',
- 'description' => '<B>DEPRECATED</B>, now controlled by ACLs. Used to enable "unapplication" of unclosed credits.',
- 'type' => 'checkbox',
- },
-
{
'key' => 'dirhash',
'section' => 'shell',
'description' => 'Return address on email invoices (address only, see invoice_from_name)',
'type' => 'text',
'per_agent' => 1,
- 'validate' => sub { $_[0] =~
- /^[^@]+\@[[:alnum:]-]+(\.[[:alnum:]-]+)+$/
- ? '' : 'Invalid email address';
- }
+ 'validate' => $validate_email,
},
{
'per_locale' => 1,
},
+ {
+ 'key' => 'invoice_htmlwatermark',
+ 'section' => 'invoicing',
+ 'description' => 'Watermark for HTML invoices. Appears in a semitransparent positioned DIV overlaid on the main invoice container.',
+ 'type' => 'textarea',
+ 'per_agent' => 1,
+ 'per_locale' => 1,
+ },
+
{
'key' => 'invoice_latex',
'section' => 'invoicing',
{
'key' => 'invoice_latexextracouponspace',
'section' => 'invoicing',
- 'description' => 'Optional LaTeX invoice textheight space to reserve for a tear off coupon. Include units. Default is 3.6cm',
+ 'description' => 'Optional LaTeX invoice textheight space to reserve for a tear off coupon. Include units. Default is 2.7 inches.',
'type' => 'text',
'per_agent' => 1,
'validate' => sub { shift =~
{
'key' => 'invoice_latexcouponfootsep',
'section' => 'invoicing',
- 'description' => 'Optional LaTeX invoice separation between tear off coupon and footer. Include units.',
+ 'description' => 'Optional LaTeX invoice separation between bottom of coupon address and footer. Include units. Default is 0.2 inches.',
'type' => 'text',
'per_agent' => 1,
'validate' => sub { shift =~
{
'key' => 'invoice_latexcouponamountenclosedsep',
'section' => 'invoicing',
- 'description' => 'Optional LaTeX invoice separation between total due and amount enclosed line. Include units.',
+ 'description' => 'Optional LaTeX invoice separation between total due and amount enclosed line. Include units. Default is 2.25 em.',
'type' => 'text',
'per_agent' => 1,
'validate' => sub { shift =~
{
'key' => 'invoice_latexcoupontoaddresssep',
'section' => 'invoicing',
- 'description' => 'Optional LaTeX invoice separation between invoice data and the to address (usually invoice_latexreturnaddress). Include units.',
+ 'description' => 'Optional LaTeX invoice separation between invoice data and the address (usually invoice_latexreturnaddress). Include units. Default is 1 inch.',
'type' => 'text',
'per_agent' => 1,
'validate' => sub { shift =~
{
'key' => 'invoice_latexverticalreturnaddress',
- 'section' => 'invoicing',
- 'description' => 'Place the return address under the company logo rather than beside it.',
+ 'section' => 'deprecated',
+ 'description' => 'Deprecated. With old invoice_latex template, places the return address under the company logo rather than beside it.',
'type' => 'checkbox',
'per_agent' => 1,
},
'per_locale' => 1,
},
+ {
+ 'key' => 'invoice_latexwatermark',
+ 'section' => 'invoicing',
+ 'description' => 'Watermark for LaTeX invoices. See "texdoc background" for information on what this can contain. The content itself should be enclosed in braces, optionally followed by a comma and any formatting options.',
+ 'type' => 'textarea',
+ 'per_agent' => 1,
+ 'per_locale' => 1,
+ },
+
{
'key' => 'invoice_email_pdf',
'section' => 'invoicing',
'type' => 'select',
'per_agent' => 1,
'select_enum' => [
- '', 'Payable upon receipt', 'Net 0', 'Net 3', 'Net 5', 'Net 9', 'Net 10', 'Net 14',
+ '', 'Payable upon receipt', 'Net 0', 'Net 3', 'Net 5', 'Net 7', 'Net 9', 'Net 10', 'Net 14',
'Net 15', 'Net 18', 'Net 20', 'Net 21', 'Net 25', 'Net 30', 'Net 45',
'Net 60', 'Net 90'
], },
'type' => 'checkbox',
},
- {
- 'key' => 'invoice_send_receipts',
- 'section' => 'deprecated',
- 'description' => '<b>DEPRECATED</b>, this used to send an invoice copy on payments and credits. See the payment_receipt_email and XXXX instead.',
- 'type' => 'checkbox',
- },
-
{
'key' => 'payment_receipt',
'section' => 'notification',
'agent_bool' => 1,
},
+ {
+ 'key' => 'payment_receipt_statement_mode',
+ 'section' => 'notification',
+ 'description' => 'Automatic payments will cause a post-payment statement to be sent to the customer. Select the invoice mode to use for this statement. If unspecified, it will use the "_statement" versions of invoice configuration settings, and have the notice name "Statement".',
+ %invoice_mode_options,
+ },
+
{
'key' => 'payment_receipt_msgnum',
'section' => 'notification',
- 'description' => 'Template to use for payment receipts.',
+ 'description' => 'Template to use for manual payment receipts.',
%msg_template_options,
},
'per_agent' => 1,
},
- {
- 'key' => 'payment_receipt_email',
- 'section' => 'deprecated',
- 'description' => 'Template file for payment receipts. Payment receipts are sent to the customer email invoice destination(s) when a payment is received.',
- 'type' => [qw( checkbox textarea )],
- },
-
{
'key' => 'payment_receipt-trigger',
'section' => 'notification',
'per_agent' => 1,
},
+ {
+ 'key' => 'refund_receipt_msgnum',
+ 'section' => 'notification',
+ 'description' => 'Template to use for manual refund receipts.',
+ %msg_template_options,
+ },
+
{
'key' => 'trigger_export_insert_on_payment',
'section' => 'billing',
{
'key' => 'passwordmax',
'section' => 'password',
- 'description' => 'Maximum password length (default 8) (don\'t set this over 12 if you need to import or export crypt() passwords)',
+ 'description' => 'Maximum password length (default 12) (don\'t set this over 12 if you need to import or export crypt() passwords)',
'type' => 'text',
},
# 'description' => 'Directory which contains domain registry information. Each registry is a directory.',
# },
- {
- 'key' => 'report_template',
- 'section' => 'deprecated',
- 'description' => 'Deprecated template file for reports.',
- 'type' => 'textarea',
- },
-
{
'key' => 'maxsearchrecordsperpage',
'section' => 'UI',
},
{
- 'key' => 'unsuspendauto',
+ 'key' => 'unsuspend_balance',
'section' => 'billing',
- 'description' => 'Enables the automatic unsuspension of suspended packages when a customer\'s balance due changes from positive to zero or negative as the result of a payment or credit',
- 'type' => 'checkbox',
+ 'description' => 'Enables the automatic unsuspension of suspended packages when a customer\'s balance due is at or below the specified amount after a payment or credit',
+ 'type' => 'select',
+ 'select_enum' => [
+ '', 'Zero', 'Latest invoice charges', 'Charges not past due'
+ ],
},
{
'svc_acct' => 'Account (svc_acct)',
'svc_phone' => 'Phone number (svc_phone)',
'svc_pbx' => 'PBX (svc_pbx)',
+ 'none' => 'None - package only',
],
},
%msg_template_options,
},
- {
- 'key' => 'declinetemplate',
- 'section' => 'deprecated',
- 'description' => 'Template file for credit card and electronic check decline emails.',
- 'type' => 'textarea',
- },
-
{
'key' => 'emaildecline',
'section' => 'notification',
%msg_template_options,
},
- {
- 'key' => 'cancelmessage',
- 'section' => 'deprecated',
- 'description' => 'Template file for cancellation emails.',
- 'type' => 'textarea',
- },
-
- {
- 'key' => 'cancelsubject',
- 'section' => 'deprecated',
- 'description' => 'Subject line for cancellation emails.',
- 'type' => 'text',
- },
-
{
'key' => 'emailcancel',
'section' => 'notification',
{
'key' => 'enable_taxclasses',
- 'section' => 'billing',
+ 'section' => 'taxation',
'description' => 'Enable per-package tax classes',
'type' => 'checkbox',
},
{
'key' => 'require_taxclasses',
- 'section' => 'billing',
+ 'section' => 'taxation',
'description' => 'Require a taxclass to be entered for every package',
'type' => 'checkbox',
},
{
- 'key' => 'enable_taxproducts',
- 'section' => 'billing',
+ 'key' => 'tax_data_vendor',
+ 'section' => 'taxation',
'description' => 'Tax data vendor you are using.',
'type' => 'select',
- 'select_enum' => [ 'cch', 'billsoft', 'avalara' ],
+ 'select_enum' => [ '', 'cch', 'billsoft', 'avalara', 'suretax' ],
},
{
'key' => 'taxdatadirectdownload',
- 'section' => 'billing', #well
- 'description' => 'Enable downloading tax data directly from the vendor site. at least three lines: URL, username, and password.j',
+ 'section' => 'taxation',
+ 'description' => 'Enable downloading tax data directly from CCH. at least three lines: URL, username, and password.j',
'type' => 'textarea',
},
{
'key' => 'ignore_incalculable_taxes',
- 'section' => 'billing',
+ 'section' => 'taxation',
'description' => 'Prefer to invoice without tax over not billing at all',
'type' => 'checkbox',
},
{
'key' => 'billsoft-company_code',
- 'section' => 'billing',
+ 'section' => 'taxation',
'description' => 'Billsoft tax service company code (3 letters)',
'type' => 'text',
},
{
'key' => 'avalara-taxconfig',
- 'section' => 'billing',
+ 'section' => 'taxation',
'description' => 'Avalara tax service configuration. Four lines: company code, account number, license key, test mode (1 to enable).',
'type' => 'textarea',
},
{
- 'key' => 'welcome_msgnum',
- 'section' => 'notification',
- 'description' => 'Template to use for welcome messages when a svc_acct record is created.',
- %msg_template_options,
- },
-
- {
- 'key' => 'svc_acct_welcome_exclude',
- 'section' => 'notification',
- 'description' => 'A list of svc_acct services for which no welcome email is to be sent.',
- 'type' => 'select-part_svc',
- 'multiple' => 1,
+ 'key' => 'suretax-hostname',
+ 'section' => 'taxation',
+ 'description' => 'SureTax server name; defaults to the test server.',
+ 'type' => 'text',
},
{
- 'key' => 'welcome_email',
- 'section' => 'deprecated',
- 'description' => 'Template file for welcome email. Welcome emails are sent to the customer email invoice destination(s) each time a svc_acct record is created.',
- 'type' => 'textarea',
- 'per_agent' => 1,
+ 'key' => 'suretax-client_number',
+ 'section' => 'taxation',
+ 'description' => 'SureTax tax service client ID.',
+ 'type' => 'text',
},
-
{
- 'key' => 'welcome_email-from',
- 'section' => 'deprecated',
- 'description' => 'From: address header for welcome email',
+ 'key' => 'suretax-validation_key',
+ 'section' => 'taxation',
+ 'description' => 'SureTax validation key (UUID).',
'type' => 'text',
- 'per_agent' => 1,
},
-
{
- 'key' => 'welcome_email-subject',
- 'section' => 'deprecated',
- 'description' => 'Subject: header for welcome email',
+ 'key' => 'suretax-business_unit',
+ 'section' => 'taxation',
+ 'description' => 'SureTax client business unit name; optional.',
'type' => 'text',
'per_agent' => 1,
},
-
{
- 'key' => 'welcome_email-mimetype',
- 'section' => 'deprecated',
- 'description' => 'MIME type for welcome email',
+ 'key' => 'suretax-regulatory_code',
+ 'section' => 'taxation',
+ 'description' => 'SureTax client regulatory status.',
'type' => 'select',
- 'select_enum' => [ 'text/plain', 'text/html' ],
+ 'select_enum' => [ '', 'ILEC', 'IXC', 'CLEC', 'VOIP', 'ISP', 'Wireless' ],
'per_agent' => 1,
},
- {
- 'key' => 'welcome_letter',
- 'section' => '',
- 'description' => 'Optional LaTex template file for a printed welcome letter. A welcome letter is printed the first time a cust_pkg record is created. See the <a href="http://search.cpan.org/dist/Text-Template/lib/Text/Template.pm">Text::Template</a> documentation and the billing documentation for details on the template substitution language. A variable exists for each fieldname in the customer record (<code>$first, $last, etc</code>). The following additional variables are available<ul><li><code>$payby</code> - a friendler represenation of the field<li><code>$payinfo</code> - the masked payment information<li><code>$expdate</code> - the time at which the payment method expires (a UNIX timestamp)<li><code>$returnaddress</code> - the invoice return address for this customer\'s agent</ul>',
- 'type' => 'textarea',
- },
-
-# {
-# 'key' => 'warning_msgnum',
-# 'section' => 'notification',
-# 'description' => 'Template to use for warning messages, sent to the customer email invoice destination(s) when a svc_acct record has its usage drop below a threshold.',
-# %msg_template_options,
-# },
{
- 'key' => 'warning_email',
+ 'key' => 'welcome_msgnum',
'section' => 'notification',
- 'description' => 'Template file for warning email. Warning emails are sent to the customer email invoice destination(s) each time a svc_acct record has its usage drop below a threshold or 0. See the <a href="http://search.cpan.org/dist/Text-Template/lib/Text/Template.pm">Text::Template</a> documentation for details on the template substitution language. The following variables are available<ul><li><code>$username</code> <li><code>$password</code> <li><code>$first</code> <li><code>$last</code> <li><code>$pkg</code> <li><code>$column</code> <li><code>$amount</code> <li><code>$threshold</code></ul>',
- 'type' => 'textarea',
+ 'description' => 'Template to use for welcome messages when a svc_acct record is created.',
+ %msg_template_options,
},
-
+
{
- 'key' => 'warning_email-from',
+ 'key' => 'svc_acct_welcome_exclude',
'section' => 'notification',
- 'description' => 'From: address header for warning email',
- 'type' => 'text',
+ 'description' => 'A list of svc_acct services for which no welcome email is to be sent.',
+ 'type' => 'select-part_svc',
+ 'multiple' => 1,
},
{
- 'key' => 'warning_email-cc',
- 'section' => 'notification',
- 'description' => 'Additional recipient(s) (comma separated) for warning email when remaining usage reaches zero.',
- 'type' => 'text',
+ 'key' => 'welcome_letter',
+ 'section' => '',
+ 'description' => 'Optional LaTex template file for a printed welcome letter. A welcome letter is printed the first time a cust_pkg record is created. See the <a href="http://search.cpan.org/dist/Text-Template/lib/Text/Template.pm">Text::Template</a> documentation and the billing documentation for details on the template substitution language. A variable exists for each fieldname in the customer record (<code>$first, $last, etc</code>). The following additional variables are available<ul><li><code>$payby</code> - a friendler represenation of the field<li><code>$payinfo</code> - the masked payment information<li><code>$expdate</code> - the time at which the payment method expires (a UNIX timestamp)<li><code>$returnaddress</code> - the invoice return address for this customer\'s agent</ul>',
+ 'type' => 'textarea',
},
{
- 'key' => 'warning_email-subject',
+ 'key' => 'threshold_warning_msgnum',
'section' => 'notification',
- 'description' => 'Subject: header for warning email',
- 'type' => 'text',
- },
-
- {
- 'key' => 'warning_email-mimetype',
- 'section' => 'notification',
- 'description' => 'MIME type for warning email',
- 'type' => 'select',
- 'select_enum' => [ 'text/plain', 'text/html' ],
+ 'description' => 'Template to use for warning messages sent to the customer email invoice destination(s) when a svc_acct record has its usage drop below a threshold. Extra substitutions available: $column, $amount, $threshold',
+ %msg_template_options,
},
{
'section' => 'billing',
'description' => 'Available payment types.',
'type' => 'selectmultiple',
- 'select_enum' => [ qw(CARD DCRD CHEK DCHK CASH WEST MCRD MCHK PPAL) ],
+ 'select_enum' => [ qw(CARD DCRD CHEK DCHK) ], #BILL CASH WEST MCRD MCHK PPAL) ],
+ },
+
+ {
+ 'key' => 'banned_pay-pad',
+ 'section' => 'billing',
+ 'description' => 'Padding for encrypted storage of banned credit card hashes. If you already have new-style SHA512 entries in the banned_pay table, do not change as this will invalidate the old entries.',
+ 'type' => 'text',
},
{
'type' => 'checkbox',
},
- {
- 'key' => 'paymentforcedtobatch',
- 'section' => 'deprecated',
- 'description' => 'See batch-enable_payby and realtime-disable_payby. Used to (for CHEK): Cause per customer payment entry to be forced to a batch processor rather than performed realtime.',
- 'type' => 'checkbox',
- },
-
{
'key' => 'svc_acct-notes',
'section' => 'deprecated',
'type' => 'checkbox',
},
+ {
+ 'key' => 'radius-canopy',
+ 'section' => '',
+ 'description' => 'Enable RADIUS attributes for Cambium (formerly Motorola) Canopy (Motorola-Canopy-Gateway).',
+ 'type' => 'checkbox',
+ },
+
{
'key' => 'svc_broadband-radius',
'section' => '',
'type' => 'text',
},
- {
- 'key' => 'users-allow_comp',
- 'section' => 'deprecated',
- 'description' => '<b>DEPRECATED</b>, enable the <i>Complimentary customer</i> access right instead. Was: Usernames (Freeside users, created with <a href="../docs/man/bin/freeside-adduser.html">freeside-adduser</a>) which can create complimentary customers, one per line. If no usernames are entered, all users can create complimentary accounts.',
- 'type' => 'textarea',
- },
-
{
'key' => 'credit_card-recurring_billing_flag',
'section' => 'billing',
'type' => 'select',
'select_hash' => [
'actual_oncard' => 'Default/classic behavior: set the flag if a customer has actual previous charges on the card.',
- 'transaction_is_recur' => 'Set the flag if the transaction itself is recurring, irregardless of previous charges on the card.',
+ 'transaction_is_recur' => 'Set the flag if the transaction itself is recurring, regardless of previous charges on the card.',
],
},
'type' => 'checkbox',
},
+ {
+ 'key' => 'manual_process-single_invoice_amount',
+ 'section' => 'billing',
+ 'description' => 'When entering manual credit card and ACH payments, amount will not autofill if the customer has more than one open invoice',
+ 'type' => 'checkbox',
+ },
+
{
'key' => 'manual_process-pkgpart',
'section' => 'billing',
},
'option_sub' => sub { require FS::Record;
require FS::agent_type;
- my $agent = FS::Record::qsearchs(
+ my $agent_type = FS::Record::qsearchs(
'agent_type', { 'typenum'=>shift }
);
$agent_type ? $agent_type->atype : '';
}
},
},
+
{
'key' => 'ticket_system-force_default_queueid',
'section' => 'ticketing',
'description' => 'Disallow queue selection when creating new tickets from customer view.',
'type' => 'checkbox',
},
+
{
'key' => 'ticket_system-selfservice_queueid',
'section' => 'ticketing',
'type' => 'checkbox',
},
+ {
+ 'key' => 'ticket_system-appointment-queueid',
+ 'section' => 'ticketing',
+ 'description' => 'Ticketing queue to use for appointments.',
+ #false laziness w/above
+ 'type' => 'select-sub',
+ 'options_sub' => sub {
+ my $conf = new FS::Conf;
+ if ( $conf->config('ticket_system') ) {
+ eval "use FS::TicketSystem;";
+ die $@ if $@;
+ FS::TicketSystem->queues();
+ } else {
+ ();
+ }
+ },
+ 'option_sub' => sub {
+ my $conf = new FS::Conf;
+ if ( $conf->config('ticket_system') ) {
+ eval "use FS::TicketSystem;";
+ die $@ if $@;
+ FS::TicketSystem->queue(shift);
+ } else {
+ '';
+ }
+ },
+ },
+
+ {
+ 'key' => 'ticket_system-appointment-custom_field',
+ 'section' => 'ticketing',
+ 'description' => 'Ticketing custom field to use as an appointment classification.',
+ 'type' => 'text',
+ },
+
{
'key' => 'ticket_system-escalation',
'section' => 'ticketing',
'per_agent' => 1,
},
- {
- 'key' => 'city_not_required',
- 'section' => 'required',
- 'description' => 'Turn off requirement for a City to be entered for billing & shipping addresses',
- 'type' => 'checkbox',
- 'per_agent' => 1,
- },
-
- {
- 'key' => 'echeck-void',
- 'section' => 'deprecated',
- 'description' => '<B>DEPRECATED</B>, now controlled by ACLs. Used to enable local-only voiding of echeck payments in addition to refunds against the payment gateway',
- 'type' => 'checkbox',
- },
-
- {
- 'key' => 'cc-void',
- 'section' => 'deprecated',
- 'description' => '<B>DEPRECATED</B>, now controlled by ACLs. Used to enable local-only voiding of credit card payments in addition to refunds against the payment gateway',
- 'type' => 'checkbox',
- },
-
- {
- 'key' => 'unvoid',
- 'section' => 'deprecated',
- 'description' => '<B>DEPRECATED</B>, now controlled by ACLs. Used to enable unvoiding of voided payments',
- 'type' => 'checkbox',
- },
-
{
'key' => 'address1-search',
'section' => 'UI',
{
'key' => 'cust_main-require_address2',
'section' => 'UI',
- 'description' => 'Second address field is required (on service address only, if billing and service addresses differ). Also enables "Unit" labeling of address2 on customer view and edit pages. Useful for multi-tenant applications. See also: address2-search',
+ 'description' => 'Second address field is required. Also enables "Unit" labeling of address2 on customer view and edit pages. Useful for multi-tenant applications. See also: address2-search', # service address only part not working in the modern world, see #41184 (on service address only, if billing and service addresses differ)
'type' => 'checkbox',
},
'per_agent' => 1,
},
- { 'key' => 'referral_credit',
- 'section' => 'deprecated',
- 'description' => "Used to enable one-time referral credits in the amount of one month <i>referred</i> customer's recurring fee (irregardless of frequency). Replace with a billing event on appropriate packages.",
- 'type' => 'checkbox',
- },
-
{ 'key' => 'selfservice_server-cache_module',
'section' => 'self-service',
'description' => 'Module used to store self-service session information. All modules handle any number of self-service servers. Cache::SharedMemoryCache is appropriate for a single database / single Freeside server. Cache::FileCache is useful for multiple databases on a single server, or when IPC::ShareLite is not available (i.e. FreeBSD).', # _Database stores session information in the database and is appropriate for multiple Freeside servers, but may be slower.',
{
'key' => 'voip-cdr_email',
'section' => 'telephony',
- 'description' => 'Include the call details on emailed invoices (and HTML invoices viewed in the backend), even if the customer is configured for not printing them on the invoices.',
+ 'description' => 'Include the call details inline on emailed invoices (and HTML invoices viewed in the backend), even if the customer is configured for not printing them on the invoices. Useful for including these details in electronic delivery but omitting them when printing.',
'type' => 'checkbox',
},
{
'key' => 'voip-cust_email_csv_cdr',
- 'section' => 'telephony',
- 'description' => 'Enable the per-customer option for including CDR information as a CSV attachment on emailed invoices.',
+ 'section' => 'deprecated',
+ 'description' => 'Deprecated, see voip-cdr_email_attach instead. Used to enable the per-customer option for including CDR information as a CSV attachment on emailed invoices.',
'type' => 'checkbox',
},
+ {
+ 'key' => 'voip-cdr_email_attach',
+ 'section' => 'telephony',
+ 'description' => 'Enable the per-customer option for including CDR information as an attachment on emailed invoices.',
+ 'type' => 'select',
+ 'select_hash' => [ '' => 'Disabled',
+ 'csv' => 'Text (CSV) attachment',
+ 'zip' => 'Zip attachment',
+ ],
+ },
+
{
'key' => 'cgp_rule-domain_templates',
'section' => '',
{
'key' => 'tax-ship_address',
- 'section' => 'billing',
+ 'section' => 'taxation',
'description' => 'By default, tax calculations are done based on the billing address. Enable this switch to calculate tax based on the shipping address instead.',
'type' => 'checkbox',
}
,
{
'key' => 'tax-pkg_address',
- 'section' => 'billing',
+ 'section' => 'taxation',
'description' => 'By default, tax calculations are done based on the billing address. Enable this switch to calculate tax based on the package address instead (when present).',
'type' => 'checkbox',
},
'select_enum' => [ 'approve', 'decline' ],
},
+ # replaces batch-errors_to (sent email on error)
{
- 'key' => 'batch-errors_to',
+ 'key' => 'batch-errors_not_fatal',
'section' => 'billing',
- 'description' => 'Email errors when processing batches to this address. If unspecified, batch processing will stop immediately on error.',
- 'type' => 'text',
+ 'description' => 'If checked, when importing batches from a gateway, item errors will be recorded in the system log without aborting processing. If unchecked, batch processing will fail on error.',
+ 'type' => 'checkbox',
},
#lists could be auto-generated from pay_batch info
{
'key' => 'batchconfig-RBC',
'section' => 'billing',
- 'description' => 'Configuration for Royal Bank of Canada PDS batching, four lines: 1. Client number, 2. Short name, 3. Long name, 4. Transaction code.',
+ 'description' => 'Configuration for Royal Bank of Canada PDS batching, five lines: 1. Client number, 2. Short name, 3. Long name, 4. Transaction code 5. (optional) set to TEST to turn on test mode.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'batchconfig-RBC-login',
+ 'section' => 'billing',
+ 'description' => 'FTPS login for uploading Royal Bank of Canada batches. Two lines: 1. username, 2. password. If not supplied, batches can still be created but not automatically uploaded.',
'type' => 'textarea',
},
'type' => 'text',
},
+ {
+ 'key' => 'batchconfig-nacha-origin_name',
+ 'section' => 'billing',
+ 'description' => 'Configuration for NACHA batching, Origin name (defaults to company name, but sometimes bank name is needed instead.)',
+ 'type' => 'text',
+ },
+
{
'key' => 'batch-manual_approval',
'section' => 'billing',
'type' => 'checkbox',
},
- {
- 'key' => 'cust_main-enable_order_package',
- 'section' => 'UI',
- 'description' => 'Display order new package on the basic tab',
- 'type' => 'checkbox',
- },
-
{
'key' => 'cust_main-edit_calling_list_exempt',
'section' => 'UI',
{
'key' => 'support-key',
'section' => '',
- 'description' => 'A support key enables access to commercial services delivered over the network, such as the payroll module, access to the internal ticket system, priority support and optional backups.',
+ 'description' => 'A support key enables access to commercial services delivered over the network, such as address normalization and invoice printing.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'freesideinc-webservice-svcpart',
+ 'section' => '',
+ 'description' => 'Do not set this.',
'type' => 'text',
},
'type' => 'text',
},
- {
- 'key' => 'enable_fuzzy_on_exact',
- 'section' => 'UI',
- 'description' => 'Enable approximate customer searching even when an exact match is found.',
- 'type' => 'checkbox',
- },
-
{ 'key' => 'pkg_referral',
'section' => '',
'description' => 'Enable package-specific advertising sources.',
%msg_template_options,
},
- {
- 'key' => 'impending_recur_template',
- 'section' => 'deprecated',
- 'description' => 'Template file for alerts about looming first time recurrant billing. See the <a href="http://search.cpan.org/dist/Text-Template/lib/Text/Template.pm">Text::Template</a> documentation for details on the template substitition language. Also see packages with a <a href="../browse/part_pkg.cgi">flat price plan</a> The following variables are available<ul><li><code>$packages</code> allowing <code>$packages->[0]</code> thru <code>$packages->[n]</code> <li><code>$package</code> the first package, same as <code>$packages->[0]</code> <li><code>$recurdates</code> allowing <code>$recurdates->[0]</code> thru <code>$recurdates->[n]</code> <li><code>$recurdate</code> the first recurdate, same as <code>$recurdate->[0]</code> <li><code>$first</code> <li><code>$last</code></ul>',
-# <li><code>$payby</code> <li><code>$expdate</code> most likely only confuse
- 'type' => 'textarea',
- },
-
{
'key' => 'logo.png',
'section' => 'UI', #'invoicing' ?
'select_enum' => [ '1 hour', '2 hours', '4 hours', '8 hours', '1 day', '1 week', ],
},
- {
- 'key' => 'password-generated-allcaps',
- 'section' => 'password',
- 'description' => 'Causes passwords automatically generated to consist entirely of capital letters',
- 'type' => 'checkbox',
- },
+ # 3.x-only options for a more tolerant password policy
+# {
+# 'key' => 'password-generated-characters',
+# 'section' => 'password',
+# 'description' => 'Set of characters to use when generating random passwords. This must contain at least one lowercase letter, uppercase letter, digit, and punctuation mark.',
+# 'type' => 'textarea',
+# },
+#
+# {
+# 'key' => 'password-no_reuse',
+# 'section' => 'password',
+# 'description' => 'Minimum number of password changes before a password can be reused. By default, passwords can be reused without restriction.',
+# 'type' => 'text',
+# },
+#
{
'key' => 'datavolume-forcemegabytes',
'section' => 'UI',
reason_type_options('R'),
},
+ # was only used to negate invoices during signup when card was declined, now we just void
{
'key' => 'signup_credit_type',
- 'section' => 'billing', #self-service?
+ 'section' => 'deprecated', #self-service?
'description' => 'The group to use for new, automatically generated credit reasons resulting from signup and self-service declines.',
reason_type_options('R'),
},
{
'key' => 'disable_previous_balance',
'section' => 'invoicing',
- 'description' => 'Disable inclusion of previous balance, payment, and credit lines on invoices.',
+ 'description' => 'Show new charges only; do not list previous invoices, payments, or credits on the invoice.',
'type' => 'checkbox',
'per_agent' => 1,
},
{
'key' => 'previous_balance-exclude_from_total',
'section' => 'invoicing',
- 'description' => 'Do not include previous balance in the \'Total\' line. Only meaningful when invoice_sections is false. Optionally provide text to override the Total New Charges description',
- 'type' => [ qw(checkbox text) ],
+ 'description' => 'Show separate totals for previous invoice balance and new charges. Only meaningful when invoice_sections is false.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'previous_balance-text',
+ 'section' => 'invoicing',
+ 'description' => 'Text for the label of the total previous balance, when it is shown separately. Defaults to "Previous Balance".',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'previous_balance-text-total_new_charges',
+ 'section' => 'invoicing',
+ 'description' => 'Text for the label of the total of new charges, when it is shown separately. If invoice_show_prior_due_date is enabled, the due date of current charges will be appended. Defaults to "Total New Charges".',
+ 'type' => 'text',
},
{
'description' => 'Method for standardizing customer addresses.',
'type' => 'select',
'select_hash' => [ '' => '',
+ 'uscensus' => 'U.S. Census Bureau',
'usps' => 'U.S. Postal Service',
'tomtom' => 'TomTom',
'melissa' => 'Melissa WebSmart',
+ 'freeside' => 'Freeside web service (support contract required)',
],
},
'type' => 'checkbox',
},
+ {
+ 'key' => 'cust_main-no_city_in_address',
+ 'section' => 'UI',
+ 'description' => 'Turn off City for billing & shipping addresses',
+ 'type' => 'checkbox',
+ },
+
{
'key' => 'census_year',
'section' => 'UI',
{
'key' => 'tax_district_method',
- 'section' => 'UI',
+ 'section' => 'taxation',
'description' => 'The method to use to look up tax district codes.',
'type' => 'select',
#'select_hash' => [ FS::Misc::Geo::get_district_methods() ],
{
'key' => 'cust_main-default_agent_custid',
'section' => 'UI',
- 'description' => 'Display the agent_custid field when available instead of the custnum field.',
+ 'description' => 'Display the agent_custid field when available instead of the custnum field. Restart Apache after changing.',
'type' => 'checkbox',
},
'per_agent' => 1,
},
- {
- 'key' => 'cust_main-custnum-display_special',
- 'section' => 'UI',
- 'description' => 'Use this customer number prefix format',
- 'type' => 'select',
- 'select_hash' => [ '' => '',
- 'CoStAg' => 'CoStAg (country, state, agent name or display_prefix)',
- 'CoStCl' => 'CoStCl (country, state, class name)' ],
- },
-
{
'key' => 'cust_main-custnum-display_length',
'section' => 'UI',
- 'description' => 'Zero fill the customer number to this many digits for display purposes.',
+ 'description' => 'Zero fill the customer number to this many digits for display purposes. Restart Apache after changing.',
'type' => 'text',
},
{
'key' => 'part_pkg-delay_cancel-days',
'section' => '',
- 'description' => 'Expire packages in this many days when using delay_cancel (default is 1)',
+ 'description' => 'Number of days to suspend when using automatic suspension period before cancel (default is 1)',
'type' => 'text',
'validate' => sub { (($_[0] =~ /^\d*$/) && (($_[0] eq '') || $_[0]))
- ? 'Must specify an integer number of days'
- : '' }
+ ? ''
+ : 'Must specify an integer number of days' }
},
{
'type' => 'text',
},
- {
- 'key' => 'email_report-subject',
- 'section' => '',
- 'description' => 'Subject for reports emailed by freeside-fetch. Defaults to "Freeside report".',
- 'type' => 'text',
- },
-
{
'key' => 'selfservice-head',
'section' => 'self-service',
{
'key' => 'tax-cust_exempt-groups',
- 'section' => 'billing',
+ 'section' => 'taxation',
'description' => 'List of grouping possibilities for tax names, for per-customer exemption purposes, one tax name per line. For example, "GST" would indicate the ability to exempt customers individually from taxes named "GST" (but not other taxes).',
'type' => 'textarea',
},
{
'key' => 'tax-cust_exempt-groups-num_req',
- 'section' => 'billing',
+ 'section' => 'taxation',
'description' => 'When using tax-cust_exempt-groups, control whether individual tax exemption numbers are required for exemption from different taxes.',
'type' => 'select',
'select_hash' => [ '' => 'Not required',
],
},
+ {
+ 'key' => 'tax-round_per_line_item',
+ 'section' => 'billing',
+ 'description' => 'Calculate tax and round to the nearest cent for each line item, rather than for the whole invoice.',
+ 'type' => 'checkbox',
+ },
+
{
'key' => 'cust_main-default_view',
'section' => 'UI',
{
'key' => 'enable_tax_adjustments',
- 'section' => 'billing',
+ 'section' => 'taxation',
'description' => 'Enable the ability to add manual tax adjustments.',
'type' => 'checkbox',
},
my @part_export =
map { qsearch( 'part_export', {exporttype => $_ } ) }
keys %{FS::part_export::export_info('cust_main')};
- map { $_->exportnum => $_->exporttype.' to '.$_->machine } @part_export;
+ map { $_->exportnum => $_->exportname } @part_export;
},
'option_sub' => sub {
require FS::Record;
'part_export', { 'exportnum' => shift }
);
$part_export
- ? $part_export->exporttype.' to '.$part_export->machine
+ ? $part_export->exportname
: '';
},
},
{
'key' => 'cust_location-exports',
'section' => '',
- 'description' => 'Export(s) to call on cust_location insert, modification and deletion.',
+ 'description' => 'Export(s) to call on cust_location insert or modification',
'type' => 'select-sub',
'multiple' => 1,
'options_sub' => sub {
my @part_export =
map { qsearch( 'part_export', {exporttype => $_ } ) }
keys %{FS::part_export::export_info('cust_location')};
- map { $_->exportnum => $_->exporttype.' to '.$_->machine } @part_export;
+ map { $_->exportnum => $_->exportname } @part_export;
},
'option_sub' => sub {
require FS::Record;
'part_export', { 'exportnum' => shift }
);
$part_export
- ? $part_export->exporttype.' to '.$part_export->machine
+ ? $part_export->exportname
: '';
},
},
{
'key' => 'cust_main-status_module',
'section' => 'UI',
- 'description' => 'Which module to use for customer status display. The "Classic" module (the default) considers accounts with cancelled recurring packages but un-cancelled one-time charges Inactive. The "Recurring" module considers those customers Cancelled. Similarly for customers with suspended recurring packages but one-time charges.', #other differences?
+ 'description' => 'Which module to use for customer status display. The "Classic" module (the default) considers accounts with cancelled recurring packages but un-cancelled one-time charges Inactive. The "Recurring" module considers those customers Cancelled. Similarly for customers with suspended recurring packages but one-time charges. Restart Apache after changing.', #other differences?
'type' => 'select',
'select_enum' => [ 'Classic', 'Recurring' ],
},
'type' => 'checkbox',
},
- {
- 'key' => 'cust-email-high-visibility',
- 'section' => 'UI',
- 'description' => 'Move the invoicing e-mail address field to the top of the billing address section and highlight it.',
- 'type' => 'checkbox',
- },
-
{
'key' => 'cust-edit-alt-field-order',
'section' => 'UI',
{
'key' => 'translate-auto-insert',
'section' => '',
- 'description' => 'Auto-insert untranslated strings for selected non-en_US locales with their default/en_US values. Do not turn this on unless translating the interface into a new language.',
+ 'description' => 'Auto-insert untranslated strings for selected non-en_US locales with their default/en_US values. Do not turn this on unless translating the interface into a new language. Restart Apache after changing.',
'type' => 'select',
'multiple' => 1,
'select_enum' => [ grep { $_ ne 'en_US' } FS::Locales::locales ],
{
'key' => 'cust_class-tax_exempt',
- 'section' => 'billing',
+ 'section' => 'taxation',
'description' => 'Control the tax exemption flag per customer class rather than per indivual customer.',
'type' => 'checkbox',
},
'type' => 'checkbox',
},
+ {
+ 'key' => 'selfservice-enable_payment_without_balance',
+ 'section' => 'self-service',
+ 'description' => 'Allow selfservice customers to make payments even if balance is zero or below (resulting in an unapplied payment and negative balance.)',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'selfservice-announcement',
+ 'section' => 'self-service',
+ 'description' => 'HTML announcement to display to all authenticated users on account overview page',
+ 'type' => 'textarea',
+ },
+
{
'key' => 'logout-timeout',
'section' => 'UI',
],
},
- {
- 'key' => 'agent-email_day',
- 'section' => '',
- 'description' => 'On this day of each month, agents with master customer records containing email addresses will be emailed a list of their customers and balances.',
- 'type' => 'text',
- },
-
{
'key' => 'report-cust_pay-select_time',
'section' => 'UI',
'type' => 'checkbox',
},
- { key => "apacheroot", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "apachemachine", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "apachemachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "bindprimary", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "bindsecondaries", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "bsdshellmachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "cyrus", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "cp_app", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "erpcdmachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "icradiusmachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "icradius_mysqldest", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "icradius_mysqlsource", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "icradius_secrets", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "maildisablecatchall", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "mxmachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "nsmachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "arecords", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "cnamerecords", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "nismachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "qmailmachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "radiusmachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "sendmailconfigpath", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "sendmailmachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "sendmailrestart", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "shellmachine", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "shellmachine-useradd", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "shellmachine-userdel", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "shellmachine-usermod", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "shellmachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "radiusprepend", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "textradiusprepend", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "username_policy", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "vpopmailmachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "vpopmailrestart", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "safe-part_pkg", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "selfservice_server-quiet", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "signup_server-quiet", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "signup_server-email", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "vonage-username", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "vonage-password", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
- { key => "vonage-fromnumber", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
+ {
+ 'key' => 'default_appointment_length',
+ 'section' => 'UI',
+ 'description' => 'Default appointment length, in minutes (30 minute granularity).',
+ 'type' => 'text',
+ },
+
+ # for internal use only; test databases should declare this option and
+ # everyone else should pretend it doesn't exist
+ #{
+ # 'key' => 'no_random_ids',
+ # 'section' => '',
+ # 'description' => 'Replace random identifiers in UI code with a static string, for repeatable testing. Don\'t use in production.',
+ # 'type' => 'checkbox',
+ #},
);