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
|