X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_main.pm;h=60556a5a4c1c1878abb85019baadd878c0f05093;hb=583902ab51f62551fe3620d98d42e72620edfa76;hp=d8dbd5297527ba7f91e054afff24d3e50e891417;hpb=649ceeca76084d16d22013124bd7f80f053d75c4;p=freeside.git diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index d8dbd5297..60556a5a4 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1,10 +1,11 @@ package FS::cust_main; use strict; -use vars qw( @ISA $conf $DEBUG $import ); +use vars qw( @ISA @EXPORT_OK $conf $DEBUG $import ); use vars qw( $realtime_bop_decline_quiet ); #ugh use Safe; use Carp; +use Exporter; BEGIN { eval "use Time::Local;"; die "Time::Local minimum version 1.05 required with Perl versions before 5.6" @@ -43,6 +44,8 @@ use FS::Msgcat qw(gettext); @ISA = qw( FS::Record ); +@EXPORT_OK = qw( smart_search ); + $realtime_bop_decline_quiet = 0; $DEBUG = 0; @@ -1006,6 +1009,27 @@ sub unsuspended_pkgs { grep { ! $_->susp } $self->ncancelled_pkgs; } +=item num_cancelled_pkgs + +Returns the number of cancelled packages (see L) for this +customer. + +=cut + +sub num_cancelled_pkgs { + my $self = shift; + $self->num_pkgs("cancel IS NOT NULL AND cust_pkg.cancel != 0"); +} + +sub num_pkgs { + my( $self, $sql ) = @_; + my $sth = dbh->prepare( + "SELECT COUNT(*) FROM cust_pkg WHERE custnum = ? AND $sql" + ) or die dbh->errstr; + $sth->execute($self->custnum) or die $sth->errstr; + $sth->fetchrow_arrayref->[0]; +} + =item unsuspend Unsuspends all unflagged suspended packages (see L @@ -1319,7 +1343,7 @@ sub bill { || $tax->recurtax =~ /^Y$/i; next unless $taxable_charged; - if ( $tax->exempt_amount > 0 ) { + if ( $tax->exempt_amount && $tax->exempt_amount > 0 ) { my ($mon,$year) = (localtime($sdate) )[4,5]; $mon++; my $freq = $part_pkg->freq || 1; @@ -1579,6 +1603,7 @@ sub collect { my $error; { local $realtime_bop_decline_quiet = 1 if $options{'quiet'}; + local $SIG{__DIE__}; # don't want Mason __DIE__ handler active $error = eval $part_bill_event->eventcode; } @@ -2634,6 +2659,19 @@ sub referral_cust_pkg { $self->referral_cust_main($depth); } +=item referring_cust_main + +Returns the single cust_main record for the customer who referred this customer +(referral_custnum), or false. + +=cut + +sub referring_cust_main { + my $self = shift; + return '' unless $self->referral_custnum; + qsearchs('cust_main', { 'custnum' => $self->referral_custnum } ); +} + =item credit AMOUNT, REASON Applies a credit to this customer. If there is an error, returns the error, @@ -2914,6 +2952,7 @@ sub susp_sql { " AND 0 = ( SELECT COUNT(*) FROM cust_pkg WHERE cust_pkg.custnum = cust_main.custnum AND ( cust_pkg.susp IS NULL OR cust_pkg.susp = 0 ) + AND ( cust_pkg.cancel IS NULL OR cust_pkg.cancel = 0 ) ) "; } @@ -2977,6 +3016,94 @@ sub fuzzy_search { =over 4 +=item smart_search OPTION => VALUE ... + +Accepts the following options: I, the string to search for. The string +will be searched for as a customer number, last name or company name, first +searching for an exact match then fuzzy and substring matches. + +Any additional options treated as an additional qualifier on the search +(i.e. I). + +Returns a (possibly empty) array of FS::cust_main objects. + +=cut + +sub smart_search { + my %options = @_; + my $search = delete $options{'search'}; + my @cust_main = (); + + if ( $search =~ /^\s*(\d+)\s*$/ ) { # customer # search + + push @cust_main, qsearch('cust_main', { 'custnum' => $1, %options } ); + + } elsif ( $search =~ /^\s*(\S.*\S)\s*$/ ) { #value search + + my $value = lc($1); + my $q_value = dbh->quote($value); + + #exact + my $sql = scalar(keys %options) ? ' AND ' : ' WHERE '; + $sql .= " ( LOWER(last) = $q_value OR LOWER(company) = $q_value"; + $sql .= " OR LOWER(ship_last) = $q_value OR LOWER(ship_company) = $q_value" + if defined dbdef->table('cust_main')->column('ship_last'); + $sql .= ' )'; + + push @cust_main, qsearch( 'cust_main', \%options, '', $sql ); + + unless ( @cust_main ) { #no exact match, trying substring/fuzzy + + #still some false laziness w/ search/cust_main.cgi + + #substring + push @cust_main, qsearch( 'cust_main', + { 'last' => { 'op' => 'ILIKE', + 'value' => "%$q_value%" }, + %options, + } + ); + push @cust_main, qsearch( 'cust_main', + { 'ship_last' => { 'op' => 'ILIKE', + 'value' => "%$q_value%" }, + %options, + + } + ) + if defined dbdef->table('cust_main')->column('ship_last'); + + push @cust_main, qsearch( 'cust_main', + { 'company' => { 'op' => 'ILIKE', + 'value' => "%$q_value%" }, + %options, + } + ); + push @cust_main, qsearch( 'cust_main', + { 'ship_company' => { 'op' => 'ILIKE', + 'value' => "%$q_value%" }, + %options, + } + ) + if defined dbdef->table('cust_main')->column('ship_last'); + + #fuzzy + push @cust_main, FS::cust_main->fuzzy_search( + { 'last' => $value }, + \%options, + ); + push @cust_main, FS::cust_main->fuzzy_search( + { 'company' => $value }, + \%options, + ); + + } + + } + + @cust_main; + +} + =item check_and_rebuild_fuzzyfiles =cut