Disable conf_cache by default, enable it only when safe to do so
[freeside.git] / FS / FS / Conf.pm
index 41b6d24..e204747 100644 (file)
@@ -1,6 +1,9 @@
 package FS::Conf;
 
-use vars qw($base_dir @config_items @base_items @card_types $DEBUG);
+use strict;
+use vars qw( $base_dir @config_items @base_items @card_types $DEBUG
+             $conf_cache $conf_cache_enabled
+           );
 use Carp;
 use IO::File;
 use File::Basename;
@@ -120,6 +123,7 @@ sub _config {
   my($self,$name,$agentnum,$agentonly)=@_;
   my $hashref = { 'name' => $name };
   local $FS::Record::conf = undef;  # XXX evil hack prevents recursion
+  $conf_cache = undef unless $conf_cache_enabled;  # use cache only when it is safe to do so
   my $cv;
   my @a = (
     ($agentnum || ()),
@@ -133,9 +137,13 @@ sub _config {
   foreach my $a (@a) {
     $hashref->{agentnum} = $a;
     foreach my $l (@l) {
-      $hashref->{locale} = $l;
-      $cv = FS::Record::qsearchs('conf', $hashref);
-      return $cv if $cv;
+      my $key = join(':',$name, $a, $l);
+      if (! exists $conf_cache->{$key}){
+        $hashref->{locale} = $l;
+        # $conf_cache is reset in FS::UID during myconnect, so the cache is reset per connection
+        $conf_cache->{$key} = FS::Record::qsearchs('conf', $hashref);
+      }
+      return $conf_cache->{$key} if $conf_cache->{$key};
     }
   }
   return undef;
@@ -361,6 +369,12 @@ sub set {
     $error = $new->insert;
   }
 
+  if (! $error) {
+    # clean the object cache
+    my $key = join(':',$name, $agentnum, $self->{locale});
+    $conf_cache->{ $key } = $new;
+  }
+
   die "error setting configuration value: $error \n"
     if $error;
 
@@ -593,6 +607,21 @@ sub config_items {
   ( @config_items, $self->_orbase_items(@_) );
 }
 
+=item invoice_from_full [ AGENTNUM ]
+
+Returns values of invoice_from and invoice_from_name, appropriately combined
+based on their current values.
+
+=cut
+
+sub invoice_from_full {
+  my ($self, $agentnum) = @_;
+  return $self->config('invoice_from_name', $agentnum ) ?
+         $self->config('invoice_from_name', $agentnum ) . ' <' .
+         $self->config('invoice_from', $agentnum ) . '>' :
+         $self->config('invoice_from', $agentnum );
+}
+
 =back
 
 =head1 SUBROUTINES
@@ -718,6 +747,23 @@ my %batch_gateway_options = (
   },
 );
 
+my %invoice_mode_options = (
+  'type'        => 'select-sub',
+  'options_sub' => sub { 
+    my @modes = qsearch({
+        'table' => 'invoice_mode', 
+        'extra_sql' => ' WHERE '.
+          $FS::CurrentUser::CurrentUser->agentnums_sql(null => 1),
+        });
+    map { $_->modenum, $_->modename } @modes;
+  },
+  'option_sub'  => sub { 
+                         my $mode = FS::invoice_mode->by_key(shift);
+                         $mode ? $mode->modename : '',
+                       },
+  'per_agent' => 1,
+);
+
 my @cdr_formats = (
   '' => '',
   'default' => 'Default',
@@ -773,7 +819,7 @@ sub reason_type_options {
   {
     'key'         => 'log_sent_mail',
     'section'     => 'notification',
-    'description' => 'Enable logging of template-generated email.',
+    'description' => 'Enable logging of all sent email.',
     'type'        => 'checkbox',
   },
 
@@ -958,7 +1004,7 @@ sub reason_type_options {
   {
     'key'         => 'business-onlinepayment',
     'section'     => 'billing',
-    'description' => '<a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> support, at least three lines: processor, login, and password.  An optional fourth line specifies the action or actions (multiple actions are separated with `,\': for example: `Authorization Only, Post Authorization\').    Optional additional lines are passed to Business::OnlinePayment as %processor_options.',
+    'description' => '<a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> support, at least three lines: processor, login, and password.  An optional fourth line specifies the action or actions (multiple actions are separated with `,\': for example: `Authorization Only, Post Authorization\').    Optional additional lines are passed to Business::OnlinePayment as %processor_options.  For more detailed information and examples see the <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:3:Documentation:Administration:Real-time_Processing">real-time credit card processing documentation</a>.',
     'type'        => 'textarea',
   },
 
@@ -1114,7 +1160,7 @@ sub reason_type_options {
   {
     'key'         => 'unapplycredits',
     'section'     => 'deprecated',
-    'description' => '<B>DEPRECATED</B>, now controlled by ACLs.  Used to nable "unapplication" of unclosed credits.',
+    'description' => '<B>DEPRECATED</B>, now controlled by ACLs.  Used to enable "unapplication" of unclosed credits.',
     'type'        => 'checkbox',
   },
 
@@ -1233,11 +1279,35 @@ sub reason_type_options {
   {
     'key'         => 'invoice_from',
     'section'     => 'required',
-    'description' => 'Return address on email invoices',
+    'description' => 'Return address on email invoices (address only, see invoice_from_name)',
+    'type'        => 'text',
+    'per_agent'   => 1,
+    'validate'    => sub { $_[0] =~
+                             /^[^@]+\@[[:alnum:]-]+(\.[[:alnum:]-]+)+$/
+                             ? '' : 'Invalid email address';
+                         }
+  },
+
+  {
+    'key'         => 'invoice_from_name',
+    'section'     => 'invoicing',
+    'description' => 'Return name on email invoices (set address in invoice_from)',
+    'type'        => 'text',
+    'per_agent'   => 1,
+    'validate'    => sub { (($_[0] =~ /[^[:alnum:][:space:]]/) && ($_[0] !~ /^\".*\"$/))
+                           ? 'Invalid name.  Use quotation marks around names that contain punctuation.'
+                           : '' }
+  },
+
+  {
+    'key'         => 'quotation_from',
+    'section'     => '',
+    'description' => 'Return address on email quotations',
     'type'        => 'text',
     'per_agent'   => 1,
   },
 
+
   {
     'key'         => 'invoice_subject',
     'section'     => 'invoicing',
@@ -1248,6 +1318,15 @@ sub reason_type_options {
   },
 
   {
+    'key'         => 'quotation_subject',
+    'section'     => '',
+    'description' => 'Subject: header on email quotations.  Defaults to "Quotation".', #  The following substitutions are available: $name, $name_short, $invoice_number, and $invoice_date.',
+    'type'        => 'text',
+    #'per_agent'   => 1,
+    'per_locale'  => 1,
+  },
+
+  {
     'key'         => 'invoice_usesummary',
     'section'     => 'invoicing',
     'description' => 'Indicates that html and latex invoices should be in summary style and make use of invoice_latexsummary.',
@@ -1502,14 +1581,35 @@ and customer address. Include units.',
   {
     'key'         => 'invoice_email_pdf',
     'section'     => 'invoicing',
-    'description' => 'Send PDF invoice as an attachment to emailed invoices.  By default, includes the plain text invoice as the email body, unless invoice_email_pdf_note is set.',
+    'description' => 'Send PDF invoice as an attachment to emailed invoices.  By default, includes the HTML invoice as the email body, unless invoice_email_pdf_note is set.',
     'type'        => 'checkbox'
   },
 
   {
+    'key'         => 'quotation_email_pdf',
+    'section'     => '',
+    'description' => 'Send PDF quotations as an attachment to emailed quotations.  By default, includes the HTML quotation as the email body, unless quotation_email_pdf_note is set.',
+    'type'        => 'checkbox'
+  },
+
+  {
+    'key'         => 'invoice_email_pdf_msgnum',
+    'section'     => 'invoicing',
+    'description' => 'Message template to send as the text and HTML part of PDF invoices. If not selected, a text and HTML version of the invoice will be sent.',
+    %msg_template_options,
+  },
+
+  {
     'key'         => 'invoice_email_pdf_note',
     'section'     => 'invoicing',
-    'description' => 'If defined, this text will replace the default plain text invoice as the body of emailed PDF invoices.',
+    'description' => 'If defined, this text will replace the default HTML invoice as the body of emailed PDF invoices.',
+    'type'        => 'textarea'
+  },
+
+  {
+    'key'         => 'quotation_email_pdf_note',
+    'section'     => '',
+    'description' => 'If defined, this text will replace the default HTML quotation as the body of emailed PDF quotations.',
     'type'        => 'textarea'
   },
 
@@ -1527,11 +1627,19 @@ and customer address. Include units.',
     'type'        => 'checkbox',
   },
 
+  {
+    'key'         => 'invoice_print_pdf-duplex',
+    'section'     => 'invoicing',
+    'description' => 'Insert blank pages so that spooled invoices are each an even number of pages.  Use this for double-sided printing.',
+    'type'        => 'checkbox',
+  },
+
   { 
     'key'         => 'invoice_default_terms',
     'section'     => 'invoicing',
     'description' => 'Optional default invoice term, used to calculate a due date printed on invoices.',
     'type'        => 'select',
+    'per_agent'   => 1,
     'select_enum' => [ 
       '', 'Payable upon receipt', 'Net 0', 'Net 3', 'Net 5', 'Net 9', 'Net 10', 'Net 14', 
       'Net 15', 'Net 18', 'Net 20', 'Net 21', 'Net 25', 'Net 30', 'Net 45', 
@@ -1561,11 +1669,19 @@ and customer address. Include units.',
   },
 
   {
-    'key'         => 'invoice_sections_by_location',
+    'key'         => 'invoice_sections_method',
     'section'     => 'invoicing',
-    'description' => 'Divide invoice into sections according to service location.  Currently, this overrides sectioning by package category.',
-    'type'        => 'checkbox',
-    'per_agent'   => 1,
+    'description' => 'How to group line items on multi-section invoices.',
+    'type'        => 'select',
+    'select_enum' => [ qw(category location) ],
+  },
+
+  {
+    'key'         => 'summary_subtotals_method',
+    'section'     => 'invoicing',
+    'description' => 'How to group line items when calculating summary subtotals.  By default, it will be the same method used for grouping invoice sections.',
+    'type'        => 'select',
+    'select_enum' => [ qw(category location) ],
   },
 
   #quotations seem broken-ish with sections ATM?
@@ -1636,9 +1752,16 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'payment_receipt_statement_mode',
+    'section'     => 'notification',
+    'description' => 'Automatic payments will cause a post-payment statement to be sent to the customer. Select the invoice mode to use for this statement. If unspecified, it will use the "_statement" versions of invoice configuration settings, and have the notice name "Statement".',
+    %invoice_mode_options,
+  },
+
+  {
     'key'         => 'payment_receipt_msgnum',
     'section'     => 'notification',
-    'description' => 'Template to use for payment receipts.',
+    'description' => 'Template to use for manual payment receipts.',
     %msg_template_options,
   },
   
@@ -2069,13 +2192,6 @@ and customer address. Include units.',
   },
 
   {
-    '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'         => 'show_ship_company',
     'section'     => 'UI',
     'description' => 'Turns on display/collection of a "service company name" field for customers.',
@@ -2171,7 +2287,7 @@ and customer address. Include units.',
     'section'     => 'self-service',
     'description' => 'Acceptable payment types for the signup server',
     'type'        => 'selectmultiple',
-    'select_enum' => [ qw(CARD DCRD CHEK DCHK PREPAY PPAL BILL COMP) ],
+    'select_enum' => [ qw(CARD DCRD CHEK DCHK PREPAY PPAL ) ], # BILL COMP) ],
   },
 
   {
@@ -2438,8 +2554,9 @@ and customer address. Include units.',
   {
     'key'         => 'enable_taxproducts',
     'section'     => 'billing',
-    'description' => 'Enable per-package mapping to vendor tax data from CCH or elsewhere.',
-    'type'        => 'checkbox',
+    'description' => 'Tax data vendor you are using.',
+    'type'        => 'select',
+    'select_enum' => [ 'cch', 'billsoft', 'avalara' ],
   },
 
   {
@@ -2457,6 +2574,20 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'billsoft-company_code',
+    'section'     => 'billing',
+    'description' => 'Billsoft tax service company code (3 letters)',
+    'type'        => 'text',
+  },
+
+  {
+    'key'         => 'avalara-taxconfig',
+    'section'     => 'billing',
+    'description' => 'Avalara tax service configuration. Four lines: company code, account number, license key, test mode (1 to enable).',
+    'type'        => 'textarea',
+  },
+
+  {
     'key'         => 'welcome_msgnum',
     'section'     => 'notification',
     'description' => 'Template to use for welcome messages when a svc_acct record is created.',
@@ -2559,13 +2690,13 @@ and customer address. Include units.',
     'section'     => 'billing',
     'description' => 'Available payment types.',
     'type'        => 'selectmultiple',
-    'select_enum' => [ qw(CARD DCRD CHEK DCHK BILL CASH WEST MCRD PPAL COMP) ],
+    'select_enum' => [ qw(CARD DCRD CHEK DCHK CASH WEST MCRD MCHK PPAL) ],
   },
 
   {
     'key'         => 'payby-default',
-    'section'     => 'UI',
-    'description' => 'Default payment type.  HIDE disables display of billing information and sets customers to BILL.',
+    'section'     => 'deprecated',
+    'description' => 'Deprecated; in 4.x there is no longer the concept of a single "payment type".  Used to indicate the default payment type.  HIDE disables display of billing information and sets customers to BILL.',
     'type'        => 'select',
     'select_enum' => [ '', qw(CARD DCRD CHEK DCHK BILL CASH WEST MCRD PPAL COMP HIDE) ],
   },
@@ -2691,6 +2822,20 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'backoffice-require_cvv',
+    'section'     => 'billing',
+    'description' => 'Require CVV for manual credit card entry.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'selfservice-onfile_require_cvv',
+    'section'     => 'self-service',
+    'description' => 'Require CVV for on-file credit card during self-service payments.',
+    'type'        => 'checkbox',
+  },
+
+  {
     'key'         => 'selfservice-require_cvv',
     'section'     => 'self-service',
     'description' => 'Require CVV for credit card self-service payments, except for cards on-file.',
@@ -2724,6 +2869,22 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'selfservice_immutable-package',
+    'section'     => 'self-service',
+    'description' => 'Disable package changes in self-service interface.',
+    'type'        => 'checkbox',
+    'per_agent'   => 1,
+  },
+
+  {
+    'key'         => 'selfservice_hide-usage',
+    'section'     => 'self-service',
+    'description' => 'Hide usage data in self-service interface.',
+    'type'        => 'checkbox',
+    'per_agent'   => 1,
+  },
+
+  {
     'key'         => 'selfservice_process-pkgpart',
     'section'     => 'billing',
     'description' => 'Package to add to each manual credit card and ACH payment entered by the customer themselves in the self-service interface.  Enabling this option may be in violation of your merchant agreement(s), so please check it(/them) carefully before enabling this option.',
@@ -2873,7 +3034,7 @@ and customer address. Include units.',
     'type'        => 'select',
     'select_hash' => [ '' => 'Password reset disabled',
                        'email' => 'Click on a link in email',
-                       'paymask,amount,zip' => 'Click on a link in email, and also verify with credit card (or bank account) last 4 digits, payment amount and zip code',
+                       'paymask,amount,zip' => 'Click on a link in email, and also verify with credit card (or bank account) last 4 digits, payment amount and zip code.  Note: Do not use if you have multi-customer contacts, as they will be unable to reset their passwords.',
                      ],
   },
 
@@ -2931,7 +3092,7 @@ and customer address. Include units.',
                         },
     'option_sub'  => sub { require FS::Record;
                            require FS::agent_type;
-                          my $agent = FS::Record::qsearchs(
+                          my $agent_type = FS::Record::qsearchs(
                             'agent_type', { 'typenum'=>shift }
                           );
                            $agent_type ? $agent_type->atype : '';
@@ -3229,6 +3390,14 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'city_not_required',
+    'section'     => 'required',
+    'description' => 'Turn off requirement for a City to be entered for billing & shipping addresses',
+    'type'        => 'checkbox',
+    'per_agent'   => 1,
+  },
+
+  {
     'key'         => 'echeck-void',
     'section'     => 'deprecated',
     'description' => '<B>DEPRECATED</B>, now controlled by ACLs.  Used to enable local-only voiding of echeck payments in addition to refunds against the payment gateway',
@@ -3439,7 +3608,8 @@ and customer address. Include units.',
     'description' => 'Optional "site ID" to show in the location label',
     'type'        => 'select',
     'select_hash' => [ '' => '',
-                       'CoStAg' => 'CoStAgXXXXX (country, state, agent name, locationnum)',
+                       'CoStAg'    => 'CoStAgXXXXX (country, state, agent name, locationnum)',
+                       '_location' => 'Manually defined per location',
                       ],
   },
 
@@ -3465,13 +3635,6 @@ and customer address. Include units.',
   },
 
   {
-    'key'         => 'cust_pkg-show_fcc_voice_grade_equivalent',
-    'section'     => 'UI',
-    'description' => "Show fields on package definitions for FCC Form 477 classification",
-    'type'        => 'checkbox',
-  },
-
-  {
     'key'         => 'cust_pkg-large_pkg_size',
     'section'     => 'UI',
     'description' => "In customer view, summarize packages with more than this many services.  Set to zero to never summarize packages.",
@@ -3486,6 +3649,13 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'part_pkg-show_fcc_options',
+    'section'     => 'UI',
+    'description' => "Show fields on package definitions for FCC Form 477 classification",
+    'type'        => 'checkbox',
+  },
+
+  {
     'key'         => 'svc_acct-edit_uid',
     'section'     => 'shell',
     'description' => 'Allow UID editing.',
@@ -3668,7 +3838,7 @@ and customer address. Include units.',
     'type'        => 'select',
     'select_enum' => [ 'NACHA', 'csv-td_canada_trust-merchant_pc_batch',
                        'csv-chase_canada-E-xactBatch', 'BoM', 'PAP',
-                       'paymentech', 'ach-spiritone', 'RBC'
+                       'paymentech', 'ach-spiritone', 'RBC', 'CIBC',
                     ]
   },
 
@@ -3730,7 +3900,7 @@ and customer address. Include units.',
     'type'        => 'select',
     'select_enum' => [ 'NACHA', 'csv-td_canada_trust-merchant_pc_batch', 'BoM',
                        'PAP', 'paymentech', 'ach-spiritone', 'RBC',
-                       'td_eft1464', 'eft_canada'
+                       'td_eft1464', 'eft_canada', 'CIBC'
                      ]
   },
 
@@ -3748,6 +3918,13 @@ and customer address. Include units.',
     'type'        => 'textarea',
   },
 
+{
+    'key'         => 'batchconfig-CIBC',
+    'section'     => 'billing',
+    'description' => 'Configuration for Canadian Imperial Bank of Commerce, six lines: 1. Origin ID, 2. Datacenter, 3. Typecode, 4. Short name, 5. Bank, 6. Bank account',
+    'type'        => 'textarea',
+  },
+
   {
     'key'         => 'batchconfig-PAP',
     'section'     => 'billing',
@@ -3786,7 +3963,7 @@ and customer address. Include units.',
   {
     'key'         => 'batchconfig-eft_canada',
     'section'     => 'billing',
-    'description' => 'Configuration for EFT Canada batching, four lines: 1. SFTP username, 2. SFTP password, 3. Transaction code, 4. Number of days to delay process date.  If you are using separate per-agent batches (batch-spoolagent), you must set this option separately for each agent, as the global setting will be ignored.',
+    'description' => 'Configuration for EFT Canada batching, five lines: 1. SFTP username, 2. SFTP password, 3. Business transaction code, 4. Personal transaction code, 5. Number of days to delay process date.  If you are using separate per-agent batches (batch-spoolagent), you must set this option separately for each agent, as the global setting will be ignored.',
     'type'        => 'textarea',
     'per_agent'   => 1,
   },
@@ -4031,13 +4208,6 @@ and customer address. Include units.',
   },
 
   {
-    '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',
@@ -4292,7 +4462,6 @@ and customer address. Include units.',
     'type'        => 'select',
     'select_hash' => [ '' => '', 
                        'usps'     => 'U.S. Postal Service',
-                       'ezlocate' => 'EZLocate',
                        'tomtom'   => 'TomTom',
                        'melissa'  => 'Melissa WebSmart',
                      ],
@@ -4315,25 +4484,11 @@ and customer address. Include units.',
   {
     'key'         => 'tomtom-userid',
     'section'     => 'UI',
-    'description' => 'TomTom geocoding service API key.  See <a href="http://www.tomtom.com/">the TomTom website</a> to obtain a key.  This is recommended for addresses in the United States only.',
-    'type'        => 'text',
-  },
-
-  {
-    'key'         => 'ezlocate-userid',
-    'section'     => 'UI',
-    'description' => 'User ID for EZ-Locate service.  See <a href="http://www.geocode.com/">the TomTom website</a> for access and pricing information.',
+    'description' => 'TomTom geocoding service API key.  See <a href="http://geocoder.tomtom.com/">the TomTom website</a> to obtain a key.  This is recommended for addresses in the United States only.',
     'type'        => 'text',
   },
 
   {
-    'key'         => 'ezlocate-password',
-    'section'     => 'UI',
-    'description' => 'Password for EZ-Locate service.',
-    'type'        => 'text'
-  },
-
-  {
     'key'         => 'melissa-userid',
     'section'     => 'UI', # it's really not...
     'description' => 'User ID for Melissa WebSmart service.  See <a href="http://www.melissadata.com/">the Melissa website</a> for access and pricing.',
@@ -4510,6 +4665,16 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'part_pkg-delay_cancel-days',
+    'section'     => '',
+    'description' => 'Expire packages in this many days when using delay_cancel (default is 1)',
+    'type'        => 'text',
+    'validate'    => sub { (($_[0] =~ /^\d*$/) && (($_[0] eq '') || $_[0]))
+                           ? 'Must specify an integer number of days'
+                           : '' }
+  },
+
+  {
     'key'         => 'mcp_svcpart',
     'section'     => '',
     'description' => 'Master Control Program svcpart.  Leave this blank.',
@@ -4903,9 +5068,16 @@ and customer address. Include units.',
   },
 
   {
+    'key'         => 'svc_phone-bulk_provision_simple',
+    'section'     => 'telephony',
+    'description' => 'Bulk provision phone numbers with a simple number range instead of from DID vendor orders',
+    'type'        => 'checkbox',
+  },
+
+  {
     'key'         => 'default_phone_countrycode',
-    'section'     => '',
-    'description' => 'Default countrcode',
+    'section'     => 'telephony',
+    'description' => 'Default countrycode',
     'type'        => 'text',
   },
 
@@ -5115,19 +5287,30 @@ and customer address. Include units.',
 
   {
     'key'         => 'tax-cust_exempt-groups',
-    'section'     => '',
+    'section'     => 'billing',
     'description' => 'List of grouping possibilities for tax names, for per-customer exemption purposes, one tax name per line.  For example, "GST" would indicate the ability to exempt customers individually from taxes named "GST" (but not other taxes).',
     'type'        => 'textarea',
   },
 
   {
     'key'         => 'tax-cust_exempt-groups-require_individual_nums',
-    'section'     => '',
-    'description' => 'When using tax-cust_exempt-groups, require an individual tax exemption number for each exemption from different taxes.',
+    'section'     => 'deprecated',
+    'description' => 'Deprecated: see tax-cust_exempt-groups-number_requirement',
     'type'        => 'checkbox',
   },
 
   {
+    'key'         => 'tax-cust_exempt-groups-num_req',
+    'section'     => 'billing',
+    'description' => 'When using tax-cust_exempt-groups, control whether individual tax exemption numbers are required for exemption from different taxes.',
+    'type'        => 'select',
+    'select_hash' => [ ''            => 'Not required',
+                       'residential' => 'Required for residential customers only',
+                       'all'         => 'Required for all customers',
+                     ],
+  },
+
+  {
     'key'         => 'cust_main-default_view',
     'section'     => 'UI',
     'description' => 'Default customer view, for users who have not selected a default view in their preferences.',
@@ -5773,6 +5956,20 @@ and customer address. Include units.',
                      ],
   },
 
+  {
+    'key'         => 'old_fcc_report',
+    'section'     => '',
+    'description' => 'Use the old (pre-2014) FCC Form 477 report format.',
+    'type'        => 'checkbox',
+  },
+
+  {
+    'key'         => 'cust_main-default_commercial',
+    'section'     => 'UI',
+    'description' => 'Default for new customers is commercial rather than residential.',
+    'type'        => 'checkbox',
+  },
+
   { key => "apacheroot", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
   { key => "apachemachine", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },
   { key => "apachemachines", section => "deprecated", description => "<b>DEPRECATED</b>", type => "text" },