Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / FS / FS / contact / Import.pm
1 package FS::contact::Import;
2
3 use strict;
4 use vars qw( $DEBUG ); #$conf );
5 use Data::Dumper;
6 use FS::Misc::DateTime qw( parse_datetime );
7 use FS::Record qw( qsearchs );
8 use FS::contact;
9 use FS::cust_main;
10
11 $DEBUG = 0;
12
13 =head1 NAME
14
15 FS::contact::Import - Batch contact importing
16
17 =head1 SYNOPSIS
18
19   use FS::contact::Import;
20
21   #import
22   FS::contact::Import::batch_import( {
23     file      => $file,      #filename
24     type      => $type,      #csv or xls
25     format    => $format,    #default
26     agentnum  => $agentnum,
27     job       => $job,       #optional job queue job, for progressbar updates
28     pkgbatch  => $pkgbatch,  #optional batch unique identifier
29   } );
30   die $error if $error;
31
32   #ajax helper
33   use FS::UI::Web::JSRPC;
34   my $server =
35     new FS::UI::Web::JSRPC 'FS::contact::Import::process_batch_import', $cgi;
36   print $server->process;
37
38 =head1 DESCRIPTION
39
40 Batch contact importing.
41
42 =head1 SUBROUTINES
43
44 =item process_batch_import
45
46 Load a batch import as a queued JSRPC job
47
48 =cut
49
50 sub process_batch_import {
51   my $job = shift;
52   my $param = shift;
53   warn Dumper($param) if $DEBUG;
54   
55   my $files = $param->{'uploaded_files'}
56     or die "No files provided.\n";
57
58   my (%files) = map { /^(\w+):([\.\w]+)$/ ? ($1,$2):() } split /,/, $files;
59
60   my $dir = '%%%FREESIDE_CACHE%%%/cache.'. $FS::UID::datasrc. '/';
61   #my $dir = '/usr/local/etc/freeside/cache.'. $FS::UID::datasrc. '/';
62   my $file = $dir. $files{'file'};
63
64   my $type;
65   if ( $file =~ /\.(\w+)$/i ) {
66     $type = lc($1);
67   } else {
68     #or error out???
69     warn "can't parse file type from filename $file; defaulting to CSV";
70     $type = 'csv';
71   }
72
73   my $error =
74     FS::contact::Import::batch_import( {
75       job      => $job,
76       file     => $file,
77       type     => $type,
78       agentnum => $param->{'agentnum'},
79       'format' => $param->{'format'},
80     } );
81
82   unlink $file;
83
84   die "$error\n" if $error;
85
86 }
87
88 =item batch_import
89
90 =cut
91
92 my %formatfields = (
93   'default'      => [ qw( custnum last first title comment selfservice_access emailaddress phonetypenum1 phonetypenum3 phonetypenum2 ) ],
94 );
95
96 sub _formatfields {
97   \%formatfields;
98 }
99
100 ## not tested but maybe allow 2nd format to attach location in the future
101 my %import_options = (
102   'table'         => 'contact',
103
104   'preinsert_callback'  => sub {
105     my($record, $param) = @_;
106     my @location_params = grep /^location\./, keys %$param;
107     if (@location_params) {
108       my $cust_location = FS::cust_location->new({
109           'custnum' => $record->custnum,
110       });
111       foreach my $p (@location_params) {
112         $p =~ /^location.(\w+)$/;
113         $cust_location->set($1, $param->{$p});
114       }
115
116       my $error = $cust_location->find_or_insert; # this avoids duplicates
117       return "error creating location: $error" if $error;
118       $record->set('locationnum', $cust_location->locationnum);
119     }
120     '';
121   },
122
123 );
124
125 sub _import_options {
126   \%import_options;
127 }
128
129 sub batch_import {
130   my $opt = shift;
131
132   my $iopt = _import_options;
133   $opt->{$_} = $iopt->{$_} foreach keys %$iopt;
134
135   my $format = delete $opt->{'format'};
136
137   my $formatfields = _formatfields();
138     die "unknown format $format" unless $formatfields->{$format};
139
140   my @fields;
141   foreach my $field ( @{ $formatfields->{$format} } ) {
142     push @fields, $field;
143   }
144
145   $opt->{'fields'} = \@fields;
146
147   FS::Record::batch_import( $opt );
148
149 }
150
151 =head1 BUGS
152
153 Not enough documentation.
154
155 =head1 SEE ALSO
156
157 L<FS::contact>
158
159 =cut
160
161 1;