X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2FConf.pm;h=9c9c6aaaffa872deb64a6818e5e0e7744073c00d;hp=8bff460fe59d522f1800a5e0074a0e7e402c0a08;hb=2b8ffc98529637ffddfe7cbf6b4f9b8deb90f0fa;hpb=0dd05e9ff98263d2d42b419b1e278a5a3bc594b2 diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 8bff460fe..9c9c6aaaf 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -1,16 +1,19 @@ package FS::Conf; -use vars qw($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); +use FS::UID qw(dbh datasrc use_confcompat); $base_dir = '%%%FREESIDE_CONF%%%'; - $DEBUG = 0; =head1 NAME @@ -72,51 +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,$agent)=@_; + my($self,$name,$agentnum)=@_; my $hashref = { 'name' => $name }; - if (defined($agent) && $agent) { - $hashref->{agent} = $agent; - } + $hashref->{agentnum} = $agentnum; 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}); + if (!$cv && defined($agentnum) && $agentnum) { + $hashref->{agentnum} = ''; $cv = FS::Record::qsearchs('conf', $hashref); } return $cv; } sub config { - my($self,$name,$agent)=@_; - my $cv = $self->_config($name, $agent) 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 ) { - split "\n", $cv->value; + my $v = $cv->value; + chomp $v; + (split "\n", $v, -1); } else { (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,$name,$agent)=@_; - my $cv = $self->_config($name, $agent) or return; + 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. @@ -124,8 +143,11 @@ is undefined. =cut sub exists { - my($self,$name,$agent)=@_; - defined($self->_config($name, $agent)); + my $self = shift; + return $self->_usecompat('exists', @_) if use_confcompat; + + my($name,$agentnum)=@_; + defined($self->_config($name, $agentnum)); } =item config_orbase KEY SUFFIX @@ -135,8 +157,14 @@ 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, $name, $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 { @@ -144,33 +172,85 @@ sub config_orbase { } } -=item touch KEY +=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 { + $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 [ AGENT ]; Creates the specified configuration key if it does not exist. =cut sub touch { - my($self, $name, $agent) = @_; - $self->set($name, '', $agent); + 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, $name, $value, $agent) = @_; + my $self = shift; + return $self->_usecompat('set', @_) if use_confcompat; + + my($name, $value, $agentnum) = @_; $value =~ /^(.*)$/s; $value = $1; - warn "[FS::Conf] SET $file\n" if $DEBUG; + warn "[FS::Conf] SET $name\n" if $DEBUG; - my $old = FS::Record::qsearchs('conf', {name => $name, agent => $agent}); + my $old = FS::Record::qsearchs('conf', {name => $name, agentnum => $agentnum}); my $new = new FS::conf { $old ? $old->hash - : ('name' => $name, 'agent' => $agent) + : ('name' => $name, 'agentnum' => $agentnum) }; $new->value($value); @@ -186,7 +266,7 @@ sub set { } -=item set_binary KEY VALUE +=item set_binary KEY VALUE [ AGENTNUM ] Sets the specified configuration key to an exact scalar value which can be retrieved with config_binary. @@ -194,20 +274,26 @@ can be retrieved with config_binary. =cut sub set_binary { - my($self,$name, $value, $agent)=@_; - $self->set($name, encode_base64($value), $agent); + my $self = shift; + return if use_confcompat; + + my($name, $value, $agentnum)=@_; + $self->set($name, encode_base64($value), $agentnum); } -=item delete KEY +=item delete KEY [ AGENTNUM ]; Deletes the specified configuration key. =cut sub delete { - my($self, $name, $agent) = @_; - if ( my $cv = FS::Record::qsearchs('conf', {name => $name, agent => $agent}) ) { - warn "[FS::Conf] DELETE $file\n"; + 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; @@ -225,81 +311,192 @@ sub delete { } } +=item import_config_item CONFITEM DIR + + Imports the item specified by the CONFITEM (see L) into +the database as a conf record (see L). 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) 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. 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 billing documentation 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. +Returns all of the possible global/default configuration items as +FS::ConfItem objects. See L. =cut sub config_items { my $self = shift; - #quelle kludge - @config_items, - ( map { - new FS::ConfItem { - 'key' => $_->name, - 'section' => 'billing', - 'description' => 'Alternate template file for invoices. See the billing documentation for details.', - 'type' => 'textarea', - } - } 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 { - new FS::ConfItem { - 'key' => $_->name, - 'section' => 'billing', - 'description' => 'Alternate HTML template for invoices. See the billing documentation for details.', - 'type' => 'textarea', - } - } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_html!_%' ESCAPE '!'") - ), - ( map { - ($latexname = $_->name ) =~ s/latex/html/; - new FS::ConfItem { - 'key' => $_->name, - 'section' => 'billing', - 'description' => "Alternate Notes section for HTML invoices. Defaults to the same data in $latexname if not specified.", - 'type' => 'textarea', - } - } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_htmlnotes!_%' ESCAPE '!'") - ), - ( map { - new FS::ConfItem { - 'key' => $_->name, - 'section' => 'billing', - 'description' => 'Alternate LaTeX template for invoices. See the billing documentation for details.', - 'type' => 'textarea', - } - } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_latex!_%' 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!_%.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', - } - } FS::Record::qsearch('conf', {}, '', "WHERE name LIKE 'invoice!_latexnotes!_%' ESCAPE '!'") - ); + 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 @@ -313,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 @@ -331,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 $_ } ( { @@ -343,7 +554,7 @@ httemplate/docs/config.html { 'key' => 'alerter_template', 'section' => 'billing', - 'description' => 'Template file for billing method expiration alerts. See the billing documentation for details.', + 'description' => 'Template file for billing method expiration alerts. See the billing documentation for details.', 'type' => 'textarea', }, @@ -411,6 +622,13 @@ httemplate/docs/config.html }, { + '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', + }, + + { 'key' => 'countrydefault', 'section' => 'UI', 'description' => 'Default two-letter country code (if not supplied, the default is `US\')', @@ -513,6 +731,13 @@ httemplate/docs/config.html }, { + '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', 'description' => 'Prevent cancelled packages from showing up in listings (though they will still be in the database)', @@ -528,7 +753,7 @@ 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', }, @@ -538,19 +763,20 @@ httemplate/docs/config.html '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 billing documentation 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 billing documentation for details.', 'type' => 'textarea', }, { 'key' => 'invoice_html', 'section' => 'billing', - 'description' => 'Optional HTML template for invoices. See the billing documentation for details.', + 'description' => 'Optional HTML template for invoices. See the billing documentation for details.', 'type' => 'textarea', }, @@ -579,7 +805,7 @@ httemplate/docs/config.html { 'key' => 'invoice_latex', 'section' => 'billing', - 'description' => 'Optional LaTeX template for typeset PostScript invoices. See the billing documentation for details.', + 'description' => 'Optional LaTeX template for typeset PostScript invoices. See the billing documentation for details.', 'type' => 'textarea', }, @@ -598,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.', @@ -631,13 +864,27 @@ 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_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 Text::Template documentation for details on the template substitution language. The following variables are available:
  • $date
  • $name
  • $paynum - Freeside payment number
  • $paid - Amount of payment
  • $payby - Payment type (Card, Check, Electronic check, etc.)
  • $payinfo - Masked credit card number or check number
  • $balance - New balance
', + 'description' => 'Template file for payment receipts. Payment receipts are sent to the customer email invoice destination(s) when a payment is received. See the Text::Template documentation for details on the template substitution language. The following variables are available:
  • $date
  • $name
  • $paynum - Freeside payment number
  • $paid - Amount of payment
  • $payby - Payment type (Card, Check, Electronic check, etc.)
  • $payinfo - Masked credit card number or check number
  • $balance - New balance
', 'type' => [qw( checkbox textarea )], }, @@ -649,6 +896,20 @@ httemplate/docs/config.html }, { + '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' => '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' => 'money_char', 'section' => '', 'description' => 'Currency symbol - defaults to `$\'', @@ -731,7 +992,7 @@ httemplate/docs/config.html { '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', }, @@ -746,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 signup server CGI, 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 signup server CGI, the customer view screen will display a customized link to the signup server with the appropriate customer as referral', 'type' => 'text', }, @@ -879,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', }, @@ -911,6 +1172,13 @@ httemplate/docs/config.html 'type' => 'checkbox', }, + { + 'key' => 'show_bankstate', + 'section' => 'UI', + 'description' => "Turns on display/collection of state for bank accounts in the web interface. Sometimes required by electronic check (ACH) processors.", + 'type' => 'checkbox', + }, + { 'key' => 'agent_defaultpkg', 'section' => 'UI', @@ -1004,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; @@ -1025,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.', @@ -1120,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', }, @@ -1146,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 Text::Template documentation for details on the template substitution language. The following variables are available
  • $username
  • $password
  • $first
  • $last
  • $pkg
', + '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 Text::Template documentation for details on the template substitution language. The following variables are available
  • $username
  • $password
  • $first
  • $last
  • $pkg
', 'type' => 'textarea', + 'per_agent' => 1, }, { @@ -1157,6 +1472,7 @@ httemplate/docs/config.html 'section' => '', 'description' => 'From: address header for welcome email', 'type' => 'text', + 'per_agent' => 1, }, { @@ -1164,6 +1480,7 @@ httemplate/docs/config.html 'section' => '', 'description' => 'Subject: header for welcome email', 'type' => 'text', + 'per_agent' => 1, }, { @@ -1172,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 Text::Template documentation and the billing documentation for details on the template substitution language. A variable exists for each fieldname in the customer record ($first, $last, etc). The following additional variables are available
  • $payby - a friendler represenation of the field
  • $payinfo - the masked payment information
  • $expdate - the time at which the payment method expires (a UNIX timestamp)
  • $returnaddress - the invoice return address for this customer\'s agent
', + '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 Text::Template documentation for details on the template substitution language. The following variables are available
  • $username
  • $password
  • $first
  • $last
  • $pkg
  • $column
  • $amount
  • $threshold
', + '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
', 'type' => 'textarea', }, @@ -1227,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.', @@ -1334,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.', @@ -1356,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).', @@ -1373,7 +1727,7 @@ httemplate/docs/config.html { 'key' => 'ticket_system', 'section' => '', - 'description' => 'Ticketing system integration. RT_Internal uses the built-in RT ticketing system (see the integrated ticketing installation instructions). RT_External accesses an external RT installation in a separate database (local or remote).', + 'description' => 'Ticketing system integration. RT_Internal uses the built-in RT ticketing system (see the integrated ticketing installation instructions). RT_External 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) ], @@ -1407,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.', @@ -1447,18 +1808,41 @@ httemplate/docs/config.html 'section' => 'required', 'description' => 'Your company name', 'type' => 'text', + 'per_agent' => 1, + }, + + { + 'key' => 'company_address', + 'section' => 'required', + 'description' => 'Your company address', + 'type' => 'textarea', + 'per_agent' => 1, }, { 'key' => 'address2-search', 'section' => 'UI', - 'description' => 'Enable a "Unit" search box which searches the second address field', + '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' => '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' => '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 referred customer's recurring fee (irregardless of frequency).", + 'section' => 'deprecated', + 'description' => "Used to enable one-time referral credits in the amount of one month referred customer's recurring fee (irregardless of frequency). Replace with a billing event on appropriate packages.", 'type' => 'checkbox', }, @@ -1471,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.', @@ -1548,27 +1983,98 @@ httemplate/docs/config.html }, { - 'key' => 'svc_forward-arbitrary_dst', + 'key' => 'voip-cust_cdr_squelch', '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.", + 'description' => 'Enable the per-customer option for not printing CDR on invoices.', 'type' => 'checkbox', }, { - 'key' => 'tax-ship_address', + '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' => '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 this switch to include the ship address on the invoice.', + 'type' => 'checkbox', + }, + + { + 'key' => 'invoice-unitprice', + 'section' => 'billing', + 'description' => 'This switch enables unit pricing on the invoice.', + 'type' => 'checkbox', + }, + + { + 'key' => 'postal_invoice-fee_pkgpart', + 'section' => 'billing', + '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' => 'postal_invoice-recurring_only', 'section' => 'billing', + 'description' => 'The postal invoice fee is omitted on invoices without reucrring charges when this is set.', + 'type' => 'checkbox', + }, + + { + '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.', @@ -1706,6 +2212,25 @@ 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', @@ -1715,7 +2240,7 @@ httemplate/docs/config.html { '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
', + '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', }, @@ -1742,6 +2267,14 @@ httemplate/docs/config.html }, { + '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.', @@ -1769,7 +2302,314 @@ httemplate/docs/config.html '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 USPS website, 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 USPS website, 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; -