X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2FConf.pm;h=f80f2d55f331baed5c6b8ffb39c04da94f3aa9a5;hb=7898193bb13ad215d1cc95983dbd092fbd2ba799;hp=802794c6446fbe32864629adb746c90008c61781;hpb=24c38179b5d35f4edf2ab5fa157c7ca86046552e;p=freeside.git diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 802794c64..f80f2d55f 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -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; @@ -8,18 +11,19 @@ use MIME::Base64; 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 @@ -108,18 +112,12 @@ specific value(s) is returned. =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 || ()), @@ -133,9 +131,14 @@ 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; @@ -143,7 +146,6 @@ sub _config { sub config { my $self = shift; - return $self->_usecompat('config', @_) if use_confcompat; carp "FS::Conf->config(". join(', ', @_). ") called" if $DEBUG > 1; @@ -167,7 +169,6 @@ Returns the exact scalar value for key. 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) : ''; @@ -182,7 +183,6 @@ is undefined. sub exists { my $self = shift; - return $self->_usecompat('exists', @_) if use_confcompat; #my($name, $agentnum)=@_; @@ -197,7 +197,6 @@ sub exists { sub config_bool { my $self = shift; - return $self->_usecompat('exists', @_) if use_confcompat; my($name,$agentnum,$agentonly) = @_; @@ -252,7 +251,6 @@ KEY_SUFFIX, if it exists, otherwise for KEY # 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") ) { @@ -272,7 +270,6 @@ config_orbase. 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") ) { @@ -315,7 +312,6 @@ Creates the specified configuration key if it does not exist. sub touch { my $self = shift; - return $self->_usecompat('touch', @_) if use_confcompat; my($name, $agentnum) = @_; #unless ( $self->exists($name, $agentnum) ) { @@ -336,7 +332,6 @@ Sets the specified configuration key to the given value. sub set { my $self = shift; - return $self->_usecompat('set', @_) if use_confcompat; my($name, $value, $agentnum) = @_; $value =~ /^(.*)$/s; @@ -361,6 +356,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; @@ -375,7 +376,6 @@ can be retrieved with config_binary. sub set_binary { my $self = shift; - return if use_confcompat; my($name, $value, $agentnum)=@_; $self->set($name, encode_base64($value), $agentnum); @@ -389,7 +389,6 @@ Deletes the specified configuration key. 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}}) ) { @@ -416,7 +415,6 @@ sub delete { sub delete_bool { my $self = shift; - return $self->_usecompat('delete', @_) if use_confcompat; my($name, $agentnum) = @_; @@ -447,7 +445,7 @@ in the directory DIR. 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"); @@ -456,68 +454,9 @@ sub import_config_item { }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); - - 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 @@ -588,11 +527,25 @@ FS::ConfItem objects. See L. 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 @@ -609,23 +562,11 @@ to conf records in the database. 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 } @@ -718,6 +659,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', @@ -1546,6 +1504,13 @@ and customer address. Include units.', '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', @@ -1698,10 +1663,17 @@ and customer address. Include units.', '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, }, @@ -2131,13 +2103,6 @@ and customer address. Include units.', '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', @@ -2234,7 +2199,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) ], }, { @@ -2637,13 +2602,20 @@ and customer address. Include units.', 'section' => 'billing', 'description' => 'Available payment types.', 'type' => 'selectmultiple', - 'select_enum' => [ qw(CARD DCRD CHEK DCHK BILL CASH WEST MCRD MCHK 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) ], }, @@ -2789,6 +2761,13 @@ and customer address. Include units.', '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', @@ -2981,7 +2960,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.', ], }, @@ -3039,7 +3018,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 : ''; @@ -3336,6 +3315,14 @@ and customer address. Include units.', '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', @@ -3888,7 +3875,7 @@ and customer address. Include units.', { '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', }, @@ -4331,8 +4318,22 @@ and customer address. Include units.', { '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', }, { @@ -4368,6 +4369,7 @@ and customer address. Include units.', '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', }, { @@ -4603,6 +4605,16 @@ and customer address. Include units.', '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' => '',