L<FS::cust_main::Import> - Batch customer importing
+L<FS::contact::Import> - Batch contact importing
+
=head2 Database record classes
L<FS::Record> - Database record base class
use FS::Cursor;
use FS::contact_phone;
use FS::contact_email;
+use FS::contact::Import;
use FS::queue;
use FS::phone_type; #for cgi_contact_fields
use FS::cust_contact;
+++ /dev/null
-package FS::contact_import;
-
-use strict;
-use vars qw( $DEBUG ); #$conf );
-use Data::Dumper;
-use FS::Misc::DateTime qw( parse_datetime );
-use FS::Record qw( qsearchs );
-use FS::contact;
-use FS::cust_main;
-
-$DEBUG = 0;
-
-=head1 NAME
-
-FS::contact_import - Batch contact importing
-
-=head1 SYNOPSIS
-
- use FS::contact_import;
-
- #import
- FS::contact_import::batch_import( {
- file => $file, #filename
- type => $type, #csv or xls
- format => $format, #default
- agentnum => $agentnum,
- job => $job, #optional job queue job, for progressbar updates
- pkgbatch => $pkgbatch, #optional batch unique identifier
- } );
- die $error if $error;
-
- #ajax helper
- use FS::UI::Web::JSRPC;
- my $server =
- new FS::UI::Web::JSRPC 'FS::contact_import::process_batch_import', $cgi;
- print $server->process;
-
-=head1 DESCRIPTION
-
-Batch contact importing.
-
-=head1 SUBROUTINES
-
-=item process_batch_import
-
-Load a batch import as a queued JSRPC job
-
-=cut
-
-sub process_batch_import {
- my $job = shift;
- my $param = shift;
- warn Dumper($param) if $DEBUG;
-
- my $files = $param->{'uploaded_files'}
- or die "No files provided.\n";
-
- my (%files) = map { /^(\w+):([\.\w]+)$/ ? ($1,$2):() } split /,/, $files;
-
- my $dir = '%%%FREESIDE_CACHE%%%/cache.'. $FS::UID::datasrc. '/';
-
- my $file = $dir. $files{'file'};
-
- my $type;
- if ( $file =~ /\.(\w+)$/i ) {
- $type = lc($1);
- } else {
- #or error out???
- warn "can't parse file type from filename $file; defaulting to CSV";
- $type = 'csv';
- }
-
- my $error =
- FS::contact_import::batch_import( {
- job => $job,
- file => $file,
- type => $type,
- agentnum => $param->{'agentnum'},
- 'format' => $param->{'format'},
- } );
-
- unlink $file;
-
- die "$error\n" if $error;
-
-}
-
-=item batch_import
-
-=cut
-
-my %formatfields = (
- 'default' => [ qw( custnum last first title comment selfservice_access emailaddress phonetypenum1 phonetypenum3 phonetypenum2 ) ],
-);
-
-sub _formatfields {
- \%formatfields;
-}
-
-## not tested but maybe allow 2nd format to attach location in the future
-my %import_options = (
- 'table' => 'contact',
-
- 'preinsert_callback' => sub {
- my($record, $param) = @_;
- my @location_params = grep /^location\./, keys %$param;
- if (@location_params) {
- my $cust_location = FS::cust_location->new({
- 'custnum' => $record->custnum,
- });
- foreach my $p (@location_params) {
- $p =~ /^location.(\w+)$/;
- $cust_location->set($1, $param->{$p});
- }
-
- my $error = $cust_location->find_or_insert; # this avoids duplicates
- return "error creating location: $error" if $error;
- $record->set('locationnum', $cust_location->locationnum);
- }
- '';
- },
-
-);
-
-sub _import_options {
- \%import_options;
-}
-
-sub batch_import {
- my $opt = shift;
-
- my $iopt = _import_options;
- $opt->{$_} = $iopt->{$_} foreach keys %$iopt;
-
- my $format = delete $opt->{'format'};
-
- my $formatfields = _formatfields();
- die "unknown format $format" unless $formatfields->{$format};
-
- my @fields;
- foreach my $field ( @{ $formatfields->{$format} } ) {
- push @fields, $field;
- }
-
- $opt->{'fields'} = \@fields;
-
- FS::Record::batch_import( $opt );
-
-}
-
-=head1 BUGS
-
-Not enough documentation.
-
-=head1 SEE ALSO
-
-L<FS::contact>
-
-=cut
-
-1;
\ No newline at end of file
my $phonenum = "$1$2$3";
#my $extension = $4;
- #cust_main phone numbers
+ #cust_main phone numbers and contact phone number
push @cust_main, qsearch( {
'table' => 'cust_main',
'hashref' => { %options },
join(' OR ', map "$_ = '$phonen'",
qw( daytime night mobile fax )
).
+ " OR phonenum = '$phonenum' ".
' ) '.
" AND $agentnums_sql", #agent virtualization
+ 'addl_from' => ' left join cust_contact using (custnum) left join contact_phone using (contactnum) ',
} );
- #contact phone numbers
- push @cust_main,
- grep $agentnums_href->{$_->agentnum}, #agent virt
- grep $_, #skip contacts that don't have cust_main records
- map $_->contact->cust_main,
- qsearch({
- 'table' => 'contact_phone',
- 'hashref' => { 'phonenum' => $phonenum },
- });
-
unless ( @cust_main || $phonen =~ /x\d+$/ ) { #no exact match
#try looking for matches with extensions unless one was specified
}
- if ( $search =~ /@/ ) { #email address
-
- # invoicing email address
- push @cust_main,
- grep $agentnums_href->{$_->agentnum}, #agent virt
- map $_->cust_main,
- qsearch( {
- 'table' => 'cust_main_invoice',
- 'hashref' => { 'dest' => $search },
- }
- );
-
- # contact email address
- push @cust_main,
- grep $agentnums_href->{$_->agentnum}, #agent virt
- grep $_, #skip contacts that don't have cust_main records
- map $_->contact->cust_main,
- qsearch( {
- 'table' => 'contact_email',
- 'hashref' => { 'emailaddress' => $search },
- }
- );
+ if ( $search =~ /@/ ) { #email address from cust_main_invoice and contact_email
+
+ push @cust_main, qsearch( {
+ 'table' => 'cust_main',
+ 'hashref' => { %options },
+ 'extra_sql' => ( scalar(keys %options) ? ' AND ' : ' WHERE ' ).
+ ' ( '.
+ join(' OR ', map "$_ = '$search'",
+ qw( dest emailaddress )
+ ).
+ ' ) '.
+ " 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
# legacy cust "numbers" have letters
} elsif ( ! $NameParse->parse($value) ) {
my %name = $NameParse->components;
- $first = $name{'given_name_1'} || $name{'initials_1'}; #wtf NameParse, Ed?
- $last = $name{'surname_1'};
+ $first = lc($name{'given_name_1'}) || $name{'initials_1'}; #wtf NameParse, Ed?
+ $last = lc($name{'surname_1'});
}
#exact
my $sql = scalar(keys %options) ? ' AND ' : ' WHERE ';
- $sql .= "( LOWER(cust_main.last) = $q_last AND LOWER(cust_main.first) = $q_first )";
+ $sql .= "( (LOWER(cust_main.last) = $q_last AND LOWER(cust_main.first) = $q_first)
+ OR (LOWER(contact.last) = $q_last AND LOWER(contact.first) = $q_first) )";
- #cust_main
+ #cust_main and contacts
push @cust_main, qsearch( {
'table' => 'cust_main',
- 'hashref' => \%options,
+ 'select' => 'cust_main.*, cust_contact.*, contact.contactnum, contact.last as contact_last, contact.first as contact_first, contact.title',
+ '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) ',
} );
- #contacts
- push @cust_main,
- grep $agentnums_href->{$_->agentnum}, #agent virt
- grep $_, #skip contacts that don't have cust_main records
- map $_->cust_main,
- qsearch( {
- 'table' => 'contact',
- 'hashref' => { 'first' => $first,
- 'last' => $last,
- },
- }
- );
-
# or it just be something that was typed in... (try that in a sec)
}
OR LOWER(cust_main.last) = $q_value
OR LOWER(cust_main.company) = $q_value
OR LOWER(cust_main.ship_company) = $q_value
- ";
+ OR LOWER(contact.first) = $q_value
+ OR LOWER(contact.last) = $q_value
+ )";
#address1 (yes, it's a kludge)
$sql .= " OR EXISTS (
)"
if $conf->exists('address1-search');
- #contacts (look, another kludge)
- $sql .= " OR EXISTS ( SELECT 1 FROM contact
- WHERE ( LOWER(contact.first) = $q_value
- OR LOWER(contact.last) = $q_value
- )
- AND contact.custnum IS NOT NULL
- AND contact.custnum = cust_main.custnum
- )
- ) ";
-
push @cust_main, qsearch( {
'table' => 'cust_main',
- 'hashref' => \%options,
+ 'select' => 'cust_main.*, cust_contact.*, contact.contactnum, contact.last as contact_last, contact.first as contact_first, contact.title',
+ '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
FS/category_Common.pm
t/category_Common.t
FS/contact.pm
+FS/contact/Import.pm
t/contact.t
FS/contact_phone.pm
t/contact_phone.t
" blib/lib/FS/part_export/*.pm;\
perl -p -i -e "\
s|%%%FREESIDE_CACHE%%%|${FREESIDE_CACHE}|g;\
- " blib/lib/FS/cust_main/*.pm blib/lib/FS/cust_pkg/*.pm;\
+ " blib/lib/FS/cust_main/*.pm blib/lib/FS/cust_pkg/*.pm blib/lib/FS/contact/*.pm;\
perl -p -i -e "\
s|%%%FREESIDE_LOG%%%|${FREESIDE_LOG}|g;\
" blib/lib/FS/Daemon/*.pm;\
my $menu_position = $curuser->option('menu_position') || 'top';
my $cust_width = 246;
-my $cust_label = '(cust #, name, company';
+my $cust_label = '(cust #, name, company, email';
if ( $conf->exists('address1-search') ) {
$cust_label .= ', address';
$cust_width += 56;
unless $FS::CurrentUser::CurrentUser->access_right('Import');
my $server =
- new FS::UI::Web::JSRPC 'FS::contact_import::process_batch_import', $cgi;
+ new FS::UI::Web::JSRPC 'FS::contact::Import::process_batch_import', $cgi;
</%init>
join(', ', map $_->emailaddress, @contact_email);
};
+my $work_phone_sub = sub {
+ my $contact = shift;
+ #can't because contactnum is in the wrong field
+ my @contact_workphone = qsearch('contact_phone', { 'contactnum' => $contact->contact_contactnum, 'phonetypenum' => '1' } );
+ join(', ', map $_->phonenum, @contact_workphone);
+};
+
+my $mobile_phone_sub = sub {
+ my $contact = shift;
+ #can't because contactnum is in the wrong field
+ my @contact_mobilephone = qsearch('contact_phone', { 'contactnum' => $contact->contact_contactnum, 'phonetypenum' => '3' } );
+ join(', ', map $_->phonenum, @contact_mobilephone);
+};
+
+my $home_phone_sub = sub {
+ my $contact = shift;
+ #can't because contactnum is in the wrong field
+ my @contact_homephone = qsearch('contact_phone', { 'contactnum' => $contact->contact_contactnum, 'phonetypenum' => '2' } );
+ join(', ', map $_->phonenum, @contact_homephone);
+};
+
my $link; #for closure in this sub, we'll define it later
my $contact_classname_sub = sub {
my $contact = shift;
$X_contact->contact_classname;
};
-my @header = ( 'First', 'Last', 'Title', 'Email', 'Type' );
-my @fields = ( 'first', 'last', 'title', $email_sub, $contact_classname_sub );
-my @links = ( '', '', '', '', '', );
+my @header = ( 'First', 'Last', 'Title', 'Email', 'Work Phone', 'Mobile Phone', 'Home Phone', 'Type' );
+my @fields = ( 'first', 'last', 'title', $email_sub, $work_phone_sub, $mobile_phone_sub, $home_phone_sub, $contact_classname_sub );
+my @links = ( '', '', '', '', '', '', '', '', );
my $company_link = '';