X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_main%2FSearch.pm;h=4eab474e19a3cb4c18b41c9a655c313af520cd7e;hb=ce7d68e984aab0075f87cf3fa5a55ee4083fadd2;hp=215fdc2bcc989acdfc5359351c3c50f51b33a541;hpb=37ac9c4f5754a1398b7bc354db716be828f04253;p=freeside.git diff --git a/FS/FS/cust_main/Search.pm b/FS/FS/cust_main/Search.pm index 215fdc2bc..4eab474e1 100644 --- a/FS/FS/cust_main/Search.pm +++ b/FS/FS/cust_main/Search.pm @@ -356,30 +356,39 @@ sub smart_search { #still some false laziness w/search (was search/cust_main.cgi) + my $min_len = + $FS::CurrentUser::CurrentUser->access_right('List all customers') + ? 3 : 4; + #substring - my @hashrefs = ( - { 'company' => { op=>'ILIKE', value=>"%$value%" }, }, - { 'ship_company' => { op=>'ILIKE', value=>"%$value%" }, }, - ); + my @company_hashrefs = (); + if ( length($value) >= $min_len ) { + @company_hashrefs = ( + { 'company' => { op=>'ILIKE', value=>"%$value%" }, }, + { 'ship_company' => { op=>'ILIKE', value=>"%$value%" }, }, + ); + } + my @hashrefs = (); if ( $first && $last ) { - push @hashrefs, + @hashrefs = ( { 'first' => { op=>'ILIKE', value=>"%$first%" }, 'last' => { op=>'ILIKE', value=>"%$last%" }, }, - ; + ); - } else { + } elsif ( length($value) >= $min_len ) { - push @hashrefs, + @hashrefs = ( { 'first' => { op=>'ILIKE', value=>"%$value%" }, }, { 'last' => { op=>'ILIKE', value=>"%$value%" }, }, - ; + ); + } - foreach my $hashref ( @hashrefs ) { + foreach my $hashref ( @company_hashrefs, @hashrefs ) { push @cust_main, qsearch( { 'table' => 'cust_main', @@ -391,7 +400,7 @@ sub smart_search { } - if ( $conf->exists('address1-search') ) { + if ( $conf->exists('address1-search') && length($value) >= $min_len ) { push @cust_main, qsearch( { table => 'cust_main', @@ -405,8 +414,6 @@ sub smart_search { #contact substring - shift @hashrefs; #no company column in contact table - foreach my $hashref ( @hashrefs ) { push @cust_main, @@ -441,7 +448,8 @@ sub smart_search { 'contact.first' => $first }, # %fuzopts ); - } + } + foreach my $field ( 'first', 'last', 'company', 'ship_company' ) { push @cust_main, FS::cust_main::Search->fuzzy_search( { $field => $value }, @@ -477,11 +485,12 @@ sub smart_search { push @cust_main, qsearch({ 'table' => 'cust_main', + 'addl_from' => ' JOIN cust_payby USING (custnum)', 'hashref' => {}, - 'extra_sql' => " WHERE ( payinfo LIKE '$like_search' - OR paymask = '$mask_search' + 'extra_sql' => " WHERE ( cust_payby.payinfo LIKE '$like_search' + OR cust_payby.paymask = '$mask_search' ) ". - " AND payby IN ('CARD','DCRD') ". + " AND cust_payby.payby IN ('CARD','DCRD') ". " AND $agentnums_sql", #agent virtulization }); @@ -513,11 +522,9 @@ none or one). sub email_search { my %options = @_; - local($DEBUG) = 1; - my $email = delete $options{'email'}; - #we're only being used by RT at the moment... no agent virtualization yet + #no agent virtualization yet #my $agentnums_sql = $FS::CurrentUser::CurrentUser->agentnums_sql; my @cust_main = (); @@ -530,10 +537,12 @@ sub email_search { if $DEBUG; push @cust_main, - map $_->cust_main, + map { $_->cust_main } + map { $_->cust_contact } + map { $_->contact } qsearch( { - 'table' => 'cust_main_invoice', - 'hashref' => { 'dest' => $email }, + 'table' => 'contact_email', + 'hashref' => { 'emailaddress' => $email }, } ); @@ -607,14 +616,6 @@ listref of start date, end date listref of start date, end date -=item payby - -listref - -=item paydate_year - -=item paydate_month - =item current_balance listref (list returned by FS::UI::Web::parse_lt_gt($cgi, 'current_balance')) @@ -645,7 +646,6 @@ sub search { 'status' => '', 'address' => '', 'zip' => '', - 'paydate_year' => '', 'invoice_terms' => '', 'custbatch' => '', %$params @@ -703,6 +703,21 @@ sub search { push @where, FS::cust_main->$method(); } + my $current = ''; + unless ( $params->{location_history} ) { + $current = ' + AND ( cust_location.locationnum IN ( cust_main.bill_locationnum, + cust_main.ship_locationnum + ) + OR cust_location.locationnum IN ( + SELECT locationnum FROM cust_pkg + WHERE cust_pkg.custnum = cust_main.custnum + AND locationnum IS NOT NULL + AND '. FS::cust_pkg->ncancelled_recurring_sql.' + ) + )'; + } + ## # address ## @@ -722,11 +737,51 @@ sub search { SELECT 1 FROM cust_location WHERE cust_location.custnum = cust_main.custnum AND (".join(' OR ',@orwhere).") + $current )"; } } ## + # city + ## + if ( $params->{'city'} =~ /\S/ ) { + my $city = dbh->quote($params->{'city'}); + push @where, "EXISTS( + SELECT 1 FROM cust_location + WHERE cust_location.custnum = cust_main.custnum + AND cust_location.city = $city + $current + )"; + } + + ## + # county + ## + if ( $params->{'county'} =~ /\S/ ) { + my $county = dbh->quote($params->{'county'}); + push @where, "EXISTS( + SELECT 1 FROM cust_location + WHERE cust_location.custnum = cust_main.custnum + AND cust_location.county = $county + $current + )"; + } + + ## + # state + ## + if ( $params->{'state'} =~ /\S/ ) { + my $state = dbh->quote($params->{'state'}); + push @where, "EXISTS( + SELECT 1 FROM cust_location + WHERE cust_location.custnum = cust_main.custnum + AND cust_location.state = $state + $current + )"; + } + + ## # zipcode ## if ( $params->{'zip'} =~ /\S/ ) { @@ -735,6 +790,20 @@ sub search { SELECT 1 FROM cust_location WHERE cust_location.custnum = cust_main.custnum AND cust_location.zip LIKE $zip + $current + )"; + } + + ## + # country + ## + if ( $params->{'country'} =~ /^(\w\w)$/ ) { + my $country = uc($1); + push @where, "EXISTS( + SELECT 1 FROM cust_location + WHERE cust_location.custnum = cust_main.custnum + AND cust_location.country = '$country' + $current )"; } @@ -768,33 +837,62 @@ sub search { ## push @where, - 'EXISTS ( SELECT 1 FROM cust_main_invoice - WHERE cust_main_invoice.custnum = cust_main.custnum - AND length(dest) > 5 - )' # AND dest LIKE '%@%' + 'EXISTS ( SELECT 1 FROM contact_email + JOIN cust_contact USING (contactnum) + WHERE cust_contact.custnum = cust_main.custnum + )' if $params->{'with_email'}; ## # "with postal mail invoices" checkbox ## - push @where, - "EXISTS ( SELECT 1 FROM cust_main_invoice - WHERE cust_main_invoice.custnum = cust_main.custnum - AND dest = 'POST' )" + push @where, "cust_main.postal_invoice = 'Y'" if $params->{'POST'}; ## # "without postal mail invoices" checkbox ## - push @where, - "NOT EXISTS ( SELECT 1 FROM cust_main_invoice - WHERE cust_main_invoice.custnum = cust_main.custnum - AND dest = 'POST' )" + push @where, "cust_main.postal_invoice IS NULL" if $params->{'no_POST'}; ## + # "tax exempt" checkbox + ## + push @where, "cust_main.tax = 'Y'" + if $params->{'tax'}; + + ## + # "not tax exempt" checkbox + ## + push @where, "(cust_main.tax = '' OR cust_main.tax IS NULL )" + if $params->{'no_tax'}; + + ## + # with referrals + ## + if ( $params->{with_referrals} =~ /^\s*(\d+)\s*$/ ) { + + my $n = $1; + + # referral status + my $and_status = ''; + if ( grep { $params->{referral_status} eq $_ } FS::cust_main->statuses() ) { + my $method = $params->{referral_status}. '_sql'; + $and_status = ' AND '. FS::cust_main->$method(); + $and_status =~ s/ cust_main\./ referred_cust_main./g; + } + + push @where, + " $n <= ( SELECT COUNT(*) FROM cust_main AS referred_cust_main + WHERE cust_main.custnum = referred_cust_main.referral_custnum + $and_status + )"; + + } + + ## # dates ## @@ -850,40 +948,6 @@ sub search { } ### - # payby - ### - - if ( $params->{'payby'} ) { - - my @payby = ref( $params->{'payby'} ) - ? @{ $params->{'payby'} } - : ( $params->{'payby'} ); - - @payby = grep /^([A-Z]{4})$/, @payby; - - push @where, '( '. join(' OR ', map "cust_main.payby = '$_'", @payby). ' )' - if @payby; - - } - - ### - # paydate_year / paydate_month - ### - - if ( $params->{'paydate_year'} =~ /^(\d{4})$/ ) { - my $year = $1; - $params->{'paydate_month'} =~ /^(\d\d?)$/ - or die "paydate_year without paydate_month?"; - my $month = $1; - - push @where, - 'paydate IS NOT NULL', - "paydate != ''", - "CAST(paydate AS timestamp) < CAST('$year-$month-01' AS timestamp )" -; - } - - ### # invoice terms ### @@ -949,6 +1013,35 @@ sub search { } } + # pkg_classnum + # all_pkg_classnums + # any_pkg_status + if ( $params->{'pkg_classnum'} ) { + my @pkg_classnums = ref( $params->{'pkg_classnum'} ) ? + @{ $params->{'pkg_classnum'} } : + $params->{'pkg_classnum'}; + @pkg_classnums = grep /^(\d+)$/, @pkg_classnums; + + if ( @pkg_classnums ) { + + my @pkg_where; + if ( $params->{'all_pkg_classnums'} ) { + push @pkg_where, "part_pkg.classnum = $_" foreach @pkg_classnums; + } else { + push @pkg_where, + 'part_pkg.classnum IN('. join(',', @pkg_classnums).')'; + } + foreach (@pkg_where) { + my $select_pkg = + "SELECT 1 FROM cust_pkg JOIN part_pkg USING (pkgpart) WHERE ". + "cust_pkg.custnum = cust_main.custnum AND $_ "; + if ( not $params->{'any_pkg_status'} ) { + $select_pkg .= 'AND '.FS::cust_pkg->active_sql; + } + push @where, "EXISTS($select_pkg)"; + } + } + } ## # setup queries, subs, etc. for the search @@ -970,10 +1063,15 @@ sub search { 'ON (cust_main.'.$pre.'locationnum = '.$pre.'location.locationnum) '; } + # always make referral available in results + # (maybe we should be using FS::UI::Web::join_cust_main instead?) + $addl_from .= ' LEFT JOIN (select refnum, referral from part_referral) AS part_referral_x ON (cust_main.refnum = part_referral_x.refnum) '; + my $count_query = "SELECT COUNT(*) FROM cust_main $addl_from $extra_sql"; my @select = ( 'cust_main.custnum', + 'cust_main.salesnum', # there's a good chance that we'll need these 'cust_main.bill_locationnum', 'cust_main.ship_locationnum', @@ -1030,6 +1128,20 @@ sub search { } + if ( $params->{'with_referrals'} ) { + + #XXX next: num for each customer status + + push @select, + '( SELECT COUNT(*) FROM cust_main AS referred_cust_main + WHERE cust_main.custnum = referred_cust_main.referral_custnum + ) AS num_referrals'; + + unshift @extra_headers, 'Referrals'; + unshift @extra_fields, 'num_referrals'; + + } + my $select = join(', ', @select); my $sql_query = { @@ -1043,7 +1155,6 @@ sub search { 'extra_headers' => \@extra_headers, 'extra_fields' => \@extra_fields, }; - #warn Data::Dumper::Dumper($sql_query); $sql_query; } @@ -1222,7 +1333,7 @@ sub append_fuzzyfiles_fuzzyfield { my ($field, $table) = reverse split('\.', $fuzzyfield); $table ||= 'cust_main'; - return unless length($value); + return unless defined($value) && length($value); open(CACHE, '>>:encoding(UTF-8)', "$dir/$table.$field" ) or die "can't open $dir/$table.$field: $!";