diff options
| -rw-r--r-- | FS/FS/ClientAPI/MyAccount.pm | 125 | ||||
| -rw-r--r-- | FS/FS/IP_Mixin.pm | 4 | ||||
| -rw-r--r-- | FS/FS/Record.pm | 26 | ||||
| -rw-r--r-- | FS/FS/Schema.pm | 1 | ||||
| -rw-r--r-- | FS/FS/cust_main/Search.pm | 3 | ||||
| -rw-r--r-- | FS/FS/log.pm | 22 | ||||
| -rw-r--r-- | FS/FS/log_email.pm | 4 | ||||
| -rw-r--r-- | FS/FS/part_event/Action/bill_sales_credit.pm | 2 | ||||
| -rw-r--r-- | httemplate/browse/discount.html | 31 | ||||
| -rw-r--r-- | httemplate/browse/log_email.html | 44 | ||||
| -rw-r--r-- | httemplate/edit/log_email.html | 11 | ||||
| -rw-r--r-- | httemplate/edit/msg_template.html | 6 | ||||
| -rw-r--r-- | httemplate/misc/delete-log_email.html | 14 | ||||
| -rw-r--r-- | httemplate/search/cust_bill_pkg_discount.html | 6 | ||||
| -rwxr-xr-x | httemplate/search/report_cust_main.html | 4 | ||||
| -rw-r--r-- | httemplate/view/prospect_main.html | 4 |
16 files changed, 125 insertions, 182 deletions
diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index ba698bd8e..9e1a4adc4 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -1016,9 +1016,6 @@ sub validate_payment { my $payinfo2 = $1; $payinfo = $payinfo1. '@'. $payinfo2; - $payinfo = $cust_main->payinfo - if $cust_main->paymask eq $payinfo; - my $achonfile = 0; if ( $cust_main->paymask eq $payinfo ) { $payinfo = $cust_main->payinfo; @@ -1655,128 +1652,6 @@ sub payment_receipt { }; } -sub list_payby { - my $p = shift; - - my($context, $session, $custnum) = _custoragent_session_custnum($p); - return { 'error' => $session } if $context eq 'error'; - - my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } ) - or return { 'error' => "unknown custnum $custnum" }; - - return { - 'payby' => [ map { - my $cust_payby = $_; - +{ - map { $_ => $cust_payby->$_ } - qw( custpaybynum weight payby paymask paydate - payname paystate paytype - ) - }; - } - $cust_main->cust_payby - ], - }; -} - -sub insert_payby { - my $p = shift; - - my($context, $session, $custnum) = _custoragent_session_custnum($p); - return { 'error' => $session } if $context eq 'error'; - - #XXX payinfo1 + payinfo2 for CHEK? - #or take the opportunity to use separate, more well- named fields? - # my $payinfo; - # $p->{'payinfo1'} =~ /^([\dx]+)$/ - # or return { 'error' => "illegal account number ". $p->{'payinfo1'} }; - # my $payinfo1 = $1; - # $p->{'payinfo2'} =~ /^([\dx\.]+)$/ # . turned on by echeck-country CA ? - # or return { 'error' => "illegal ABA/routing number ". $p->{'payinfo2'} }; - # my $payinfo2 = $1; - # $payinfo = $payinfo1. '@'. $payinfo2; - - my $cust_payby = new FS::cust_payby { - 'custnum' => $custnum, - map { $_ => $p->{$_} } qw( weight payby payinfo paycvv paydate payname - paystate paytype payip - ), - }; - - my $error = $cust_payby->insert; - if ( $error ) { - return { 'error' => $error }; - } else { - return { 'custpaybynum' => $cust_payby->custpaybynum }; - } - -} - -sub update_payby { - my $p = shift; - - my($context, $session, $custnum) = _custoragent_session_custnum($p); - return { 'error' => $session } if $context eq 'error'; - - my $cust_payby = qsearchs('cust_payby', { - 'custnum' => $custnum, - 'custpaybynum' => $p->{'custpaybynum'}, - }) - or return { 'error' => 'unknown custpaybynum '. $p->{'custpaybynum'} }; - - foreach my $field ( - qw( weight payby payinfo paycvv paydate payname paystate paytype payip ) - ) { - next unless exists($p->{$field}); - $cust_payby->set($field,$p->{$field}); - } - - my $error = $cust_payby->replace; - if ( $error ) { - return { 'error' => $error }; - } else { - return { 'custpaybynum' => $cust_payby->custpaybynum }; - } - -} - -sub verify_payby { - my $p = shift; - - my($context, $session, $custnum) = _custoragent_session_custnum($p); - return { 'error' => $session } if $context eq 'error'; - - my $cust_payby = qsearchs('cust_payby', { - 'custnum' => $custnum, - 'custpaybynum' => $p->{'custpaybynum'}, - }) - or return { 'error' => 'unknown custpaybynum '. $p->{'custpaybynum'} }; - - return { 'error' => $cust_payby->verify }; - -} - -sub delete_payby { - my $p = shift; - - my($context, $session, $custnum) = _custoragent_session_custnum($p); - return { 'error' => $session } if $context eq 'error'; - - my $cust_payby = qsearchs('cust_payby', { - 'custnum' => $custnum, - 'custpaybynum' => $p->{'custpaybynum'}, - }) - or return { 'error' => 'unknown custpaybynum '. $p->{'custpaybynum'} }; - - my $conf = new FS::Conf; - if (($cust_payby->payby eq "DCHK" || $cust_payby->payby eq "CHEK") && $conf->exists('selfservice-ACH_info_readonly')) { - return { 'error' => "Sorry you do not have permission to delete bank information." }; - } - else { - return { 'error' => $cust_payby->delete }; - } -} - sub cancel { my $p = shift; my $session = _cache->get($p->{'session_id'}) diff --git a/FS/FS/IP_Mixin.pm b/FS/FS/IP_Mixin.pm index 3ec769313..8920cebc5 100644 --- a/FS/FS/IP_Mixin.pm +++ b/FS/FS/IP_Mixin.pm @@ -94,6 +94,10 @@ sub ip_check { $self->ip_addr(''); } + # Will strip extraneous leading zeros from ip adddresses + # e.g. 10.0.022.220 corrected to 10.0.22.220 + $self->ut_ip46n('ip_addr'); + if ( $self->ip_addr and !$self->router and $self->conf->exists('auto_router') ) { diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index 89957cb47..fe8fad969 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -289,6 +289,11 @@ the individual PARAMS_HASHREF queries #regular FS::TABLE methods #on it. +C<$FS::Record::qsearch_qualify_columns> package global is disabled by default. +When enabled, the WHERE clause generated from the 'hashref' parameter has +the table name prepended to each column name. WHERE column = 'value' becomes +WHERE table.coumn = 'value' + =cut my %TYPE = (); #for debugging @@ -2671,7 +2676,7 @@ sub ut_ip { $self->getfield($field) =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ or return "Illegal (IP address) $field: ". $self->getfield($field); for ( $1, $2, $3, $4 ) { return "Illegal (IP address) $field" if $_ > 255; } - $self->setfield($field, "$1.$2.$3.$4"); + $self->setfield( $field, $self->_ut_ip_strip_leading_zeros( "$1.$2.$3.$4" )); ''; } @@ -2700,8 +2705,9 @@ Check/untaint IPv4 or IPv6 address. sub ut_ip46 { my( $self, $field ) = @_; - my $ip = NetAddr::IP->new($self->getfield($field)) - or return "Illegal (IP address) $field: ".$self->getfield($field); + my $ip = NetAddr::IP->new( + $self->_ut_ip_strip_leading_zeros( $self->getfield($field) ) + ) or return "Illegal (IP address) $field: ".$self->getfield($field); $self->setfield($field, lc($ip->addr)); return ''; } @@ -2721,6 +2727,20 @@ sub ut_ip46n { $self->ut_ip46($field); } +sub _ut_ip_strip_leading_zeros { + # strip user-entered leading 0's from IP addresses + # so parsers like NetAddr::IP don't mangle the address + # e.g. NetAddr::IP converts 10.0.022.220 into 10.0.18.220 + + my ( $self, $ip ) = @_; + + return join '.', map int, split /\./, $ip + if $ip + && $ip =~ /\./ + && $ip =~ /[\.^]0/; + $ip; +} + =item ut_coord COLUMN [ LOWER [ UPPER ] ] Check/untaint coordinates. diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index ecd071e49..2168c4c39 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -4665,6 +4665,7 @@ sub tables_hashref { 'min_level', 'int', 'NULL', '', '', '', 'msgnum', 'int', '', '', '', '', 'to_addr', 'varchar', 'NULL', 255, '', '', + 'context_height', 'int', 'NULL', '', '', '', ], 'primary_key' => 'logemailnum', 'unique' => [], diff --git a/FS/FS/cust_main/Search.pm b/FS/FS/cust_main/Search.pm index 1a19ea343..58bdd8835 100644 --- a/FS/FS/cust_main/Search.pm +++ b/FS/FS/cust_main/Search.pm @@ -1049,8 +1049,9 @@ sub search { if ( @tagnums ) { if ( $params->{'all_tags'} ) { + my $exists = $params->{'all_tags'} eq 'all' ? 'exists' : 'not exists'; foreach ( @tagnums ) { - push @where, 'exists(select 1 from cust_tag where '. + push @where, $exists.'(select 1 from cust_tag where '. 'cust_tag.custnum = cust_main.custnum and tagnum = '. $_ . ')'; } diff --git a/FS/FS/log.pm b/FS/FS/log.pm index 75e17c847..64d036e4d 100644 --- a/FS/FS/log.pm +++ b/FS/FS/log.pm @@ -4,6 +4,7 @@ use strict; use base qw( FS::Record ); use FS::Record qw( qsearch qsearchs dbdef ); use FS::UID qw( dbh driver_name ); +use FS::Log; use FS::log_context; use FS::log_email; use FS::upgrade_journal; @@ -81,18 +82,22 @@ Will send emails according to the conditions in L<FS::log_email>. sub insert { # not using process_o2m for this, because we don't have a web interface my $self = shift; + my $error = $self->SUPER::insert; return $error if $error; - my $contexts = {}; #for quick checks when sending emails - foreach ( @_ ) { + + my $contexts = {}; + my $context_height = @_; + foreach ( @_ ) { # ordered from least to most specific my $context = FS::log_context->new({ 'lognum' => $self->lognum, 'context' => $_ }); $error = $context->insert; return $error if $error; - $contexts->{$_} = 1; + $contexts->{$_} = $context_height--; } + foreach my $log_email ( qsearch('log_email', { @@ -104,19 +109,20 @@ sub insert { } ) ) { - # shouldn't be a lot of these, so not packing this into the qsearch + # shouldn't be a lot of log_email records, so not packing these checks into the qsearch next if $log_email->context && !$contexts->{$log_email->context}; + next if $log_email->context_height && ($contexts->{$log_email->context} > $log_email->context_height); my $msg_template = qsearchs('msg_template',{ 'msgnum' => $log_email->msgnum }); unless ($msg_template) { warn "Could not send email when logging, could not load message template for logemailnum " . $log_email->logemailnum; next; } my $emailerror = $msg_template->send( - 'msgtype' => 'admin', - 'to' => $log_email->to_addr, + 'msgtype' => 'admin', + 'to' => $log_email->to_addr, 'substitutions' => { - 'loglevel' => $FS::Log::LEVELS{$self->level}, # which has hopefully been loaded... - 'logcontext' => $log_email->context, # use the one that triggered the email + 'loglevel' => $FS::Log::LEVELS{$self->level} || 'unknown', + 'logcontext' => join(', ', keys( %$contexts )) || 'unknown', 'logmessage' => $self->message, }, ); diff --git a/FS/FS/log_email.pm b/FS/FS/log_email.pm index 9c53c230a..a055cb4c6 100644 --- a/FS/FS/log_email.pm +++ b/FS/FS/log_email.pm @@ -42,6 +42,9 @@ The following fields are currently supported: =item to_addr - who the email will be sent to (in addition to any bcc on the template) +=item context_height - number of context stack levels to match against +(0 or null matches against full stack, 1 only matches lowest level context, 2 matches lowest two levels, etc.) + =back =head1 METHODS @@ -88,6 +91,7 @@ sub check { || $self->ut_number('min_level') || $self->ut_foreign_key('msgnum', 'msg_template', 'msgnum') || $self->ut_textn('to_addr') + || $self->ut_numbern('context_height') ; return $error if $error; diff --git a/FS/FS/part_event/Action/bill_sales_credit.pm b/FS/FS/part_event/Action/bill_sales_credit.pm index ab69375e2..e1474300a 100644 --- a/FS/FS/part_event/Action/bill_sales_credit.pm +++ b/FS/FS/part_event/Action/bill_sales_credit.pm @@ -72,7 +72,7 @@ sub do_action { my $reasonnum = $self->option('reasonnum'); - my $desc = 'from invoice #'. $cust_bill->display_invnum . + my $desc = ' for customer #'.$cust_main->display_custnum.': '.$cust_main->name.' from invoice #'. $cust_bill->display_invnum . ' ('. time2str($date_format, $cust_bill->_date) . ')'; # could also show custnum and pkgnums here? my $error = $sales_cust_main->credit( diff --git a/httemplate/browse/discount.html b/httemplate/browse/discount.html index d3cf873d0..5ed43cf0e 100644 --- a/httemplate/browse/discount.html +++ b/httemplate/browse/discount.html @@ -1,10 +1,9 @@ <% include( 'elements/browse.html', 'title' => 'Discounts', 'name' => 'discounts', - 'menubar' => [ 'Add a new discount' => - $p.'edit/discount.html', - ], - 'query' => { 'table' => 'discount', }, + 'menubar' => \@menubar, + 'query' => \%query, + 'order_by_sql' => { description => 'discountnum' }, 'count_query' => 'SELECT COUNT(*) FROM discount', 'disableable' => 1, 'disabled_statuspos' => 1, @@ -13,9 +12,7 @@ 'classname', 'description', ], - 'links' => [ $link, - $link, - ], + 'links' => \@links ) %> <%init> @@ -23,6 +20,24 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right('Configuration'); -my $link = [ "${p}edit/discount.html?", 'discountnum' ]; +my @links = ( + [ "${p}edit/discount.html?", 'discountnum' ], + [ "${p}edit/discount_class.html?", 'classnum' ], +); + +# Fixes disableable, because discount and discount_class tables +# both contain a 'disabled' column +local $FS::Record::qsearch_qualify_columns = 1; + +my %query = ( + select => 'discount.*, discount_class.*', + table => 'discount', + addl_from => 'LEFT JOIN discount_class USING(classnum)', +); + +my @menubar = ( + 'Add a new discount' => $p.'edit/discount.html', + 'Discount classes' => $p.'browse/discount_class.html', +); </%init> diff --git a/httemplate/browse/log_email.html b/httemplate/browse/log_email.html index 007ea6f74..fe583dc62 100644 --- a/httemplate/browse/log_email.html +++ b/httemplate/browse/log_email.html @@ -6,10 +6,7 @@ . $add_condition_link . ' | ' . $system_log_link - . '</P>' - . '<SCRIPT>' - . $areyousure - . '</SCRIPT>', + . '</P>', 'query' => $query, 'count_query' => $count_query, 'header' => [ '#', @@ -43,6 +40,23 @@ ) %> +<script> + function areyousure_delete_log_email(logemailnum) { + if ( confirm( 'Delete log email condition #' + logemailnum )) { + <% + include( + '/elements/popup_link_onclick.html' => { + js_action => qq( '${fsurl}/misc/delete-log_email.html?logemailnum=' + logemailnum ), + actionlabel => 'Delete log email condition', + nofalse => 1, + } + ) + %> + return; + } + } +</script> + <%init> my $curuser = $FS::CurrentUser::CurrentUser; @@ -50,11 +64,7 @@ my $curuser = $FS::CurrentUser::CurrentUser; die "access denied" unless $curuser->access_right([ 'View system logs', 'Configuration' ]); -my $add_condition_link = include('/elements/popup_link.html', - 'action' => $p.'edit/log_email.html?popup=1', - 'label' => 'Add log email condition', - 'actionlabel' => 'Add log email condition', -); +my $add_condition_link = qq( <a href="${fsurl}edit/log_email.html">Add log email condition</a> ); my $system_log_link = qq(<A HREF="${p}search/log.html">System Log</A>); @@ -68,24 +78,10 @@ my $query = { my $count_query = "SELECT COUNT(*) FROM log_email"; my $actions = sub { - my $log_email = shift; - my $logemailnum = $log_email->logemailnum; + my $logemailnum = shift->logemailnum; qq!<A HREF="javascript:areyousure_delete_log_email($logemailnum)">(delete)</A>!; }; -my $areyousure_onclick = include('/elements/popup_link_onclick.html', - 'js_action' => q(') . $p . q(misc/delete-log_email.html?logemailnum=' + logemailnum), - 'actionlabel' => 'Delete log email condition', -); - -my $areyousure = <<EOF; -function areyousure_delete_log_email(logemailnum) { - if (confirm('Are you sure you want to delete log email condition #'+logemailnum+'?')) { -${areyousure_onclick} - } -} -EOF - my $editlink = [ $p.'edit/log_email.html?logemailnum=', 'logemailnum' ]; </%init> diff --git a/httemplate/edit/log_email.html b/httemplate/edit/log_email.html index 19b415d4d..b79aba986 100644 --- a/httemplate/edit/log_email.html +++ b/httemplate/edit/log_email.html @@ -8,6 +8,12 @@ 'labels' => { '' => '(all)', map { $_ => $_ } @contexts }, 'curr_value' => scalar($cgi->param('context')), }, + { 'field' => 'context_height', + 'type' => 'checkbox', + 'postfix' => 'Only match most specific context', + 'value' => 1, + 'curr_value' => scalar($cgi->param('context_height')), + }, { 'field' => 'min_level', 'type' => 'select', 'options' => [ &FS::Log::levelnums ], @@ -24,6 +30,7 @@ ], 'labels' => { 'context' => 'Context', + 'context_height' => '', 'min_level' => 'Min. Level', 'to_addr' => 'To', 'msgnum' => 'Message', @@ -44,6 +51,10 @@ die "access denied" unless $FS::CurrentUser::CurrentUser->access_right([ 'View system logs', 'Configuration' ]); my $msgnum = $cgi->param('msgnum'); + +# XXX This attempt to set a default message isn't working, not sure why +# $msgnum gets set correctly, but isn't selected in the popup window...fix later + unless ($msgnum) { my ($msg_template) = qsearch('msg_template',{ msgname => 'System log' }); # doesn't seem worth having a config just for the default selected template diff --git a/httemplate/edit/msg_template.html b/httemplate/edit/msg_template.html index 0478a8066..17e9966de 100644 --- a/httemplate/edit/msg_template.html +++ b/httemplate/edit/msg_template.html @@ -305,6 +305,11 @@ my %substitutions = ( '$payinfo' => 'Card/account# (masked)', '$payinfo_end' => 'Card/account last 4 digits', ], + 'system_log' => [ + '$loglevel' => 'Log event severity level', + '$logcontext' => 'Log event context', + '$logmessage' => 'Log event message text' + ], ); tie my %sections, 'Tie::IxHash', ( @@ -319,6 +324,7 @@ tie my %sections, 'Tie::IxHash', ( 'svc_domain'=> 'Domain service fields', 'svc_phone' => 'Phone service fields', 'svc_broadband' => 'Broadband service fields', +'system_log' => 'System log fields', ); my $widget = new HTML::Widgets::SelectLayers( diff --git a/httemplate/misc/delete-log_email.html b/httemplate/misc/delete-log_email.html index cc17b15a0..5a6bdc083 100644 --- a/httemplate/misc/delete-log_email.html +++ b/httemplate/misc/delete-log_email.html @@ -3,7 +3,7 @@ % } else { <H1>Log email condition deleted</H1> <SCRIPT> -window.top.location.reload(); +window.top.location = "<% $fsurl %>browse/log_email.html"; </SCRIPT> % } @@ -11,10 +11,12 @@ window.top.location.reload(); die "access denied" unless $FS::CurrentUser::CurrentUser->access_right([ 'View system logs', 'Configuration' ]); -my $logemailnum = $cgi->param('logemailnum'); -$logemailnum =~ /^\d+$/ or die "bad logemailnum '$logemailnum'"; -my $log_email = FS::log_email->by_key($logemailnum) - or die "logemailnum '$logemailnum' not found"; -my $error = $log_email->delete; + my $error; + my $logemailnum = $cgi->param('logemailnum'); + if ( $logemailnum && $logemailnum =~ /^\d+$/ ) { + if ( my $log_email = FS::log_email->by_key( $logemailnum ) ) { + $error = $log_email->delete; + } + } </%init> diff --git a/httemplate/search/cust_bill_pkg_discount.html b/httemplate/search/cust_bill_pkg_discount.html index 691a11e60..9ddc97da2 100644 --- a/httemplate/search/cust_bill_pkg_discount.html +++ b/httemplate/search/cust_bill_pkg_discount.html @@ -39,8 +39,8 @@ Parameters: # Standard discount, not a waived setup fee my $discount = qsearchs('discount',{ discountnum => $_[0]->discountnum - }); - return $discount->description; + }) || return 'Bad discountnum '.$_[0]->pkgdiscountnum; + return encode_entities $discount->description; } else { return 'Waive setup fee'; } @@ -53,7 +53,7 @@ Parameters: my $discount = qsearchs('discount',{ discountnum => $_[0]->discountnum }); - return $discount->classname; + return encode_entities $discount->classname; } else { return 'n/a'; } diff --git a/httemplate/search/report_cust_main.html b/httemplate/search/report_cust_main.html index e1ce26dcb..9edd3ee5c 100755 --- a/httemplate/search/report_cust_main.html +++ b/httemplate/search/report_cust_main.html @@ -104,7 +104,9 @@ <DIV STYLE="display:inline-block; vertical-align:baseline"> <INPUT TYPE="radio" NAME="all_tags" VALUE="0" CHECKED> Any of these <BR> - <INPUT TYPE="radio" NAME="all_tags" VALUE="1"> All of these + <INPUT TYPE="radio" NAME="all_tags" VALUE="all"> All of these + <BR> + <INPUT TYPE="radio" NAME="all_tags" VALUE="none"> None of these </DIV> </TD> </TR> diff --git a/httemplate/view/prospect_main.html b/httemplate/view/prospect_main.html index 66abffcdd..ac56fa7a2 100644 --- a/httemplate/view/prospect_main.html +++ b/httemplate/view/prospect_main.html @@ -41,8 +41,8 @@ % foreach my $contact ( $prospect_main->contact ) { <TR> - <TD ALIGN="right"><% $contact->contact_classname %> Contact</TD> - <TD BGCOLOR="#FFFFFF"><% $contact->line %></TD> + <TD ALIGN="right"><% $contact->contact_classname |h %> Contact</TD> + <TD BGCOLOR="#FFFFFF"><% $contact->line |h %></TD> </TR> %} |
