| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
 | #!/usr/bin/perl -Tw
use strict;
use Fcntl qw(:flock);
use Date::Parse;
use Getopt::Std;
use FS::UID qw(adminsuidsetup swapuid);
use FS::Record qw(qsearch qsearchs);
use FS::cust_main;
&untaint_argv;	#what it sounds like  (eww)
use vars qw($opt_a $opt_c $opt_i $opt_d);
getopts("acid:");
my $user = shift or die &usage;
adminsuidsetup $user;
my %bill_only = map { $_ => 1 } (
  @ARGV ? @ARGV : ( map $_->custnum, qsearch('cust_main', {} ) )
);
#we're at now now (and later).
my($time)= $main::opt_d ? str2time($main::opt_d) : $^T;
# find packages w/ bill < time && cancel != '', and create corresponding
# customer objects
my($cust_main,%saw);
foreach $cust_main (
  map {
    unless ( exists $saw{ $_->custnum } && defined $saw{ $_->custnum} ) {
      $saw{ $_->custnum } = 0; # to avoid 'use of uninitialized value' errors
    }
    if (
      ( $main::opt_a || ( ( $_->getfield('bill') || 0 ) <= $time ) )
      && $bill_only{ $_->custnum }
      && !$saw{ $_->custnum }++
    ) {
      qsearchs('cust_main',{'custnum'=> $_->custnum } );
    } else {
      ();
    }
  } ( qsearch('cust_pkg', { 'cancel' => '' }),
      qsearch('cust_pkg', { 'cancel' => 0  }),
    )
) {
  # and bill them
  print "Billing customer #" . $cust_main->getfield('custnum') . "\n";
  my($error);
  $error=$cust_main->bill('time'=>$time);
  warn "Error billing,  customer #" . $cust_main->getfield('custnum') . 
    ":" . $error if $error;
  if ($main::opt_c) {
    $error=$cust_main->collect('invoice_time'=>$time,
                               'batch_card' => $main::opt_i ? 'no' : 'yes',
                              );
    warn "Error collecting customer #" . $cust_main->getfield('custnum') .
      ":" . $error if $error;
  #sleep 1;
  }
}
# subroutines
sub untaint_argv {
  foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV
    #$ARGV[$_] =~ /^([\w\-\/]*)$/ || die "Illegal arguement \"$ARGV[$_]\"";
    # Date::Parse
    $ARGV[$_] =~ /^(.*)$/ || die "Illegal arguement \"$ARGV[$_]\"";
    $ARGV[$_]=$1;
  }
}
sub usage {
  die "Usage:\n\n  freeside-bill [ -c [ i ] ] [ -d 'date' ] [ -b ] user\n";
}
=head1 NAME
freeside-bill - Command line (crontab, script) interface to customer billing.
=head1 SYNOPSIS
  freeside-bill [ -c [ -a ] [ -i ] ] [ -d 'date' ] user [ custnum custnum ... ]
=head1 DESCRIPTION
Bills customers.  Searches for customers who are due for billing and calls
the bill and collect methods of a cust_main object.  See L<FS::cust_main>.
  -c: Turn on collecting (you probably want this).
  -a: Call collect even if there isn't a new invoice (probably a bad idea for
      daily use)
  -i: real-time billing (as opposed to batch billing).  only relevant
      for credit cards.
  -d: Pretend it's 'date'.  Date is in any format Date::Parse is happy with,
      but be careful.
user: From the mapsecrets file - see config.html from the base documentation
custnum: if one or more customer numbers are specified, only bills those
customers.  Otherwise, bills all customers.
=head1 VERSION
$Id: freeside-bill,v 1.6 2000-06-24 00:28:30 ivan Exp $
=head1 BUGS
=head1 SEE ALSO
L<FS::cust_main>, config.html from the base documentation
=cut
 |