# subroutine for misc/process/cust_main-import_charges.cgi
use strict;
-use Text::CSV_XS;
use FS::UID qw( dbh );
use FS::CurrentUser;
use FS::Record qw( qsearchs );
use FS::cust_main;
+use FS::Conf;
+
+my $DEBUG = '';
+
+my %import_charges_info;
+foreach my $INC ( @INC ) {
+ warn "globbing $INC/FS/cust_main/import_charges/[a-z]*.pm\n" if $DEBUG;
+ foreach my $file ( glob("$INC/FS/cust_main/import_charges/[a-z]*.pm") ) {
+ warn "attempting to load import charges format info from $file\n" if $DEBUG;
+ $file =~ /\/(\w+)\.pm$/ or do {
+ warn "unrecognized file in $INC/FS/cust_main/import_charges/: $file\n";
+ next;
+ };
+ my $mod = $1;
+ my $info = eval "use FS::cust_main::import_charges::$mod; ".
+ "\\%FS::cust_main::import_charges::$mod\::info;";
+ if ( $@ ) {
+ die "error using FS::cust_main::import_charges::$mod (skipping): $@\n" if $@;
+ next;
+ }
+ unless ( keys %$info ) {
+ warn "no %info hash found in FS::cust_main::import_charges::$mod, skipping\n";
+ next;
+ }
+ warn "got import charges format info from FS::cust_main::import_charges::$mod: $info\n" if $DEBUG;
+ if ( exists($info->{'disabled'}) && $info->{'disabled'} ) {
+ warn "skipping disabled import charges format FS::cust_main::import_charges::$mod" if $DEBUG;
+ next;
+ }
+ $import_charges_info{$mod} = $info;
+ }
+}
+
+tie my %import_formats, 'Tie::IxHash',
+ map { $_ => $import_charges_info{$_}->{'name'} }
+ sort { $import_charges_info{$a}->{'weight'} <=> $import_charges_info{$b}->{'weight'} }
+ grep { exists($import_charges_info{$_}->{'fields'}) }
+ keys %import_charges_info;
+
+sub import_formats {
+ %import_formats;
+}
=head1 NAME
=cut
sub batch_charge {
+ my $job = shift;
my $param = shift;
#warn join('-',keys %$param);
- my $fh = $param->{filehandle};
my $agentnum = $param->{agentnum};
my $format = $param->{format};
+ 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 $filename = $dir. $files{'file'};
+
+ my $type;
+ if ( $filename =~ /\.(\w+)$/i ) {
+ $type = lc($1);
+ } else {
+ #or error out???
+ warn "can't parse file type from filename $filename; defaulting to CSV";
+ $type = 'csv';
+ }
+
my $extra_sql = ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql;
my @fields;
- if ( $format eq 'simple' ) {
- @fields = qw( custnum agent_custid amount pkg );
+ my %charges;
+
+ if ( $import_charges_info{$format} ) {
+ @fields = @{$import_charges_info{$format}->{'fields'}};
+ %charges = %{$import_charges_info{$format}->{'charges'}};
} else {
die "unknown format $format";
}
- my $csv = new Text::CSV_XS;
- #warn $csv;
- #warn $fh;
+ my $count;
+ my $parser;
+ my @buffer = ();
+
+ if ( $type eq 'csv' ) {
+
+ eval "use Text::CSV_XS;";
+ eval "use File::Slurp qw( slurp );";
+ die $@ if $@;
+
+ $parser = new Text::CSV_XS;
+
+ @buffer = split(/\r?\n/, slurp($filename) );
+ $count = scalar(@buffer);
+
+ } elsif ( $type eq 'xls' ) {
+ eval "use Spreadsheet::ParseExcel;";
+ die $@ if $@;
+
+ my $excel = Spreadsheet::ParseExcel::Workbook->new->Parse($filename);
+ $parser = $excel->{Worksheet}[0]; #first sheet
+
+ $count = $parser->{MaxRow} || $parser->{MinRow};
+ $count++;
+
+ } else {
+ die "Unknown file type $type\n";
+ }
my $imported = 0;
#my $columns;
my $oldAutoCommit = $FS::UID::AutoCommit;
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
-
- #while ( $columns = $csv->getline($fh) ) {
+
my $line;
- while ( defined($line=<$fh>) ) {
+ my $row = 0;
+ my %data = ();
+ my( $last, $min_sec ) = ( time, 5 ); #progressbar foo
+ while (1) {
+ my @columns = ();
- $csv->parse($line) or do {
- $dbh->rollback if $oldAutoCommit;
- return "can't parse: ". $csv->error_input();
- };
+ if ( $type eq 'csv' ) {
+
+ last unless scalar(@buffer);
+ $line = shift(@buffer);
+
+ $parser->parse($line) or do {
+ $dbh->rollback if $oldAutoCommit;
+ return "can't parse: ". $parser->error_input();
+ };
+ @columns = $parser->fields();
+
+ } elsif ( $type eq 'xls' ) {
+ last if $row > ($parser->{MaxRow} || $parser->{MinRow})
+ || ! $parser->{Cells}[$row];
+
+ my @row = @{ $parser->{Cells}[$row] };
+ @columns = map $_->{Val}, @row;
+
+ } else {
+ die "Unknown file type $type\n";
+ }
- my @columns = $csv->fields();
#warn join('-',@columns);
my %row = ();
return "can't specify custnum with agent_custid $row{agent_custid}";
}
+ my $id;
my %hash = ();
+
if ( $row{agent_custid} && $agentnum ) {
+ $id = $row{agent_custid};
+ $data{$id}{cust} = {
+ 'agent_custid' => $row{agent_custid},
+ 'agentnum' => $agentnum,
+ };
%hash = ( 'agent_custid' => $row{agent_custid},
'agentnum' => $agentnum,
);
}
if ( $row{custnum} ) {
+ $id = $row{custnum};
+ $data{$id}{cust} = {
+ 'custnum' => $row{custnum},
+ 'testnum' => 'test',
+ };
%hash = ( 'custnum' => $row{custnum} );
}
return "can't find customer without custnum or agent_custid and agentnum";
}
- my $cust_main = qsearchs('cust_main', { %hash } );
+ ## add new pkg data or upate existing by adding new amount for custnum
+ $data{$id}{pkg}{$row{pkg}} = $data{$id}{pkg}{$row{pkg}} ? $data{$id}{pkg}{$row{pkg}} + $row{'amount'} : $row{'amount'};
+
+ $row++;
+
+ if ( $job && time - $min_sec > $last ) { #progress bar
+ $job->update_statustext( int(100 * $row / $count) );
+ $last = time;
+ }
+
+ }
+
+ ### run through data hash to post all charges.
+ foreach my $k (keys %data) {
+ my %pkg_hash = %{$data{$k}{pkg}};
+ my %cust_hash = %{$data{$k}{cust}};
+
+ my $cust_main = qsearchs('cust_main', { %cust_hash } );
unless ( $cust_main ) {
$dbh->rollback if $oldAutoCommit;
- my $custnum = $row{custnum} || $row{agent_custid};
+ my $custnum = $cust_hash{custnum} || $cust_hash{agent_custid};
return "unknown custnum $custnum";
}
- if ( $row{'amount'} > 0 ) {
- my $error = $cust_main->charge($row{'amount'}, $row{'pkg'});
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
- }
- $imported++;
- } elsif ( $row{'amount'} < 0 ) {
- my $error = $cust_main->credit( sprintf( "%.2f", 0-$row{'amount'} ),
- $row{'pkg'} );
- if ( $error ) {
- $dbh->rollback if $oldAutoCommit;
- return $error;
- }
- $imported++;
- } else {
+ foreach my $pkg_key (keys %pkg_hash) {
+ my $pkg = $pkg_key;
+ my $amount = $pkg_hash{$pkg_key};
+
+ if (%charges) { next unless $charges{$pkg}; }
+
+ if ( $amount > 0 ) {
+ my $error = $cust_main->charge($amount, $pkg);
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ $imported++;
+ } elsif ( $amount < 0 ) {
+ my $error = $cust_main->credit( sprintf( "%.2f", 0-$amount ), $pkg );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ $imported++;
+ } else {
#hmm?
+ }
}
}
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
+ unlink $filename;
+
return "Empty file!" unless $imported;
''; #no error
}
-1;
+1;
\ No newline at end of file