From: Mark Wells Date: Fri, 13 May 2016 21:31:18 +0000 (-0700) Subject: Merge branch 'master' of git.freeside.biz:/home/git/freeside X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=07f96113f8da936c6255245c42f941ae8a3bb16f;hp=e614e538496f9069fca2fff6da6b248db9750792 Merge branch 'master' of git.freeside.biz:/home/git/freeside --- diff --git a/FS/FS/ConfDefaults.pm b/FS/FS/ConfDefaults.pm index b24a300f9..4c37175c3 100644 --- a/FS/FS/ConfDefaults.pm +++ b/FS/FS/ConfDefaults.pm @@ -77,6 +77,9 @@ sub cust_fields_avail { ( 'Cust# | Cust. Status | Name | Company | (bill) Address 1 | (bill) Address 2 | (bill) City | (bill) State | (bill) Zip | (bill) Country | (bill) Latitude | (bill) Longitude | Day phone | Night phone | Mobile phone | Fax number | (service) Address 1 | (service) Address 2 | (service) City | (service) State | (service) Zip | (service) Country | (service) Latitude | (service) Longitude | Invoicing email(s) | Payment Type | Current Balance' => 'custnum | Status | Last, First | Company | (address+coord) | (all phones) | (service address+coord) | Invoicing email(s) | Payment Type | Current Balance', + 'Cust# | Cust. Status | Name | Company | (bill) Address 1 | (bill) Address 2 | (bill) City | (bill) State | (bill) Zip | (bill) Country | (bill) Latitude | (bill) Longitude | Day phone | Night phone | Mobile phone | Fax number | (service) Address 1 | (service) Address 2 | (service) City | (service) State | (service) Zip | (service) Country | (service) Latitude | (service) Longitude | Invoicing email(s) | Payment Type | Current Balance | Advertising Source' => + 'custnum | Status | Last, First | Company | (address+coord) | (all phones) | (service address+coord) | Invoicing email(s) | Payment Type | Current Balance | Advertising Source', + 'Invoicing email(s)' => 'Invoicing email(s)', 'Cust# | Invoicing email(s)' => 'custnum | Invoicing email(s)', diff --git a/FS/FS/UI/Web.pm b/FS/FS/UI/Web.pm index 8f10011e5..e07e682ba 100644 --- a/FS/FS/UI/Web.pm +++ b/FS/FS/UI/Web.pm @@ -346,6 +346,7 @@ sub cust_header { 'Payment Type' => 'cust_payby', 'Current Balance' => 'current_balance', 'Agent Cust#' => 'agent_custid', + 'Advertising Source' => 'referral', ); $header2method{'Cust#'} = 'display_custnum' if $conf->exists('cust_main-default_agent_custid'); @@ -455,6 +456,9 @@ sub cust_sql_fields { push @extra_fields, FS::cust_main->balance_sql . " AS current_balance"; } + push @extra_fields, 'part_referral_x.referral AS referral' + if grep { $_ eq 'referral' } @cust_fields; + map("cust_main.$_", @fields), @location_fields, @extra_fields; } @@ -519,6 +523,10 @@ sub join_cust_main { " ON (ship_location.locationnum = $location_table.$locationnum) "; } + if ( !@cust_fields or grep { $_ eq 'referral' } @cust_fields ) { + $sql .= ' LEFT JOIN (select refnum, referral from part_referral) AS part_referral_x ON (cust_main.refnum = part_referral_x.refnum) '; + } + $sql; } diff --git a/FS/FS/cdr/conexiant.pm b/FS/FS/cdr/conexiant.pm new file mode 100644 index 000000000..852c2f60f --- /dev/null +++ b/FS/FS/cdr/conexiant.pm @@ -0,0 +1,43 @@ +package FS::cdr::conexiant; +use base qw( FS::cdr ); + +use strict; +use vars qw( %info ); +use FS::Record qw( qsearchs ); +use FS::cdr qw( _cdr_date_parser_maker _cdr_min_parser_maker ); + +%info = ( + 'name' => 'Conexiant', + 'weight' => 600, + 'header' => 1, + 'type' => 'csv', + 'import_fields' => [ + skip(3), #LookupError,Direction,LegType + sub { #CallId + my($cdr,$value,$conf,$param) = @_; + if (qsearchs('cdr',{'uniqueid' => $value})) { + $param->{'skiprow'} = 1; + $param->{'empty_ok'} = 1; + } else { + $cdr->uniqueid($value); + } + }, + 'upstream_rateplanid', #ClientRateSheetId + skip(1), #ClientRouteId + 'src', #SourceNumber + skip(1), #RawNumber + 'dst', #DestNumber + skip(1), #DestLRN + _cdr_date_parser_maker('startdate'), #CreatedOn + _cdr_date_parser_maker('answerdate'), #AnsweredOn + _cdr_date_parser_maker('enddate'), #HangupOn + skip(4), #CallCause,SipCode,Price,USFCharge + 'upstream_price', #TotalPrice + _cdr_min_parser_maker('billsec'), #PriceDurationMins + skip(2), #SipEndpointId, SipEndpointName + ], +); + +sub skip { map {''} (1..$_[0]) } + +1; diff --git a/FS/FS/cust_main/Search.pm b/FS/FS/cust_main/Search.pm index cc23f50e0..11a106a68 100644 --- a/FS/FS/cust_main/Search.pm +++ b/FS/FS/cust_main/Search.pm @@ -620,10 +620,6 @@ listref (list returned by FS::UI::Web::parse_lt_gt($cgi, 'current_balance')) bool -=item select_referral - -bool, join to part_referral and select part_referral.referral - =back =cut @@ -1017,6 +1013,10 @@ sub search { 'ON (cust_main.'.$pre.'locationnum = '.$pre.'location.locationnum) '; } + # always make referral available in results + # (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 = ( @@ -1031,13 +1031,6 @@ sub search { my(@extra_headers) = (); my(@extra_fields) = (); - if ($params->{'select_referral'}) { - $addl_from .= ' LEFT JOIN part_referral ON ( cust_main.refnum = part_referral.refnum ) '; - push @select, 'part_referral.referral'; - push @extra_headers, 'Advertising Source'; - push @extra_fields, 'referral'; - } - if ($params->{'flattened_pkgs'}) { #my $pkg_join = ''; diff --git a/FS/FS/cust_payby.pm b/FS/FS/cust_payby.pm index 50d9ee0f8..fd75567e6 100644 --- a/FS/FS/cust_payby.pm +++ b/FS/FS/cust_payby.pm @@ -196,10 +196,6 @@ sub replace { ? shift : $self->replace_old; - if ( length($old->paycvv) && $self->paycvv =~ /^\s*[\*x]*\s*$/ ) { - $self->paycvv($old->paycvv); - } - if ( $self->payby =~ /^(CARD|DCRD)$/ && ( $self->payinfo =~ /xx/ || $self->payinfo =~ /^\s*N\/A\s+\(tokenized\)\s*$/ @@ -221,6 +217,17 @@ sub replace { $self->payinfo($new_account.'@'.$new_aba); } + # don't preserve paycvv if it was passed blank and payinfo changed + unless ( $self->payby =~ /^(CARD|DCRD)$/ + && $old->payinfo ne $self->payinfo + && $old->paymask ne $self->paymask + && $self->paycvv =~ /^\s*$/ ) + { + if ( length($old->paycvv) && $self->paycvv =~ /^\s*[\*x]*\s*$/ ) { + $self->paycvv($old->paycvv); + } + } + local($ignore_expired_card) = 1 if $old->payby =~ /^(CARD|DCRD)$/ && $self->payby =~ /^(CARD|DCRD)$/ @@ -831,6 +838,9 @@ sub search_sql { ' LEFT JOIN cust_location AS '.$pre.'location '. 'ON (cust_main.'.$pre.'locationnum = '.$pre.'location.locationnum) '; } + # always make referral available in results + # (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_payby $addl_from $extra_sql"; diff --git a/FS/bin/freeside-cdr-conexiant-import b/FS/bin/freeside-cdr-conexiant-import new file mode 100755 index 000000000..a79477c51 --- /dev/null +++ b/FS/bin/freeside-cdr-conexiant-import @@ -0,0 +1,127 @@ +#!/usr/bin/perl + +use strict; + +use Cpanel::JSON::XS; +use Getopt::Long; +use LWP::UserAgent; +use MIME::Base64; +use Net::HTTPS::Any qw(https_post https_get); + +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearchs); +use FS::cdr; +use FS::cdr_batch; + +sub usage { +"Usage: +freeside-cdr-conexiant-import -h -u username -p apikey [-v] freesideuser + +Downloads any existing CDR files with the BilledCallsOnly flag and +imports records that have not been imported yet. Silently skips +records that have already been imported. +"; +} + +# should really be using a module for this +`which unzip` or die "can't find unzip executable"; + +my ($username,$password,$verbose); +GetOptions( + "password=s" => \$password, + "username=s" => \$username, + "verbose" => \$verbose, +); + +my $fsuser = $ARGV[-1]; + +die usage() unless $fsuser; + +adminsuidsetup($fsuser); + +my ( $page, $response, %reply_headers ) = https_post( + 'host' => 'api.conexiant.net', + 'port' => '443', + 'path' => '/v1/Cdrs/SearchCdrsDownloads', + 'headers' => { + 'Authorization' => 'Basic ' . MIME::Base64::encode("$username:$password",'') + }, + 'content' => '{}', +); + +die "Bad response from conexiant server: $response" + unless $response =~ /^200/; + +my $result = decode_json($page); + +die "Error from conexiant: " . ($result->{'ErrorInfo'} || 'No error message') + unless $result->{'Success'}; + +my $files = $result->{'Data'}->{'Result'}; + +die "Unexpected results from conexiant, not an array" + unless ref($files) eq 'ARRAY'; + +my $dir = $FS::UID::cache_dir. "/cache.". $FS::UID::datasrc; +my $ua = LWP::UserAgent->new; + +# Download files are created automatically at regular frequent intervals, +# but they contain overlapping data. +# +# FS::cdr::conexiant automatically skips previously imported cdrs, +# though if it does so for all records in a file, +# then batch_import thinks the file is empty +foreach my $file (@$files) { + next unless $file->{'BilledCallsOnly'}; + my $cdrbatch = 'conexiant-' . $file->{'Identifier'}; + # files that were "empty" will unfortunately be re-downloaded, + # but the alternative is to leave an excess of empty batches in system, + # and re-downloading is harmless (all files expire after 48 hours anyway) + if (qsearchs('cdr_batch',{ 'cdrbatch' => $cdrbatch })) { + print "$cdrbatch already imported\n" if $verbose; + next; + } + if ($verbose) { + print "Downloading $cdrbatch\n". + " Created ".$file->{'CreatedOn'}."\n". + " Start ".$file->{'QueryStart'}."\n". + " End ".$file->{'QueryEnd'}."\n". + " Link ".$file->{'ValidLink'}."\n"; + } + my $zfh = new File::Temp( TEMPLATE => 'conexiant.XXXXXXXX', + SUFFIX => '.zip', + DIR => $dir, + ) + or die "can't open temporary file to store download: $!\n"; + my $cfh = new File::Temp( TEMPLATE => 'conexiant.XXXXXXXX', + SUFFIX => '.csv', + DIR => $dir, + ) + or die "can't open temporary file to unzip download: $!\n"; + # yeah, these files ain't secured in any way + my $response = $ua->get($file->{'ValidLink'}, ':content_file' => $zfh->filename); + unless ($response->is_success) { + die "Error downloading $cdrbatch: ".$response->status_line; + } + my $zfilename = $zfh->filename; + print $cfh `unzip -p $zfilename 'Conexiant Cdrs.csv'`; + seek($cfh,0,0); + print "Importing batch $cdrbatch\n" if $verbose; + my $error = FS::cdr::batch_import({ + 'batch_namevalue' => $cdrbatch, + 'file' => $cfh->filename, + 'format' => 'conexiant' + }); + if ($error eq 'Empty file!') { + print "File contains no new cdrs, no batch created\n" if $verbose; + $error = ''; + } elsif ($verbose && !$error) { + print "File successfully imported\n"; + } + die "Error importing $cdrbatch: $error" if $error; +} + +exit; + + + diff --git a/httemplate/search/cust_main.html b/httemplate/search/cust_main.html index 84eee1b80..672c20174 100755 --- a/httemplate/search/cust_main.html +++ b/httemplate/search/cust_main.html @@ -50,7 +50,6 @@ my @scalars = qw ( all_tags all_pkg_classnums any_pkg_status - select_referral ); for my $param ( @scalars ) { diff --git a/httemplate/search/report_cust_main.html b/httemplate/search/report_cust_main.html index 2e8f67bf1..ba7c99a45 100755 --- a/httemplate/search/report_cust_main.html +++ b/httemplate/search/report_cust_main.html @@ -278,11 +278,6 @@ <& /elements/tr-select-cust-fields.html &> - <% mt('Add advertising source column') |h %> - - - - <% mt('Add package columns') |h %>