X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2FConf.pm;h=f2b1bea56ae90694e033590905635772bed8cfb3;hb=16a91fd700e3c3e5ec051d2c3692275f9389aab4;hp=0bf1afeeb1f362051f587ef198abb0377e7a20d5;hpb=33aeb33a7fafaf099c679c6d7150b54b99e4810f;p=freeside.git diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 0bf1afeeb..f2b1bea56 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -1,9 +1,15 @@ package FS::Conf; -use vars qw($default_dir @config_items $DEBUG ); -use IO::File; -use File::Basename; +use vars qw($base_dir @config_items @card_types $DEBUG ); +use MIME::Base64; use FS::ConfItem; +use FS::ConfDefaults; +use FS::conf; +use FS::Record qw(qsearch qsearchs); +use FS::UID qw(dbh); + +$base_dir = '%%%FREESIDE_CONF%%%'; + $DEBUG = 0; @@ -15,13 +21,8 @@ FS::Conf - Freeside configuration values use FS::Conf; - $conf = new FS::Conf "/config/directory"; - - $FS::Conf::default_dir = "/config/directory"; $conf = new FS::Conf; - $dir = $conf->dir; - $value = $conf->config('key'); @list = $conf->config('key'); $bool = $conf->exists('key'); @@ -41,34 +42,33 @@ but this may change in the future. =over 4 -=item new [ DIRECTORY ] +=item new -Create a new configuration object. A directory arguement is required if -$FS::Conf::default_dir has not been set. +Create a new configuration object. =cut sub new { - my($proto,$dir) = @_; + my($proto) = @_; my($class) = ref($proto) || $proto; - my($self) = { 'dir' => $dir || $default_dir } ; + my($self) = { 'base_dir' => $base_dir }; bless ($self, $class); } -=item dir +=item base_dir -Returns the directory. +Returns the base directory. By default this is /usr/local/etc/freeside. =cut -sub dir { +sub base_dir { my($self) = @_; - my $dir = $self->{dir}; - -e $dir or die "FATAL: $dir doesn't exist!"; - -d $dir or die "FATAL: $dir isn't a directory!"; - -r $dir or die "FATAL: Can't read $dir!"; - -x $dir or die "FATAL: $dir not searchable (executable)!"; - $dir =~ /^(.*)$/; + my $base_dir = $self->{base_dir}; + -e $base_dir or die "FATAL: $base_dir doesn't exist!"; + -d $base_dir or die "FATAL: $base_dir isn't a directory!"; + -r $base_dir or die "FATAL: Can't read $base_dir!"; + -x $base_dir or die "FATAL: $base_dir not searchable (executable)!"; + $base_dir =~ /^(.*)$/; $1; } @@ -78,20 +78,29 @@ Returns the configuration value or values (depending on context) for key. =cut +sub _config { + my($self,$name,$agent)=@_; + my $hashref = { 'name' => $name }; + if (defined($agent) && $agent) { + $hashref->{agent} = $agent; + } + local $FS::Record::conf = undef; # XXX evil hack prevents recursion + my $cv = FS::Record::qsearchs('conf', $hashref); + if (!$cv && exists($hashref->{agent})) { + delete($hashref->{agent}); + $cv = FS::Record::qsearchs('conf', $hashref); + } + return $cv; +} + sub config { - my($self,$file)=@_; - my($dir)=$self->dir; - my $fh = new IO::File "<$dir/$file" or return; + my($self,$name,$agent)=@_; + my $cv = $self->_config($name, $agent) or return; + if ( wantarray ) { - map { - /^(.*)$/ - or die "Illegal line (array context) in $dir/$file:\n$_\n"; - $1; - } <$fh>; + split "\n", $cv->value; } else { - <$fh> =~ /^(.*)$/ - or die "Illegal line (scalar context) in $dir/$file:\n$_\n"; - $1; + (split("\n", $cv->value))[0]; } } @@ -102,12 +111,9 @@ Returns the exact scalar value for key. =cut sub config_binary { - my($self,$file)=@_; - my($dir)=$self->dir; - my $fh = new IO::File "<$dir/$file" or return; - local $/; - my $content = <$fh>; - $content; + my($self,$name,$agent)=@_; + my $cv = $self->_config($name, $agent) or return; + decode_base64($cv->value); } =item exists KEY @@ -118,9 +124,8 @@ is undefined. =cut sub exists { - my($self,$file)=@_; - my($dir) = $self->dir; - -e "$dir/$file"; + my($self,$name,$agent)=@_; + defined($self->_config($name, $agent)); } =item config_orbase KEY SUFFIX @@ -131,11 +136,11 @@ KEY_SUFFIX, if it exists, otherwise for KEY =cut sub config_orbase { - my( $self, $file, $suffix ) = @_; - if ( $self->exists("${file}_$suffix") ) { - $self->config("${file}_$suffix"); + my( $self, $name, $suffix ) = @_; + if ( $self->exists("${name}_$suffix") ) { + $self->config("${name}_$suffix"); } else { - $self->config($file); + $self->config($name); } } @@ -146,12 +151,8 @@ Creates the specified configuration key if it does not exist. =cut sub touch { - my($self, $file) = @_; - my $dir = $self->dir; - unless ( $self->exists($file) ) { - warn "[FS::Conf] TOUCH $file\n" if $DEBUG; - system('touch', "$dir/$file"); - } + my($self, $name, $agent) = @_; + $self->set($name, '', $agent); } =item set KEY VALUE @@ -161,23 +162,41 @@ Sets the specified configuration key to the given value. =cut sub set { - my($self, $file, $value) = @_; - my $dir = $self->dir; + my($self, $name, $value, $agent) = @_; $value =~ /^(.*)$/s; $value = $1; - unless ( join("\n", @{[ $self->config($file) ]}) eq $value ) { - warn "[FS::Conf] SET $file\n" if $DEBUG; -# warn "$dir" if is_tainted($dir); -# warn "$dir" if is_tainted($file); - chmod 0644, "$dir/$file"; - my $fh = new IO::File ">$dir/$file" or return; - chmod 0644, "$dir/$file"; - print $fh "$value\n"; + + warn "[FS::Conf] SET $file\n" if $DEBUG; + + my $old = FS::Record::qsearchs('conf', {name => $name, agent => $agent}); + my $new = new FS::conf { $old ? $old->hash + : ('name' => $name, 'agent' => $agent) + }; + $new->value($value); + + my $error; + if ($old) { + $error = $new->replace($old); + } else { + $error = $new->insert; } + + die "error setting configuration value: $error \n" + if $error; + +} + +=item set_binary KEY VALUE + +Sets the specified configuration key to an exact scalar value which +can be retrieved with config_binary. + +=cut + +sub set_binary { + my($self,$name, $value, $agent)=@_; + $self->set($name, encode_base64($value), $agent); } -#sub is_tainted { -# return ! eval { join('',@_), kill 0; 1; }; -# } =item delete KEY @@ -186,11 +205,23 @@ Deletes the specified configuration key. =cut sub delete { - my($self, $file) = @_; - my $dir = $self->dir; - if ( $self->exists($file) ) { + my($self, $name, $agent) = @_; + if ( my $cv = FS::Record::qsearchs('conf', {name => $name, agent => $agent}) ) { warn "[FS::Conf] DELETE $file\n"; - unlink "$dir/$file"; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $error = $cv->delete; + + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + die "error setting configuration value: $error \n" + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + } } @@ -206,65 +237,68 @@ sub config_items { #quelle kludge @config_items, ( map { - my $basename = basename($_); - $basename =~ /^(.*)$/; - $basename = $1; new FS::ConfItem { - 'key' => $basename, + 'key' => $_->name, 'section' => 'billing', 'description' => 'Alternate template file for invoices. See the billing documentation for details.', 'type' => 'textarea', } - } glob($self->dir. '/invoice_template_*') + } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_template!_%' ESCAPE '!'") + ), + ( map { + new FS::ConfItem { + 'key' => '$_->name', + 'section' => 'billing', #? + 'description' => 'An image to include in some types of invoices', + 'type' => 'binary', + } + } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'logo!_%.png' ESCAPE '!'") ), ( map { - my $basename = basename($_); - $basename =~ /^(.*)$/; - $basename = $1; new FS::ConfItem { - 'key' => $basename, + 'key' => $_->name, 'section' => 'billing', 'description' => 'Alternate HTML template for invoices. See the billing documentation for details.', 'type' => 'textarea', } - } glob($self->dir. '/invoice_html_*') + } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_html!_%' ESCAPE '!'") ), ( map { - my $basename = basename($_); - $basename =~ /^(.*)$/; - $basename = $1; - ($latexname = $basename ) =~ s/latex/html/; + ($latexname = $_->name ) =~ s/latex/html/; new FS::ConfItem { - 'key' => $basename, + 'key' => $_->name, 'section' => 'billing', 'description' => "Alternate Notes section for HTML invoices. Defaults to the same data in $latexname if not specified.", 'type' => 'textarea', } - } glob($self->dir. '/invoice_htmlnotes_*') + } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_htmlnotes!_%' ESCAPE '!'") ), ( map { - my $basename = basename($_); - $basename =~ /^(.*)$/; - $basename = $1; new FS::ConfItem { - 'key' => $basename, + 'key' => $_->name, 'section' => 'billing', 'description' => 'Alternate LaTeX template for invoices. See the billing documentation for details.', 'type' => 'textarea', } - } glob($self->dir. '/invoice_latex_*') + } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_latex!_%' ESCAPE '!'") ), ( map { - my $basename = basename($_); - $basename =~ /^(.*)$/; - $basename = $1; new FS::ConfItem { - 'key' => $basename, + 'key' => '$_->name', + 'section' => 'billing', #? + 'description' => 'An image to include in some types of invoices', + 'type' => 'binary', + } + } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'logo!_%.eps' ESCAPE '!'") + ), + ( map { + new FS::ConfItem { + 'key' => $_->name, 'section' => 'billing', 'description' => 'Alternate Notes section for LaTeX typeset PostScript invoices. See the billing documentation for details.', 'type' => 'textarea', } - } glob($self->dir. '/invoice_latexnotes_*') + } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_latexnotes!_%' ESCAPE '!'") ); } @@ -283,6 +317,20 @@ httemplate/docs/config.html =cut +#Business::CreditCard +@card_types = ( + "VISA card", + "MasterCard", + "Discover card", + "American Express card", + "Diner's Club/Carte Blanche", + "enRoute", + "JCB", + "BankCard", + "Switch", + "Solo", +); + @config_items = map { new FS::ConfItem $_ } ( { @@ -411,6 +459,17 @@ httemplate/docs/config.html 'type' => 'text', }, + { + 'key' => 'date_format', + 'section' => 'UI', + 'description' => 'Format for displaying dates', + 'type' => 'select', + 'select_hash' => [ + '%m/%d/%Y' => 'MM/DD/YYYY', + '%Y/%m/%d' => 'YYYY/MM/DD', + ], + }, + { 'key' => 'cyrus', 'section' => 'deprecated', @@ -434,29 +493,36 @@ httemplate/docs/config.html { 'key' => 'deletepayments', - 'section' => 'UI', - 'description' => 'Enable deletion of unclosed payments. Be very careful! Only delete payments that were data-entry errors, not adjustments. Optionally specify one or more comma-separated email addresses to be notified when a payment is deleted.', + 'section' => 'billing', + 'description' => 'Enable deletion of unclosed payments. Really, with voids this is pretty much not recommended in any situation anymore. Be very careful! Only delete payments that were data-entry errors, not adjustments. Optionally specify one or more comma-separated email addresses to be notified when a payment is deleted.', 'type' => [qw( checkbox text )], }, { 'key' => 'deletecredits', - 'section' => 'UI', - 'description' => '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' => 'deprecated', + 'description' => 'DEPRECATED, 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.', 'type' => [qw( checkbox text )], }, + { + 'key' => 'deleterefunds', + 'section' => 'billing', + 'description' => 'Enable deletion of unclosed refunds. Be very careful! Only delete refunds that were data-entry errors, not adjustments.', + 'type' => 'checkbox', + }, + { 'key' => 'unapplypayments', - 'section' => 'UI', - 'description' => 'Enable "unapplication" of unclosed payments.', + 'section' => 'deprecated', + 'description' => 'DEPRECATED, now controlled by ACLs. Used to enable "unapplication" of unclosed payments.', 'type' => 'checkbox', }, { 'key' => 'unapplycredits', - 'section' => 'UI', - 'description' => 'Enable "unapplication" of unclosed credits.', + 'section' => 'deprecated', + 'description' => 'DEPRECATED, now controlled by ACLs. Used to nable "unapplication" of unclosed credits.', 'type' => 'checkbox', }, @@ -502,6 +568,13 @@ httemplate/docs/config.html 'type' => 'checkbox', }, + { + 'key' => 'emailinvoiceautoalways', + 'section' => 'billing', + 'description' => 'Automatically adds new accounts to the email invoice list even when the list contains email addresses', + 'type' => 'checkbox', + }, + { 'key' => 'exclude_ip_addr', 'section' => '', @@ -512,7 +585,7 @@ httemplate/docs/config.html { 'key' => 'erpcdmachines', 'section' => 'deprecated', - 'description' => 'DEPRECATED, ERPCD is no longer supported. Used to be ERPCD authenticaion machines, one per line. This enables export of `/usr/annex/acp_passwd\' and `/usr/annex/acp_dialup\'', + 'description' => 'DEPRECATED, ERPCD is no longer supported. Used to be ERPCD authentication machines, one per line. This enables export of `/usr/annex/acp_passwd\' and `/usr/annex/acp_dialup\'', 'type' => 'textarea', }, @@ -987,6 +1060,13 @@ httemplate/docs/config.html 'type' => 'checkbox', }, + { + 'key' => 'unsuspend-always_adjust_next_bill_date', + 'section' => 'billing', + 'description' => 'Global override that causes unsuspensions to always adjust the next bill date under any circumstances. This is now controlled on a per-package bases - probably best not to use this option unless you are a legacy installation that requires this behaviour.', + 'type' => 'checkbox', + }, + { 'key' => 'usernamemin', 'section' => 'username', @@ -1176,15 +1256,63 @@ httemplate/docs/config.html { 'key' => 'signup_server-default_agentnum', 'section' => '', - 'description' => 'Default agentnum for the signup server', - 'type' => 'text', + 'description' => 'Default agent for the signup server', + 'type' => 'select-sub', + 'options_sub' => sub { require FS::Record; + require FS::agent; + map { $_->agentnum => $_->agent } + FS::Record::qsearch('agent', { disabled=>'' } ); + }, + 'option_sub' => sub { require FS::Record; + require FS::agent; + my $agent = FS::Record::qsearchs( + 'agent', { 'agentnum'=>shift } + ); + $agent ? $agent->agent : ''; + }, }, { 'key' => 'signup_server-default_refnum', 'section' => '', - 'description' => 'Default advertising source number for the signup server', - 'type' => 'text', + 'description' => 'Default advertising source for the signup server', + 'type' => 'select-sub', + 'options_sub' => sub { require FS::Record; + require FS::part_referral; + map { $_->refnum => $_->referral } + FS::Record::qsearch( 'part_referral', + { 'disabled' => '' } + ); + }, + 'option_sub' => sub { require FS::Record; + require FS::part_referral; + my $part_referral = FS::Record::qsearchs( + 'part_referral', { 'refnum'=>shift } ); + $part_referral ? $part_referral->referral : ''; + }, + }, + + { + 'key' => 'signup_server-default_pkgpart', + 'section' => '', + 'description' => 'Default pakcage for the signup server', + 'type' => 'select-sub', + 'options_sub' => sub { require FS::Record; + require FS::part_pkg; + map { $_->pkgpart => $_->pkg.' - '.$_->comment } + FS::Record::qsearch( 'part_pkg', + { 'disabled' => ''} + ); + }, + 'option_sub' => sub { require FS::Record; + require FS::part_pkg; + my $part_pkg = FS::Record::qsearchs( + 'part_pkg', { 'pkgpart'=>shift } + ); + $part_pkg + ? $part_pkg->pkg.' - '.$part_pkg->comment + : ''; + }, }, { @@ -1200,6 +1328,50 @@ httemplate/docs/config.html 'description' => 'Run billing for signup server signups immediately, and do not provision accounts which subsequently have a balance.', 'type' => 'checkbox', }, + { + 'key' => 'signup_server-classnum2', + 'section' => '', + 'description' => 'Package Class for first optional purchase', + 'type' => 'select-sub', + 'options_sub' => sub { require FS::Record; + require FS::pkg_class; + map { $_->classnum => $_->classname } + FS::Record::qsearch('pkg_class', {} ); + }, + 'option_sub' => sub { require FS::Record; + require FS::pkg_class; + my $pkg_class = FS::Record::qsearchs( + 'pkg_class', { 'classnum'=>shift } + ); + $pkg_class ? $pkg_class->classname : ''; + }, + }, + + { + 'key' => 'signup_server-classnum3', + 'section' => '', + 'description' => 'Package Class for second optional purchase', + 'type' => 'select-sub', + 'options_sub' => sub { require FS::Record; + require FS::pkg_class; + map { $_->classnum => $_->classname } + FS::Record::qsearch('pkg_class', {} ); + }, + 'option_sub' => sub { require FS::Record; + require FS::pkg_class; + my $pkg_class = FS::Record::qsearchs( + 'pkg_class', { 'classnum'=>shift } + ); + $pkg_class ? $pkg_class->classname : ''; + }, + }, + + { + 'key' => 'backend-realtime', + 'section' => '', + 'description' => 'Run billing for backend signups immediately.', + 'type' => 'checkbox', + }, { 'key' => 'declinetemplate', @@ -1257,6 +1429,13 @@ httemplate/docs/config.html 'type' => 'checkbox', }, + { + 'key' => 'require_taxclasses', + 'section' => 'billing', + 'description' => 'Require a taxclass to be entered for every package', + 'type' => 'checkbox', + }, + { 'key' => 'welcome_email', 'section' => '', @@ -1286,12 +1465,56 @@ httemplate/docs/config.html 'select_enum' => [ 'text/plain', 'text/html' ], }, + { + 'key' => 'warning_email', + 'section' => '', + '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 Text::Template documentation for details on the template substitution language. The following variables are available
$username
$password
$first
$last
$pkg
$column
$amount
$threshold
DBI:Pg:user=rt_user;password=rt_word;host=rt.example.com;dbname=rt
',
+ 'type' => 'text',
+
+ },
+
+ {
+ 'key' => 'ticket_system-rt_external_url',
+ 'section' => '',
+ 'description' => 'With external RT integration, the URL for the external RT installation, for example, https://rt.example.com/rt
',
+ 'type' => 'text',
+ },
+
{
'key' => 'company_name',
'section' => 'required',
@@ -1499,15 +1749,22 @@ httemplate/docs/config.html
{
'key' => 'echeck-void',
- 'section' => 'billing',
- 'description' => 'Enable local-only voiding of echeck payments in addition to refunds against the payment gateway',
+ 'section' => 'deprecated',
+ 'description' => 'DEPRECATED, 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' => 'billing',
- 'description' => 'Enable local-only voiding of credit card payments in addition to refunds against the payment gateway',
+ 'section' => 'deprecated',
+ 'description' => 'DEPRECATED, 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' => 'DEPRECATED, now controlled by ACLs. Used to enable unvoiding of voided payments',
'type' => 'checkbox',
},
@@ -1541,32 +1798,30 @@ httemplate/docs/config.html
{
'key' => 'svc_acct-usage_suspend',
'section' => 'billing',
- 'description' => 'Suspends the package an account belongs to when svc_acct.seconds is decremented to 0 or below (accounts with an empty seconds value are ignored). Typically used in conjunction with prepaid packages and freeside-sqlradius-radacctd.',
+ 'description' => 'Suspends the package an account belongs to when svc_acct.seconds or a bytecount is decremented to 0 or below (accounts with an empty seconds and up|down|totalbytes value are ignored). Typically used in conjunction with prepaid packages and freeside-sqlradius-radacctd.',
'type' => 'checkbox',
},
{
'key' => 'svc_acct-usage_unsuspend',
'section' => 'billing',
- 'description' => 'Unuspends the package an account belongs to when svc_acct.seconds is incremented from 0 or below to a positive value (accounts with an empty seconds value are ignored). Typically used in conjunction with prepaid packages and freeside-sqlradius-radacctd.',
+ 'description' => 'Unuspends the package an account belongs to when svc_acct.seconds or a bytecount is incremented from 0 or below to a positive value (accounts with an empty seconds and up|down|totalbytes value are ignored). Typically used in conjunction with prepaid packages and freeside-sqlradius-radacctd.',
'type' => 'checkbox',
},
+ {
+ 'key' => 'svc_acct-usage_threshold',
+ 'section' => 'billing',
+ 'description' => 'The threshold (expressed as percentage) of acct.seconds or acct.up|down|totalbytes at which a warning message is sent to a service holder. Typically used in conjunction with prepaid packages and freeside-sqlradius-radacctd. Defaults to 80.',
+ 'type' => 'text',
+ },
+
{
'key' => 'cust-fields',
'section' => 'UI',
- 'description' => 'Which customer fields to display on reports',
+ 'description' => 'Which customer fields to display on reports by default',
'type' => 'select',
- 'select_enum' => [
- 'Customer: Last, First or Company (Last, First)',
- 'Cust# | Customer: custnum | Last, First or Company (Last, First)',
- 'Name | Company: Last, First | Company',
- 'Cust# | Name | Company: custnum | Last, First | Company',
- '(bill) Customer | (service) Customer: Last, First or Company (Last, First) | (same for service address if present)',
- 'Cust# | (bill) Customer | (service) Customer: custnum | Last, First or Company (Last, First) | (same for service address if present)',
- '(bill) Name | (bill) Company | (service) Name | (service) Company: Last, First | Company | (same for service address if present)',
- 'Cust# | (bill) Name | (bill) Company | (service) Name | (service) Company: custnum | Last, First | Company | (same for service address if present)',
- ],
+ 'select_hash' => [ FS::ConfDefaults->cust_fields_avail() ],
},
{
@@ -1590,6 +1845,236 @@ httemplate/docs/config.html
'type' => 'checkbox',
},
+ {
+ 'key' => 'zone-underscore',
+ 'section' => 'BIND',
+ 'description' => 'Allow underscores in zone names. As underscores are illegal characters in zone names, this option is not recommended.',
+ 'type' => 'checkbox',
+ },
+
+ #these should become per-user...
+ {
+ 'key' => 'vonage-username',
+ 'section' => '',
+ 'description' => 'Vonage Click2Call username (see https://secure.click2callu.com/)',
+ 'type' => 'text',
+ },
+ {
+ 'key' => 'vonage-password',
+ 'section' => '',
+ 'description' => 'Vonage Click2Call username (see https://secure.click2callu.com/)',
+ 'type' => 'text',
+ },
+ {
+ 'key' => 'vonage-fromnumber',
+ 'section' => '',
+ 'description' => 'Vonage Click2Call number (see https://secure.click2callu.com/)',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'echeck-nonus',
+ 'section' => 'billing',
+ 'description' => 'Disable ABA-format account checking for Electronic Check payment info',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'voip-cust_cdr_spools',
+ 'section' => '',
+ 'description' => 'Enable the per-customer option for individual CDR spools.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'svc_forward-arbitrary_dst',
+ 'section' => '',
+ 'description' => "Allow forwards to point to arbitrary strings that don't necessarily look like email addresses. Only used when using forwards for weird, non-email things.",
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'tax-ship_address',
+ 'section' => 'billing',
+ 'description' => 'By default, tax calculations are done based on the billing address. Enable this switch to calculate tax based on the shipping address instead. Note: Tax reports can take a long time when enabled.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'batch-enable',
+ 'section' => 'billing',
+ 'description' => 'Enable credit card batching - leave disabled for real-time installations.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'batch-default_format',
+ 'section' => 'billing',
+ 'description' => 'Default format for batches.',
+ 'type' => 'select',
+ 'select_enum' => [ 'csv-td_canada_trust-merchant_pc_batch',
+ 'csv-chase_canada-E-xactBatch', 'BoM', 'PAP' ]
+ },
+
+ {
+ 'key' => 'batch-fixed_format-CARD',
+ 'section' => 'billing',
+ 'description' => 'Fixed (unchangeable) format for credit card batches.',
+ 'type' => 'select',
+ 'select_enum' => [ 'csv-td_canada_trust-merchant_pc_batch', 'BoM', 'PAP' ,
+ 'csv-chase_canada-E-xactBatch', 'BoM', 'PAP' ]
+ },
+
+ {
+ 'key' => 'batch-fixed_format-CHEK',
+ 'section' => 'billing',
+ 'description' => 'Fixed (unchangeable) format for electronic check batches.',
+ 'type' => 'select',
+ 'select_enum' => [ 'csv-td_canada_trust-merchant_pc_batch', 'BoM', 'PAP' ]
+ },
+
+ {
+ 'key' => 'batch-increment_expiration',
+ 'section' => 'billing',
+ 'description' => 'Increment expiration date years in batches until cards are current. Make sure this is acceptable to your batching provider before enabling.',
+ 'type' => 'checkbox'
+ },
+
+ {
+ 'key' => 'batchconfig-BoM',
+ 'section' => 'billing',
+ 'description' => 'Configuration for Bank of Montreal batching, seven lines: 1. Origin ID, 2. Datacenter, 3. Typecode, 4. Short name, 5. Long name, 6. Bank, 7. Bank account',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'batchconfig-PAP',
+ 'section' => 'billing',
+ 'description' => 'Configuration for PAP batching, seven lines: 1. Origin ID, 2. Datacenter, 3. Typecode, 4. Short name, 5. Long name, 6. Bank, 7. Bank account',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'batchconfig-csv-chase_canada-E-xactBatch',
+ 'section' => 'billing',
+ 'description' => 'Gateway ID for Chase Canada E-xact batching',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'payment_history-years',
+ 'section' => 'UI',
+ 'description' => 'Number of years of payment history to show by default. Currently defaults to 2.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'cust_main-use_comments',
+ 'section' => 'UI',
+ 'description' => 'Display free form comments on the customer edit screen. Useful as a scratch pad.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'cust_main-disable_notes',
+ 'section' => 'UI',
+ 'description' => 'Disable new style customer notes - timestamped and user identified customer notes. Useful in tracking who did what.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'cust_main_note-display_times',
+ 'section' => 'UI',
+ 'description' => 'Display full timestamps (not just dates) for customer notes.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'cust_main-ticket_statuses',
+ 'section' => 'UI',
+ 'description' => 'Show tickets with these statuses on the customer view page.',
+ 'type' => 'selectmultiple',
+ 'select_enum' => [qw( new open stalled resolved rejected deleted )],
+ },
+
+ {
+ 'key' => 'cust_main-max_tickets',
+ 'section' => 'UI',
+ 'description' => 'Maximum number of tickets to show on the customer view page.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'cust_main-skeleton_tables',
+ 'section' => '',
+ 'description' => 'Tables which will have skeleton records inserted into them for each customer. Syntax for specifying tables is unfortunately a tricky perl data structure for now.',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'cust_main-skeleton_custnum',
+ 'section' => '',
+ 'description' => 'Customer number specifying the source data to copy into skeleton tables for new customers.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'cust_main-enable_birthdate',
+ 'section' => 'UI',
+ 'descritpion' => 'Enable tracking of a birth date with each customer record',
+ 'type' => 'checkbox',
+ },
+
+ {
+ '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.',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'card-types',
+ 'section' => 'billing',
+ 'description' => 'Select one or more card types to enable only those card types. If no card types are selected, all card types are available.',
+ 'type' => 'selectmultiple',
+ 'select_enum' => \@card_types,
+ },
+
+ {
+ 'key' => 'dashboard-toplist',
+ 'section' => 'UI',
+ 'description' => 'List of items to display on the top of the front page',
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'impending_recur_template',
+ 'section' => 'billing',
+ 'description' => 'Template file for alerts about looming first time recurrant billing. See the Text::Template documentation for details on the template substitition language. Also see packages with a flat price plan The following variables are available$packages
allowing $packages->[0]
thru $packages->[n]
$package
the first package, same as $packages->[0]
$recurdates
allowing $recurdates->[0]
thru $recurdates->[n]
$recurdate
the first recurdate, same as $recurdate->[0]
$first
$last
$payby
$expdate
most likely only confuse
+ 'type' => 'textarea',
+ },
+
+ {
+ 'key' => 'logo.png',
+ 'section' => 'billing', #?
+ 'description' => 'An image to include in some types of invoices',
+ 'type' => 'binary',
+ },
+
+ {
+ 'key' => 'logo.eps',
+ 'section' => 'billing', #?
+ 'description' => 'An image to include in some types of invoices',
+ 'type' => 'binary',
+ },
+
+ {
+ 'key' => 'selfservice-ignore_quantity',
+ 'section' => '',
+ 'description' => 'Ignores service quantity restrictions in self-service context. Strongly not recommended - just set your quantities correctly in the first place.',
+ 'type' => 'checkbox',
+ },
);