package FS::cust_main::Search;
use strict;
+use Carp qw( croak );
use base qw( Exporter );
use vars qw( @EXPORT_OK $DEBUG $me $conf @fuzzyfields );
use String::Approx qw(amatch);
#cust_main phone numbers and contact phone number
push @cust_main, qsearch( {
- 'table' => 'cust_main',
- 'hashref' => { %options },
+ 'select' => 'cust_main.*',
+ 'table' => 'cust_main',
+ 'addl_from' => ' left join cust_contact using (custnum) '.
+ ' left join contact_phone using (contactnum) ',
+ 'hashref' => { %options },
'extra_sql' => ( scalar(keys %options) ? ' AND ' : ' WHERE ' ).
' ( '.
join(' OR ', map "$_ = '$phonen'",
" OR phonenum = '$phonenum' ".
' ) '.
" AND $agentnums_sql", #agent virtualization
- 'addl_from' => ' left join cust_contact using (custnum) left join contact_phone using (contactnum) ',
} );
unless ( @cust_main || $phonen =~ /x\d+$/ ) { #no exact match
#try looking for matches with extensions unless one was specified
push @cust_main, qsearch( {
- 'table' => 'cust_main',
- 'hashref' => { %options },
+ 'table' => 'cust_main',
+ 'hashref' => { %options },
'extra_sql' => ( scalar(keys %options) ? ' AND ' : ' WHERE ' ).
' ( '.
join(' OR ', map "$_ LIKE '$phonen\%'",
if ( $search =~ /@/ ) { #email address from cust_main_invoice and contact_email
push @cust_main, qsearch( {
- 'table' => 'cust_main',
- 'hashref' => { %options },
+ 'select' => 'cust_main.*',
+ 'table' => 'cust_main',
+ 'addl_from' => ' left join cust_main_invoice using (custnum) '.
+ ' left join cust_contact using (custnum) '.
+ ' left join contact_email using (contactnum) ',
+ 'hashref' => { %options },
'extra_sql' => ( scalar(keys %options) ? ' AND ' : ' WHERE ' ).
' ( '.
join(' OR ', map "$_ = '$search'",
).
' ) '.
" AND $agentnums_sql", #agent virtualization
- 'addl_from' => ' left join cust_main_invoice using (custnum) left join cust_contact using (custnum) left join contact_email using (contactnum) ',
} );
# custnum search (also try agent_custid), with some tweaking options if your
# probably the Right Thing: return customers that have any associated
# locations matching the string, not just bill/ship location
push @cust_main, qsearch( {
+ 'select' => 'cust_main.*',
'table' => 'cust_main',
'addl_from' => ' JOIN cust_location USING (custnum) ',
'hashref' => { %options, },
#doesn't throw a wrench in the works)
push @cust_main, qsearch( {
- 'table' => 'cust_main',
- 'hashref' => { %options },
- 'extra_sql' =>
+ 'table' => 'cust_main',
+ 'hashref' => { %options },
+ 'extra_sql' =>
( keys(%options) ? ' AND ' : ' WHERE ' ).
join(' AND ',
" LOWER(first) = ". dbh->quote(lc($first)),
" LOWER(company) = ". dbh->quote(lc($company)),
$agentnums_sql,
),
- } ),
+ } );
#contacts?
# probably not necessary for the "something a browser remembered" case
#cust_main and contacts
push @cust_main, qsearch( {
+ 'select' => 'cust_main.*',
'table' => 'cust_main',
- 'select' => 'cust_main.*, cust_contact.*, contact.contactnum, contact.last as contact_last, contact.first as contact_first, contact.title',
+ 'addl_from' => ' left join cust_contact using (custnum) '.
+ ' left join contact using (contactnum) ',
'hashref' => { %options },
'extra_sql' => "$sql AND $agentnums_sql", #agent virtualization
- 'addl_from' => ' left join cust_contact on cust_main.custnum = cust_contact.custnum left join contact using (contactnum) ',
} );
# or it just be something that was typed in... (try that in a sec)
if $conf->exists('address1-search');
push @cust_main, qsearch( {
+ 'select' => 'cust_main.*',
'table' => 'cust_main',
- 'select' => 'cust_main.*, cust_contact.*, contact.contactnum, contact.last as contact_last, contact.first as contact_first, contact.title',
+ 'addl_from' => ' left join cust_contact using (custnum) '.
+ ' left join contact using (contactnum) ',
'hashref' => { %options },
'extra_sql' => "$sql AND $agentnums_sql", #agent virtualization
- 'addl_from' => 'left join cust_contact on cust_main.custnum = cust_contact.custnum left join contact using (contactnum) ',
} );
#no exact match, trying substring/fuzzy
if ( $conf->exists('address1-search') && length($value) >= $min_len ) {
push @cust_main, qsearch( {
+ select => 'cust_main.*',
table => 'cust_main',
addl_from => 'JOIN cust_location USING (custnum)',
extra_sql => 'WHERE '.
my $mask_search = FS::payinfo_Mixin->mask_payinfo('CARD', $card_search);
push @cust_main, qsearch({
+ 'select' => 'cust_main.*',
'table' => 'cust_main',
'addl_from' => ' JOIN cust_payby USING (custnum)',
'hashref' => {},
unless $params->{'cancelled_pkgs'};
##
- # "with email address(es)" checkbox
+ # "with email address(es)" checkbox,
+ # also optionally: with_email_dest and with_contact_type
##
- push @where,
- 'EXISTS ( SELECT 1 FROM contact_email
+ if ($params->{with_email}) {
+ my @email_dest;
+ my $email_dest_sql;
+ my $contact_type_sql;
+
+ if ($params->{with_email_dest}) {
+ croak unless ref $params->{with_email_dest} eq 'ARRAY';
+
+ @email_dest = @{$params->{with_email_dest}};
+ $email_dest_sql =
+ " AND ( ".
+ join(' OR ',map(" cust_contact.${_}_dest IS NOT NULL ", @email_dest)).
+ " ) ";
+ # Can't use message_dist = 'Y' because single quotes are escaped later
+ }
+ if ($params->{with_contact_type}) {
+ croak unless ref $params->{with_contact_type} eq 'ARRAY';
+
+ my @contact_type = grep {/^\d+$/ && $_ > 0} @{$params->{with_contact_type}};
+ my $has_null_type = 0;
+ $has_null_type = 1 if grep { $_ eq 0 } @{$params->{with_contact_type}};
+ my $hnt_sql;
+ if ($has_null_type) {
+ $hnt_sql = ' OR ' if @contact_type;
+ $hnt_sql .= ' cust_contact.classnum IS NULL ';
+ }
+
+ $contact_type_sql =
+ " AND ( ".
+ join(' OR ', map(" cust_contact.classnum = $_ ", @contact_type)).
+ $hnt_sql.
+ " ) ";
+ }
+ push @where,
+ "EXISTS ( SELECT 1 FROM contact_email
JOIN cust_contact USING (contactnum)
WHERE cust_contact.custnum = cust_main.custnum
- )'
- if $params->{'with_email'};
+ $email_dest_sql
+ $contact_type_sql
+ ) ";
+ }
##
# "with postal mail invoices" checkbox
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 = '.
$_ . ')';
}
}
}
+ ##
+ # contacts
+ ##
+ if (keys %{ $params->{'contacts'} }) {
+ my $contact_params = $params->{'contacts'};
+
+ if ($contact_params->{'contacts_firstname'} || $contact_params->{'contacts_lastname'}) {
+ my $first_query = " AND contact.first = '" . $contact_params->{'contacts_firstname'} . "'"
+ unless !$contact_params->{'contacts_firstname'};
+ my $last_query = " AND contact.last = '" . $contact_params->{'contacts_lastname'} . "'"
+ unless !$contact_params->{'contacts_lastname'};
+ push @where,
+ "EXISTS ( SELECT 1 FROM contact
+ JOIN cust_contact USING (contactnum)
+ WHERE cust_contact.custnum = cust_main.custnum
+ $first_query $last_query
+ ) ";
+ }
+
+ if ($contact_params->{'contacts_email'}) {
+ push @where,
+ "EXISTS ( SELECT 1 FROM contact_email
+ JOIN cust_contact USING (contactnum)
+ WHERE cust_contact.custnum = cust_main.custnum
+ AND contact_email.emailaddress = '" . $contact_params->{'contacts_email'} . "'
+ ) ";
+ }
+
+ if ($contact_params->{'contacts_homephone'} || $contact_params->{'contacts_workphone'} || $contact_params->{'contacts_mobilephone'}) {
+ foreach my $phone (qw( contacts_homephone contacts_workphone contacts_mobilephone )) {
+ (my $num = $contact_params->{$phone}) =~ s/\W//g;
+ if ( $num =~ /^1?(\d{3})(\d{3})(\d{4})(\d*)$/ ) { $contact_params->{$phone} = "$1$2$3"; }
+ }
+ my $home_query = " AND ( contact_phone.phonetypenum = '2' AND contact_phone.phonenum = '" . $contact_params->{'contacts_homephone'} . "' )"
+ unless !$contact_params->{'contacts_homephone'};
+ my $work_query = " AND ( contact_phone.phonetypenum = '1' AND contact_phone.phonenum = '" . $contact_params->{'contacts_workphone'} . "' )"
+ unless !$contact_params->{'contacts_workphone'};
+ my $mobile_query = " AND ( contact_phone.phonetypenum = '3' AND contact_phone.phonenum = '" . $contact_params->{'contacts_mobilephone'} . "' )"
+ unless !$contact_params->{'contacts_mobilephone'};
+ push @where,
+ "EXISTS ( SELECT 1 FROM contact_phone
+ JOIN cust_contact USING (contactnum)
+ WHERE cust_contact.custnum = cust_main.custnum
+ $home_query $work_query $mobile_query
+ ) ";
+ }
+}
+
+
##
# setup queries, subs, etc. for the search
##
- $orderby ||= 'ORDER BY custnum';
+ $orderby ||= 'ORDER BY cust_main.custnum';
# here is the agent virtualization
push @where,
# (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',
my @extra_fields = ();
my @extra_sort_fields = ();
- ## search contacts
- if ($params->{'contacts'}) {
- my $contact_params = $params->{'contacts'};
-
- $addl_from .=
- ' LEFT JOIN cust_contact ON ( cust_main.custnum = cust_contact.custnum ) ';
-
- if ($contact_params->{'contacts_firstname'} || $contact_params->{'contacts_lastname'}) {
- $addl_from .= ' LEFT JOIN contact ON ( cust_contact.contactnum = contact.contactnum ) ';
- my $first_query = " AND contact.first = '" . $contact_params->{'contacts_firstname'} . "'"
- unless !$contact_params->{'contacts_firstname'};
- my $last_query = " AND contact.last = '" . $contact_params->{'contacts_lastname'} . "'"
- unless !$contact_params->{'contacts_lastname'};
- $extra_sql .= " AND ( '1' $first_query $last_query )";
- }
-
- if ($contact_params->{'contacts_email'}) {
- $addl_from .= ' LEFT JOIN contact_email ON ( cust_contact.contactnum = contact_email.contactnum ) ';
- $extra_sql .= " AND ( contact_email.emailaddress = '" . $contact_params->{'contacts_email'} . "' )";
- }
-
- if ($contact_params->{'contacts_homephone'} || $contact_params->{'contacts_workphone'} || $contact_params->{'contacts_mobilephone'}) {
- $addl_from .= ' LEFT JOIN contact_phone ON ( cust_contact.contactnum = contact_phone.contactnum ) ';
- my $contacts_mobilephone;
- foreach my $phone (qw( contacts_homephone contacts_workphone contacts_mobilephone )) {
- (my $num = $contact_params->{$phone}) =~ s/\W//g;
- if ( $num =~ /^1?(\d{3})(\d{3})(\d{4})(\d*)$/ ) { $contact_params->{$phone} = "$1$2$3"; }
- }
- my $home_query = " AND ( contact_phone.phonetypenum = '2' AND contact_phone.phonenum = '" . $contact_params->{'contacts_homephone'} . "' )"
- unless !$contact_params->{'contacts_homephone'};
- my $work_query = " AND ( contact_phone.phonetypenum = '1' AND contact_phone.phonenum = '" . $contact_params->{'contacts_workphone'} . "' )"
- unless !$contact_params->{'contacts_workphone'};
- my $mobile_query = " AND ( contact_phone.phonetypenum = '3' AND contact_phone.phonenum = '" . $contact_params->{'contacts_mobilephone'} . "' )"
- unless !$contact_params->{'contacts_mobilephone'};
- $extra_sql .= " AND ( '1' $home_query $work_query $mobile_query )";
- }
-
- }
+ my $count_query = "SELECT COUNT(DISTINCT cust_main.custnum) FROM cust_main $addl_from $extra_sql";
if ($params->{'flattened_pkgs'}) {
=cut
1;
-