[freeside-commits] branch FREESIDE_3_BRANCH updated. 41a4c4b426f82359f91679b3051d689c93314ea4

Christopher Burger burgerc at 420.am
Fri Sep 8 10:24:12 PDT 2017


The branch, FREESIDE_3_BRANCH has been updated
       via  41a4c4b426f82359f91679b3051d689c93314ea4 (commit)
       via  321a2e69b5ab89ebf3e2d6b711b2a21126b28ff8 (commit)
      from  d2d82863f354790d1eb3ee1d3b193d2e423ae8d0 (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 41a4c4b426f82359f91679b3051d689c93314ea4
Author: Christopher Burger <burgerc at freeside.biz>
Date:   Fri Sep 8 13:23:26 2017 -0400

    removed change to Mason.pm as not needed.

diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm
index f50192c..60e3779 100644
--- a/FS/FS/Mason.pm
+++ b/FS/FS/Mason.pm
@@ -266,7 +266,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 321a2e69b5ab89ebf3e2d6b711b2a21126b28ff8
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
    
    Conflicts:
    	httemplate/elements/menu.html

diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm
index 60e3779..f50192c 100644
--- a/FS/FS/Mason.pm
+++ b/FS/FS/Mason.pm
@@ -266,6 +266,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..599132b
--- /dev/null
+++ b/FS/FS/contact_import.pm
@@ -0,0 +1,164 @@
+package FS::contact_import;
+
+use strict;
+use vars qw( $DEBUG ); #$conf );
+use Storable qw(thaw);
+use Data::Dumper;
+use MIME::Base64;
+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;
+  my $param = thaw(decode_base64(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 c3f3dbf..045bbdf 100644
--- a/httemplate/elements/menu.html
+++ b/httemplate/elements/menu.html
@@ -488,6 +488,8 @@ tie my %tools_importing, 'Tie::IxHash',
   'Package definitions'  => [ $fsurl.'misc/part_pkg-import.html', '' ],
   'Customer packages'    => [ $fsurl.'misc/cust_pkg-import.html', '' ],
   'Customer comments'    => [ $fsurl.'misc/cust_main_note-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                            |  164 ++++++++++++++++++++
 httemplate/elements/menu.html                      |    2 +
 httemplate/misc/contact-import.cgi                 |  102 ++++++++++++
 .../{part_pkg-import.html => contact-import.cgi}   |    2 +-
 5 files changed, 430 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