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(-) 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(-) 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 + httemplate/edit/cust_main.cgi | 120 ++++++++---- httemplate/view/cust_main.cgi | 429 +++++++++++++++++++++--------------------- 3 files changed, 308 insertions(+), 250 deletions(-) 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; diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index 3a5df086f..a76cd36d1 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -336,48 +336,94 @@ sub expselect { $return; } -print "
Billing information", &itable("#cccccc"), - qq!tax eq "Y"; -print qq!>Tax Exempt!; -print qq!invoicing_list; -print qq! CHECKED! - if ( ! @invoicing_list && ! $conf->exists('disablepostalinvoicedefault') ) - || grep { $_ eq 'POST' } @invoicing_list; -print qq!>Postal mail invoice!; -my $invoicing_list = join(', ', grep { $_ ne 'POST' } @invoicing_list ); -print qq!Email invoice !; - -print "Billing type", - "", - &table("#cccccc"), ""; - -my($payinfo, $payname)=( - $cust_main->payinfo, - $cust_main->payname, -); +my $payby_default = $conf->config('payby-default'); + +if ( $payby_default eq 'HIDE' ) { + + $cust_main->payby('BILL') unless $cust_main->payby; + + foreach my $field (qw( tax payby )) { + print qq!'; + } + + print qq!'; + + foreach my $payby (qw( CARD BILL COMP )) { + foreach my $field (qw( payinfo payname )) { + print qq!'; + } + + #false laziness w/expselect + my( $m, $y ) = (0, 0); + if ( scalar(@_) ) { + my $date = shift || '01-2000'; + if ( $date =~ /^(\d{4})-(\d{1,2})-\d{1,2}$/ ) { #PostgreSQL date format + ( $m, $y ) = ( $2, $1 ); + } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) { + ( $m, $y ) = ( $1, $3 ); + } else { + die "unrecognized expiration date format: $date"; + } + } + + print qq! qq!Credit card
${r}
${r}Exp !. expselect("CARD"). qq!
${r}Name on card
!, - 'BILL' => qq!Billing
P.O.
${r}Exp !. expselect("BILL", "12-2037"). qq!
Attention
!, - 'COMP' => qq!Complimentary
${r}Approved by
${r}Exp !. expselect("COMP"), +} else { + + print "
Billing information", &itable("#cccccc"), + qq!tax eq "Y"; + print qq!>Tax Exempt!. + qq!invoicing_list; + print qq! CHECKED! + if ( ! @invoicing_list && ! $conf->exists('disablepostalinvoicedefault') ) + || grep { $_ eq 'POST' } @invoicing_list; + print qq!>Postal mail invoice!; + my $invoicing_list = join(', ', grep { $_ ne 'POST' } @invoicing_list ); + print qq!Email invoice !; + + print "Billing type", + "", + &table("#cccccc"), ""; + + my($payinfo, $payname)=( + $cust_main->payinfo, + $cust_main->payname, + ); + + my %payby = ( + 'CARD' => qq!Credit card
${r}
${r}Exp !. expselect("CARD"). qq!
${r}Name on card
!, + 'BILL' => qq!Billing
P.O.
${r}Exp !. expselect("BILL", "12-2037"). qq!
Attention
!, + 'COMP' => qq!Complimentary
${r}Approved by
${r}Exp !. expselect("COMP"), ); -my %paybychecked = ( - 'CARD' => qq!Credit card
${r}
${r}Exp !. expselect("CARD", $cust_main->paydate). qq!
${r}Name on card
!, - 'BILL' => qq!Billing
P.O.
${r}Exp !. expselect("BILL", $cust_main->paydate). qq!
Attention
!, - 'COMP' => qq!Complimentary
${r}Approved by
${r}Exp !. expselect("COMP", $cust_main->paydate), + + my %paybychecked = ( + 'CARD' => qq!Credit card
${r}
${r}Exp !. expselect("CARD", $cust_main->paydate). qq!
${r}Name on card
!, + 'BILL' => qq!Billing
P.O.
${r}Exp !. expselect("BILL", $cust_main->paydate). qq!
Attention
!, + 'COMP' => qq!Complimentary
${r}Approved by
${r}Exp !. expselect("COMP", $cust_main->paydate), ); -for (qw(CARD BILL COMP)) { - print qq!payby eq "$_") { - print qq! CHECKED> $paybychecked{$_}!; - } else { - print qq!> $payby{$_}!; + + $cust_main->payby($payby_default) unless $cust_main->payby; + for (qw(CARD BILL COMP)) { + print qq!payby eq "$_") { + print qq! CHECKED> $paybychecked{$_}!; + } else { + print qq!> $payby{$_}!; + } } -} -print "$r required fields for each billing type"; + print "$r required fields for each billing type"; + +} if ( defined $cust_main->dbdef_table->column('comments') ) { print "

Comments", &itable("#cccccc"), diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index 707de8d70..25260fa3c 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -188,6 +188,8 @@ print ''; print '
'; +if ( $conf->config('payby-default') ne 'HIDE' ) { + my @invoicing_list = $cust_main->invoicing_list; print "Billing information (", qq!!, "Bill now)", @@ -236,6 +238,8 @@ print '
'; print ""; +} + print ''; if ( defined $cust_main->dbdef_table->column('comments') @@ -268,30 +272,34 @@ foreach my $type_pkgs ( qsearch('type_pkgs',{'typenum'=> $agent->typenum }) ) { print '
'; -print '
'. - qq!
!. - qq!!. - qq!Description:!. - qq! Amount:!. - qq! !; - -#false laziness w/ edit/part_pkg.cgi -if ( $conf->exists('enable_taxclasses') ) { - print '!. + qq!Description:!. + qq! Amount:!. + qq! !; + + #false laziness w/ edit/part_pkg.cgi + if ( $conf->exists('enable_taxclasses') ) { + print ''; + } else { + print ''; } - print ''; -} else { - print ''; -} + + print qq!

!; -print qq!
!; +} print < @@ -451,48 +459,132 @@ function cust_pay_areyousure(href) { END -#formatting -print qq!

Payment History!. - qq! ( !. - qq!!. - qq!Post payment | !. - qq!!. - qq!Post credit )!; - -#get payment history -# -# major problem: this whole thing is way too sloppy. -# minor problem: the description lines need better formatting. - -my @history = (); #needed for mod_perl :) - -my %target = (); - -my @bills = qsearch('cust_bill',{'custnum'=>$custnum}); -foreach my $bill (@bills) { - my($bref)=$bill->hashref; - my $bpre = ( $bill->owed > 0 ) - ? ' Open ' - : ''; - my $bpost = ( $bill->owed > 0 ) ? '' : ''; - push @history, - $bref->{_date} . qq!\t${bpre}Invoice #! . $bref->{invnum} . - qq! (Balance \$! . $bill->owed . qq!)$bpost\t! . - $bref->{charged} . qq!\t\t\t!; - - my(@cust_bill_pay)=qsearch('cust_bill_pay',{'invnum'=> $bref->{invnum} } ); -# my(@payments)=qsearch('cust_pay',{'invnum'=> $bref->{invnum} } ); -# my($payment); -# foreach $payment (@payments) { - foreach my $cust_bill_pay (@cust_bill_pay) { - my $payment = $cust_bill_pay->cust_pay; - my($date,$invnum,$payby,$payinfo,$paid)=($payment->_date, - $cust_bill_pay->invnum, - $payment->payby, - $payment->payinfo, - $cust_bill_pay->amount, - ); +if ( $conf->config('payby-default') ne 'HIDE' ) { + + #formatting + print qq!

Payment History!. + qq! ( !. + qq!!. + qq!Post payment | !. + qq!!. + qq!Post credit )!; + + #get payment history + # + # major problem: this whole thing is way too sloppy. + # minor problem: the description lines need better formatting. + + my @history = (); #needed for mod_perl :) + + my %target = (); + + my @bills = qsearch('cust_bill',{'custnum'=>$custnum}); + foreach my $bill (@bills) { + my($bref)=$bill->hashref; + my $bpre = ( $bill->owed > 0 ) + ? ' Open ' + : ''; + my $bpost = ( $bill->owed > 0 ) ? '' : ''; + push @history, + $bref->{_date} . qq!\t${bpre}Invoice #! . $bref->{invnum} . + qq! (Balance \$! . $bill->owed . qq!)$bpost\t! . + $bref->{charged} . qq!\t\t\t!; + + my(@cust_bill_pay)=qsearch('cust_bill_pay',{'invnum'=> $bref->{invnum} } ); + # my(@payments)=qsearch('cust_pay',{'invnum'=> $bref->{invnum} } ); + # my($payment); + foreach my $cust_bill_pay (@cust_bill_pay) { + my $payment = $cust_bill_pay->cust_pay; + my($date,$invnum,$payby,$payinfo,$paid)=($payment->_date, + $cust_bill_pay->invnum, + $payment->payby, + $payment->payinfo, + $cust_bill_pay->amount, + ); + $payinfo = 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4)) + if $payby eq 'CARD'; + my $target = "$payby$payinfo"; + $payby =~ s/^BILL$/Check #/ if $payinfo; + $payby =~ s/^(CARD|COMP)$/$1 /; + my $delete = $payment->closed !~ /^Y/i && $conf->exists('deletepayments') + ? qq! (delete)! + : ''; + push @history, + "$date\tPayment, Invoice #$invnum ($payby$payinfo)$delete\t\t$paid\t\t\t$target"; + } + + my(@cust_credit_bill)= + qsearch('cust_credit_bill', { 'invnum'=> $bref->{invnum} } ); + foreach my $cust_credit_bill (@cust_credit_bill) { + my $cust_credit = $cust_credit_bill->cust_credit; + my($date, $invnum, $crednum, $amount, $reason, $app_date ) = ( + $cust_credit->_date, + $cust_credit_bill->invnum, + $cust_credit_bill->crednum, + $cust_credit_bill->amount, + $cust_credit->reason, + time2str("%D", $cust_credit_bill->_date), + ); + push @history, + "$date\tCredit #$crednum: $reason
". + "(applied to invoice #$invnum on $app_date)\t\t\t$amount\t"; + } + } + + my @credits = grep { scalar(my @array = $_->cust_credit_refund) } + qsearch('cust_credit',{'custnum'=>$custnum}); + foreach my $credit (@credits) { + my($cref)=$credit->hashref; + my(@cust_credit_refund)= + qsearch('cust_credit_refund', { 'crednum'=> $cref->{crednum} } ); + foreach my $cust_credit_refund (@cust_credit_refund) { + my $cust_refund = $cust_credit_refund->cust_credit; + my($date, $crednum, $amount, $reason, $app_date ) = ( + $credit->_date, + $credit->crednum, + $cust_credit_refund->amount, + $credit->reason, + time2str("%D", $cust_credit_refund->_date), + ); + push @history, + "$date\tCredit #$crednum: $reason
". + "(applied to refund on $app_date)\t\t\t$amount\t"; + } + } + + @credits = grep { $_->credited > 0 } + qsearch('cust_credit',{'custnum'=>$custnum}); + foreach my $credit (@credits) { + my($cref)=$credit->hashref; + push @history, + $cref->{_date} . "\t" . + qq!!. + 'Unapplied credit #' . + $cref->{crednum} . ": ". + $cref->{reason} . "\t\t\t" . $credit->credited . "\t"; + } + + my(@refunds)=qsearch('cust_refund',{'custnum'=> $custnum } ); + foreach my $refund (@refunds) { + my($rref)=$refund->hashref; + my($refundnum) = ( + $refund->refundnum, + ); + + push @history, + $rref->{_date} . "\tRefund #$refundnum, (" . + $rref->{payby} . " " . $rref->{payinfo} . ") by " . + $rref->{otaker} . " - ". $rref->{reason} . "\t\t\t\t" . + $rref->{refund}; + } + + my @unapplied_payments = + grep { $_->unapplied > 0 } qsearch('cust_pay', { 'custnum' => $custnum } ); + foreach my $payment (@unapplied_payments) { + my $payby = $payment->payby; + my $payinfo = $payment->payinfo; + #false laziness w/above $payinfo = 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4)) if $payby eq 'CARD'; my $target = "$payby$payinfo"; @@ -502,161 +594,72 @@ foreach my $bill (@bills) { ? qq! (delete)! : ''; push @history, - "$date\tPayment, Invoice #$invnum ($payby$payinfo)$delete\t\t$paid\t\t\t$target"; - } - - my(@cust_credit_bill)= - qsearch('cust_credit_bill', { 'invnum'=> $bref->{invnum} } ); - foreach my $cust_credit_bill (@cust_credit_bill) { - my $cust_credit = $cust_credit_bill->cust_credit; - my($date, $invnum, $crednum, $amount, $reason, $app_date ) = ( - $cust_credit->_date, - $cust_credit_bill->invnum, - $cust_credit_bill->crednum, - $cust_credit_bill->amount, - $cust_credit->reason, - time2str("%D", $cust_credit_bill->_date), - ); - push @history, - "$date\tCredit #$crednum: $reason
". - "(applied to invoice #$invnum on $app_date)\t\t\t$amount\t"; - } -} - -my @credits = grep { scalar(my @array = $_->cust_credit_refund) } - qsearch('cust_credit',{'custnum'=>$custnum}); -foreach my $credit (@credits) { - my($cref)=$credit->hashref; - my(@cust_credit_refund)= - qsearch('cust_credit_refund', { 'crednum'=> $cref->{crednum} } ); - foreach my $cust_credit_refund (@cust_credit_refund) { - my $cust_refund = $cust_credit_refund->cust_credit; - my($date, $crednum, $amount, $reason, $app_date ) = ( - $credit->_date, - $credit->crednum, - $cust_credit_refund->amount, - $credit->reason, - time2str("%D", $cust_credit_refund->_date), - ); - push @history, - "$date\tCredit #$crednum: $reason
". - "(applied to refund on $app_date)\t\t\t$amount\t"; + $payment->_date. "\t". + 'Unapplied payment #' . + $payment->paynum . " ($payby$payinfo) ". + '('. + "apply)$delete". + "\t\t" . $payment->unapplied . "\t\t\t$target"; } -} - -@credits = grep { $_->credited > 0 } - qsearch('cust_credit',{'custnum'=>$custnum}); -foreach my $credit (@credits) { - my($cref)=$credit->hashref; - push @history, - $cref->{_date} . "\t" . - qq!!. - 'Unapplied credit #' . - $cref->{crednum} . ": ". - $cref->{reason} . "\t\t\t" . $credit->credited . "\t"; -} - -my(@refunds)=qsearch('cust_refund',{'custnum'=> $custnum } ); -foreach my $refund (@refunds) { - my($rref)=$refund->hashref; - my($refundnum) = ( - $refund->refundnum, - ); - - push @history, - $rref->{_date} . "\tRefund #$refundnum, (" . - $rref->{payby} . " " . $rref->{payinfo} . ") by " . - $rref->{otaker} . " - ". $rref->{reason} . "\t\t\t\t" . - $rref->{refund}; -} - -my @unapplied_payments = - grep { $_->unapplied > 0 } qsearch('cust_pay', { 'custnum' => $custnum } ); -foreach my $payment (@unapplied_payments) { - my $payby = $payment->payby; - my $payinfo = $payment->payinfo; - #false laziness w/above - $payinfo = 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4)) - if $payby eq 'CARD'; - my $target = "$payby$payinfo"; - $payby =~ s/^BILL$/Check #/ if $payinfo; - $payby =~ s/^(CARD|COMP)$/$1 /; - my $delete = $payment->closed !~ /^Y/i && $conf->exists('deletepayments') - ? qq! (delete)! - : ''; - push @history, - $payment->_date. "\t". - 'Unapplied payment #' . - $payment->paynum . " ($payby$payinfo) ". - '('. - "apply)$delete". - "\t\t" . $payment->unapplied . "\t\t\t$target"; -} - - #formatting - print &table(), < - Date - Description - Charge - Payment - In-house
Credit
- Refund - Balance - + + #formatting + print &table(), < + Date + Description + Charge + Payment + In-house
Credit
+ Refund + Balance + END + + #display payment history + + my $balance = 0; + foreach my $item (sort keyfield_numerically @history) { + my($date,$desc,$charge,$payment,$credit,$refund,$target)=split(/\t/,$item); + $charge ||= 0; + $payment ||= 0; + $credit ||= 0; + $refund ||= 0; + $balance += $charge - $payment; + $balance -= $credit - $refund; + $balance = sprintf("%.2f", $balance); + $balance =~ s/^\-0\.00$/0.00/; #yay ieee fp + $target = '' unless defined $target; + + print ""; + print qq!! unless $target && $target{$target}++; + print time2str("%D",$date); + print '' if $target && $target{$target} == 1; + print "", + "$desc", + "", + ( $charge ? "\$".sprintf("%.2f",$charge) : '' ), + "", + "", + ( $payment ? "- \$".sprintf("%.2f",$payment) : '' ), + "", + "", + ( $credit ? "- \$".sprintf("%.2f",$credit) : '' ), + "", + "", + ( $refund ? "\$".sprintf("%.2f",$refund) : '' ), + "", + "\$" . $balance, + "", + "\n"; + } + + print ""; -#display payment history - -my $balance = 0; -foreach my $item (sort keyfield_numerically @history) { - my($date,$desc,$charge,$payment,$credit,$refund,$target)=split(/\t/,$item); - $charge ||= 0; - $payment ||= 0; - $credit ||= 0; - $refund ||= 0; - $balance += $charge - $payment; - $balance -= $credit - $refund; - $balance = sprintf("%.2f", $balance); - $balance =~ s/^\-0\.00$/0.00/; #yay ieee fp - $target = '' unless defined $target; - - print ""; - print qq!! unless $target && $target{$target}++; - print time2str("%D",$date); - print '' if $target && $target{$target} == 1; - print "", - "$desc", - "", - ( $charge ? "\$".sprintf("%.2f",$charge) : '' ), - "", - "", - ( $payment ? "- \$".sprintf("%.2f",$payment) : '' ), - "", - "", - ( $credit ? "- \$".sprintf("%.2f",$credit) : '' ), - "", - "", - ( $refund ? "\$".sprintf("%.2f",$refund) : '' ), - "", - "\$" . $balance, - "", - "\n"; } -#formatting -print ""; - -#end - -#formatting -print < - -END +print ''; #subroutiens -sub keyfield_numerically { (split(/\t/,$a))[0] <=> (split(/\t/,$b))[0] ; } +sub keyfield_numerically { (split(/\t/,$a))[0] <=> (split(/\t/,$b))[0]; } %> -- 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 ++++++ httemplate/view/svc_acct.cgi | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) 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', + }, ); diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi index df55e85bf..f2228424c 100755 --- a/httemplate/view/svc_acct.cgi +++ b/httemplate/view/svc_acct.cgi @@ -144,8 +144,8 @@ if ($svc_acct->slipip) { print 'RADIUS groups'. join('
', $svc_acct->radius_groups). ''; -print "". - '
'. joblisting({'svcnum'=>$svcnum}, 1). - ""; +print '

'. + join("\n", $conf->config('svc_acct-notes') ). + '

'. joblisting({'svcnum'=>$svcnum}, 1). ''; %> -- cgit v1.2.1 From 2a2fa626446a69e7e1a5953b8bb693b5e4274d8b Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 8 Oct 2002 10:50:43 +0000 Subject: slightly less sucky --- eg/export_template.pm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/eg/export_template.pm b/eg/export_template.pm index 00942fd12..ca58d4bed 100644 --- a/eg/export_template.pm +++ b/eg/export_template.pm @@ -42,9 +42,15 @@ sub myexport_queue { } sub myexport_insert { #subroutine, not method + my( $username, $password ) = @_; + #do things with $username and $password } + sub myexport_replace { #subroutine, not method } + sub myexport_delete { #subroutine, not method + my( $username ) = @_; + #do things with $username } -- cgit v1.2.1 From 61e25db54f2da624a79ecedb6bf3d678c7fdefc5 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 8 Oct 2002 11:10:51 +0000 Subject: add suspended package browse (closes: Bug#467) --- httemplate/index.html | 3 ++- httemplate/search/cust_pkg.cgi | 20 +++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/httemplate/index.html b/httemplate/index.html index f17639d44..017a2cc3a 100644 --- a/httemplate/index.html +++ b/httemplate/index.html @@ -119,7 +119,8 @@ Packages diff --git a/httemplate/search/cust_pkg.cgi b/httemplate/search/cust_pkg.cgi index 5f0782b8c..78a5bb3bb 100755 --- a/httemplate/search/cust_pkg.cgi +++ b/httemplate/search/cust_pkg.cgi @@ -43,10 +43,16 @@ if ( $cgi->param('magic') && $cgi->param('magic') eq 'bill' ) { } else { - my $unconf = ''; + my $qual = ''; if ( $query eq 'pkgnum' ) { $sortby=\*pkgnum_sort; + } elsif ( $query eq 'SUSP_pkgnum' ) { + + $sortby=\*pkgnum_sort; + + $qual = 'WHERE susp IS NOT NULL AND susp != 0'; + } elsif ( $query eq 'APKG_pkgnum' ) { $sortby=\*pkgnum_sort; @@ -101,12 +107,12 @@ if ( $cgi->param('magic') && $cgi->param('magic') eq 'bill' ) { AND pkg_svc.quantity != 0;"; $sth = dbh->prepare($query) or die dbh->errstr. " preparing $query"; $sth->execute or die "Error executing \"$query\": ". $sth->errstr; - $unconf = " LEFT JOIN temp2_$$ ON cust_pkg.pkgnum = temp2_$$.pkgnum - WHERE temp2_$$.pkgnum IS NOT NULL"; + $qual = " LEFT JOIN temp2_$$ ON cust_pkg.pkgnum = temp2_$$.pkgnum + WHERE temp2_$$.pkgnum IS NOT NULL"; } else { - $unconf = " + $qual = " WHERE 0 < ( SELECT count(*) FROM pkg_svc WHERE pkg_svc.pkgpart = cust_pkg.pkgpart @@ -120,10 +126,10 @@ if ( $cgi->param('magic') && $cgi->param('magic') eq 'bill' ) { } } else { - die "Empty QUERY_STRING!"; + die "Empty or unknown QUERY_STRING!"; } - my $statement = "SELECT COUNT(*) FROM cust_pkg $unconf"; + my $statement = "SELECT COUNT(*) FROM cust_pkg $qual"; my $sth = dbh->prepare($statement) or die dbh->errstr." preparing $statement"; $sth->execute or die "Error executing \"$statement\": ". $sth->errstr; @@ -131,7 +137,7 @@ if ( $cgi->param('magic') && $cgi->param('magic') eq 'bill' ) { my $tblname = driver_name eq 'mysql' ? 'cust_pkg.' : ''; @cust_pkg = - qsearch('cust_pkg',{}, '', "$unconf ORDER BY ${tblname}pkgnum $limit" ); + qsearch('cust_pkg',{}, '', "$qual ORDER BY ${tblname}pkgnum $limit" ); if ( driver_name eq 'mysql' ) { $query = "DROP TABLE temp1_$$,temp2_$$;"; -- 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(-) 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(-) 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(-) 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(-) 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 f5571d9d6c79d04e65f8da92be923c3f3ae5c54a Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 10 Oct 2002 16:28:58 +0000 Subject: expiration date bugfix for HIDE --- httemplate/edit/cust_main.cgi | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index a76cd36d1..38d8d2b7e 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -357,16 +357,14 @@ if ( $payby_default eq 'HIDE' ) { } #false laziness w/expselect - my( $m, $y ) = (0, 0); - if ( scalar(@_) ) { - my $date = shift || '01-2000'; - if ( $date =~ /^(\d{4})-(\d{1,2})-\d{1,2}$/ ) { #PostgreSQL date format - ( $m, $y ) = ( $2, $1 ); - } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) { - ( $m, $y ) = ( $1, $3 ); - } else { - die "unrecognized expiration date format: $date"; - } + my( $m, $y ); + my $date = $cust_main->paydate || '12-2037'; + if ( $date =~ /^(\d{4})-(\d{1,2})-\d{1,2}$/ ) { #PostgreSQL date format + ( $m, $y ) = ( $2, $1 ); + } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) { + ( $m, $y ) = ( $1, $3 ); + } else { + die "unrecognized expiration date format: $date"; } print qq! Date: Thu, 10 Oct 2002 16:48:09 +0000 Subject: bugfix in payby-default HIDE expiration dates --- httemplate/edit/cust_main.cgi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index 38d8d2b7e..0921cb373 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -367,8 +367,8 @@ if ( $payby_default eq 'HIDE' ) { die "unrecognized expiration date format: $date"; } - print qq!!. + qq!!; } -- 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 +- fs_signup/FS-SignupClient/cgi/signup.cgi | 10 +++-- httemplate/edit/cust_main.cgi | 12 ++++-- httemplate/edit/process/cust_main.cgi | 9 +++- httemplate/view/cust_main.cgi | 10 +++++ 10 files changed, 109 insertions(+), 45 deletions(-) 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*$/ diff --git a/fs_signup/FS-SignupClient/cgi/signup.cgi b/fs_signup/FS-SignupClient/cgi/signup.cgi index 816b8213b..333a88cf8 100755 --- a/fs_signup/FS-SignupClient/cgi/signup.cgi +++ b/fs_signup/FS-SignupClient/cgi/signup.cgi @@ -1,6 +1,6 @@ #!/usr/bin/perl -Tw # -# $Id: signup.cgi,v 1.30 2002-08-26 19:07:10 khoff Exp $ +# $Id: signup.cgi,v 1.31 2002-10-12 10:15:55 ivan Exp $ use strict; use vars qw( @payby $cgi $locales $packages $pops $init_data $error @@ -611,14 +611,18 @@ Contact Information my %payby = ( 'CARD' => qq!Credit card
*$cardselect
*Exp !. expselect("CARD"). qq!
*Name on card
!, - 'BILL' => qq!Billing
P.O.
*Exp !. expselect("BILL", "12-2037"). qq!
*Attention
!, + 'CHEK' => qq!Electronic check
${r}Account number
${r}ABA/Routing code
${r}Bank name !, + 'BILL' => qq!Billing
P.O.
Attention
!, 'COMP' => qq!Complimentary
*Approved by
*Exp !. expselect("COMP"), 'PREPAY' => qq!Prepaid card
*!, ); + my( $account, $aba ) = split('@', $payinfo); + my %paybychecked = ( 'CARD' => qq!Credit card
*$cardselect
*Exp !. expselect("CARD", $paydate). qq!
*Name on card
!, - 'BILL' => qq!Billing
P.O.
*Exp !. expselect("BILL", $paydate). qq!
*Attention
!, + 'CHEK' => qq!Electronic check
${r}Account number
${r}ABA/Routing code
${r}Bank name !, + 'BILL' => qq!Billing
P.O.
Attention
!, 'COMP' => qq!Complimentary
*Approved by
*Exp !. expselect("COMP", $paydate), 'PREPAY' => qq!Prepaid card
*!, ); diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index 0921cb373..9e62b00ef 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -350,7 +350,7 @@ if ( $payby_default eq 'HIDE' ) { print qq!'; - foreach my $payby (qw( CARD BILL COMP )) { + foreach my $payby (qw( CARD CHEK BILL COMP )) { foreach my $field (qw( payinfo payname )) { print qq!'; @@ -399,18 +399,22 @@ if ( $payby_default eq 'HIDE' ) { my %payby = ( 'CARD' => qq!Credit card
${r}
${r}Exp !. expselect("CARD"). qq!
${r}Name on card
!, - 'BILL' => qq!Billing
P.O.
${r}Exp !. expselect("BILL", "12-2037"). qq!
Attention
!, + 'CHEK' => qq!Electronic check
${r}Account number
${r}ABA/Routing code
${r}Bank name !, + 'BILL' => qq!Billing
P.O.
Attention
!, 'COMP' => qq!Complimentary
${r}Approved by
${r}Exp !. expselect("COMP"), ); + my( $account, $aba ) = split('@', $payinfo); + my %paybychecked = ( 'CARD' => qq!Credit card
${r}
${r}Exp !. expselect("CARD", $cust_main->paydate). qq!
${r}Name on card
!, - 'BILL' => qq!Billing
P.O.
${r}Exp !. expselect("BILL", $cust_main->paydate). qq!
Attention
!, + 'CHEK' => qq!Electronic check
${r}Account number
${r}ABA/Routing code
${r}Bank name !, + 'BILL' => qq!Billing
P.O.
Attention
!, 'COMP' => qq!Complimentary
${r}Approved by
${r}Exp !. expselect("COMP", $cust_main->paydate), ); $cust_main->payby($payby_default) unless $cust_main->payby; - for (qw(CARD BILL COMP)) { + for (qw(CARD CHEK BILL COMP)) { print qq!payby eq "$_") { print qq! CHECKED> $paybychecked{$_}!; diff --git a/httemplate/edit/process/cust_main.cgi b/httemplate/edit/process/cust_main.cgi index 6ce60d14a..c15ea0321 100755 --- a/httemplate/edit/process/cust_main.cgi +++ b/httemplate/edit/process/cust_main.cgi @@ -10,9 +10,14 @@ $cgi->param('refnum', (split(/:/, ($cgi->param('refnum'))[0] ))[0] ); my $payby = $cgi->param('payby'); if ( $payby ) { - $cgi->param('payinfo', $cgi->param( $payby. '_payinfo' ) ); + if ( $payby eq 'CHEK' ) { + $cgi->param('payinfo', + $cgi->param('CHEK_payinfo1'). '@'. $cgi->param('CHEK_payinfo2') ); + } else { + $cgi->param('payinfo', $cgi->param( $payby. '_payinfo' ) ); + } $cgi->param('paydate', - $cgi->param( $payby. '_month' ). '-'. $cgi->param( $payby. '_year' ) ); + $cgi->param( $payby. '_month' ). '-'. $cgi->param( $payby. '_year' ) ); $cgi->param('payname', $cgi->param( $payby. '_payname' ) ); } diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index 25260fa3c..f7906cfa3 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -217,6 +217,16 @@ if ( $conf->config('payby-default') ne 'HIDE' ) { 'Name on card', $cust_main->payname, '' ; + } elsif ( $cust_main->payby eq 'CHEK' ) { + my( $account, $aba ) = split('@', $cust_main->payinfo ); + print 'Electronic check', + 'Account number', + $account, '', + 'ABA/Routing code', + $aba, '', + 'Bank name', + $cust_main->payname, '' + ; } elsif ( $cust_main->payby eq 'BILL' ) { print 'Billing'; print 'P.O. ', -- 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 +++++++++++++- httemplate/edit/part_pkg.cgi | 31 ++++++++++++++++ 4 files changed, 181 insertions(+), 5 deletions(-) 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). diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index 38d7358a5..ddd86765a 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -355,6 +355,37 @@ tie my %plans, 'Tie::IxHash', }, + 'sqlradacct_hour' => { + 'name' => 'Base charge plus charge per-hour from an external SQL radacct table', + 'fields' => { + 'setup_fee' => { 'name' => 'Setup fee for this package', + 'default' => 0, + }, + 'recur_flat' => { 'name' => 'Base monthly charge for this package', + 'default' => 0, + }, + 'sql_datasrc' => { 'name' => 'DBI data source', + 'default' => 'DBI:mysql:host=radius.server.name;dbname=radius', + }, + 'sql_username' => { 'name' => 'Database username', + 'default' => 'radius', + }, + 'sql_password' => { 'name' => 'Database password', + 'default' => '', + }, + 'recur_included_hours' => { 'name' => 'Hours included', + 'default' => 0, + }, + 'recur_hourly_charge' => { 'name' => 'Additional charge per hour', + 'default' => 0, + }, + }, + 'fieldorder' => [ 'setup_fee', 'recur_flat', 'recur_included_hours', 'recur_hourly_charge' ], + 'setup' => 'what.setup_fee.value', + 'recur' => '\'my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($sdate))[0,1,2,3,4,5]; $mon+=$part_pkg->freq; until ($mon<12) { $mon-=12; $year++ }; $edate = timelocal($sec,$min,$hour,$mday,$mon,$year); my $hours = $cust_pkg->seconds_since_sqlradacct($sdate, $edate, \' + what.sql_datasrc + \', \' + what.sql_username + \', \' + what.sql_password + \' ) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours;\'', + }, + + ; my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } -- cgit v1.2.1 From ac96a7afbae06cc3b594b3e461bec8a34d65cfe5 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 12 Oct 2002 13:46:16 +0000 Subject: dayphone/nightphone as customizable labels, closes: Bug#464 --- bin/populate-msgcat | 8 ++++++++ httemplate/edit/cust_main.cgi | 11 +++++++---- httemplate/view/cust_main.cgi | 10 ++++++---- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/bin/populate-msgcat b/bin/populate-msgcat index 3b198f718..719d33046 100755 --- a/bin/populate-msgcat +++ b/bin/populate-msgcat @@ -110,6 +110,14 @@ sub messages { 'en_US' => 'Expired card', }, + 'daytime' => { + 'en_US' => 'Day Phone', + }, + + 'night' => { + 'en_US' => 'Night Phone', + }, + ); } diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index 9e62b00ef..d99b54aed 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -195,10 +195,13 @@ my($daytime,$night,$fax)=( $cust_main->fax, ); +my $daytime_label = gettext('daytime') || 'Day Phone'; +my $night_label = gettext('night') || 'Night Phone'; + print <${r}Country$country_html -Day Phone -Night Phone +$daytime_label +$night_label Fax END @@ -294,8 +297,8 @@ END print <${r}Country$ship_country_html - Day Phone - Night Phone + $daytime_label + $night_label Fax END diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index f7906cfa3..d157be397 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -83,9 +83,11 @@ print '', $cust_main->country, '', ; - print 'Day Phone', + my $daytime_label = gettext('daytime') || 'Day Phone'; + my $night_label = gettext('night') || 'Night Phone'; + print '$daytime_label', $cust_main->daytime || ' ', '', - 'Night Phone', + '$night_label', $cust_main->night || ' ', '', 'Fax', $cust_main->fax || ' ', '', @@ -122,10 +124,10 @@ print '', $cust_main->get("${pre}country"), '', ; - print 'Day Phone', + print '$daytime_label', '', $cust_main->get("${pre}daytime") || ' ', '', - 'Night Phone'. + '$night_label'. '', $cust_main->get("${pre}night") || ' ', '', 'Fax', -- cgit v1.2.1 From dcef219e16a1b4b6d552b8ea2ae17fd58fb2be3a Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 12 Oct 2002 14:21:17 +0000 Subject: fix dayphone/nightphone msgcat --- httemplate/edit/cust_main.cgi | 4 ++-- httemplate/view/cust_main.cgi | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index d99b54aed..8f2fe7cee 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -195,8 +195,8 @@ my($daytime,$night,$fax)=( $cust_main->fax, ); -my $daytime_label = gettext('daytime') || 'Day Phone'; -my $night_label = gettext('night') || 'Night Phone'; +my $daytime_label = FS::Msgcat::_gettext('daytime') || 'Day Phone'; +my $night_label = FS::Msgcat::_gettext('night') || 'Night Phone'; print <${r}Country$country_html diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index d157be397..a1a47ea74 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -83,11 +83,13 @@ print '', $cust_main->country, '', ; - my $daytime_label = gettext('daytime') || 'Day Phone'; - my $night_label = gettext('night') || 'Night Phone'; - print '$daytime_label', + my $daytime_label = FS::Msgcat::_gettext('daytime') || 'Day Phone'; + my $night_label = FS::Msgcat::_gettext('night') || 'Night Phone'; + print ''. $daytime_label. + '', $cust_main->daytime || ' ', '', - '$night_label', + ''. $night_label. + '', $cust_main->night || ' ', '', 'Fax', $cust_main->fax || ' ', '', @@ -124,10 +126,10 @@ print '', $cust_main->get("${pre}country"), '', ; - print '$daytime_label', + print ''. $daytime_label. '', '', $cust_main->get("${pre}daytime") || ' ', '', - '$night_label'. + ''. $night_label. ''. '', $cust_main->get("${pre}night") || ' ', '', 'Fax', -- 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(-) 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(-) 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 f2b66016c409270f51b8b76c4c61e7886f363366 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 13 Oct 2002 06:49:27 +0000 Subject: don't use ILIKE (7.1-ism) anymore --- httemplate/docs/install.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/docs/install.html b/httemplate/docs/install.html index 3c48a746f..100a3cc64 100644 --- a/httemplate/docs/install.html +++ b/httemplate/docs/install.html @@ -12,7 +12,7 @@ Before installing, you need:
  • rsync
  • A transactional database engine supported by Perl's DBI.
      -
    • PostgreSQL is recommended (v7.1.x or later, not 7.0.x). +
    • PostgreSQL is recommended (v7or later).
    • MySQL versions before 4.1 do not support standard SQL subqueries and are NOT SUPPORTED. If you are a developer who wishes to contribute MySQL 3.x/4.0 support, see ticket #438 in the bug-tracking system and ask on the -devel mailing list. -- cgit v1.2.1 From a5dfbdaabced96bb6a4d00026459297230a3bf5b Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 13 Oct 2002 07:13:52 +0000 Subject: msgcat docs for upgrade --- httemplate/docs/upgrade9.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/httemplate/docs/upgrade9.html b/httemplate/docs/upgrade9.html index efd25887d..478f8aa4f 100644 --- a/httemplate/docs/upgrade9.html +++ b/httemplate/docs/upgrade9.html @@ -10,5 +10,10 @@
    • Copy aspdocs/ or masondocs/ to your web server's document space.
    • Run make install-perl-modules.
    • Install Net::SSH minimum version 0.07 +
    • Apply the following changes to your database: +
      +INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 17, 'daytime', 'en_US', 'Day Phone' );
      +INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 18, 'nigh', 'en_US', 'Night Phone' );
      +
    • Restart Apache and freeside-queued. -- cgit v1.2.1 From 225f258fc288fd8891a3681597f153e5c5c5265c Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 13 Oct 2002 07:14:59 +0000 Subject: doh --- httemplate/docs/session.html | 7 ++++++- httemplate/docs/upgrade9.html | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/httemplate/docs/session.html b/httemplate/docs/session.html index 7dac5fdf7..72e16424e 100644 --- a/httemplate/docs/session.html +++ b/httemplate/docs/session.html @@ -38,9 +38,14 @@ freeside-logout username ( portnum | ip | nasnum nasport )
    • username is a customer username from the svc_acct table
    • portnum, ip or nasport and nasnum uniquely identify a port in the port database table.
    -
  • RADIUS +
  • RADIUS - One of:
      +
    • Run the freeside-sqlradius-radacctd daemon to import radacct + records from all configured sqlradius exports: + freeside-sqlradius-radacctd username
    • Configure your RADIUS server's login and logout callbacks to use the command-line freeside-login and freeside-logout utilites. +
    • (incomplete)Use the fs_radlog/fs_radlogd tool to + import records from a text radacct file.

    Callbacks

    diff --git a/httemplate/docs/upgrade9.html b/httemplate/docs/upgrade9.html index 478f8aa4f..7cf44ea31 100644 --- a/httemplate/docs/upgrade9.html +++ b/httemplate/docs/upgrade9.html @@ -13,7 +13,7 @@
  • Apply the following changes to your database:
     INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 17, 'daytime', 'en_US', 'Day Phone' );
    -INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 18, 'nigh', 'en_US', 'Night Phone' );
    +INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 18, 'night', 'en_US', 'Night Phone' );
     
  • Restart Apache and freeside-queued. -- cgit v1.2.1 From 05030dc1852f7886f3b792b5a5fe469dcaa36199 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 14 Oct 2002 06:16:07 +0000 Subject: show time online this billing cycle on view account screen --- httemplate/view/svc_acct.cgi | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi index f2228424c..e755f87d7 100755 --- a/httemplate/view/svc_acct.cgi +++ b/httemplate/view/svc_acct.cgi @@ -144,8 +144,38 @@ if ($svc_acct->slipip) { print 'RADIUS groups'. join('
    ', $svc_acct->radius_groups). ''; -print '

    '. - join("\n", $conf->config('svc_acct-notes') ). - '

    '. joblisting({'svcnum'=>$svcnum}, 1). ''; +print '

    '; + +if ( $cust_pkg && $cust_pkg->part_pkg->plan eq 'sqlradacct_hour' ) { + + #false laziness w/httemplate/edit/part_pkg... this stuff doesn't really + #belong in plan data + my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } + split("\n", $cust_pkg->part_pkg->plandata ); + + my $last_bill = $cust_pkg->last_bill; + my $seconds = $svc_acct->seconds_since_sqlradacct( + $last_bill, + time, + $plandata{sql_datasrc}, + $plandata{sql_username}, + $plandata{sql_password}, + ); + my $h = int($seconds/3600); + my $m = int( ($seconds%3600) / 60 ); + my $s = $seconds%60; + if ( $seconds ) { + print 'Online $h h $m m $s s this billing cycle (since '. + time2str(%C, $last_bill). ') - '. + $plandata{recur_included_hours}. ' total hours in plan

    '; + } else { + print 'Has not logged on this billing cycle (since '. + time2str(%C, $last_bill). ')

    '; + } + +} + +print join("\n", $conf->config('svc_acct-notes') ). '

    '. + joblisting({'svcnum'=>$svcnum}, 1). ''; %> -- 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 +++++++++++++++++-- httemplate/edit/part_pkg.cgi | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) 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 diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index ddd86765a..5fbcd0bd1 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -382,7 +382,7 @@ tie my %plans, 'Tie::IxHash', }, 'fieldorder' => [ 'setup_fee', 'recur_flat', 'recur_included_hours', 'recur_hourly_charge' ], 'setup' => 'what.setup_fee.value', - 'recur' => '\'my ($sec,$min,$hour,$mday,$mon,$year) = (localtime($sdate))[0,1,2,3,4,5]; $mon+=$part_pkg->freq; until ($mon<12) { $mon-=12; $year++ }; $edate = timelocal($sec,$min,$hour,$mday,$mon,$year); my $hours = $cust_pkg->seconds_since_sqlradacct($sdate, $edate, \' + what.sql_datasrc + \', \' + what.sql_username + \', \' + what.sql_password + \' ) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours;\'', + 'recur' => '\'my $hours = $cust_pkg->seconds_since_sqlradacct($cust_pkg->last_bill, $sdate, \' + what.sql_datasrc + \', \' + what.sql_username + \', \' + what.sql_password + \' ) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours;\'', }, -- 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 +++++++ httemplate/edit/svc_acct.cgi | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) 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; diff --git a/httemplate/edit/svc_acct.cgi b/httemplate/edit/svc_acct.cgi index 90b26324a..c27bab88a 100755 --- a/httemplate/edit/svc_acct.cgi +++ b/httemplate/edit/svc_acct.cgi @@ -163,7 +163,7 @@ if ( $part_svc->part_svc_column('domsvc')->columnflag eq 'F' ) { } my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => $pkgnum } ); - if ($cust_pkg) { + if ($cust_pkg && !$conf->exists('svc_acct-alldomains') ) { my @cust_svc = map { qsearch('cust_svc', { 'pkgnum' => $_->pkgnum } ) } qsearch('cust_pkg', { 'custnum' => $cust_pkg->custnum } ); -- 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(-) 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 1b2fb3324740555200590d8f75e339e44acf447a Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 14 Oct 2002 09:28:14 +0000 Subject: close invoices which are declined. closes: Bug#408 --- fs_signup/fs_signup_server | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs_signup/fs_signup_server b/fs_signup/fs_signup_server index 7f962e057..703c76ec7 100755 --- a/fs_signup/fs_signup_server +++ b/fs_signup/fs_signup_server @@ -188,9 +188,15 @@ while (1) { if $bill_error; if ( $cust_main->balance > 0 ) { + + #this makes sense. credit is "un-doing" the invoice + $cust_main->credit( $cust_main->balance, 'signup server decline' ); + $cust_main->apply_credits; + #should check list for errors... #$cust_main->suspend; $cust_main->cancel; + $error = '_decline'; } } -- 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(-) 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 bc1639be3d9f32711b4740324c6de1f3bffb0124 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 17 Oct 2002 11:17:50 +0000 Subject: another mason fix, this one from 5 --- httemplate/search/cust_bill.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/search/cust_bill.cgi b/httemplate/search/cust_bill.cgi index 586399a41..985e3dbf5 100755 --- a/httemplate/search/cust_bill.cgi +++ b/httemplate/search/cust_bill.cgi @@ -11,7 +11,7 @@ $limit .= "LIMIT $maxrecords" if $maxrecords; my $offset = $cgi->param('offset') || 0; $limit .= " OFFSET $offset" if $offset; -my $total; +my($total, $tot_amount, $tot_balance); my(@cust_bill); if ( $cgi->keywords ) { -- 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 +++-- httemplate/edit/part_pkg.cgi | 13 +--- httemplate/view/svc_acct.cgi | 16 +---- 6 files changed, 110 insertions(+), 118 deletions(-) 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 diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index 5fbcd0bd1..187578a35 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -356,7 +356,7 @@ tie my %plans, 'Tie::IxHash', }, 'sqlradacct_hour' => { - 'name' => 'Base charge plus charge per-hour from an external SQL radacct table', + 'name' => 'Base charge plus charge per-hour from an external sqlradius radacct table', 'fields' => { 'setup_fee' => { 'name' => 'Setup fee for this package', 'default' => 0, @@ -364,15 +364,6 @@ tie my %plans, 'Tie::IxHash', 'recur_flat' => { 'name' => 'Base monthly charge for this package', 'default' => 0, }, - 'sql_datasrc' => { 'name' => 'DBI data source', - 'default' => 'DBI:mysql:host=radius.server.name;dbname=radius', - }, - 'sql_username' => { 'name' => 'Database username', - 'default' => 'radius', - }, - 'sql_password' => { 'name' => 'Database password', - 'default' => '', - }, 'recur_included_hours' => { 'name' => 'Hours included', 'default' => 0, }, @@ -382,7 +373,7 @@ tie my %plans, 'Tie::IxHash', }, 'fieldorder' => [ 'setup_fee', 'recur_flat', 'recur_included_hours', 'recur_hourly_charge' ], 'setup' => 'what.setup_fee.value', - 'recur' => '\'my $hours = $cust_pkg->seconds_since_sqlradacct($cust_pkg->last_bill, $sdate, \' + what.sql_datasrc + \', \' + what.sql_username + \', \' + what.sql_password + \' ) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours;\'', + 'recur' => '\'my $hours = $cust_pkg->seconds_since_sqlradacct($cust_pkg->last_bill, $sdate ) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours;\'', }, diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi index e755f87d7..dd242b980 100755 --- a/httemplate/view/svc_acct.cgi +++ b/httemplate/view/svc_acct.cgi @@ -146,21 +146,11 @@ print 'RADIUS groups'. print '

    '; -if ( $cust_pkg && $cust_pkg->part_pkg->plan eq 'sqlradacct_hour' ) { - - #false laziness w/httemplate/edit/part_pkg... this stuff doesn't really - #belong in plan data - my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } - split("\n", $cust_pkg->part_pkg->plandata ); +#if ( $cust_pkg && $cust_pkg->part_pkg->plan eq 'sqlradacct_hour' ) { +if ( $cust_pkg && $part_svc->part_export('sqlradius') ) { my $last_bill = $cust_pkg->last_bill; - my $seconds = $svc_acct->seconds_since_sqlradacct( - $last_bill, - time, - $plandata{sql_datasrc}, - $plandata{sql_username}, - $plandata{sql_password}, - ); + my $seconds = $svc_acct->seconds_since_sqlradacct( $last_bill, time ); my $h = int($seconds/3600); my $m = int( ($seconds%3600) / 60 ); my $s = $seconds%60; -- cgit v1.2.1 From 8dc221c91266dc284655942bb5de6392beecbbb3 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 17 Oct 2002 14:33:13 +0000 Subject: sqlradacct hour update --- httemplate/view/svc_acct.cgi | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi index dd242b980..d50241d40 100755 --- a/httemplate/view/svc_acct.cgi +++ b/httemplate/view/svc_acct.cgi @@ -147,20 +147,36 @@ print 'RADIUS groups'. print '

    '; #if ( $cust_pkg && $cust_pkg->part_pkg->plan eq 'sqlradacct_hour' ) { -if ( $cust_pkg && $part_svc->part_export('sqlradius') ) { +if ( $part_svc->part_export('sqlradius') ) { + + my $last_bill; + if ( $cust_pkg ) { + #false laziness w/httemplate/edit/part_pkg... this stuff doesn't really + #belong in plan data + my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } + split("\n", $cust_pkg->part_pkg->plandata ); + + $last_bill = $cust_pkg->last_bill; + } else { + $last_bill = 0; + } - my $last_bill = $cust_pkg->last_bill; my $seconds = $svc_acct->seconds_since_sqlradacct( $last_bill, time ); my $h = int($seconds/3600); my $m = int( ($seconds%3600) / 60 ); my $s = $seconds%60; + if ( $seconds ) { - print 'Online $h h $m m $s s this billing cycle (since '. - time2str(%C, $last_bill). ') - '. + print "Online ${h}h ${m}m ${s}s"; + } else { + print 'Has not logged on'; + } + + if ( $cust_pkg ) { + print ' this billing cycle (since '. time2str(%C, $last_bill). ') - '. $plandata{recur_included_hours}. ' total hours in plan

    '; } else { - print 'Has not logged on this billing cycle (since '. - time2str(%C, $last_bill). ')

    '; + print ' (no billing cycle available for unaudited package)

    '; } } -- 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(-) 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(-) 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(-) 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(-) 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 2f91e1d377e1e03f567ea1ec6bcd9fab0bedff5e Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 17 Oct 2002 15:05:55 +0000 Subject: UI change for hour info --- httemplate/view/svc_acct.cgi | 70 ++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi index d50241d40..c79f71f5d 100755 --- a/httemplate/view/svc_acct.cgi +++ b/httemplate/view/svc_acct.cgi @@ -56,6 +56,41 @@ function areyousure(href) { <% +#if ( $cust_pkg && $cust_pkg->part_pkg->plan eq 'sqlradacct_hour' ) { +if ( $part_svc->part_export('sqlradius') ) { + + my $last_bill; + if ( $cust_pkg ) { + #false laziness w/httemplate/edit/part_pkg... this stuff doesn't really + #belong in plan data + my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } + split("\n", $cust_pkg->part_pkg->plandata ); + + $last_bill = $cust_pkg->last_bill; + } else { + $last_bill = 0; + } + + my $seconds = $svc_acct->seconds_since_sqlradacct( $last_bill, time ); + my $h = int($seconds/3600); + my $m = int( ($seconds%3600) / 60 ); + my $s = $seconds%60; + + if ( $seconds ) { + print "Online $hh $mm $ss"; + } else { + print 'Has not logged on'; + } + + if ( $cust_pkg ) { + print ' this billing cycle (since '. time2str(%C, $last_bill). ') - '. + $plandata{recur_included_hours}. ' total hours in plan

    '; + } else { + print ' (no billing cycle available for unaudited package)

    '; + } + +} + #print qq!
    Send account information!; print qq!Edit this information
    !. @@ -146,41 +181,6 @@ print 'RADIUS groups'. print '

    '; -#if ( $cust_pkg && $cust_pkg->part_pkg->plan eq 'sqlradacct_hour' ) { -if ( $part_svc->part_export('sqlradius') ) { - - my $last_bill; - if ( $cust_pkg ) { - #false laziness w/httemplate/edit/part_pkg... this stuff doesn't really - #belong in plan data - my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } - split("\n", $cust_pkg->part_pkg->plandata ); - - $last_bill = $cust_pkg->last_bill; - } else { - $last_bill = 0; - } - - my $seconds = $svc_acct->seconds_since_sqlradacct( $last_bill, time ); - my $h = int($seconds/3600); - my $m = int( ($seconds%3600) / 60 ); - my $s = $seconds%60; - - if ( $seconds ) { - print "Online ${h}h ${m}m ${s}s"; - } else { - print 'Has not logged on'; - } - - if ( $cust_pkg ) { - print ' this billing cycle (since '. time2str(%C, $last_bill). ') - '. - $plandata{recur_included_hours}. ' total hours in plan

    '; - } else { - print ' (no billing cycle available for unaudited package)

    '; - } - -} - print join("\n", $conf->config('svc_acct-notes') ). '

    '. joblisting({'svcnum'=>$svcnum}, 1). ''; -- cgit v1.2.1 From 497bd20a2aa6a33cff22c25232929b3d7aeaac86 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 17 Oct 2002 15:06:48 +0000 Subject: use consistant terminology --- httemplate/view/svc_acct.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi index c79f71f5d..3fb9156cc 100755 --- a/httemplate/view/svc_acct.cgi +++ b/httemplate/view/svc_acct.cgi @@ -86,7 +86,7 @@ if ( $part_svc->part_export('sqlradius') ) { print ' this billing cycle (since '. time2str(%C, $last_bill). ') - '. $plandata{recur_included_hours}. ' total hours in plan

    '; } else { - print ' (no billing cycle available for unaudited package)

    '; + print ' (no billing cycle available for unaudited account)

    '; } } -- 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 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(-) 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(-) 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 f3175f9f238b54db37d701a7a7a5ede425b5753b Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 18 Oct 2002 16:54:01 +0000 Subject: force executable permissions on bin/pod2x --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index b2b2fcdbc..c47720b80 100644 --- a/Makefile +++ b/Makefile @@ -95,6 +95,7 @@ htmlman: [ -e ./httemplate/docs/man/FS ] || mkdir httemplate/docs/man/FS [ -e ./httemplate/docs/man/FS/UI ] || mkdir httemplate/docs/man/FS/UI [ -e ./httemplate/docs/man/FS/part_export ] || mkdir httemplate/docs/man/FS/part_export + chmod a+rx bin/pod2x [ -e DONT_REBUILD_DOCS ] || bin/pod2x forcehtmlman: -- 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 ++++++++++++++++++----------- eg/vpopmailrestart | 11 ----------- 3 files changed, 21 insertions(+), 22 deletions(-) delete mode 100755 eg/vpopmailrestart 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); } diff --git a/eg/vpopmailrestart b/eg/vpopmailrestart deleted file mode 100755 index c716e2e2b..000000000 --- a/eg/vpopmailrestart +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -for domain in /home/vpopmail/domains/* -do - /home/vpopmail/bin/vmkpasswd `/bin/basename $domain` -done - -/var/qmail/bin/qmail-newu - -killall -HUP qmail-send - -- 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(-) 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(+) 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 f076e082da5f5ec892e2ff6919e478baa1fd2274 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 21 Oct 2002 15:14:07 +0000 Subject: Prevent a fixed or default username or password from being defined --- httemplate/edit/part_svc.cgi | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi index b2862f5a3..f1d42f341 100755 --- a/httemplate/edit/part_svc.cgi +++ b/httemplate/edit/part_svc.cgi @@ -80,7 +80,10 @@ my %defs = ( select_key => 'popnum', select_label => 'city', }, - 'username' => 'Username', + 'username' => { + desc => 'Username', + type => 'disabled', + }, 'quota' => '', '_password' => 'Password', 'gid' => 'GID (when blank, defaults to UID)', @@ -188,15 +191,20 @@ my %defs = ( $html .= "$field"; $html .= "- $desc" if $desc; $html .= ""; - $html .= - qq!Off". - qq!Default ". - qq!Fixed ". - '
    '; if ( ref($def) ) { + $flag = '' if $def->{type} eq 'disabled'; + $html .= + qq!Off". + ''; + unless ( $def->{type} eq 'disabled' ) { + $html .= + qq!Default ". + qq!Fixed ". + '
    '; + } if ( $def->{type} eq 'select' ) { $html .= qq!!; } else { $html .= 'unknown type'. $def->{type}; } -- cgit v1.2.1 From 7c220a811b73a1d237cf0ffd09c48a80ff985a3b Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 21 Oct 2002 15:20:41 +0000 Subject: don't disable for all items --- httemplate/edit/part_svc.cgi | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi index f1d42f341..5fbec4f88 100755 --- a/httemplate/edit/part_svc.cgi +++ b/httemplate/edit/part_svc.cgi @@ -191,20 +191,20 @@ my %defs = ( $html .= "$field"; $html .= "- $desc" if $desc; $html .= ""; + $flag = '' if ref($def) && $def->{type} eq 'disabled'; + $html .= + qq!Off". + ''; + unless ( ref($def) && $def->{type} eq 'disabled' ) { + $html .= + qq!Default ". + qq!Fixed ". + '
    '; + } if ( ref($def) ) { - $flag = '' if $def->{type} eq 'disabled'; - $html .= - qq!Off". - ''; - unless ( $def->{type} eq 'disabled' ) { - $html .= - qq!Default ". - qq!Fixed ". - '
    '; - } if ( $def->{type} eq 'select' ) { $html .= qq! END -for (qw(CARD BILL COMP)) { +for (qw(CARD CHEK BILL COMP)) { print qq!"; -- 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 ++-- httemplate/edit/part_bill_event.cgi | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) 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') diff --git a/httemplate/edit/part_bill_event.cgi b/httemplate/edit/part_bill_event.cgi index 5486b1855..70aca99eb 100755 --- a/httemplate/edit/part_bill_event.cgi +++ b/httemplate/edit/part_bill_event.cgi @@ -108,6 +108,12 @@ tie my %events, 'Tie::IxHash', 'weight' => 30, }, + 'realtime-check' => { + 'name' => 'Run check with a Business::OnlinePayment realtime gateway', + 'code' => '$cust_bill->realtime_ach();', + 'weight' => 30, + }, + 'batch-card' => { 'name' => 'Add card to the pending credit card batch', 'code' => '$cust_bill->batch_card();', -- 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(-) 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 +++++++ httemplate/misc/unapply-cust_pay.cgi | 18 ++++++++++++++++++ httemplate/view/cust_main.cgi | 11 ++++++++++- 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100755 httemplate/misc/unapply-cust_pay.cgi 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', diff --git a/httemplate/misc/unapply-cust_pay.cgi b/httemplate/misc/unapply-cust_pay.cgi new file mode 100755 index 000000000..28643ef6e --- /dev/null +++ b/httemplate/misc/unapply-cust_pay.cgi @@ -0,0 +1,18 @@ +<% + +#untaint paynum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal paynum"; +my $paynum = $1; + +my $cust_pay = qsearchs('cust_pay', { 'paynum' => $paynum } ); +my $custnum = $cust_pay->custnum; + +foreach my $cust_bill_pay ( $cust_pay->cust_bill_pay ) { + my $error = $cust_bill_pay->delete; + eidiot($error) if $error; +} + +print $cgi->redirect($p. "view/cust_main.cgi?". $custnum); + +%> diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index a1a47ea74..7dbdc1356 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -470,6 +470,11 @@ function cust_pay_areyousure(href) { == true) window.location.href = href; } +function cust_pay_unapply_areyousure(href) { + if (confirm("Are you sure you want to unapply this payment?") + == true) + window.location.href = href; +} END @@ -524,8 +529,12 @@ if ( $conf->config('payby-default') ne 'HIDE' ) { my $delete = $payment->closed !~ /^Y/i && $conf->exists('deletepayments') ? qq! (delete)! : ''; + my $unapply = + $payment->closed !~ /^Y/i && $conf->exists('unapplypayments') + ? qq! (unapply)! + : ''; push @history, - "$date\tPayment, Invoice #$invnum ($payby$payinfo)$delete\t\t$paid\t\t\t$target"; + "$date\tPayment, Invoice #$invnum ($payby$payinfo)$delete$unapply\t\t$paid\t\t\t$target"; } my(@cust_credit_bill)= -- 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(-) 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 bcc33ffd55343ce8c2e8f576997ce10018b9d716 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 25 Oct 2002 13:39:02 +0000 Subject: show export numbers --- httemplate/browse/part_svc.cgi | 2 +- httemplate/edit/part_svc.cgi | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/httemplate/browse/part_svc.cgi b/httemplate/browse/part_svc.cgi index 0a06d8ddb..ee7a2622a 100755 --- a/httemplate/browse/part_svc.cgi +++ b/httemplate/browse/part_svc.cgi @@ -84,7 +84,7 @@ map { qsearchs('part_export', { exportnum => $_->exportnum } ) } qsearch('export ) { %> - <%= $part_export->exporttype %> to <%= $part_export->machine %> + <%= $part_export->exportnum %>: <%= $part_export->exporttype %> to <%= $part_export->machine %> <% } %> diff --git a/httemplate/edit/part_svc.cgi b/httemplate/edit/part_svc.cgi index 5fbec4f88..0ee0a468a 100755 --- a/httemplate/edit/part_svc.cgi +++ b/httemplate/edit/part_svc.cgi @@ -154,7 +154,7 @@ my %defs = ( my @part_export = map { qsearch( 'part_export', {exporttype => $_ } ) } keys %{FS::part_export::export_info($layer)}; - $html .= '

    '. table(). + $html .= '

    '. table(). table(). "Exports"; foreach my $part_export ( @part_export ) { $html .= ' $part_export->exportnum, svcpart => $clone || $part_svc->svcpart }); - $html .= '> '. $part_export->exporttype. ' to '. $part_export->machine. - ''; + $html .= '>'. $part_export->exportnum. ': '. $part_export->exporttype. + ' to '. $part_export->machine. ''; $count++; $html .= '' unless $count % $columns; } -- 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(+) 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(-) 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 dfaabf0c82291f2839922065aa80b2590bab25b0 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 2 Nov 2002 00:13:33 +0000 Subject: whew, glad i had a copy of this --- httemplate/graph/money_time-graph.cgi | 96 +++++++++++++++++++++++++++++++++++ httemplate/graph/money_time.cgi | 43 ++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100755 httemplate/graph/money_time-graph.cgi create mode 100644 httemplate/graph/money_time.cgi diff --git a/httemplate/graph/money_time-graph.cgi b/httemplate/graph/money_time-graph.cgi new file mode 100755 index 000000000..93a80d165 --- /dev/null +++ b/httemplate/graph/money_time-graph.cgi @@ -0,0 +1,96 @@ +<% + +#find first month +my $syear = 2001; +my $smonth = 8; + +#find last month +my $eyear = 2002; +my $emonth = 11; + +my @labels; +my %data; + +while ( $syear < $eyear || ( $syear == $eyear && $smonth < $emonth ) ) { + push @labels, "$smonth/$syear"; + + my $speriod = timelocal(0,0,0,1,$smonth-1,$syear); + if ( ++$smonth == 13 ) { $syear++; $smonth=1; } + my $eperiod = timelocal(0,0,0,1,$smonth-1,$syear); + + my $where = "WHERE _date >= $speriod AND _date < $eperiod"; + + # Invoiced + my $charged_sql = "SELECT SUM(charged) FROM cust_bill $where"; + my $charged_sth = dbh->prepare($charged_sql) or die dbh->errstr; + $charged_sth->execute or die $charged_sth->errstr; + my $charged = $charged_sth->fetchrow_arrayref->[0] || 0; + + push @{$data{charged}}, $charged; + + #accounts receivable +# my $ar_sql2 = "SELECT SUM(amount) FROM cust_credit $where"; + my $credited_sql = "SELECT SUM(cust_credit_bill.amount) FROM cust_credit_bill, cust_bill WHERE cust_bill.invnum = cust_credit_bill.invnum AND cust_bill._date >= $speriod AND cust_bill._date < $eperiod"; + my $credited_sth = dbh->prepare($credited_sql) or die dbh->errstr; + $credited_sth->execute or die $credited_sth->errstr; + my $credited = $credited_sth->fetchrow_arrayref->[0] || 0; + + #horrible local kludge + my $expenses_sql = "SELECT SUM(cust_bill_pkg.setup) FROM cust_bill_pkg, cust_bill, cust_pkg, part_pkg WHERE cust_bill.invnum = cust_bill_pkg.invnum AND cust_bill._date >= $speriod AND cust_bill._date < $eperiod AND cust_pkg.pkgnum = cust_bill_pkg.pkgnum AND cust_pkg.pkgpart = part_pkg.pkgpart AND LOWER(part_pkg.pkg) LIKE 'expense _%'"; + my $expenses_sth = dbh->prepare($expenses_sql) or die dbh->errstr; + $expenses_sth->execute or die $expenses_sth->errstr; + my $expenses = $expenses_sth->fetchrow_arrayref->[0] || 0; + + push @{$data{ar}}, $charged-$credited-$expenses; + + #deferred revenue +# push @{$data{defer}}, '0'; + + #cashflow + my $paid_sql = "SELECT SUM(paid) FROM cust_pay $where"; + my $paid_sth = dbh->prepare($paid_sql) or die dbh->errstr; + $paid_sth->execute or die $paid_sth->errstr; + my $paid = $paid_sth->fetchrow_arrayref->[0] || 0; + + my $refunded_sql = "SELECT SUM(refund) FROM cust_refund $where"; + my $refunded_sth = dbh->prepare($refunded_sql) or die dbh->errstr; + $refunded_sth->execute or die $refunded_sth->errstr; + my $refunded = $refunded_sth->fetchrow_arrayref->[0] || 0; + + push @{$data{cash}}, $paid-$refunded; + +} + +#my $chart = Chart::LinesPoints->new(1024,480); +my $chart = Chart::LinesPoints->new(768,480); + +$chart->set( + #'min_val' => 0, + 'legend' => 'bottom', + 'legend_labels' => [ #'Invoiced (cust_bill)', + 'Accounts receivable (invoices - applied credits)', + #'Deferred revenue', + 'Actual cashflow (payments - refunds)' ], +); + +my @data = ( \@labels, + #map $data{$_}, qw( ar defer cash ) + #map $data{$_}, qw( charged ar cash ) + map $data{$_}, qw( ar cash ) + ); + +#my $gd = $chart->plot(\@data); +#open (IMG, ">i_r_c.png"); +#print IMG $gd->png; +#close IMG; + +#$chart->png("i_r_c.png", \@data); + +#$chart->cgi_png(\@data); + +http_header('Content-Type' => 'image/png' ); +$Response->{ContentType} = 'image/png'; + +$chart->_set_colors(); + +%><%= $chart->scalar_png(\@data) %> diff --git a/httemplate/graph/money_time.cgi b/httemplate/graph/money_time.cgi new file mode 100644 index 000000000..d6c35434b --- /dev/null +++ b/httemplate/graph/money_time.cgi @@ -0,0 +1,43 @@ + + + Graphing monetary values over time + + + +
    +
    + + Accounts receivable (invoices - applied credits)
    + + Just Invoices
    + + Accounts receivable, with deferred revenue (invoices - applied credits, with charges for annual/semi-annual/quarterly/etc. services deferred over applicable time period) (there has got to be a shorter description for this)
    + + Cashflow (payments - refunds)
    +
    +From + + to + + + +
    + + -- cgit v1.2.1 From 62e07cc34e38055a59ce160e1c06fcc5edb26927 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 4 Nov 2002 20:51:43 +0000 Subject: fix cosmetic bug on online time view --- httemplate/view/svc_acct.cgi | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi index 3fb9156cc..e86d43f30 100755 --- a/httemplate/view/svc_acct.cgi +++ b/httemplate/view/svc_acct.cgi @@ -60,15 +60,17 @@ function areyousure(href) { if ( $part_svc->part_export('sqlradius') ) { my $last_bill; + my %plandata; if ( $cust_pkg ) { #false laziness w/httemplate/edit/part_pkg... this stuff doesn't really #belong in plan data - my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } - split("\n", $cust_pkg->part_pkg->plandata ); + %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } + split("\n", $cust_pkg->part_pkg->plandata ); $last_bill = $cust_pkg->last_bill; } else { $last_bill = 0; + %plandata = (); } my $seconds = $svc_acct->seconds_since_sqlradacct( $last_bill, time ); @@ -83,7 +85,7 @@ if ( $part_svc->part_export('sqlradius') ) { } if ( $cust_pkg ) { - print ' this billing cycle (since '. time2str(%C, $last_bill). ') - '. + print ' this billing cycle (since '. time2str("%C", $last_bill). ') - '. $plandata{recur_included_hours}. ' total hours in plan

    '; } else { print ' (no billing cycle available for unaudited account)

    '; -- cgit v1.2.1 From d036b0227eb84732140866c72fd0d62cc3b92d7a Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 4 Nov 2002 21:20:44 +0000 Subject: doc --- httemplate/docs/upgrade9.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httemplate/docs/upgrade9.html b/httemplate/docs/upgrade9.html index 7cf44ea31..bcd3f4d5a 100644 --- a/httemplate/docs/upgrade9.html +++ b/httemplate/docs/upgrade9.html @@ -12,8 +12,8 @@
  • Install Net::SSH minimum version 0.07
  • Apply the following changes to your database:
    -INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 17, 'daytime', 'en_US', 'Day Phone' );
    -INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 18, 'night', 'en_US', 'Night Phone' );
    +INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 18, 'daytime', 'en_US', 'Day Phone' );
    +INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 19, 'night', 'en_US', 'Night Phone' );
     
  • Restart Apache and freeside-queued. -- 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(+) 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 6e98f45f5fb306a76bef37c746a6eaf9c9184f88 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 5 Nov 2002 02:15:41 +0000 Subject: local kludge --- httemplate/graph/money_time-graph.cgi | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/httemplate/graph/money_time-graph.cgi b/httemplate/graph/money_time-graph.cgi index 93a80d165..32c2d89e3 100755 --- a/httemplate/graph/money_time-graph.cgi +++ b/httemplate/graph/money_time-graph.cgi @@ -57,7 +57,15 @@ while ( $syear < $eyear || ( $syear == $eyear && $smonth < $emonth ) ) { $refunded_sth->execute or die $refunded_sth->errstr; my $refunded = $refunded_sth->fetchrow_arrayref->[0] || 0; - push @{$data{cash}}, $paid-$refunded; + #horrible local kludge that doesn't even really work right + my $expenses_sql = "SELECT SUM(cust_bill_pay.amount) FROM cust_bill_pay, cust_bill WHERE cust_bill_pay.invnum = cust_bill.invnum AND cust_bill_pay._date >= $speriod AND cust_bill_pay._date < $eperiod AND 0 < ( select count(*) from cust_bill_pkg, cust_pkg, part_pkg WHERE cust_bill.invnum = cust_bill_pkg.invnum AND cust_pkg.pkgnum = cust_bill_pkg.pkgnum AND cust_pkg.pkgpart = part_pkg.pkgpart AND LOWER(part_pkg.pkg) LIKE 'expense _%' )"; + +# my $expenses_sql = "SELECT SUM(cust_bill_pay.amount) FROM cust_bill_pay, cust_bill_pkg, cust_bill, cust_pkg, part_pkg WHERE cust_bill_pay.invnum = cust_bill.invnum AND cust_bill.invnum = cust_bill_pkg.invnum AND cust_bill_pay._date >= $speriod AND cust_bill_pay._date < $eperiod AND cust_pkg.pkgnum = cust_bill_pkg.pkgnum AND cust_pkg.pkgpart = part_pkg.pkgpart AND LOWER(part_pkg.pkg) LIKE 'expense _%'"; + my $expenses_sth = dbh->prepare($expenses_sql) or die dbh->errstr; + $expenses_sth->execute or die $expenses_sth->errstr; + my $expenses = $expenses_sth->fetchrow_arrayref->[0] || 0; + + push @{$data{cash}}, $paid-$refunded-$expenses; } -- 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 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 +++++++++++ httemplate/edit/part_pkg.cgi | 29 +++++++++++++++--- httemplate/view/svc_acct.cgi | 18 +++++++++-- 5 files changed, 165 insertions(+), 26 deletions(-) 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). diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index 187578a35..6141c0083 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -356,7 +356,7 @@ tie my %plans, 'Tie::IxHash', }, 'sqlradacct_hour' => { - 'name' => 'Base charge plus charge per-hour from an external sqlradius radacct table', + 'name' => 'Base charge plus charge per-hour (and for data) from an external sqlradius radacct table', 'fields' => { 'setup_fee' => { 'name' => 'Setup fee for this package', 'default' => 0, @@ -370,13 +370,34 @@ tie my %plans, 'Tie::IxHash', 'recur_hourly_charge' => { 'name' => 'Additional charge per hour', 'default' => 0, }, + 'recur_included_input' => { 'name' => 'Input megabytes included', + 'default' => 0, + }, + 'recur_input_charge' => { 'name' => + 'Additional charge per input megabyte', + 'default' => 0, + }, + 'recur_included_output' => { 'name' => 'Output megabytes included', + 'default' => 0, + }, + 'recur_output_charge' => { 'name' => + 'Additional charge per output megabyte', + 'default' => 0, + }, + 'recur_included_total' => { 'name' => + 'Total input+output megabytes included', + 'default' => 0, + }, + 'recur_total_charge' => { 'name' => + 'Additional charge per input+output megabyte', + 'default' => 0, + }, }, - 'fieldorder' => [ 'setup_fee', 'recur_flat', 'recur_included_hours', 'recur_hourly_charge' ], + 'fieldorder' => [qw( setup_fee recur_flat recur_included_hours recur_hourly_charge recur_included_input recur_input_charge recur_included_input recur_output_charge recur_included_total recur_total_charge )], 'setup' => 'what.setup_fee.value', - 'recur' => '\'my $hours = $cust_pkg->seconds_since_sqlradacct($cust_pkg->last_bill, $sdate ) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours;\'', + 'recur' => '\'my $last_bill = $cust_pkg->last_bill; my $hours = $cust_pkg->seconds_since_sqlradacct($last_bill, $sdate ) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; my $input = $cust_pkg->attribute_since_sqlradacct($last_bill, $sdate, "Acct-Input-Octets" ) / 1048576; my $output = $cust_pkg->attribute_since_sqlradacct($last_bill, $sdate, "Acct-Output-Octets" ) / 1048576; my $total = $input + $output - \' + what.recur_included_total.value + \'; $total = 0 if $total < 0; my $input = $input - \' + what.recur_included_input.value + \'; $input = 0 if $input < 0; my $output = $output - \' + what.recur_included_output.value + \'; $output = 0 if $output < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours + \' + what.recur_input_charge + \' * $input + \' + what.recur_output_charge + \' * $output + \' + what.recur_total_charge + \' * $total ;\'', }, - ; my %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); } diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi index e86d43f30..7295f577d 100755 --- a/httemplate/view/svc_acct.cgi +++ b/httemplate/view/svc_acct.cgi @@ -78,6 +78,13 @@ if ( $part_svc->part_export('sqlradius') ) { my $m = int( ($seconds%3600) / 60 ); my $s = $seconds%60; + my $input = $svc_acct->attribute_since_sqlradacct( + $last_bill, time, 'Acct-Input-Octets' + ) / 1048576; + my $output = $svc_acct->attribute_since_sqlradacct( + $last_bill, time, 'Acct-Output-Octets' + ) / 1048576; + if ( $seconds ) { print "Online $hh $mm $ss"; } else { @@ -86,11 +93,16 @@ if ( $part_svc->part_export('sqlradius') ) { if ( $cust_pkg ) { print ' this billing cycle (since '. time2str("%C", $last_bill). ') - '. - $plandata{recur_included_hours}. ' total hours in plan

    '; + $plandata{recur_included_hours}. ' total hours in plan
    '; } else { - print ' (no billing cycle available for unaudited account)

    '; + print ' (no billing cycle available for unaudited account)
    '; } + print 'Input: '. sprintf("%.3f", $input). ' megabytes
    '; + print 'Output: '. sprintf("%.3f", $output). ' megabytes
    '; + + print '
    '; + } #print qq!
    Send account information!; @@ -183,7 +195,7 @@ print 'RADIUS groups'. print '

    '; -print join("\n", $conf->config('svc_acct-notes') ). '

    '. +print join("\n", $conf->config('svc_acct-notes') ). '

    '. joblisting({'svcnum'=>$svcnum}, 1). ''; %> -- 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(-) 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 b4206f7dd4e3f00b1fac73245ade1d28388f2ad3 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 5 Nov 2002 23:41:07 +0000 Subject: fix for correct radacct column names --- httemplate/edit/part_pkg.cgi | 2 +- httemplate/view/svc_acct.cgi | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index 6141c0083..bbecd0c52 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -395,7 +395,7 @@ tie my %plans, 'Tie::IxHash', }, 'fieldorder' => [qw( setup_fee recur_flat recur_included_hours recur_hourly_charge recur_included_input recur_input_charge recur_included_input recur_output_charge recur_included_total recur_total_charge )], 'setup' => 'what.setup_fee.value', - 'recur' => '\'my $last_bill = $cust_pkg->last_bill; my $hours = $cust_pkg->seconds_since_sqlradacct($last_bill, $sdate ) / 3600 - \' + what.recur_included_hours.value + \'; $hours = 0 if $hours < 0; my $input = $cust_pkg->attribute_since_sqlradacct($last_bill, $sdate, "Acct-Input-Octets" ) / 1048576; my $output = $cust_pkg->attribute_since_sqlradacct($last_bill, $sdate, "Acct-Output-Octets" ) / 1048576; my $total = $input + $output - \' + what.recur_included_total.value + \'; $total = 0 if $total < 0; my $input = $input - \' + what.recur_included_input.value + \'; $input = 0 if $input < 0; my $output = $output - \' + what.recur_included_output.value + \'; $output = 0 if $output < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours + \' + what.recur_input_charge + \' * $input + \' + what.recur_output_charge + \' * $output + \' + what.recur_total_charge + \' * $total ;\'', + 'recur' => '\'my $last_bill = $cust_pkg->last_bill; my $hours = $cust_pkg->seconds_since_sqlradacct($last_bill, $sdate ) / 3600 - \' + what.recur_included_hours.value + \'; $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 - \' + what.recur_included_total.value + \'; $total = 0 if $total < 0; my $input = $input - \' + what.recur_included_input.value + \'; $input = 0 if $input < 0; my $output = $output - \' + what.recur_included_output.value + \'; $output = 0 if $output < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours + \' + what.recur_input_charge + \' * $input + \' + what.recur_output_charge + \' * $output + \' + what.recur_total_charge + \' * $total ;\'', }, ; diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi index 7295f577d..30480d1e8 100755 --- a/httemplate/view/svc_acct.cgi +++ b/httemplate/view/svc_acct.cgi @@ -79,10 +79,10 @@ if ( $part_svc->part_export('sqlradius') ) { my $s = $seconds%60; my $input = $svc_acct->attribute_since_sqlradacct( - $last_bill, time, 'Acct-Input-Octets' + $last_bill, time, 'AcctInputOctets' ) / 1048576; my $output = $svc_acct->attribute_since_sqlradacct( - $last_bill, time, 'Acct-Output-Octets' + $last_bill, time, 'AcctOutputOctets' ) / 1048576; if ( $seconds ) { -- cgit v1.2.1 From 4ff72381c99c7508f6028d2c44a2ec5c455e4670 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 5 Nov 2002 23:43:20 +0000 Subject: ui --- httemplate/view/svc_acct.cgi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi index 30480d1e8..e00562ace 100755 --- a/httemplate/view/svc_acct.cgi +++ b/httemplate/view/svc_acct.cgi @@ -98,8 +98,8 @@ if ( $part_svc->part_export('sqlradius') ) { print ' (no billing cycle available for unaudited account)
    '; } - print 'Input: '. sprintf("%.3f", $input). ' megabytes
    '; - print 'Output: '. sprintf("%.3f", $output). ' megabytes
    '; + print 'Input: '. sprintf("%.3f", $input). ' megabytes
    '; + print 'Output: '. sprintf("%.3f", $output). ' megabytes
    '; print '
    '; -- cgit v1.2.1 From 456021fddfef45aaf2d629af509fda9074db00cf Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 6 Nov 2002 03:58:42 +0000 Subject: data charging --- httemplate/edit/part_pkg.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index bbecd0c52..be52e5b77 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -393,7 +393,7 @@ tie my %plans, 'Tie::IxHash', 'default' => 0, }, }, - 'fieldorder' => [qw( setup_fee recur_flat recur_included_hours recur_hourly_charge recur_included_input recur_input_charge recur_included_input recur_output_charge recur_included_total recur_total_charge )], + 'fieldorder' => [qw( setup_fee recur_flat recur_included_hours recur_hourly_charge recur_included_input recur_input_charge recur_included_output recur_output_charge recur_included_total recur_total_charge )], 'setup' => 'what.setup_fee.value', 'recur' => '\'my $last_bill = $cust_pkg->last_bill; my $hours = $cust_pkg->seconds_since_sqlradacct($last_bill, $sdate ) / 3600 - \' + what.recur_included_hours.value + \'; $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 - \' + what.recur_included_total.value + \'; $total = 0 if $total < 0; my $input = $input - \' + what.recur_included_input.value + \'; $input = 0 if $input < 0; my $output = $output - \' + what.recur_included_output.value + \'; $output = 0 if $output < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours + \' + what.recur_input_charge + \' * $input + \' + what.recur_output_charge + \' * $output + \' + what.recur_total_charge + \' * $total ;\'', }, -- cgit v1.2.1 From 928c6b2dbe79b079eb79eca941bc8f1e24dd5795 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 6 Nov 2002 04:11:44 +0000 Subject: data billing --- httemplate/edit/part_pkg.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index be52e5b77..bea6dcb7f 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -395,7 +395,7 @@ tie my %plans, 'Tie::IxHash', }, 'fieldorder' => [qw( setup_fee recur_flat recur_included_hours recur_hourly_charge recur_included_input recur_input_charge recur_included_output recur_output_charge recur_included_total recur_total_charge )], 'setup' => 'what.setup_fee.value', - 'recur' => '\'my $last_bill = $cust_pkg->last_bill; my $hours = $cust_pkg->seconds_since_sqlradacct($last_bill, $sdate ) / 3600 - \' + what.recur_included_hours.value + \'; $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 - \' + what.recur_included_total.value + \'; $total = 0 if $total < 0; my $input = $input - \' + what.recur_included_input.value + \'; $input = 0 if $input < 0; my $output = $output - \' + what.recur_included_output.value + \'; $output = 0 if $output < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours + \' + what.recur_input_charge + \' * $input + \' + what.recur_output_charge + \' * $output + \' + what.recur_total_charge + \' * $total ;\'', + 'recur' => '\'my $last_bill = $cust_pkg->last_bill; my $hours = $cust_pkg->seconds_since_sqlradacct($last_bill, $sdate ) / 3600 - \' + what.recur_included_hours.value + \'; $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 - \' + what.recur_included_total.value + \'; $total = 0 if $total < 0; my $input = $input - \' + what.recur_included_input.value + \'; $input = 0 if $input < 0; my $output = $output - \' + what.recur_included_output.value + \'; $output = 0 if $output < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours + \' + what.recur_input_charge.value + \' * $input + \' + what.recur_output_charge.value + \' * $output + \' + what.recur_total_charge.value + \' * $total ;\'', }, ; -- 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(-) 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 d2f7bc5bcdb39f689d4a72946f0728325d0c09c8 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 6 Nov 2002 05:41:13 +0000 Subject: lala --- httemplate/graph/money_time-graph.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/graph/money_time-graph.cgi b/httemplate/graph/money_time-graph.cgi index 32c2d89e3..ca8f6e86b 100755 --- a/httemplate/graph/money_time-graph.cgi +++ b/httemplate/graph/money_time-graph.cgi @@ -6,7 +6,7 @@ my $smonth = 8; #find last month my $eyear = 2002; -my $emonth = 11; +my $emonth = 12; my @labels; my %data; -- 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(+) 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 db7c28d12dae1ff90383fa64725893b198007865 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 9 Nov 2002 10:59:08 +0000 Subject: javascript quoting problem in per-hour charging --- httemplate/edit/part_pkg.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index bea6dcb7f..1fd634961 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -395,7 +395,7 @@ tie my %plans, 'Tie::IxHash', }, 'fieldorder' => [qw( setup_fee recur_flat recur_included_hours recur_hourly_charge recur_included_input recur_input_charge recur_included_output recur_output_charge recur_included_total recur_total_charge )], 'setup' => 'what.setup_fee.value', - 'recur' => '\'my $last_bill = $cust_pkg->last_bill; my $hours = $cust_pkg->seconds_since_sqlradacct($last_bill, $sdate ) / 3600 - \' + what.recur_included_hours.value + \'; $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 - \' + what.recur_included_total.value + \'; $total = 0 if $total < 0; my $input = $input - \' + what.recur_included_input.value + \'; $input = 0 if $input < 0; my $output = $output - \' + what.recur_included_output.value + \'; $output = 0 if $output < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours + \' + what.recur_input_charge.value + \' * $input + \' + what.recur_output_charge.value + \' * $output + \' + what.recur_total_charge.value + \' * $total ;\'', + 'recur' => '\'my $last_bill = $cust_pkg->last_bill; my $hours = $cust_pkg->seconds_since_sqlradacct($last_bill, $sdate ) / 3600 - \' + what.recur_included_hours.value + \'; $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 - \' + what.recur_included_total.value + \'; $total = 0 if $total < 0; my $input = $input - \' + what.recur_included_input.value + \'; $input = 0 if $input < 0; my $output = $output - \' + what.recur_included_output.value + \'; $output = 0 if $output < 0; \' + what.recur_flat.value + \' + \' + what.recur_hourly_charge.value + \' * $hours + \' + what.recur_input_charge.value + \' * $input + \' + what.recur_output_charge.value + \' * $output + \' + what.recur_total_charge.value + \' * $total ;\'', }, ; -- 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(-) 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 + httemplate/edit/part_export.cgi | 2 + 5 files changed, 279 insertions(+) create mode 100644 FS/FS/part_export/ldap.pm create mode 100644 FS/t/part_export-ldap.t 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"; diff --git a/httemplate/edit/part_export.cgi b/httemplate/edit/part_export.cgi index bd427aa40..d64526dd4 100644 --- a/httemplate/edit/part_export.cgi +++ b/httemplate/edit/part_export.cgi @@ -70,6 +70,8 @@ my $widget = new HTML::Widgets::SelectLayers( $html .= qq!!; } elsif ( $type eq 'text' ) { $html .= qq!!; + } elsif ( $type eq 'checkbox' ) { + $html .= qq!!; } else { $html .= "unknown type $type"; } -- cgit v1.2.1 From d9877cfc04344365f799b52057a13fc39c5743b7 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 19 Nov 2002 05:17:46 +0000 Subject: oops, remove 10 digit account number limit --- httemplate/edit/cust_main.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index 8f2fe7cee..c8db6b206 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -402,7 +402,7 @@ if ( $payby_default eq 'HIDE' ) { my %payby = ( 'CARD' => qq!Credit card
    ${r}
    ${r}Exp !. expselect("CARD"). qq!
    ${r}Name on card
    !, - 'CHEK' => qq!Electronic check
    ${r}Account number
    ${r}ABA/Routing code
    ${r}Bank name !, + 'CHEK' => qq!Electronic check
    ${r}Account number
    ${r}ABA/Routing code
    ${r}Bank name !, 'BILL' => qq!Billing
    P.O.
    Attention
    !, 'COMP' => qq!Complimentary
    ${r}Approved by
    ${r}Exp !. expselect("COMP"), ); -- 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 + fs_signup/FS-SignupClient/cgi/signup.cgi | 204 ++---------------------------- fs_signup/FS-SignupClient/cgi/signup.html | 5 + httemplate/docs/schema.html | 8 +- httemplate/edit/cust_main.cgi | 6 +- httemplate/edit/part_bill_event.cgi | 2 +- httemplate/view/cust_main.cgi | 7 + 13 files changed, 81 insertions(+), 217 deletions(-) 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 { diff --git a/fs_signup/FS-SignupClient/cgi/signup.cgi b/fs_signup/FS-SignupClient/cgi/signup.cgi index 333a88cf8..1eb0613ba 100755 --- a/fs_signup/FS-SignupClient/cgi/signup.cgi +++ b/fs_signup/FS-SignupClient/cgi/signup.cgi @@ -1,6 +1,6 @@ #!/usr/bin/perl -Tw # -# $Id: signup.cgi,v 1.31 2002-10-12 10:15:55 ivan Exp $ +# $Id: signup.cgi,v 1.32 2002-11-19 09:51:59 ivan Exp $ use strict; use vars qw( @payby $cgi $locales $packages $pops $init_data $error @@ -18,7 +18,7 @@ use vars qw( @payby $cgi $locales $packages $pops $init_data $error $self_url ); use subs qw( print_form print_okay print_decline - signup_default success_default decline_default + success_default decline_default expselect ); use CGI; #use CGI::Carp qw(fatalsToBrowser); @@ -88,11 +88,13 @@ if ( -e $signup_html ) { $agentnum = $1; } } else { - $signup_template = new Text::Template ( TYPE => 'STRING', - SOURCE => &signup_default, - DELIMITERS => [ '<%=', '%>' ] - ) - or die $Text::Template::ERROR; + #too much maintenance hassle to keep in this file + die "can't find ./signup.html or /usr/local/freeside/signup.html"; + #$signup_template = new Text::Template ( TYPE => 'STRING', + # SOURCE => &signup_default, + # DELIMITERS => [ '<%=', '%>' ] + # ) + # or die $Text::Template::ERROR; } if ( -e $success_html ) { @@ -510,191 +512,3 @@ support. END } -sub signup_default { #html to use if you don't specify a template file - <<'END'; -ISP Signup form -ISP Signup form

    -<%= $error %> -
    - - - -Contact Information - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    *Contact name
    (last, first)
    , -
    Company
    *Address
     
    *City*State/Country*Zip
    Day Phone
    Night Phone
    Fax
    * required fields
    -
    Billing information - - -<%= scalar(@payby) > 1 ? '' : '' %> -
    - - <%= - $OUT .= ' - - Postal mail invoice -
    Email invoice -
    Billing type
    - - - - <%= - - my $cardselect = ''; - - my %payby = ( - 'CARD' => qq!Credit card
    *$cardselect
    *Exp !. expselect("CARD"). qq!
    *Name on card
    !, - 'CHEK' => qq!Electronic check
    ${r}Account number
    ${r}ABA/Routing code
    ${r}Bank name !, - 'BILL' => qq!Billing
    P.O.
    Attention
    !, - 'COMP' => qq!Complimentary
    *Approved by
    *Exp !. expselect("COMP"), - 'PREPAY' => qq!Prepaid card
    *!, - ); - - my( $account, $aba ) = split('@', $payinfo); - - my %paybychecked = ( - 'CARD' => qq!Credit card
    *$cardselect
    *Exp !. expselect("CARD", $paydate). qq!
    *Name on card
    !, - 'CHEK' => qq!Electronic check
    ${r}Account number
    ${r}ABA/Routing code
    ${r}Bank name !, - 'BILL' => qq!Billing
    P.O.
    Attention
    !, - 'COMP' => qq!Complimentary
    *Approved by
    *Exp !. expselect("COMP", $paydate), - 'PREPAY' => qq!Prepaid card
    *!, - ); - - for (@payby) { - if ( scalar(@payby) == 1) { - $OUT .= '"; - } else { - $OUT .= qq!!; - } else { - $OUT .= qq!> $payby{$_}!; - } - - } - } - %> - -
    '. - qq!!. - "$paybychecked{$_} $paybychecked{$_}
    * required fields for each billing type -

    First package - - - - - - - - - - - - - - - - -<%= - if ( $init_data->{'security_phrase'} ) { - $OUT .= < - - - -ENDOUT - } else { - $OUT .= ''; - } -%> -<%= - if ( scalar(@$pops) ) { - $OUT .= ''; - } else { - $OUT .= popselector($popnum); - } -%> -
    Username
    Password
    Re-enter Password
    Security Phrase -
    Access number'. - popselector($popnum). '
    -

    -
    -END -} diff --git a/fs_signup/FS-SignupClient/cgi/signup.html b/fs_signup/FS-SignupClient/cgi/signup.html index 6c601410c..d89b6854b 100755 --- a/fs_signup/FS-SignupClient/cgi/signup.html +++ b/fs_signup/FS-SignupClient/cgi/signup.html @@ -97,13 +97,18 @@ Contact Information my %payby = ( 'CARD' => qq!Credit card
    *$cardselect
    *Exp !. expselect("CARD"). qq!
    *Name on card
    !, + 'CHEK' => qq!Electronic check
    ${r}Account number
    ${r}ABA/Routing code
    ${r}Bank name !, + 'LECB' => qq!Phone bill billing
    ${r}Phone number !, 'BILL' => qq!Billing
    P.O.
    *Exp !. expselect("BILL", "12-2037"). qq!
    *Attention
    !, 'COMP' => qq!Complimentary
    *Approved by
    *Exp !. expselect("COMP"), 'PREPAY' => qq!Prepaid card
    *!, ); + my( $account, $aba ) = split('@', $payinfo); my %paybychecked = ( 'CARD' => qq!Credit card
    *$cardselect
    *Exp !. expselect("CARD", $paydate). qq!
    *Name on card
    !, + 'CHEK' => qq!Electronic check
    ${r}Account number
    ${r}ABA/Routing code
    ${r}Bank name !, + 'LECB' => qq!Phone bill billing
    ${r}Phone number !, 'BILL' => qq!Billing
    P.O.
    *Exp !. expselect("BILL", $paydate). qq!
    *Attention
    !, 'COMP' => qq!Complimentary
    *Approved by
    *Exp !. expselect("COMP", $paydate), 'PREPAY' => qq!Prepaid card
    *!, diff --git a/httemplate/docs/schema.html b/httemplate/docs/schema.html index c518d4a4d..b4d21f3b9 100644 --- a/httemplate/docs/schema.html +++ b/httemplate/docs/schema.html @@ -39,7 +39,7 @@
  • part_bill_event - Invoice event definitions
    • eventpart - primary key -
    • payby - CARD, BILL, or COMP +
    • payby - CARD, CHEK, LECB, BILL, or COMP
    • event - event name
    • eventcode - event action
    • seconds - how long after the invoice date (cust_bill._date) events of this type are triggered @@ -109,7 +109,7 @@
    • ship_daytime
    • ship_night
    • ship_fax -
    • payby - CARD, BILL, or COMP +
    • payby - CARD, CHEK, LECB, BILL, or COMP
    • payinfo - card number, P.O.#, or comp issuer
    • paydate - expiration date
    • payname - billing name (name on card) @@ -150,7 +150,7 @@
    • custnum - customer
    • paid - amount
    • _date -
    • payby - CARD, BILL, or COMP +
    • payby - CARD, CHEK, LECB, BILL, or COMP
    • payinfo - card number, P.O.#, or comp issuer
    • paybatch - text field for tracking card processor batches
    • closed - books closed flag, empty or `Y' @@ -200,7 +200,7 @@
    • custnum - customer
    • refund - amount
    • _date -
    • payby - CARD, BILL or COMP +
    • payby - CARD, CHEK, LECB, BILL or COMP
    • payinfo - card number, P.O.#, or comp issuer
    • otaker - order taker
    • closed - books closed flag, empty or `Y' diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index c8db6b206..5642604d2 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -353,7 +353,7 @@ if ( $payby_default eq 'HIDE' ) { print qq!'; - foreach my $payby (qw( CARD CHEK BILL COMP )) { + foreach my $payby (qw( CARD CHEK LECB BILL COMP )) { foreach my $field (qw( payinfo payname )) { print qq!'; @@ -403,6 +403,7 @@ if ( $payby_default eq 'HIDE' ) { my %payby = ( 'CARD' => qq!Credit card
      ${r}
      ${r}Exp !. expselect("CARD"). qq!
      ${r}Name on card
      !, 'CHEK' => qq!Electronic check
      ${r}Account number
      ${r}ABA/Routing code
      ${r}Bank name !, + 'LECB' => qq!Phone bill billing
      ${r}Phone number !, 'BILL' => qq!Billing
      P.O.
      Attention
      !, 'COMP' => qq!Complimentary
      ${r}Approved by
      ${r}Exp !. expselect("COMP"), ); @@ -412,12 +413,13 @@ if ( $payby_default eq 'HIDE' ) { my %paybychecked = ( 'CARD' => qq!Credit card
      ${r}
      ${r}Exp !. expselect("CARD", $cust_main->paydate). qq!
      ${r}Name on card
      !, 'CHEK' => qq!Electronic check
      ${r}Account number
      ${r}ABA/Routing code
      ${r}Bank name !, + 'LECB' => qq!Phone bill billing
      ${r}Phone number !, 'BILL' => qq!Billing
      P.O.
      Attention
      !, 'COMP' => qq!Complimentary
      ${r}Approved by
      ${r}Exp !. expselect("COMP", $cust_main->paydate), ); $cust_main->payby($payby_default) unless $cust_main->payby; - for (qw(CARD CHEK BILL COMP)) { + for (qw(CARD CHEK LECB BILL COMP)) { print qq!payby eq "$_") { print qq! CHECKED> $paybychecked{$_}!; diff --git a/httemplate/edit/part_bill_event.cgi b/httemplate/edit/part_bill_event.cgi index 70aca99eb..30a60ea41 100755 --- a/httemplate/edit/part_bill_event.cgi +++ b/httemplate/edit/part_bill_event.cgi @@ -41,7 +41,7 @@ print ntable("#cccccc",2), <Payby
    ', + '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 36ebe10e75936261aad914bbb5e5e2154323412c Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 28 Nov 2002 10:54:13 +0000 Subject: separate state and country !; + $county_html .= ''; + } else { + $county_html .= + qq!!; + } + + my $state_html = qq!'; + + $state_html .= ''; + + my $country_html = qq!'; + + ($county_html, $state_html, $country_html); + +} + sub success_default { #html to use if you don't specify a success file <<'END'; Signup successful diff --git a/fs_signup/FS-SignupClient/cgi/signup.html b/fs_signup/FS-SignupClient/cgi/signup.html index d89b6854b..724ffd7f8 100755 --- a/fs_signup/FS-SignupClient/cgi/signup.html +++ b/fs_signup/FS-SignupClient/cgi/signup.html @@ -28,25 +28,20 @@ Contact Information *City *State/Country - + + <%= + ($county_html, $state_html, $country_html) = + regionselector( $county, $state, $country ); + + "$county_html $state_html"; + %> + *Zip + + *Country + <%= $country_html %> Day Phone diff --git a/fs_signup/fs_signup_server b/fs_signup/fs_signup_server index 4b7e898f6..e0fa9ba5f 100755 --- a/fs_signup/fs_signup_server +++ b/fs_signup/fs_signup_server @@ -94,7 +94,11 @@ while (1) { 'msgcat' => { map { $_=>gettext($_) } qw( passwords_dont_match invalid_card unknown_card_type not_a - ) } + ) }, + + 'statedefault' => $conf->config('statedefault') || 'CA', + + 'countrydefault' => $conf->config('countrydefault') || 'US', }; -- cgit v1.2.1 From f096f7efd2093da376b9a31e3e5a872577bdc9b4 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 29 Nov 2002 05:14:21 +0000 Subject: accept unmunged state/county/country --- fs_signup/FS-SignupClient/cgi/signup.cgi | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/fs_signup/FS-SignupClient/cgi/signup.cgi b/fs_signup/FS-SignupClient/cgi/signup.cgi index b6cc08a47..dc242bdcf 100755 --- a/fs_signup/FS-SignupClient/cgi/signup.cgi +++ b/fs_signup/FS-SignupClient/cgi/signup.cgi @@ -1,6 +1,6 @@ #!/usr/bin/perl -Tw # -# $Id: signup.cgi,v 1.33 2002-11-28 10:54:13 ivan Exp $ +# $Id: signup.cgi,v 1.34 2002-11-29 05:14:21 ivan Exp $ use strict; use vars qw( @payby $cgi $locales $packages $pops $init_data $error @@ -143,11 +143,21 @@ $cgi = new CGI; if ( defined $cgi->param('magic') ) { if ( $cgi->param('magic') eq 'process' ) { - $cgi->param('state') =~ /^(\w*)( \(([\w ]+)\))? ?\/ ?(\w+)$/ - or die "Oops, illegal \"state\" param: ". $cgi->param('state'); - $state = $1; - $county = $3 || ''; - $country = $4; + if ( $cgi->param('state') =~ /^(\w*)( \(([\w ]+)\))? ?\/ ?(\w+)$/ ) { + $state = $1; + $county = $3 || ''; + $country = $4; + } elsif ( $cgi->param('state') =~ /^(\w*)$/ ) { + $state = $1; + $cgi->param('county') =~ /^([\w ]*)$/ + or die "illegal county: ". $cgi->param('county'); + $county = $1; + $cgi->param('country') =~ /^(\w+)$/ + or die "illegal country: ". $cgi->param('country'); + $country = $1; + } else { + die "illegal state: ". $cgi->param('state'); + } $payby = $cgi->param('payby'); $payinfo = $cgi->param( $payby. '_payinfo' ); -- 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(-) 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 5b1348a5b82cb153e6f42be8187de1a7c84dfb6d Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 4 Dec 2002 12:37:49 +0000 Subject: oops, typo --- bin/bind.export | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bind.export b/bin/bind.export index 63fb0f60c..b1594ae6b 100755 --- a/bin/bind.export +++ b/bin/bind.export @@ -39,7 +39,7 @@ foreach my $export ( @exports ) { or die "can't open $prefix/named.conf: $!"; open(CONF_HEADER,"<$prefix/named.conf.HEADER") - or die "can't open $prefix/named.conf.HEADER: $!" + or die "can't open $prefix/named.conf.HEADER: $!"; while () { print NAMED_CONF $_; } close CONF_HEADER; -- cgit v1.2.1 From d75b4ad13df9e8e3cb570060252fa45ef4e80def Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 4 Dec 2002 12:43:17 +0000 Subject: really fixed now --- bin/bind.export | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bind.export b/bin/bind.export index b1594ae6b..943aefbb0 100755 --- a/bin/bind.export +++ b/bin/bind.export @@ -139,7 +139,7 @@ foreach my $sexport ( @sexports ) { #false laziness with above or die "can't open $prefix/named.conf: $!"; open(CONF_HEADER,"<$prefix/named.conf.HEADER") - or die "can't open $prefix/named.conf.HEADER: $!" + or die "can't open $prefix/named.conf.HEADER: $!"; while () { print NAMED_CONF $_; } close CONF_HEADER; -- cgit v1.2.1 From 2f1f5c47edd9df2af61d104b512b9a1be12c3ad1 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 9 Dec 2002 10:54:24 +0000 Subject: doc --- httemplate/docs/install.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/httemplate/docs/install.html b/httemplate/docs/install.html index 100a3cc64..d22915176 100644 --- a/httemplate/docs/install.html +++ b/httemplate/docs/install.html @@ -114,7 +114,10 @@ $ su
    • Run make aspdocs -
    • Copy aspdocs/ to your web server's document space. +
    • Copy aspdocs/ to your web server's document space: +
      +cp aspdocs /usr/local/apache/htdocs/freeside-asp
      +
    • Create a Global directory, such as /usr/local/etc/freeside/asp-global/:
       mkdir /usr/local/etc/freeside/asp-global/
      -- 
      cgit v1.2.1
      
      
      From 6addb511875324241cb002b2fe96225c066d0ddc Mon Sep 17 00:00:00 2001
      From: ivan 
      Date: Wed, 11 Dec 2002 00:12:22 +0000
      Subject: beginning of web-based data importer
      
      ---
       httemplate/misc/meta-import.cgi         |  52 ++++++++++++
       httemplate/misc/process/meta-import.cgi | 145 ++++++++++++++++++++++++++++++++
       2 files changed, 197 insertions(+)
       create mode 100644 httemplate/misc/meta-import.cgi
       create mode 100644 httemplate/misc/process/meta-import.cgi
      
      diff --git a/httemplate/misc/meta-import.cgi b/httemplate/misc/meta-import.cgi
      new file mode 100644
      index 000000000..ebd2a7e2f
      --- /dev/null
      +++ b/httemplate/misc/meta-import.cgi
      @@ -0,0 +1,52 @@
      +
      +<%= header('Import') %>
      +
      +Import a CSV file containing customer records (zip tar etc).

      + +##no##Default file format is CSV, with the following field order: cust_pkg.setup, dayphone, first, last, address1, address2, city, state, zip, comments

      + +<% + #false laziness with edit/cust_main.cgi + my @agents = qsearch( 'agent', {} ); + die "No agents created!" unless @agents; + my $agentnum = $agents[0]->agentnum; #default to first + + if ( scalar(@agents) == 1 ) { +%> + +<% } else { %> +

      Agent

      +<% } %> + +<% + my @referrals = qsearch('part_referral',{}); + die "No advertising sources created!" unless @referrals; + my $refnum = $referrals[0]->refnum; #default to first + + if ( scalar(@referrals) == 1 ) { +%> + +<% } else { %> +

      Advertising source

      +<% } %> + + First package:

      + + CSV (zip, tar etc) Filename:

      + +
      + + + diff --git a/httemplate/misc/process/meta-import.cgi b/httemplate/misc/process/meta-import.cgi new file mode 100644 index 000000000..d42d6d466 --- /dev/null +++ b/httemplate/misc/process/meta-import.cgi @@ -0,0 +1,145 @@ + +<%= header('Map tables') %> + +<% + #one + unless ( $cgi->param('magic') ) { + + #oops, silly + #my $fh = $cgi->upload('csvfile'); + ##warn $cgi; + ##warn $fh; + # + #use Archive::Tar; + #$tar = Archive::Tar->new(); + #$tar->create_archive($fh); #or die $tar->error; + + #haha for now + my @files = qw( +authserv credtype dunprev invoice pmtdet product taxplan +ccdet customer genlog ledger pops pubvars +cchist discplan glacct origco prodcat recur users +credcode dundet invline payment prodclas repforms webserv + ); + + %> +
      + + <%= hashmaker('schema', \@files, [ grep { ! /^h_/ } dbdef->tables ] ) %> +
      +
      + + + <% + + } elsif ( $cgi->param('magic') eq 'process' ) { + + %> +
      + + <% + + my $schema_string = $cgi->param('schema'); + my %schema = map { /^\s*(\w+)\s*=>\s*(\w+)\s*$/ + or die "guru meditation #420: $_"; + ( $1 => $2 ); + } + split( /\n/, $schema_string ); + + #*** should be in global.asa/handler.pl like the rest + eval 'use Text::CSV_XS;'; + + foreach my $table ( keys %schema ) { + + my $csv = Text::CSV_XS->new({ 'binary'=>1 }); + open(FILE,"); + close FILE; + $csv->parse($header) or die; + my @from_columns = $csv->fields; + + my @fs_columns = dbdef->table($schema{$table})->columns; + + %> + <%= hashmaker($table, \@from_columns, \@fs_columns, $table, $schema{$table} ) %> +


      + <% + + } + + %> +
      +
      + + + <% + + } elsif ( $cgi->param('magic') eq 'process' ) { + + %> + print results!! + <% + } + + #hashmaker widget + sub hashmaker { + my($name, $from, $to, $labelfrom, $labelto) = @_; + $fromsize = scalar(@$from); + $tosize = scalar(@$to); + "'. + '
      $labelfrom$labelto
      ". + qq!\n". + ''. + qq!\n". + '
      '. + qq!!. + '
      '. + qq!!. + '
      '. + "". + ''; + } + +%> -- 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(+) 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 ++++++++------- httemplate/misc/process/meta-import.cgi | 50 +++++++++++++++++++++++++-------- 2 files changed, 49 insertions(+), 24 deletions(-) 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]; diff --git a/httemplate/misc/process/meta-import.cgi b/httemplate/misc/process/meta-import.cgi index d42d6d466..4c3c7d665 100644 --- a/httemplate/misc/process/meta-import.cgi +++ b/httemplate/misc/process/meta-import.cgi @@ -19,6 +19,7 @@ function SafeOnsubmit() { gSafeOnsubmit[i](); } +
      <% #one unless ( $cgi->param('magic') ) { @@ -41,23 +42,19 @@ credcode dundet invline payment prodclas repforms webserv ); %> - <%= hashmaker('schema', \@files, [ grep { ! /^h_/ } dbdef->tables ] ) %>
      -
      - - <% } elsif ( $cgi->param('magic') eq 'process' ) { %> -
      <% my $schema_string = $cgi->param('schema'); + %><% my %schema = map { /^\s*(\w+)\s*=>\s*(\w+)\s*$/ or die "guru meditation #420: $_"; ( $1 => $2 ); @@ -88,18 +85,47 @@ credcode dundet invline payment prodclas repforms webserv %>
      -
      - - <% - } elsif ( $cgi->param('magic') eq 'process' ) { + } elsif ( $cgi->param('magic') eq 'process2' ) { - %> - print results!! - <% + print "
      \n";
      +    #false laziness with above
      +    my $schema_string = $cgi->param('schema');
      +    my %schema = map { /^\s*(\w+)\s*=>\s*(\w+)\s*$/
      +                         or die "guru meditation #420: $_";
      +                       ( $1 => $2 );
      +                     }
      +                 split( /\n/, $schema_string );
      +    foreach my $table ( keys %schema ) {
      +      ( my $spaces = $table ) =~ s/./ /g;
      +      print "'$table' => { 'table' => '$schema{$table}',\n".
      +            #(length($table) x ' '). "         'map'   => {\n";
      +            "$spaces        'map'   => {\n";
      +      my %map = map { /^\s*(\w+)\s*=>\s*(\w+)\s*$/
      +                         or die "guru meditation #420: $_";
      +                       ( $1 => $2 );
      +                     }
      +                 split( /\n/, $cgi->param($table) );
      +      foreach ( keys %map ) {
      +        print "$spaces                     '$_' => '$map{$_}',\n";
      +      }
      +      print "$spaces                   },\n";
      +      print "$spaces      },\n";
      +
      +    }
      +    print "\n
      "; + + } else { + warn "unrecognized magic: ". $cgi->param('magic'); } + %> + + + + + <% #hashmaker widget sub hashmaker { my($name, $from, $to, $labelfrom, $labelto) = @_; -- 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(-) 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 7b636e0d0a90e05e37ebe778bde29709f3323813 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 16 Dec 2002 10:47:38 +0000 Subject: working date range selector that defaults to the past year! --- httemplate/graph/money_time-graph.cgi | 12 ++++++++---- httemplate/graph/money_time.cgi | 26 +++++++++++++++++++++----- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/httemplate/graph/money_time-graph.cgi b/httemplate/graph/money_time-graph.cgi index ca8f6e86b..944019a7a 100755 --- a/httemplate/graph/money_time-graph.cgi +++ b/httemplate/graph/money_time-graph.cgi @@ -1,12 +1,16 @@ <% +#my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +my ($curmon,$curyear) = (localtime(time))[4,5]; + #find first month -my $syear = 2001; -my $smonth = 8; +my $syear = $cgi->param('syear') || 1899+$curyear; +my $smonth = $cgi->param('smonth') || $curmon+1; #find last month -my $eyear = 2002; -my $emonth = 12; +my $eyear = $cgi->param('eyear') || 1900+$curyear; +my $emonth = $cgi->param('emonth') || $curmon+1; +if ( $emonth++>12 ) { $emonth-=12; $eyear++; } my @labels; my %data; diff --git a/httemplate/graph/money_time.cgi b/httemplate/graph/money_time.cgi index d6c35434b..e24157ccb 100644 --- a/httemplate/graph/money_time.cgi +++ b/httemplate/graph/money_time.cgi @@ -1,9 +1,25 @@ +