start adding package locations, RT#4499
[freeside.git] / FS / FS / Conf.pm
index 0d680b2..9c9c6aa 100644 (file)
@@ -1,14 +1,18 @@
 package FS::Conf;
 
-use vars qw($default_dir $base_dir @config_items @card_types $DEBUG );
+use vars qw($base_dir @config_items @base_items @card_types $DEBUG);
+use Carp;
 use IO::File;
 use File::Basename;
+use MIME::Base64;
 use FS::ConfItem;
 use FS::ConfDefaults;
+use FS::Conf_compat17;
+use FS::conf;
+use FS::Record qw(qsearch qsearchs);
+use FS::UID qw(dbh datasrc use_confcompat);
 
 $base_dir = '%%%FREESIDE_CONF%%%';
-$default_dir = '%%%FREESIDE_CONF%%%';
-
 
 $DEBUG = 0;
 
@@ -20,13 +24,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');
@@ -46,39 +45,19 @@ 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,
-                'base_dir' => $base_dir,
-              };
+  my($self) = { 'base_dir' => $base_dir };
   bless ($self, $class);
 }
 
-=item dir
-
-Returns the conf directory.
-
-=cut
-
-sub 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 =~ /^(.*)$/;
-  $1;
-}
-
 =item base_dir
 
 Returns the base directory.  By default this is /usr/local/etc/freeside.
@@ -96,45 +75,67 @@ sub base_dir {
   $1;
 }
 
-=item config KEY
+=item config KEY [ AGENTNUM ]
 
 Returns the configuration value or values (depending on context) for key.
+The optional agent number selects an agent specific value instead of the
+global default if one is present.
 
 =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)=@_;
+  my $hashref = { 'name' => $name };
+  $hashref->{agentnum} = $agentnum;
+  local $FS::Record::conf = undef;  # XXX evil hack prevents recursion
+  my $cv = FS::Record::qsearchs('conf', $hashref);
+  if (!$cv && defined($agentnum) && $agentnum) {
+    $hashref->{agentnum} = '';
+    $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 = shift;
+  return $self->_usecompat('config', @_) if use_confcompat;
+
+  my($name,$agentnum)=@_;
+  my $cv = $self->_config($name, $agentnum) or return;
+
   if ( wantarray ) {
-    map {
-      /^(.*)$/
-        or die "Illegal line (array context) in $dir/$file:\n$_\n";
-      $1;
-    } <$fh>;
+    my $v = $cv->value;
+    chomp $v;
+    (split "\n", $v, -1);
   } else {
-    <$fh> =~ /^(.*)$/
-      or die "Illegal line (scalar context) in $dir/$file:\n$_\n";
-    $1;
+    (split("\n", $cv->value))[0];
   }
 }
 
-=item config_binary KEY
+=item config_binary KEY [ AGENTNUM ]
 
 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 = shift;
+  return $self->_usecompat('config_binary', @_) if use_confcompat;
+
+  my($name,$agentnum)=@_;
+  my $cv = $self->_config($name, $agentnum) or return;
+  decode_base64($cv->value);
 }
 
-=item exists KEY
+=item exists KEY [ AGENTNUM ]
 
 Returns true if the specified key exists, even if the corresponding value
 is undefined.
@@ -142,9 +143,11 @@ is undefined.
 =cut
 
 sub exists {
-  my($self,$file)=@_;
-  my($dir) = $self->dir;
-  -e "$dir/$file";
+  my $self = shift;
+  return $self->_usecompat('exists', @_) if use_confcompat;
+
+  my($name,$agentnum)=@_;
+  defined($self->_config($name, $agentnum));
 }
 
 =item config_orbase KEY SUFFIX
@@ -154,142 +157,346 @@ KEY_SUFFIX, if it exists, otherwise for KEY
 
 =cut
 
+# outmoded as soon as we shift to agentnum based config values
+# well, mostly.  still useful for e.g. late notices, etc. in that we want
+# these to fall back to standard values
 sub config_orbase {
-  my( $self, $file, $suffix ) = @_;
-  if ( $self->exists("${file}_$suffix") ) {
-    $self->config("${file}_$suffix");
+  my $self = shift;
+  return $self->_usecompat('config_orbase', @_) if use_confcompat;
+
+  my( $name, $suffix ) = @_;
+  if ( $self->exists("${name}_$suffix") ) {
+    $self->config("${name}_$suffix");
+  } else {
+    $self->config($name);
+  }
+}
+
+=item key_orbase KEY SUFFIX
+
+If the config value KEY_SUFFIX exists, returns KEY_SUFFIX, otherwise returns
+KEY.  Useful for determining which exact configuration option is returned by
+config_orbase.
+
+=cut
+
+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") ) {
+    "${name}_$suffix";
   } else {
-    $self->config($file);
+    $name;
+  }
+}
+
+=item invoice_templatenames
+
+Returns all possible invoice template names.
+
+=cut
+
+sub invoice_templatenames {
+  my( $self ) = @_;
+
+  my %templatenames = ();
+  foreach my $item ( $self->config_items ) {
+    foreach my $base ( @base_items ) {
+      my( $main, $ext) = split(/\./, $base);
+      $ext = ".$ext" if $ext;
+      if ( $item->key =~ /^${main}_(.+)$ext$/ ) {
+      $templatenames{$1}++;
+      }
+    }
   }
+  
+  sort keys %templatenames;
+
 }
 
-=item touch KEY
+=item touch KEY [ AGENT ];
 
 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 = shift;
+  return $self->_usecompat('touch', @_) if use_confcompat;
+
+  my($name, $agentnum) = @_;
+  unless ( $self->exists($name, $agentnum) ) {
+    $self->set($name, '', $agentnum);
   }
 }
 
-=item set KEY VALUE
+=item set KEY VALUE [ AGENTNUM ];
 
 Sets the specified configuration key to the given value.
 
 =cut
 
 sub set {
-  my($self, $file, $value) = @_;
-  my $dir = $self->dir;
+  my $self = shift;
+  return $self->_usecompat('set', @_) if use_confcompat;
+
+  my($name, $value, $agentnum) = @_;
   $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 $name\n" if $DEBUG;
+
+  my $old = FS::Record::qsearchs('conf', {name => $name, agentnum => $agentnum});
+  my $new = new FS::conf { $old ? $old->hash 
+                                : ('name' => $name, 'agentnum' => $agentnum)
+                         };
+  $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 [ AGENTNUM ]
+
+Sets the specified configuration key to an exact scalar value which
+can be retrieved with config_binary.
+
+=cut
+
+sub set_binary {
+  my $self  = shift;
+  return if use_confcompat;
+
+  my($name, $value, $agentnum)=@_;
+  $self->set($name, encode_base64($value), $agentnum);
 }
-#sub is_tainted {
-#             return ! eval { join('',@_), kill 0; 1; };
-#         }
 
-=item delete KEY
+=item delete KEY [ AGENTNUM ];
 
 Deletes the specified configuration key.
 
 =cut
 
 sub delete {
-  my($self, $file) = @_;
-  my $dir = $self->dir;
-  if ( $self->exists($file) ) {
-    warn "[FS::Conf] DELETE $file\n";
-    unlink "$dir/$file";
+  my $self = shift;
+  return $self->_usecompat('delete', @_) if use_confcompat;
+
+  my($name, $agentnum) = @_;
+  if ( my $cv = FS::Record::qsearchs('conf', {name => $name, agentnum => $agentnum}) ) {
+    warn "[FS::Conf] DELETE $name\n";
+
+    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;
+
+  }
+}
+
+=item import_config_item CONFITEM DIR 
+
+  Imports the item specified by the CONFITEM (see L<FS::ConfItem>) into
+the database as a conf record (see L<FS::conf>).  Imports from the file
+in the directory DIR.
+
+=cut
+
+sub import_config_item { 
+  my ($self,$item,$dir) = @_;
+  my $key = $item->key;
+  if ( -e "$dir/$key" && ! use_confcompat ) {
+    warn "Inserting $key\n" if $DEBUG;
+    local $/;
+    my $value = readline(new IO::File "$dir/$key");
+    if ($item->type eq 'binary') {
+      $self->set_binary($key, $value);
+    }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);
+
+  unless ($type eq 'binary') {
+    {
+      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;
+    }
+  }
+
+  if ($type eq 'binary') {
+    $error .= "$key fails binary comparison; "
+      unless scalar($self->config_binary($key)) eq scalar($compat->config_binary($key));
+  }
+
+  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
+#
+#Returns all of the possible extensible config items as FS::ConfItem objects.
+#See #L<FS::ConfItem>.  OPTIONS consists of name value pairs.  Possible
+#options include
+#
+# dir - the directory to search for configuration option files instead
+#       of using the conf records in the database
+#
+#cut
+
+#quelle kludge
+sub _orbase_items {
+  my ($self, %opt) = @_; 
+
+  my $listmaker = sub { my $v = shift;
+                        $v =~ s/_/!_/g;
+                        if ( $v =~ /\.(png|eps)$/ ) {
+                          $v =~ s/\./!_%./;
+                        }else{
+                          $v .= '!_%';
+                        }
+                        map { $_->name }
+                          FS::Record::qsearch( 'conf',
+                                               {},
+                                               '',
+                                               "WHERE name LIKE '$v' ESCAPE '!'"
+                                             );
+                      };
+
+  if (exists($opt{dir}) && $opt{dir}) {
+    $listmaker = sub { my $v = shift;
+                       if ( $v =~ /\.(png|eps)$/ ) {
+                         $v =~ s/\./_*./;
+                       }else{
+                         $v .= '_*';
+                       }
+                       map { basename $_ } glob($opt{dir}. "/$v" );
+                     };
+  }
+
+  ( map { 
+          my $proto;
+          my $base = $_;
+          for ( @config_items ) { $proto = $_; last if $proto->key eq $base;  }
+          die "don't know about $base items" unless $proto->key eq $base;
+
+          map { new FS::ConfItem { 
+                                   'key' => $_,
+                                   'section' => $proto->section,
+                                   'description' => 'Alternate ' . $proto->description . '  See the <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.7:Documentation:Administration#Invoice_templates">billing documentation</a> for details.',
+                                   'type' => $proto->type,
+                                 };
+              } &$listmaker($base);
+        } @base_items,
+  );
 }
 
 =item config_items
 
-Returns all of the possible configuration items as FS::ConfItem objects.  See
-L<FS::ConfItem>.
+Returns all of the possible global/default configuration items as
+FS::ConfItem objects.  See L<FS::ConfItem>.
 
 =cut
 
 sub config_items {
   my $self = shift; 
-  #quelle kludge
-  @config_items,
-  ( map { 
-        my $basename = basename($_);
-        $basename =~ /^(.*)$/;
-        $basename = $1;
-        new FS::ConfItem {
-                           'key'         => $basename,
-                           'section'     => 'billing',
-                           'description' => 'Alternate template file for invoices.  See the <a href="../docs/billing.html">billing documentation</a> for details.',
-                           'type'        => 'textarea',
-                         }
-      } glob($self->dir. '/invoice_template_*')
-  ),
-  ( map { 
-        my $basename = basename($_);
-        $basename =~ /^(.*)$/;
-        $basename = $1;
-        new FS::ConfItem {
-                           'key'         => $basename,
-                           'section'     => 'billing',
-                           'description' => 'Alternate HTML template for invoices.  See the <a href="../docs/billing.html">billing documentation</a> for details.',
-                           'type'        => 'textarea',
-                         }
-      } glob($self->dir. '/invoice_html_*')
-  ),
-  ( map { 
-        my $basename = basename($_);
-        $basename =~ /^(.*)$/;
-        $basename = $1;
-        ($latexname = $basename ) =~ s/latex/html/;
-        new FS::ConfItem {
-                           'key'         => $basename,
-                           '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_*')
-  ),
-  ( map { 
-        my $basename = basename($_);
-        $basename =~ /^(.*)$/;
-        $basename = $1;
-        new FS::ConfItem {
-                           'key'         => $basename,
-                           'section'     => 'billing',
-                           'description' => 'Alternate LaTeX template for invoices.  See the <a href="../docs/billing.html">billing documentation</a> for details.',
-                           'type'        => 'textarea',
-                         }
-      } glob($self->dir. '/invoice_latex_*')
-  ),
-  ( map { 
-        my $basename = basename($_);
-        $basename =~ /^(.*)$/;
-        $basename = $1;
-        new FS::ConfItem {
-                           'key'         => $basename,
-                           'section'     => 'billing',
-                           'description' => 'Alternate Notes section for LaTeX typeset PostScript invoices.  See the <a href="../docs/billing.html">billing documentation</a> for details.',
-                           'type'        => 'textarea',
-                         }
-      } glob($self->dir. '/invoice_latexnotes_*')
-  );
+  return $self->_usecompat('config_items', @_) if use_confcompat;
+
+  ( @config_items, $self->_orbase_items(@_) );
+}
+
+=back
+
+=head1 SUBROUTINES
+
+=over 4
+
+=item init-config DIR
+
+Imports the non-deprecated configuration items from DIR (1.7 compatible)
+to conf records in the database.
+
+=cut
+
+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;
+    }
+  }
+
+  $FS::UID::use_confcompat = 0;
+  '';  #success
 }
 
 =back
@@ -303,8 +510,6 @@ worry that config_items is freeside-specific and icky.
 
 "Configuration" in the web interface (config/config.cgi).
 
-httemplate/docs/config.html
-
 =cut
 
 #Business::CreditCard
@@ -321,6 +526,22 @@ httemplate/docs/config.html
   "Solo",
 );
 
+@base_items = qw (
+                   invoice_template
+                   invoice_latex
+                   invoice_latexreturnaddress
+                   invoice_latexfooter
+                   invoice_latexsmallfooter
+                   invoice_latexnotes
+                   invoice_latexcoupon
+                   invoice_html
+                   invoice_htmlreturnaddress
+                   invoice_htmlfooter
+                   invoice_htmlnotes
+                   logo.png
+                   logo.eps
+                 );
+
 @config_items = map { new FS::ConfItem $_ } (
 
   {
@@ -333,18 +554,11 @@ httemplate/docs/config.html
   {
     'key'         => 'alerter_template',
     'section'     => 'billing',
-    'description' => 'Template file for billing method expiration alerts.  See the <a href="../docs/billing.html#invoice_template">billing documentation</a> for details.',
+    'description' => 'Template file for billing method expiration alerts.  See the <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.7:Documentation:Administration#Credit_cards_and_Electronic_checks">billing documentation</a> for details.',
     'type'        => 'textarea',
   },
 
   {
-    'key'         => 'apacheroot',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>www_shellcommands</i> <a href="../browse/part_export.cgi">export</a> instead.  The directory containing Apache virtual hosts',
-    'type'        => 'text',
-  },
-
-  {
     'key'         => 'apacheip',
     'section'     => 'deprecated',
     'description' => '<b>DEPRECATED</b>, add an <i>apache</i> <a href="../browse/part_export.cgi">export</a> instead.  Used to be the current IP address to assign to new virtual hosts',
@@ -352,34 +566,6 @@ httemplate/docs/config.html
   },
 
   {
-    'key'         => 'apachemachine',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>www_shellcommands</i> <a href="../browse/part_export.cgi">export</a> instead.  A machine with the apacheroot directory and user home directories.  The existance of this file enables setup of virtual host directories, and, in conjunction with the `home\' configuration file, symlinks into user home directories.',
-    'type'        => 'text',
-  },
-
-  {
-    'key'         => 'apachemachines',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add an <i>apache</i> <a href="../browse/part_export.cgi">export</a> instead.  Used to be Apache machines, one per line.  This enables export of `/etc/apache/vhosts.conf\', which can be included in your Apache configuration via the <a href="http://www.apache.org/docs/mod/core.html#include">Include</a> directive.',
-    'type'        => 'textarea',
-  },
-
-  {
-    'key'         => 'bindprimary',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>bind</i> <a href="../browse/part_export.cgi">export</a> instead.  Your BIND primary nameserver.  This enables export of /var/named/named.conf and zone files into /var/named',
-    'type'        => 'text',
-  },
-
-  {
-    'key'         => 'bindsecondaries',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>bind_slave</i> <a href="../browse/part_export.cgi">export</a> instead.  Your BIND secondary nameservers, one per line.  This enables export of /var/named/named.conf',
-    'type'        => 'textarea',
-  },
-
-  {
     'key'         => 'encryption',
     'section'     => 'billing',
     'description' => 'Enable encryption of credit cards.',
@@ -436,10 +622,10 @@ httemplate/docs/config.html
   },
 
   {
-    'key'         => 'bsdshellmachines',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>bsdshell</i> <a href="../browse/part_export.cgi">export</a> instead.  Your BSD flavored shell (and mail) machines, one per line.  This enables export of `/etc/passwd\' and `/etc/master.passwd\'.',
-    'type'        => 'textarea',
+    'key'         => 'business-onlinepayment-email_customer',
+    'section'     => 'billing',
+    'description' => 'Controls the "email_customer" flag used by some Business::OnlinePayment processors to enable customer receipts.',
+    'type'        => 'checkbox',
   },
 
   {
@@ -461,20 +647,6 @@ httemplate/docs/config.html
   },
 
   {
-    'key'         => 'cyrus',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>cyrus</i> <a href="../browse/part_export.cgi">export</a> instead.  This option used to integrate with <a href="http://asg.web.cmu.edu/cyrus/imapd/">Cyrus IMAP Server</a>, three lines: IMAP server, admin username, and admin password.  Cyrus::IMAP::Admin should be installed locally and the connection to the server secured.',
-    'type'        => 'textarea',
-  },
-
-  {
-    'key'         => 'cp_app',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>cp</i> <a href="../browse/part_export.cgi">export</a> instead.  This option used to integrate with <a href="http://www.cp.net/">Critial Path Account Provisioning Protocol</a>, four lines: "host:port", username, password, and workgroup (for new users).',
-    'type'        => 'textarea',
-  },
-
-  {
     'key'         => 'deletecustomers',
     'section'     => 'UI',
     'description' => 'Enable customer deletions.  Be very careful!  Deleting a customer will remove all traces that this customer ever existed!  It should probably only be used when auditing a legacy database.  Normally, you cancel all of a customers\' packages if they cancel service.',
@@ -503,20 +675,6 @@ httemplate/docs/config.html
   },
 
   {
-    '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 nable "unapplication" of unclosed credits.',
-    'type'        => 'checkbox',
-  },
-
-  {
     'key'         => 'dirhash',
     'section'     => 'shell',
     'description' => 'Optional numeric value to control directory hashing.  If positive, hashes directories for the specified number of levels from the front of the username.  If negative, hashes directories for the specified number of levels from the end of the username.  Some examples: <ul><li>1: user -> <a href="#home">/home</a>/u/user<li>2: user -> <a href="#home">/home</a>/u/s/user<li>-1: user -> <a href="#home">/home</a>/r/user<li>-2: user -> <a href="#home">home</a>/r/e/user</ul>',
@@ -559,6 +717,13 @@ httemplate/docs/config.html
   },
 
   {
+    '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'     => '',
     'description' => 'Exclude these from the list of available broadband service IP addresses. (One per line)',
@@ -566,12 +731,12 @@ httemplate/docs/config.html
   },
   
   {
-    'key'         => 'erpcdmachines',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, 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',
+    'key'         => 'auto_router',
+    'section'     => '',
+    'description' => 'Automatically choose the correct router/block based on supplied ip address when possible while provisioning broadband services',
+    'type'        => 'checkbox',
   },
-
+  
   {
     'key'         => 'hidecancelledpackages',
     'section'     => 'UI',
@@ -588,57 +753,30 @@ httemplate/docs/config.html
 
   {
     'key'         => 'home',
-    'section'     => 'required',
+    'section'     => 'shell',
     'description' => 'For new users, prefixed to username to create a directory name.  Should have a leading but not a trailing slash.',
     'type'        => 'text',
   },
 
   {
-    'key'         => 'icradiusmachines',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add an <i>sqlradius</i> <a href="../browse/part_export.cgi">export</a> instead.  This option used to enable radcheck and radreply table population - by default in the Freeside database, or in the database specified by the <a href="http://rootwood.haze.st/aspside/config/config-view.cgi#icradius_secrets">icradius_secrets</a> config option (the radcheck and radreply tables needs to be created manually).  You do not need to use MySQL for your Freeside database to export to an ICRADIUS/FreeRADIUS MySQL database with this option.  <blockquote><b>ADDITIONAL DEPRECATED FUNCTIONALITY</b> (instead use <a href="http://www.mysql.com/documentation/mysql/bychapter/manual_MySQL_Database_Administration.html#Replication">MySQL replication</a> or point icradius_secrets to the external database) - your <a href="ftp://ftp.cheapnet.net/pub/icradius">ICRADIUS</a> machines or <a href="http://www.freeradius.org/">FreeRADIUS</a> (with MySQL authentication) machines, one per line.  Machines listed in this file will have the radcheck table exported to them.  Each line should contain four items, separted by whitespace: machine name, MySQL database name, MySQL username, and MySQL password.  For example: <CODE>"radius.isp.tld&nbsp;radius_db&nbsp;radius_user&nbsp;passw0rd"</CODE></blockquote>',
-    'type'        => [qw( checkbox textarea )],
-  },
-
-  {
-    'key'         => 'icradius_mysqldest',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add an <i>sqlradius</i> <a href="../browse/part_export.cgi">export</a> instead.  Used to be the destination directory for the MySQL databases, on the ICRADIUS/FreeRADIUS machines.  Defaults to "/usr/local/var/".',
-    'type'        => 'text',
-  },
-
-  {
-    'key'         => 'icradius_mysqlsource',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add an <i>sqlradius</i> <a href="../browse/part_export.cgi">export</a> instead.  Used to be the source directory for for the MySQL radcheck table files, on the Freeside machine.  Defaults to "/usr/local/var/freeside".',
-    'type'        => 'text',
-  },
-
-  {
-    'key'         => 'icradius_secrets',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add an <i>sqlradius</i> <a href="../browse/part_export.cgi">export</a> instead.  This option used to specify a database for ICRADIUS/FreeRADIUS export.  Three lines: DBI data source, username and password.',
-    'type'        => 'textarea',
-  },
-
-  {
     'key'         => 'invoice_from',
     'section'     => 'required',
     'description' => 'Return address on email invoices',
     'type'        => 'text',
+    'per_agent'   => 1,
   },
 
   {
     'key'         => 'invoice_template',
-    'section'     => 'required',
-    'description' => 'Required template file for invoices.  See the <a href="../docs/billing.html">billing documentation</a> for details.',
+    'section'     => 'billing',
+    'description' => 'Text template file for invoices.  Used if no invoice_html template is defined, and also seen by users using non-HTML capable mail clients.  See the <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.7:Documentation:Administration#Plaintext_invoice_templates">billing documentation</a> for details.',
     'type'        => 'textarea',
   },
 
   {
     'key'         => 'invoice_html',
     'section'     => 'billing',
-    'description' => 'Optional HTML template for invoices.  See the <a href="../docs/billing.html">billing documentation</a> for details.',
+    'description' => 'Optional HTML template for invoices.  See the <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.7:Documentation:Administration#HTML_invoice_templates">billing documentation</a> for details.',
 
     'type'        => 'textarea',
   },
@@ -667,7 +805,7 @@ httemplate/docs/config.html
   {
     'key'         => 'invoice_latex',
     'section'     => 'billing',
-    'description' => 'Optional LaTeX template for typeset PostScript invoices.  See the <a href="../docs/billing.html">billing documentation</a> for details.',
+    'description' => 'Optional LaTeX template for typeset PostScript invoices.  See the <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.7:Documentation:Administration#Typeset_.28LaTeX.29_invoice_templates">billing documentation</a> for details.',
     'type'        => 'textarea',
   },
 
@@ -686,6 +824,13 @@ httemplate/docs/config.html
   },
 
   {
+    'key'         => 'invoice_latexcoupon',
+    'section'     => 'billing',
+    'description' => 'Remittance coupon for LaTeX typeset PostScript invoices.',
+    'type'        => 'textarea',
+  },
+
+  {
     'key'         => 'invoice_latexreturnaddress',
     'section'     => 'billing',
     'description' => 'Return address for LaTeX typeset PostScript invoices.',
@@ -719,21 +864,28 @@ httemplate/docs/config.html
     'section'     => 'billing',
     'description' => 'Optional default invoice term, used to calculate a due date printed on invoices.',
     'type'        => 'select',
-    'select_enum' => [ '', 'Payable upon receipt', 'Net 0', 'Net 10', 'Net 15', 'Net 30', 'Net 45', 'Net 60' ],
+    'select_enum' => [ '', 'Payable upon receipt', 'Net 0', 'Net 10', 'Net 15', 'Net 20', 'Net 30', 'Net 45', 'Net 60' ],
   },
 
-  {
-    '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.',
+  { 
+    'key'         => 'invoice_sections',
+    'section'     => 'billing',
+    'description' => 'Split invoice into sections and label according to package class when enabled.',
+    'type'        => 'checkbox',
+  },
+
+  { 
+    'key'         => 'separate_usage',
+    'section'     => 'billing',
+    'description' => 'Split the rated call usage into a separate line from the recurring charges.',
     'type'        => 'checkbox',
   },
 
   {
     'key'         => 'payment_receipt_email',
     'section'     => 'billing',
-    'description' => 'Template file for payment receipts.  Payment receipts are sent to the customer email invoice destination(s) when a payment is received.  See the <a href="http://search.cpan.org/~mjd/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>$date</code> <li><code>$name</code> <li><code>$paynum</code> - Freeside payment number <li><code>$paid</code> - Amount of payment <li><code>$payby</code> - Payment type (Card, Check, Electronic check, etc.) <li><code>$payinfo</code> - Masked credit card number or check number <li><code>$balance</code> - New balance</ul>',
-    'type'        => 'textarea',
+    'description' => 'Template file for payment receipts.  Payment receipts are sent to the customer email invoice destination(s) when a payment is received.  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>$date</code> <li><code>$name</code> <li><code>$paynum</code> - Freeside payment number <li><code>$paid</code> - Amount of payment <li><code>$payby</code> - Payment type (Card, Check, Electronic check, etc.) <li><code>$payinfo</code> - Masked credit card number or check number <li><code>$balance</code> - New balance</ul>',
+    'type'        => [qw( checkbox textarea )],
   },
 
   {
@@ -744,31 +896,24 @@ httemplate/docs/config.html
   },
 
   {
-    'key'         => 'maildisablecatchall',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, now the default.  Turning this option on used to disable the requirement that each virtual domain have a catch-all mailbox.',
-    'type'        => 'checkbox',
-  },
-
-  {
-    'key'         => 'money_char',
-    'section'     => '',
-    'description' => 'Currency symbol - defaults to `$\'',
+    'key'         => 'lpr-postscript_prefix',
+    'section'     => 'billing',
+    'description' => 'Raw printer commands prepended to the beginning of postscript print jobs (evaluated as a double-quoted perl string - backslash escapes are available)',
     'type'        => 'text',
   },
 
   {
-    'key'         => 'mxmachines',
-    'section'     => 'deprecated',
-    'description' => 'MX entries for new domains, weight and machine, one per line, with trailing `.\'',
-    'type'        => 'textarea',
+    'key'         => 'lpr-postscript_suffix',
+    'section'     => 'billing',
+    'description' => 'Raw printer commands added to the end of postscript print jobs (evaluated as a double-quoted perl string - backslash escapes are available)',
+    'type'        => 'text',
   },
 
   {
-    'key'         => 'nsmachines',
-    'section'     => 'deprecated',
-    'description' => 'NS nameservers for new domains, one per line, with trailing `.\'',
-    'type'        => 'textarea',
+    'key'         => 'money_char',
+    'section'     => '',
+    'description' => 'Currency symbol - defaults to `$\'',
+    'type'        => 'text',
   },
 
   {
@@ -784,27 +929,6 @@ httemplate/docs/config.html
   },
 
   {
-    'key'         => 'arecords',
-    'section'     => 'deprecated',
-    'description' => 'A list of tab seperated CNAME records to add automatically when creating a domain',
-    'type'        => 'textarea',
-  },
-
-  {
-    'key'         => 'cnamerecords',
-    'section'     => 'deprecated',
-    'description' => 'A list of tab seperated CNAME records to add automatically when creating a domain',
-    'type'        => 'textarea',
-  },
-
-  {
-    'key'         => 'nismachines',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>.  Your NIS master (not slave master) machines, one per line.  This enables export of `/etc/global/passwd\' and `/etc/global/shadow\'.',
-    'type'        => 'textarea',
-  },
-
-  {
     'key'         => 'passwordmin',
     'section'     => 'password',
     'description' => 'Minimum password length (default 6)',
@@ -833,20 +957,6 @@ httemplate/docs/config.html
   },
 
   {
-    'key'         => 'qmailmachines',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add <i>qmail</i> and <i>shellcommands</i> <a href="../browse/part_export.cgi">exports</a> instead.  This option used to export `/var/qmail/control/virtualdomains\', `/var/qmail/control/recipientmap\', and `/var/qmail/control/rcpthosts\'.  Setting this option (even if empty) also turns on user `.qmail-extension\' file maintenance in conjunction with the <b>shellmachine</b> option.',
-    'type'        => [qw( checkbox textarea )],
-  },
-
-  {
-    'key'         => 'radiusmachines',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add an <i>sqlradius</i> <a href="../browse/part_export.cgi">export</a> instead.  This option used to export to be: your RADIUS authentication machines, one per line.  This enables export of `/etc/raddb/users\'.',
-    'type'        => 'textarea',
-  },
-
-  {
     'key'         => 'referraldefault',
     'section'     => 'UI',
     'description' => 'Default referral, specified by refnum',
@@ -860,14 +970,6 @@ httemplate/docs/config.html
 #  },
 
   {
-    'key'         => 'report_template',
-    'section'     => 'deprecated',
-    'description' => 'Deprecated template file for reports.',
-    'type'        => 'textarea',
-  },
-
-
-  {
     'key'         => 'maxsearchrecordsperpage',
     'section'     => 'UI',
     'description' => 'If set, number of search records to return per page.',
@@ -875,27 +977,6 @@ httemplate/docs/config.html
   },
 
   {
-    'key'         => 'sendmailconfigpath',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>sendmail</i> <a href="../browse/part_export.cgi">export</a> instead.  Used to be sendmail configuration file path.  Defaults to `/etc\'.  Many newer distributions use `/etc/mail\'.',
-    'type'        => 'text',
-  },
-
-  {
-    'key'         => 'sendmailmachines',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>sendmail</i> <a href="../browse/part_export.cgi">export</a> instead.  Used to be sendmail machines, one per line.  This enables export of `/etc/virtusertable\' and `/etc/sendmail.cw\'.',
-    'type'        => 'textarea',
-  },
-
-  {
-    'key'         => 'sendmailrestart',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>sendmail</i> <a href="../browse/part_export.cgi">export</a> instead.  Used to define the command which is run on sendmail machines after files are copied.',
-    'type'        => 'text',
-  },
-
-  {
     'key'         => 'session-start',
     'section'     => 'session',
     'description' => 'If defined, the command which is executed on the Freeside machine when a session begins.  The contents of the file are treated as a double-quoted perl string, with the following variables available: <code>$ip</code>, <code>$nasip</code> and <code>$nasfqdn</code>, which are the IP address of the starting session, and the IP address and fully-qualified domain name of the NAS this session is on.',
@@ -910,44 +991,8 @@ httemplate/docs/config.html
   },
 
   {
-    'key'         => 'shellmachine',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>shellcommands</i> <a href="../browse/part_export.cgi">export</a> instead.  This option used to contain a single machine with user home directories mounted.  This enables home directory creation, renaming and archiving/deletion.  In conjunction with `qmailmachines\', it also enables `.qmail-extension\' file maintenance.',
-    'type'        => 'text',
-  },
-
-  {
-    'key'         => 'shellmachine-useradd',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>shellcommands</i> <a href="../browse/part_export.cgi">export</a> instead.  This option used to contain command(s) to run on shellmachine when an account is created.  If the <b>shellmachine</b> option is set but this option is not, <code>useradd -d $dir -m -s $shell -u $uid $username</code> is the default.  If this option is set but empty, <code>cp -pr /etc/skel $dir; chown -R $uid.$gid $dir</code> is the default instead.  Otherwise the value is evaluated as a double-quoted perl string, with the following variables available: <code>$username</code>, <code>$uid</code>, <code>$gid</code>, <code>$dir</code>, and <code>$shell</code>.',
-    'type'        => [qw( checkbox text )],
-  },
-
-  {
-    'key'         => 'shellmachine-userdel',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>shellcommands</i> <a href="../browse/part_export.cgi">export</a> instead.  This option used to contain command(s) to run on shellmachine when an account is deleted.  If the <b>shellmachine</b> option is set but this option is not, <code>userdel $username</code> is the default.  If this option is set but empty, <code>rm -rf $dir</code> is the default instead.  Otherwise the value is evaluated as a double-quoted perl string, with the following variables available: <code>$username</code> and <code>$dir</code>.',
-    'type'        => [qw( checkbox text )],
-  },
-
-  {
-    'key'         => 'shellmachine-usermod',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>shellcommands</i> <a href="../browse/part_export.cgi">export</a> instead.  This option used to contain command(s) to run on shellmachine when an account is modified.  If the <b>shellmachine</b> option is set but this option is empty, <code>[ -d $old_dir ] &amp;&amp; mv $old_dir $new_dir || ( chmod u+t $old_dir; mkdir $new_dir; cd $old_dir; find . -depth -print | cpio -pdm $new_dir; chmod u-t $new_dir; chown -R $uid.$gid $new_dir; rm -rf $old_dir )</code> is the default.  Otherwise the contents of the file are treated as a double-quoted perl string, with the following variables available: <code>$old_dir</code>, <code>$new_dir</code>, <code>$uid</code> and <code>$gid</code>.',
-    #'type'        => [qw( checkbox text )],
-    'type'        => 'text',
-  },
-
-  {
-    'key'         => 'shellmachines',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>sysvshell</i> <a href="../browse/part_export.cgi">export</a> instead.  Your Linux and System V flavored shell (and mail) machines, one per line.  This enables export of `/etc/passwd\' and `/etc/shadow\' files.',
-     'type'        => 'textarea',
- },
-
-  {
     'key'         => 'shells',
-    'section'     => 'required',
+    'section'     => 'shell',
     'description' => 'Legal shells (think /etc/shells).  You probably want to `cut -d: -f7 /etc/passwd | sort | uniq\' initially so that importing doesn\'t fail with `Illegal shell\' errors, then remove any special entries afterwords.  A blank line specifies that an empty shell is permitted.',
     'type'        => 'textarea',
   },
@@ -962,7 +1007,7 @@ httemplate/docs/config.html
   {
     'key'         => 'signupurl',
     'section'     => 'UI',
-    'description' => 'if you are using customer-to-customer referrals, and you enter the URL of your <a href="../docs/signup.html">signup server CGI</a>, the customer view screen will display a customized link to the signup server with the appropriate customer as referral',
+    'description' => 'if you are using customer-to-customer referrals, and you enter the URL of your <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.7:Documentation:Self-Service_Installation">signup server CGI</a>, the customer view screen will display a customized link to the signup server with the appropriate customer as referral',
     'type'        => 'text',
   },
 
@@ -1023,20 +1068,6 @@ httemplate/docs/config.html
   },
 
   {
-    'key'         => 'radiusprepend',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, real-time text radius now edits an existing file in place - just (turn off freeside-queued and) edit your RADIUS users file directly.  The contents used to be be prepended to the top of the RADIUS users file (text exports only).',
-    'type'        => 'textarea',
-  },
-
-  {
-    'key'         => 'textradiusprepend',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, use RADIUS check attributes instead.  The contents used to be prepended to the first line of a user\'s RADIUS entry in text exports.',
-    'type'        => 'text',
-  },
-
-  {
     'key'         => 'unsuspendauto',
     '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',
@@ -1109,7 +1140,7 @@ httemplate/docs/config.html
   {
     'key'         => 'username-uppercase',
     'section'     => 'username',
-    'description' => 'Allow uppercase characters in usernames',
+    'description' => 'Allow uppercase characters in usernames.  Not recommended for use with FreeRADIUS with MySQL backend, which is case-insensitive by default.',
     'type'        => 'checkbox',
   },
 
@@ -1121,46 +1152,30 @@ httemplate/docs/config.html
   },
 
   {
-    'key'         => 'username_policy',
-    'section'     => 'deprecated',
-    'description' => 'This file controls the mechanism for preventing duplicate usernames in passwd/radius files exported from svc_accts.  This should be one of \'prepend domsvc\' \'append domsvc\' \'append domain\' or \'append @domain\'',
-    'type'        => 'select',
-    'select_enum' => [ 'prepend domsvc', 'append domsvc', 'append domain', 'append @domain' ],
-    #'type'        => 'text',
-  },
-
-  {
-    'key'         => 'vpopmailmachines',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>vpopmail</i> <a href="../browse/part_export.cgi">export</a> instead.  This option used to contain your vpopmail pop toasters, one per line.  Each line is of the form "machinename vpopdir vpopuid vpopgid".  For example: <code>poptoaster.domain.tld /home/vpopmail 508 508</code>  Note: vpopuid and vpopgid are values taken from the vpopmail machine\'s /etc/passwd',
-    'type'        => 'textarea',
-  },
-
-  {
-    'key'         => 'vpopmailrestart',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, add a <i>vpopmail</i> <a href="../browse/part_export.cgi">export</a> instead.  This option used to define the shell commands to run on vpopmail machines after files are copied.  An example can be found in eg/vpopmailrestart of the source distribution.',
-    'type'        => 'textarea',
+    'key'         => 'safe-part_bill_event',
+    'section'     => 'UI',
+    'description' => 'Validates invoice event expressions against a preset list.  Useful for webdemos, annoying to powerusers.',
+    'type'        => 'checkbox',
   },
 
   {
-    'key'         => 'safe-part_pkg',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, obsolete.  Used to validate package definition setup and recur expressions against a preset list.  Useful for webdemos, annoying to powerusers.',
+    'key'         => 'show_ss',
+    'section'     => 'UI',
+    'description' => 'Turns on display/collection of social security numbers in the web interface.  Sometimes required by electronic check (ACH) processors.',
     'type'        => 'checkbox',
   },
 
   {
-    'key'         => 'safe-part_bill_event',
+    'key'         => 'show_stateid',
     'section'     => 'UI',
-    'description' => 'Validates invoice event expressions against a preset list.  Useful for webdemos, annoying to powerusers.',
+    'description' => "Turns on display/collection of driver's license/state issued id numbers in the web interface.  Sometimes required by electronic check (ACH) processors.",
     'type'        => 'checkbox',
   },
 
   {
-    'key'         => 'show_ss',
+    'key'         => 'show_bankstate',
     'section'     => 'UI',
-    'description' => 'Turns on display/collection of SS# in the web interface.',
+    'description' => "Turns on display/collection of state for bank accounts in the web interface.  Sometimes required by electronic check (ACH) processors.",
     'type'        => 'checkbox',
   },
 
@@ -1208,20 +1223,6 @@ httemplate/docs/config.html
   },
 
   {
-    'key'         => 'selfservice_server-quiet',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, the self-service server no longer sends superfluous decline and cancel emails.  Used to disable decline and cancel emails generated by transactions initiated by the selfservice server.',
-    'type'        => 'checkbox',
-  },
-
-  {
-    'key'         => 'signup_server-quiet',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, the signup server is now part of the self-service server and no longer sends superfluous decline and cancel emails.  Used to disable decline and cancel emails generated by transactions initiated by the signup server.  Does not disable welcome emails.',
-    'type'        => 'checkbox',
-  },
-
-  {
     'key'         => 'signup_server-payby',
     'section'     => '',
     'description' => 'Acceptable payment types for the signup server',
@@ -1230,13 +1231,6 @@ httemplate/docs/config.html
   },
 
   {
-    'key'         => 'signup_server-email',
-    'section'     => 'deprecated',
-    'description' => '<b>DEPRECATED</b>, this feature is no longer available.  See the ***fill me in*** report instead.  Used to contain a comma-separated list of email addresses to receive notification of signups via the signup server.',
-    'type'        => 'text',
-  },
-
-  {
     'key'         => 'signup_server-default_agentnum',
     'section'     => '',
     'description' => 'Default agent for the signup server',
@@ -1278,7 +1272,7 @@ httemplate/docs/config.html
   {
     'key'         => 'signup_server-default_pkgpart',
     'section'     => '',
-    'description' => 'Default pakcage for the signup server',
+    'description' => 'Default package for the signup server',
     'type'        => 'select-sub',
     'options_sub' => sub { require FS::Record;
                            require FS::part_pkg;
@@ -1299,6 +1293,45 @@ httemplate/docs/config.html
   },
 
   {
+    'key'         => 'signup_server-default_svcpart',
+    'section'     => '',
+    'description' => 'Default svcpart for the signup server - only necessary for services that trigger special provisioning widgets (such as DID provisioning).',
+    'type'        => 'select-sub',
+    'options_sub' => sub { require FS::Record;
+                           require FS::part_svc;
+                           map { $_->svcpart => $_->svc }
+                               FS::Record::qsearch( 'part_svc',
+                                                   { 'disabled' => ''}
+                                                 );
+                        },
+    'option_sub'  => sub { require FS::Record;
+                           require FS::part_svc;
+                           my $part_svc = FS::Record::qsearchs(
+                            'part_svc', { 'svcpart'=>shift }
+                          );
+                           $part_svc ? $part_svc->svc : '';
+                        },
+  },
+
+  {
+    'key'         => 'signup_server-service',
+    'section'     => '',
+    'description' => 'Service for the signup server - "Account (svc_acct)" is the default setting, or "Phone number (svc_phone)" for ITSP signup',
+    'type'        => 'select',
+    'select_hash' => [
+                       'svc_acct'  => 'Account (svc_acct)',
+                       'svc_phone' => 'Phone number (svc_phone)',
+                     ],
+  },
+
+  {
+    'key'         => 'selfservice_server-base_url',
+    'section'     => '',
+    'description' => 'Base URL for the self-service web interface - necessary for special provisioning widgets to find their way.',
+    'type'        => 'text',
+  },
+
+  {
     'key'         => 'show-msgcat-codes',
     'section'     => 'UI',
     'description' => 'Show msgcat codes in error messages.  Turn this option on before reporting errors to the mailing list.',
@@ -1394,7 +1427,7 @@ httemplate/docs/config.html
   {
     'key'         => 'emailcancel',
     'section'     => 'billing',
-    'description' => 'Enable emailing of cancellation notices.',
+    'description' => 'Enable emailing of cancellation notices.  Make sure to fill in the cancelmessage and cancelsubject configuration values as well.',
     'type'        => 'checkbox',
   },
 
@@ -1420,10 +1453,18 @@ httemplate/docs/config.html
   },
 
   {
+    'key'         => 'enable_taxproducts',
+    'section'     => 'billing',
+    'description' => 'Enable per-package mapping to new style tax classes',
+    'type'        => 'checkbox',
+  },
+
+  {
     'key'         => 'welcome_email',
     'section'     => '',
-    '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.  See the <a href="http://search.cpan.org/~mjd/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></ul>',
+    '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.  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></ul>',
     'type'        => 'textarea',
+    'per_agent'   => 1,
   },
 
   {
@@ -1431,6 +1472,7 @@ httemplate/docs/config.html
     'section'     => '',
     'description' => 'From: address header for welcome email',
     'type'        => 'text',
+    'per_agent'   => 1,
   },
 
   {
@@ -1438,6 +1480,7 @@ httemplate/docs/config.html
     'section'     => '',
     'description' => 'Subject: header for welcome email',
     'type'        => 'text',
+    'per_agent'   => 1,
   },
   
   {
@@ -1446,12 +1489,20 @@ httemplate/docs/config.html
     'description' => 'MIME type for welcome email',
     'type'        => 'select',
     'select_enum' => [ 'text/plain', 'text/html' ],
+    '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_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 <a href="http://search.cpan.org/~mjd/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>',
+    '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',
   },
 
@@ -1501,6 +1552,13 @@ httemplate/docs/config.html
   },
 
   {
+    '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'     => 'UI',
     'description' => 'Extra HTML to be displayed on the Account View screen.',
@@ -1545,13 +1603,6 @@ httemplate/docs/config.html
   },
 
   {
-    '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'         => 'cvv-save',
     'section'     => 'billing',
     'description' => 'Save CVV2 information after the initial transaction for the selected credit card types.  Enabling this option may be in violation of your merchant agreement(s), so please check them carefully before enabling this option for any credit card types.',
@@ -1615,6 +1666,20 @@ httemplate/docs/config.html
   },
 
   {
+    'key'         => 'selfservice_server-phone_login',
+    'section'     => '',
+    'description' => 'Allow login to self-service with phone number and PIN.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'selfservice_server-single_domain',
+    'section'     => '',
+    'description' => 'If specified, only use this one domain for self-service access.',
+    'type'        => 'text',
+  },
+
+  {
     'key'         => 'card_refund-days',
     'section'     => 'billing',
     'description' => 'After a payment, the number of days a refund link will be available for that payment.  Defaults to 120.',
@@ -1637,6 +1702,14 @@ httemplate/docs/config.html
   },
 
   {
+    'key'         => 'global_unique-phonenum',
+    'section'     => '',
+    'description' => 'Global phone number uniqueness control: none (usual setting - check countrycode+phonenumun uniqueness per exports), or countrycode+phonenum (all countrycode+phonenum pairs are globally unique, regardless of exports).  disabled turns off duplicate checking completely and is STRONGLY NOT RECOMMENDED unless you REALLY need to turn this off.',
+    'type'        => 'select',
+    'select_enum' => [ 'none', 'countrycode+phonenum', 'disabled' ],
+  },
+
+  {
     'key'         => 'svc_external-skip_manual',
     'section'     => 'UI',
     'description' => 'When provisioning svc_external services, skip manual entry of id and title fields in the UI.  Usually used in conjunction with an export that populates these fields (i.e. artera_turbo).',
@@ -1654,7 +1727,7 @@ httemplate/docs/config.html
   {
     'key'         => 'ticket_system',
     'section'     => '',
-    'description' => 'Ticketing system integration.  <b>RT_Internal</b> uses the built-in RT ticketing system (see the <a href="../docs/install-rt">integrated ticketing installation instructions</a>).   <b>RT_External</b> accesses an external RT installation in a separate database (local or remote).',
+    'description' => 'Ticketing system integration.  <b>RT_Internal</b> uses the built-in RT ticketing system (see the <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.7:Documentation:RT_Installation">integrated ticketing installation instructions</a>).   <b>RT_External</b> accesses an external RT installation in a separate database (local or remote).',
     'type'        => 'select',
     #'select_enum' => [ '', qw(RT_Internal RT_Libs RT_External) ],
     'select_enum' => [ '', qw(RT_Internal RT_External) ],
@@ -1688,6 +1761,13 @@ httemplate/docs/config.html
   },
 
   {
+    'key'         => 'ticket_system-priority_reverse',
+    'section'     => '',
+    'description' => 'Enable this to consider lower numbered priorities more important.  A bad habit we picked up somewhere.  You probably want to avoid it and use the default.',
+    'type'        => 'checkbox',
+  },
+
+  {
     'key'         => 'ticket_system-custom_priority_field',
     'section'     => '',
     'description' => 'Custom field from the ticketing system to use as a custom priority classification.',
@@ -1728,39 +1808,41 @@ httemplate/docs/config.html
     'section'     => 'required',
     'description' => 'Your company name',
     'type'        => 'text',
+    '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'         => 'company_address',
+    'section'     => 'required',
+    'description' => 'Your company address',
+    'type'        => 'textarea',
+    'per_agent'   => 1,
   },
 
   {
-    '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',
+    'key'         => 'address2-search',
+    'section'     => 'UI',
+    'description' => 'Enable a "Unit" search box which searches the second address field.  Useful for multi-tenant applications.  See also: cust_main-require_address2',
     'type'        => 'checkbox',
   },
 
   {
-    'key'         => 'unvoid',
-    'section'     => 'deprecated',
-    'description' => '<B>DEPRECATED</B>, now controlled by ACLs.  Used to enable unvoiding of voided payments',
+    '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',
     'type'        => 'checkbox',
   },
 
   {
-    'key'         => 'address2-search',
-    'section'     => 'UI',
-    'description' => 'Enable a "Unit" search box which searches the second address field',
+    'key'         => 'agent-ship_address',
+    'section'     => '',
+    'description' => "Use the agent's master service address as the service address (only ship_address2 can be entered, if blank on the master address).  Useful for multi-tenant applications.",
     'type'        => 'checkbox',
   },
 
   { 'key'         => 'referral_credit',
-    'section'     => 'billing',
-    'description' => "Enables one-time referral credits in the amount of one month <i>referred</i> customer's recurring fee (irregardless of frequency).",
+    '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',
   },
 
@@ -1773,12 +1855,63 @@ httemplate/docs/config.html
 
   {
     'key'         => 'hylafax',
-    'section'     => '',
+    'section'     => 'billing',
     'description' => 'Options for a HylaFAX server to enable the FAX invoice destination.  They should be in the form of a space separated list of arguments to the Fax::Hylafax::Client::sendfax subroutine.  You probably shouldn\'t override things like \'docfile\'.  *Note* Only supported when using typeset invoices (see the invoice_latex configuration option).',
     'type'        => [qw( checkbox textarea )],
   },
 
   {
+    'key'         => 'cust_bill-ftpformat',
+    'section'     => 'billing',
+    'description' => 'Enable FTP of raw invoice data - format.',
+    'type'        => 'select',
+    'select_enum' => [ '', 'default', 'billco', ],
+  },
+
+  {
+    'key'         => 'cust_bill-ftpserver',
+    'section'     => 'billing',
+    'description' => 'Enable FTP of raw invoice data - server.',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'cust_bill-ftpusername',
+    'section'     => 'billing',
+    'description' => 'Enable FTP of raw invoice data - server.',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'cust_bill-ftppassword',
+    'section'     => 'billing',
+    'description' => 'Enable FTP of raw invoice data - server.',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'cust_bill-ftpdir',
+    'section'     => 'billing',
+    'description' => 'Enable FTP of raw invoice data - server.',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'cust_bill-spoolformat',
+    'section'     => 'billing',
+    'description' => 'Enable spooling of raw invoice data - format.',
+    'type'        => 'select',
+    'select_enum' => [ '', 'default', 'billco', ],
+  },
+
+  {
+    'key'         => 'cust_bill-spoolagent',
+    'section'     => 'billing',
+    'description' => 'Enable per-agent spooling of raw invoice data.',
+    'type'        => 'checkbox',
+  },
+
+  {
     'key'         => 'svc_acct-usage_suspend',
     'section'     => 'billing',
     '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.',
@@ -1835,26 +1968,6 @@ httemplate/docs/config.html
     'type'        => 'checkbox',
   },
 
-  #these should become per-user...
-  {
-    'key'         => 'vonage-username',
-    'section'     => '',
-    'description' => 'Vonage Click2Call username (see <a href="https://secure.click2callu.com/">https://secure.click2callu.com/</a>)',
-    'type'        => 'text',
-  },
-  {
-    'key'         => 'vonage-password',
-    'section'     => '',
-    'description' => 'Vonage Click2Call username (see <a href="https://secure.click2callu.com/">https://secure.click2callu.com/</a>)',
-    'type'        => 'text',
-  },
-  {
-    'key'         => 'vonage-fromnumber',
-    'section'     => '',
-    'description' => 'Vonage Click2Call number (see <a href="https://secure.click2callu.com/">https://secure.click2callu.com/</a>)',
-    'type'        => 'text',
-  },
-
   {
     'key'         => 'echeck-nonus',
     'section'     => 'billing',
@@ -1870,6 +1983,13 @@ httemplate/docs/config.html
   },
 
   {
+    'key'         => 'voip-cust_cdr_squelch',
+    'section'     => '',
+    'description' => 'Enable the per-customer option for not printing CDR on invoices.',
+    '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.",
@@ -1881,49 +2001,138 @@ httemplate/docs/config.html
     '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'         => 'tax-pkg_address',
+    'section'     => 'billing',
+    '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).  Note: Tax reports can take a long time when enabled.',
+    'type'        => 'checkbox',
   },
 
   {
-    'key'         => 'batch-enable',
+    'key'         => 'invoice-ship_address',
     'section'     => 'billing',
-    'description' => 'Enable credit card batching - leave disabled for real-time installations.',
+    'description' => 'Enable this switch to include the ship address on the invoice.',
     'type'        => 'checkbox',
   },
 
   {
-    'key'         => 'batch-default_format',
+    'key'         => 'invoice-unitprice',
     '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' ]
+    'description' => 'This switch enables unit pricing on the invoice.',
+    'type'        => 'checkbox',
   },
 
   {
-    'key'         => 'batch-fixed_format-CARD',
+    'key'         => 'postal_invoice-fee_pkgpart',
     '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' ]
+    'description' => 'This allows selection of a package to insert on invoices for customers with postal invoices selected.',
+    'type'        => 'select-sub',
+    'options_sub' => sub { require FS::Record;
+                           require FS::part_pkg;
+                          map { $_->pkgpart => $_->pkg }
+                               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 : '';
+                        },
   },
 
   {
-    'key'         => 'batch-fixed_format-CHEK',
+    'key'         => 'postal_invoice-recurring_only',
     'section'     => 'billing',
-    'description' => 'Fixed (unchangeable) format for electronic check batches.',
-    'type'        => 'select',
-    'select_enum' => [ 'csv-td_canada_trust-merchant_pc_batch', 'BoM', 'PAP' ]
+    'description' => 'The postal invoice fee is omitted on invoices without reucrring charges when this is set.',
+    'type'        => 'checkbox',
   },
 
   {
-    'key'         => 'batchconfig-BoM',
+    'key'         => 'batch-enable',
+    'section'     => 'deprecated', #make sure batch-enable_payby is set for
+                                   #everyone before removing
+    'description' => 'Enable credit card and/or ACH batching - leave disabled for real-time installations.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'batch-enable_payby',
+    'section'     => 'billing',
+    'description' => 'Enable batch processing for the specified payment types.',
+    'type'        => 'selectmultiple',
+    'select_enum' => [qw( CARD CHEK )],
+  },
+
+  {
+    'key'         => 'realtime-disable_payby',
+    'section'     => 'billing',
+    'description' => 'Disable realtime processing for the specified payment types.',
+    'type'        => 'selectmultiple',
+    'select_enum' => [qw( CARD CHEK )],
+  },
+
+  {
+    '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',
+                       'ach-spiritone',
+                    ]
+  },
+
+  {
+    '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',
+                       'ach-spiritone',
+                     ]
+  },
+
+  {
+    '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.',
@@ -2003,13 +2212,404 @@ httemplate/docs/config.html
   },
 
   {
+    'key'         => 'disable-fuzzy',
+    'section'     => 'UI',
+    'description' => 'Disable fuzzy searching.  Speeds up searching for large sites, but only shows exact matches.',
+    'type'        => 'checkbox',
+  },
+
+  { 'key'         => 'pkg_referral',
+    'section'     => '',
+    'description' => 'Enable package-specific advertising sources.',
+    'type'        => 'checkbox',
+  },
+
+  { 'key'         => 'pkg_referral-multiple',
+    'section'     => '',
+    'description' => 'In addition, allow multiple advertising sources to be associated with a single package.',
+    'type'        => 'checkbox',
+  },
+
+  {
     '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 <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'     => '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',
+  },
+
+  {
+    'key'         => 'selfservice-session_timeout',
+    'section'     => '',
+    'description' => 'Self-service session timeout.  Defaults to 1 hour.',
+    'type'        => 'select',
+    'select_enum' => [ '1 hour', '2 hours', '4 hours', '8 hours', '1 day', '1 week', ],
+  },
+
+  {
+    'key'         => 'disable_setup_suspended_pkgs',
+    'section'     => 'billing',
+    'description' => 'Disables charging of setup fees for suspended packages.',
+    'type'       => 'checkbox',
+  },
+
+  {
+    'key' => 'password-generated-allcaps',
+    'section' => 'password',
+    'description' => 'Causes passwords automatically generated to consist entirely of capital letters',
+    'type' => 'checkbox',
+  },
+
+  {
+    'key'         => 'datavolume-forcemegabytes',
+    'section'     => 'UI',
+    'description' => 'All data volumes are expressed in megabytes',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'datavolume-significantdigits',
+    'section'     => 'UI',
+    'description' => 'number of significant digits to use to represent data volumes',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'disable_void_after',
+    'section'     => 'billing',
+    'description' => 'Number of seconds after which freeside won\'t attempt to VOID a payment first when performing a refund.',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'disable_line_item_date_ranges',
+    'section'     => 'billing',
+    'description' => 'Prevent freeside from automatically generating date ranges on invoice line items.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'support_packages',
+    'section'     => '',
+    'description' => 'A list of packages eligible for RT ticket time transfer, one pkgpart per line.', #this should really be a select multiple, or specified in the packages themselves...
+    'type'        => 'textarea',
+  },
+
+  {
+    'key'         => 'cust_main-require_phone',
+    'section'     => '',
+    'description' => 'Require daytime or night phone for all customer records.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'cust_main-require_invoicing_list_email',
+    'section'     => '',
+    'description' => 'Email address field is required: require at least one invoicing email address for all customer records.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'svc_acct-display_paid_time_remaining',
+    'section'     => '',
+    'description' => 'Show paid time remaining in addition to time remaining.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'cancel_credit_type',
+    'section'     => 'billing',
+    'description' => 'The group to use for new, automatically generated credit reasons resulting from cancellation.',
+    'type'        => 'select-sub',
+    'options_sub' => sub { require FS::Record;
+                           require FS::reason_type;
+                          map { $_->typenum => $_->type }
+                               FS::Record::qsearch('reason_type', { class=>'R' } );
+                        },
+    'option_sub'  => sub { require FS::Record;
+                           require FS::reason_type;
+                          my $reason_type = FS::Record::qsearchs(
+                            'reason_type', { 'typenum' => shift }
+                          );
+                           $reason_type ? $reason_type->type : '';
+                        },
+  },
+
+  {
+    'key'         => 'referral_credit_type',
+    'section'     => 'deprecated',
+    'description' => 'Used to be the group to use for new, automatically generated credit reasons resulting from referrals.  Now set in a package billing event for the referral.',
+    'type'        => 'select-sub',
+    'options_sub' => sub { require FS::Record;
+                           require FS::reason_type;
+                          map { $_->typenum => $_->type }
+                               FS::Record::qsearch('reason_type', { class=>'R' } );
+                        },
+    'option_sub'  => sub { require FS::Record;
+                           require FS::reason_type;
+                          my $reason_type = FS::Record::qsearchs(
+                            'reason_type', { 'typenum' => shift }
+                          );
+                           $reason_type ? $reason_type->type : '';
+                        },
+  },
+
+  {
+    'key'         => 'signup_credit_type',
+    'section'     => 'billing',
+    'description' => 'The group to use for new, automatically generated credit reasons resulting from signup and self-service declines.',
+    'type'        => 'select-sub',
+    'options_sub' => sub { require FS::Record;
+                           require FS::reason_type;
+                          map { $_->typenum => $_->type }
+                               FS::Record::qsearch('reason_type', { class=>'R' } );
+                        },
+    'option_sub'  => sub { require FS::Record;
+                           require FS::reason_type;
+                          my $reason_type = FS::Record::qsearchs(
+                            'reason_type', { 'typenum' => shift }
+                          );
+                           $reason_type ? $reason_type->type : '';
+                        },
+  },
+
+  {
+    'key'         => 'cust_main-agent_custid-format',
+    'section'     => '',
+    'description' => 'Enables searching of various formatted values in cust_main.agent_custid',
+    'type'        => 'select',
+    'select_hash' => [
+                       ''      => 'Numeric only',
+                       'ww?d+' => 'Numeric with one or two letter prefix',
+                     ],
+  },
+
+  {
+    'key'         => 'card_masking_method',
+    'section'     => 'UI',
+    'description' => 'Digits to display when masking credit cards.  Note that the first six digits are necessary to canonically identify the credit card type (Visa/MC, Amex, Discover, Maestro, etc.) in all cases.  The first four digits can identify the most common credit card types in most cases (Visa/MC, Amex, and Discover).  The first two digits can distinguish between Visa/MC and Amex.  Note: You should manually remove stored paymasks if you change this value on an existing database, to avoid problems using stored cards.',
+    'type'        => 'select',
+    'select_hash' => [
+                       ''            => '123456xxxxxx1234',
+                       'first6last2' => '123456xxxxxxxx12',
+                       'first4last4' => '1234xxxxxxxx1234',
+                       'first4last2' => '1234xxxxxxxxxx12',
+                       'first2last4' => '12xxxxxxxxxx1234',
+                       'first2last2' => '12xxxxxxxxxxxx12',
+                       'first0last4' => 'xxxxxxxxxxxx1234',
+                       'first0last2' => 'xxxxxxxxxxxxxx12',
+                     ],
+  },
+
+  {
+    'key'         => 'disable_previous_balance',
+    'section'     => 'billing',
+    'description' => 'Disable inclusion of previous balancem payment, and credit lines on invoices',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'usps_webtools-userid',
+    'section'     => 'UI',
+    'description' => 'Production UserID for USPS web tools.   Enables USPS address standardization.  See the <a href="http://www.usps.com/webtools/">USPS website</a>, register and agree not to use the tools for batch purposes.',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'usps_webtools-password',
+    'section'     => 'UI',
+    'description' => 'Production password for USPS web tools.   Enables USPS address standardization.  See <a href="http://www.usps.com/webtools/">USPS website</a>, register and agree not to use the tools for batch purposes.',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'cust_main-auto_standardize_address',
+    'section'     => 'UI',
+    'description' => 'When using USPS web tools, automatically standardize the address without asking.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'disable_acl_changes',
+    'section'     => '',
+    'description' => 'Disable all ACL changes, for demos.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'cust_main-edit_agent_custid',
+    'section'     => 'UI',
+    'description' => 'Enable editing of the agent_custid field.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'cust_main-default_agent_custid',
+    'section'     => 'UI',
+    'description' => 'Display the agent_custid field instead of the custnum field.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'cust_main-auto_agent_custid',
+    'section'     => 'UI',
+    'description' => 'Automatically assign an agent_custid - select format',
+    'type'        => 'select',
+    'select_hash' => [ '' => 'No',
+                       '1YMMXXXXXXXX' => '1YMMXXXXXXXX',
+                     ],
+  },
+
+  {
+    'key'         => 'cust_main-default_areacode',
+    'section'     => 'UI',
+    'description' => 'Default area code for customers.',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'mcp_svcpart',
+    'section'     => '',
+    'description' => 'Master Control Program svcpart.  Leave this blank.',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'cust_bill-max_same_services',
+    'section'     => 'billing',
+    'description' => 'Maximum number of the same service to list individually on invoices before condensing to a single line listing the number of services.  Defaults to 5.',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'suspend_email_admin',
+    'section'     => '',
+    'description' => 'Destination admin email address to enable suspension notices',
+    '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'     => '',
+    'description' => 'HTML for the HEAD section of the self-service interface, typically used for LINK stylesheet tags',
+    'type'        => 'textarea', #htmlarea?
+  },
+
+
+  {
+    'key'         => 'selfservice-body_header',
+    'section'     => '',
+    'description' => 'HTML header for the self-service interface',
+    'type'        => 'textarea', #htmlarea?
+  },
+
+  {
+    'key'         => 'selfservice-body_footer',
+    'section'     => '',
+    'description' => 'HTML header for the self-service interface',
+    'type'        => 'textarea', #htmlarea?
+  },
+
+
+  {
+    'key'         => 'selfservice-body_bgcolor',
+    'section'     => '',
+    'description' => 'HTML background color for the self-service interface, for example, #FFFFFF',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'selfservice-box_bgcolor',
+    'section'     => '',
+    'description' => 'HTML color for self-service interface input boxes, for example, #C0C0C0"',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'signup-no_company',
+    'section'     => '',
+    'description' => "Don't display a field for company name on signup.",
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'signup-recommend_email',
+    'section'     => '',
+    'description' => 'Encourage the entry of an invoicing email address on signup.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'signup-recommend_daytime',
+    'section'     => '',
+    'description' => 'Encourage the entry of a daytime phone number  invoicing email address on signup.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'svc_phone-radius-default_password',
+    'section'     => '',
+    'description' => 'Default password when exporting svc_phone records to RADIUS',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'svc_phone-allow_alpha_phonenum',
+    'section'     => '',
+    'description' => 'Allow letters in phone numbers.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'default_phone_countrycode',
+    'section'     => '',
+    'description' => 'Default countrcode',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'cdr-charged_party-accountcode',
+    'section'     => '',
+    'description' => 'Set the charged_party field of CDRs to the accountcode.',
+    'type'        => 'checkbox',
+  },
+
+
 );
 
 1;
-