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
127
128
|
#!/usr/bin/perl -w
# don't take any world-facing input
#!/usr/bin/perl -Tw
use strict;
use Fcntl qw(:flock);
use Date::Parse;
use Getopt::Std;
use FS::UID qw(adminsuidsetup);
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_d $opt_p);
getopts("acd:p");
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)= $opt_d ? str2time($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 (
( $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 ($opt_p) {
$cust_main->apply_payments;
$cust_main->apply_credits;
}
if ($opt_c) {
$error=$cust_main->collect( 'invoice_time' => $time);
warn "Error collecting from customer #" . $cust_main->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 [ -p ] ] [ -d 'date' ] user [ custnum custnum ... ]\n";
}
=head1 NAME
freeside-bill - Command line (crontab, script) interface to customer billing.
=head1 SYNOPSIS
freeside-bill [ -c [ -p ] [ -a ] ] [ -d 'date' ] user [ custnum custnum ... ]
=head1 DESCRIPTION
This script is deprecated in 1.4.0. You should use freeside-daily instead.
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).
-p: Apply unapplied payments and credits before collecting (you probably want
this too)
-a: Call collect even if there isn't a new invoice (probably a bad idea for
daily use)
-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 BUGS
=head1 SEE ALSO
L<freeside-daily>, L<FS::cust_main>, config.html from the base documentation
=cut
|