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' ) {
72 #@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', );
73 @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', );
75 ##should charges to charge be a config option?
77 'DISABILITY ACCESS/ENHANCED 911 SERVICES SURCHARGE' => '1',
78 'FEDERAL TRS FUND' => '1',
79 'FEDERAL UNIVERSAL SERVICE FUND' => '1',
80 'STATE SALES TAX' => '1',
83 die "unknown format $format";
90 if ( $type eq 'csv' ) {
92 eval "use Text::CSV_XS;";
93 eval "use File::Slurp qw( slurp );";
96 $parser = new Text::CSV_XS;
98 @buffer = split(/\r?\n/, slurp($filename) );
99 $count = scalar(@buffer);
101 } elsif ( $type eq 'xls' ) {
102 eval "use Spreadsheet::ParseExcel;";
105 my $excel = Spreadsheet::ParseExcel::Workbook->new->Parse($filename);
106 $parser = $excel->{Worksheet}[0]; #first sheet
108 $count = $parser->{MaxRow} || $parser->{MinRow};
112 die "Unknown file type $type\n";
118 local $SIG{HUP} = 'IGNORE';
119 local $SIG{INT} = 'IGNORE';
120 local $SIG{QUIT} = 'IGNORE';
121 local $SIG{TERM} = 'IGNORE';
122 local $SIG{TSTP} = 'IGNORE';
123 local $SIG{PIPE} = 'IGNORE';
125 my $oldAutoCommit = $FS::UID::AutoCommit;
126 local $FS::UID::AutoCommit = 0;
132 my( $last, $min_sec ) = ( time, 5 ); #progressbar foo
136 if ( $type eq 'csv' ) {
138 last unless scalar(@buffer);
139 $line = shift(@buffer);
141 $parser->parse($line) or do {
142 $dbh->rollback if $oldAutoCommit;
143 return "can't parse: ". $parser->error_input();
145 @columns = $parser->fields();
147 } elsif ( $type eq 'xls' ) {
148 last if $row > ($parser->{MaxRow} || $parser->{MinRow})
149 || ! $parser->{Cells}[$row];
151 my @row = @{ $parser->{Cells}[$row] };
152 @columns = map $_->{Val}, @row;
155 die "Unknown file type $type\n";
158 #warn join('-',@columns);
161 foreach my $field ( @fields ) {
162 $row{$field} = shift @columns;
165 if ( $row{custnum} && $row{agent_custid} ) {
166 dbh->rollback if $oldAutoCommit;
167 return "can't specify custnum with agent_custid $row{agent_custid}";
173 if ( $row{agent_custid} && $agentnum ) {
174 $id = $row{agent_custid};
176 'agent_custid' => $row{agent_custid},
177 'agentnum' => $agentnum,
179 %hash = ( 'agent_custid' => $row{agent_custid},
180 'agentnum' => $agentnum,
184 if ( $row{custnum} ) {
187 'custnum' => $row{custnum},
190 %hash = ( 'custnum' => $row{custnum} );
193 unless ( scalar(keys %hash) ) {
194 $dbh->rollback if $oldAutoCommit;
195 return "can't find customer without custnum or agent_custid and agentnum";
198 ## add new pkg data or upate existing by adding new amount for custnum
199 $data{$id}{pkg}{$row{pkg}} = $data{$id}{pkg}{$row{pkg}} ? $data{$id}{pkg}{$row{pkg}} + $row{'amount'} : $row{'amount'};
203 if ( $job && time - $min_sec > $last ) { #progress bar
204 $job->update_statustext( int(100 * $row / $count) );
210 ### run through data hash to post all charges.
211 foreach my $k (keys %data) {
212 my %pkg_hash = %{$data{$k}{pkg}};
213 my %cust_hash = %{$data{$k}{cust}};
215 my $cust_main = qsearchs('cust_main', { %cust_hash } );
216 unless ( $cust_main ) {
217 $dbh->rollback if $oldAutoCommit;
218 my $custnum = $cust_hash{custnum} || $cust_hash{agent_custid};
219 return "unknown custnum $custnum";
222 foreach my $pkg_key (keys %pkg_hash) {
224 my $amount = $pkg_hash{$pkg_key};
226 if (%charges) { next unless $charges{$pkg}; }
229 my $error = $cust_main->charge($amount, $pkg);
231 $dbh->rollback if $oldAutoCommit;
235 } elsif ( $amount < 0 ) {
236 my $error = $cust_main->credit( sprintf( "%.2f", 0-$amount ), $pkg );
238 $dbh->rollback if $oldAutoCommit;
249 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
253 return "Empty file!" unless $imported;