[freeside-commits] branch FREESIDE_4_BRANCH updated. e73224079b32495eef5318c2e4c99057dbfe272b

Christopher Burger burgerc at 420.am
Fri Sep 8 08:19:13 PDT 2017


The branch, FREESIDE_4_BRANCH has been updated
       via  e73224079b32495eef5318c2e4c99057dbfe272b (commit)
       via  f16d9ebb0e56f43e04242ed859d6055f98c74f15 (commit)
      from  0505597728b8a0b9b0f3b97c2e3c0607b869f92f (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit e73224079b32495eef5318c2e4c99057dbfe272b
Author: Christopher Burger <burgerc at freeside.biz>
Date:   Fri Sep 8 10:59:57 2017 -0400

    RT# 77167 - removed change as not needed.

diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm
index 8862cf8..4aeebbe 100644
--- a/FS/FS/Mason.pm
+++ b/FS/FS/Mason.pm
@@ -262,7 +262,6 @@ if ( -e $addl_handler_use_file ) {
   use FS::cust_category;
   use FS::prospect_main;
   use FS::contact;
-  use FS::contact::Import;
   use FS::phone_type;
   use FS::svc_pbx;
   use FS::discount;

commit f16d9ebb0e56f43e04242ed859d6055f98c74f15
Author: Christopher Burger <burgerc at freeside.biz>
Date:   Thu Sep 7 08:49:34 2017 -0400

    RT# 77167 - Added the ability to import a list of contacts

diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm
index 4aeebbe..8862cf8 100644
--- a/FS/FS/Mason.pm
+++ b/FS/FS/Mason.pm
@@ -262,6 +262,7 @@ if ( -e $addl_handler_use_file ) {
   use FS::cust_category;
   use FS::prospect_main;
   use FS::contact;
+  use FS::contact::Import;
   use FS::phone_type;
   use FS::svc_pbx;
   use FS::discount;
diff --git a/FS/FS/contact/Import.pm b/FS/FS/contact/Import.pm
new file mode 100644
index 0000000..26bdcfa
--- /dev/null
+++ b/FS/FS/contact/Import.pm
@@ -0,0 +1,161 @@
+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 $dir = '/usr/local/etc/freeside/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
diff --git a/FS/FS/contact_import.pm b/FS/FS/contact_import.pm
new file mode 100644
index 0000000..d6cd690
--- /dev/null
+++ b/FS/FS/contact_import.pm
@@ -0,0 +1,161 @@
+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
diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html
index 25a6967..9a3f7a4 100644
--- a/httemplate/elements/menu.html
+++ b/httemplate/elements/menu.html
@@ -510,6 +510,7 @@ tie my %tools_importing, 'Tie::IxHash',
   'Package definitions'  => [ $fsurl.'misc/part_pkg-import.html', '' ],
   'Customer packages'    => [ $fsurl.'misc/cust_pkg-import.html', '' ],
   'Customer notes'       => [ $fsurl.'misc/cust_main_note-import.html', '' ],
+  'Customer Contacts'    => [ $fsurl.'misc/contact-import.cgi', '' ],
   'One-time charges'     => [ $fsurl.'misc/cust_main-import_charges.cgi', '' ],
   'Payments'             => [ $fsurl.'misc/cust_pay-import.cgi', '' ],
   'Credits'              => [ $fsurl.'misc/cust_credit-import.html', '' ],
diff --git a/httemplate/misc/contact-import.cgi b/httemplate/misc/contact-import.cgi
new file mode 100644
index 0000000..ae2e349
--- /dev/null
+++ b/httemplate/misc/contact-import.cgi
@@ -0,0 +1,102 @@
+<% include("/elements/header.html",'Batch Contacts Import') %>
+
+Import a file containing customer contact records.
+<BR><BR>
+
+<& /elements/form-file_upload.html,
+     'name'      => 'ContactImportForm',
+     'action'    => 'process/contact-import.cgi',
+     'num_files' => 1,
+     'fields'    => [ 'custbatch', 'format' ],
+     'message'   => 'Customer contacts import successful',
+     'onsubmit'  => "document.ContactImportForm.submitButton.disabled=true;",
+&>
+
+<% &ntable("#cccccc", 2) %>
+
+  <INPUT TYPE="hidden" NAME="custbatch" VALUE="<% $custbatch %>"%>
+
+  <TR>
+    <TH ALIGN="right">Format</TH>
+    <TD>
+      <SELECT NAME="format">
+        <OPTION VALUE="default" SELECTED>Default
+      </SELECT>
+    </TD>
+  </TR>
+
+  <% include( '/elements/file-upload.html',
+                'field' => 'file',
+                'label' => 'Filename',
+            )
+  %>
+
+  <TR>
+    <TD COLSPAN=2 ALIGN="center" STYLE="padding-top:6px">
+      <INPUT TYPE    = "submit"
+             NAME    = "submitButton"
+             ID      = "submitButton"
+             VALUE   = "Import file"
+      >
+    </TD>
+  </TR>
+
+</TABLE>
+
+</FORM>
+
+<BR>
+
+Uploaded files can be CSV (comma-separated value) files or Excel spreadsheets.  The file should have a .CSV or .XLS extension.
+<BR><BR>
+
+Default Format has the following field order:
+<BR>
+<i>custnum<%$req%>, last<%$req%>, first<%$req%>, title<%$req%>, comment, selfservice_access, emailaddress, workphone, mobilephone, homephone</i>
+<BR><BR>
+
+Field information:
+<BR>
+You must include a customer number and either a last name, first name or title.
+
+<ul>
+
+  <li><i>custnum</i>: This is the customer number of the customer the contact is attached to.</li>
+
+  <li><i>last</i>: Last name for contact.</li>
+
+  <li><i>first</i>: First name for contact.</li>
+
+  <li><i>title</i>: Optional title for contact.</li>
+
+  <li><i>comment</i>: Optional comment for contact.</li>
+
+  <li><i>selfservice_access</i>: Empty for no self service access or Y if granting self service access.</li>
+
+  <li><i>emailaddress</i>: Email address for contact.</li>
+
+  <li><i>workphone</i>: Work phone number for contact. Format xxxxxxxxxx</li>
+
+  <li><i>mobilephone</i>: Mobile phone number for contact. Format xxxxxxxxxx</li>
+
+  <li><i>homephone</i>: Home phone number for contact. Format xxxxxxxxxx</li>
+
+</ul>
+
+<BR>
+
+<% include('/elements/footer.html') %>
+
+<%once>
+
+my $req = qq!<font color="#ff0000">*</font>!;
+
+</%once>
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Import');
+
+my $custbatch = time2str('webimport-%Y/%m/%d-%T'. "-$$-". rand() * 2**32, time);
+
+</%init>
\ No newline at end of file
diff --git a/httemplate/misc/process/contact-import.cgi b/httemplate/misc/process/contact-import.cgi
new file mode 100644
index 0000000..cbdcad4
--- /dev/null
+++ b/httemplate/misc/process/contact-import.cgi
@@ -0,0 +1,10 @@
+<% $server->process %>
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Import');
+
+my $server =
+  new FS::UI::Web::JSRPC 'FS::contact_import::process_batch_import', $cgi;
+
+</%init>

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/contact/Import.pm                            |  161 ++++++++++++++++++++
 FS/FS/contact_import.pm                            |  161 ++++++++++++++++++++
 httemplate/elements/menu.html                      |    1 +
 httemplate/misc/contact-import.cgi                 |  102 +++++++++++++
 .../{part_pkg-import.html => contact-import.cgi}   |    2 +-
 5 files changed, 426 insertions(+), 1 deletion(-)
 create mode 100644 FS/FS/contact/Import.pm
 create mode 100644 FS/FS/contact_import.pm
 create mode 100644 httemplate/misc/contact-import.cgi
 copy httemplate/misc/process/{part_pkg-import.html => contact-import.cgi} (64%)




More information about the freeside-commits mailing list