summaryrefslogtreecommitdiff
path: root/FS/bin/freeside-bill
blob: 42991c4f8a58ee1c214151eaf6557eb56c7a93f5 (plain)
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