package FS::Conf;
-use vars qw($base_dir @config_items @base_items @card_types $DEBUG);
+use strict;
+use vars qw( $base_dir @config_items @base_items @card_types $DEBUG
+ $conf_cache $conf_cache_enabled
+ );
use Carp;
use IO::File;
use File::Basename;
use Locale::Currency;
use FS::ConfItem;
use FS::ConfDefaults;
-use FS::Conf_compat17;
use FS::Locales;
use FS::payby;
use FS::conf;
use FS::Record qw(qsearch qsearchs);
-use FS::UID qw(dbh datasrc use_confcompat);
+use FS::UID qw(dbh datasrc);
use FS::Misc::Invoicing qw( spool_formats );
$base_dir = '%%%FREESIDE_CONF%%%';
$DEBUG = 0;
+$conf_cache_enabled = 0;
+
=head1 NAME
FS::Conf - Freeside configuration values
=cut
-sub _usecompat {
- my ($self, $method) = (shift, shift);
- carp "NO CONFIGURATION RECORDS FOUND -- USING COMPATIBILITY MODE"
- if use_confcompat;
- my $compat = new FS::Conf_compat17 ("$base_dir/conf." . datasrc);
- $compat->$method(@_);
-}
-
sub _config {
my($self,$name,$agentnum,$agentonly)=@_;
my $hashref = { 'name' => $name };
local $FS::Record::conf = undef; # XXX evil hack prevents recursion
+ $conf_cache = undef unless $conf_cache_enabled; # use cache only when it is
+ # safe to do so
my $cv;
my @a = (
($agentnum || ()),
foreach my $a (@a) {
$hashref->{agentnum} = $a;
foreach my $l (@l) {
- $hashref->{locale} = $l;
- $cv = FS::Record::qsearchs('conf', $hashref);
- return $cv if $cv;
+ my $key = join(':',$name, $a, $l);
+ if (! exists $conf_cache->{$key}){
+ $hashref->{locale} = $l;
+ # $conf_cache is reset in FS::UID during myconnect, so the cache is
+ # reset per connection
+ $conf_cache->{$key} = FS::Record::qsearchs('conf', $hashref);
+ }
+ return $conf_cache->{$key} if $conf_cache->{$key};
}
}
return undef;
sub config {
my $self = shift;
- return $self->_usecompat('config', @_) if use_confcompat;
carp "FS::Conf->config(". join(', ', @_). ") called"
if $DEBUG > 1;
sub config_binary {
my $self = shift;
- return $self->_usecompat('config_binary', @_) if use_confcompat;
my $cv = $self->_config(@_) or return;
length($cv->value) ? decode_base64($cv->value) : '';
sub exists {
my $self = shift;
- return $self->_usecompat('exists', @_) if use_confcompat;
#my($name, $agentnum)=@_;
sub config_bool {
my $self = shift;
- return $self->_usecompat('exists', @_) if use_confcompat;
my($name,$agentnum,$agentonly) = @_;
# these to fall back to standard values
sub config_orbase {
my $self = shift;
- return $self->_usecompat('config_orbase', @_) if use_confcompat;
my( $name, $suffix ) = @_;
if ( $self->exists("${name}_$suffix") ) {
sub key_orbase {
my $self = shift;
- #no compat for this...return $self->_usecompat('config_orbase', @_) if use_confcompat;
my( $name, $suffix ) = @_;
if ( $self->exists("${name}_$suffix") ) {
sub touch {
my $self = shift;
- return $self->_usecompat('touch', @_) if use_confcompat;
my($name, $agentnum) = @_;
#unless ( $self->exists($name, $agentnum) ) {
sub set {
my $self = shift;
- return $self->_usecompat('set', @_) if use_confcompat;
my($name, $value, $agentnum) = @_;
$value =~ /^(.*)$/s;
$error = $new->insert;
}
+ if (! $error) {
+ # clean the object cache
+ my $key = join(':',$name, $agentnum, $self->{locale});
+ $conf_cache->{ $key } = $new;
+ }
+
die "error setting configuration value: $error \n"
if $error;
sub set_binary {
my $self = shift;
- return if use_confcompat;
my($name, $value, $agentnum)=@_;
$self->set($name, encode_base64($value), $agentnum);
sub delete {
my $self = shift;
- return $self->_usecompat('delete', @_) if use_confcompat;
my($name, $agentnum) = @_;
if ( my $cv = FS::Record::qsearchs('conf', {name => $name, agentnum => $agentnum, locale => $self->{locale}}) ) {
sub delete_bool {
my $self = shift;
- return $self->_usecompat('delete', @_) if use_confcompat;
my($name, $agentnum) = @_;
sub import_config_item {
my ($self,$item,$dir) = @_;
my $key = $item->key;
- if ( -e "$dir/$key" && ! use_confcompat ) {
+ if ( -e "$dir/$key" ) {
warn "Inserting $key\n" if $DEBUG;
local $/;
my $value = readline(new IO::File "$dir/$key");
}else{
$self->set($key, $value);
}
- }else {
- warn "Not inserting $key\n" if $DEBUG;
- }
-}
-
-=item verify_config_item CONFITEM DIR
-
- Compares the item specified by the CONFITEM (see L<FS::ConfItem>) in
-the database to the legacy file value in DIR.
-
-=cut
-
-sub verify_config_item {
- return '' if use_confcompat;
- my ($self,$item,$dir) = @_;
- my $key = $item->key;
- my $type = $item->type;
-
- my $compat = new FS::Conf_compat17 $dir;
- my $error = '';
-
- $error .= "$key fails existential comparison; "
- if $self->exists($key) xor $compat->exists($key);
-
- if ( $type !~ /^(binary|image)$/ ) {
-
- {
- no warnings;
- $error .= "$key fails scalar comparison; "
- unless scalar($self->config($key)) eq scalar($compat->config($key));
- }
-
- my (@new) = $self->config($key);
- my (@old) = $compat->config($key);
- unless ( scalar(@new) == scalar(@old)) {
- $error .= "$key fails list comparison; ";
- }else{
- my $r=1;
- foreach (@old) { $r=0 if ($_ cmp shift(@new)); }
- $error .= "$key fails list comparison; "
- unless $r;
- }
-
} else {
-
- no warnings 'uninitialized';
- $error .= "$key fails binary comparison; "
- unless scalar($self->config_binary($key)) eq scalar($compat->config_binary($key));
-
+ warn "Not inserting $key\n" if $DEBUG;
}
-
-#remove deprecated config on our own terms, not freeside-upgrade's
-# if ($error =~ /existential comparison/ && $item->section eq 'deprecated') {
-# my $proto;
-# for ( @config_items ) { $proto = $_; last if $proto->key eq $key; }
-# unless ($proto->key eq $key) {
-# warn "removed config item $error\n" if $DEBUG;
-# $error = '';
-# }
-# }
-
- $error;
}
#item _orbase_items OPTIONS
sub config_items {
my $self = shift;
- return $self->_usecompat('config_items', @_) if use_confcompat;
( @config_items, $self->_orbase_items(@_) );
}
+=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
sub init_config {
my $dir = shift;
- {
- local $FS::UID::use_confcompat = 0;
- my $conf = new FS::Conf;
- foreach my $item ( $conf->config_items(dir => $dir) ) {
- $conf->import_config_item($item, $dir);
- my $error = $conf->verify_config_item($item, $dir);
- return $error if $error;
- }
-
- my $compat = new FS::Conf_compat17 $dir;
- foreach my $item ( $compat->config_items ) {
- my $error = $conf->verify_config_item($item, $dir);
- return $error if $error;
- }
+ my $conf = new FS::Conf;
+ foreach my $item ( $conf->config_items(dir => $dir) ) {
+ $conf->import_config_item($item, $dir);
}
- $FS::UID::use_confcompat = 0;
''; #success
}
},
);
+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',
{
'key' => 'log_sent_mail',
'section' => 'notification',
- 'description' => 'Enable logging of template-generated email.',
+ 'description' => 'Enable logging of all sent email.',
'type' => 'checkbox',
},
{
'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',
},
'%m/%d/%Y' => 'MM/DD/YYYY',
'%d/%m/%Y' => 'DD/MM/YYYY',
'%Y/%m/%d' => 'YYYY/MM/DD',
+ '%e %b %Y' => 'DD Mon YYYY',
],
'per_locale' => 1,
},
{
'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',
},
{
'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',
'per_locale' => 1,
},
+ {
+ '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',
{
'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'
},
'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',
},
{
- '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?
# 'per_agent' => 1,
#},
+ {
+ 'key' => 'usage_class_summary',
+ 'section' => 'invoicing',
+ 'description' => 'Summarize total usage by usage class in a separate section.',
+ 'type' => 'checkbox',
+ },
+
{
'key' => 'usage_class_as_a_section',
'section' => 'invoicing',
'agent_bool' => 1,
},
+ {
+ 'key' => 'payment_receipt_statement_mode',
+ 'section' => 'notification',
+ 'description' => 'Automatic payments will cause a post-payment statement to be sent to the customer. Select the invoice mode to use for this statement. If unspecified, it will use the "_statement" versions of invoice configuration settings, and have the notice name "Statement".',
+ %invoice_mode_options,
+ },
+
{
'key' => 'payment_receipt_msgnum',
'section' => 'notification',
- 'description' => 'Template to use for payment receipts.',
+ 'description' => 'Template to use for manual payment receipts.',
%msg_template_options,
},
'type' => 'text',
},
+ {
+ 'key' => 'papersize',
+ 'section' => 'billing',
+ 'description' => 'Invoice paper size. Default is "letter" (U.S. standard). The LaTeX template must be configured to match this size.',
+ 'type' => 'select',
+ 'select_enum' => [ qw(letter a4) ],
+ },
+
{
'key' => 'money_char',
'section' => '',
'type' => 'checkbox',
},
- {
- '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',
'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) ],
},
{
{
'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' ],
},
{
'type' => 'checkbox',
},
+ {
+ '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',
'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' => 'banned_pay-pad',
+ 'section' => 'billing',
+ 'description' => 'Padding for encrypted storage of banned credit card hashes. If you already have new-style SHA512 entries in the banned_pay table, do not change as this will invalidate the old entries.',
+ 'type' => 'text',
},
{
'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) ],
},
'type' => 'checkbox',
},
+ {
+ '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',
'type' => 'checkbox',
},
+ {
+ 'key' => 'manual_process-single_invoice_amount',
+ 'section' => 'billing',
+ 'description' => 'When entering manual credit card and ACH payments, amount will not autofill if the customer has more than one open invoice',
+ 'type' => 'checkbox',
+ },
+
{
'key' => 'manual_process-pkgpart',
'section' => 'billing',
'type' => 'checkbox',
},
+ {
+ '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',
'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.',
],
},
%msg_template_options,
},
+ {
+ 'key' => 'selfservice-password_change_oldpass',
+ 'section' => 'self-service',
+ 'description' => 'Require old password to be entered again for password changes (in addition to being logged in), at the API level.',
+ 'type' => 'checkbox',
+ },
+
{
'key' => 'selfservice-hide_invoices-taxclass',
'section' => 'self-service',
},
'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 : '';
'per_agent' => 1,
},
+ {
+ 'key' => 'city_not_required',
+ 'section' => 'required',
+ 'description' => 'Turn off requirement for a City to be entered for billing & shipping addresses',
+ 'type' => 'checkbox',
+ 'per_agent' => 1,
+ },
+
{
'key' => 'echeck-void',
'section' => 'deprecated',
'description' => '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',
],
},
},
{
- 'key' => 'cust_pkg-show_fcc_voice_grade_equivalent',
+ 'key' => 'cust_pkg-large_pkg_size',
'section' => 'UI',
- 'description' => "Show fields on package definitions for FCC Form 477 classification",
+ 'description' => "In customer view, summarize packages with more than this many services. Set to zero to never summarize packages.",
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'cust_pkg-hide_discontinued-part_svc',
+ 'section' => 'UI',
+ 'description' => "In customer view, hide provisioned services which are no longer available in the package definition. Not normally used except for very specific situations as it hides still-provisioned services.",
'type' => 'checkbox',
},
{
- 'key' => 'cust_pkg-large_pkg_size',
+ 'key' => 'part_pkg-show_fcc_options',
'section' => 'UI',
- 'description' => "In customer view, summarize packages with more than this many services. Set to zero to never summarize packages.",
- 'type' => 'text',
+ 'description' => "Show fields on package definitions for FCC Form 477 classification",
+ 'type' => 'checkbox',
},
{
'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',
]
},
'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'
]
},
'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',
{
'key' => 'batchconfig-RBC',
'section' => 'billing',
- 'description' => 'Configuration for Royal Bank of Canada PDS batching, four lines: 1. Client number, 2. Short name, 3. Long name, 4. Transaction code.',
+ 'description' => 'Configuration for Royal Bank of Canada PDS batching, five lines: 1. Client number, 2. Short name, 3. Long name, 4. Transaction code 5. (optional) set to TEST to turn on test mode.',
'type' => 'textarea',
},
{
'key' => 'batchconfig-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,
},
'type' => 'checkbox',
},
+ {
+ 'key' => 'cust_main-enable_order_package',
+ 'section' => 'UI',
+ 'description' => 'Display order new package on the basic tab',
+ 'type' => 'checkbox',
+ },
+
{
'key' => 'cust_main-edit_calling_list_exempt',
'section' => 'UI',
'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',
{
'key' => 'previous_balance-exclude_from_total',
'section' => 'invoicing',
- 'description' => 'Do not include previous balance in the \'Total\' line. Only meaningful when invoice_sections is false. Optionally provide text to override the Total New Charges description',
- 'type' => [ qw(checkbox text) ],
+ 'description' => 'Show separate totals for previous invoice balance and new charges. Only meaningful when invoice_sections is false.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'previous_balance-text',
+ 'section' => 'invoicing',
+ 'description' => 'Text for the label of the total previous balance, when it is shown separately. Defaults to "Previous Balance".',
+ 'type' => 'text',
+ },
+
+ {
+ 'key' => 'previous_balance-text-total_new_charges',
+ 'section' => 'invoicing',
+ 'description' => 'Text for the label of the total of new charges, when it is shown separately. If invoice_show_prior_due_date is enabled, the due date of current charges will be appended. Defaults to "Total New Charges".',
+ 'type' => 'text',
},
{
'key' => 'previous_balance-payments_since',
'section' => 'invoicing',
'description' => 'Instead of showing payments (and credits) applied to the invoice, show those received since the previous invoice date.',
+ 'type' => 'checkbox',
+ 'uscensus' => 'U.S. Census Bureau',
+ },
+
+ {
+ 'key' => 'previous_invoice_history',
+ 'section' => 'invoicing',
+ 'description' => 'Show a month-by-month history of the customer\'s '.
+ 'billing amounts. This requires template '.
+ 'modification and is currently not supported on the '.
+ 'stock template.',
'type' => 'checkbox',
},
'type' => 'select',
'select_hash' => [ '' => '',
'usps' => 'U.S. Postal Service',
- 'ezlocate' => 'EZLocate',
'tomtom' => 'TomTom',
'melissa' => 'Melissa WebSmart',
],
{
'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.',
+ '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-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.',
- 'type' => 'text',
- },
-
- {
- 'key' => 'ezlocate-password',
- 'section' => 'UI',
- 'description' => 'Password for EZ-Locate service.',
- 'type' => 'text'
- },
-
{
'key' => 'melissa-userid',
'section' => 'UI', # it's really not...
'type' => 'checkbox',
},
+ {
+ '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' => '',
'type' => 'checkbox',
},
+ {
+ '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',
},
{
'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',
},
},
+ #false laziness w/above options_sub and option_sub
+ {
+ 'key' => 'cust_location-exports',
+ 'section' => '',
+ 'description' => 'Export(s) to call on cust_location insert, modification and deletion.',
+ 'type' => 'select-sub',
+ 'multiple' => 1,
+ 'options_sub' => sub {
+ require FS::Record;
+ require FS::part_export;
+ my @part_export =
+ map { qsearch( 'part_export', {exporttype => $_ } ) }
+ keys %{FS::part_export::export_info('cust_location')};
+ map { $_->exportnum => $_->exporttype.' to '.$_->machine } @part_export;
+ },
+ 'option_sub' => sub {
+ require FS::Record;
+ require FS::part_export;
+ my $part_export = FS::Record::qsearchs(
+ 'part_export', { 'exportnum' => shift }
+ );
+ $part_export
+ ? $part_export->exporttype.' to '.$part_export->machine
+ : '';
+ },
+ },
+
{
'key' => 'cust_tag-location',
'section' => 'UI',
'select_hash' => \@cdr_formats,
},
+ {
+ 'key' => 'selfservice-hide_cdr_price',
+ 'section' => 'self-service',
+ 'description' => 'Don\'t show the "Price" column on CDRs in self-service.',
+ 'type' => 'checkbox',
+ },
+
{
'key' => 'logout-timeout',
'section' => 'UI',
},
},
+ {
+ 'key' => 'part_pkg-term_discounts',
+ 'section' => 'billing',
+ 'description' => 'Enable the term discounts feature. Recommended to keep turned off unless actually using - not well optimized for large installations.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'prepaid-never_renew',
+ 'section' => 'billing',
+ 'description' => 'Prepaid packages never renew.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'agent-disable_counts',
+ 'section' => 'UI',
+ 'description' => 'On the agent browse page, disable the customer and package counts. Typically used for very large databases when this page takes too long to render.',
+ 'type' => 'checkbox',
+ },
+
+ {
+ 'key' => 'tollfree-country',
+ 'section' => 'telephony',
+ 'description' => 'Country / region for toll-free recognition',
+ 'type' => 'select',
+ 'select_hash' => [ '' => 'NANPA (US/Canada)',
+ 'AU' => 'Australia',
+ 'NZ' => 'New Zealand',
+ ],
+ },
+
+ {
+ '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" },