+ my $sth = $cursor_dbh->prepare($sql);
+
+ $sth->execute or die $sth->errstr;
+
+ my @custnums = map { $_->[0] } @{ $sth->fetchall_arrayref };
+
+ last unless scalar(@custnums);
+
+ ###
+ # for each custnum, queue or make one customer object and bill
+ # (one at a time, to reduce memory footprint with large #s of customers)
+ ###
+
+ foreach my $custnum ( @custnums ) {
+
+ my %args = (
+ 'time' => $opt{'time'},
+ 'invoice_time' => $opt{'invoice_time'},
+ 'actual_time' => $^T, #when freeside-bill was started
+ #(not, when using -m, freeside-queued)
+ 'check_freq' => $check_freq,
+ 'resetup' => ( $opt{'s'} ? $opt{'s'} : 0 ),
+ 'not_pkgpart' => $opt{'g'}, #$not_pkgpart,
+ 'one_recur' => $opt{'o'},
+ 'no_prepaid' => 1,
+ );
+
+ if ( $opt{'m'} ) {
+
+ if ( $opt{'r'} ) {
+ warn "DRY RUN: would add custnum $custnum for queued_bill\n";
+ } else {
+
+ #avoid queuing another job if there's one still waiting to run
+ next if qsearch( 'queue', { 'job' => 'FS::cust_main::queued_bill',
+ 'custnum' => $custnum,
+ 'status' => 'new',
+ }
+ );
+
+ #add job to queue that calls bill_and_collect with options
+ my $queue = new FS::queue {
+ 'job' => 'FS::cust_main::queued_bill',
+ 'secure' => 'Y',
+ 'priority' => 99, #don't get in the way of provisioning jobs
+ };
+ my $error = $queue->insert( 'custnum'=>$custnum, %args );
+
+ }
+
+ } else {
+
+ my $cust_main = qsearchs( 'cust_main', { 'custnum' => $custnum } );
+ if ( $disable_bill ) {
+ $cust_main->collect( %args, 'debug' => $debug );
+ } else {
+ $cust_main->bill_and_collect( %args, 'debug' => $debug );
+ }
+
+ }
+
+ }
+
+ last if driver_name =~ /^mysql/;
+
+ }
+
+ $cursor_dbh->commit or die $cursor_dbh->errstr;
+
+ $log->info('finish');
+}
+
+# freeside-daily %opt:
+# -d: Pretend it's 'date'. Date is in any format Date::Parse is happy with,
+# but be careful.
+#
+# -y: In addition to -d, which specifies an absolute date, the -y switch
+# specifies an offset, in days. For example, "-y 15" would increment the
+# "pretend date" 15 days from whatever was specified by the -d switch
+# (or now, if no -d switch was given).
+#
+# -n: When used with "-d" and/or "-y", specifies that invoices should be dated
+# with today's date, regardless of the pretend date used to pre-generate
+# the invoices.
+#
+# -p: Only process customers with the specified payby (I<CARD>, I<DCRD>, I<CHEK>, I<DCHK>, I<BILL>, I<COMP>, I<LECB>)
+#
+# -a: Only process customers with the specified agentnum
+#
+# -v: enable debugging
+#
+# -l: debugging level
+
+=item bill_where
+
+Internal function. Returns a WHERE clause to select the set of customers who
+have actionable packages (no setup date, or bill date in the past, or expire
+or adjourn dates in the past) or events (does a complete where_conditions_sql
+scan).
+
+=cut
+
+sub bill_where {
+ my( %opt ) = @_;
+
+ my $time = $opt{'time'};
+ my $invoice_time = $opt{'invoice_time'};
+
+ my $check_freq = $opt{'check_freq'} || '1d';
+
+ my @search = ();
+
+ push @search, "( cust_main.archived != 'Y' OR archived IS NULL )"; #disable?
+
+ push @search, "cust_main.payby = '". $opt{'p'}. "'"
+ if $opt{'p'};
+ push @search, "cust_main.agentnum IN ( ". $opt{'a'}. " ) "
+ if $opt{'a'};
+
+ #it would be useful if i recognized $opt{g} / $not_pkgpart...
+
+ if ( @ARGV ) {
+ push @search, "( ".
+ join(' OR ', map "cust_main.custnum = $_", @ARGV ).
+ " )";
+ }
+
+ ###
+ # generate where_pkg/where_event search clause
+ ###
+
+ my $conf = new FS::Conf;
+ my $billtime = $conf->exists('next-bill-ignore-time') ? day_end($time) : $time;