From 5c0de69821c0145e89403e173986b4d8b5b52725 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 5 Oct 2002 11:14:08 +0000 Subject: fix sqlradius export to not set blank id fields --- FS/FS/part_export/sqlradius.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/part_export/sqlradius.pm b/FS/FS/part_export/sqlradius.pm index 0f93703ae..ccf9a7687 100644 --- a/FS/FS/part_export/sqlradius.pm +++ b/FS/FS/part_export/sqlradius.pm @@ -207,7 +207,7 @@ sub sqlradius_usergroup_insert { #subroutine, not method "INSERT INTO usergroup ( UserName, GroupName ) VALUES ( ?, ? )" ) or die $dbh->errstr; foreach my $group ( @groups ) { - $sth->execute( '', $username, $group ) + $sth->execute( $username, $group ) or die "can't insert into groupname table: ". $sth->errstr; } $dbh->disconnect; -- cgit v1.2.1 From 656b802d26a8eb0dfd6fd71dbcdebfab156041e9 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 7 Oct 2002 08:47:10 +0000 Subject: cancel when it is *after* expiration date, not when it is *before* --- FS/bin/freeside-daily | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/bin/freeside-daily b/FS/bin/freeside-daily index 52028b773..17ee798ff 100755 --- a/FS/bin/freeside-daily +++ b/FS/bin/freeside-daily @@ -30,7 +30,7 @@ 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 + grep { $_->expire && $_->expire <= $^T } $cust_main->ncancelled_pkgs ) { my $error = $cust_pkg->cancel; warn "Error cancelling expired pkg ". $cust_pkg->pkgnum. " for custnum ". -- cgit v1.2.1 From b97ccb2b958567490841cfc93d2c4a401d98cdb0 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 8 Oct 2002 04:46:40 +0000 Subject: payby-default config option, with special "HIDE" option to disable billing information in the web interface (closes: Bug#468) --- FS/FS/Conf.pm | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'FS') diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 788127a7f..1c4ad04a3 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -952,6 +952,15 @@ httemplate/docs/config.html 'select_enum' => [ 'text/plain', 'text/html' ], }, + { + 'key' => 'payby-default', + 'section' => 'UI', + 'description' => 'Default payment type. HIDE disables display of billing information and sets customers to BILL.', + 'type' => 'select', + 'select_enum' => [ '', 'CARD', 'BILL', 'COMP', 'HIDE' ], + }, + + ); 1; -- cgit v1.2.1 From 69f92e8567d1952bc4cbf29d944b97051467bd11 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 8 Oct 2002 08:33:27 +0000 Subject: svc_acct-notes displays static HTML on account view (closes: Bug#465) --- FS/FS/Conf.pm | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'FS') diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 1c4ad04a3..3fdaf218a 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -960,6 +960,12 @@ httemplate/docs/config.html 'select_enum' => [ '', 'CARD', 'BILL', 'COMP', 'HIDE' ], }, + { + 'key' => 'svc_acct-notes', + 'section' => 'UI', + 'description' => 'Extra HTML to be displayed on the Account View screen.', + 'type' => 'textarea', + }, ); -- cgit v1.2.1 From 3fcc6847417cbda9fd027a4286db5e59aea6d901 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 9 Oct 2002 13:07:54 +0000 Subject: radius-password config value to set the attribute used for plaintext pw's --- FS/FS/Conf.pm | 8 ++++++++ FS/FS/svc_acct.pm | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 3fdaf218a..4dd80c121 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -967,6 +967,14 @@ httemplate/docs/config.html 'type' => 'textarea', }, + { + 'key' => 'raidus-password', + 'section' => 'unclassified', + 'description' => 'RADIUS attribute for plain-text passwords.', + 'type' => 'select', + 'select_enum' => [ 'Password', 'User-Password' ], + }, + ); 1; diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index 6c0807df2..b5ade6fac 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -9,6 +9,7 @@ use vars qw( @ISA $noexport_hack $conf $username_uppercase $welcome_template $welcome_from $welcome_subject $welcome_mimetype $smtpmachine + $radius_password $dirhash @saltset @pw_set ); use Carp; @@ -60,6 +61,7 @@ $FS::UID::callback{'FS::svc_acct'} = sub { $welcome_template = ''; } $smtpmachine = $conf->config('smtpmachine'); + $radius_password = $conf->config('radius-password') || 'Password'; }; @saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' ); @@ -858,7 +860,7 @@ expected to change in the future. sub radius_check { my $self = shift; my $password = $self->_password; - my $pw_attrib = length($password) <= 12 ? 'Password' : 'Crypt-Password'; + my $pw_attrib = length($password) <= 12 ? $radius_password : 'Crypt-Password'; ( $pw_attrib => $password, map { /^(rc_(.*))$/; -- cgit v1.2.1 From 229c7bbe00221452e62e81f2e34d8f126fb4b47e Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 9 Oct 2002 13:43:07 +0000 Subject: don't error out trying to create existing directories in vpopmail export --- FS/FS/part_export/vpopmail.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'FS') diff --git a/FS/FS/part_export/vpopmail.pm b/FS/FS/part_export/vpopmail.pm index 561e2742a..2ca44016a 100644 --- a/FS/FS/part_export/vpopmail.pm +++ b/FS/FS/part_export/vpopmail.pm @@ -106,8 +106,8 @@ sub vpopmail_insert { #subroutine, not method close(VPASSWD); for my $mkdir ( - map { "$exportdir/domains/$domain/$username$_" } - ( '', qw( /Maildir /Maildir/cur /Maildir/new /Maildir/tmp ) ) + grep { ! -d $_ } map { "$exportdir/domains/$domain/$username$_" } + ( '', qw( /Maildir /Maildir/cur /Maildir/new /Maildir/tmp ) ) ) { mkdir $mkdir, 0700 or die "can't mkdir $mkdir: $!"; } -- cgit v1.2.1 From e34a817fc92eda8b6f9596b3a925c40bfb7e3887 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 9 Oct 2002 13:59:44 +0000 Subject: don't explicitly specify unclassified config section --- FS/FS/Conf.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 4dd80c121..6d21802c8 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -969,7 +969,7 @@ httemplate/docs/config.html { 'key' => 'raidus-password', - 'section' => 'unclassified', + 'section' => '', 'description' => 'RADIUS attribute for plain-text passwords.', 'type' => 'select', 'select_enum' => [ 'Password', 'User-Password' ], -- cgit v1.2.1 From 0288a8d21086022a4b867aa5a8853bec47171ec2 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 9 Oct 2002 14:30:02 +0000 Subject: nasty typo --- FS/FS/Conf.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 6d21802c8..20e42183b 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -968,7 +968,7 @@ httemplate/docs/config.html }, { - 'key' => 'raidus-password', + 'key' => 'radius-password', 'section' => '', 'description' => 'RADIUS attribute for plain-text passwords.', 'type' => 'select', -- cgit v1.2.1 From eb9d5b215af1fbe867b75c12328126f650f9fb06 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 12 Oct 2002 10:15:55 +0000 Subject: ACH support --- FS/FS/Conf.pm | 4 +-- FS/FS/cust_bill.pm | 73 ++++++++++++++++++++++++++++++++++-------------- FS/FS/cust_main.pm | 20 +++++++++---- FS/FS/cust_pay.pm | 7 +++-- FS/FS/cust_refund.pm | 7 +++-- FS/FS/part_bill_event.pm | 2 +- 6 files changed, 77 insertions(+), 36 deletions(-) (limited to 'FS') diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 20e42183b..204d26af3 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -870,7 +870,7 @@ httemplate/docs/config.html 'section' => '', 'description' => 'Acceptable payment types for the signup server', 'type' => 'selectmultiple', - 'select_enum' => [ qw(CARD PREPAY BILL COMP) ], + 'select_enum' => [ qw(CARD CHEK PREPAY BILL COMP) ], }, { @@ -957,7 +957,7 @@ httemplate/docs/config.html 'section' => 'UI', 'description' => 'Default payment type. HIDE disables display of billing information and sets customers to BILL.', 'type' => 'select', - 'select_enum' => [ '', 'CARD', 'BILL', 'COMP', 'HIDE' ], + 'select_enum' => [ '', qw(CARD CHEK BILL COMP HIDE) ], }, { diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 296c8b6a6..e875f5229 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -583,32 +583,48 @@ sub comp { =item realtime_card -Attempts to pay this invoice with a Business::OnlinePayment realtime gateway. -See http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment -for supproted processors. +Attempts to pay this invoice with a credit card payment via a +Business::OnlinePayment realtime gateway. See +http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment +for supported processors. =cut sub realtime_card { my $self = shift; + $self->realtime_bop('CC', @_); +} + +=item realtime_ach + +Attempts to pay this invoice with an electronic check (ACH) payment via a +Business::OnlinePayment realtime gateway. See +http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment +for supported processors. + +=cut + +sub realtime_ach { + my $self = shift; + $self->realtime_bop('ECHECK', @_); +} + +sub realtime_bop { + my $self = shift; + my $method = shift; my $cust_main = $self->cust_main; my $amount = $self->owed; unless ( $processor =~ /^Business::OnlinePayment::(.*)$/ ) { - return "Real-time card processing not enabled (processor $processor)"; + return "Real-time card/ACH processing not enabled (processor $processor)"; } my $bop_processor = $1; #hmm? my $address = $cust_main->address1; $address .= ", ". $cust_main->address2 if $cust_main->address2; - #fix exp. date - #$cust_main->paydate =~ /^(\d+)\/\d*(\d{2})$/; - $cust_main->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; - my $exp = "$2/$1"; - my($payname, $payfirst, $paylast); - if ( $cust_main->payname ) { + if ( $cust_main->payname && $method ne 'ECHECK' ) { $payname = $cust_main->payname; $payname =~ /^\s*([\w \,\.\-\']*)?\s+([\w\,\.\-\']+)\s*$/ or do { @@ -646,11 +662,24 @@ sub realtime_card { $description = eval qq("$dtempl"); } + + my %content; + if ( $method eq 'CC' ) { + $content{card_number} = $cust_main->payinfo; + $cust_main->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; + $content{expiration} = "$2/$1"; + } elsif ( $method eq 'ECHECK' ) { + my($account_number,$routing_code) = $cust_main->payinfo + ( $content{account_number}, $content{routing_code} ) = + split('@', $cust_main->payinfo); + $content{bank_name} = $cust_main->payname; + } my $transaction = new Business::OnlinePayment( $bop_processor, @bop_options ); $transaction->content( - 'type' => 'CC', + %content, + 'type' => $method, 'login' => $bop_login, 'password' => $bop_password, 'action' => $action1, @@ -666,8 +695,6 @@ sub realtime_card { 'state' => $cust_main->state, 'zip' => $cust_main->zip, 'country' => $cust_main->country, - 'card_number' => $cust_main->payinfo, - 'expiration' => $exp, 'referer' => 'http://cleanwhisker.420.am/', 'email' => $email, 'phone' => $cust_main->daytime || $cust_main->night, @@ -686,7 +713,8 @@ sub realtime_card { new Business::OnlinePayment( $bop_processor, @bop_options ); my %capture = ( - type => 'CC', + %content, + type => $method, action => $action2, login => $bop_login, password => $bop_password, @@ -694,8 +722,6 @@ sub realtime_card { amount => $amount, authorization => $auth, description => $description, - card_number => $cust_main->payinfo, - expiration => $exp, ); foreach my $field (qw( authorization_source_code returned_ACI transaction_identifier validation_code @@ -720,18 +746,23 @@ sub realtime_card { if ( $transaction->is_success() ) { + my %method2payby = ( + 'CC' => 'CARD', + 'ECHECK' => 'CHEK', + ); + my $cust_pay = new FS::cust_pay ( { 'invnum' => $self->invnum, 'paid' => $amount, '_date' => '', - 'payby' => 'CARD', + 'payby' => method2payby{$method}, 'payinfo' => $cust_main->payinfo, 'paybatch' => "$processor:". $transaction->authorization, } ); my $error = $cust_pay->insert; if ( $error ) { # gah, even with transactions. - my $e = 'WARNING: Card debited but database not updated - '. + my $e = 'WARNING: Card/ACH debited but database not updated - '. 'error applying payment, invnum #' . $self->invnum. " ($processor): $error"; warn $e; @@ -766,7 +797,7 @@ sub realtime_card { "Sender: $invoice_from", "Reply-To: $invoice_from", "Date: ". time2str("%a, %d %b %Y %X %z", time), - "Subject: Your credit card could not be processed", + "Subject: Your payment could not be processed", ] ); my $message = new Mail::Internet ( 'Header' => $header, @@ -838,7 +869,7 @@ sub print_text { # my $invnum = $self->invnum; my $cust_main = qsearchs('cust_main', { 'custnum', $self->custnum } ); $cust_main->payname( $cust_main->first. ' '. $cust_main->getfield('last') ) - unless $cust_main->payname; + unless $cust_main->payname && $cust_main->payby ne 'CHEK'; my( $pr_total, @pr_cust_bill ) = $self->previous; #previous balance # my( $cr_total, @cr_cust_credit ) = $self->cust_credit; #credits @@ -1043,7 +1074,7 @@ sub print_text { =head1 VERSION -$Id: cust_bill.pm,v 1.47 2002-10-04 12:09:21 ivan Exp $ +$Id: cust_bill.pm,v 1.48 2002-10-12 10:15:55 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 2701ac35d..d6e4bc1e3 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -158,7 +158,7 @@ FS::Record. The following fields are currently supported: =item ship_fax - phone (optional) -=item payby - `CARD' (credit cards), `BILL' (billing), `COMP' (free), or `PREPAY' (special billing type: applies a credit - see L and sets billing type to BILL) +=item payby - `CARD' (credit cards), `CHEK' (electronic check), `BILL' (billing), `COMP' (free), or `PREPAY' (special billing type: applies a credit - see L and sets billing type to BILL) =item payinfo - card number, P.O., comp issuer (4-8 lowercase alphanumerics; think username) or prepayment identifier (see L) @@ -482,9 +482,9 @@ sub replace { $self->invoicing_list( $invoicing_list ); } - if ( $self->payby eq 'CARD' && + if ( $self->payby =~ /^(CARD|CHEK)$/ && grep { $self->get($_) ne $old->get($_) } qw(payinfo paydate payname) ) { - # card info has changed, want to retry realtime_card invoice events + # card/check info has changed, want to retry realtime_card invoice events #false laziness w/collect foreach my $cust_bill_event ( grep { @@ -664,7 +664,7 @@ sub check { } } - $self->payby =~ /^(CARD|BILL|COMP|PREPAY)$/ + $self->payby =~ /^(CARD|CHEK|BILL|COMP|PREPAY)$/ or return "Illegal payby: ". $self->payby; $self->payby($1); @@ -681,6 +681,14 @@ sub check { return gettext('unknown_card_type') if cardtype($self->payinfo) eq "Unknown"; + } elsif ( $self->payby eq 'CHEK' ) { + + my $payinfo = $self->payinfo; + $payinfo =~ s/[\D\@]//g; + $payinfo =~ /^(\d+)\@(\d{9})$/ or return 'invalid echeck account@aba'; + $payinfo = "$1\@$2"; + $self->payinfo($payinfo); + } elsif ( $self->payby eq 'BILL' ) { $error = $self->ut_textn('payinfo'); @@ -705,7 +713,7 @@ sub check { if ( $self->paydate eq '' || $self->paydate eq '-' ) { return "Expriation date required" - unless $self->payby eq 'BILL' || $self->payby eq 'PREPAY'; + unless $self->payby =~ /^(BILL|PREPAY|CHEK)$/; $self->paydate(''); } else { $self->paydate =~ /^(\d{1,2})[\/\-](\d{2}(\d{2})?)$/ @@ -717,7 +725,7 @@ sub check { if !$import && ( $y<$nowy || ( $y==$nowy && $1<$nowm ) ); } - if ( $self->payname eq '' && + if ( $self->payname eq '' && $self->payby ne 'CHEK' && ( ! $conf->exists('require_cardname') || $self->payby ne 'CARD' ) ) { $self->payname( $self->first. " ". $self->getfield('last') ); } else { diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index 98eba704b..222691408 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -60,7 +60,8 @@ currently supported: =item _date - specified as a UNIX timestamp; see L. Also see L and L for conversion functions. -=item payby - `CARD' (credit cards), `BILL' (billing), or `COMP' (free) +=item payby - `CARD' (credit cards), `CHEK' (electronic check/ACH), +`BILL' (billing), or `COMP' (free) =item payinfo - card number, check #, or comp issuer (4-8 lowercase alphanumerics; think username), respectively @@ -346,7 +347,7 @@ sub check { $self->_date(time) unless $self->_date; - $self->payby =~ /^(CARD|BILL|COMP)$/ or return "Illegal payby"; + $self->payby =~ /^(CARD|CHEK|BILL|COMP)$/ or return "Illegal payby"; $self->payby($1); #false laziness with cust_refund::check @@ -405,7 +406,7 @@ sub unapplied { =head1 VERSION -$Id: cust_pay.pm,v 1.21 2002-06-04 14:35:52 ivan Exp $ +$Id: cust_pay.pm,v 1.22 2002-10-12 10:15:55 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_refund.pm b/FS/FS/cust_refund.pm index 8fe6876d3..aac320e61 100644 --- a/FS/FS/cust_refund.pm +++ b/FS/FS/cust_refund.pm @@ -47,7 +47,8 @@ inherits from FS::Record. The following fields are currently supported: =item _date - specified as a UNIX timestamp; see L. Also see L and L for conversion functions. -=item payby - `CARD' (credit cards), `BILL' (billing), or `COMP' (free) +=item payby - `CARD' (credit cards), `CHEK' (electronic check/ACH), +`BILL' (billing), or `COMP' (free) =item payinfo - card number, P.O.#, or comp issuer (4-8 lowercase alphanumerics; think username) @@ -234,7 +235,7 @@ sub check { unless $self->crednum || qsearchs( 'cust_main', { 'custnum' => $self->custnum } ); - $self->payby =~ /^(CARD|BILL|COMP)$/ or return "Illegal payby"; + $self->payby =~ /^(CARD|CHEK|BILL|COMP)$/ or return "Illegal payby"; $self->payby($1); #false laziness with cust_pay::check @@ -266,7 +267,7 @@ sub check { =head1 VERSION -$Id: cust_refund.pm,v 1.18 2002-02-19 03:22:39 jeff Exp $ +$Id: cust_refund.pm,v 1.19 2002-10-12 10:15:55 ivan Exp $ =head1 BUGS diff --git a/FS/FS/part_bill_event.pm b/FS/FS/part_bill_event.pm index a31b09b36..991616bb8 100644 --- a/FS/FS/part_bill_event.pm +++ b/FS/FS/part_bill_event.pm @@ -124,7 +124,7 @@ sub check { $c =~ /^\s*\$cust_main\->(suspend|cancel|invoicing_list_addpost|bill|collect)\(\);\s*("";)?\s*$/ - or $c =~ /^\s*\$cust_bill\->(comp|realtime_card|realtime_card_cybercash|batch_card|send)\(\);\s*$/ + or $c =~ /^\s*\$cust_bill\->(comp|realtime_card|realtime_ach|realtime_card_cybercash|batch_card|send)\(\);\s*$/ or $c =~ /^\s*\$cust_bill\->send\(\'\w+\'\);\s*$/ -- cgit v1.2.1 From 6f8a6c416174bcf8095c959085d14ba820425aad Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 12 Oct 2002 13:26:46 +0000 Subject: sqlradacct_hour price plan to charge per-hour against an external radacct table --- FS/FS/cust_pkg.pm | 41 ++++++++++++++++++++++++-- FS/FS/cust_svc.pm | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- FS/FS/svc_acct.pm | 27 +++++++++++++++-- 3 files changed, 150 insertions(+), 5 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 0c71435e1..b16d08137 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -475,7 +475,7 @@ sub cust_main { =item seconds_since TIMESTAMP Returns the number of seconds all accounts (see L) in this -package have been online since TIMESTAMP. +package have been online since TIMESTAMP, according to the session monitor. TIMESTAMP is specified as a UNIX timestamp; see L. Also see L and L for conversion functions. @@ -496,6 +496,43 @@ sub seconds_since { } +=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END DATASRC DB_USERNAME DB_PASSWORD + +Returns the numbers of seconds all accounts (see L) in this +package have been online between TIMESTAMP_START (inclusive) and TIMESTAMP_END +(exclusive), according to an external SQL radacct table, such as those +generated by ICRADIUS or FreeRADIUS. Sessions which started in the specified +range but are still open are counted from session start to the end of the +range. Also, sessions which end in the range but started earlier are counted +from the start of the range to session end. Finally, sessions which start +before the range but end after (or are still open) are counted for the entire +range. + +TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see +L. Also see L and L for conversion +functions. + + +=cut + +sub seconds_since_sqlradacct { + my($self, $start, $end, $datasrc, $db_user, $db_pass) = @_; + + my $dbh = DBI->connect($datasrc, $db_user, $db_pass) + or die "can't connect to $datasrc: ". $DBI::errstr; + + my $seconds = 0; + + foreach my $cust_svc ( + grep { $_->part_svc->svcdb eq 'svc_acct' } $self->cust_svc + ) { + $seconds += $cust_svc->seconds_since_sqlradacct($start, $end, $dbh); + } + + $seconds; + +} + =back =head1 SUBROUTINES @@ -678,7 +715,7 @@ sub order { =head1 VERSION -$Id: cust_pkg.pm,v 1.24 2002-09-17 09:19:06 ivan Exp $ +$Id: cust_pkg.pm,v 1.25 2002-10-12 13:26:45 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index 9d510b38a..4fc663450 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -336,11 +336,93 @@ sub seconds_since { $sth->fetchrow_arrayref->[0]; } +=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END ( DBI_DATABASE_HANDLE | DATASRC DB_USERNAME DB_PASSWORD ) + +See L. Equivalent to +$cust_svc->svc_x->seconds_since, but more efficient. Meaningless for records +where B is not "svc_acct". + +NOTE: specifying a DATASRC/USERNAME/PASSWORD instead of a DBI database handle +is not yet implemented. + +=cut + +#note: implementation here, POD in FS::svc_acct +sub seconds_since_sqlradacct { + my($self, $start, $end, $dbh) = @_; + + my $username = $self->svc_x->username; + + #select a unix time conversion function based on database type + my $str2time; + if ( $dbh->{Driver}->{Name} eq 'mysql' ) { + $str2time = 'UNIX_TIMESTAMP('; + } elsif ( $dbh->{Driver}->{Name} eq 'Pg' ) { + $str2time = 'EXTRACT( EPOCH FROM '; + } else { + warn "warning: unknown database type ". $dbh->{Driver}->{Name}. + "; guessing how to convert to UNIX timestamps"; + $str2time = 'extract(epoch from '; + } + + #find sessions completely within the given range + my $sth = $dbh->prepare("SELECT SUM(acctsessiontime) + FROM radacct + WHERE UserName = ? + AND $str2time AcctStartTime) >= ? + AND $str2time AcctStopTime ) < ? + AND AcctStopTime =! 0 + AND AcctStopTime IS NOT NULL" + ) or die $dbh->errstr; + $sth->execute($username, $start, $end) or die $sth->errstr; + my $regular = $sth->fetchrow_arrayref->[0]; + + #find open sessions which start in the range, count session start->range end + $sth = $dbh->prepare("SELECT SUM( ? - $str2time AcctStartTime ) ) + FROM radacct + WHERE UserName = ? + AND AcctStartTime >= ? + AND ( AcctStopTime = 0 + OR AcctStopTime IS NULL )" + ) or die $dbh->errstr; + $sth->execute($end, $username, $start) or die $sth->errstr; + my $start_during = $sth->fetchrow_arrayref->[0]; + + #find closed sessions which start before the range but stop during, + #count range start->session end + $sth = $dbh->prepare("SELECT SUM( $str2time AcctStopTime ) - ? ) + FROM radacct + WHERE UserName = ? + AND AcctStartTime < ? + AND AcctStopTime >= ? + AND AcctStopTime < ? + AND AcctStopTime != 0 + AND AcctStopTime IS NOT NULL" + ) or die $dbh->errstr; + $sth->execute($start, $username, $start, $start, $end ) or die $sth->errstr; + my $end_during = $sth->fetchrow_arrayref->[0]; + + #find closed or open sessions which start before the range but stop + # after, or are still open, count range start->range end + $sth = $dbh->prepare("SELECT COUNT(*) + FROM radacct + WHERE UserName = ? + AND AcctStartTime < ? + AND ( AcctStopTime >= ? + OR AcctStopTime = 0 + OR AcctStopTime IS NULL )" + ) or die $dbh->errstr; + $sth->execute($username, $start, $end ) or die $sth->errstr; + my $entire_range = ($end-$start) * $sth->fetchrow_arrayref->[0]; + + $regular + $end_during + $start_during + $entire_range; +} + =back =head1 VERSION -$Id: cust_svc.pm,v 1.17 2002-09-18 22:39:01 ivan Exp $ +$Id: cust_svc.pm,v 1.18 2002-10-12 13:26:45 ivan Exp $ =head1 BUGS @@ -352,6 +434,9 @@ pkg_svc records are not checked in general (here). Deleting this record doesn't check or delete the svc_* record associated with this record. +In seconds_since_sqlradacct, specifying a DATASRC/USERNAME/PASSWORD instead of +a DBI database handle is not yet implemented. + =head1 SEE ALSO L, L, L, L, diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index b5ade6fac..3afee7f64 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -921,8 +921,8 @@ sub email { =item seconds_since TIMESTAMP -Returns the number of seconds this account has been online since TIMESTAMP. -See L +Returns the number of seconds this account has been online since TIMESTAMP, +according to the session monitor (see L). TIMESTAMP is specified as a UNIX timestamp; see L. Also see L and L for conversion functions. @@ -935,6 +935,29 @@ sub seconds_since { $self->cust_svc->seconds_since(@_); } +=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END DATASRC DB_USERNAME DB_PASSWORD + +Returns the numbers of seconds this account has been online between +TIMESTAMP_START (inclusive) and TIMESTAMP_END (exclusive), according to an +external SQL radacct table, such as those generated by ICRADIUS or FreeRADIUS. +Sessions which started in the specified range but are still open are counted +from session start to the end of the range. Also, sessions which end in the +range but started earlier are counted from the start of the range to session +end. Finally, sessions which start before the range but end after (or are +still open) are counted for the entire range. + +TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see +L. Also see L and L for conversion +functions. + +=cut + +#note: POD here, implementation in FS::cust_svc +sub seconds_since_sqlradacct { + my $self = shift; + $self->cust_svc->seconds_since_sqlradacct(@_); +} + =item radius_groups Returns all RADIUS groups for this account (see L). -- cgit v1.2.1 From ec8b028d52fea91a4f970c0be377eaccde682997 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 13 Oct 2002 01:05:29 +0000 Subject: bug fix in new ACH code --- FS/FS/cust_bill.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index e875f5229..bdd60dbe0 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -669,7 +669,7 @@ sub realtime_bop { $cust_main->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; $content{expiration} = "$2/$1"; } elsif ( $method eq 'ECHECK' ) { - my($account_number,$routing_code) = $cust_main->payinfo + my($account_number,$routing_code) = $cust_main->payinfo; ( $content{account_number}, $content{routing_code} ) = split('@', $cust_main->payinfo); $content{bank_name} = $cust_main->payname; @@ -1074,7 +1074,7 @@ sub print_text { =head1 VERSION -$Id: cust_bill.pm,v 1.48 2002-10-12 10:15:55 ivan Exp $ +$Id: cust_bill.pm,v 1.49 2002-10-13 01:05:29 ivan Exp $ =head1 BUGS -- cgit v1.2.1 From 80b9d734807f0358403c47dfa3d86fb80f75cdd0 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 13 Oct 2002 01:14:34 +0000 Subject: change ILIKE into LOWER() for compatibility with non-Pg and Pg before 7.1 --- FS/FS/Record.pm | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'FS') diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index a23f37a62..ebcbbb497 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -208,34 +208,40 @@ sub qsearch { $statement .= ' WHERE '. join(' AND ', map { my $op = '='; + my $column = $_; if ( ref($record->{$_}) ) { $op = $record->{$_}{'op'} if $record->{$_}{'op'}; - $op = 'LIKE' if $op =~ /^ILIKE$/i && driver_name ne 'Pg'; + #$op = 'LIKE' if $op =~ /^ILIKE$/i && driver_name ne 'Pg'; + if ( uc($op) eq 'ILIKE' ) { + $op = 'LIKE'; + $record->{$_}{'value'} = lc($record->{$_}{'value'}); + $column = "LOWER($_)"; + } $record->{$_} = $record->{$_}{'value'} } if ( ! defined( $record->{$_} ) || $record->{$_} eq '' ) { if ( $op eq '=' ) { if ( driver_name eq 'Pg' ) { - qq-( $_ IS NULL OR $_ = '' )-; + qq-( $column IS NULL OR $column = '' )-; } else { - qq-( $_ IS NULL OR $_ = "" )-; + qq-( $column IS NULL OR $column = "" )-; } } elsif ( $op eq '!=' ) { if ( driver_name eq 'Pg' ) { - qq-( $_ IS NOT NULL AND $_ != '' )-; + qq-( $column IS NOT NULL AND $column != '' )-; } else { - qq-( $_ IS NOT NULL AND $_ != "" )-; + qq-( $column IS NOT NULL AND $column != "" )-; } } else { if ( driver_name eq 'Pg' ) { - qq-( $_ $op '' )-; + qq-( $column $op '' )-; } else { - qq-( $_ $op "" )-; + qq-( $column $op "" )-; } } } else { - "$_ $op ?"; + "$column $op ?"; } } @fields ); } -- cgit v1.2.1 From 7bb23c47594c1111aecb5fe8fdb2042e509cca86 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 14 Oct 2002 06:17:14 +0000 Subject: fix sql radacct billing --- FS/FS/cust_pkg.pm | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index b16d08137..803fa3c16 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -9,6 +9,7 @@ use FS::part_pkg; use FS::cust_main; use FS::type_pkgs; use FS::pkg_svc; +use FS::cust_bill_pkg; # need to 'use' these instead of 'require' in sub { cancel, suspend, unsuspend, # setup } @@ -90,7 +91,7 @@ inherits from FS::Record. The following fields are currently supported: =item setup - date -=item bill - date +=item bill - date (next bill date) =item susp - date @@ -418,6 +419,20 @@ sub unsuspend { ''; #no errors } +=item last_bill + +Returns the last bill date, or if there is no last bill date, the setup date. +Useful for billing metered services. + +=cut + +sub last_bill { + my $self = shift; + my $cust_bill_pkg = qsearchs('cust_bill_pkg', { 'pkgnum' => $self->pkgnum, + 'edate' => $self->bill, } ); + $cust_bill_pkg ? $cust_bill_pkg->sdate : $self->setup || 0; +} + =item part_pkg Returns the definition for this billing item, as an FS::part_pkg object (see @@ -715,7 +730,7 @@ sub order { =head1 VERSION -$Id: cust_pkg.pm,v 1.25 2002-10-12 13:26:45 ivan Exp $ +$Id: cust_pkg.pm,v 1.26 2002-10-14 06:17:14 ivan Exp $ =head1 BUGS -- cgit v1.2.1 From ab6a6774557598dc7cdfc57c941a4bf48f3bb64a Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 14 Oct 2002 07:30:30 +0000 Subject: svc-acct-alldomains config file allows selection of accounts from any domain --- FS/FS/Conf.pm | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'FS') diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 204d26af3..c4d1a39d2 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -975,6 +975,13 @@ httemplate/docs/config.html 'select_enum' => [ 'Password', 'User-Password' ], }, + { + 'key' => 'svc_acct-alldomains', + 'section' => '', + 'description' => 'Allow accounts to select any domain in the database. Normally accounts can only select from the domain set in the service definition and those purchased by the customer.', + 'type' => 'bool', + }, + ); 1; -- cgit v1.2.1 From 196f70d25dc9dda5c765ab534734c307644dee0c Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 14 Oct 2002 07:44:50 +0000 Subject: s/bool/checkbox/ --- FS/FS/Conf.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index c4d1a39d2..cf874aa35 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -979,7 +979,7 @@ httemplate/docs/config.html 'key' => 'svc_acct-alldomains', 'section' => '', 'description' => 'Allow accounts to select any domain in the database. Normally accounts can only select from the domain set in the service definition and those purchased by the customer.', - 'type' => 'bool', + 'type' => 'checkbox', }, ); -- cgit v1.2.1 From 88d237b8fe396b4e85a16e20eccfeb4e22e94e24 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 15 Oct 2002 09:54:24 +0000 Subject: ach fix s/ECHECK/CHECK/ --- FS/FS/cust_bill.pm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index bdd60dbe0..54641ee35 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -606,7 +606,7 @@ for supported processors. sub realtime_ach { my $self = shift; - $self->realtime_bop('ECHECK', @_); + $self->realtime_bop('CHECK', @_); } sub realtime_bop { @@ -624,7 +624,7 @@ sub realtime_bop { $address .= ", ". $cust_main->address2 if $cust_main->address2; my($payname, $payfirst, $paylast); - if ( $cust_main->payname && $method ne 'ECHECK' ) { + if ( $cust_main->payname && $method ne 'CHECK' ) { $payname = $cust_main->payname; $payname =~ /^\s*([\w \,\.\-\']*)?\s+([\w\,\.\-\']+)\s*$/ or do { @@ -668,7 +668,7 @@ sub realtime_bop { $content{card_number} = $cust_main->payinfo; $cust_main->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; $content{expiration} = "$2/$1"; - } elsif ( $method eq 'ECHECK' ) { + } elsif ( $method eq 'CHECK' ) { my($account_number,$routing_code) = $cust_main->payinfo; ( $content{account_number}, $content{routing_code} ) = split('@', $cust_main->payinfo); @@ -747,8 +747,8 @@ sub realtime_bop { if ( $transaction->is_success() ) { my %method2payby = ( - 'CC' => 'CARD', - 'ECHECK' => 'CHEK', + 'CC' => 'CARD', + 'CHECK' => 'CHEK', ); my $cust_pay = new FS::cust_pay ( { @@ -1074,7 +1074,7 @@ sub print_text { =head1 VERSION -$Id: cust_bill.pm,v 1.49 2002-10-13 01:05:29 ivan Exp $ +$Id: cust_bill.pm,v 1.50 2002-10-15 09:54:24 ivan Exp $ =head1 BUGS -- cgit v1.2.1 From acfb0f48c226a5cba64fbe391677391128a6cbf7 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 17 Oct 2002 14:16:17 +0000 Subject: radacct update: use sqlradius for datasrc, not plandata options (whew) --- FS/FS/cust_pkg.pm | 19 ++----- FS/FS/cust_svc.pm | 150 ++++++++++++++++++++++++++++++------------------------ FS/FS/part_svc.pm | 15 +++--- FS/FS/svc_acct.pm | 15 +++--- 4 files changed, 105 insertions(+), 94 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 803fa3c16..55ee37d9d 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -511,17 +511,11 @@ sub seconds_since { } -=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END DATASRC DB_USERNAME DB_PASSWORD +=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END Returns the numbers of seconds all accounts (see L) in this package have been online between TIMESTAMP_START (inclusive) and TIMESTAMP_END -(exclusive), according to an external SQL radacct table, such as those -generated by ICRADIUS or FreeRADIUS. Sessions which started in the specified -range but are still open are counted from session start to the end of the -range. Also, sessions which end in the range but started earlier are counted -from the start of the range to session end. Finally, sessions which start -before the range but end after (or are still open) are counted for the entire -range. +(exclusive). TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see L. Also see L and L for conversion @@ -531,17 +525,14 @@ functions. =cut sub seconds_since_sqlradacct { - my($self, $start, $end, $datasrc, $db_user, $db_pass) = @_; - - my $dbh = DBI->connect($datasrc, $db_user, $db_pass) - or die "can't connect to $datasrc: ". $DBI::errstr; + my($self, $start, $end) = @_; my $seconds = 0; foreach my $cust_svc ( grep { $_->part_svc->svcdb eq 'svc_acct' } $self->cust_svc ) { - $seconds += $cust_svc->seconds_since_sqlradacct($start, $end, $dbh); + $seconds += $cust_svc->seconds_since_sqlradacct($start, $end); } $seconds; @@ -730,7 +721,7 @@ sub order { =head1 VERSION -$Id: cust_pkg.pm,v 1.26 2002-10-14 06:17:14 ivan Exp $ +$Id: cust_pkg.pm,v 1.27 2002-10-17 14:16:17 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index 4fc663450..50d94452a 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -12,6 +12,7 @@ use FS::svc_acct; use FS::svc_domain; use FS::svc_forward; use FS::domain_record; +use FS::part_export; @ISA = qw( FS::Record ); @@ -336,93 +337,110 @@ sub seconds_since { $sth->fetchrow_arrayref->[0]; } -=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END ( DBI_DATABASE_HANDLE | DATASRC DB_USERNAME DB_PASSWORD ) +=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END See L. Equivalent to $cust_svc->svc_x->seconds_since, but more efficient. Meaningless for records where B is not "svc_acct". -NOTE: specifying a DATASRC/USERNAME/PASSWORD instead of a DBI database handle -is not yet implemented. - =cut #note: implementation here, POD in FS::svc_acct sub seconds_since_sqlradacct { - my($self, $start, $end, $dbh) = @_; + my($self, $start, $end) = @_; my $username = $self->svc_x->username; - #select a unix time conversion function based on database type - my $str2time; - if ( $dbh->{Driver}->{Name} eq 'mysql' ) { - $str2time = 'UNIX_TIMESTAMP('; - } elsif ( $dbh->{Driver}->{Name} eq 'Pg' ) { - $str2time = 'EXTRACT( EPOCH FROM '; - } else { - warn "warning: unknown database type ". $dbh->{Driver}->{Name}. - "; guessing how to convert to UNIX timestamps"; - $str2time = 'extract(epoch from '; + my @part_export = $self->part_svc->part_export('sqlradius') + or die "no sqlradius export configured for this service type"; + #or return undef; + + my $seconds = 0; + foreach my $part_export ( @part_export ) { + + my $dbh = DBI->connect( map { $part_export->option($_) } + qw(datasrc username password) ) + or die "can't connect to sqlradius database: ". $DBI::errstr; + + #select a unix time conversion function based on database type + my $str2time; + if ( $dbh->{Driver}->{Name} eq 'mysql' ) { + $str2time = 'UNIX_TIMESTAMP('; + } elsif ( $dbh->{Driver}->{Name} eq 'Pg' ) { + $str2time = 'EXTRACT( EPOCH FROM '; + } else { + warn "warning: unknown database type ". $dbh->{Driver}->{Name}. + "; guessing how to convert to UNIX timestamps"; + $str2time = 'extract(epoch from '; + } + + #find closed sessions completely within the given range + my $sth = $dbh->prepare("SELECT SUM(acctsessiontime) + FROM radacct + WHERE UserName = ? + AND $str2time AcctStartTime) >= ? + AND $str2time AcctStopTime ) < ? + AND AcctStopTime =! 0 + AND AcctStopTime IS NOT NULL" + ) or die $dbh->errstr; + $sth->execute($username, $start, $end) or die $sth->errstr; + my $regular = $sth->fetchrow_arrayref->[0]; + + #find open sessions which start in the range, count session start->range end + # don't count them if they are over 1 day old (probably missing stop record) + $sth = $dbh->prepare("SELECT SUM( ? - $str2time AcctStartTime ) ) + FROM radacct + WHERE UserName = ? + AND $str2time AcctStartTime ) >= ? + AND ( ? - $str2time AcctStartTime ) < 86400 + AND ( AcctStopTime = 0 + OR AcctStopTime IS NULL )" + ) or die $dbh->errstr; + $sth->execute($end, $username, $start, $end) or die $sth->errstr; + my $start_during = $sth->fetchrow_arrayref->[0]; + + #find closed sessions which start before the range but stop during, + #count range start->session end + $sth = $dbh->prepare("SELECT SUM( $str2time AcctStopTime ) - ? ) + FROM radacct + WHERE UserName = ? + AND $str2time AcctStartTime ) < ? + AND $str2time AcctStopTime ) >= ? + AND $str2time AcctStopTime ) < ? + AND AcctStopTime != 0 + AND AcctStopTime IS NOT NULL" + ) or die $dbh->errstr; + $sth->execute($start, $username, $start, $start, $end ) or die $sth->errstr; + my $end_during = $sth->fetchrow_arrayref->[0]; + + #find closed (not anymore - or open) sessions which start before the range + # but stop # after, or are still open, count range start->range end + # don't count open sessions (probably missing stop record) + $sth = $dbh->prepare("SELECT COUNT(*) + FROM radacct + WHERE UserName = ? + AND $str2time AcctStartTime ) < ? + AND ( $str2time AcctStopTime ) >= ? + )" + # OR AcctStopTime = 0 + # OR AcctStopTime IS NULL )" + ) or die $dbh->errstr; + $sth->execute($username, $start, $end ) or die $sth->errstr; + my $entire_range = ($end-$start) * $sth->fetchrow_arrayref->[0]; + + $seconds += $regular + $end_during + $start_during + $entire_range; + } - #find sessions completely within the given range - my $sth = $dbh->prepare("SELECT SUM(acctsessiontime) - FROM radacct - WHERE UserName = ? - AND $str2time AcctStartTime) >= ? - AND $str2time AcctStopTime ) < ? - AND AcctStopTime =! 0 - AND AcctStopTime IS NOT NULL" - ) or die $dbh->errstr; - $sth->execute($username, $start, $end) or die $sth->errstr; - my $regular = $sth->fetchrow_arrayref->[0]; - - #find open sessions which start in the range, count session start->range end - $sth = $dbh->prepare("SELECT SUM( ? - $str2time AcctStartTime ) ) - FROM radacct - WHERE UserName = ? - AND AcctStartTime >= ? - AND ( AcctStopTime = 0 - OR AcctStopTime IS NULL )" - ) or die $dbh->errstr; - $sth->execute($end, $username, $start) or die $sth->errstr; - my $start_during = $sth->fetchrow_arrayref->[0]; - - #find closed sessions which start before the range but stop during, - #count range start->session end - $sth = $dbh->prepare("SELECT SUM( $str2time AcctStopTime ) - ? ) - FROM radacct - WHERE UserName = ? - AND AcctStartTime < ? - AND AcctStopTime >= ? - AND AcctStopTime < ? - AND AcctStopTime != 0 - AND AcctStopTime IS NOT NULL" - ) or die $dbh->errstr; - $sth->execute($start, $username, $start, $start, $end ) or die $sth->errstr; - my $end_during = $sth->fetchrow_arrayref->[0]; - - #find closed or open sessions which start before the range but stop - # after, or are still open, count range start->range end - $sth = $dbh->prepare("SELECT COUNT(*) - FROM radacct - WHERE UserName = ? - AND AcctStartTime < ? - AND ( AcctStopTime >= ? - OR AcctStopTime = 0 - OR AcctStopTime IS NULL )" - ) or die $dbh->errstr; - $sth->execute($username, $start, $end ) or die $sth->errstr; - my $entire_range = ($end-$start) * $sth->fetchrow_arrayref->[0]; + $seconds; - $regular + $end_during + $start_during + $entire_range; } =back =head1 VERSION -$Id: cust_svc.pm,v 1.18 2002-10-12 13:26:45 ivan Exp $ +$Id: cust_svc.pm,v 1.19 2002-10-17 14:16:17 ivan Exp $ =head1 BUGS diff --git a/FS/FS/part_svc.pm b/FS/FS/part_svc.pm index 7c6acdbcd..06c15ed2a 100644 --- a/FS/FS/part_svc.pm +++ b/FS/FS/part_svc.pm @@ -286,22 +286,23 @@ sub all_part_svc_column { qsearch('part_svc_column', { 'svcpart' => $self->svcpart } ); } -=item part_export +=item part_export [ EXPORTTYPE ] + +Returns all exports (see L) for this service, or, if an +export type is specified, only returns exports of the given type. =cut sub part_export { my $self = shift; - map { qsearchs('part_export', { 'exportnum' => $_->exportnum } ) } + my %search; + $search{'exporttype'} = shift if @_; + map { qsearchs('part_export', { 'exportnum' => $_->exportnum, %search } ) } qsearch('export_svc', { 'svcpart' => $self->svcpart } ); } =back -=head1 VERSION - -$Id: part_svc.pm,v 1.14 2002-09-17 09:19:06 ivan Exp $ - =head1 BUGS Delete is unimplemented. @@ -309,7 +310,7 @@ Delete is unimplemented. The list of svc_* tables is hardcoded. When svc_acct_pop is renamed, this should be fixed. -all_part_svc_column and part_export methods should be documented +all_part_svc_column method should be documented =head1 SEE ALSO diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index 3afee7f64..c41c30602 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -935,16 +935,17 @@ sub seconds_since { $self->cust_svc->seconds_since(@_); } -=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END DATASRC DB_USERNAME DB_PASSWORD +=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END Returns the numbers of seconds this account has been online between TIMESTAMP_START (inclusive) and TIMESTAMP_END (exclusive), according to an -external SQL radacct table, such as those generated by ICRADIUS or FreeRADIUS. -Sessions which started in the specified range but are still open are counted -from session start to the end of the range. Also, sessions which end in the -range but started earlier are counted from the start of the range to session -end. Finally, sessions which start before the range but end after (or are -still open) are counted for the entire range. +external SQL radacct table, specified via sqlradius export. Sessions which +started in the specified range but are still open are counted from session +start to the end of the range (unless they are over 1 day old, in which case +they are presumed missing their stop record and not counted). Also, sessions +which end in therange but started earlier are counted from the start of the +range to session end. Finally, sessions which start before the range but end +after are counted for the entire range. TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see L. Also see L and L for conversion -- cgit v1.2.1 From dbcf3603c7929de3a0f2011d6516b996541e93fa Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 17 Oct 2002 14:37:58 +0000 Subject: fix sqlradacct calculations for old Pg --- FS/FS/cust_svc.pm | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index 50d94452a..bed6a0ab3 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -380,7 +380,7 @@ sub seconds_since_sqlradacct { WHERE UserName = ? AND $str2time AcctStartTime) >= ? AND $str2time AcctStopTime ) < ? - AND AcctStopTime =! 0 + AND $str2time AcctStopTime ) =! 0 AND AcctStopTime IS NOT NULL" ) or die $dbh->errstr; $sth->execute($username, $start, $end) or die $sth->errstr; @@ -393,7 +393,7 @@ sub seconds_since_sqlradacct { WHERE UserName = ? AND $str2time AcctStartTime ) >= ? AND ( ? - $str2time AcctStartTime ) < 86400 - AND ( AcctStopTime = 0 + AND ( $str2time AcctStopTime ) = 0 OR AcctStopTime IS NULL )" ) or die $dbh->errstr; $sth->execute($end, $username, $start, $end) or die $sth->errstr; @@ -407,7 +407,7 @@ sub seconds_since_sqlradacct { AND $str2time AcctStartTime ) < ? AND $str2time AcctStopTime ) >= ? AND $str2time AcctStopTime ) < ? - AND AcctStopTime != 0 + AND $str2time AcctStopTime ) != 0 AND AcctStopTime IS NOT NULL" ) or die $dbh->errstr; $sth->execute($start, $username, $start, $start, $end ) or die $sth->errstr; @@ -438,10 +438,6 @@ sub seconds_since_sqlradacct { =back -=head1 VERSION - -$Id: cust_svc.pm,v 1.19 2002-10-17 14:16:17 ivan Exp $ - =head1 BUGS Behaviour of changing the svcpart of cust_svc records is undefined and should -- cgit v1.2.1 From ee083facc9f4e18f27df07f829b224366483a56e Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 17 Oct 2002 14:46:04 +0000 Subject: really fix sqlradacct for old Pg --- FS/FS/cust_svc.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index bed6a0ab3..6ce12cbe9 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -380,7 +380,7 @@ sub seconds_since_sqlradacct { WHERE UserName = ? AND $str2time AcctStartTime) >= ? AND $str2time AcctStopTime ) < ? - AND $str2time AcctStopTime ) =! 0 + AND $str2time AcctStopTime ) > 0 AND AcctStopTime IS NOT NULL" ) or die $dbh->errstr; $sth->execute($username, $start, $end) or die $sth->errstr; @@ -407,7 +407,7 @@ sub seconds_since_sqlradacct { AND $str2time AcctStartTime ) < ? AND $str2time AcctStopTime ) >= ? AND $str2time AcctStopTime ) < ? - AND $str2time AcctStopTime ) != 0 + AND $str2time AcctStopTime ) > 0 AND AcctStopTime IS NOT NULL" ) or die $dbh->errstr; $sth->execute($start, $username, $start, $start, $end ) or die $sth->errstr; -- cgit v1.2.1 From 23bc7fbb197d8dc58ddab651c49f825324044614 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 17 Oct 2002 14:50:11 +0000 Subject: *sigh* better debugging --- FS/FS/cust_svc.pm | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index 6ce12cbe9..d6ed7ee6b 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -373,6 +373,8 @@ sub seconds_since_sqlradacct { "; guessing how to convert to UNIX timestamps"; $str2time = 'extract(epoch from '; } + + my $query; #find closed sessions completely within the given range my $sth = $dbh->prepare("SELECT SUM(acctsessiontime) @@ -387,16 +389,16 @@ sub seconds_since_sqlradacct { my $regular = $sth->fetchrow_arrayref->[0]; #find open sessions which start in the range, count session start->range end - # don't count them if they are over 1 day old (probably missing stop record) - $sth = $dbh->prepare("SELECT SUM( ? - $str2time AcctStartTime ) ) - FROM radacct - WHERE UserName = ? - AND $str2time AcctStartTime ) >= ? - AND ( ? - $str2time AcctStartTime ) < 86400 - AND ( $str2time AcctStopTime ) = 0 - OR AcctStopTime IS NULL )" - ) or die $dbh->errstr; - $sth->execute($end, $username, $start, $end) or die $sth->errstr; + $query = "SELECT SUM( ? - $str2time AcctStartTime ) ) + FROM radacct + WHERE UserName = ? + AND $str2time AcctStartTime ) >= ? + AND ( ? - $str2time AcctStartTime ) < 86400 + AND ( $str2time AcctStopTime ) = 0 + OR AcctStopTime IS NULL )"; + $sth = $dbh->prepare($query) or die $dbh->errstr; + $sth->execute($end, $username, $start, $end) + or die $sth->errstr. " executing query $query"; my $start_during = $sth->fetchrow_arrayref->[0]; #find closed sessions which start before the range but stop during, -- cgit v1.2.1 From d6ebf4c35d7c7b7d559828bfac3744c770dbf3eb Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 17 Oct 2002 14:59:29 +0000 Subject: yay missing paren --- FS/FS/cust_svc.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index d6ed7ee6b..211b0ad23 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -393,7 +393,7 @@ sub seconds_since_sqlradacct { FROM radacct WHERE UserName = ? AND $str2time AcctStartTime ) >= ? - AND ( ? - $str2time AcctStartTime ) < 86400 + AND ( ? - $str2time AcctStartTime ) ) < 86400 AND ( $str2time AcctStopTime ) = 0 OR AcctStopTime IS NULL )"; $sth = $dbh->prepare($query) or die $dbh->errstr; -- cgit v1.2.1 From 94fb4aafeae9abf099a8a4ee87b72de86c812ce0 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 18 Oct 2002 10:28:46 +0000 Subject: adding --- FS/MANIFEST | 3 ++ FS/bin/freeside-radgroup | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 FS/bin/freeside-radgroup (limited to 'FS') diff --git a/FS/MANIFEST b/FS/MANIFEST index 24fef1748..e37216e19 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -17,7 +17,10 @@ bin/freeside-deluser bin/freeside-setup bin/freeside-setinvoice bin/freeside-overdue +bin/freeside-radgroup bin/freeside-receivables-report +bin/freeside-sqlradius-radacctd +bin/freeside-sqlradius-reset bin/freeside-tax-report bin/freeside-cc-receipts-report bin/freeside-credit-report diff --git a/FS/bin/freeside-radgroup b/FS/bin/freeside-radgroup new file mode 100644 index 000000000..e1a819788 --- /dev/null +++ b/FS/bin/freeside-radgroup @@ -0,0 +1,76 @@ +#!/usr/bin/perl -w + +use strict; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch); +use FS::cust_svc; +use FS::svc_acct; + +&untaint_argv; #what it sounds like (eww) + +my($user, $action, $groupname, $svcpart) = @ARGV; + +adminsuidsetup $user; + +my @svc_acct = map { $_->svc_x } qsearch('cust_svc', { svcpart => $svcpart } ); + +if ( lc($action) eq 'add' ) { + foreach my $svc_acct ( @svc_acct ) { + my @groups = $svc_acct->radius_groups; + next if grep { $_ eq $groupname } @groups; + push @groups, $groupname; + my %hash = $svc_acct->hash; + $hash{radius_groups} = \@groups; + my $new = new FS::svc_acct \%hash; + my $error = $new->replace($svc_acct); + die $error if $error; + } +} else { + die &usage; +} + +# subroutines + +sub untaint_argv { + foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV + $ARGV[$_] =~ /^(.*)$/ || die "Illegal arguement \"$ARGV[$_]\""; + $ARGV[$_]=$1; + } +} + +sub usage { + die "Usage:\n\n freeside-radgroup user action groupname svcpart\n"; +} + +=head1 NAME + +freeside-radgroup - Command line utility to manipulate radius groups + +=head1 SYNOPSIS + + freeside-addgroup user action groupname svcpart + +=head1 DESCRIPTION + + B is a freeside user as added with freeside-adduser. + + B is the action to take. Available actions are: I + + B is the group to add (or remove, etc.) + + B specifies which accounts will be updated. + +=head1 EXAMPLES + +freeside-radgroup freesideuser add groupname 3 + +Adds I to all accounts with service definition 3. + +=head1 BUGS + +=head1 SEE ALSO + +L, L, L + +=cut + -- cgit v1.2.1 From b75341fcfedbdcb2d39c6616690a1d59e4b233fc Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 18 Oct 2002 13:23:27 +0000 Subject: don't re-insert non-changed usernames to fuzzy cache --- FS/FS/svc_acct.pm | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'FS') diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index c41c30602..b33f3ae29 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -562,18 +562,19 @@ sub replace { return $error if $error; } - #false laziness with sub insert (and cust_main) - my $queue = new FS::queue { - 'svcnum' => $new->svcnum, - 'job' => 'FS::svc_acct::append_fuzzyfiles' - }; - $error = $queue->insert($new->username); - if ( $error ) { - $dbh->rollback if $oldAutoCommit; - return "queueing job (transaction rolled back): $error"; + if ( $new->username ne $old->username ) { + #false laziness with sub insert (and cust_main) + my $queue = new FS::queue { + 'svcnum' => $new->svcnum, + 'job' => 'FS::svc_acct::append_fuzzyfiles' + }; + $error = $queue->insert($new->username); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "queueing job (transaction rolled back): $error"; + } } - $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; #no error } -- cgit v1.2.1 From 9b1a8ec900ec1f5cd7d1f622f49066510c8f547c Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 18 Oct 2002 13:28:03 +0000 Subject: argh --- FS/bin/freeside-radgroup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/bin/freeside-radgroup b/FS/bin/freeside-radgroup index e1a819788..ed85626d2 100644 --- a/FS/bin/freeside-radgroup +++ b/FS/bin/freeside-radgroup @@ -20,7 +20,7 @@ if ( lc($action) eq 'add' ) { next if grep { $_ eq $groupname } @groups; push @groups, $groupname; my %hash = $svc_acct->hash; - $hash{radius_groups} = \@groups; + $hash{usergroup} = \@groups; my $new = new FS::svc_acct \%hash; my $error = $new->replace($svc_acct); die $error if $error; -- cgit v1.2.1 From e6f6f496883b8e8be42f4d92f01b61dbc2c590be Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 20 Oct 2002 03:28:23 +0000 Subject: vpopmail restart export option --- FS/FS/part_export.pm | 3 +++ FS/FS/part_export/vpopmail.pm | 29 ++++++++++++++++++----------- 2 files changed, 21 insertions(+), 11 deletions(-) (limited to 'FS') diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm index 1b402e014..c9ae41fc1 100644 --- a/FS/FS/part_export.pm +++ b/FS/FS/part_export.pm @@ -643,6 +643,9 @@ tie my %vpopmail_options, 'Tie::IxHash', 'dir' => { label=>'directory', }, # ?more info? default? 'uid' => { label=>'vpopmail uid' }, 'gid' => { label=>'vpopmail gid' }, + 'restart' => { label=> 'vpopmail restart command', + default=> 'cd /home/vpopmail/domains; for domain in *; do /home/vpopmail/bin/vmkpasswd $domain; done; /var/qmail/bin/qmail-newu; killall -HUP qmail-send', + }, ; tie my %bind_options, 'Tie::IxHash', diff --git a/FS/FS/part_export/vpopmail.pm b/FS/FS/part_export/vpopmail.pm index 2ca44016a..bddf175ee 100644 --- a/FS/FS/part_export/vpopmail.pm +++ b/FS/FS/part_export/vpopmail.pm @@ -19,6 +19,7 @@ sub _export_insert { crypt($svc_acct->_password,$saltset[int(rand(64))].$saltset[int(rand(64))]), $svc_acct->domain, $svc_acct->quota, + $svc_acct->finger, ); } @@ -46,7 +47,7 @@ sub _export_replace { return '' unless $old->_password ne $new->_password; $self->vpopmail_queue( $new->svcnum, 'replace', - $new->username, $cpassword, $new->domain, $new->quota ); + $new->username, $cpassword, $new->domain, $new->quota, $new->finger ); } sub _export_delete { @@ -77,13 +78,14 @@ sub vpopmail_queue { $self->option('dir'), $self->option('uid'), $self->option('gid'), + $self->option('restart'), @_ ); } sub vpopmail_insert { #subroutine, not method - my( $exportdir, $machine, $dir, $uid, $gid ) = splice @_,0,5; - my( $username, $password, $domain, $quota ) = @_; + my( $exportdir, $machine, $dir, $uid, $gid, $restart ) = splice @_,0,6; + my( $username, $password, $domain, $quota, $finger ) = @_; mkdir "$exportdir/domains/$domain", 0700 or die $! unless -d "$exportdir/domains/$domain"; @@ -112,13 +114,13 @@ sub vpopmail_insert { #subroutine, not method mkdir $mkdir, 0700 or die "can't mkdir $mkdir: $!"; } - vpopmail_sync( $exportdir, $machine, $dir, $uid, $gid ); + vpopmail_sync( $exportdir, $machine, $dir, $uid, $gid, $restart ); } sub vpopmail_replace { #subroutine, not method - my( $exportdir, $machine, $dir, $uid, $gid ) = splice @_,0,5; - my( $username, $password, $domain ) = @_; + my( $exportdir, $machine, $dir, $uid, $gid, $restart ) = splice @_,0,6; + my( $username, $password, $domain, $quota, $finger ) = @_; (open(VPASSWD, "$exportdir/domains/$domain/vpasswd") and flock(VPASSWD,LOCK_EX) @@ -140,7 +142,7 @@ sub vpopmail_replace { #subroutine, not method '1', '0', $finger, - $dir, + "$dir/domains/$domain/$username", #$vdir $quota ? $quota.'S' : 'NOQUOTA', ), "\n"; } @@ -153,12 +155,12 @@ sub vpopmail_replace { #subroutine, not method flock(VPASSWD,LOCK_UN); close(VPASSWD); - vpopmail_sync( $exportdir, $machine, $dir, $uid, $gid ); + vpopmail_sync( $exportdir, $machine, $dir, $uid, $gid, $restart ); } sub vpopmail_delete { #subroutine, not method - my( $exportdir, $machine, $dir, $uid, $gid ) = splice @_,0,5; + my( $exportdir, $machine, $dir, $uid, $gid, $restart ) = splice @_,0,6; my( $username, $domain ) = @_; (open(VPASSWD, "$exportdir/domains/$domain/vpasswd") @@ -185,11 +187,11 @@ sub vpopmail_delete { #subroutine, not method rmtree "$exportdir/domains/$domain/$username" or die "can't rmtree $exportdir/domains/$domain/$username: $!"; - vpopmail_sync( $exportdir, $machine, $dir, $uid, $gid ); + vpopmail_sync( $exportdir, $machine, $dir, $uid, $gid, $restart ); } sub vpopmail_sync { - my( $exportdir, $machine, $dir, $uid, $gid ) = splice @_,0,5; + my( $exportdir, $machine, $dir, $uid, $gid, $restart ) = splice @_,0,6; chdir $exportdir; # my @args = ( $rsync, "-rlpt", "-e", $ssh, "domains/", @@ -214,6 +216,11 @@ sub vpopmail_sync { 'STDERR: '. join(" / ", $rsync->err). ', '. 'STDOUT: '. join(" / ", $rsync->out); } + + eval "use Net::SSH;"; + die $@ if $@; + + ssh("vpopmail\@$machine", $restart); } -- cgit v1.2.1 From e31feacedbd07e333183b83360d20d21bcb611bd Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 20 Oct 2002 07:26:54 +0000 Subject: don't run restart command unless there is one --- FS/FS/part_export/vpopmail.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/part_export/vpopmail.pm b/FS/FS/part_export/vpopmail.pm index bddf175ee..646af44cd 100644 --- a/FS/FS/part_export/vpopmail.pm +++ b/FS/FS/part_export/vpopmail.pm @@ -220,7 +220,7 @@ sub vpopmail_sync { eval "use Net::SSH;"; die $@ if $@; - ssh("vpopmail\@$machine", $restart); + ssh("vpopmail\@$machine", $restart) if $restart; } -- cgit v1.2.1 From d927a8b53105cb9b715f6d6f430e3bfee3fcfd95 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 20 Oct 2002 08:27:52 +0000 Subject: enable shellcommands suspension/unsuspension hooks --- FS/FS/part_export.pm | 24 ++++++++++++++++++++++++ FS/FS/part_export/shellcommands.pm | 10 ++++++++++ 2 files changed, 34 insertions(+) (limited to 'FS') diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm index c9ae41fc1..5d725ab22 100644 --- a/FS/FS/part_export.pm +++ b/FS/FS/part_export.pm @@ -552,6 +552,18 @@ tie my %shellcommands_options, 'Tie::IxHash', type =>'textarea', default=>'', }, + 'suspend' => { label=>'Suspension command', + default=>'', + }, + 'suspend_stdin' => { label=>'Suspension command STDIN', + default=>'', + }, + 'unsuspend' => { label=>'Unsuspension command', + default=>'', + }, + 'unsuspend_stdin' => { label=>'Unsuspension command STDIN', + default=>'', + }, ; tie my %shellcommands_withdomain_options, 'Tie::IxHash', @@ -577,6 +589,18 @@ tie my %shellcommands_withdomain_options, 'Tie::IxHash', type =>'textarea', #default=>"$_password\n$_password\n", }, + 'suspend' => { label=>'Suspension command', + default=>'', + }, + 'suspend_stdin' => { label=>'Suspension command STDIN', + default=>'', + }, + 'unsuspend' => { label=>'Unsuspension command', + default=>'', + }, + 'unsuspend_stdin' => { label=>'Unsuspension command STDIN', + default=>'', + }, ; tie my %www_shellcommands_options, 'Tie::IxHash', diff --git a/FS/FS/part_export/shellcommands.pm b/FS/FS/part_export/shellcommands.pm index a514f9375..da6f4c46c 100644 --- a/FS/FS/part_export/shellcommands.pm +++ b/FS/FS/part_export/shellcommands.pm @@ -20,6 +20,16 @@ sub _export_delete { $self->_export_command('userdel', @_); } +sub _export_suspend { + my($self) = shift; + $self->_export_command('suspend', @_); +} + +sub _export_unsuspend { + my($self) = shift; + $self->_export_command('unsuspend', @_); +} + sub _export_command { my ( $self, $action, $svc_acct) = (shift, shift, shift); my $command = $self->option($action); -- cgit v1.2.1 From 28a584bc4a0ea3e868871cf1e2471e6412bfb3f3 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 22 Oct 2002 08:13:06 +0000 Subject: ACH fixes from s5 --- FS/FS/part_bill_event.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'FS') diff --git a/FS/FS/part_bill_event.pm b/FS/FS/part_bill_event.pm index 991616bb8..e86b5c1fb 100644 --- a/FS/FS/part_bill_event.pm +++ b/FS/FS/part_bill_event.pm @@ -37,7 +37,7 @@ FS::Record. The following fields are currently supported: =item eventpart - primary key -=item payby - CARD, BILL, or COMP +=item payby - CARD, CHEK, BILL, or COMP =item event - event name @@ -140,7 +140,7 @@ sub check { } my $error = $self->ut_numbern('eventpart') - || $self->ut_enum('payby', [qw( CARD BILL COMP )] ) + || $self->ut_enum('payby', [qw( CARD CHEK BILL COMP )] ) || $self->ut_text('event') || $self->ut_anything('eventcode') || $self->ut_number('seconds') -- cgit v1.2.1 From b7440710b9bca319aba4d2782b8fdcf076abe2b7 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 22 Oct 2002 09:15:59 +0000 Subject: bugfix in vpopmail restart --- FS/FS/part_export/vpopmail.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/part_export/vpopmail.pm b/FS/FS/part_export/vpopmail.pm index 646af44cd..a505a0f47 100644 --- a/FS/FS/part_export/vpopmail.pm +++ b/FS/FS/part_export/vpopmail.pm @@ -217,7 +217,7 @@ sub vpopmail_sync { 'STDOUT: '. join(" / ", $rsync->out); } - eval "use Net::SSH;"; + eval "use Net::SSH qw(ssh);"; die $@ if $@; ssh("vpopmail\@$machine", $restart) if $restart; -- cgit v1.2.1 From 9f96bd19b87cb0084dda17da070f3bb5dadd4823 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 23 Oct 2002 15:49:44 +0000 Subject: add option to unapply payments --- FS/FS/Conf.pm | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'FS') diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index cf874aa35..b3fffe327 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -317,6 +317,13 @@ httemplate/docs/config.html 'type' => [qw( checkbox text )], }, + { + 'key' => 'unapplypayments', + 'section' => 'UI', + 'description' => 'Enable "unapplication" of unclosed payments.', + 'type' => 'checkbox', + }, + { 'key' => 'dirhash', 'section' => 'shell', -- cgit v1.2.1 From 1583472a6afefb1ad33e05656fd206674f37d9df Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 23 Oct 2002 17:07:59 +0000 Subject: database dump & scp support --- FS/FS/Conf.pm | 7 +++++++ FS/bin/freeside-daily | 19 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index b3fffe327..c007a501a 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -989,6 +989,13 @@ httemplate/docs/config.html 'type' => 'checkbox', }, + { + 'key' => 'dump-scpdest', + 'section' => '', + 'description' => 'destination for scp database dumps: user@host:/path', + 'type' => 'text', + }, + ); 1; diff --git a/FS/bin/freeside-daily b/FS/bin/freeside-daily index 17ee798ff..1db786120 100755 --- a/FS/bin/freeside-daily +++ b/FS/bin/freeside-daily @@ -4,8 +4,9 @@ use strict; use Fcntl qw(:flock); use Date::Parse; use Getopt::Std; -use FS::UID qw(adminsuidsetup driver_name dbh); +use FS::UID qw(adminsuidsetup driver_name dbh datasrc); use FS::Record qw(qsearch qsearchs); +use FS::Conf; use FS::cust_main; &untaint_argv; #what it sounds like (eww) @@ -57,6 +58,22 @@ if ( driver_name eq 'Pg' ) { } } +#local hack +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; + } + scp("/var/tmp/$database.sql", $dest); + unlink "/var/tmp/$database.sql" or die $!; +} + # subroutines sub untaint_argv { -- cgit v1.2.1 From 3702269ee9f6a63572f6e915ace56d70b5080033 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 25 Oct 2002 21:24:55 +0000 Subject: make $old_domain available too --- FS/FS/part_export/shellcommands.pm | 1 + 1 file changed, 1 insertion(+) (limited to 'FS') diff --git a/FS/FS/part_export/shellcommands.pm b/FS/FS/part_export/shellcommands.pm index da6f4c46c..04e5041c3 100644 --- a/FS/FS/part_export/shellcommands.pm +++ b/FS/FS/part_export/shellcommands.pm @@ -65,6 +65,7 @@ sub _export_replace { } $new_finger = shell_quote $new_finger; $quoted_new__password = shell_quote $new__password; + $old_domain = $old->domain; $new_domain = $new->domain; $new_crypt_password = ''; #surpress "used only once" warnings $new_crypt_password = crypt( $new->_password, -- cgit v1.2.1 From 749cce349c6801e6d75834065197c3aceddda599 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 28 Oct 2002 13:22:45 +0000 Subject: signal-less queued child handling (closes: Bug#477) --- FS/bin/freeside-queued | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'FS') diff --git a/FS/bin/freeside-queued b/FS/bin/freeside-queued index 311fe62f9..6ea27c05f 100644 --- a/FS/bin/freeside-queued +++ b/FS/bin/freeside-queued @@ -1,10 +1,10 @@ #!/usr/bin/perl -w use strict; -use vars qw( $log_file $sigterm $sigint $kids $max_kids ); +use vars qw( $log_file $sigterm $sigint $kids $max_kids %kids ); use subs qw( _die _logmsg ); use Fcntl qw(:flock); -use POSIX qw(setsid); +use POSIX qw(:sys_wait_h setsid); use Date::Format; use IO::File; use FS::UID qw(adminsuidsetup forksuidsetup driver_name dbh); @@ -28,8 +28,8 @@ my $pid_file = "/var/run/freeside-queued.pid"; &daemonize1; -sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; $kids--; } -$SIG{CHLD} = \&REAPER; +#sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; $kids--; } +#$SIG{CHLD} = \&REAPER; $sigterm = 0; $sigint = 0; @@ -65,9 +65,11 @@ warn "freeside-queued starting\n"; my $warnkids=0; while (1) { + &reap_kids; #prevent runaway forking if ( $kids >= $max_kids ) { warn "WARNING: maximum $kids children reached\n" unless $warnkids++; + &reap_kids; sleep 1; #waiting for signals is cheap next; } @@ -131,6 +133,7 @@ while (1) { if ( $pid ) { $kids++; + $kids{$pid} = 1; } else { #kid time #get new db handle @@ -230,6 +233,16 @@ sub daemonize2 { open STDERR, '>&STDOUT' or die "Can't dup stdout: $!"; } +sub reap_kids { + foreach my $pid ( keys %kids ) { + my $kid = waitpid($pid, WNOHANG); + if ( $kid > 0 ) { + $kids--; + delete $kids{$kid}; + } + } +} + =head1 NAME freeside-queued - Job queue daemon -- cgit v1.2.1 From baaa14867224a536143b843ff33787f74d1c5032 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 4 Nov 2002 23:40:55 +0000 Subject: balance on small_custview --- FS/FS/CGI.pm | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'FS') diff --git a/FS/FS/CGI.pm b/FS/FS/CGI.pm index d69aad2fc..86d20f6cb 100644 --- a/FS/FS/CGI.pm +++ b/FS/FS/CGI.pm @@ -322,6 +322,10 @@ sub small_custview { $html .= ''; + $html .= '
Balance: $'. $cust_main->balance. '
'; + + # last payment might be good here too? + $html; } -- cgit v1.2.1 From fc3b6024fcf0bf0394e6239639cbe31786b0cad8 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 5 Nov 2002 20:29:57 +0000 Subject: lost? --- FS/bin/freeside-sqlradius-radacctd | 180 +++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 FS/bin/freeside-sqlradius-radacctd (limited to 'FS') diff --git a/FS/bin/freeside-sqlradius-radacctd b/FS/bin/freeside-sqlradius-radacctd new file mode 100644 index 000000000..4e8d57c51 --- /dev/null +++ b/FS/bin/freeside-sqlradius-radacctd @@ -0,0 +1,180 @@ +#!/usr/bin/perl -Tw + +use strict; +use vars qw( $log_file $sigterm $sigint ); +use subs qw( _die _logmsg ); +use Fcntl qw(:flock); +use POSIX qw(setsid); +use Date::Format; +use IO::File; +use FS::UID qw(adminsuidsetup); +#use FS::Record qw(qsearch qsearchs); +#use FS::part_export; +#use FS::svc_acct; +#use FS::cust_svc; + +#lots of false laziness w/freeside-queued + +my $user = shift or die &usage; + +#my $pid_file = "/var/run/freeside-sqlradius-radacctd.$user.pid"; +my $pid_file = "/var/run/freeside-sqlradius-radacctd.pid"; + +&daemonize1; + +#sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; $kids--; } +#$SIG{CHLD} = \&REAPER; + +$sigterm = 0; +$sigint = 0; +$SIG{INT} = sub { warn "SIGINT received; shutting down\n"; $sigint++; }; +$SIG{TERM} = sub { warn "SIGTERM received; shutting down\n"; $sigterm++; }; + +my $freeside_gid = scalar(getgrnam('freeside')) + or die "can't setgid to freeside group\n"; +$) = $freeside_gid; +$( = $freeside_gid; +#if freebsd can't setuid(), presumably it can't setgid() either. grr fleabsd +($(,$)) = ($),$(); +$) = $freeside_gid; + +$> = $FS::UID::freeside_uid; +$< = $FS::UID::freeside_uid; +#freebsd is sofa king broken, won't setuid() +($<,$>) = ($>,$<); +$> = $FS::UID::freeside_uid; + +#$ENV{HOME} = (getpwuid($>))[7]; #for ssh +adminsuidsetup $user; + +$log_file= "/usr/local/etc/freeside/sqlradius-radacctd-log.". $FS::UID::datasrc; + +&daemonize2; + +$SIG{__DIE__} = \&_die; +$SIG{__WARN__} = \&_logmsg; + +warn "freeside-sqlradius-radacctd starting\n"; + +#eslaf + +#my $machine = shift or die &usage; #would need to be up higher for real +my @exports = qsearch('part_export', { 'exporttype' => 'sqlradius' } ); + +while (1) { + + my %seen = (); + foreach my $export ( @exports ) { + next if $seen{$export->option('datasrc')}++; + my $dbh = DBI->connect( + map { $export->option($_) } qw( datasrc username password ) + ) or do { + warn "can't connect to ". $export->option('datasrc'). ": ". $DBI::errstr; + next; + } + + # find old radacct position + #$lastid = 0; + + # get new radacct records + my $sth = $dbh->prepare('SELECT * FROM radacct WHERE radacctid > ?') or do { + warn "can't select in radacct table from ". $export->option('datasrc'). + ": ". $dbh->errstr; + next; + }; + + while ( my $radacct = $sth->fetchrow_arrayref({}) ) { + + my $session = new FS::session { + portnum => + svcnum => + login => + #logout => + }; + + } + + # look for updated radacct records & replace them + + } + + sleep 5; + +} + +#more false laziness w/freeside-queued + +sub usage { + die "Usage:\n\n freeside-sqlradius-radacctd user\n"; +} + +sub _die { + my $msg = shift; + unlink $pid_file if -e $pid_file; + _logmsg($msg); +} + +sub _logmsg { + chomp( my $msg = shift ); + my $log = new IO::File ">>$log_file"; + flock($log, LOCK_EX); + seek($log, 0, 2); + print $log "[". time2str("%a %b %e %T %Y",time). "] [$$] $msg\n"; + flock($log, LOCK_UN); + close $log; +} + +sub daemonize1 { + + chdir "/" or die "Can't chdir to /: $!"; + open STDIN, '/dev/null' or die "Can't read /dev/null: $!"; + defined(my $pid = fork) or die "Can't fork: $!"; + if ( $pid ) { + print "freeside-sqlradius-radacctd started with pid $pid\n"; + #logging to $log_file\n"; + exit unless $pid_file; + my $pidfh = new IO::File ">$pid_file" or exit; + print $pidfh "$pid\n"; + exit; + } + #open STDOUT, '>/dev/null' + # or die "Can't write to /dev/null: $!"; + #setsid or die "Can't start a new session: $!"; + #open STDERR, '>&STDOUT' or die "Can't dup stdout: $!"; + +} + +sub daemonize2 { + open STDOUT, '>/dev/null' + or die "Can't write to /dev/null: $!"; + setsid or die "Can't start a new session: $!"; + open STDERR, '>&STDOUT' or die "Can't dup stdout: $!"; +} + + +#eslaf + +=head1 NAME + +freeside-sqlradius-radacctd - Real-time radacct import daemon + +=head1 SYNOPSIS + + freeside-sqlradius-radacctd username + +=head1 DESCRIPTION + +Imports records from an SQL radacct table in real-time into the session +monitor. + +This enables per-minute or per-hour charges as well as the +"View active NAS ports" function. + +B is a username added by freeside-adduser. + +=head1 SEE ALSO + +session.html from the base documentation. + +=cut + -- cgit v1.2.1 From 548a47b0ec1040320e56f17cfac71f716785cb95 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 5 Nov 2002 23:29:38 +0000 Subject: bandwidth charges from sqlradius --- FS/FS/cust_pkg.pm | 54 ++++++++++++++++++++++++++++++++--------- FS/FS/cust_svc.pm | 72 ++++++++++++++++++++++++++++++++++++++++++++++++------- FS/FS/svc_acct.pm | 18 ++++++++++++++ 3 files changed, 125 insertions(+), 19 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index 55ee37d9d..e83b95156 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -530,7 +530,11 @@ sub seconds_since_sqlradacct { my $seconds = 0; foreach my $cust_svc ( - grep { $_->part_svc->svcdb eq 'svc_acct' } $self->cust_svc + grep { + my $part_svc = $_->part_svc; + $part_svc->svcdb eq 'svc_acct' + && scalar($part_svc->part_export('sqlradius')); + } $self->cust_svc ) { $seconds += $cust_svc->seconds_since_sqlradacct($start, $end); } @@ -539,6 +543,38 @@ sub seconds_since_sqlradacct { } +=item attribute_since_sqlradacct TIMESTAMP_START TIMESTAMP_END ATTRIBUTE + +Returns the sum of the given attribute for all accounts (see L) +in this package for sessions ending between TIMESTAMP_START (inclusive) and +TIMESTAMP_END +(exclusive). + +TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see +L. Also see L and L for conversion +functions. + +=cut + +sub attribute_since_sqlradacct { + my($self, $start, $end, $attrib) = @_; + + my $sum = 0; + + foreach my $cust_svc ( + grep { + my $part_svc = $_->part_svc; + $part_svc->svcdb eq 'svc_acct' + && scalar($part_svc->part_export('sqlradius')); + } $self->cust_svc + ) { + $sum += $cust_svc->attribute_since_sqlradacct($start, $end, $attrib); + } + + $sum; + +} + =back =head1 SUBROUTINES @@ -719,10 +755,6 @@ sub order { =back -=head1 VERSION - -$Id: cust_pkg.pm,v 1.27 2002-10-17 14:16:17 ivan Exp $ - =head1 BUGS sub order is not OO. Perhaps it should be moved to FS::cust_main and made so? @@ -732,12 +764,12 @@ In sub order, the @pkgparts array (passed by reference) is clobbered. Also in sub order, no money is adjusted. Once FS::part_pkg defines a standard method to pass dates to the recur_prog expression, it should do so. -FS::svc_acct, FS::svc_domain, FS::svc_www and FS::svc_forward are loaded via -'use' at compile time, rather than via 'require' in sub -{ setup, suspend, unsuspend, cancel } because they use %FS::UID::callback to -load configuration values. Probably need a subroutine which decides what to -do based on whether or not we've fetched the user yet, rather than a hash. -See FS::UID and the TODO. +FS::svc_acct, FS::svc_domain, FS::svc_www, FS::svc_ip and FS::svc_forward are +loaded via 'use' at compile time, rather than via 'require' in sub { setup, +suspend, unsuspend, cancel } because they use %FS::UID::callback to load +configuration values. Probably need a subroutine which decides what to do +based on whether or not we've fetched the user yet, rather than a hash. See +FS::UID and the TODO. Now that things are transactional should the check in the insert method be moved to check ? diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index 211b0ad23..e0d582b51 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -337,11 +337,11 @@ sub seconds_since { $sth->fetchrow_arrayref->[0]; } -=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END +=item seconds_since_sqlradacct TIMESTAMP_START TIMESTAMP_END See L. Equivalent to -$cust_svc->svc_x->seconds_since, but more efficient. Meaningless for records -where B is not "svc_acct". +$cust_svc->svc_x->seconds_since_sqlradacct, but more efficient. Meaningless +for records where B is not "svc_acct". =cut @@ -361,7 +361,7 @@ sub seconds_since_sqlradacct { my $dbh = DBI->connect( map { $part_export->option($_) } qw(datasrc username password) ) or die "can't connect to sqlradius database: ". $DBI::errstr; - + #select a unix time conversion function based on database type my $str2time; if ( $dbh->{Driver}->{Name} eq 'mysql' ) { @@ -416,20 +416,20 @@ sub seconds_since_sqlradacct { my $end_during = $sth->fetchrow_arrayref->[0]; #find closed (not anymore - or open) sessions which start before the range - # but stop # after, or are still open, count range start->range end + # but stop after, or are still open, count range start->range end # don't count open sessions (probably missing stop record) $sth = $dbh->prepare("SELECT COUNT(*) FROM radacct WHERE UserName = ? AND $str2time AcctStartTime ) < ? AND ( $str2time AcctStopTime ) >= ? - )" + )" # OR AcctStopTime = 0 - # OR AcctStopTime IS NULL )" + # OR AcctStopTime IS NULL )" ) or die $dbh->errstr; $sth->execute($username, $start, $end ) or die $sth->errstr; my $entire_range = ($end-$start) * $sth->fetchrow_arrayref->[0]; - + $seconds += $regular + $end_during + $start_during + $entire_range; } @@ -438,6 +438,62 @@ sub seconds_since_sqlradacct { } +=item attribute_since_sqlradacct TIMESTAMP_START TIMESTAMP_END ATTRIBUTE + +See L. Equivalent to +$cust_svc->svc_x->attribute_since_sqlradacct, but more efficient. Meaningless +for records where B is not "svc_acct". + +=cut + +#note: implementation here, POD in FS::svc_acct +#(false laziness w/seconds_since_sqlradacct above) +sub attribute_since_sqlradacct { + my($self, $start, $end, $attrib) = @_; + + my $username = $self->svc_x->username; + + my @part_export = $self->part_svc->part_export('sqlradius') + or die "no sqlradius export configured for this service type"; + #or return undef; + + my $sum = 0; + + foreach my $part_export ( @part_export ) { + + my $dbh = DBI->connect( map { $part_export->option($_) } + qw(datasrc username password) ) + or die "can't connect to sqlradius database: ". $DBI::errstr; + + #select a unix time conversion function based on database type + my $str2time; + if ( $dbh->{Driver}->{Name} eq 'mysql' ) { + $str2time = 'UNIX_TIMESTAMP('; + } elsif ( $dbh->{Driver}->{Name} eq 'Pg' ) { + $str2time = 'EXTRACT( EPOCH FROM '; + } else { + warn "warning: unknown database type ". $dbh->{Driver}->{Name}. + "; guessing how to convert to UNIX timestamps"; + $str2time = 'extract(epoch from '; + } + + my $sth = $dbh->prepare("SELECT SUM(?) + FROM radacct + WHERE UserName = ? + AND $str2time AcctStopTime ) >= ? + AND $str2time AcctStopTime ) < ? + AND AcctStopTime IS NOT NULL" + ) or die $dbh->errstr; + $sth->execute($attrib, $username, $start, $end) or die $sth->errstr; + + $sum += $sth->fetchrow_arrayref->[0]; + + } + + $sum; + +} + =back =head1 BUGS diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index b33f3ae29..c808aeea4 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -960,6 +960,24 @@ sub seconds_since_sqlradacct { $self->cust_svc->seconds_since_sqlradacct(@_); } +=item attribute_since_sqlradacct TIMESTAMP_START TIMESTAMP_END ATTRIBUTE + +Returns the sum of the given attribute for all accounts (see L) +in this package for sessions ending between TIMESTAMP_START (inclusive) and +TIMESTAMP_END (exclusive). + +TIMESTAMP_START and TIMESTAMP_END are specified as UNIX timestamps; see +L. Also see L and L for conversion +functions. + +=cut + +#note: POD here, implementation in FS::cust_svc +sub attribute_since_sqlradacct { + my $self = shift; + $self->cust_svc->attribute_since_sqlradacct(@_); +} + =item radius_groups Returns all RADIUS groups for this account (see L). -- cgit v1.2.1 From d32ae4e36b14a3418979856e3ee3f662c5290d65 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 5 Nov 2002 23:34:11 +0000 Subject: can't use placeholders in SELECT SUM(?) --- FS/FS/cust_svc.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index e0d582b51..7516be599 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -477,14 +477,14 @@ sub attribute_since_sqlradacct { $str2time = 'extract(epoch from '; } - my $sth = $dbh->prepare("SELECT SUM(?) + my $sth = $dbh->prepare("SELECT SUM($attrib) FROM radacct WHERE UserName = ? AND $str2time AcctStopTime ) >= ? AND $str2time AcctStopTime ) < ? AND AcctStopTime IS NOT NULL" ) or die $dbh->errstr; - $sth->execute($attrib, $username, $start, $end) or die $sth->errstr; + $sth->execute($username, $start, $end) or die $sth->errstr; $sum += $sth->fetchrow_arrayref->[0]; -- cgit v1.2.1 From 4014161f196408567c02ce3fe5a0cd3c27f633c7 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 6 Nov 2002 04:23:22 +0000 Subject: safe regex for sqlradius hour/data billing, closes: Bug#474 --- FS/FS/part_pkg.pm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'FS') diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm index e914636e4..f290420df 100644 --- a/FS/FS/part_pkg.pm +++ b/FS/FS/part_pkg.pm @@ -218,6 +218,8 @@ sub check { or $r =~ /^my \$min = \$cust_pkg\->seconds_since\(\$cust_pkg\->bill \|\| 0\) \/ 60 \- \s*\d*\.?\d*\s*; \$min = 0 if \$min < 0; \s*\d*\.?\d*\s* \+ \s*\d*\.?\d*\s* \* \$min;\s*$/ + or $r =~ /^my \$last_bill = \$cust_pkg\->last_bill; my \$hours = \$cust_pkg\->seconds_since_sqlradacct\(\$last_bill, \$sdate \) \/ 3600 - \s*\d\.?\d*\s*; \$hours = 0 if \$hours < 0; my \$input = \$cust_pkg\->attribute_since_sqlradacct\(\$last_bill, \$sdate, "AcctInputOctets" \) \/ 1048576; my \$output = \$cust_pkg\->attribute_since_sqlradacct\(\$last_bill, \$sdate, "AcctOutputOctets" \) \/ 1048576; my \$total = \$input \+ \$output \- \s*\d\.?\d*\s*; \$total = 0 if \$total < 0; my \$input = \$input - \s*\d\.?\d*\s*; \$input = 0 if \$input < 0; my \$output = \$output - \s*\d\.?\d*\s*; \$output = 0 if \$output < 0; \s*\d\.?\d*\s* \+ \s*\d\.?\d*\s* \* \$hours \+ \s*\d\.?\d*\s* \* \$input \+ \s*\d\.?\d*\s* \* \$output \+ \s*\d\.?\d*\s* \* \$total *;\s*$/ + or do { #log! return "illegal recur: $r"; @@ -295,10 +297,6 @@ sub payby { =back -=head1 VERSION - -$Id: part_pkg.pm,v 1.16 2002-06-10 01:39:50 khoff Exp $ - =head1 BUGS The delete method is unimplemented. -- cgit v1.2.1 From 825c291369542af6f66fa6e08d1762374b5388a1 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 7 Nov 2002 22:53:53 +0000 Subject: doc --- FS/FS/cust_main.pm | 2 ++ 1 file changed, 2 insertions(+) (limited to 'FS') diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index d6e4bc1e3..f9f473db9 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -172,6 +172,8 @@ FS::Record. The following fields are currently supported: =item comments - comments (optional) +=item referral_custnum - referring customer number + =back =head1 METHODS -- cgit v1.2.1 From 9efddfba948a749413d11970e6106651b9a41d2d Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 16 Nov 2002 10:33:16 +0000 Subject: separate ACH processor support --- FS/FS/Conf.pm | 11 ++++++++-- FS/FS/cust_bill.pm | 60 +++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 50 insertions(+), 21 deletions(-) (limited to 'FS') diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index c007a501a..e76ea3873 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -268,6 +268,13 @@ httemplate/docs/config.html 'type' => 'textarea', }, + { + 'key' => 'business-onlinepayment-ach', + 'section' => 'billing', + 'description' => 'Alternate Business::OnlinePayment support for ACH transactions (defaults to regular business-onlinepayment). At least three lines: processor, login, and password. An optional fourth line specifies the action or actions (multiple actions are separated with `,\': for example: `Authorization Only, Post Authorization\'). Optional additional lines are passed to Business::OnlinePayment as %processor_options.', + 'type' => 'textarea', + }, + { 'key' => 'business-onlinepayment-description', 'section' => 'billing', @@ -877,7 +884,7 @@ httemplate/docs/config.html 'section' => '', 'description' => 'Acceptable payment types for the signup server', 'type' => 'selectmultiple', - 'select_enum' => [ qw(CARD CHEK PREPAY BILL COMP) ], + 'select_enum' => [ qw(CARD CHEK LECB PREPAY BILL COMP) ], }, { @@ -964,7 +971,7 @@ httemplate/docs/config.html 'section' => 'UI', 'description' => 'Default payment type. HIDE disables display of billing information and sets customers to BILL.', 'type' => 'select', - 'select_enum' => [ '', qw(CARD CHEK BILL COMP HIDE) ], + 'select_enum' => [ '', qw(CARD CHEK LECB BILL COMP HIDE) ], }, { diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 54641ee35..708b99746 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -3,9 +3,9 @@ package FS::cust_bill; use strict; use vars qw( @ISA $conf $money_char ); use vars qw( $lpr $invoice_from $smtpmachine ); -use vars qw( $processor ); use vars qw( $xaction $E_NoErr ); use vars qw( $bop_processor $bop_login $bop_password $bop_action @bop_options ); +use vars qw( $ach_processor $ach_login $ach_password $ach_action @ach_options ); use vars qw( $invoice_lines @buf ); #yuck use Date::Format; use Mail::Internet 1.44; @@ -43,8 +43,20 @@ $FS::UID::callback{'FS::cust_bill'} = sub { @bop_options ) = $conf->config('business-onlinepayment'); $bop_action ||= 'normal authorization'; + ( $ach_processor, $ach_login, $ach_password, $ach_action, @ach_options ) = + ( $bop_processor, $bop_login, $bop_password, $bop_action, @bop_options ); + eval "use Business::OnlinePayment"; + } + + if ( $conf->exists('business-onlinepayment-ach') ) { + ( $ach_processor, + $ach_login, + $ach_password, + $ach_action, + @ach_options + ) = $conf->config('business-onlinepayment-ach'); + $ach_action ||= 'normal authorization'; eval "use Business::OnlinePayment"; - $processor="Business::OnlinePayment::$bop_processor"; } }; @@ -592,7 +604,15 @@ for supported processors. sub realtime_card { my $self = shift; - $self->realtime_bop('CC', @_); + $self->realtime_bop( + 'CC', + $bop_processor, + $bop_login, + $bop_password, + $bop_action, + \@bop_options, + @_ + ); } =item realtime_ach @@ -606,20 +626,22 @@ for supported processors. sub realtime_ach { my $self = shift; - $self->realtime_bop('CHECK', @_); + $self->realtime_bop( + 'CHECK', + $ach_processor, + $ach_login, + $ach_password, + $ach_action, + \@ach_options, + @_ + ); } sub realtime_bop { - my $self = shift; - my $method = shift; + my( $self, $method, $processor, $login, $password, $action, $options ) = @_; my $cust_main = $self->cust_main; my $amount = $self->owed; - unless ( $processor =~ /^Business::OnlinePayment::(.*)$/ ) { - return "Real-time card/ACH processing not enabled (processor $processor)"; - } - my $bop_processor = $1; #hmm? - my $address = $cust_main->address1; $address .= ", ". $cust_main->address2 if $cust_main->address2; @@ -645,7 +667,7 @@ sub realtime_bop { } my $email = $invoicing_list[0]; - my( $action1, $action2 ) = split(/\s*\,\s*/, $bop_action ); + my( $action1, $action2 ) = split(/\s*\,\s*/, $action ); my $description = 'Internet Services'; if ( $conf->exists('business-onlinepayment-description') ) { @@ -676,12 +698,12 @@ sub realtime_bop { } my $transaction = - new Business::OnlinePayment( $bop_processor, @bop_options ); + new Business::OnlinePayment( $processor, @$options ); $transaction->content( %content, 'type' => $method, - 'login' => $bop_login, - 'password' => $bop_password, + 'login' => $login, + 'password' => $password, 'action' => $action1, 'description' => $description, 'amount' => $amount, @@ -710,14 +732,14 @@ sub realtime_bop { #warn "********* $auth ***********\n"; #warn "********* $ordernum ***********\n"; my $capture = - new Business::OnlinePayment( $bop_processor, @bop_options ); + new Business::OnlinePayment( $processor, @$options ); my %capture = ( %content, type => $method, action => $action2, - login => $bop_login, - password => $bop_password, + login => $login, + password => $password, order_number => $ordernum, amount => $amount, authorization => $auth, @@ -1074,7 +1096,7 @@ sub print_text { =head1 VERSION -$Id: cust_bill.pm,v 1.50 2002-10-15 09:54:24 ivan Exp $ +$Id: cust_bill.pm,v 1.51 2002-11-16 10:33:16 ivan Exp $ =head1 BUGS -- cgit v1.2.1 From b0995f6ec4eeaad9c72be4963970f1d69fe1ef02 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 18 Nov 2002 10:15:37 +0000 Subject: preliminary ldap export --- FS/FS/part_export.pm | 32 +++++++ FS/FS/part_export/ldap.pm | 238 ++++++++++++++++++++++++++++++++++++++++++++++ FS/MANIFEST | 2 + FS/t/part_export-ldap.t | 5 + 4 files changed, 277 insertions(+) create mode 100644 FS/FS/part_export/ldap.pm create mode 100644 FS/t/part_export-ldap.t (limited to 'FS') diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm index 5d725ab22..79fe91396 100644 --- a/FS/FS/part_export.pm +++ b/FS/FS/part_export.pm @@ -724,6 +724,32 @@ tie my %sqlmail_options, 'Tie::IxHash', 'password' => { label=>'Database password' }, ; +tie my %ldap_options, 'Tie::IxHash', + 'dn' => { label=>'DN' }, + 'password' => { label=>'Optional DN password' }, + 'attributes' => { label=>'Attributes', + type=>'textarea', + default=>join("\n", + 'uid $username', + 'mail $username\@$domain', + 'uidno $uid', + 'gidno $gid', + 'cn $first', + 'sn $last', + 'mailquota $quota', + 'vmail', + 'location', + 'mailtag', + 'mailhost', + 'mailmessagestore $dir', + 'userpassword $crypt_password', + 'hint', + 'answer $sec_phrase', + ), + }, + 'radius' => { label=>'Export RADIUS attributes', type=>'checkbox', }, +; + #export names cannot have dashes... %exports = ( @@ -766,6 +792,12 @@ tie my %sqlmail_options, 'Tie::IxHash', 'notes' => 'Run remote commands via SSH. username@domain (rather than just usernames) are considered unique (also see shellcommands). You probably want this if the commands you are running will accept a domain as a parameter, and will allow the same username with different domains. You will need to setup SSH for unattended operation.', }, + 'ldap' => { + 'desc' => 'Real-time export to LDAP', + 'options' => \%ldap_options, + 'notes' => 'Real-time export to arbitrary LDAP attributes. Requires installation of Net::LDAP from CPAN.', + }, + 'sqlradius' => { 'desc' => 'Real-time export to SQL-backed RADIUS (ICRADIUS, FreeRADIUS)', 'options' => \%sqlradius_options, diff --git a/FS/FS/part_export/ldap.pm b/FS/FS/part_export/ldap.pm new file mode 100644 index 000000000..40f27d695 --- /dev/null +++ b/FS/FS/part_export/ldap.pm @@ -0,0 +1,238 @@ +package FS::part_export::ldap; + +use vars qw(@ISA); +use FS::Record qw( dbh ); +use FS::part_export; + +@ISA = qw(FS::part_export); + +sub rebless { shift; } + +sub _export_insert { + my($self, $svc_acct) = (shift, shift); + + #false laziness w/shellcommands.pm + { + no strict 'refs'; + ${$_} = $svc_acct->getfield($_) foreach $svc_acct->fields; + ${$_} = $svc_acct->$_() foreach qw( domain ); + my $cust_pkg = $svc_acct->cust_svc->cust_pkg; + if ( $cust_pkg ) { + my $cust_main = $cust_pkg->cust_main; + ${$_} = $cust_main->getfield($_) foreach qw(first last); + } + } + $crypt_password = ''; #surpress "used only once" warnings + $crypt_password = crypt( $svc_acct->_password, + $saltset[int(rand(64))].$saltset[int(rand(64))] ); + + + my %attrib = map { /^\s*(\w+)\s+(.*\S)\s*$/; ( $1 => eval(qq("$2")) ); } + grep { /^\s*(\w+)\s+(.*\S)\s*$/ } + split("\n", $self->option('attributes')); + + if ( $self->option('radius') { + foreach my $table (qw(reply check)) { + my $method = "radius_$table"; + my %radius = $svc_acct->$method(); + foreach my $radius ( keys %radius ) { + ( my $ldap = $radius ) =~ s/\-//g; + $attrib{$ldap} = $radius{$radius}; + } + } + } + + my $err_or_queue = $self->ldap_queue( $svc_acct->svcnum, 'insert', + #$svc_acct->username, + %attrib ); + return $err_or_queue unless ref($err_or_queue); + + #groups with LDAP? + #my @groups = $svc_acct->radius_groups; + #if ( @groups ) { + # my $err_or_queue = $self->ldap_queue( + # $svc_acct->svcnum, 'usergroup_insert', + # $svc_acct->username, @groups ); + # return $err_or_queue unless ref($err_or_queue); + #} + + ''; +} + +sub _export_replace { + my( $self, $new, $old ) = (shift, shift, shift); + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + return "can't (yet?) change username with ldap" + if $old->username ne $new->username; + + return "ldap replace unimplemented"; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $jobnum = ''; + #if ( $old->username ne $new->username ) { + # my $err_or_queue = $self->ldap_queue( $new->svcnum, 'rename', + # $new->username, $old->username ); + # unless ( ref($err_or_queue) ) { + # $dbh->rollback if $oldAutoCommit; + # return $err_or_queue; + # } + # $jobnum = $err_or_queue->jobnum; + #} + + foreach my $table (qw(reply check)) { + my $method = "radius_$table"; + my %new = $new->$method(); + my %old = $old->$method(); + if ( grep { !exists $old{$_} #new attributes + || $new{$_} ne $old{$_} #changed + } keys %new + ) { + my $err_or_queue = $self->ldap_queue( $new->svcnum, 'insert', + $table, $new->username, %new ); + unless ( ref($err_or_queue) ) { + $dbh->rollback if $oldAutoCommit; + return $err_or_queue; + } + if ( $jobnum ) { + my $error = $err_or_queue->depend_insert( $jobnum ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + } + + my @del = grep { !exists $new{$_} } keys %old; + if ( @del ) { + my $err_or_queue = $self->ldap_queue( $new->svcnum, 'attrib_delete', + $table, $new->username, @del ); + unless ( ref($err_or_queue) ) { + $dbh->rollback if $oldAutoCommit; + return $err_or_queue; + } + if ( $jobnum ) { + my $error = $err_or_queue->depend_insert( $jobnum ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + } + } + + # (sorta) false laziness with FS::svc_acct::replace + my @oldgroups = @{$old->usergroup}; #uuuh + my @newgroups = $new->radius_groups; + my @delgroups = (); + foreach my $oldgroup ( @oldgroups ) { + if ( grep { $oldgroup eq $_ } @newgroups ) { + @newgroups = grep { $oldgroup ne $_ } @newgroups; + next; + } + push @delgroups, $oldgroup; + } + + if ( @delgroups ) { + my $err_or_queue = $self->ldap_queue( $new->svcnum, 'usergroup_delete', + $new->username, @delgroups ); + unless ( ref($err_or_queue) ) { + $dbh->rollback if $oldAutoCommit; + return $err_or_queue; + } + if ( $jobnum ) { + my $error = $err_or_queue->depend_insert( $jobnum ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + } + + if ( @newgroups ) { + my $err_or_queue = $self->ldap_queue( $new->svcnum, 'usergroup_insert', + $new->username, @newgroups ); + unless ( ref($err_or_queue) ) { + $dbh->rollback if $oldAutoCommit; + return $err_or_queue; + } + if ( $jobnum ) { + my $error = $err_or_queue->depend_insert( $jobnum ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + + ''; +} + +sub _export_delete { + my( $self, $svc_acct ) = (shift, shift); + return "ldap delete unimplemented"; + my $err_or_queue = $self->ldap_queue( $svc_acct->svcnum, 'delete', + $svc_acct->username ); + ref($err_or_queue) ? '' : $err_or_queue; +} + +sub ldap_queue { + my( $self, $svcnum, $method ) = (shift, shift, shift); + my $queue = new FS::queue { + 'svcnum' => $svcnum, + 'job' => "FS::part_export::ldap::ldap_$method", + }; + $queue->insert( + $self->machine, + $self->option('dn'), + $self->option('password'), + @_, + ) or $queue; +} + +sub ldap_insert { #subroutine, not method + my $dn = ldap_connect(shift, shift, shift); + my %attrib = @_; + + my $status = $ldap->add( $dn, attrs => [ %attrib ] ); + die $status->error if $status->is_error; + + $ldap->unbind; +} + +#sub ldap_delete { #subroutine, not method +# my $dbh = ldap_connect(shift, shift, shift); +# my $username = shift; +# +# foreach my $table (qw( radcheck radreply usergroup )) { +# my $sth = $dbh->prepare( "DELETE FROM $table WHERE UserName = ?" ); +# $sth->execute($username) +# or die "can't delete from $table table: ". $sth->errstr; +# } +# $dbh->disconnect; +#} + +sub ldap_connect { + my( $machine, $dn, $password ) = @_; + + eval "use Net::LDAP"; + die $@ if $@; + + my $ldap = Net::LDAP->net($machine) or die $@; + my $status = $ldap->bind( $dn, password=>$password ); + die $status->error if $status->is_error; + + $dn; +} + diff --git a/FS/MANIFEST b/FS/MANIFEST index e37216e19..47c3bf206 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -75,6 +75,7 @@ FS/part_export/cyrus.pm FS/part_export/domain_shellcommands.pm FS/part_export/http.pm FS/part_export/infostreet.pm +FS/part_export/ldap.pm FS/part_export/null.pm FS/part_export/shellcommands.pm FS/part_export/shellcommands_withdomain.pm @@ -149,6 +150,7 @@ t/part_export-cyrus.t t/part_export-domain_shellcommands.t t/part_export-http.t t/part_export-infostreet.t +t/part_export-ldap.t t/part_export-null.t t/part_export-shellcommands.t t/part_export-shellcommands_withdomain.t diff --git a/FS/t/part_export-ldap.t b/FS/t/part_export-ldap.t new file mode 100644 index 000000000..826c3418d --- /dev/null +++ b/FS/t/part_export-ldap.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::part_export::ldap; +$loaded=1; +print "ok 1\n"; -- cgit v1.2.1 From 789c34c5251f4b831a7cb27bd2a9af700ccf2ced Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 19 Nov 2002 09:51:59 +0000 Subject: add LEC billing --- FS/FS/cust_bill.pm | 29 +++++++++++++++++++++++++++-- FS/FS/cust_main.pm | 17 +++++++++++++---- FS/FS/cust_pay.pm | 6 +++--- FS/FS/cust_refund.pm | 6 +++--- FS/FS/part_bill_event.pm | 4 ++-- FS/FS/part_export/ldap.pm | 2 +- FS/FS/part_pkg.pm | 2 ++ 7 files changed, 51 insertions(+), 15 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 708b99746..a682c5958 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -637,6 +637,28 @@ sub realtime_ach { ); } +=item realtime_lec + +Attempts to pay this invoice with phone bill (LEC) payment via a +Business::OnlinePayment realtime gateway. See +http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment +for supported processors. + +=cut + +sub realtime_ach { + my $self = shift; + $self->realtime_bop( + 'LEC', + $bop_processor, + $bop_login, + $bop_password, + $bop_action, + \@bop_options, + @_ + ); +} + sub realtime_bop { my( $self, $method, $processor, $login, $password, $action, $options ) = @_; my $cust_main = $self->cust_main; @@ -695,12 +717,13 @@ sub realtime_bop { ( $content{account_number}, $content{routing_code} ) = split('@', $cust_main->payinfo); $content{bank_name} = $cust_main->payname; + } elsif ( $method eq 'LEC' ) { + $content{phone} = $cust_main->payinfo; } my $transaction = new Business::OnlinePayment( $processor, @$options ); $transaction->content( - %content, 'type' => $method, 'login' => $login, 'password' => $password, @@ -720,6 +743,7 @@ sub realtime_bop { 'referer' => 'http://cleanwhisker.420.am/', 'email' => $email, 'phone' => $cust_main->daytime || $cust_main->night, + %content, #after ); $transaction->submit(); @@ -771,6 +795,7 @@ sub realtime_bop { my %method2payby = ( 'CC' => 'CARD', 'CHECK' => 'CHEK', + 'LEC' => 'LECB', ); my $cust_pay = new FS::cust_pay ( { @@ -1096,7 +1121,7 @@ sub print_text { =head1 VERSION -$Id: cust_bill.pm,v 1.51 2002-11-16 10:33:16 ivan Exp $ +$Id: cust_bill.pm,v 1.52 2002-11-19 09:51:58 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index f9f473db9..4a5cff2fc 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -158,7 +158,7 @@ FS::Record. The following fields are currently supported: =item ship_fax - phone (optional) -=item payby - `CARD' (credit cards), `CHEK' (electronic check), `BILL' (billing), `COMP' (free), or `PREPAY' (special billing type: applies a credit - see L and sets billing type to BILL) +=item payby - `CARD' (credit cards), `CHEK' (electronic check), `LECB' (Phone bill billing), `BILL' (billing), `COMP' (free), or `PREPAY' (special billing type: applies a credit - see L and sets billing type to BILL) =item payinfo - card number, P.O., comp issuer (4-8 lowercase alphanumerics; think username) or prepayment identifier (see L) @@ -484,14 +484,15 @@ sub replace { $self->invoicing_list( $invoicing_list ); } - if ( $self->payby =~ /^(CARD|CHEK)$/ && + if ( $self->payby =~ /^(CARD|CHEK|LECB)$/ && grep { $self->get($_) ne $old->get($_) } qw(payinfo paydate payname) ) { # card/check info has changed, want to retry realtime_card invoice events #false laziness w/collect foreach my $cust_bill_event ( grep { #$_->part_bill_event->plan eq 'realtime-card' - $_->part_bill_event->eventcode eq '$cust_bill->realtime_card();' + $_->part_bill_event->eventcode =~ + /^\$cust_bill\->realtime_(card|ach|lec)\(\);$/ && $_->status eq 'done' && $_->statustext } @@ -691,6 +692,14 @@ sub check { $payinfo = "$1\@$2"; $self->payinfo($payinfo); + } elsif ( $self->payby eq 'LECB' ) { + + my $payinfo = $self->payinfo; + $payinfo =~ s/\D//g; + $payinfo =~ /^1?(\d{10})$/ or return 'invalid btn billing telephone number'; + $payinfo = $1; + $self->payinfo($payinfo); + } elsif ( $self->payby eq 'BILL' ) { $error = $self->ut_textn('payinfo'); @@ -715,7 +724,7 @@ sub check { if ( $self->paydate eq '' || $self->paydate eq '-' ) { return "Expriation date required" - unless $self->payby =~ /^(BILL|PREPAY|CHEK)$/; + unless $self->payby =~ /^(BILL|PREPAY|CHEK|LECB)$/; $self->paydate(''); } else { $self->paydate =~ /^(\d{1,2})[\/\-](\d{2}(\d{2})?)$/ diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index 222691408..79cf82755 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -61,7 +61,7 @@ currently supported: L and L for conversion functions. =item payby - `CARD' (credit cards), `CHEK' (electronic check/ACH), -`BILL' (billing), or `COMP' (free) +`LECB' (phone bill billing), `BILL' (billing), or `COMP' (free) =item payinfo - card number, check #, or comp issuer (4-8 lowercase alphanumerics; think username), respectively @@ -347,7 +347,7 @@ sub check { $self->_date(time) unless $self->_date; - $self->payby =~ /^(CARD|CHEK|BILL|COMP)$/ or return "Illegal payby"; + $self->payby =~ /^(CARD|CHEK|LECB|BILL|COMP)$/ or return "Illegal payby"; $self->payby($1); #false laziness with cust_refund::check @@ -406,7 +406,7 @@ sub unapplied { =head1 VERSION -$Id: cust_pay.pm,v 1.22 2002-10-12 10:15:55 ivan Exp $ +$Id: cust_pay.pm,v 1.23 2002-11-19 09:51:58 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_refund.pm b/FS/FS/cust_refund.pm index aac320e61..763671736 100644 --- a/FS/FS/cust_refund.pm +++ b/FS/FS/cust_refund.pm @@ -48,7 +48,7 @@ inherits from FS::Record. The following fields are currently supported: L and L for conversion functions. =item payby - `CARD' (credit cards), `CHEK' (electronic check/ACH), -`BILL' (billing), or `COMP' (free) +`LECB' (Phone bill billing), `BILL' (billing), or `COMP' (free) =item payinfo - card number, P.O.#, or comp issuer (4-8 lowercase alphanumerics; think username) @@ -235,7 +235,7 @@ sub check { unless $self->crednum || qsearchs( 'cust_main', { 'custnum' => $self->custnum } ); - $self->payby =~ /^(CARD|CHEK|BILL|COMP)$/ or return "Illegal payby"; + $self->payby =~ /^(CARD|CHEK|LECB|BILL|COMP)$/ or return "Illegal payby"; $self->payby($1); #false laziness with cust_pay::check @@ -267,7 +267,7 @@ sub check { =head1 VERSION -$Id: cust_refund.pm,v 1.19 2002-10-12 10:15:55 ivan Exp $ +$Id: cust_refund.pm,v 1.20 2002-11-19 09:51:58 ivan Exp $ =head1 BUGS diff --git a/FS/FS/part_bill_event.pm b/FS/FS/part_bill_event.pm index e86b5c1fb..dc10be879 100644 --- a/FS/FS/part_bill_event.pm +++ b/FS/FS/part_bill_event.pm @@ -37,7 +37,7 @@ FS::Record. The following fields are currently supported: =item eventpart - primary key -=item payby - CARD, CHEK, BILL, or COMP +=item payby - CARD, CHEK, LECB, BILL, or COMP =item event - event name @@ -140,7 +140,7 @@ sub check { } my $error = $self->ut_numbern('eventpart') - || $self->ut_enum('payby', [qw( CARD CHEK BILL COMP )] ) + || $self->ut_enum('payby', [qw( CARD CHEK LECB BILL COMP )] ) || $self->ut_text('event') || $self->ut_anything('eventcode') || $self->ut_number('seconds') diff --git a/FS/FS/part_export/ldap.pm b/FS/FS/part_export/ldap.pm index 40f27d695..ec1d37fd5 100644 --- a/FS/FS/part_export/ldap.pm +++ b/FS/FS/part_export/ldap.pm @@ -31,7 +31,7 @@ sub _export_insert { grep { /^\s*(\w+)\s+(.*\S)\s*$/ } split("\n", $self->option('attributes')); - if ( $self->option('radius') { + if ( $self->option('radius') ) { foreach my $table (qw(reply check)) { my $method = "radius_$table"; my %radius = $svc_acct->$method(); diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm index f290420df..99d88d56a 100644 --- a/FS/FS/part_pkg.pm +++ b/FS/FS/part_pkg.pm @@ -282,6 +282,8 @@ following logic instead; If the package has B<0> setup and B<0> recur, the single item B is returned, otherwise, the single item B is returned. +(CHEK? LEC? Probably shouldn't accept those by default, prone to abuse) + =cut sub payby { -- cgit v1.2.1 From ec28c4e3c2a08f0057020b81907174e84a654d25 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 19 Nov 2002 10:02:19 +0000 Subject: silly regex bug parsing echeck info --- FS/FS/cust_main.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 4a5cff2fc..a8b1dc291 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -687,7 +687,7 @@ sub check { } elsif ( $self->payby eq 'CHEK' ) { my $payinfo = $self->payinfo; - $payinfo =~ s/[\D\@]//g; + $payinfo =~ s/[^\d\@]//g; $payinfo =~ /^(\d+)\@(\d{9})$/ or return 'invalid echeck account@aba'; $payinfo = "$1\@$2"; $self->payinfo($payinfo); -- cgit v1.2.1 From 103cdcd9ea5630d3b1ce263345c48cd8d261e34c Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 19 Nov 2002 10:09:34 +0000 Subject: typo adding lec transactions --- FS/FS/cust_bill.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index a682c5958..3e9377802 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -646,7 +646,7 @@ for supported processors. =cut -sub realtime_ach { +sub realtime_lec { my $self = shift; $self->realtime_bop( 'LEC', @@ -1121,7 +1121,7 @@ sub print_text { =head1 VERSION -$Id: cust_bill.pm,v 1.52 2002-11-19 09:51:58 ivan Exp $ +$Id: cust_bill.pm,v 1.53 2002-11-19 10:09:34 ivan Exp $ =head1 BUGS -- cgit v1.2.1 From 55bfcaa26d8cc7729a8fbaa3a5325e4372588e8b Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 19 Nov 2002 20:36:43 +0000 Subject: increase length of reczone and recdata fields in domain_record --- FS/bin/freeside-setup | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'FS') diff --git a/FS/bin/freeside-setup b/FS/bin/freeside-setup index d61e8b0bf..587f0158b 100755 --- a/FS/bin/freeside-setup +++ b/FS/bin/freeside-setup @@ -805,10 +805,12 @@ sub tables_hash_hack { 'columns' => [ 'recnum', 'serial', '', '', 'svcnum', 'int', '', '', - 'reczone', 'varchar', '', $char_d, + #'reczone', 'varchar', '', $char_d, + 'reczone', 'varchar', '', 255, 'recaf', 'char', '', 2, 'rectype', 'char', '', 5, - 'recdata', 'varchar', '', $char_d, + #'recdata', 'varchar', '', $char_d, + 'recdata', 'varchar', '', 255, ], 'primary_key' => 'recnum', 'unique' => [], -- cgit v1.2.1 From f5be6be6a52ee4461243eeaadcf769c14571b82f Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 19 Nov 2002 20:56:12 +0000 Subject: ldap export update --- FS/FS/part_export/ldap.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/part_export/ldap.pm b/FS/FS/part_export/ldap.pm index ec1d37fd5..6077b7418 100644 --- a/FS/FS/part_export/ldap.pm +++ b/FS/FS/part_export/ldap.pm @@ -229,7 +229,7 @@ sub ldap_connect { eval "use Net::LDAP"; die $@ if $@; - my $ldap = Net::LDAP->net($machine) or die $@; + my $ldap = Net::LDAP->new($machine) or die $@; my $status = $ldap->bind( $dn, password=>$password ); die $status->error if $status->is_error; -- cgit v1.2.1 From bf79e1879f8f6b309391a71c9d563d9ee8782e36 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 19 Nov 2002 21:20:03 +0000 Subject: ldap export: don't use password if not given --- FS/FS/part_export/ldap.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/part_export/ldap.pm b/FS/FS/part_export/ldap.pm index 6077b7418..776814c59 100644 --- a/FS/FS/part_export/ldap.pm +++ b/FS/FS/part_export/ldap.pm @@ -225,12 +225,14 @@ sub ldap_insert { #subroutine, not method sub ldap_connect { my( $machine, $dn, $password ) = @_; + my %bind_options; + $bind_options{password} = $password if length($password); eval "use Net::LDAP"; die $@ if $@; my $ldap = Net::LDAP->new($machine) or die $@; - my $status = $ldap->bind( $dn, password=>$password ); + my $status = $ldap->bind( $dn, %bind_options ); die $status->error if $status->is_error; $dn; -- cgit v1.2.1 From 34928158d52fb8456aa665c4bacd1f915b9cae0d Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 19 Nov 2002 22:48:02 +0000 Subject: Business::OnlinePayment type is ECHECK not CHECK --- FS/FS/cust_bill.pm | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 3e9377802..75e2b1718 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -627,7 +627,7 @@ for supported processors. sub realtime_ach { my $self = shift; $self->realtime_bop( - 'CHECK', + 'ECHECK', $ach_processor, $ach_login, $ach_password, @@ -668,7 +668,7 @@ sub realtime_bop { $address .= ", ". $cust_main->address2 if $cust_main->address2; my($payname, $payfirst, $paylast); - if ( $cust_main->payname && $method ne 'CHECK' ) { + if ( $cust_main->payname && $method ne 'ECHECK' ) { $payname = $cust_main->payname; $payname =~ /^\s*([\w \,\.\-\']*)?\s+([\w\,\.\-\']+)\s*$/ or do { @@ -712,7 +712,7 @@ sub realtime_bop { $content{card_number} = $cust_main->payinfo; $cust_main->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; $content{expiration} = "$2/$1"; - } elsif ( $method eq 'CHECK' ) { + } elsif ( $method eq 'ECHECK' ) { my($account_number,$routing_code) = $cust_main->payinfo; ( $content{account_number}, $content{routing_code} ) = split('@', $cust_main->payinfo); @@ -793,9 +793,9 @@ sub realtime_bop { if ( $transaction->is_success() ) { my %method2payby = ( - 'CC' => 'CARD', - 'CHECK' => 'CHEK', - 'LEC' => 'LECB', + ' CC' => 'CARD', + 'ECHECK' => 'CHEK', + 'LEC' => 'LECB', ); my $cust_pay = new FS::cust_pay ( { @@ -1121,7 +1121,7 @@ sub print_text { =head1 VERSION -$Id: cust_bill.pm,v 1.53 2002-11-19 10:09:34 ivan Exp $ +$Id: cust_bill.pm,v 1.54 2002-11-19 22:48:02 ivan Exp $ =head1 BUGS -- cgit v1.2.1 From 26da8f3994e58ca5cf80ac62f034b3ad64539e47 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 19 Nov 2002 22:55:06 +0000 Subject: give better error message on bad invnum, also 'use FS::cust_bill' here --- FS/FS/cust_bill_event.pm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_bill_event.pm b/FS/FS/cust_bill_event.pm index f631987aa..44e4d4797 100644 --- a/FS/FS/cust_bill_event.pm +++ b/FS/FS/cust_bill_event.pm @@ -3,6 +3,7 @@ package FS::cust_bill_event; use strict; use vars qw( @ISA ); use FS::Record qw( qsearch qsearchs ); +use FS::cust_bill; use FS::part_bill_event; @ISA = qw(FS::Record); @@ -111,10 +112,10 @@ sub check { || $self->ut_textn('statustext') ; - return "Unknown invnum" + return "Unknown invnum ". $self->invnum unless qsearchs( 'cust_bill' ,{ 'invnum' => $self->invnum } ); - return "Unknown eventpart" + return "Unknown eventpart ". $self->eventpart unless qsearchs( 'part_bill_event' ,{ 'eventpart' => $self->eventpart } ); ''; #no error -- cgit v1.2.1 From cfd4d4d5fd2c64f0f0512905a465aeb4abce484c Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 20 Nov 2002 09:07:27 +0000 Subject: ugh... need to increase length of payinfo field in cust_pay and cust_refund for ACH --- FS/bin/freeside-setup | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'FS') diff --git a/FS/bin/freeside-setup b/FS/bin/freeside-setup index 587f0158b..8f3d99fd5 100755 --- a/FS/bin/freeside-setup +++ b/FS/bin/freeside-setup @@ -541,7 +541,7 @@ sub tables_hash_hack { '_date', @date_type, 'payby', 'char', '', 4, # CARD/BILL/COMP, should be index into # payment type table. - 'payinfo', 'varchar', 'NULL', 16, #see cust_main above + 'payinfo', 'varchar', 'NULL', $char_d, #see cust_main above 'paybatch', 'varchar', 'NULL', $char_d, #for auditing purposes. 'closed', 'char', 'NULL', 1, ], @@ -618,7 +618,7 @@ sub tables_hash_hack { 'reason', 'varchar', '', $char_d, 'payby', 'char', '', 4, # CARD/BILL/COMP, should be index # into payment type table. - 'payinfo', 'varchar', 'NULL', 16, #see cust_main above + 'payinfo', 'varchar', 'NULL', $char_d, #see cust_main above 'paybatch', 'varchar', 'NULL', $char_d, 'closed', 'char', 'NULL', 1, ], -- cgit v1.2.1 From 4631154982b0607405c2cabc8f1a718445307f4d Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 20 Nov 2002 09:10:02 +0000 Subject: fix silly bug in ldap export --- FS/FS/part_export/ldap.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'FS') diff --git a/FS/FS/part_export/ldap.pm b/FS/FS/part_export/ldap.pm index 776814c59..57d213af0 100644 --- a/FS/FS/part_export/ldap.pm +++ b/FS/FS/part_export/ldap.pm @@ -202,7 +202,7 @@ sub ldap_queue { } sub ldap_insert { #subroutine, not method - my $dn = ldap_connect(shift, shift, shift); + my $ldap = ldap_connect(shift, (my $dn = shift), shift); my %attrib = @_; my $status = $ldap->add( $dn, attrs => [ %attrib ] ); @@ -235,6 +235,6 @@ sub ldap_connect { my $status = $ldap->bind( $dn, %bind_options ); die $status->error if $status->is_error; - $dn; + $ldap; } -- cgit v1.2.1 From eb694678cbb835267b44c5eb9ff574ee1d7ce115 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 20 Nov 2002 10:09:19 +0000 Subject: hmm, so you add the username to the DN for the add call...? i don't get LDAP --- FS/FS/part_export/ldap.pm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'FS') diff --git a/FS/FS/part_export/ldap.pm b/FS/FS/part_export/ldap.pm index 57d213af0..6ff9abe12 100644 --- a/FS/FS/part_export/ldap.pm +++ b/FS/FS/part_export/ldap.pm @@ -27,7 +27,10 @@ sub _export_insert { $saltset[int(rand(64))].$saltset[int(rand(64))] ); - my %attrib = map { /^\s*(\w+)\s+(.*\S)\s*$/; ( $1 => eval(qq("$2")) ); } + my $username_attrib; + my %attrib = map { /^\s*(\w+)\s+(.*\S)\s*$/; + $username_attrib = $1 if $2 eq '$username'; + ( $1 => eval(qq("$2")) ); } grep { /^\s*(\w+)\s+(.*\S)\s*$/ } split("\n", $self->option('attributes')); @@ -44,6 +47,7 @@ sub _export_insert { my $err_or_queue = $self->ldap_queue( $svc_acct->svcnum, 'insert', #$svc_acct->username, + $username_attrib, %attrib ); return $err_or_queue unless ref($err_or_queue); @@ -203,7 +207,8 @@ sub ldap_queue { sub ldap_insert { #subroutine, not method my $ldap = ldap_connect(shift, (my $dn = shift), shift); - my %attrib = @_; + my( $username_attrib, %attrib ) = @_; + $dn = "$username_attrib=$attrib{$username_attrib}, $dn" if $username_attrib; my $status = $ldap->add( $dn, attrs => [ %attrib ] ); die $status->error if $status->is_error; -- cgit v1.2.1 From 96c1150cabe382dbafbdc8f4e89a2719fe24d605 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 20 Nov 2002 21:13:52 +0000 Subject: add objectclass and ability to have multiple comma-separated values to LDAP export --- FS/FS/part_export.pm | 1 + FS/FS/part_export/ldap.pm | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'FS') diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm index 79fe91396..86bd4240e 100644 --- a/FS/FS/part_export.pm +++ b/FS/FS/part_export.pm @@ -745,6 +745,7 @@ tie my %ldap_options, 'Tie::IxHash', 'userpassword $crypt_password', 'hint', 'answer $sec_phrase', + 'objectclass top,person,inetOrgPerson', ), }, 'radius' => { label=>'Export RADIUS attributes', type=>'checkbox', }, diff --git a/FS/FS/part_export/ldap.pm b/FS/FS/part_export/ldap.pm index 6ff9abe12..a28504313 100644 --- a/FS/FS/part_export/ldap.pm +++ b/FS/FS/part_export/ldap.pm @@ -208,7 +208,12 @@ sub ldap_queue { sub ldap_insert { #subroutine, not method my $ldap = ldap_connect(shift, (my $dn = shift), shift); my( $username_attrib, %attrib ) = @_; + $dn = "$username_attrib=$attrib{$username_attrib}, $dn" if $username_attrib; + #icky hack, but should be unsurprising to the LDAPers + foreach my $key ( grep { $attrib{$_} =~ /,/ } keys %attrib ) { + $attrib{$key} = [ split(/,/, $attrib{$key}) ]; + } my $status = $ldap->add( $dn, attrs => [ %attrib ] ); die $status->error if $status->is_error; -- cgit v1.2.1 From 4d04b87cf2223bea7c913f587a248c111862f070 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 21 Nov 2002 20:44:45 +0000 Subject: change DN labeling for those obtuse blockheads at netmagic --- FS/FS/part_export.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm index 86bd4240e..8e8a828e7 100644 --- a/FS/FS/part_export.pm +++ b/FS/FS/part_export.pm @@ -725,7 +725,7 @@ tie my %sqlmail_options, 'Tie::IxHash', ; tie my %ldap_options, 'Tie::IxHash', - 'dn' => { label=>'DN' }, + 'dn' => { label=>'Root DN' }, 'password' => { label=>'Optional DN password' }, 'attributes' => { label=>'Attributes', type=>'textarea', -- cgit v1.2.1 From 7a94fd2dd84ccb204e97e8cbd9ce4162e93fd12e Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 22 Nov 2002 07:50:23 +0000 Subject: separate root and user dn in ldap export --- FS/FS/part_export.pm | 3 ++- FS/FS/part_export/ldap.pm | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'FS') diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm index 8e8a828e7..4b15f44ca 100644 --- a/FS/FS/part_export.pm +++ b/FS/FS/part_export.pm @@ -726,7 +726,8 @@ tie my %sqlmail_options, 'Tie::IxHash', tie my %ldap_options, 'Tie::IxHash', 'dn' => { label=>'Root DN' }, - 'password' => { label=>'Optional DN password' }, + 'password' => { label=>'Root DN password' }, + 'userdn' => { label=>'User DN' }, 'attributes' => { label=>'Attributes', type=>'textarea', default=>join("\n", diff --git a/FS/FS/part_export/ldap.pm b/FS/FS/part_export/ldap.pm index a28504313..68a63528e 100644 --- a/FS/FS/part_export/ldap.pm +++ b/FS/FS/part_export/ldap.pm @@ -201,21 +201,23 @@ sub ldap_queue { $self->machine, $self->option('dn'), $self->option('password'), + $self->option('userdn'), @_, ) or $queue; } sub ldap_insert { #subroutine, not method - my $ldap = ldap_connect(shift, (my $dn = shift), shift); - my( $username_attrib, %attrib ) = @_; + my $ldap = ldap_connect(shift, shift, shift); + my( $userdn, $username_attrib, %attrib ) = @_; - $dn = "$username_attrib=$attrib{$username_attrib}, $dn" if $username_attrib; + $userdn = "$username_attrib=$attrib{$username_attrib}, $userdn" + if $username_attrib; #icky hack, but should be unsurprising to the LDAPers foreach my $key ( grep { $attrib{$_} =~ /,/ } keys %attrib ) { $attrib{$key} = [ split(/,/, $attrib{$key}) ]; } - my $status = $ldap->add( $dn, attrs => [ %attrib ] ); + my $status = $ldap->add( $userdn, attrs => [ %attrib ] ); die $status->error if $status->is_error; $ldap->unbind; -- cgit v1.2.1 From 071c5ee7dfb91ff3106310cedd002cff0554b9aa Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 22 Nov 2002 10:48:34 +0000 Subject: oops, one last LECB change --- FS/FS/cust_main.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index a8b1dc291..237abcddb 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -667,7 +667,7 @@ sub check { } } - $self->payby =~ /^(CARD|CHEK|BILL|COMP|PREPAY)$/ + $self->payby =~ /^(CARD|CHEK|LECB|BILL|COMP|PREPAY)$/ or return "Illegal payby: ". $self->payby; $self->payby($1); -- cgit v1.2.1 From 37dc3ebec42104e6ba77dae9a4d8dbdf31364678 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 22 Nov 2002 11:14:04 +0000 Subject: add lec billing event --- FS/FS/part_bill_event.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/part_bill_event.pm b/FS/FS/part_bill_event.pm index dc10be879..a75a011b0 100644 --- a/FS/FS/part_bill_event.pm +++ b/FS/FS/part_bill_event.pm @@ -124,7 +124,7 @@ sub check { $c =~ /^\s*\$cust_main\->(suspend|cancel|invoicing_list_addpost|bill|collect)\(\);\s*("";)?\s*$/ - or $c =~ /^\s*\$cust_bill\->(comp|realtime_card|realtime_ach|realtime_card_cybercash|batch_card|send)\(\);\s*$/ + or $c =~ /^\s*\$cust_bill\->(comp|realtime_(card|ach|lec)|realtime_card_cybercash|batch_card|send)\(\);\s*$/ or $c =~ /^\s*\$cust_bill\->send\(\'\w+\'\);\s*$/ -- cgit v1.2.1 From edb6a2341e74b303ea6278a294be9162ddc46c01 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 22 Nov 2002 12:19:15 +0000 Subject: fix nasty typo which would affect credit card payments --- FS/FS/cust_bill.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 75e2b1718..3481a9a86 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -793,7 +793,7 @@ sub realtime_bop { if ( $transaction->is_success() ) { my %method2payby = ( - ' CC' => 'CARD', + 'CC' => 'CARD', 'ECHECK' => 'CHEK', 'LEC' => 'LECB', ); @@ -1121,7 +1121,7 @@ sub print_text { =head1 VERSION -$Id: cust_bill.pm,v 1.54 2002-11-19 22:48:02 ivan Exp $ +$Id: cust_bill.pm,v 1.55 2002-11-22 12:19:15 ivan Exp $ =head1 BUGS -- cgit v1.2.1 From f4ea75e514763082b64e1b3654cfbbba2ddf1c01 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 25 Nov 2002 10:46:55 +0000 Subject: fix disappearing radius group bug, whew --- FS/FS/svc_acct.pm | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index c808aeea4..141133403 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -1,7 +1,7 @@ package FS::svc_acct; use strict; -use vars qw( @ISA $noexport_hack $conf +use vars qw( @ISA $DEBUG $me $noexport_hack $conf $dir_prefix @shells $usernamemin $usernamemax $passwordmin $passwordmax $username_ampersand $username_letter $username_letterfirst @@ -32,6 +32,9 @@ use FS::Msgcat qw(gettext); @ISA = qw( FS::svc_Common ); +$DEBUG = 0; +$me = '[FS::svc_acct]'; + #ask FS::UID to run this stuff for us later $FS::UID::callback{'FS::svc_acct'} = sub { $conf = new FS::Conf; @@ -496,6 +499,7 @@ sqlradius export only) sub replace { my ( $new, $old ) = ( shift, shift ); my $error; + warn "$me replacing $old with $new\n" if $DEBUG; return "Username in use" if $old->username ne $new->username && @@ -522,7 +526,13 @@ sub replace { local $FS::UID::AutoCommit = 0; my $dbh = dbh; + # redundant, but so $new->usergroup gets set + my $error = $new->check; + return $error if $error; + $old->usergroup( [ $old->radius_groups ] ); + warn "old groups: ". join(' ',@{$old->usergroup}). "\n" if $DEBUG; + warn "new groups: ". join(' ',@{$new->usergroup}). "\n" if $DEBUG; if ( $new->usergroup ) { #(sorta) false laziness with FS::part_export::sqlradius::_export_replace my @newgroups = @{$new->usergroup}; -- cgit v1.2.1 From 1caff2f971082d5ccce9928726b4b2e88678ee7a Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 26 Nov 2002 05:42:19 +0000 Subject: remove harmless re-my to silence warning --- FS/FS/svc_acct.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index 141133403..388b8dd88 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -527,7 +527,7 @@ sub replace { my $dbh = dbh; # redundant, but so $new->usergroup gets set - my $error = $new->check; + $error = $new->check; return $error if $error; $old->usergroup( [ $old->radius_groups ] ); -- cgit v1.2.1 From 3ac3bd76d4716016ba3a51f51a83a02732d9d2de Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 26 Nov 2002 10:25:55 +0000 Subject: ldap export: fix $crypt_password --- FS/FS/part_export/ldap.pm | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'FS') diff --git a/FS/FS/part_export/ldap.pm b/FS/FS/part_export/ldap.pm index 68a63528e..fd7f11d90 100644 --- a/FS/FS/part_export/ldap.pm +++ b/FS/FS/part_export/ldap.pm @@ -1,11 +1,13 @@ package FS::part_export::ldap; -use vars qw(@ISA); +use vars qw(@ISA @saltset); use FS::Record qw( dbh ); use FS::part_export; @ISA = qw(FS::part_export); +@saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' ); + sub rebless { shift; } sub _export_insert { @@ -26,7 +28,6 @@ sub _export_insert { $crypt_password = crypt( $svc_acct->_password, $saltset[int(rand(64))].$saltset[int(rand(64))] ); - my $username_attrib; my %attrib = map { /^\s*(\w+)\s+(.*\S)\s*$/; $username_attrib = $1 if $2 eq '$username'; @@ -218,7 +219,7 @@ sub ldap_insert { #subroutine, not method } my $status = $ldap->add( $userdn, attrs => [ %attrib ] ); - die $status->error if $status->is_error; + die 'LDAP error: '. $status->error. "\n" if $status->is_error; $ldap->unbind; } @@ -245,7 +246,7 @@ sub ldap_connect { my $ldap = Net::LDAP->new($machine) or die $@; my $status = $ldap->bind( $dn, %bind_options ); - die $status->error if $status->is_error; + die 'LDAP error: '. $status->error. "\n" if $status->is_error; $ldap; } -- cgit v1.2.1 From 5153f40717ef15e1d41aeb86d29b204e84c81509 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 28 Nov 2002 05:10:33 +0000 Subject: deprecate username_policy --- FS/FS/Conf.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index e76ea3873..6de311596 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -801,7 +801,7 @@ httemplate/docs/config.html { 'key' => 'username_policy', - 'section' => '', + 'section' => 'deprecated', 'description' => 'This file controls the mechanism for preventing duplicate usernames in passwd/radius files exported from svc_accts. This should be one of \'prepend domsvc\' \'append domsvc\' \'append domain\' or \'append @domain\'', 'type' => 'select', 'select_enum' => [ 'prepend domsvc', 'append domsvc', 'append domain', 'append @domain' ], -- cgit v1.2.1 From 3926b0ad41690f96041284fc12eb75e5f9b10357 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 28 Nov 2002 05:44:19 +0000 Subject: add -g FreeBSD shellcommands export as per "Stephen Bechard" --- FS/FS/part_export.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm index 4b15f44ca..d62bef50d 100644 --- a/FS/FS/part_export.pm +++ b/FS/FS/part_export.pm @@ -785,7 +785,7 @@ tie my %ldap_options, 'Tie::IxHash', 'desc' => 'Real-time export via remote SSH (i.e. useradd, userdel, etc.)', 'options' => \%shellcommands_options, 'nodomain' => 'Y', - 'notes' => 'Run remote commands via SSH. Usernames are considered unique (also see shellcommands_withdomain). You probably want this if the commands you are running will not accept a domain as a parameter. You will need to setup SSH for unattended operation.

Use these buttons for some useful presets:
', + 'notes' => 'Run remote commands via SSH. Usernames are considered unique (also see shellcommands_withdomain). You probably want this if the commands you are running will not accept a domain as a parameter. You will need to setup SSH for unattended operation.

Use these buttons for some useful presets:
', }, 'shellcommands_withdomain' => { -- cgit v1.2.1 From 20f37c06d04ecf57e9b464bad23998fce6ac1e80 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 4 Dec 2002 12:31:49 +0000 Subject: empty invoice_lines() fix --- FS/FS/cust_bill.pm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 3481a9a86..1742f604f 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -1092,16 +1092,14 @@ sub print_text { # ); #and subroutine for the template - sub FS::cust_bill::_template::invoice_lines { - my $lines = shift or return @buf; + my $lines = shift || scalar(@buf); map { scalar(@buf) ? shift @buf : [ '', '' ]; } ( 1 .. $lines ); } - #and fill it in $FS::cust_bill::_template::page = 1; my $lines; @@ -1121,7 +1119,7 @@ sub print_text { =head1 VERSION -$Id: cust_bill.pm,v 1.55 2002-11-22 12:19:15 ivan Exp $ +$Id: cust_bill.pm,v 1.56 2002-12-04 12:31:49 ivan Exp $ =head1 BUGS -- cgit v1.2.1 From 59aa696fb295598b6ceecaa45009617ef6d56aaf Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 12 Dec 2002 21:44:28 +0000 Subject: custnum in welcome email --- FS/FS/svc_acct.pm | 1 + 1 file changed, 1 insertion(+) (limited to 'FS') diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index 388b8dd88..2062eb9ba 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -369,6 +369,7 @@ sub insert { 'subject' => $welcome_subject, 'mimetype' => $welcome_mimetype, 'body' => $welcome_template->fill_in( HASH => { + 'custnum' => $self->custnum, 'username' => $self->username, 'password' => $self->_password, 'first' => $cust_main->first, -- cgit v1.2.1 From 64d21fc13eddf275f614f54ff9e17eca74dcd858 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 13 Dec 2002 00:31:32 +0000 Subject: taxclass fix (?) --- FS/FS/cust_main.pm | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'FS') diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 237abcddb..890371de7 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1058,26 +1058,25 @@ sub bill { || $self->payby eq 'COMP' || $taxable_charged == 0 ) { - my $cust_main_county = - qsearchs('cust_main_county',{ + my $cust_main_county = qsearchs('cust_main_county',{ 'state' => $self->state, 'county' => $self->county, 'country' => $self->country, 'taxclass' => $part_pkg->taxclass, - } ) - or qsearchs('cust_main_county',{ + } ); + $cust_main_county ||= qsearchs('cust_main_county',{ 'state' => $self->state, 'county' => $self->county, 'country' => $self->country, 'taxclass' => '', - } ) - or do { - $dbh->rollback if $oldAutoCommit; - return - "fatal: can't find tax rate for state/county/country/taxclass ". - join('/', ( map $self->$_(), qw(state county country) ), - $part_pkg->taxclass ). "\n"; - }; + } ); + unless ( $cust_main_county ) { + $dbh->rollback if $oldAutoCommit; + return + "fatal: can't find tax rate for state/county/country/taxclass ". + join('/', ( map $self->$_(), qw(state county country) ), + $part_pkg->taxclass ). "\n"; + } if ( $cust_main_county->exempt_amount ) { my ($mon,$year) = (localtime($sdate) )[4,5]; -- cgit v1.2.1 From edbcab06936c79a4f8d4edc0d0222139fa8c312c Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 14 Dec 2002 21:18:23 +0000 Subject: fix for auditing packages --- FS/FS/cust_svc.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'FS') diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm index 7516be599..8bcb0fcca 100644 --- a/FS/FS/cust_svc.pm +++ b/FS/FS/cust_svc.pm @@ -220,6 +220,7 @@ sub check { # or new FS::pkg_svc ( { 'pkgpart' => $cust_pkg->pkgpart, # 'svcpart' => $self->svcpart, # 'quantity' => 0 } ); + my $quantity = $pkg_svc ? $pkg_svc->quantity : 0; my @cust_svc = qsearch('cust_svc', { 'pkgnum' => $self->pkgnum, @@ -227,7 +228,7 @@ sub check { }); return "Already ". scalar(@cust_svc). " ". $part_svc->svc. " services for pkgnum ". $self->pkgnum - if scalar(@cust_svc) >= $pkg_svc->quantity; + if scalar(@cust_svc) >= $quantity; } ''; #no error -- cgit v1.2.1 From 50dbca8812cac271c584cbe5629d4583cd11a01c Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Dec 2002 21:52:01 +0000 Subject: fix for Pg 7.3, are there others? --- FS/FS/part_svc.pm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'FS') diff --git a/FS/FS/part_svc.pm b/FS/FS/part_svc.pm index 06c15ed2a..63bc2ad1c 100644 --- a/FS/FS/part_svc.pm +++ b/FS/FS/part_svc.pm @@ -265,12 +265,12 @@ COLUMNNAME, or a new part_svc_column object if none exists. =cut sub part_svc_column { - my $self = shift; - my $columnname = shift; - qsearchs('part_svc_column', { - 'svcpart' => $self->svcpart, - 'columnname' => $columnname, - } + my( $self, $columnname) = @_; + $self->svcpart && + qsearchs('part_svc_column', { + 'svcpart' => $self->svcpart, + 'columnname' => $columnname, + } ) or new FS::part_svc_column { 'svcpart' => $self->svcpart, 'columnname' => $columnname, -- cgit v1.2.1 From 99076cc92a72f9c578c95d527b14b741434b4a8f Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 17 Dec 2002 09:24:59 +0000 Subject: adding freeside-sqlradius-seconds --- FS/MANIFEST | 1 + FS/bin/freeside-sqlradius-seconds | 57 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 FS/bin/freeside-sqlradius-seconds (limited to 'FS') diff --git a/FS/MANIFEST b/FS/MANIFEST index 47c3bf206..9c387d42e 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -21,6 +21,7 @@ bin/freeside-radgroup bin/freeside-receivables-report bin/freeside-sqlradius-radacctd bin/freeside-sqlradius-reset +bin/freeside-sqlradius-seconds bin/freeside-tax-report bin/freeside-cc-receipts-report bin/freeside-credit-report diff --git a/FS/bin/freeside-sqlradius-seconds b/FS/bin/freeside-sqlradius-seconds new file mode 100644 index 000000000..e65b87f89 --- /dev/null +++ b/FS/bin/freeside-sqlradius-seconds @@ -0,0 +1,57 @@ +#!/usr/bin/perl -Tw + +use strict; +use Date::Parse; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearchs); +use FS::svc_acct; + +my $fs_user = shift or die &usage; +adminsuidsetup( $fs_user ); + +my $target_user = shift or die &usage; +my $start = shift or die &usage; +my $stop = shift || time; + +my $svc_acct = qsearchs( 'svc_acct', { 'username' => $target_user } ); +die "username $target_user not found\n" unless $svc_acct; + +print $svc_acct->seconds_since_sqlradacct( str2time($start), str2time($stop) ); + +sub usage { + die "Usage:\n\n freeside-sqlradius-seconds freeside_username target_username start_date stop_date\n"; +} + + +=head1 NAME + +freeside-sqlradius-seconds - Real-time radacct import daemon + +=head1 SYNOPSIS + + freeside-sqlradius-seconds freeside_username target_username start_date [ stop_date ] + +=head1 DESCRIPTION + +Returns the number of seconds the specified username has been online between +start_date (inclusive) and stop_date (exclusive). +See L + +B is a username added by freeside-adduser. +B is the username of the user account to query. +B and B are in any format Date::Parse is happy with. +B defaults to now if not specified. + +=head1 BUGS + +Selection of the account in question is rather simplistic in that +B doesn't necessarily identify a unique account (and wouldn't +even if a domain was specified), and no sqlradius export is checked for. + +=head1 SEE ALSO + +L + +=cut + +1; -- cgit v1.2.1