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 ##should charges to charge be a config option?
74 'DISABILITY ACCESS/ENHANCED 911 SERVICES SURCHARGE' => '1',
75 'FEDERAL TRS FUND' => '1',
76 'FEDERAL UNIVERSAL SERVICE FUND' => '1',
77 'STATE SALES TAX' => '1',
80 die "unknown format $format";
87 if ( $type eq 'csv' ) {
89 eval "use Text::CSV_XS;";
90 eval "use File::Slurp qw( slurp );";
93 $parser = new Text::CSV_XS;
95 @buffer = split(/\r?\n/, slurp($filename) );
96 $count = scalar(@buffer);
98 } elsif ( $type eq 'xls' ) {
99 eval "use Spreadsheet::ParseExcel;";
102 my $excel = Spreadsheet::ParseExcel::Workbook->new->Parse($filename);
103 $parser = $excel->{Worksheet}[0]; #first sheet
105 $count = $parser->{MaxRow} || $parser->{MinRow};
109 die "Unknown file type $type\n";
115 local $SIG{HUP} = 'IGNORE';
116 local $SIG{INT} = 'IGNORE';
117 local $SIG{QUIT} = 'IGNORE';
118 local $SIG{TERM} = 'IGNORE';
119 local $SIG{TSTP} = 'IGNORE';
120 local $SIG{PIPE} = 'IGNORE';
122 my $oldAutoCommit = $FS::UID::AutoCommit;
123 local $FS::UID::AutoCommit = 0;
129 my( $last, $min_sec ) = ( time, 5 ); #progressbar foo
133 if ( $type eq 'csv' ) {
135 last unless scalar(@buffer);
136 $line = shift(@buffer);
138 $parser->parse($line) or do {
139 $dbh->rollback if $oldAutoCommit;
140 return "can't parse: ". $parser->error_input();
142 @columns = $parser->fields();
144 } elsif ( $type eq 'xls' ) {
145 last if $row > ($parser->{MaxRow} || $parser->{MinRow})
146 || ! $parser->{Cells}[$row];
148 my @row = @{ $parser->{Cells}[$row] };
149 @columns = map $_->{Val}, @row;
152 die "Unknown file type $type\n";
155 #warn join('-',@columns);
158 foreach my $field ( @fields ) {
159 $row{$field} = shift @columns;
162 if ( $row{custnum} && $row{agent_custid} ) {
163 dbh->rollback if $oldAutoCommit;
164 return "can't specify custnum with agent_custid $row{agent_custid}";
170 if ( $row{agent_custid} && $agentnum ) {
171 $id = $row{agent_custid};
173 'agent_custid' => $row{agent_custid},
174 'agentnum' => $agentnum,
176 %hash = ( 'agent_custid' => $row{agent_custid},
177 'agentnum' => $agentnum,
181 if ( $row{custnum} ) {
184 'custnum' => $row{custnum},
187 %hash = ( 'custnum' => $row{custnum} );
190 unless ( scalar(keys %hash) ) {
191 $dbh->rollback if $oldAutoCommit;
192 return "can't find customer without custnum or agent_custid and agentnum";
195 ## add new pkg data or upate existing by adding new amount for custnum
196 $data{$id}{pkg}{$row{pkg}} = $data{$id}{pkg}{$row{pkg}} ? $data{$id}{pkg}{$row{pkg}} + $row{'amount'} : $row{'amount'};
200 if ( $job && time - $min_sec > $last ) { #progress bar
201 $job->update_statustext( int(100 * $row / $count) );
207 ### run through data hash to post all charges.
208 foreach my $k (keys %data) {
209 my %pkg_hash = %{$data{$k}{pkg}};
210 my %cust_hash = %{$data{$k}{cust}};
212 my $cust_main = qsearchs('cust_main', { %cust_hash } );
213 unless ( $cust_main ) {
214 $dbh->rollback if $oldAutoCommit;
215 my $custnum = $cust_hash{custnum} || $cust_hash{agent_custid};
216 return "unknown custnum $custnum";
219 foreach my $pkg_key (keys %pkg_hash) {
221 my $amount = $pkg_hash{$pkg_key};
223 if (%charges) { next unless $charges{$pkg}; }
226 my $error = $cust_main->charge($amount, $pkg);
228 $dbh->rollback if $oldAutoCommit;
232 } elsif ( $amount < 0 ) {
233 my $error = $cust_main->credit( sprintf( "%.2f", 0-$amount ), $pkg );
235 $dbh->rollback if $oldAutoCommit;
246 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
250 return "Empty file!" unless $imported;