import torrus 1.0.9
[freeside.git] / FS / FS / Cron / upload.pm
1 package FS::Cron::upload;
2
3 use strict;
4 use vars qw( @ISA @EXPORT_OK $me $DEBUG );
5 use Exporter;
6 use Date::Format;
7 use FS::UID qw(dbh);
8 use FS::Record qw( qsearch qsearchs );
9 use FS::Conf;
10 use FS::queue;
11 use FS::agent;
12 use LWP::UserAgent;
13 use HTTP::Request;
14 use HTTP::Request::Common;
15 use HTTP::Response;
16
17 @ISA = qw( Exporter );
18 @EXPORT_OK = qw ( upload );
19 $DEBUG = 0;
20 $me = '[FS::Cron::upload]';
21
22 #freeside-daily %opt:
23 #  -v: enable debugging
24 #  -l: debugging level
25 #  -m: Experimental multi-process mode uses the job queue for multi-process and/or multi-machine billing.
26 #  -r: Multi-process mode dry run option
27 #  -a: Only process customers with the specified agentnum
28
29
30 sub upload {
31   my %opt = @_;
32
33   my $debug = 0;
34   $debug = 1 if $opt{'v'};
35   $debug = $opt{'l'} if $opt{'l'};
36
37   local $DEBUG = $debug if $debug;
38
39   warn "$me upload called\n" if $DEBUG;
40
41   my $conf = new FS::Conf;
42   my @agent = grep { $conf->config( 'billco-username', $_->agentnum, 1 ) }
43               grep { $conf->config( 'billco-password', $_->agentnum, 1 ) }
44               qsearch( 'agent', {} );
45
46   my $date =  time2str('%Y%m%d%H%M%S', $^T); # more?
47
48   @agent = grep { $_ == $opt{'a'} } @agent if $opt{'a'};
49
50   foreach my $agent ( @agent ) {
51
52     my $agentnum = $agent->agentnum;
53
54     if ( $opt{'m'} ) {
55
56       if ( $opt{'r'} ) {
57         warn "DRY RUN: would add agent $agentnum for queued upload\n";
58       } else {
59
60         my $queue = new FS::queue {
61           'job'      => 'FS::Cron::upload::billco_upload',
62         };
63         my $error = $queue->insert(
64                                     'agentnum' => $agentnum,
65                                     'date'     => $date,
66                                     'l'        => $opt{'l'} || '',
67                                     'm'        => $opt{'m'} || '',
68                                     'v'        => $opt{'v'} || '',
69                                   );
70
71       }
72
73     } else {
74
75       eval "&billco_upload( 'agentnum' => $agentnum, 'date' => $date );";
76       warn "billco_upload failed: $@\n"
77         if ( $@ );
78
79     }
80
81   }
82
83 }
84
85 sub billco_upload {
86   my %opt = @_;
87
88   warn "$me billco_upload called\n" if $DEBUG;
89   my $conf = new FS::Conf;
90   my $dir = '%%%FREESIDE_EXPORT%%%/export.'. $FS::UID::datasrc. '/cust_bill';
91
92   my $agentnum = $opt{agentnum} or die "no agentnum provided\n";
93   my $url      = $conf->config( 'billco-url', $agentnum )
94     or die "no url for agent $agentnum\n";
95   my $username = $conf->config( 'billco-username', $agentnum, 1 )
96     or die "no username for agent $agentnum\n";
97   my $password = $conf->config( 'billco-password', $agentnum, 1 )
98     or die "no password for agent $agentnum\n";
99   my $clicode  = $conf->config( 'billco-clicode', $agentnum )
100     or die "no clicode for agent $agentnum\n";
101
102   die "no date provided\n" unless $opt{date};
103   my $zipfile  = "$dir/agentnum$agentnum-$opt{date}.zip";
104
105   local $SIG{HUP} = 'IGNORE';
106   local $SIG{INT} = 'IGNORE';
107   local $SIG{QUIT} = 'IGNORE';
108   local $SIG{TERM} = 'IGNORE';
109   local $SIG{TSTP} = 'IGNORE';
110   local $SIG{PIPE} = 'IGNORE';
111
112   my $oldAutoCommit = $FS::UID::AutoCommit;
113   local $FS::UID::AutoCommit = 0;
114   my $dbh = dbh;
115
116   my $agent = qsearchs( 'agent', { agentnum => $agentnum } )
117     or die "no such agent: $agentnum";
118   $agent->select_for_update; #mutex 
119
120   unless ( -f "$dir/agentnum$agentnum-header.csv" ||
121            -f "$dir/agentnum$agentnum-detail.csv" )
122   {
123     warn "$me neither $dir/agentnum$agentnum-header.csv nor ".
124          "$dir/agentnum$agentnum-detail.csv found\n" if $DEBUG;
125     $dbh->commit or die $dbh->errstr if $oldAutoCommit;
126     return;
127   }
128
129   # a better way?
130   if ($opt{m}) {
131     my $sql = "SELECT count(*) FROM queue LEFT JOIN cust_main USING(custnum) ".
132       "WHERE queue.job='FS::cust_main::queued_bill' AND cust_main.agentnum = ?";
133     my $sth = $dbh->prepare($sql) or die $dbh->errstr;
134     while (1) {
135       $sth->execute( $agentnum )
136         or die "Unexpected error executing statement $sql: ". $sth->errstr;
137       last if $sth->fetchow_arrayref->[0];
138       sleep 300;
139     }
140   }
141
142   foreach ( qw ( header detail ) ) {
143     rename "$dir/agentnum$agentnum-$_.csv",
144            "$dir/agentnum$agentnum-$opt{date}-$_.csv";
145   }
146
147   my $command = "cd $dir; zip $zipfile ".
148                 "agentnum$agentnum-$opt{date}-header.csv ".
149                 "agentnum$agentnum-$opt{date}-detail.csv";
150
151   system($command) and die "$command failed\n";
152
153   unlink "agentnum$agentnum-$opt{date}-header.csv",
154          "agentnum$agentnum-$opt{date}-detail.csv";
155
156   my $ua = new LWP::UserAgent;
157   my $res = $ua->request( POST( $url,
158                                 'Content_Type' => 'form-data',
159                                 'Content' => [ 'username' => $username,
160                                                'pass'     => $password,
161                                                'custid'   => $username,
162                                                'clicode'  => $clicode,
163                                                'file1'    => [ $zipfile ],
164                                              ],
165                               )
166                         );
167
168   die "upload failed: ". $res->status_line. "\n"
169     unless $res->is_success;
170
171   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
172   '';
173
174 }
175
176 1;