1 package FS::cust_main::Import_Charges;
2 #actually no specific reason it lives under FS::cust_main:: othan than it calls
3 # a thing on cust_main objects. not part of the inheritence, just providess a
4 # subroutine for misc/process/cust_main-import_charges.cgi
9 use FS::Record qw( qsearchs );
14 FS::cust_main::Import_Charges - Batch charge importing
18 use FS::cust_main::Import_Charges;
21 FS::cust_main::Import_charges::batch_charge( {
23 'agentnum' => scalar($cgi->param('agentnum')),
24 'format' => scalar($cgi->param('format')),
29 Batch customer charging.
43 #warn join('-',keys %$param);
44 my $agentnum = $param->{agentnum};
45 my $format = $param->{format};
47 my $files = $param->{'uploaded_files'}
48 or die "No files provided.\n";
50 my (%files) = map { /^(\w+):([\.\w]+)$/ ? ($1,$2):() } split /,/, $files;
52 my $dir = '%%%FREESIDE_CACHE%%%/cache.'. $FS::UID::datasrc. '/';
53 my $filename = $dir. $files{'file'};
56 if ( $filename =~ /\.(\w+)$/i ) {
60 warn "can't parse file type from filename $filename; defaulting to CSV";
64 my $extra_sql = ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql;
68 if ( $format eq 'simple' ) {
69 @fields = qw( custnum agent_custid amount pkg );
70 } elsif ( $format eq 'ooma' ) {
71 #@fields = ( 'userfield1', 'userfield2', 'userfield3', 'userfield4', 'userfield5', 'userfield6', 'userfield7', 'userfield8', 'userfield9', 'userfield10', 'amount', 'userfield12', 'userfield13', 'userfield14', 'userfield15', 'userfield16', 'userfield17', 'userfield18', 'pkg', 'userfield20', 'custnum', 'userfield22', 'userfield23', 'userfield24', 'userfield25', );
72 @fields = ( 'userfield1', 'userfield2', 'userfield3', 'userfield4', 'userfield5', 'userfield6', 'userfield7', 'userfield8', 'amount', 'userfield10', 'userfield11', 'userfield12', 'userfield13', 'userfield14', 'userfield15', 'userfield16', 'pkg', 'userfield18', 'custnum', 'userfield20', 'userfield21', 'userfield22', 'userfield23', 'userfield24', 'userfield25', );
74 ##should charges to charge be a config option?
76 'DISABILITY ACCESS/ENHANCED 911 SERVICES SURCHARGE' => '1',
77 'FEDERAL TRS FUND' => '1',
78 'FEDERAL UNIVERSAL SERVICE FUND' => '1',
79 'STATE SALES TAX' => '1',
82 die "unknown format $format";
89 if ( $type eq 'csv' ) {
91 eval "use Text::CSV_XS;";
92 eval "use File::Slurp qw( slurp );";
95 $parser = new Text::CSV_XS;
97 @buffer = split(/\r?\n/, slurp($filename) );
98 $count = scalar(@buffer);
100 } elsif ( $type eq 'xls' ) {
101 eval "use Spreadsheet::ParseExcel;";
104 my $excel = Spreadsheet::ParseExcel::Workbook->new->Parse($filename);
105 $parser = $excel->{Worksheet}[0]; #first sheet
107 $count = $parser->{MaxRow} || $parser->{MinRow};
111 die "Unknown file type $type\n";
117 local $SIG{HUP} = 'IGNORE';
118 local $SIG{INT} = 'IGNORE';
119 local $SIG{QUIT} = 'IGNORE';
120 local $SIG{TERM} = 'IGNORE';
121 local $SIG{TSTP} = 'IGNORE';
122 local $SIG{PIPE} = 'IGNORE';
124 my $oldAutoCommit = $FS::UID::AutoCommit;
125 local $FS::UID::AutoCommit = 0;
131 my( $last, $min_sec ) = ( time, 5 ); #progressbar foo
135 if ( $type eq 'csv' ) {
137 last unless scalar(@buffer);
138 $line = shift(@buffer);
140 $parser->parse($line) or do {
141 $dbh->rollback if $oldAutoCommit;
142 return "can't parse: ". $parser->error_input();
144 @columns = $parser->fields();
146 } elsif ( $type eq 'xls' ) {
147 last if $row > ($parser->{MaxRow} || $parser->{MinRow})
148 || ! $parser->{Cells}[$row];
150 my @row = @{ $parser->{Cells}[$row] };
151 @columns = map $_->{Val}, @row;
154 die "Unknown file type $type\n";
157 #warn join('-',@columns);
160 foreach my $field ( @fields ) {
161 $row{$field} = shift @columns;
164 if ( $row{custnum} && $row{agent_custid} ) {
165 dbh->rollback if $oldAutoCommit;
166 return "can't specify custnum with agent_custid $row{agent_custid}";
172 if ( $row{agent_custid} && $agentnum ) {
173 $id = $row{agent_custid};
175 'agent_custid' => $row{agent_custid},
176 'agentnum' => $agentnum,
178 %hash = ( 'agent_custid' => $row{agent_custid},
179 'agentnum' => $agentnum,
183 if ( $row{custnum} ) {
186 'custnum' => $row{custnum},
189 %hash = ( 'custnum' => $row{custnum} );
192 unless ( scalar(keys %hash) ) {
193 $dbh->rollback if $oldAutoCommit;
194 return "can't find customer without custnum or agent_custid and agentnum";
197 ## add new pkg data or upate existing by adding new amount for custnum
198 $data{$id}{pkg}{$row{pkg}} = $data{$id}{pkg}{$row{pkg}} ? $data{$id}{pkg}{$row{pkg}} + $row{'amount'} : $row{'amount'};
202 if ( $job && time - $min_sec > $last ) { #progress bar
203 $job->update_statustext( int(100 * $row / $count) );
209 ### run through data hash to post all charges.
210 foreach my $k (keys %data) {
211 my %pkg_hash = %{$data{$k}{pkg}};
212 my %cust_hash = %{$data{$k}{cust}};
214 my $cust_main = qsearchs('cust_main', { %cust_hash } );
215 unless ( $cust_main ) {
216 $dbh->rollback if $oldAutoCommit;
217 my $custnum = $cust_hash{custnum} || $cust_hash{agent_custid};
218 return "unknown custnum $custnum";
221 foreach my $pkg_key (keys %pkg_hash) {
223 my $amount = $pkg_hash{$pkg_key};
225 if (%charges) { next unless $charges{$pkg}; }
228 my $error = $cust_main->charge($amount, $pkg);
230 $dbh->rollback if $oldAutoCommit;
234 } elsif ( $amount < 0 ) {
235 my $error = $cust_main->credit( sprintf( "%.2f", 0-$amount ), $pkg );
237 $dbh->rollback if $oldAutoCommit;
248 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
252 return "Empty file!" unless $imported;