diff options
Diffstat (limited to 'FS/bin')
-rwxr-xr-x | FS/bin/freeside-addgroup | 50 | ||||
-rw-r--r-- | FS/bin/freeside-addoutsource | 28 | ||||
-rw-r--r-- | FS/bin/freeside-addoutsourceuser | 17 | ||||
-rw-r--r-- | FS/bin/freeside-adduser | 108 | ||||
-rwxr-xr-x | FS/bin/freeside-bill | 128 | ||||
-rwxr-xr-x | FS/bin/freeside-daily | 161 | ||||
-rw-r--r-- | FS/bin/freeside-deloutsource | 13 | ||||
-rw-r--r-- | FS/bin/freeside-deloutsourceuser | 2 | ||||
-rw-r--r-- | FS/bin/freeside-deluser | 2 | ||||
-rwxr-xr-x | FS/bin/freeside-email | 4 | ||||
-rwxr-xr-x | FS/bin/freeside-expiration-alerter | 4 | ||||
-rwxr-xr-x | FS/bin/freeside-monthly | 91 | ||||
-rw-r--r-- | FS/bin/freeside-prepaidd | 41 | ||||
-rw-r--r-- | FS/bin/freeside-queued | 7 | ||||
-rwxr-xr-x | FS/bin/freeside-reset-fixed | 69 | ||||
-rw-r--r-- | FS/bin/freeside-selfservice-server | 23 | ||||
-rwxr-xr-x | FS/bin/freeside-setup | 86 | ||||
-rw-r--r-- | FS/bin/freeside-sqlradius-radacctd | 2 | ||||
-rwxr-xr-x | FS/bin/freeside-upgrade | 132 |
19 files changed, 462 insertions, 506 deletions
diff --git a/FS/bin/freeside-addgroup b/FS/bin/freeside-addgroup new file mode 100755 index 000000000..7b30f7d95 --- /dev/null +++ b/FS/bin/freeside-addgroup @@ -0,0 +1,50 @@ +#!/usr/bin/perl + +use strict; +use vars qw($opt_s); +use Getopt::Std; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch); +use FS::CurrentUser; +use FS::AccessRight; +use FS::access_group; +use FS::access_right; +use FS::access_groupagent; + +getopts("s"); +my $user = shift or die &usage; #just for adminsuidsetup +my $group = shift or die &usage; + +$FS::CurrentUser::upgrade_hack = 1; +#adminsuidsetup $rootuser; +adminsuidsetup $user; + +my $access_group = new FS::access_group { 'groupname' => $group }; +my $error = $access_group->insert; +die $error if $error; + +if ( $opt_s ) { + foreach my $rightname ( FS::AccessRight->rights ) { + my $access_right = new FS::access_right { + 'righttype' => 'FS::access_group', + 'rightobjnum' => $access_group->groupnum, + 'rightname' => $rightname, + }; + my $ar_error = $access_right->insert; + die $ar_error if $ar_error; + } + + foreach my $agent ( qsearch('agent', {} ) ) { + my $access_groupagent = new FS::access_groupagent { + 'groupnum' => $access_group->groupnum, + 'agentnum' => $agent->agentnum, + }; + my $aga_error = $access_groupagent->insert; + die $aga_error if $aga_error; + } +} + +sub usage { + die "Usage:\n\n freeside-addgroup [ -s ] username groupname" +} + diff --git a/FS/bin/freeside-addoutsource b/FS/bin/freeside-addoutsource index db4e7a307..9cb12195a 100644 --- a/FS/bin/freeside-addoutsource +++ b/FS/bin/freeside-addoutsource @@ -2,23 +2,31 @@ domain=$1 +FREESIDE_CONF=%%%FREESIDE_CONF%%% +FREESIDE_CACHE=%%%FREESIDE_CACHE%%% +FREESIDE_EXPORT=%%%FREESIDE_EXPORT%%% + +#without this, [a-z]* matches CVS/, the copy doesn't return a sucessful error +# status, and the rest of the commands aren't run +export LANG=C + createdb $domain && \ \ -mkdir /usr/local/etc/freeside/conf.DBI:Pg:dbname=$domain && \ +mkdir $FREESIDE_CONF/conf.DBI:Pg:dbname=$domain && \ \ -chown freeside /usr/local/etc/freeside/conf.DBI:Pg:dbname=$domain && \ +chown freeside $FREESIDE_CONF/conf.DBI:Pg:dbname=$domain && \ \ -cp /home/ivan/freeside/conf/[a-z]* /usr/local/etc/freeside/conf.DBI:Pg:dbname=$domain && \ +cp /home/ivan/freeside/conf/[a-z]* $FREESIDE_CONF/conf.DBI:Pg:dbname=$domain && \ \ -touch /usr/local/etc/freeside/conf.DBI:Pg:dbname=$domain/secrets && \ +touch $FREESIDE_CONF/conf.DBI:Pg:dbname=$domain/secrets && \ \ -chown freeside /usr/local/etc/freeside/conf.DBI:Pg:dbname=$domain/secrets && \ +chown freeside $FREESIDE_CONF/conf.DBI:Pg:dbname=$domain/secrets && \ \ -chmod 600 /usr/local/etc/freeside/conf.DBI:Pg:dbname=$domain/secrets && \ +chmod 600 $FREESIDE_CONF/conf.DBI:Pg:dbname=$domain/secrets && \ \ -echo -e "DBI:Pg:dbname=$domain\nfreeside\n" >/usr/local/etc/freeside/conf.DBI:Pg:dbname=$domain/secrets && \ +echo -e "DBI:Pg:dbname=$domain\nfreeside\n" >$FREESIDE_CONF/conf.DBI:Pg:dbname=$domain/secrets && \ \ -mkdir /usr/local/etc/freeside/counters.DBI:Pg:dbname=$domain && \ -mkdir /usr/local/etc/freeside/cache.DBI:Pg:dbname=$domain && \ -mkdir /usr/local/etc/freeside/export.DBI:Pg:dbname=$domain +mkdir $FREESIDE_CACHE/counters.DBI:Pg:dbname=$domain && \ +mkdir $FREESIDE_CACHE/cache.DBI:Pg:dbname=$domain && \ +mkdir $FREESIDE_EXPORT/export.DBI:Pg:dbname=$domain diff --git a/FS/bin/freeside-addoutsourceuser b/FS/bin/freeside-addoutsourceuser index cad07f1fd..cbe792acc 100644 --- a/FS/bin/freeside-addoutsourceuser +++ b/FS/bin/freeside-addoutsourceuser @@ -3,13 +3,16 @@ username=$1 domain=$2 password=$3 +realdomain=$4 +FREESIDE_CONF=%%%FREESIDE_CONF%%% -freeside-adduser -h /usr/local/etc/freeside/htpasswd \ - -s conf.DBI:Pg:dbname=$domain/secrets \ - -b \ - $username $password 2>/dev/null +freeside-adduser -s conf.DBI:Pg:dbname=$domain/secrets \ + -n \ + $username #2>/dev/null -[ -e /usr/local/etc/freeside/dbdef.DBI:Pg:dbname=$domain ] \ - || ( freeside-setup -s $username 2>/dev/null; \ - /home/ivan/freeside/bin/populate-msgcat $username 2>/dev/null ) +[ -e $FREESIDE_CONF/dbdef.DBI:Pg:dbname=$domain ] \ + || ( freeside-setup -d $realdomain -u $username ) +freeside-adduser -g 1 $username + +htpasswd -b $FREESIDE_CONF/htpasswd $username $password diff --git a/FS/bin/freeside-adduser b/FS/bin/freeside-adduser index c3ee05b9b..237e29ef8 100644 --- a/FS/bin/freeside-adduser +++ b/FS/bin/freeside-adduser @@ -1,37 +1,85 @@ #!/usr/bin/perl -w -# -# $Id: freeside-adduser,v 1.8 2002-09-27 05:36:29 ivan Exp $ use strict; -use vars qw($opt_h $opt_b $opt_c $opt_s); +use vars qw($opt_s $opt_g $opt_n); use Fcntl qw(:flock); use Getopt::Std; -my $FREESIDE_CONF = "/usr/local/etc/freeside"; +my $FREESIDE_CONF = "%%%FREESIDE_CONF%%%"; -getopts("bch:s:"); -die &usage if $opt_c && ! $opt_h; +getopts("s:g:n"); my $user = shift or die &usage; -if ( $opt_h ) { - my @args = ( 'htpasswd' ); - push @args, '-b' if $opt_b; - push @args, '-c' if $opt_c; - push @args, $opt_h, $user; - push @args, shift if $opt_b; - system(@args) == 0 or die "htpasswd failed: $?"; +if ( $opt_s ) { + + #if ( -e "$FREESIDE_CONF/mapsecrets" ) { + # open(MAPSECRETS,"<$FREESIDE_CONF/mapsecrets") + # or die "can't open $FREESIDE_CONF/mapsecrets: $!"; + # while (<MAPSECRETS>) { + # /^(\S+) / or die "unparsable line in mapsecrets: $_"; + # die "user $user already exists\n" if $user eq $1; + # } + # close MAPSECRETS; + #} + + #insert new entry before a wildcard... + open(MAPSECRETS,"<$FREESIDE_CONF/mapsecrets") + and flock(MAPSECRETS,LOCK_EX) + or die "can't open $FREESIDE_CONF/mapsecrets: $!"; + open(NEW,">$FREESIDE_CONF/mapsecrets.new") + or die "can't open $FREESIDE_CONF/mapsecrets.new: $!"; + while(<MAPSECRETS>) { + if ( /^\*\s/ ) { + print NEW "$user $opt_s\n"; + } + print NEW $_; + } + close MAPSECRETS or die "can't close $FREESIDE_CONF/mapsecrets: $!"; + close NEW or die "can't close $FREESIDE_CONF/mapsecrets.new: $!"; + rename("$FREESIDE_CONF/mapsecrets.new", "$FREESIDE_CONF/mapsecrets") + or die "can't move mapsecrets.new into place: $!"; + } -my $secretfile = $opt_s || 'secrets'; +### + +exit if $opt_n; + +### + +use FS::UID qw(adminsuidsetup); +use FS::CurrentUser; +use FS::access_user; +use FS::access_usergroup; + +$FS::CurrentUser::upgrade_hack = 1; +#adminsuidsetup $rootuser; +adminsuidsetup $user; + +my $access_user = new FS::access_user { + 'username' => $user, + '_password' => 'notyet', + 'first' => 'Firstname', # $opt_f || + 'last' => 'Lastname', # $opt_l || +}; +my $au_error = $access_user->insert; +die $au_error if $au_error; + +if ( $opt_g ) { -open(MAPSECRETS,">>$FREESIDE_CONF/mapsecrets") - and flock(MAPSECRETS,LOCK_EX) - or die "can't open $FREESIDE_CONF/mapsecrets: $!"; -print MAPSECRETS "$user $secretfile\n"; -close MAPSECRETS or die "can't close $FREESIDE_CONF/mapsecrets: $!"; + my $access_usergroup = new FS::access_usergroup { + 'usernum' => $access_user->usernum, + 'groupnum' => $opt_g, + }; + my $aug_error = $access_usergroup->insert; + die $aug_error if $aug_error; + +} + +### sub usage { - die "Usage:\n\n freeside-adduser [ -h htpasswd_file [ -c ] [ -b ] ] [ -s secretfile ] username" + die "Usage:\n\n freeside-adduser [ -n ] [ -s ] [ -g groupnum ] username [ password ]" } =head1 NAME @@ -40,24 +88,32 @@ freeside-adduser - Command line interface to add (freeside) users. =head1 SYNOPSIS - freeside-adduser [ -h htpasswd_file [ -c ] ] [ -s secretfile ] username + freeside-adduser [ -n ] [ -s ] [ -g groupnum ] username [ password ] =head1 DESCRIPTION Adds a user to the Freeside billing system. This is for adding users (internal sales/tech folks) to the web interface, not for adding customer accounts. - -h: Also call htpasswd for this user with the given filename +This functionality is now available in the web interface as well, under +B<Configuration | Employees | View/Edit employees>. + + -g: initial groupnum + + Development/multi-DB options: + + -s: alternate secrets file - -c: Passed to htpasswd(1) + -n: no ACL added, for bootstrapping - -s: Specify an alternate secret file +=head1 NOTE - -b: same as htpasswd(1), probably insecure, not recommended +No explicit htpasswd options are available in 1.7 - passwordsa are now +maintained automatically. =head1 SEE ALSO -L<htpasswd>(1), base Freeside documentation +Base Freeside documentation =cut diff --git a/FS/bin/freeside-bill b/FS/bin/freeside-bill deleted file mode 100755 index 49ad4a768..000000000 --- a/FS/bin/freeside-bill +++ /dev/null @@ -1,128 +0,0 @@ -#!/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 - diff --git a/FS/bin/freeside-daily b/FS/bin/freeside-daily index 603da12b8..a06a2b185 100755 --- a/FS/bin/freeside-daily +++ b/FS/bin/freeside-daily @@ -1,157 +1,32 @@ #!/usr/bin/perl -w use strict; -use Fcntl qw(:flock); -use Date::Parse; use Getopt::Std; -use FS::UID qw(adminsuidsetup driver_name dbh datasrc); -use FS::Record qw(qsearch qsearchs dbdef); -use FS::Conf; -use FS::cust_main; +use FS::UID qw(adminsuidsetup); &untaint_argv; #what it sounds like (eww) -use vars qw($opt_d $opt_v $opt_p $opt_a $opt_s $opt_y); -getopts("p:a:d:vsy:"); -my $user = shift or die &usage; +#use vars qw($opt_d $opt_v $opt_p $opt_a $opt_s $opt_y); +use vars qw(%opt); +getopts("p:a:d:vsy:", \%opt); +my $user = shift or die &usage; adminsuidsetup $user; -$FS::cust_main::DEBUG = 1 if $opt_v; - -my %search = (); -$search{'payby'} = $opt_p if $opt_p; -$search{'agentnum'} = $opt_a if $opt_a; - -#we're at now now (and later). -my($time)= $opt_d ? str2time($opt_d) : $^T; -$time += $opt_y * 86400 if $opt_y; - -# select * from cust_main where -my $where_pkg = <<"END"; - 0 < ( select count(*) from cust_pkg - where cust_main.custnum = cust_pkg.custnum - and ( cancel is null or cancel = 0 ) - and ( setup is null or setup = 0 - or bill is null or bill <= $time - or ( expire is not null and expire <= $^T ) - ) - ) -END - -# or -my $where_bill_event = <<"END"; - 0 < ( select count(*) from cust_bill - where cust_main.custnum = cust_bill.custnum - and 0 < charged - - coalesce( - ( select sum(amount) from cust_bill_pay - where cust_bill.invnum = cust_bill_pay.invnum ) - ,0 - ) - - coalesce( - ( select sum(amount) from cust_credit_bill - where cust_bill.invnum = cust_credit_bill.invnum ) - ,0 - ) - and 0 < ( select count(*) from part_bill_event - where payby = cust_main.payby - and ( disabled is null or disabled = '' ) - and seconds <= $time - cust_bill._date - and 0 = ( select count(*) from cust_bill_event - where cust_bill.invnum = cust_bill_event.invnum - and part_bill_event.eventpart = cust_bill_event.eventpart - and status = 'done' - ) - - ) - ) -END - -my $extra_sql = ( scalar(%search) ? ' AND ' : ' WHERE ' ). "( $where_pkg OR $where_bill_event )"; - -my @cust_main; -if ( @ARGV ) { - @cust_main = map { qsearchs('cust_main', { custnum => $_, %search } ) } @ARGV -} else { - @cust_main = qsearch('cust_main', \%search, '', $extra_sql ); -} -; - -my($cust_main,%saw); -foreach $cust_main ( @cust_main ) { - - # $^T not $time because -d is for pre-printing invoices - foreach my $cust_pkg ( - grep { $_->expire && $_->expire <= $^T } $cust_main->ncancelled_pkgs - ) { - my $error = $cust_pkg->cancel; - warn "Error cancelling expired pkg ". $cust_pkg->pkgnum. " for custnum ". - $cust_main->custnum. ": $error" - if $error; - } - # $^T not $time because -d is for pre-printing invoices - foreach my $cust_pkg ( - grep { $_->part_pkg->is_prepaid - && $_->bill && $_->bill < $^T && ! $_->susp - } - $cust_main->ncancelled_pkgs - ) { - my $error = $cust_pkg->suspend; - warn "Error suspending package ". $cust_pkg->pkgnum. - " for custnum ". $cust_main->custnum. - ": $error" - if $error; - } - - my $error = $cust_main->bill( 'time' => $time, - 'resetup' => $opt_s, ); - warn "Error billing, custnum ". $cust_main->custnum. ": $error" if $error; - - $cust_main->apply_payments; - $cust_main->apply_credits; - - $error = $cust_main->collect( 'invoice_time' => $time ); - warn "Error collecting, custnum". $cust_main->custnum. ": $error" if $error; +use FS::Cron::bill qw(bill); +bill(%opt); -} +use FS::Cron::notify qw(notify_flat_delay); +notify_flat_delay(%opt); -if ( driver_name eq 'Pg' ) { - dbh->{AutoCommit} = 1; #so we can vacuum - foreach my $table ( dbdef->tables ) { - my $sth = dbh->prepare("VACUUM ANALYZE $table") or die dbh->errstr; - $sth->execute or die $sth->errstr; - } -} +use FS::Cron::vacuum qw(vacuum); +vacuum(); -my $conf = new FS::Conf; -my $dest = $conf->config('dump-scpdest'); -if ( $dest ) { - datasrc =~ /dbname=([\w\.]+)$/ or die "unparsable datasrc ". datasrc; - my $database = $1; - eval "use Net::SCP qw(scp);"; - if ( driver_name eq 'Pg' ) { - system("pg_dump $database >/var/tmp/$database.sql") - } else { - die "database dumps not yet supported for ". driver_name; - } - if ( $conf->config('dump-pgpid') ) { - eval 'use GnuPG'; - my $gpg = new GnuPG; - $gpg->encrypt( plaintext => "/var/tmp/$database.sql", - output => "/var/tmp/$database.gpg", - recipient => $conf->config('dump-pgpid'), - ); - chmod 0600, '/var/tmp/$database.gpg'; - scp("/var/tmp/$database.gpg", $dest); - unlink "/var/tmp/$database.gpg" or die $!; - } else { - chmod 0600, '/var/tmp/$database.sql'; - scp("/var/tmp/$database.sql", $dest); - } - unlink "/var/tmp/$database.sql" or die $!; -} +use FS::Cron::backup qw(backup_scp); +backup_scp(); +### # subroutines +### sub untaint_argv { foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV @@ -166,6 +41,10 @@ sub usage { die "Usage:\n\n freeside-daily [ -d 'date' ] user [ custnum custnum ... ]\n"; } +### +# documentation +### + =head1 NAME freeside-daily - Run daily billing and invoice collection events. @@ -179,8 +58,6 @@ freeside-daily - Run daily billing and invoice collection events. Bills customers and runs invoice collection events. Should be run from crontab daily. -This script replaces freeside-bill from 1.3.1. - 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>. diff --git a/FS/bin/freeside-deloutsource b/FS/bin/freeside-deloutsource index 561853539..afc3a0118 100644 --- a/FS/bin/freeside-deloutsource +++ b/FS/bin/freeside-deloutsource @@ -1,11 +1,14 @@ #!/bin/sh domain=$1 +FREESIDE_CONF=%%%FREESIDE_CONF%%% +FREESIDE_CACHE=%%%FREESIDE_CACHE%%% +FREESIDE_EXPORT=%%%FREESIDE_EXPORT%%% dropdb $domain && \ -rm -rf /usr/local/etc/freeside/conf.DBI:Pg:host=localhost\;dbname=$domain && \ -rm -rf /usr/local/etc/freeside/counters.DBI:Pg:host=localhost\;dbname=$domain && \ -rm -rf /usr/local/etc/freeside/cache.DBI:Pg:host=localhost\;dbname=$domain && \ -rm -rf /usr/local/etc/freeside/export.DBI:Pg:host=localhost\;dbname=$domain && \ -rm /usr/local/etc/freeside/dbdef.DBI:Pg:host=localhost\;dbname=$domain +rm -rf $FREESIDE_CONF/conf.DBI:Pg:host=localhost\;dbname=$domain && \ +rm -rf $FREESIDE_CACHE/counters.DBI:Pg:host=localhost\;dbname=$domain && \ +rm -rf $FREESIDE_CACHE/cache.DBI:Pg:host=localhost\;dbname=$domain && \ +rm -rf $FREESIDE_EXPORT/export.DBI:Pg:host=localhost\;dbname=$domain && \ +rm $FREESIDE_CONF/dbdef.DBI:Pg:host=localhost\;dbname=$domain diff --git a/FS/bin/freeside-deloutsourceuser b/FS/bin/freeside-deloutsourceuser index 96871e50c..dc4ff9cdc 100644 --- a/FS/bin/freeside-deloutsourceuser +++ b/FS/bin/freeside-deloutsourceuser @@ -2,5 +2,5 @@ username=$1 -freeside-deluser -h /usr/local/etc/freeside/htpasswd $username 2>/dev/null +freeside-deluser -h %%%FREESIDE_CONF%%%/htpasswd $username 2>/dev/null diff --git a/FS/bin/freeside-deluser b/FS/bin/freeside-deluser index 57d6ce165..a2a361a83 100644 --- a/FS/bin/freeside-deluser +++ b/FS/bin/freeside-deluser @@ -5,7 +5,7 @@ use vars qw($opt_h); use Fcntl qw(:flock); use Getopt::Std; -my $FREESIDE_CONF = "/usr/local/etc/freeside"; +my $FREESIDE_CONF = "%%%FREESIDE_CONF%%%"; getopts("h:"); my $user = shift or die &usage; diff --git a/FS/bin/freeside-email b/FS/bin/freeside-email index 400dc2ac7..7a93f78ee 100755 --- a/FS/bin/freeside-email +++ b/FS/bin/freeside-email @@ -47,10 +47,6 @@ Prints the email addresses of all customers on STDOUT, separated by newlines. user: From the mapsecrets file - see config.html from the base documentation -=head1 VERSION - -$Id: freeside-email,v 1.2 2002-09-18 22:50:44 ivan Exp $ - =head1 BUGS =head1 SEE ALSO diff --git a/FS/bin/freeside-expiration-alerter b/FS/bin/freeside-expiration-alerter index 691fd3aa5..e49bd62aa 100755 --- a/FS/bin/freeside-expiration-alerter +++ b/FS/bin/freeside-expiration-alerter @@ -200,10 +200,6 @@ is about to expire. Usually run as a cron job. user: From the mapsecrets file - see config.html from the base documentation -=head1 VERSION - -$Id: freeside-expiration-alerter,v 1.5 2003-04-21 20:53:57 ivan Exp $ - =head1 BUGS Yes..... Use at your own risk. No guarantees or warrantees of any diff --git a/FS/bin/freeside-monthly b/FS/bin/freeside-monthly new file mode 100755 index 000000000..a6c75e715 --- /dev/null +++ b/FS/bin/freeside-monthly @@ -0,0 +1,91 @@ +#!/usr/bin/perl -w + +use strict; +use Getopt::Std; +use FS::UID qw(adminsuidsetup); + +&untaint_argv; #what it sounds like (eww) +#use vars qw($opt_d $opt_v $opt_p $opt_a $opt_s $opt_y); +use vars qw(%opt); +getopts("p:a:d:vsy:", \%opt); + +my $user = shift or die &usage; +adminsuidsetup $user; + +use FS::Cron::bill qw(bill); +bill(%opt, 'freq'=>'1m' ); + +### +# 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-monthly [ -d 'date' ] user [ custnum custnum ... ]\n"; +} + +### +# documentation +### + +=head1 NAME + +freeside-monthly - Run monthly billing and invoice collection events. + +=head1 SYNOPSIS + + freeside-monthly [ -d 'date' ] [ -y days ] [ -p 'payby' ] [ -a agentnum ] [ -s ] [ -v ] user [ custnum custnum ... ] + +=head1 DESCRIPTION + +Bills customers and runs invoice collection events, for the alternate monthly +event chain. If you have defined monthly event checks, should be run from +crontab monthly. + +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>. + + -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). + + -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 + + -s: re-charge setup fees + + -v: enable debugging + +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 NOTE + +In most cases, you would use freeside-daily only and not freeside-monthly. +freeside-monthly would only be used in cases where you have events that can +only be run once each month, for example, batching invoices to a third-party +print/mail provider. + +=head1 BUGS + +=head1 SEE ALSO + +L<freeside-daily>, L<FS::cust_main>, config.html from the base documentation + +=cut + diff --git a/FS/bin/freeside-prepaidd b/FS/bin/freeside-prepaidd index e51a56350..73f7523c4 100644 --- a/FS/bin/freeside-prepaidd +++ b/FS/bin/freeside-prepaidd @@ -3,7 +3,7 @@ use strict; use FS::Daemon qw(daemonize1 drop_root logfile daemonize2 sigint sigterm); use FS::UID qw(adminsuidsetup); -use FS::Record qw(qsearch); # qsearchs); +use FS::Record qw(qsearch qsearchs); use FS::cust_pkg; my $user = shift or die &usage; @@ -37,9 +37,38 @@ while (1) { " AND ( cancel IS NULL OR cancel = 0)" } ) ) { - my $error = $cust_pkg->suspend; - warn "Error suspended package ". $cust_pkg->pkgnum. - " for custnum ". $cust_pkg->custnum. + + my $work_cust_pkg = $cust_pkg; + + my $cust_main = $cust_pkg->cust_main; + if ( $cust_main->total_unapplied_payments > 0 + or $cust_main->total_credited > 0 + ) + { + #this needs a flag to say only do the prepaid packages... + # and only try em if the renewal price matches.. but this will do for now + my $b_error = $cust_main->bill; + if ( $b_error ) { + warn "Error billing customer #". $cust_main->custnum; + next; + } + #$b_error = $cust_main->apply_payments_and_credits; + $b_error = $cust_main->apply_payments; + $b_error = $cust_main->apply_credits; + + $work_cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $work_cust_pkg->pkgnum } ); + + next + if $cust_main->balance <= 0 + and $work_cust_pkg->bill >= time; + } + + my $action = $work_cust_pkg->part_pkg->option('recur_action') || 'suspend'; + + my $error = $work_cust_pkg->$action(); + + warn "Error ${action}ing package ". $work_cust_pkg->pkgnum. + " for custnum ". $work_cust_pkg->custnum. ": $error\n" if $error; } @@ -65,8 +94,8 @@ freeside-prepaidd - Real-time daemon for prepaid packages =head1 DESCRIPTION -Runs continuously and suspendes any prepaid customer packages which have -passed their renewal date (next bill date). +Runs continuously and suspends or cancels any prepaid customer packages which +have passed their renewal date (next bill date). =head1 SEE ALSO diff --git a/FS/bin/freeside-queued b/FS/bin/freeside-queued index 3a0a9b4e5..93d735d1a 100644 --- a/FS/bin/freeside-queued +++ b/FS/bin/freeside-queued @@ -10,11 +10,8 @@ use FS::Record qw(qsearch qsearchs); use FS::queue; use FS::queue_depend; -# no autoloading just yet -use FS::cust_main; -use FS::svc_acct; +# no autoloading for non-FS classes... use Net::SSH 0.07; -use FS::part_export; $DEBUG = 0; @@ -44,7 +41,7 @@ while ( $@ ) { } } -logfile( "/usr/local/etc/freeside/queuelog.". $FS::UID::datasrc ); +logfile( "%%%FREESIDE_LOG%%%/queuelog.". $FS::UID::datasrc ); warn "completing daemonization (detaching))\n" if $DEBUG; daemonize2(); diff --git a/FS/bin/freeside-reset-fixed b/FS/bin/freeside-reset-fixed new file mode 100755 index 000000000..5829d441b --- /dev/null +++ b/FS/bin/freeside-reset-fixed @@ -0,0 +1,69 @@ +#!/usr/bin/perl -w + +use strict; +use vars qw($opt_p $opt_s $opt_r); +use Getopt::Std; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch qsearchs); +use FS::cust_svc; +use FS::svc_Common; + +getopts('p:s:r'); + +my $user = shift or die &usage; +adminsuidsetup $user; + +die &usage + if ($opt_p && $opt_s); + +$FS::Record::nowarn_identical = 1; +$FS::svc_Common::noexport_hack = 1 + unless $opt_r; + +my @svc_x = (); +if ( $opt_s ) { + $opt_s =~ /^(\d+)$/ or die "invalid svcnum"; + my $cust_svc = qsearchs('cust_svc', { svcnum => $1 } ) + or die "svcnum $opt_s not found\n"; + push @svc_x, $cust_svc->svc_x; +} elsif ( $opt_p ) { + $opt_p =~ /^(\d+)$/ or die "invalid svcpart"; + push @svc_x, map { $_->svc_x } qsearch('cust_svc', { svcpart => $1 } ); + die "no services with svcpart $opt_p found\n" unless @svc_x; +} else { + push @svc_x, map { $_->svc_x } qsearch('cust_svc', {} ); + die "no services found\n" unless @svc_x; +} + +foreach my $svc_x ( @svc_x ) { + my $result = $svc_x->setfixed; + die $result unless ref($result); + my $error = $svc_x->replace + if $svc_x->modified; + die $error if $error; +} + + +sub usage { + die "Usage:\n\n freeside-reset-fixed user [ -s svcnum | -p svcpart ] [ -r ]\n"; +} + +=head1 NAME + +freeside-reset-fixed - Command line tool to set the fixed columns for existing services + +=head1 SYNOPSIS + + freeside-reset-fixed user [ -s svcnum | -p svcpart ] [ -r ] + +=head1 DESCRIPTION + + Resets the fixed columns for the specified service part or service number. + Re-exports the service if -r is specified. + +=head1 SEE ALSO + +L<freeside-reexport>, L<FS::part_svc> + +=cut + diff --git a/FS/bin/freeside-selfservice-server b/FS/bin/freeside-selfservice-server index c73349a60..187bc1469 100644 --- a/FS/bin/freeside-selfservice-server +++ b/FS/bin/freeside-selfservice-server @@ -1,7 +1,8 @@ #!/usr/bin/perl -w use strict; -use vars qw( $Debug %kids $kids $max_kids $ssh_pid $keepalives ); +use vars qw( $FREESIDE_LOG $FREESIDE_LOCK ); +use vars qw( $Debug %kids $kids $max_kids $ssh_pid %old_ssh_pid $keepalives ); use subs qw( lock_write unlock_write myshutdown usage ); use Fcntl qw(:flock); use POSIX qw(:sys_wait_h); @@ -18,6 +19,9 @@ use FS::Conf; use FS::cust_bill; use FS::cust_pkg; +$FREESIDE_LOG = "%%%FREESIDE_LOG%%%"; +$FREESIDE_LOCK = "%%%FREESIDE_LOCK%%%"; + $Debug = 1; # 2 will turn on more logging # 3 will log packet contents, including passwords @@ -29,8 +33,7 @@ my $user = shift or die &usage; my $machine = shift or die &usage; my $tag = scalar(@ARGV) ? shift : ''; -my $lock_file = "/usr/local/etc/freeside/selfservice.$machine.writelock"; - +my $lock_file = "$FREESIDE_LOCK/selfservice.$machine.writelock"; # to keep pid files unique w/multi machines (and installs!) # $FS::UID::datasrc not posible @@ -50,11 +53,10 @@ $ENV{HOME} = (getpwuid($>))[7]; #for ssh adminsuidsetup $user; #logfile("/usr/local/etc/freeside/selfservice.". $FS::UID::datasrc); #MACHINE -logfile("/usr/local/etc/freeside/selfservice.$machine.log"); +logfile("$FREESIDE_LOG/selfservice.$machine.log"); daemonize2(); - my $conf = new FS::Conf; my $clientd = "/usr/local/sbin/freeside-selfservice-clientd"; #better name? @@ -102,6 +104,7 @@ while (1) { if ( $ssh_pid ) { warn "sending TERM signal to ssh process $ssh_pid\n" if $Debug; kill 'TERM', $ssh_pid; + $old_ssh_pid{$ssh_pid} = 1; $ssh_pid = 0; } last; @@ -133,11 +136,11 @@ while (1) { } else { #kid time ##get new db handle - #$FS::UID::dbh->{InactiveDestroy} = 1; - #forksuidsetup($user); + $FS::UID::dbh->{InactiveDestroy} = 1; + forksuidsetup($user); #get db handle - adminsuidsetup($user); + #adminsuidsetup($user); my $type = $packet->{_packet}; warn "calling $type handler\n" if $Debug; @@ -180,6 +183,10 @@ sub reap_kids { delete $kids{$kid}; } } + + foreach my $pid ( keys %old_ssh_pid ) { + waitpid($pid, WNOHANG) and delete $old_ssh_pid{$pid}; + } #warn "done reaping\n"; } diff --git a/FS/bin/freeside-setup b/FS/bin/freeside-setup index a16e51749..ddc210f50 100755 --- a/FS/bin/freeside-setup +++ b/FS/bin/freeside-setup @@ -4,28 +4,27 @@ BEGIN { $FS::Schema::setup_hack = 1; } use strict; -use vars qw($opt_s); +use vars qw($opt_u $opt_d $opt_v); use Getopt::Std; -use Locale::Country; -use Locale::SubCountry; use FS::UID qw(adminsuidsetup datasrc checkeuid getsecrets); +use FS::CurrentUser; use FS::Schema qw( dbdef_dist reload_dbdef ); use FS::Record; -use FS::cust_main_county; #use FS::raddb; -use FS::part_bill_event; +use FS::Setup qw(create_initial_data); die "Not running uid freeside!" unless checkeuid(); #my %attrib2db = # map { lc($FS::raddb::attrib{$_}) => $_ } keys %FS::raddb::attrib; -getopts("s"); -my $user = shift or die &usage; -getsecrets($user); +getopts("u:vd:"); +#my $user = shift or die &usage; + +getsecrets($opt_u); #$user); #needs to match FS::Record -my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc; +my($dbdef_file) = "%%%FREESIDE_CONF%%%/dbdef.". datasrc; ### @@ -88,12 +87,14 @@ $dbdef->save($dbdef_file); # create 'em ### -my $dbh = adminsuidsetup $user; +$FS::CurrentUser::upgrade_hack = 1; +my $dbh = adminsuidsetup $opt_u; #$user; #create tables $|=1; foreach my $statement ( $dbdef->sql($dbh) ) { + warn $statement if $statement =~ /TABLE cdr/; $dbh->do( $statement ) or die "CREATE error: ". $dbh->errstr. "\ndoing statement: $statement"; } @@ -104,69 +105,14 @@ dbdef_create($dbh, $dbdef_file); delete $FS::Schema::dbdef_cache{$dbdef_file}; #force an actual reload reload_dbdef($dbdef_file); -#cust_main_county -foreach my $country ( sort map uc($_), all_country_codes ) { - - my $subcountry = eval { new Locale::SubCountry($country) }; - my @states = $subcountry ? $subcountry->all_codes : undef; - - if ( !scalar(@states) || ( scalar(@states) == 1 && !defined($states[0]) ) ) { - - my $cust_main_county = new FS::cust_main_county({ - 'tax' => 0, - 'country' => $country, - }); - my $error = $cust_main_county->insert; - die $error if $error; - - } else { - - if ( $states[0] =~ /^(\d+|\w)$/ ) { - @states = map $subcountry->full_name($_), @states - } - - foreach my $state ( @states ) { +create_initial_data('domain' => $opt_d); - my $cust_main_county = new FS::cust_main_county({ - 'state' => $state, - 'tax' => 0, - 'country' => $country, - }); - my $error = $cust_main_county->insert; - die $error if $error; - - } - - } -} - -#billing events -foreach my $aref ( - #[ 'COMP', 'Comp invoice', '$cust_bill->comp();', 30, 'comp' ], - [ 'CARD', 'Batch card', '$cust_bill->batch_card();', 40, 'batch-card' ], - [ 'BILL', 'Send invoice', '$cust_bill->send();', 50, 'send' ], - [ 'DCRD', 'Send invoice', '$cust_bill->send();', 50, 'send' ], - [ 'DCHK', 'Send invoice', '$cust_bill->send();', 50, 'send' ], -) { - - my $part_bill_event = new FS::part_bill_event({ - 'payby' => $aref->[0], - 'event' => $aref->[1], - 'eventcode' => $aref->[2], - 'seconds' => 0, - 'weight' => $aref->[3], - 'plan' => $aref->[4], - }); - my($error); - $error=$part_bill_event->insert; - die $error if $error; - -} +warn "Freeside database initialized - commiting transaction\n" if $opt_v; $dbh->commit or die $dbh->errstr; $dbh->disconnect or die $dbh->errstr; -#print "Freeside database initialized sucessfully\n"; +warn "Database initialization committed successfully\n" if $opt_v; sub dbdef_create { # reverse engineer the schema from the DB and save to file my( $dbh, $file ) = @_; @@ -175,8 +121,10 @@ sub dbdef_create { # reverse engineer the schema from the DB and save to file } sub usage { - die "Usage:\n freeside-setup user\n"; + die "Usage:\n freeside-setup -d domain.name [ -v ]\n" + # [ -u user ] for devel/multi-db installs } 1; + diff --git a/FS/bin/freeside-sqlradius-radacctd b/FS/bin/freeside-sqlradius-radacctd index e98eaa015..83fd4bfd1 100644 --- a/FS/bin/freeside-sqlradius-radacctd +++ b/FS/bin/freeside-sqlradius-radacctd @@ -23,7 +23,7 @@ drop_root(); adminsuidsetup $user; -logfile( "/usr/local/etc/freeside/sqlradius-radacctd-log.". $FS::UID::datasrc ); +logfile( "%%%FREESIDE_LOG%%%/sqlradius-radacctd-log.". $FS::UID::datasrc ); daemonize2(); diff --git a/FS/bin/freeside-upgrade b/FS/bin/freeside-upgrade index 419384c2a..3a4e4f8e3 100755 --- a/FS/bin/freeside-upgrade +++ b/FS/bin/freeside-upgrade @@ -1,88 +1,45 @@ #!/usr/bin/perl -w use strict; +use vars qw($opt_d $opt_q $opt_v); use vars qw($DEBUG $DRY_RUN); -use Term::ReadKey; -use DBIx::DBSchema 0.27; +use Getopt::Std; +use DBIx::DBSchema 0.31; use FS::UID qw(adminsuidsetup checkeuid datasrc ); #getsecrets); +use FS::CurrentUser; use FS::Schema qw( dbdef dbdef_dist reload_dbdef ); +die "Not running uid freeside!" unless checkeuid(); -$DEBUG = 1; -$DRY_RUN = 0; +getopts("dq"); +$DEBUG = !$opt_q; +#$DEBUG = $opt_v; -die "Not running uid freeside!" unless checkeuid(); +$DRY_RUN = $opt_d; my $user = shift or die &usage; +$FS::CurrentUser::upgrade_hack = 1; my $dbh = adminsuidsetup($user); #needs to match FS::Schema... -my $dbdef_file = "/usr/local/etc/freeside/dbdef.". datasrc; +my $dbdef_file = "%%%FREESIDE_CONF%%%/dbdef.". datasrc; dbdef_create($dbh, $dbdef_file); delete $FS::Schema::dbdef_cache{$dbdef_file}; #force an actual reload reload_dbdef($dbdef_file); +$DBIx::DBSchema::DEBUG = $DEBUG; +$DBIx::DBSchema::Table::DEBUG = $DEBUG; -foreach my $table ( dbdef_dist->tables ) { - - if ( dbdef->table($table) ) { - - warn "$table exists\n" if $DEBUG > 1; - - foreach my $column ( dbdef_dist->table($table)->columns ) { - if ( dbdef->table($table)->column($column) ) { - warn " $table.$column exists\n" if $DEBUG > 2; - } else { - - if ( $DEBUG ) { - print STDERR "column $table.$column does not exist. create?"; - next unless yesno(); - } - - foreach my $statement ( - dbdef_dist->table($table)->column($column)->sql_add_column( $dbh ) - ) { - warn "$statement\n" if $DEBUG || $DRY_RUN; - unless ( $DRY_RUN ) { - $dbh->do( $statement) - or die "CREATE error: ". $dbh->errstr. "\nexecuting: $statement"; - } - } - - } - - } - - #should eventually check & create missing indices - - #should eventually drop columns not in dbdef_dist... - - } else { - - if ( $DEBUG ) { - print STDERR "table $table does not exist. create?"; - next unless yesno(); - } - - foreach my $statement ( - dbdef_dist->table($table)->sql_create_table( $dbh ) - ) { - warn "$statement\n" if $DEBUG || $DRY_RUN; - unless ( $DRY_RUN ) { - $dbh->do( $statement) - or die "CREATE error: ". $dbh->errstr. "\nexecuting: $statement"; - } - } - - } - +if ( $DRY_RUN ) { + print join(";\n", dbdef->sql_update_schema( dbdef_dist, $dbh ) ). ";\n"; + exit; +} else { + dbdef->update_schema( dbdef_dist, $dbh ); } -# should eventually drop tables not in dbdef_dist too i guess... - $dbh->commit or die $dbh->errstr; dbdef_create($dbh, $dbdef_file); @@ -91,32 +48,6 @@ $dbh->disconnect or die $dbh->errstr; ### -my $all = 0; -sub yesno { - print STDERR ' [yes/no/all] '; - if ( $all ) { - warn "yes\n"; - return 1; - } else { - while ( 1 ) { - ReadMode 4; - my $x = lc(ReadKey); - ReadMode 0; - if ( $x eq 'n' ) { - warn "no\n"; - return 0; - } elsif ( $x eq 'y' ) { - warn "yes\n"; - return 1; - } elsif ( $x eq 'a' ) { - warn "yes\n"; - $all = 1; - return 1; - } - } - } -} - sub dbdef_create { # reverse engineer the schema from the DB and save to file my( $dbh, $file ) = @_; my $dbdef = new_native DBIx::DBSchema $dbh; @@ -124,8 +55,31 @@ sub dbdef_create { # reverse engineer the schema from the DB and save to file } sub usage { - die "Usage:\n freeside-upgrade user\n"; + die "Usage:\n freeside-upgrade [ -d ] [ -q | -v ] user\n"; } -1; +=head1 NAME + +freeside-upgrade - Upgrades database schema for new freeside verisons. + +=head1 SYNOPSIS + + freeside-adduser [ -d ] [ -q | -v ] + +=head1 DESCRIPTION + +Reads your existing database schema and updates it to match the current schema, +adding any columns or tables necessary. + + [ -d ]: Dry run; output SQL statements (to STDOUT) only, but do not execute + them. + + [ -q ]: Run quietly. This may become the default at some point. + + [ -v ]: Run verbosely, sending debugging information to STDERR. This is the + current default. + +=head1 SEE ALSO + +=cut |